[英]Retrieve list of VESA video modes from Int 10h/AX=4F00h
我正在嘗試開發一個概念驗證操作系統。 但是,在此過程中,我遇到的問題之一是 vesa 視頻模式。 在 vesa 告訴我們從 vbe bios 信息中獲取它們並找到適合我們需要的視頻模式編號之后,似乎缺少硬編碼的視頻模式編號。 但是我無法接收視頻模式,因為我不知道如何使用 32 位vbeFarPtr
kernel 中的 vbeFarPtr
這是我的 kernel 代碼:
在接收到 int 0x10 ax=0x4f00 的信息后,我將VbeInfoBlock
作為參數從我的第二階段引導加載程序傳遞給 kernel
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));
我無法理解這個問題。 還有其他方法嗎? 還是我的方式正確但我的代碼不正確?
我認為問題在於 VbeInfoBlock 中的VbeInfoBlock
部分被定義為段:偏移量對。 我不知道如何在 32 位 C 代碼中使用它。
(您可以請求我的第二階段引導加載程序或我原來的引導加載程序,但對於這個問題,我認為沒有必要)
編輯:
我在 Brendan 回答后嘗試的代碼
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);
}
編輯4:
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++,Z56121CC37D7123E665C0F8317F17AA5- -enable-libstdcxx-time=yes --enable-threads=win32 --enable-libgomp --enable-libatomic --enable-lto --enable-graphite --enable-checking=release --enable-fully-dynamic-字符串 --enable-version-specific-runtime-libs --disable-sjlj-exceptions --with-dwarf2 --disable-libstdcxx-pch --disable-libstdcxx-debug --enable-bootstrap --disable-rpath -- disable-win32-registry --disable-nls --disable-werror --disable-symvers --with-gnu-as --with-gnu-ld --with-arch=i686 --with-tune=generic -- with-libiconv --with-system-z lib --with-gmp=/c/mingw810/prerequisites/i686-w64-mingw32-static --with-mpfr=/c/mingw810/prerequisites/i686-w64-mingw32-static --with-mpc=/c/ mingw810/prerequisites/i686-w64-mingw32-static --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/prerequisites/i686-zlib-static/include -I/c/mingw810/prerequisites/i686-w64-mingw32-static/include' CXXFLAGS='-O2 -pipe - fno-ident -I/c/mingw810/i686-810-win32-dwarf-rt_v6-rev0/mingw32/opt/include -I/c/mingw810/prerequisites/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/prerequisites/i686- zlib-static/include -I/c/mingw810/prerequisites/i686-w64-mingw32 -static/include' LDFLAGS='-pipe -fno-ident -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,--large-address-aware' 線程 model:win32 gcc 版本 8.1.dwarf-win6322 , 由 MinGW-W64 項目構建)
編輯5:
首先,稍微改變一下結構,將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 位無符號”減法,以便如果結果為負,它會環繞為有效的正結果) . 如果使用分頁,那么它將取決於如何使用分頁(例如,您可能在 map 包含您喜歡的任何虛擬地址的視頻模式列表的物理頁面)。
在任何情況下,一旦你有了一個可用的指針,你就可以執行以下操作:
while(*videoListPointer != 0xFFFF) {
printf("0x%04X\n", *videoListPointer);
videoListPointer++;
}
然而; 如果可行,您將獲得一個無意義數字列表(舊的“固定模式編號”已被棄用,現在任何模式編號都可以表示任何含義)。 您必須使用“int 0x10, ax = 0x4F01, Get VBE mode information”來找出實際的模式是什么(分辨率,顏色深度,...); 而且您不能在保護模式下執行此操作,並且必須為此切換回實模式。
鑒於您必須切換回實模式才能理解模式編號,切換回實模式然后迭代模式編號列表可能會更容易(使用 VBE 的實模式“分段和偏移”)給你沒有任何轉換)。
這是 Brendan 答案的附錄。 在您的第一次編輯中,您合並了 Brendan 建議的更改並執行了以下操作:
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
可能返回的最長字符串。 對於包含 8 個十六進制數字和 NUL(\0) 終止符的 9 個字符的十六進制。 對於基數 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 上的所有代碼,我才發現這個錯誤。 Brendan 建議進行正確的更改,通過替換來分解VBEInfoBlock
結構的video_modes
成員:
uint32_t video_modes; // segment:offset pointer to list of supported video mode
和:
uint16_t video_modes_offset;
uint16_t video_modes_segment;
實模式段:偏移對存儲在 memory 中,偏移后跟段。 問題出在 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;
由於這個錯誤,您為視頻模式列表計算的地址是錯誤的,這會導致生成不正確的列表。
如果進行了這些更改,output 應該類似於:
這看起來像是一個正確的列表,特別是因為列表的末尾包括 EGA/VGA 視頻模式:
0 1 2 3 4 5 6 7 DEF 10 11 12 13 6A
視頻模式8 9 AB C
通常是保留的,或者不是 QEMU 支持的標准 EGA/VGA 視頻模式的一部分。 模式6A
脫穎而出,因為它恰好是標准的 VESA 800x600 16 位顏色模式。 基於此,我假設我正在查看適合 QEMU 的列表。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.