вывод на экран в защищённом режиме
меня интересует:
1) как изменить разрешение экрана (пока рассматривается только текстовый режим)
2) как позиционировать курсор
3) если нужно сдвинуть весь текст на экране на строчку вверх (чтобы освободить нижнюю), есть какой нибудь способ, кроме как пробежаться по всей видеопамяти и переместить каждый символ?
Дайте, пожалуйста, ссылку на какую-нибудь инфу по этой теме - я ничего не нашёл.
2)
#define VGA_DATA_PORT 0x3D5
#define VGA_SET_CURSOR_HIGH 0x0E
#define VGA_SET_CURSOR_LOW 0x0F
/**
* Setting console cursor position.
*/
void console_set_cursor_pos ( ui32_t x, ui32_t y ) {
if ( x >= VIDEO_COLUMNS ) {
/* Move to the next line */
y += x / VIDEO_COLUMNS;
x %= VIDEO_COLUMNS;
}
if ( y >= VIDEO_LINES ) {
/* Scroll down */
console_scroll(y - VIDEO_LINES + 1);
y = VIDEO_LINES - 1;
}
int pos = x + y * VIDEO_COLUMNS;
outb(VGA_SET_CURSOR_HIGH, VGA_COMMAND_PORT);
outb((pos >> 8), VGA_DATA_PORT);
outb(VGA_SET_CURSOR_LOW, VGA_COMMAND_PORT);
outb((pos & 0xFF), VGA_DATA_PORT);
kconsole_state.col = x;
kconsole_state.row = y;
}
3) Нужно копировать кусок видеопямяти наверх.
* Scroll several lines.
*/
void console_scroll ( ui32_t deltha ) {
int i;
if ( deltha == 0 )
return;
for ( i = 0; i < VIDEO_LINES - deltha; i++ ) {
memcpy( (void*)(VIDEO_ADDR + i*VIDEO_COLUMNS*2),
(void*)(VIDEO_ADDR + (i+deltha)*VIDEO_COLUMNS*2),
VIDEO_COLUMNS*2 );
}
for ( ; i < VIDEO_LINES; i++ )
memset((void *)(VIDEO_ADDR + i*VIDEO_COLUMNS*2), 0x0, VIDEO_COLUMNS*2);
}
Так что без вызова прерываний BIOS, думаю, не обойтись.
Ну, как сказать, давно не работал с DOS32, для которого подобные вопросы были актуальны, поэтому могу привести только старые примеры.
Из брендов, у которых не было VGA-совместммости, - Matrox (совместим только на уровне прерываний, при попытке работать через порты - выдавал нечто непредсказуемое), и кое-какие проблемы с VGA-совместимостью были у встроенных в чипсет видеоконтроллеров Intel 810-815. Как сейчас, честно говоря, не знаю. Но, с одной стороны, прецеденты несовместимости есть, а с другой - сейчас эта несовместимость на уровне портов уже никого не волнует, т.к. все равно используются индивидуальные загружаемые драйвера.
PS. Почему бы не вызывать прерывания из защищенного режима? Тогда можно воспользоваться BIOS. VM86- это всеголишь 32битная задача. С выставленным одним флагом + кое какие настройки.
PS. Почему бы не вызывать прерывания из защищенного режима? Тогда можно воспользоваться BIOS. VM86- это всеголишь 32битная задача. С выставленным одним флагом + кое какие настройки.
Хм... До этого я в изучении защищённого режима ещё не дошёл.
Лучше поищу инфу про vga.
Собственно, стандарт VESA и был разработан для обеспечения унифицированной работы с аппаратно несовместимым железом. Так что не нужно здесь пытаться изобретать велосипед.
Лучше поищу инфу про vga.
Советую, наоборот, начать с того, что научиться вызывать прерывание из защищенного режима. Писать программы надо так, чтобы они работали везде, а не только на комьютере разработчика.
Собственно, стандарт VESA и был разработан для обеспечения унифицированной работы с аппаратно несовместимым железом. Так что не нужно здесь пытаться изобретать велосипед.
Советую, наоборот, начать с того, что научиться вызывать прерывание из защищенного режима. Писать программы надо так, чтобы они работали везде, а не только на комьютере разработчика.
я не понял: сервис VESA - это тоже самое, что и сервис bios ?
Или ты посоветовал 2 различных способа?
VBE - VESA BIOS EXTENSION
Иногда когда говорят VESA подрозумивают VBE.
BIOS это набор сервисов.
К примеру
Int 1Ah–Time of Day Services
Int 1Ah–General PCI Services
Int 10h –Video Services
Так вот функции видео сервиса начинающии с ah=4f относятся к VBE. Поэтому VESA это тоже сервис BIOS.
Так как хочется больших разрещений и много цветов, то надо использовать VESA. Так как VGA/EGA не позволяют этого, а каждая видео карта программируется по своему. Но для стандартизации ввели сервис BIOSA - VESA. Каждая видео карта имеет свой биос, который и реализует видео функции.
Проблемы начинаются при выходи в защищенный режим. Напрямую прерывания BIOS'а вызывать нельзя так как режим другой. Приходиться прыгать в реальный режим или виртуальный чтобы вызвать прерывание. Или использовать стандарт VGA/EGA и программировать через порты. Как один из вариантов до перехода в защищенный режим устанавливают VESA режим, а дальше идет работа с видео памятью напрямую. Больше и ненадо. Можно еще написать свои драйвера. Видео карты VGA/EGA позволяют делать многое, так что свои видео драйвера для поддержки таких карт иметь стоит.
BIOS VGA-совместимых видеокарт имеет несколько специфических функций, по наличию которых можно определить их присутствие.
Также первый раз об этом слышу.
Это вариант, но для организации полноценной виртуальной машины выставления одного флага + кое-каких настроек недостаточно (одна виртуализация прерываний чего стоит), к тому же это влечет за собой усложнение ядра там, где в этом нет особой необходимости. Я режим V86 не использую вообще и использовать не собираюсь.
Собственно, стандарт VESA и был разработан для обеспечения унифицированной работы с аппаратно несовместимым железом. Так что не нужно здесь пытаться изобретать велосипед.
Советую, наоборот, начать с того, что научиться вызывать прерывание из защищенного режима.
Графика на основе VBE частенько подтормаживает, причем не из-за накладных расходов вследствии использования VBE реального режима в защищенном режиме, а из-за того, что некоторые производители видеокарт плохо реализовали функции VBE в своем железе. Предпочитаю использовать текстовые режимы на основе прямого программирования VGA, чем графические режимы высокого разрешения на основе VBE (не люблю присутствие постороннего кода в основе написанных мной защищенных систем).
Это абсолютно справедливо! Я сам не раз говорил об этом.
Или ты посоветовал 2 различных способа?
Да, сервис VESA доступен через стандартное 10h прерывание BIOS, функция 4Fh.
Выставляем второй флаг VME. И делаем редирект прерываний. Путем записи битов в TSS. Правда эта возможность появилась начиная с пентиумов. На первых порах можно не заботиться о исключениях, потому что при вызове прерываний они не должны происходить если там нет ошибки в коде и оборудование исправна.
Наднях напишу пример и опубликую. Пока код умещается в 20 строчек.
Уж скоро 10 лет, как писал...
http://www.osp.ru/pcworld/1998/08/159480/
Функция 0Ah запрашивает интерфейс защищенного режима.
далее в dl помещается смещение таблицы, а вот какой у таблицы формат, там не написано?
Подскажите что делать, или я что то не понимаю?
З.Ы Извиняюсь за свой тугодумость:)
1. Установить видео режим.
2. Вывод ведеться ввидео память.
mov [Video_addr+(y*width+x)*BytePerPixel],ColorOfPixel
3. Пишем программы вывода приметивов. Формулы можно найти или придумать.
Проблемы только с установкой видео режима. Для этого надо вызвать прерывания VESA. Прерывания вызывать из реального режима(до перехода в реальный режим) или виртуального.
Надо получить список видео режимов функция 00. Потом перебрать все видео режимы функция 01 вернет параметры о видео режиме.
Собственно надо знать 3 параметра высоту разрешения и ширину. А также формат пикселя. А еще функция 01 возращает адресс видео памяти. Форматов пикселя есть несколько видов
1. 8 бит 256 цветов с палитрой
2. 15 бит, на самом деле 16 abbbbbgggggrrrrr последний бит не используется
3. 16 бит, цвет кодируется bbbbbggggggrrrrr
4. 24 бита, цвет кодируется первый байт крастный, второй зеленый третий синий
5. 32 бита, цвет кодируется первый байт крастный, второй зеленый третий синий, четвертый байт не используется
После того как я перебрал все режимы и поместил информацию в буфер. Какова структура этой информации(т.е какие поля там содержаться)
2. Вывод ведеться ввидео память.
mov [Video_addr+(y*width+x)*BytePerPixel],ColorOfPixel
Проблема в том, что делать, когда мы выходим за пределы 64К.
1. 8 бит 256 цветов с палитрой
2. 15 бит, на самом деле 16 abbbbbgggggrrrrr последний бит не используется
3. 16 бит, цвет кодируется bbbbbggggggrrrrr
4. 24 бита, цвет кодируется первый байт крастный, второй зеленый третий синий
5. 32 бита, цвет кодируется первый байт крастный, второй зеленый третий синий, четвертый байт не используется
Форматов намного больше. Собственно, биты r g и b могут располагаться в каком угодно порядке и количество битов для каждого цвета также может быть любым.
andriano,
Насчет 64kb. Собственно есть банковый режим работы c видео памятью и не банковый. В первом случии если выходим за границу, то надо вызывать функцию переключения банка. Номер банка определяется через деление на цело на 64kb. Что касается не банкового, то тут просто выводим в линейный буффер.
Если вспомнить историю, то LFB придумали что бы побороть неудобство банков. В памяти компьютера заводился линейный буфер(этим делом заведовал драйвер) вывод велся в него. LFB- Line Frame Buffer -линейный буфер кадра. А после переодически копируется в видео память к примеру синхронизировать с обратным ходом луча по кадру.
Это только потом появились видео карты которые отоброжали линейно видео память в верхних адрессах памяти. А адрес это продолжали называть LFB, в спецификацие VBE3 указатель называется PhysBasePtr.
Собственно надо помнить, что некоторые карты работают только с банками другии только с линейным буффером, а третьи держут оба режима.
Форматов пикселей может быть и больше, но наданный момен эти самые распространенные.Собственно их и надо считать стандартными. Остальное уже не стандарт. Собственно найдите мне другой формат на видео карте, тогда можно будет поговорить.
PS. Собственно предыдущий пост не был подробным. Уходил к знакомым комп чинить.
Насчет 64kb. Собственно есть банковый режим работы c видео памятью и не банковый. В первом случии если выходим за границу, то надо вызывать функцию переключения банка. Номер банка определяется через деление на цело на 64kb.
Нет.
Делим на гранулярность банков (которая не только не обязана быть 64К, но и не обязана равняться размеру банка).
Это только потом появились видео карты которые отоброжали линейно видео память в верхних адрессах памяти. А адрес это продолжали называть LFB, в спецификацие VBE3 указатель называется PhysBasePtr.
Вообще-то наоборот. Сначала появились карты с LFB. Первый LFB располагался в 15-Мбайте физического адресного пространства. И только потом появился стандарт VESA. И еще позже появилась версия VESA 2.0, в который ввели LFB.
Собственно надо помнить, что некоторые карты работают только с банками другии только с линейным буффером, а третьи держут оба режима.
Нет, банки - обязательно, LFB - при условии VESA 2.0.
Стандартное - то, что утверждено стандартом.
Не следует путать стандарт с конкретной продукцией, нередко этот стандарт нарушающей.
Сначала появились карты с LFB. Первый LFB располагался в 15-Мбайте физического адресного пространства. И только потом появился стандарт VESA. И еще позже появилась версия VESA 2.0, в который ввели LFB.
Я говорю что LFB появился раньше чем его ввели в стандарт VESA. И не обязательно он был аппоратным, а в полне мог быть и програмным.
Нет, банки - обязательно, LFB - при условии VESA 2.0.
Стандарт давно смотрели?
VBE 3.0
provides new memory models that do not require the traditional frame buffer "banking" mechanisms.
Вообщето мне попадались видео карты VESA2 у которых банки не работали.
Стандартное - то, что утверждено стандартом.Не следует путать стандарт с конкретной продукцией, нередко этот стандарт нарушающей.
Со словами согласен. Но когда ты будешь писать программу, что будешь делать тут все по стандарту веса? Поддерживать все форматы? ИХМО не к чему. Надо быть реалистами и выберать золотую середину.
1) в формуле Video_addr+(y*width+x)*BytePerPixel вместо width правильнее использовать BytesPerLine;
2) я программно проверял адрес и размер первого "окна", возможность чтения из видеопамяти (если это необходимо), гранулярность банков и если какой-то из параметров не соответствовал требованиям программы, просто выдавал сообщение об ошибке и завершал программу. Точно помню, что использовал единственное "окно" по адресу 0xA0000 размером 64 Кб и программы работали на всех используемых мной компьютерах с поддержкой VESA и достаточным количеством видеопамяти. Ошибки стали всплывать только потом с появлением новой техники;
3) при построчном выводе изображения для переключения банков я использовал инструкцию into, причем весьма хитрым способом (делал какое-то псевдосмещение на 32 Кб), а при выводе полноэкранных изображений переключал банки явно;
4) в графическом ядре программы хранил номер активного банка и осуществлял вызов процедуры VBE, выполняющей переключение, только тогда, когда это действительно было необходимо, причем с помощью предварительно сохраненного дальнего указателя, а не прерывания VideoBIOS.
Короче все работало как надо, т.е. быстро. Скорость обновления кадров не замерял, но помню, что не было никаких неприятных эффектов и даже указатель мыши не мигал над изменяющимся изображением.
Из твоего поста №25 следует порядок: банки->программная эмуляция LFB->аппаратный LFB, что не соответствует действительности.
Точнее, программно-аппаратным. Ты, кстати, пишешь про обратный ход луча - это уже аппаратная фича, так что программная реализация описанного тобой алгоритма невозможна без аппаратного прерывания по обратному ходу. И, кстати, описанный тобой алгоритм, коль скоро мы вернулись к этому вопросу, мне представляется крайне маловероятным:
1. Драйвер DOS отъедает от системной памяти буфер размером с видеопамять? Не верю!
2. Запись в экран осуществляется двукратной перезаписью: из экранного буфера программы в линейный буфер драйвера и из линейного буфера драйвера - в странично организованную видеопамять? Тоже не верю.
А вот реализация (кстати, был такой загружаемый драйвер UniVBE) через механизм исключений при доступе к памяти - совсем другое дело.
VBE 3.0
Неплохой стандарт. Жаль мертворожденный. Точнее, рожденный слишком поздно, уже неактуальный, а потому так и оставшийся практически только на бумаге.
Вообщето мне попадались видео карты VESA2 у которых банки не работали.
Рискну предположить, что сами по себе банки как раз работали, а не работала твоя программа, предполагающая, что гранулярность банков всегда 64К.
Со словами согласен. Но когда ты будешь писать программу, что будешь делать тут все по стандарту веса? Поддерживать все форматы? ИХМО не к чему. Надо быть реалистами и выберать золотую середину.
Вот ты предположил, что гранулярность всегда 64К, и обломался. И кто виноват?
Вероятно, мнение о том, где именно находится эта золотая середина, у каждого свое. Так что использование константы, считанной из информационного блока вряд ли чем-то отличается от использования заранее предопределенной константы. Зато позволяет избежать многих проблем.
Совршенно верно.
Скажу более, были видеокарты, у которых, например, в режиме 800х600х256 цветов длина строки была не 800, а 1024 байта.
3) при построчном выводе изображения для переключения банков я использовал инструкцию into, причем весьма хитрым способом (делал какое-то псевдосмещение на 32 Кб), а при выводе полноэкранных изображений переключал банки явно;
Честно говоря, статическая графика меня интересовала мало, поэтому с видеопамятью работал единственным способом - переливал в нее уже сформированное в буфере изображение. Естественно, существовало два варианта такой процедуры - для банкового режима и LFB. Все примитивы отрисовывались исключительно в буфере, создаваемом программой.
4) в графическом ядре программы хранил номер активного банка и осуществлял вызов процедуры VBE, выполняющей переключение, только тогда, когда это действительно было необходимо, причем с помощью предварительно сохраненного дальнего указателя, а не прерывания VideoBIOS.
Вполне логично. Только этот указатель - то же самое прерывание BIOS, лишенное, правда, некоторой "обертки". (кстати, в современных API, в том же OpenGL, принята аналогичная техника) В документации именно так и советовалось.
FPS для процедуры отображения измерять как-то не додумался, но, помню, измерял скорость перезаписи из оперативной памяти в видеопамять. Если общение происходило из-под Win9x по AGP, то скорость эта была, как правило, выше, чем просто при пересылке внутри памяти. В том числе при использовании при пересылке регистров MMX (на многих системах это работало быстрее стандартного rep movsd).
1) в формуле Video_addr+(y*width+x)*BytePerPixel вместо width правильнее использовать BytesPerLine;
ДА надо, говорю же вчера спешил когда писал.
FPS для процедуры отображения измерять как-то не додумался, но, помню, измерял скорость перезаписи из оперативной памяти в видеопамять. Если общение происходило из-под Win9x по AGP, то скорость эта была, как правило, выше, чем просто при пересылке внутри памяти. В том числе при использовании при пересылке регистров MMX (на многих системах это работало быстрее стандартного rep movsd).
Походу это связанно с кэшированием. AGP память обычно не кэшируется.
Я ничего не придумываю. Вот цитата из твоего сообщения:
Возможно. Но маловероятно. По крайней мере, когда то же самое делаешь под "голым" DOS, скорость получается ниже. Значит, дело в том, как винды программируют AGP. Ну а дальше все понятно:
1. Видеопамять сама по себе быстрее оперативной.
2. Когда мы пишем из памяти с одним адреснывм пространством в память с другим адресным пространствам, у нас не происходит постоянного переключения адресов на участке НМС-ОЗУ, для AGP, насколько я помню, начиная с Pentium II, была своя независимая шина.
Я считаю что всетаки это свщяанно с кэшированием а именно с настройкой MTRRS регистров. Хотя возможно идет настройка AGP, но там помойму основные параметры остаются такимиже как в биосе. Так что тут я особо и не копал.
может так:
mov si,[es:11] ; поместили указатель в si
mov ax,[es:si] ; прочитали номер режима
но я точно не уверен
P.S. инфа о VESA у меня помещается в es:di (0000h:0000h).
Указатель проще всего загрузить так
LFS SI,[ES: DI+14]
дальше будешь использовать FS
MOV AX,[FS:SI]
es:di (0000h:0000h). так ты всю таблицу векторов попортишь.
VesaInfoBlock = record
VESASignature : array[0..3]of char; {"VESA"}
VESAVersion : word; {номер версии VESA}
OEMStringPtr : CPtr; {указатель на строку с названием производителя (OEM) }
Capabilities : dword; {флаги графических возможностей}
VideoModePtr : WPtr; {указатель на список поддерживаемых видеорежимов}
TotalMemory : word; {количество видеопамяти в 64-килобайтных блоках}
Reserved : array[0..235]of byte;
{зарезервировано}
END;
Как я понял, мне нужен вот этот указатель VideoModePtr.
но он же находиться со смещение 11 или я что-то путаю. И еще вопрос: ведь этот указатель содержит смещение массива, а где же содержится база в структуре VesaInfoBlock?
VESASignature : array[0..3]of char; {+00 "VESA"}
VESAVersion : word; {+04 номер версии VBA}
OEMStringPtr : CPtr; {+06 указатель на строку с названием производителя (OEM) }
Capabilities : Dword; {+10 флаги графических возможностей}
VideoModePtr : WPtr; {+14 указатель на список поддерживаемых видеорежимов}
TotalMemory : word; {+18 количество видеопамяти в 64-килобайтных блоках}
InVersion : word; {+20 Внутренняя версия реализации VBA}
NameFirme : CPtr; {+22 указатель на название производителя}
NameVESA : CPtr; {+26 указатель на название видеоодаптора}
PTRVESAVersion: CPtr; {+30 указатель на название версия видеоодаптора}
Version_AF : word; {+34 версия vba/af(bcd 0100h для 1.0)}
VideoModeAF : WPtr; {+36 указатель на намира режимов поддержувающих AF ускорение}
Reserved : array[0..215]of byte;{+40 зарезервировано}
OemData : array[0..255]of byte;{+256 зарезервировано для внутренних данных}
END;
Ты сам передаешь базу в функцию 00 в ES: DI
я сделал так:
mov eax,[es:14] ; взял указатель на видеорежим
mov si,ax
shr eax,16
mov fs,ax
Спасибо, все понятно.
Но почему не работает такой код, хотя все правильно
инфу о VESA поместил в es:si (6C00h:0000h), чтобы не затерать вектора прерываний(как мне посоветовали)
[highlight=asm]
xor di,di
xor dx,dx
mov bx,256
vesa_3:
mov ah,4fh
mov al,01h
mov cx,word [fs:si]
int 10h
add si,2 ;,двигаю указатель на следующий режим
inc dx ;просто веду счетчик режимов
cmp [es:di+18],word 640 ; ищу такую ширину
je cuda
dec bx
cmp bx,0h
ja vesa_3
jmp $
cuda: ;просто проверка, что хоть что-то найдено
add dx,30h
mov ax,0b800h
mov es,ax
mov [es:00h],dx
jmp $
[/highlight]