Получить список режимов видео VESA из Int 10 / AX = 4F00h - PullRequest
1 голос
/ 10 октября 2019

Я пытаюсь разработать доказательство концепции ОС. Как бы то ни было, одна из проблем, с которыми я сталкиваюсь, это видео режимы vesa. Похоже, что нет жестко запрограммированных номеров видеорежимов после того, как vesa сказал нам получить их из информации биографии vbe и найти тот, который соответствует нашим потребностям. Однако я не могу получить видео режимы, так как я не знаю, как использовать vbeFarPtr из ядра C в 32-битном

Вот мой код ядра:

Я передал VbeInfoBlock в качестве параметра для ядра из моего загрузчика второго этапа после получения информации с int 0x10 ax = 0x4f00


int kmain(struct VbeInfoBlock *vbeinfo)
{


    init_idt();
    SetPITSpeed(100);

    init_DTCursor();

    printf(vbeinfo->signature); // I can print VESA here means I have the vbeinfoblock

    char* str = "";

    itoa(vbeinfo->video_modes,str,16); // I want a hex dump so I convert it to hex

    printf(str); // I get "VESA" for the signature followed by a string "1053" and nothing else while the list should be like this
    // If for example video mode 0x0103, 0x0118 and 0x0115 are supported
    // The list should be as 03 01 15 01 18 01 FF FF
    // So I should atleast get some FF FF
    // My output is "VESA 1053"

    while(1);
}

VbeInfoBlock определяется следующим образом, если вы не знаете

struct VbeInfoBlock
    {
        char signature[4];  // must be "VESA" to indicate valid VBE support
        uint16_t version;           // VBE version; high byte is major version, low byte is minor version
        uint32_t oem;           // segment:offset pointer to OEM
        uint32_t capabilities;      // bitfield that describes card capabilities
        uint32_t video_modes;       // segment:offset pointer to list of supported video modes
        uint16_t video_memory;      // amount of video memory in 64KB blocks
        uint16_t software_rev;      // software revision
        uint32_t vendor;            // segment:offset to card vendor string
        uint32_t product_name;      // segment:offset to card model name
        uint32_t product_rev;       // segment:offset pointer to product revision
        char reserved[222];     // reserved for future expansion
        char oem_data[256];     // OEM BIOSes store their strings in this area
    } __attribute__ ((packed));

Я не мог понять проблему. Есть ли другой способ сделать это? Или мой путь верен, но мой код неверен?

Мне кажется, проблема в том, что часть video_modes в VbeInfoBlock определяется как пара сегмент: смещение. Я не знаю, как использовать его в 32-битном коде C.

(Вы можете запросить мой загрузчик второго уровня или мой оригинальный загрузчик, но для этой проблемы я думаю, что это не нужно)

РЕДАКТИРОВАТЬ:

Код, который я пробовал после ответа Брендана

    uint32_t physical_address = (vbeinfo->video_modes_segment << 4) + vbeinfo->video_modes_offset;

    uint16_t *videoListPointer = (uint16_t *)physical_address;
    char chr = '\0';
    while(*videoListPointer != 0xffff) {

        itoa(*videoListPointer,chr,16);
        printf(chr);
        videoListPointer++;
    }

и мой gdt

gdt_start :
gdt_null : ; the mandatory null descriptor
dd 0x0 ; 'dd ' means define double word ( i.e. 4 bytes )
dd 0x0
gdt_code : 
dw 0xffff ; Limit ( bits 0 -15)
dw 0x0 ; Base ( bits 0 -15)
db 0x0 ; Base ( bits 16 -23)
db 10011010b ; 1st flags , type flags
db 11001111b ; 2nd flags , Limit ( bits 16 -19)
db 0x0 ; Base ( bits 24 -31)
gdt_data : 
dw 0xffff ; Limit ( bits 0 -15)
dw 0x0 ; Base ( bits 0 -15)
db 0x0 ; Base ( bits 16 -23)
db 10010010b ; 1st flags , type flags
db 11001111b ; 2nd flags , Limit ( bits 16 -19)
db 0x0 ; Base ( bits 24 -31)
gdt_end : 

gdt_descriptor :
dw gdt_end - gdt_start - 1 
dd gdt_start 

CODE_SEG equ gdt_code - gdt_start
DATA_SEG equ gdt_data - gdt_start   


Редактировать 2:

Изображение

Снимок экрана с моим выводом

Редактировать 3:

Код, который я использовал:


int kmain(struct VbeInfoBlock *vbeinfo)
{


    init_idt();
    SetPITSpeed(100);

    init_DTCursor();

    uint32_t physical_address = (vbeinfo->video_modes_segment << 4) + vbeinfo->video_modes_offset;

    uint16_t *videoListPointer = (uint16_t *)physical_address;
    char chr[9];

    while(*videoListPointer != 0xffff) {

        //itoa(*videoListPointer, chr,16);
        printf(*videoListPointer);
        videoListPointer++;

    }


    while(1);
}

