3. 使用QEMU运行UEFI程序

任务目标

本案例将完成一个最小可复现的UEFI程序运行闭环:使用QEMU模拟器加载OVMF(UEFI固件),运行上一案例编译生成的UEFI应用程序,并在串口终端观察程序输出。通过本案例,你将掌握UEFI程序在无真实硬件环境下的验证方法。

环境准备

需要以下软件包(以Ubuntu 22.04为例):

  • QEMU:apt install qemu-system-x86
  • OVMF:apt install ovmf(安装后固件位于 /usr/share/OVMF)
  • 构建工具:上一案例已完成的EDK II构建环境及编译产物

OVMF固件说明

OVMF是UEFI固件的开源实现,作为QEMU的固件层。安装后包含两个关键文件:

  • OVMF_CODE.fd:UEFI固件主体(只读)
  • OVMF_VARS.fd:UEFI变量存储区(可写副本)

运行前需将变量文件复制为可写副本,避免污染系统默认文件。

运行步骤

假设上一案例编译生成的UEFI应用位于 Build/MdeModule/DEBUG_GCC5/X64/HelloWorld.efi(路径以实际构建配置为准)。执行以下命令:

1. 准备变量存储副本

cp /usr/share/OVMF/OVMF_VARS.fd ./OVMF_VARS_copy.fd

2. 制作启动镜像

UEFI应用需要放在FAT格式的磁盘镜像中才能被固件识别。使用dd和mkfs.vfat创建:

dd if=/dev/zero of=uefi_disk.img bs=1M count=64
mkfs.vfat uefi_disk.img
# 挂载并拷贝EFI应用(需要root权限)
mkdir -p /mnt/uefi
mount uefi_disk.img /mnt/uefi
mkdir -p /mnt/uefi/EFI/BOOT
cp Build/MdeModule/DEBUG_GCC5/X64/HelloWorld.efi /mnt/uefi/EFI/BOOT/BOOTX64.EFI
umount /mnt/uefi

3. 启动QEMU

qemu-system-x86_64 \
  -drive if=pflash,format=raw,readonly=on,file=/usr/share/OVMF/OVMF_CODE.fd \
  -drive if=pflash,format=raw,file=./OVMF_VARS_copy.fd \
  -drive if=ide,format=raw,file=uefi_disk.img \
  -nographic

验证方法

启动后QEMU会进入UEFI Shell。由于-nographic将串口重定向到当前终端,你应看到:

  1. OVMF固件启动日志(包含TianoCore版本信息)
  2. UEFI Shell提示符 Shell>
  3. Shell自动执行启动脚本,加载 EFI/BOOT/BOOTX64.EFI,屏幕显示程序输出

通过条件:终端出现上一案例中HelloWorld.c里Print函数输出的字符串(例如 Hello UEFI World!),且Shell无报错信息。

常见问题

  • 无法进入Shell:确认OVMF路径正确,且OVMF_VARS_copy.fd已创建。
  • 找不到启动设备:确认磁盘镜像已正确格式化为FAT且EFI文件路径为 \EFI\BOOT\BOOTX64.EFI。
  • 串口无输出:尝试去掉-nographic改用-serial stdio,并观察图形窗口。

本案例验证了UEFI应用从编译到运行的最小闭环。后续案例将在此基础上扩展更复杂的UEFI功能开发。