You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Qemu自制BIOS写入0xB8000显存无显示问题排查

问题

作为学术实践,我正在为Qemu编写一个简单的Hello World BIOS,已使Qemu识别显示初始化完成,但启动后仅显示黑屏,向字符视频内存0xB8000写入数据无效果。我已配置PCI插槽、设置VGA寄存器为80x25文本模式并启用显示,请问遗漏了什么?为何显存写入无法在屏幕呈现结果?以下是我目前编写的NASM汇编代码:

[BITS 16]
times 4194304 - 2000 db 0x00
_jmpTo:

;Configure the VGA's PCI slot (hardcoded for now)

mov eax, 0x80001004
mov dx, 0x0CF8
out dx, eax

mov dx, 0x0CFC
in eax, dx

or eax, 0x0000037F
and eax, 0xFFFFFFFE
or eax, 0x00000002
mov dx, 0x0CFC
out dx, eax

mov eax, 0x80001008
mov dx, 0x0CF8
out dx, eax

mov dx, 0x0CFC
in eax, dx
and eax, 0x0000FFFF
or eax, 0x03000000
out dx, eax


;map BARS

mov eax, 0x80001010
mov dx, 0x0CF8
out dx, eax

mov dx, 0x0CFC
in eax, dx
or eax, 0xe0000000
out dx, eax

mov eax, 0x80001018
mov dx, 0x0CF8
out dx, eax

mov dx, 0x0CFC
in eax, dx
or eax, 0xe1000000
out dx, eax

mov eax, 0x80001030
mov dx, 0x0CF8
out dx, eax

mov dx, 0x0CFC
in eax, dx
or eax, 0xB0000001
out dx, eax



;Set VGA Config Registers via I/O

mov dx, 0x03DA
in eax, dx
mov dx, 0x03C0
mov al, 0x10
out dx, al
mov al, 0x0C
out dx, al

mov dx, 0x03DA
in eax, dx
mov dx, 0x03C0
mov al, 0x11
out dx, al
mov al, 0x00
out dx, al

mov dx, 0x03DA
in eax, dx
mov dx, 0x03C0
mov al, 0x12
out dx, al
mov al, 0x0F
out dx, al

mov dx, 0x03DA
in eax, dx
mov dx, 0x03C0
mov al, 0x13
out dx, al
mov al, 0x08
out dx, al

mov dx, 0x03DA
in eax, dx
mov dx, 0x03C0
mov al, 0x14
out dx, al
mov al, 0x00
out dx, al

mov dx, 0x03C2
mov al, 0x67
out dx, al

mov dx, 0x03C4
mov al, 0x00
out dx, al
mov dx, 0x03C5
mov al, 0x01
out dx, al

mov dx, 0x03C4
mov al, 0x01
out dx, al
mov dx, 0x03C5
mov al, 0x00
out dx, al

mov dx, 0x03C4
mov al, 0x02
out dx, al
mov dx, 0x03C5
mov al, 0x03
out dx, al

mov dx, 0x03C4
mov al, 0x04
out dx, al
mov dx, 0x03C5
mov al, 0x0A
out dx, al

mov dx, 0x03C4
mov al, 0x00
out dx, al
mov dx, 0x03C5
mov al, 0x03
out dx, al

mov dx, 0x03CE
mov al, 0x05
out dx, al
mov dx, 0x03CF
mov al, 0x00
out dx, al

mov dx, 0x03CE
mov al, 0x06
out dx, al
mov dx, 0x03CF
mov al, 0x03
out dx, al

;disable write protect
mov dx, 0x03D4
mov al, 0x11
out dx, al
mov dx, 0x03D5
mov al, 0x00
out dx, al

;crct
mov dx, 0x03D4
mov al, 0x00
out dx, al
mov dx, 0x03D5
mov al, 0x5F
out dx, al

mov dx, 0x03D4
mov al, 0x01
out dx, al
mov dx, 0x03D5
mov al, 0x4F
out dx, al

mov dx, 0x03D4
mov al, 0x02
out dx, al
mov dx, 0x03D5
mov al, 0x50
out dx, al

mov dx, 0x03D4
mov al, 0x03
out dx, al
mov dx, 0x03D5
mov al, 0x82
out dx, al

mov dx, 0x03D4
mov al, 0x04
out dx, al
mov dx, 0x03D5
mov al, 0x55
out dx, al

mov dx, 0x03D4
mov al, 0x06
out dx, al
mov dx, 0x03D5
mov al, 0xB5
out dx, al

mov dx, 0x03D4
mov al, 0x07
out dx, al
mov dx, 0x03D5
mov al, 0x0D
out dx, al

mov dx, 0x03D4
mov al, 0x08
out dx, al
mov dx, 0x03D5
mov al, 0x00
out dx, al