и снимок экрана с моим выводом без itoa

Edit4:

gcc -v

C: \ Users \ Asus> gcc -v Использование встроенных спецификаций. COLLECT_GCC = gcc COLLECT_LTO_WRAPPER = D: / MinGW / mingw32 / bin /../ libexec / gcc / i686-w64-mingw32 / 8.1.0 / lto-wrapper.exe Цель: i686-w64-mingw32 Конфигурируется с помощью: ../. ./../src/gcc-8.1.0/configure --host = i686-w64-mingw32 --build = i686-w64-mingw32 --target = i686-w64-mingw32 --prefix = / mingw32 --with-sysroot = / c / mingw810 / i686-810-win32-dwarf-rt_v6-rev0 / mingw32 --enable-shared --enable-static --disable-multilib --enable-languages ​​= c, c ++, fortran, lto --enable-libstdcxx-time = да --enable-threads = win32 --enable-libgomp --enable-libatomic --enable-lto --enable-графит --enable-проверочный = выпуск --enable-полностью-динамический-строка --enable-specific-version-runtime-libs --disable-sjlj-exceptions --with-dwarf2 --disable-libstdcxx-pch --disable-libstdcxx-debug --enable-bootstrap --disable-rpath -отключить-win32-registry --disable-nls --disable-werror --disable-symvers --with-gnu-as --with-gnu-ld --with-arch = i686 --with-tune = generic -with-libiconv --with-system-zlib --with-gmp = / c / mingw810 / предварительные требования / i686-w64-mingw32-статические --with-mpfr = / c / mingw810 / предварительные требования / i686-w64-mingw32-статические --with-mpc = / c / mingw810 / предварительные требования / i686-w64-mingw32-статические --with-isl = / c /mingw810 / prerequisites / i686-w64-mingw32-static --with-pkgversion = 'i686-win32-dwarf-rev0, созданный проектом MinGW-W64' --with-bugurl = https://sourceforge.net/projects/mingw-w64 CFLAGS = '- O2-pipe -fno-ident -I / c / mingw810 / i686-810-win32-dwarf-rt_v6-rev0 / mingw32 / opt / include -I / c / mingw810 / предварительные требования / i686-zlib-static / include -I / c/ mingw810 / предварительные требования / i686-w64-mingw32-static / include 'CXXFLAGS =' - O2 -pipe -fno-идент -I / c / mingw810 / i686-810-win32-dwarf-rt_v6-rev0 / mingw32 / opt / include-I / c / mingw810 / предварительные требования / i686-zlib-static / include -I / c / mingw810 / предварительные требования / i686-w64-mingw32-static / include 'CPPFLAGS =' -I / c / mingw810 / i686-810-win32-dwarf-rt_v6-rev0 / mingw32 / opt / include -I / c / mingw810 / предварительные требования / i686-zlib-static / include -I / c / mingw810 / предварительные условия / i686-w64-mingw32-static / include 'LDFLAGS ='-pipe -fno-идент -L / c / mingw810 / i686-810-win32-dwarf-rt_v6-rev0 / mingw32 / opt / lib -L / c / mingw810/ prerequisites / i686-zlib-static / lib -L / c / mingw810 / prerequisites / i686-w64-mingw32-static / lib -Wl, - с поддержкой больших адресов 'Модель потока: win32 gcc версия 8.1.0 (i686-win32-dwarf-rev0, созданный проектом MinGW-W64)

Edit5:

Снимок экрана с выводом без *

Ответы [ 2 ]

2 голосов
/ 10 октября 2019

Во-первых, немного измените свою структуру, чтобы video_modes был разделен на 2 поля, например:

struct VbeInfoBlock {
    char signature[4];  // must be "VESA" to indicate valid VBE support
    uint16_t version;           // VBE version; high byte is major version, low byte is minor version
    uint32_t oem;           // segment:offset pointer to OEM
    uint32_t capabilities;      // bitfield that describes card capabilities

    uint16_t video_modes_offset;
    uint16_t video_modes_segment;

    uint16_t video_memory;      // amount of video memory in 64KB blocks
    uint16_t software_rev;      // software revision
    uint32_t vendor;            // segment:offset to card vendor string
    uint32_t product_name;      // segment:offset to card model name
    uint32_t product_rev;       // segment:offset pointer to product revision
    char reserved[222];     // reserved for future expansion
    char oem_data[256];     // OEM BIOSes store their strings in this area
} __attribute__ ((packed));

Затем вычислите физический адрес списка режимов видео, например:

uint32_t physical_address = (vbeinfo->video_modes_segment << 4) + vbeinfo->video_modes_offset;

