利用 QEMU 在树莓派 5 运行 Windows on Arm
之前尝试过使用树莓派原生运行 Windows on Arm,但是它的驱动体验并不是特别的好。
搜了下相关内容,发现 virtio-win 的镜像其实包含了部分关键组件的 aarch64 驱动,而树莓派 5 看起来也支持内核虚拟化(存在有 /dev/kvm
这个特殊设备),因此就想试试在 x86-64 的操作系统上利用 QEMU 模拟 aarch64,然后再将经验搬到树莓派上。剧透:前者卡到怀疑人生;不过后者倒是一次成功了,且运行速度完全可以接受。
因为在 x86-64 下跑 WoA 太慢了,因此该教程是在 Arch Linux 下通过远程 SSH 进入树莓派操作的。Windows 操作部分则是透过 VNC 和 RDP 连接操作。
准备工作 (客户端)
安装依赖
提前在本机安装一下 VNC 和 RDP 客户端备用即可。
sudo pacman -S --needed remmina libvncserver freerdp
你也可以安装其它的 VNC 客户端。
准备工作 (树莓派)
本文假设你的工作目录为 /woa
。
安装依赖
树莓派的 Raspbian 系统则需要安装多一些包:
sudo apt update -y
sudo apt install --no-install-recommends \
aria2 \
netcat-openbsd \
socat \
qemu-efi-aarch64 \
qemu-system-arm \
qemu-utils
如果希望在树莓派下载、生成系统安装镜像,还需要额外安装下述工具:
sudo apt install \
cabextract \
chntpw \
genisoimage \
wimtools \
unzip
下载安装镜像
访问 uupdump.net 获取 arm64 架构的 Windows 11 镜像。
依次选择版本(如 Windows 11, version 23H2 (22631.3668) arm64
)、语言、系统版本,确保选中「Download and convert to ISO」选项来自动生成 ISO 文件,得到一个 ZIP 格式的压缩包。
使用 scp
将其提交到树莓派:
# 上传 uup.zip 到 IP 为 "1.2.3.4" 的树莓派的 "/tmp" 目录下
scp "uup.zip" 1.2.3.4:/tmp/
然后使用 ssh
进入树莓派,将其解压并开始下载:
# 切换工作目录为 /woa/temp
sudo mkdir -p /woa/temp
cd /woa/temp
# 解压、下载到 /woa/images 下
unzip uup.zip
bash uup_download_linux.sh
# 将镜像文件移动到上级目录 (/woa)
mv *.iso ../
cd ..
# 清理临时下载目录
sudo rm -rf /woa/temp
稍等数分钟后得到 Windows 安装镜像文件到当前目录,
※ 如果你希望不透过浏览器下载,也可以利用 uup id
在终端直接获取该压缩包。
uup_id="bef09951-e4b0-442a-822d-5eb976ec55a8"
uup_lang="en-gb"
curl -o uup.zip "https://uupdump.net/get.php?id=${uup_id}&pack=${uup_lang}&edition=core;professional" \
-H 'Content-Type: application/x-www-form-urlencoded' \
--data-raw 'autodl=2&updates=1&cleanup=1'
下载驱动镜像
下载预编译好的 virtio-win
驱动镜像到当前目录即可:
aria2c -x 2 https://fedorapeople.org/groups/virt/virtio-win/direct-downloads/archive-virtio/virtio-win-0.1.240-1/virtio-win-0.1.240.iso
准备 UEFI 固件
从系统拷贝一份到当前目录备份:
cp /usr/share/qemu-efi-aarch64/QEMU_EFI.fd ./
准备磁盘
为虚拟机建立一个 80G 的空白硬盘做 C 盘用:
qemu-img create disk-C-win11-aarch64.img 80G
安装系统
配置当前终端的一些变量:
※ 如果可以,生成随机的系统 UUID、MAC 地址(MAC 地址建议使用 52:54:00:
前缀)。
system_uuid="f9a7b1a7-2b2c-419e-aa80-e01e71356626"
eth_mac="52:54:00:11:22:33"
woa_iso="22621.1_MULTI_ARM64_EN-GB.ISO"
virt_win_iso="virtio-win-0.1.240.iso"
然后执行 QEMU 来启动安装程序:
qemu-system-aarch64 \
-M virt -m 4G -cpu host -smp cpus=2 \
-bios QEMU_EFI.fd\
--accel kvm \
-device ramfb \
-device qemu-xhci -device usb-kbd -device usb-tablet \
\
-device usb-storage,drive=install \
-drive if=none,id=install,format=raw,media=cdrom,file="${woa_iso}" \
\
-device usb-storage,drive=virtio-drivers \
-drive if=none,id=virtio-drivers,format=raw,media=cdrom,file="${virt_win_iso}" \
\
-drive if=virtio,id=system,format=raw,file=disk-C-win11-aarch64.img \
\
-nic user,model=virtio-net-pci,mac="${eth_mac}" \
-uuid "${system_uuid}" \
\
-vnc :0 \
-monitor tcp:127.0.0.1:4444,server,nowait
如果因为某些原因需要重启(例如使用 VNC 引导,并错过光驱指示),可以利用 socat
操作 QEMU 来进行一些操作:
echo "system_reset" | socat - TCP:127.0.0.1:4444
常见的一些操作指令:
system_reset
- 强制重启system_powerdown
- 强制关机system_wakeup
- 从休眠唤醒
此外,虽然没有对 VNC 端口进行认证保护,但是默认是监听在回路地址,因此也没太大问题。如果需要添加访问认证,请参考官方文档。
执行安装
如果没有使用 SSH 进行端口转发,则应当开一个新的终端并建立端口转发规则:
ssh -L 4444:127.0.0.1:4444 -L 5900:127.0.0.1:5900 1.2.3.4
然后使用 Remmina 通过 VNC 连接 :0
即可(即 5900
端口)。
如果系统现在无法操作(错过光驱引导提示),可以参考上一节的强制重启命令,强制重新引导。
等待下面的画面出现时按下任意按键进入安装程序。这个感应比较慢,可能需要多按几次。
选择语言并点击下一步,然后点击安装即可。
此时会提示激活信息,点击「我没有序列号」跳过:
此时选择版本,根据自己喜好选择,然后点击下一步即可,然后得到一个「该设备不支持 Windows 11」错误提示:
点击安装程序窗口左上角的返回按钮,然后按下 Shift-F10 打开 CMD,然后键入 regedit
并回车打开注册表编辑器。
导航到 HKEY_LOCAL_MACHINE\SYSTEM\Setup
,右键「Setup
」键值 →「新建」→「键」→「LabConfig
」,添加下述内容(DWORD 类型,值为 1
):
BypassCPUCheck
BypassSecureBootCheck
BypassStorageCheck
BypassRAMCheck
BypassTPMCheck
如果不确定,可以参考本节结尾的视频。
应用完注册表更改后,将 CMD 和注册表编辑器关闭即可。此时点击下一步,可以正常继续安装。
选择「自定义安装」,提示选择硬盘。因为使用了基于 virtio 的硬盘,因此点击主窗口的「加载驱动(Load driver)」→ virtio-win 驱动磁盘 → 依次选择 viostor\w11\ARM64
目录 → 点击「确定」。
添加注册表操作和加载驱动操作可以参考下方的短片:
系统初始化
第一次启动会进行系统初始化操作,然后执行「开箱初始化(OOBE)」,其第一步是选择「国家与地区」。
现在的 Windows 11 安装程序会要求联网登录帐号,但此时还没有安装上对应驱动,因此需要绕过。
按下键盘的「Shift
-F10
」来呼出命令行,键入下述内容:
cd oobe
bypassnro
稍等片刻后会自动重启。此时会重新进入「开箱初始化」阶段,根据屏幕上的指示操作即可。提示「连接到网络」时选择「有限设置」即可。
安装驱动
打开文件管理器,依次导航到下述目录:
NetKVM\w11\ARM64
(以太网网络设备)vioserial\w11\ARM64
(串口设备,可选)viorng\w11\ARM64
(随机数设备,-device virtio-rng-pci
,可选)viogpudo\w11\ARM64
(显卡设备,-device virtio-gpu-pci
,可选)
右键对应目录下的 .inf
文件,并选择「安装」,如下操作:
虚拟显卡
ramfb
的默认分辨率是 800x600
,最大 1024x768
,透过 UEFI 固件设定配置。
但是当我尝试储存的时候却无法正常应用,因此需要切换到 virtio-gpu-pci
显卡。
首先确保上一节「安装驱动」部分中安装了 viogpudo
的驱动并关机,然后在终端 QEMU 进程按下 Ctrl-C
退出;更改 QEMU 参数中,将 -device ramfb
更改为 -device virtio-gpu-pci
后重新启动即可应用。
缺点就是 Windows 引导界面无法正常渲染,且导致虚拟机引导 UEFI 界面后断开 VNC 连接,直到 Windows 引导结束后才可以透过 VNC 连接;但感觉图形性能(包括后续使用 RDP 连接)会好一些?也有可能是我的错觉。
使用 RDP 可以绕过分辨率的问题,且能正常拖放文件、复制粘贴。
RDP 远程桌面
RDP 远程桌面的体验会相对更加流畅,因此启用它。
打开「Windows 开始菜单」,检索「Remote Desktop Settings」。
在弹出的设置界面启用它,并展开、禁用「Network Level Authentication」:
RDP 需要设置用户密码。如果尚未设置,可以打开「Windows 开始菜单」,检索「Password」。
展开「密码」项,并点击「添加」:
若尚未配置 QEMU 的端口转发,需要先在 Windows 虚拟机中关机,添加 QEMU 端口转发参数,如下所示:
-nic user,model=virtio-net-pci,mac="${eth_mac}",hostfwd=tcp:0.0.0.0:3389-:3389 \
之后就可以通过树莓派的 IP 直接进行 RDP 连接了。
※ 注意:
- 你也可以删除参数中的
0.0.0.0
使其监听本地地址,要求 SSH 端口转发然后访问; - QEMU 的端口转发仅支持 IPv4。
- 你也可以配置桥接网络,这样就不需要手动配置转发端口了,但这就不是该文的范围了。
已知问题
关机后会残留进程
在 Windows 中使用关机命令,可以看到 QEMU 进程短暂进入 0% 使用率,然后飙升到 100% 不停。
关机后还得记得手动退出 QEMU 进程,有点怪的。
图形加速
图形加速利用 virtio-gpu-pci
设备能够缓解,但是视频解码和 3D 加速性能还是相对比较弱。
期待未来会有 virtio-gpu-rutabaga
可以用吧(目前 Debian 官方软件仓库还没有)。
最终启动脚本
驱动都安装好之后,就不需要加载驱动镜像了。
将最终的启动命令整合到启动脚本,储存到 /woa/woa.sh
方便未来使用:
#!/usr/bin/env bash
# 配置参数
system_uuid="f9a7b1a7-2b2c-419e-aa80-e01e71356626"
eth_mac="52:54:00:11:22:33"
# 启动
qemu-system-aarch64 \
-M virt -m 4G -cpu host -smp cpus=2 \
-bios QEMU_EFI.fd\
--accel kvm \
-device virtio-gpu-pci \
-device virtio-rng-pci \
-device qemu-xhci -device usb-kbd -device usb-tablet \
\
-drive if=virtio,id=system,format=raw,file=disk-C-win11-aarch64.img \
\
-nic user,model=virtio-net-pci,mac="${eth_mac}",hostfwd=tcp:0.0.0.0:3389-:3389 \
-uuid "${system_uuid}" \
\
-vnc :0 \
-monitor tcp:127.0.0.1:4444,server,nowait
如果有需要,也可以建立个简单的 systemd 服务来管理虚拟机状态,本文就不涉及了。
结语
本来还想着在 x86-64 平台下利用 qemu-system-aarch64
全虚拟化模拟执行,但是效率实在是太低了,而且 OOBE 会无法正常加载,导致无法完成安装。
不过相比直接在树莓派上运行 WoA,又好一些 - 因为风扇会根据当前负载来运作,而非一直满速运转。
VNC 界面有一点很烦,我也没搞懂怎么映射某些按键,结果就是反斜杠「\
」无法正常输入。使用 RDP 远程连接则没有这个问题。