BIOS VESA扩展:视频模式缓冲区指向空数组问题排查
VESA模式列表读取异常问题排查与解决
问题背景
通过INT 10h / AX=4F00h获取VESA基本信息块后,读取视频模式列表时出现异常:在QEMU和DOSBox中运行时,打印大量空值,首个非零值出现后内核崩溃,不符合VESA规范中模式列表以FFFFH结尾的预期。
相关代码
获取VESA基本信息块代码
PUSH cs ; POP es ; ;- perform VESA check ; PUSH es ; some BIOSes destroy ES with this call MOV di, OFFSET DRV_VESA_infoBlock ; ES:DI buffer for at least 256 bytes (512 for VBE v2.0+) MOV ax, 04F00H ; INT 10H ; POP es ; ; ;- check for errors ; CALL DRV_VESA_bioscallErrorCheck ; ; ;-- check buffer signature ; PUSH CS ; POP ES ; MOV di, OFFSET DRV_VESA_infoBlock ; ES:DI = buffer MOV cx, 4 ; MAC_IMMSTRING "VESA" ; DS:SI = "VESA" signature needs to match! REPZ CMPSB ; JZ @@noErrors ; MAC_DPT_PRINTIMM "VESA buffer: signature does not match!" DRV_VESA_panic ; ; ;-- check vesa version ; MOV ax, CS:[DRV_VESA_infoBlock].version CMP ax, 00102H ; JGE @@noErrors ; MAC_DPT_PRINTIMM "VESA: version too low" DRV_VESA_panic ; @@noErrors: ; ... ... ... ; ALIGN DWORD ; some bioses might require the structs to be aligned DRV_VESA_infoBlock DRV_VESA_VBE_INFO_STRUCT {} ALIGN DWORD ; DRV_VESA_modeInfo DRV_VESA_VBE_MODE_INFO_STRUCT {}
获取视频模式缓冲区指针代码
;-- get vesa modes buffer address ; MOV ax, WORD PTR [bx].DRV_VESA_VBE_INFO_STRUCT.modesOff MOV si, ax MOV ax, WORD PTR [bx].DRV_VESA_VBE_INFO_STRUCT.modesSeg PUSH ax ; POP fs ; ;
打印视频模式初步操作代码
@@displayModeLoop: ; MOV cx, WORD PTR fs:[si] ; CMP cx, 0FFFFH ; JE @@displayModeEndLoop ; MOV ax, cx ; CALL DPT_printNum ; ;--- get mode information ; MOV ax, 04F01H ; INT 10H ; CALL DRV_VESA_bioscallErrorCheck ; ADD si, 2 ; JMP @@displayModeLoop ; @@displayModeEndLoop: ;
已知信息
DPT_printNum功能正常,无故障- 移除BIOS函数调用后问题仍存在
- 当前运行在实模式(RMODE)
- 使用自定义引导加载程序
问题现象
在QEMU和DOSBox中运行时,打印大量空值(0),首个非零模式值出现后内核立即崩溃,模式列表未按VESA规范以FFFFH结尾。
问题原因分析
bx寄存器未初始化:获取模式缓冲区指针时,直接使用[bx].DRV_VESA_VBE_INFO_STRUCT.modesOff,但未设置bx指向DRV_VESA_infoBlock的偏移地址,导致读取到错误的段/偏移值。- 结构体定义不匹配:若
DRV_VESA_VBE_INFO_STRUCT的定义与VESA规范不符(比如modesOff和modesSeg的偏移位置错误),会读取到无效的模式列表地址。 - 段寻址错误:模式列表的远指针(段:偏移)加载错误,导致访问非法内存区域,出现大量空值。
- 内存覆盖:自定义引导加载程序或内核代码可能覆盖了VESA信息块或模式列表所在的内存区域,导致数据损坏。
- BIOS调用参数缺失:执行
INT 10h/AX=4F01h时未正确设置es:di指向模式信息结构体,且未保留当前模式号在cx中,触发非法操作。
解决方法
- 初始化
bx寄存器:在获取模式缓冲区指针前,将bx设置为DRV_VESA_infoBlock的偏移地址:; 添加到获取模式缓冲区指针的代码前 MOV bx, OFFSET DRV_VESA_infoBlock - 验证结构体定义:检查
DRV_VESA_VBE_INFO_STRUCT是否严格符合VESA规范,确保modesOff(偏移0x14)和modesSeg(偏移0x16)的位置正确,结构体对齐符合要求。 - 修正BIOS调用参数:执行
INT 10h/AX=4F01h时,设置es:di指向模式信息结构体,并保留当前模式号在cx中:@@displayModeLoop: ; MOV cx, WORD PTR fs:[si] ; CMP cx, 0FFFFH ; JE @@displayModeEndLoop ; MOV ax, cx ; CALL DPT_printNum ; ;--- get mode information ; PUSH cs POP es ; ES指向模式信息结构所在段 MOV di, OFFSET DRV_VESA_modeInfo ; ES:DI指向模式信息缓冲区 MOV ax, 04F01H ; INT 10H ; CX仍为当前模式号 CALL DRV_VESA_bioscallErrorCheck ; ADD si, 2 ; JMP @@displayModeLoop ; @@displayModeEndLoop: ; - 排查内存覆盖问题:确保引导加载程序和内核代码未占用VESA信息块或模式列表的内存区域,可通过BIOS内存映射确认可用区域,或调整结构体的存储位置。
- 调试段地址:添加代码打印
modesSeg和modesOff的值,验证是否为有效内存地址,确认fs段寄存器设置正确。
内容的提问来源于stack exchange,提问作者Maximilian Wittmer
相关产品推荐
相关产品推荐

