Windows 10 ARM64 on KVM

之前给大家介绍过利用 QEMU 安装 Windows 10 ARM64,但是单纯用 QEMU 进行安装速度实在是太慢了(装个系统能装一下午),那对于手头上已经有 ARM 硬件(如 RK3399 开发板)的人们来说,利用 KVM 虚拟化就成了个现实的问题。

障碍

  • 老版本 qemu 没有可用的显示设备

VGA 设备及其驱动在 KVM 环境下不能用(这也是它被踢出 ArmVirtPkg 的原因),而 virtio-gpu 的 GOP 不被 Windows 支持,所以没有可用的显示设备,只能把系统装上之后找办法用 RDP 等手段远程访问。

qemu 3.0.0 加入了 ramfb 设备,用一块内存模拟类 VGA 的 Framebuffer,这样 Windows 就有显示输出了(当然还是没有硬件加速)

  • 老版本 Windows 10 (1903-)启动时会导致 KVM 崩溃

其实这是 KVM 的锅。KVM 不支持类似 `str w8,[x10],#4` 的指令,遇到就会崩溃:

error: kvm run failed Function not implemented
PC=fffff80151b52840  SP=ffffd388881edff0
X00=ffffc30f771f37d0 X01=0000000000000004 X02=0000000000000001 X03=fffff80151b530e8
X04=0000000000000018 X05=0000000000000000 X06=000000000000001c X07=0000000000000080
X08=ffffac80360da000 X09=0000000000000100 X10=ffffd388881edf98 X11=0000000000000000
X12=ffffd388881edf98 X13=ffffc30f77180094 X14=ffffc30f77180088 X15=000000000000001c
X16=00007b289058984f X17=ffff585ff7c64971 X18=fffff801b4b10000 X19=0000000000000000
X20=ffffc30f771f37d0 X21=00000000000001e0 X22=0000000000000000 X23=0000000000000000
X24=ffffc30f771f31a0 X25=ffffc30f771f3020 X26=ffffd388881ee0e0 X27=0000000000000000
X28=0000000000000000 X29=ffffd388881edff0 X30=fffff80151b51ebc
PSTATE=60000044 -ZC- EL1t

而正好 Windows 的 pci.sys 等驱动有这样的指令,所以无法在 KVM 上运行。

详细分析请看

这位在微软的大佬帮忙阻止编译器生成这种指令,所以 19H1(准确来说是 18348+)不会有这样的问题。

我曾经 fork 了 qemu 3.0.0 的源码,通过禁用部分功能(主要是 MSIX 支持)绕过带有这种指令的代码,能够启动 Windows 10 Build 17134,但更老的版本没有测试。

  • 虚拟机放在某些核心上时,Windows 会卡在开机画面

对于 RK3399 来说,出问题的是四个小核,用大核就没问题。这可能是内核的 bug。

  • 没有网卡驱动

Windows 10 ARM64 只有 Mellanox 几个网卡(所以谁 pass-though 一个试试)和若干 USB 网卡的驱动。e1000/pcnet 等都没驱动。

更新:virtio-win 0.1.189+的ISO已经包括可用的ARM64 NetKVM驱动。

当然 pass-through 一个网卡总是可以的。PCIe 没条件试,但 USB 可以用。

另外,微软在系统中内置了 e1000 和 virtio-net 用于 KDNET 内核调试的驱动,所以可以通过打开 KDNET 变相联网。

安装

内核建议用比较新的,qemu 3.0 以上(原因上面有讲)。

我用的是 NanoPi M4,系统 Armbian buster,源里的 qemu 是 3.1,dev 5.3-rc4 内核。

安装其实跟在 x86 上没多大区别,我启动 qemu 的命令行如下:

sudo taskset -c 4-5 \
    qemu-system-aarch64 \
        -M virt-2.12 \
        -cpu host -smp 2 \
        -accel kvm \
        -m 1536 \
        -pflash efi.bin -pflash vars.bin \
        -device ramfb \
        -device qemu-xhci \
        -device usb-kbd \
        -device usb-tablet \
        -drive if=virtio,file=hdd.vhd,format=vpc \
        -netdev user,id=net0 \
        -device e1000,netdev=net0 \
        -vnc :0

安装系统时可以把安装 ISO 挂在 usb-storage 上。

efi.bin 是 QEMU_EFI.fd (Debian 包 qemu-efi-aarch64) dd 到 64MiB,vars.bin 是 64MiB 的空文件,这样可以保存 NVRAM 设置。

virtio-win stable 的 ISO 里就有 ARM64 的驱动,viostor 在 ARM64 上已经稳定了,直接用就好。

开启 KDNET

virtio-net 的 NetKVM 驱动已经修复,不再需要靠 KDNET 实现联网。

虚拟机里打开个管理员 CMD,然后执行如下命令:

bcdedit /dbgsettings NET HOSTIP:<调试宿主的IP> PORT:<端口> KEY:<KEY>
bcdedit /set {default} debug on

如果你不是真的要调试,宿主IP可以随便填。否则请对应设置并配置好端口映射。

KEY 可以是任意四个数,中间用点隔开,比如 1.2.3.4。

开机时 Windows 会停下来等待调试器连接,但等待超时后会继续进系统,网络连接依然可用。

虚拟机的网卡可以是 e1000 或 virtio-net,如果是 virtio,请传入 disable-legacy=on 参数,如 -device virtio-net,disable-legacy=on,netdev=net0。

截图

系统属性
任务管理器
ARM64 原生应用:7-zip
ARM64 原生应用:DOSBox-X
ARM64 原生应用:PPSSPP
PPSSPP 运行 PSP demo,没硬件加速居然还能跑到15fps...
ARM64 原生应用:SDLPAL,仙剑的开源复刻
ARM64 原生应用:Filezilla
ARM64 原生应用:Firefox
ARM64 应用:Edge Chromium

编辑于 2020-10-02 23:04