跳至内容

Jixun's Blog 填坑还是开坑,这是个好问题。

利用 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 文件,并选择「安装」,如下操作:

右键选择 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 并禁用 NLA 认证选项。

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 远程连接则没有这个问题。


参考资料

知识共享许可协议 本作品采用知识共享署名-相同方式共享 4.0 国际许可协议进行许可。

评论区