From b073d87a566dc4bfe174fc9c83a887ee7a3b622a Mon Sep 17 00:00:00 2001 From: Guofang Date: Fri, 23 Oct 2026 23:17:25 +0800 Subject: [PATCH] Disable the HVF in-kernel irqchip for Windows 11 on macOS and document why With the HVF in-kernel GICv3, QEMU's usb-storage races on the status packet and Windows Setup stalls 10 s after every burst of reads when installing from the ISO (utmapp/UTM#7970). Use the emulated interrupt controller until upstream QEMU gets the fix from the UTM fork. Record the investigation in windows11-arm64-install-speed.md. Co-Authored-By: Claude Sonnet 5.5 --- qemu/windows11-darwin-arm64.ini | 5 ++ windows11-arm64-install-speed.md | 79 ++++++++++++++++++++++++++++++-- 2 files changed, 79 insertions(+), 5 deletions(-) diff --git a/qemu/windows11-darwin-arm64.ini b/qemu/windows11-darwin-arm64.ini index 1470608..8b1b99b 100644 --- a/qemu/windows11-darwin-arm64.ini +++ b/qemu/windows11-darwin-arm64.ini @@ -7,8 +7,13 @@ [accel] accel = "tcg" +# With the HVF in-kernel GICv3, QEMU's usb-storage races on the status packet +# and Windows Setup stalls 10 s after every burst of reads (utmapp/UTM#7970), +# so use the emulated interrupt controller; upstream QEMU only gets the fix +# from the UTM fork. [machine] type = "virt" + kernel-irqchip = "off" # The "virt" machine has no IDE. NVMe and USB mass storage (used by the # installation media of --install-from-iso) both have inbox Windows drivers. diff --git a/windows11-arm64-install-speed.md b/windows11-arm64-install-speed.md index b3f2137..fed43fd 100644 --- a/windows11-arm64-install-speed.md +++ b/windows11-arm64-install-speed.md @@ -5,10 +5,14 @@ ## 结论 -- 慢的原因是**安装介质走了模拟的 USB 光驱**(`usb-storage` 挂 ISO):读安装文件平均只有约 4 MB/s。 -- 把安装介质改成**FAT32 分区里的 NVMe 磁盘镜像**(`install.wim` 拆成 `.swm`)后,读速达到 54 到 92 MB/s - (前 7 个采样平均约 74 MB/s),安装在约 80 秒内到 40%,复制阶段约 2 分钟结束。 -- 方案已接进 `run-windows11.py`:`--install-from-img`,镜像由 `vm-images/build-windows-install-disk.sh` 生成。 +- **根因(第五节)**:HVF 的内核态 GICv3 与 QEMU 的 `usb-storage` 有竞态,Windows Setup 每读一批数据就卡约 10 秒。 + 在 `[machine]` 里加 `kernel-irqchip = "off"`(已写入 `qemu/windows11-darwin-arm64.ini`)后, + **同样走 USB 光驱的 `--install-from-iso` 也变快了**,和 UTM 的速度一致。 +- 下面第一到五节是更早的分析:当时把慢归因于"模拟 USB 光驱吞吐低"(平均约 4 MB/s), + 这个归因不准确,真实原因是上面的 10 秒停顿;那时测到的低吞吐就是停顿拉低的平均值。 +- 把安装介质改成**FAT32 分区里的 NVMe 磁盘镜像**(`install.wim` 拆成 `.swm`,`--install-from-img`)仍然有效, + 因为它绕开了 usb-storage,读速达到 54 到 92 MB/s,镜像由 `vm-images/build-windows-install-disk.sh` 生成。 + 但现在不是必须的。 ## 环境 @@ -158,7 +162,72 @@ vm-images/build-windows-install-disk.sh [--force] ISO [OUTPUT.img] - **显卡**:arm64 配置用 `ramfb`。`virtio-gpu-pci` 会让画面冻结在 "Start boot option"(QEMU 固件的 virtio-gpu 输出在 Windows 引导管理器处冻结)。 - **`-daemonize` 与 Cocoa**:Cocoa 窗口不能和 `-daemonize` 一起用,要看界面只能前台运行。 -## 五、后续(需要决定) +## 五、为什么 UTM 用同样的 USB 光驱却很快 + +现象:同一台机器、同一个 ISO,UTM 里装 Windows 11 Arm 很快,本仓库的 `--install-from-iso` 很慢。 +UTM 和本仓库都是 QEMU + HVF,ISO 也都是 `usb-storage`(UTM 加 `removable=true`,挂在 `nec-usb-xhci` 上),所以设备类型不是原因。 + +### 排查过程 + +1. 在 UTM 里建一台 QEMU 后端的 Windows ARM 虚拟机,用同一个 ISO 启动,再用 + `ps -ww -o args= -p $(pgrep -f QEMULauncher)` 取出完整命令行。UTM 的 QEMU 是 `Frameworks/qemu-aarch64-softmmu.framework` + 里的 dylib,由 `QEMULauncher` 加载(沙盒继承,不能脱离 UTM 单独运行)。 +2. 与本仓库的配置逐项对照,差异有:`-machine virt,gic-version=3`、`-cpu host`、 + `-accel hvf,ipa-granule-size=0x1000`、6 核、系统盘 `discard=unmap,detect-zeroes=unmap`、 + `file.locking=off`、`nec-usb-xhci`、`-nodefaults`、`-rtc base=localtime`、UTM 自己的 UEFI 固件等。 + 把前面几项全部对齐后速度**没有改善**。 +3. 查 UTM 仓库的提交,找到 [95a7f4a2](https://github.com/utmapp/UTM/commit/95a7f4a2) + (PR [#7971](https://github.com/utmapp/UTM/pull/7971),Issue [#7970](https://github.com/utmapp/UTM/issues/7970))。 + +### 根因 + +UTM 5.0.7 启用了 Hypervisor.framework 的内核态 GICv3。这暴露了 QEMU `usb-storage` 的一个竞态: +命令完成时,客户机已经排队的状态包(CSW)被重入处理,请求仍标记为在途,被"挂起"后永远得不到应答。 +Windows 对 USB 存储传输的超时是 10 秒,于是每一批读取之后都会停约 10 秒,随后重置设备并重试。 +这与第一节测到的现象一致:客户机发出的请求很少、主机很闲、读吞吐只有几 MB/s。 + +UTM 记录的"复制文件"阶段耗时(Windows 11 24H2 ARM64,USB CD): + +| 构建 | 耗时 | +|---|---| +| 5.0.6 | 165 秒 | +| 5.0.7(有竞态) | 约 1230 秒 | +| 5.0.7 + `-machine kernel-irqchip=off` | 160 秒 | +| 5.0.7 + 修复补丁 | 约 135 秒 | + +修复补丁在 UTM 的 QEMU fork(`utmapp/qemu@ae92cdc41f`),在完成数据包之前先释放 SCSI 请求。 +UTM 5.0.8 带有这个修复;Homebrew 的 QEMU 11.1.2 没有,所以上游版本会遇到这个问题。 + +### 处理 + +在 `qemu/windows11-darwin-arm64.ini` 的 `[machine]` 加 `kernel-irqchip = "off"`,改用模拟的中断控制器。 +这一项改完后速度明显提升,已确认和 UTM 一致。 + +```ini +[machine] + type = "virt" + kernel-irqchip = "off" +``` + +只验证单项(不改配置文件)时,可以用 `./run-windows11.py --install-from-iso -- -machine virt,kernel-irqchip=off`。 + +### 对齐 UTM 时试过、后来回退的改动 + +对齐 UTM 时一度同时改了下面这些,但只有 `kernel-irqchip=off` 确认有效,其余没有单独验证过,已全部回退: + +- `-machine` 的 `gic-version=3`、`-cpu host`、`-nodefaults`、`-rtc base=localtime`。 +- 安装介质挂在独立的 `nec-usb-xhci` 上,`usb-storage` 加 `removable=true,bus=usb-bus.0`,ISO 的 `-drive` 加 `file.locking=off`。 +- `cpus` 从 8 改为 6,系统盘加 `discard=unmap`、`detect-zeroes=unmap`。 + +没有对齐的:`-accel hvf,ipa-granule-size=0x1000`(UTM 的补丁参数)、UTM 的 `edk2-aarch64-secure-code.fd`、TPM、 +`virtio-rng-pci`、Intel HDA、`virtio-ramfb-gl`、`vmnet-shared`。 + +### 代价与后续 + +- 模拟中断控制器的运行时性能略低于内核态 GIC。若只在安装阶段需要,日常运行可以改回去(去掉 `kernel-irqchip`)。 +- 等上游 QEMU 合入这个 `usb-storage` 修复后,可以去掉这一项。 + +## 六、后续(需要决定) 1. (已完成)`run-windows11.py --install-from-img` 和 `build-windows-install-disk.sh`。 2. 核对 `Autounattend.xml` 的映像序号。