nicolasyang's blog
macOS 下用 qemu 跑 windows 虚拟机
在 macOS catalina 下,用 qemu-hvf 跑 windows 10 虚拟机

现在 macOS 上的免费的虚拟机里面, virtualbox 性能很差,vmware player 功能有限,就想看一下 qemu 有没有 hypervisor.framework 的移植,一查还真的有,还是稳定支持。

折腾了一下,没把 libvirt 配置起来,识别不到 qemu, 但直接用 qemu 也是可以的嘛。

安装

Macports

sudo port install qemu

其它包管理器

homebrew, fink 都有对应的包。

创建磁盘镜像

qemu-img create -f qcow2 /path/to/img.qcow2 64G

安装光盘

  1. 从微软网站上下载 Windows 10 的安装光盘
  2. 从 fedora 网站上下载 virtio 的 windows 驱动光盘

启动命令

qemu-system-x86_64 \
	-accel hvf \
	-machine q35 \
	-cpu Nehalem,hv-relaxed,hv-vapic,hv-runtime,hv-time,hv-tlbflush,hv-frequencies \
        -smp 2 \ -m 4G \
	-rtc base=localtime \
	-vga virtio \
	-usb -device usb-tablet \
	-drive file=/path/to/img.qcow2,format=qcow2,if=none,id=sda,aio=threads,cache=none,discard=unmap	-device virtio-scsi-pci,id=scsi0 -device scsi-hd,rotation_rate=1,drive=sda	\
	-netdev user,id=nic0 -device virtio-net,netdev=nic0 \
	-monitor stdio \
	-drive file=windows.iso,media=cdrom -drive file=virtio-win.iso,media=cdrom

可以保存成一个 shell 脚本。

解释

  • -accel hvf 指定使用 hypervisor.framework 加速
  • -machine q35 指定模拟的主板,q35 模拟 2007 年的 ICH9 南桥,特点为使用 PCIe 总线。如果不指定这个选项,默认会模拟一款 90 年代的设备,会大量使用 PCI/ISA 总线,在现代操作系统上很可能运行不起来。
  • -cpu Nehalem 指定模拟的 CPU 架构。由于是使用 hypervisor.framework 加速的,所以这里指定的 CPU 实际上只是传递给 guest 的型号信息,并不实际执行模拟工作。这个里指定的型号不能带有 hypervisor.framework 不支持的特性。我试出来最新能支持的就是 Nehalem 了。这里指定成 hostmax 都不行,会在 windows 安装过程中产生蓝屏
  • -rtc localtime 众所周知,windows 的 rtc 是用本地时钟的
  • -vga virtio 显卡,virtio 是 VGA 兼容的,就算没有驱动,也可以运行起来。实际上 macports 版本的 qemu 也没有把 opengl 编译进去,所以 virtio 也用不了 3D 加速,和指定为 vga 应该没什么区别。
  • -usb 启用 USB 控制器,-device usb-tablet 模拟一个 USB 触摸屏。由于 usb tablet 使用绝对坐标,模拟 usb tablet 可以让鼠标“无缝”移动。
  • -drive 指定了磁盘镜像的文件和类型,同时禁用缓存(guest 操作系统会自己缓存,没必要重复缓存)、启用 TRIM、使用多线程模拟异步I/O (mac os 上只支持这种方式),最后还有 if=none 让磁盘不要连接到自动生成的总线上。id=sda 是磁盘的名字,可以给后面的配置项引用
  • -device virtio-scsi-pci,id=scsi0 配置一个 virtio 实现的 SCSI 控制器
  • -device scsi-hd,rotation_rate=1,drive=sda 在 SCSI 控制器上配置一个硬盘,并把刚才的磁盘镜像配置到这个硬盘上。rotation_rate=1 让 guest 操作系统能把它识别为 SSD.
  • -netdev user,id=nic0 配置一个用户空间模拟(就是由 qemu 进程模拟)的网卡,-device virtio-net,netdev=nic0 把这个网卡通过 virtio 暴露给虚拟机
  • -monitor stdio 通过 stdio 提供 monitor 接口。monitor 接口可以用来向虚拟机发送 ACPI 关机、RESET 之类的操作
  • -drive file=windows.iso,media=cdrom -drive file=virtio-win.iso,media=cdrom 模拟两个光驱,分别是 windows 安装光盘和 virtio 驱动光盘

安装

启动后 windows 安装程序开始会找不到硬盘(因为没有 virtio 驱动),只要点加载驱动就可以了。

安装后

驱动

启动后需要到设备管理器里面给 virtio 网卡、显卡更新驱动。

安装完驱动后,就可以从启动脚本里面,把两个光驱的参数删除了。

时钟

Windows 默认使用 TSC 时钟,在虚拟机下是不准确的。可以在管理员权限的 powershell 下执行

bcdedit /set '{default}' USEPLATFORMCLOCK on

来把时钟源切换到 RTC.

后记

其实虚拟 I/O 设备的模拟,是分成两个部分的。一部分是在 Host 端,要怎么模拟虚拟设备的功能,如 -drive 用 qcow2 文件的读写来模拟磁盘的读写;另一部分是在 guest 端,怎么模拟设备的接口,比如 -device scsi-hd 用 SCSI 接口来提供对虚拟磁盘的访问。同样,-netdev-device virtio-net 也是一对。

搞清楚这个后,手写 qemu 命令也并不复杂。

参考资料

Updates:

  • qemu-img--fromat 选项应为 -f
  • qemu-system-x86_64 命令行需要用 -smp 指定核心数,-m 指定内存大小
  • -cpu 参数增加 paravirtualization 特性

最后修改于 2021-10-15

Comments powered by Disqus