一般来说,在Windows上使用qemu时,我们要以uefi方式启动一个镜像是这样的:

qemu-system-x86_64 -drive if=pflash,format=raw,file=/path/to/edk2-x86_64.fd \
                   -drive format=qcow2,file=.\nixos.img

特定目标的edk2固件在qemu的share目录里就有。注意,这种情况下想成功加载固件,需要用-drive的方式,使用-bios会失败。

这种方式在tcg后端下是工作正常的,但tcg毕竟相当于没有加速,性能损失很大,既然我们是开同架构的虚拟机,不利用硬件虚拟化的功能加速就太可惜了。在intel的haxm停止维护之后,我们在windows平台上最好的选择就是使用whpx。

这样一来也就遇到了我们标题中的问题,由于whpx后端几年前并未真正得到OVMF的支持,所以它们预期的行为有些不一致,这涉及使用nvram进行状态保存的问题。简单来说,OVMF固件以一种称为ROMD的存储形式存在,正常来说,在boot阶段,这个存储器里的内容应该被映射到内存中运行,但whpx似乎并不认识这类设备,所以boot时不会进行内存映射,启动就失败了。

有一个补丁解决了这个问题,实现方式是使whpx对ROMD采取与ROM一样的映射方式来启动固件。这个解决方式有争议,同时上游也对这个问题究竟应该由whpx解决还是由qemu解决存在分歧,所以迟迟没有合并,到现在已经一年过去了。如果不想自己编译qemu的话,这种方式还是不用抱希望了。

于是我们还得从OVMF的固件本身上想办法,issue讨论里有人给了有效的方案,即把edk2-vars.fdedk2-code.fd连接成一个文件edk2.fd,相当于把状态也固定到只读文件里,这样whpx就能正常启动了。

我们可以这样子连接,注意文件顺序:

cat edk2-vars.fd edk2-code.fd > edk2.fd

然后我们就可以这样启动,注意这时不能再使用-drive加载pflash,而应该用-bios:

qemu-system-x86_64 -bios /path/to/edk2.fd \
                   -drive format=qcow2,file=.\nixos.img \
                   -accel accel=whpx,kernel-irqchip=off

另外,其实archlinux的包管理网站上现在已经提供了连接好的固件,我们可以方便的下载使用。下载解压后找到相应架构下的OVMF.fd或OVMF.4m.fd即可使用。