2. BIOS自检(POST)与硬件探测实战

任务目标

使用QEMU虚拟机启动一个最小化系统,通过固件日志与串口输出观察BIOS自检(POST)流程,识别内存容量探测、显卡初始化、键盘控制器检测等硬件探测顺序,并理解各阶段输出信息的含义。

环境准备

  • 安装QEMU:apt-get install qemu-system-x86(Debian/Ubuntu)或 yum install qemu(RHEL/CentOS)
  • 准备一个引导镜像:使用OVMF.fd(UEFI固件)或默认SeaBIOS。本案例使用QEMU默认的SeaBIOS,无需额外下载。
  • 需要gcc和nasm编译一个最小引导扇区,用于触发完整的POST流程。

实现原理与代码

QEMU启动时默认加载SeaBIOS作为固件,执行完整的POST流程。为了观察POST输出,我们编译一个仅包含hlt指令的最小引导扇区,使系统在BIOS完成硬件探测后停在已知状态,便于捕获完整的POST日志。

; boot.asm - 最小引导扇区
BITS 16
ORG 0x7C00

start:
    ; 清屏并显示提示信息
    mov ax, 0x0003
    int 0x10
    
    mov si, msg
print_loop:
    lodsb
    or al, al
    jz done
    mov ah, 0x0E
    int 0x10
    jmp print_loop
    
done:
    ; 停止CPU,等待重启
    cli
    hlt
    jmp done

msg db 'POST completed. System halted.', 0

times 510-($-$$) db 0
dw 0xAA55

编译并制作启动镜像:

nasm -f bin boot.asm -o boot.bin
dd if=/dev/zero of=disk.img bs=512 count=1
dd if=boot.bin of=disk.img conv=notrunc

运行与观察POST输出

使用QEMU的-debugcon参数捕获BIOS调试输出,同时用-serial捕获串口输出:

qemu-system-x86_64 -drive file=disk.img,format=raw -debugcon file:post_log.txt -serial file:serial_log.txt -m 256 -display none

运行后查看post_log.txt,预期输出包含以下关键阶段(顺序固定):

SeaBIOS (version 1.13.0-1ubuntu1.1)
...
Booting from Hard Disk...
Booting from 0000:7c00

同时,在QEMU监视器(Ctrl+Alt+2)中执行info registers可确认CPU已停在hlt指令处。

硬件探测顺序识别

在post_log.txt中,硬件探测顺序体现为以下日志序列:

  1. 内存探测:日志中Ram Size=0x10000000(256MB),对应-m 256参数
  2. 显卡初始化:VGA detected或Display present,随后设置显示模式
  3. 键盘控制器:PS/2 keyboard initialized,对应8042控制器检测
  4. 存储设备枚举:Found 1 disks,识别到虚拟硬盘

要更详细地观察每个设备的探测时序,可添加-d int参数查看中断调用序列,或使用-trace events=acpi*跟踪ACPI表遍历过程。

验证方法

  • 通过条件:post_log.txt中按顺序出现内存容量、显卡、键盘、磁盘的探测记录,且serial_log.txt为空(无错误输出)
  • 功能验证:QEMU监视器中执行info status显示VM status: paused (halted),证明POST完成后系统正确停在引导扇区
  • 对比实验:将-m参数改为512,重新运行,观察Ram Size值变化,确认内存探测与配置一致

常见问题

  • 若post_log.txt为空:确认QEMU版本支持-debugcon,或改用-boot order=a强制从硬盘引导
  • 若未显示键盘初始化:部分QEMU版本默认不启用PS/2控制器,添加-device piix3-usb-uhci或-machine q35可改变设备拓扑
  • 引导扇区无法启动:检查disk.img是否为512字节且以0x55AA结尾,用xxd disk.img | tail -1确认