Затем сделайте все, что вам нужно, чтобы преобразовать физический адрес в виртуальный адрес, который можно использовать в качестве указателя. Если вы не используете пейджинг и базовые адреса регистров сегмента равны нулю, это будет тривиально, например uint16_t *videoListPointer = (uint16_t *)physical_address;. Если базы регистров сегмента отличны от нуля, вам нужно будет вычесть их из физического адреса (и убедитесь, что вы используете вычитание «32-битный без знака», чтобы в случае отрицательного результата результат получился положительным),Если используется пейджинг, то это будет зависеть от того, как используется пейджинг (например, вы можете отобразить физические страницы, содержащие список режимов видео, на любой виртуальный адрес, который вам нравится).

В любом случае, если выИмея полезный указатель, вы можете сделать что-то вроде:

    while(*videoListPointer != 0xFFFF) {
        printf("0x%04X\n", *videoListPointer);
        videoListPointer++;
    }

Однако;если это сработает, у вас будет список бессмысленных чисел (старые «номера фиксированного режима» устарели, и теперь любой номер режима может означать что угодно). Вы должны использовать «int 0x10, ax = 0x4F01, Получить информацию о режиме VBE», чтобы узнать, что режим на самом деле (разрешение, глубина цвета, ...);и вы не можете сделать это в защищенном режиме, и вам придется переключиться обратно в реальный режим для этого.

Учитывая, что вам придется переключиться обратно в реальный режим, чтобы разобраться с номерами режимов, вероятно,будет проще переключиться обратно в реальный режим и затем выполнить итерацию списка номеров режимов (используя реальный режим «сегмент и смещение», который VBE дал вам без каких-либо преобразований).

0 голосов
/ 23 октября 2019

Это дополнение к ответу Брендана. В вашем первом редактировании вы включили изменения, предложенные Бренданом, и сделали это:

uint32_t physical_address = (vbeinfo->video_modes_segment << 4) + \
                            vbeinfo->video_modes_offset;

uint16_t *videoListPointer = (uint16_t *)physical_address;
char chr = '\0';
while(*videoListPointer != 0xffff) {

    itoa(*videoListPointer,chr,16);
    printf(chr);
    videoListPointer++;
}

Прежде всего char chr = '\0' гарантирует только выделение одного байта, инициализированного 0. Вам действительно нужен буфер символов, достаточно большой длясамая длинная строка, которая может быть возвращена itoa. Для шестнадцатеричного числа это 9 символов, которое включает 8 шестнадцатеричных цифр и терминатор NUL (\ 0). Для наихудшего случая основания 2 (двоичного) это 33 символа, включая терминатор NUL (\ 0). Вы можете объявить буфер следующим образом:

char buf[9];

Вы можете передать этот буфер в itoa. Считать номера режима видео проще, если между ними поместить символ пробел . Модифицированный код может выглядеть следующим образом:

uint32_t physical_address = (vbeinfo->video_modes_segment << 4) + \
                            vbeinfo->video_modes_offset;

uint16_t *videoListPointer = (uint16_t *)physical_address;
char buf[9];

while(*videoListPointer != 0xffff) {        
    itoa(*videoListPointer, buf, 16);
    printf(buf);
    printf(" ");
    videoListPointer++;
}

Самое важное : я не уловил эту ошибку, пока не просмотрел весь ваш код на GitHub. Брендан предложил правильное изменение, чтобы разбить элемент video_modes структуры VBEInfoBlock, заменив:

    uint32_t video_modes; // segment:offset pointer to list of supported video mode

на:

    uint16_t video_modes_offset;
    uint16_t video_modes_segment;

Сегмент реального режима: пары смещений сохраняютсяв памяти со смещением, за которым следует сегмент. Проблема в том, что в GitHub вы изменили смещение и сегмент, выполнив это:

    uint16_t video_modes_segment; // segment:offset pointer to list of supported video modes
    uint16_t video_modes_offset;

Когда это должно быть:

    uint16_t video_modes_offset;  // segment:offset pointer to list of supported video modes
    uint16_t video_modes_segment;

Из-за этой ошибки адрес, который вы вычисляете для списка режимов видеонеправильно, что приводит к созданию неправильного списка.


Если эти изменения сделаны, выходные данные должны выглядеть примерно так:

enter image description here

Это выглядит как правильный список, тем более что в конец списка входят режимы видео EGA / VGA:

0 1 2 3 4 5 6 7 D E F 10 11 12 13 6A

Режимы видео 8 9 A B C обычно резервируются или не являются частьюиз стандартных режимов видео EGA / VGA, поддерживаемых QEMU. Режим 6A выделяется тем, что это стандартный 16-битный цветовой режим VESA 800x600. Исходя из этого, я предполагаю, что смотрю на список, который подходит для QEMU.

...