mov dx, 0x03D4
mov al, 0x09
out dx, al
mov dx, 0x03D5
mov al, 0x0F
out dx, al

mov dx, 0x03D4
mov al, 0x0A
out dx, al
mov dx, 0x03D5
mov al, 0x0E
out dx, al

mov dx, 0x03D4
mov al, 0x0B
out dx, al
mov dx, 0x03D5
mov al, 0x0F
out dx, al

mov dx, 0x03D4
mov al, 0x0C
out dx, al
mov dx, 0x03D5
mov al, 0x00
out dx, al

mov dx, 0x03D4
mov al, 0x0D
out dx, al
mov dx, 0x03D5
mov al, 0x00
out dx, al

mov dx, 0x03D4
mov al, 0x0E
out dx, al
mov dx, 0x03D5
mov al, 0x00
out dx, al

mov dx, 0x03D4
mov al, 0x0F
out dx, al
mov dx, 0x03D5
mov al, 0x00
out dx, al

mov dx, 0x03D4
mov al, 0x10
out dx, al
mov dx, 0x03D5
mov al, 0x90
out dx, al

mov dx, 0x03D4
mov al, 0x11
out dx, al
mov dx, 0x03D5
mov al, 0x8C
out dx, al

mov dx, 0x03D4
mov al, 0x12
out dx, al
mov dx, 0x03D5
mov al, 0xAF
out dx, al

mov dx, 0x03D4
mov al, 0x13
out dx, al
mov dx, 0x03D5
mov al, 0x28
out dx, al

mov dx, 0x03D4
mov al, 0x14
out dx, al
mov dx, 0x03D5
mov al, 0x07
out dx, al

mov dx, 0x03D4
mov al, 0x15
out dx, al
mov dx, 0x03D5
mov al, 0x9C
out dx, al

mov dx, 0x03D4
mov al, 0x16
out dx, al
mov dx, 0x03D5
mov al, 0xE3
out dx, al

mov dx, 0x03D4
mov al, 0x17
out dx, al
mov dx, 0x03D5
mov al, 0xE3
out dx, al


;mode control
mov dx, 0x03da
in al, dx     
mov al, 0x10
mov dx, 0x03c0
out dx, al 
mov al, 0x20
out dx, al


mov dx, 0x03C6
mov al, 0xFF
out dx, al

;enable display

mov dx, 0x03da
in al, dx     
mov al, 0x20
mov dx, 0x03c0
out dx, al 



mov ax, 0xB800
mov es, ax
mov di, 0x0000
mov al, 0x41
mov ah, 0x07
mov [es:di], ax



_loop:
jmp _loop
hlt

times (4194304 - ($-$$) - 16) db 0x00

_main:
jmp _jmpTo
_end:

times (4194304 - ($-$$)) db 0x00
分析与解决

你的代码存在几个关键问题,导致显存写入无法显示:

  • BIOS入口位置错误:Qemu会从BIOS ROM的最后16字节区域加载执行入口,而你的_main标签放在了文件末尾的填充区之后,实际执行的是前面的空数据,而非初始化代码。必须将入口跳转指令放在ROM最后16字节的范围内。
  • 缺少BIOS ROM签名:标准BIOS ROM的最后两个字节必须是0x55AA,这是Qemu识别有效BIOS的标志,缺失会导致代码无法正确执行。
  • VGA寄存器手动配置不可靠:硬编码所有VGA寄存器容易出现配置冲突或遗漏,更稳妥的方式是调用VGA BIOS中断INT 0x10来设置80x25文本模式,该中断会自动完成所有必要的寄存器初始化。

修正后的代码

[BITS 16]
ORG 0x0000  ; BIOS ROM起始地址

; 主入口:跳转到初始化代码
_main:
    jmp _start

; 填充到ROM最后16字节前的位置,确保入口在正确区域
times (4194304 - 16 - ($-$$)) db 0x00

_start:
    ; 调用VGA BIOS中断设置80x25彩色文本模式
    mov ah, 0x00
    mov al, 0x03
    int 0x10

    ; 写入字符'A'到显存起始位置(黑底白字)
    mov ax, 0xB800
    mov es, ax
    mov di, 0x0000
    mov al, 'A'
    mov ah, 0x07
    mov [es:di], ax

    ; 设置光标到屏幕左上角(0,0)
    mov ah, 0x02
    mov bh, 0x00  ; 第0页
    mov dh, 0x00  ; 行号
    mov dl, 0x00  ; 列号
    int 0x10

; 无限循环
_loop:
    jmp _loop
    hlt

; 填充剩余空间并添加BIOS签名(最后两个字节必须为0x55AA)
times (4194304 - 2 - ($-$$)) db 0x00
dw 0xAA55  ; 小端序存储,对应内存最后两字节为0x55AA

内容的提问来源于stack exchange,提问作者Matthias Birkemeier

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.12 03:59:50