WHPX: unconditional kernel-irqchip=off prevents VM boot on Windows ARM64
Nobody has claimed this yet.
Assessment
- Difficulty
- 2/5
- Estimated time
- 1-3 hours
- Newbie friendliness
- 78/100
- Issue type
- Bug
- Clarity
- Clearly specified
- Activity status
- Quiet
- Tech stack
- python
- Domain
- infrastructure, operating-systems
Research direction
Start in quicksand_core/qemu/platform.py around line 224 and inspect the Architecture definitions used by self.arch.arch_type. Reproduce the bundled QEMU WHPX command on ARM64, then verify that the generated command omits kernel-irqchip=off on ARM while preserving the existing x86_64 behavior and allowing the VM to boot.
Written by the indexing model from the issue text.
Description
Summary
quicksand_core/qemu/platform.py appends kernel-irqchip=off to the WHPX accelerator argument
unconditionally. QEMU rejects that on aarch64 hosts, so Quicksand cannot start a VM at all on Windows
ARM64, even though WHPX is available and the aarch64 guest images exist.
The failure surfaces as VM process exited unexpectedly (exit code: 1) with an empty QEMU stderr, which
makes it quite hard to trace back to the accelerator flag.
Repro
quicksand_core-0.12.1, quicksand-qemu 0.5.10, quick-sandbox 0.11.15
QEMU 10.2.92 (v11.0.0-rc2), Python 3.12.10 (ARM64)
Windows 11 Enterprise 26200, Snapdragon X (Surface Pro 11), WHPX enabled
Minimal reproduction with the bundled QEMU — current behaviour:
$ qemu-system-aarch64.exe -machine virt -accel "whpx,kernel-irqchip=off" -cpu max -m 512 \
-display none -nodefaults -no-user-config -S -monitor none -serial none
qemu-system-aarch64.EXE: -accel whpx,kernel-irqchip=off: WHPX: on Arm, only kernel-irqchip=on is currently supported
qemu-system-aarch64.EXE: -accel whpx,kernel-irqchip=off: failed to initialize whpx: Invalid argument
EXIT=1
Same command without the flag — initializes fine and stays paused at -S:
$ qemu-system-aarch64.exe -machine virt -accel whpx -cpu max -m 512 \
-display none -nodefaults -no-user-config -S -monitor none -serial none
(no output; process running)
Cause
quicksand_core/qemu/platform.py (0.12.1), around line 224:
if accelerator:
accel_arg = accelerator.value
if accelerator == Accelerator.WHPX:
# kernel-irqchip=off routes interrupts through userspace. WHPX's
# in-kernel irqchip combined with the guest's noapic boot param
# (our IO-APIC workaround) delivers device interrupts unreliably:
# later `mount -t cifs` operations hang in the guest kernel until
# they time out. This was previously only applied when nested
# (baseboard == "Microsoft Corporation"), but bare-metal Windows
# hosts need it too, so apply it for WHPX unconditionally.
accel_arg = "whpx,kernel-irqchip=off"
cmd.extend(["-accel", accel_arg])
As the comment itself explains, this is a workaround for the x86 noapic boot parameter
(WindowsConfig.extra_kernel_params returns ["noapic"], an IO-APIC concept that doesn't apply to the
Arm virt machine). On Arm it isn't needed, and QEMU refuses it outright.
Suggested fix
Scope the flag to x86_64. arch_type is already the module's idiom for this
(self.arch.machine_type, self.arch.qemu_suffix, etc.), but note that Architecture is not currently
imported in platform.py — only ArchitectureConfig, BaseArchitectureConfig and MachineType are.
from .arch import (
+ Architecture,
ArchitectureConfig,
BaseArchitectureConfig,
MachineType,
)
if accelerator:
accel_arg = accelerator.value
if accelerator == Accelerator.WHPX:
# kernel-irqchip=off routes interrupts through userspace. WHPX's
# in-kernel irqchip combined with the guest's noapic boot param
# (our IO-APIC workaround) delivers device interrupts unreliably:
# later `mount -t cifs` operations hang in the guest kernel until
# they time out. This was previously only applied when nested
# (baseboard == "Microsoft Corporation"), but bare-metal Windows
# hosts need it too, so apply it for WHPX unconditionally.
- accel_arg = "whpx,kernel-irqchip=off"
+ # Arm hosts only support kernel-irqchip=on, and the noapic
+ # workaround above is x86-only, so scope this to x86_64.
+ if self.arch.arch_type == Architecture.X86_64:
+ accel_arg = "whpx,kernel-irqchip=off"
cmd.extend(["-accel", accel_arg])
x86_64 behaviour is byte-identical — the flag is still applied there.
Verified
With that change applied to 0.12.1 in a local venv, a full boot on Windows ARM64 succeeds with hardware
acceleration:
VM config: memory=6G, cpus=1, port_forwards=10 ports
VM started successfully (~5s)
Init setup complete.
QuicksandBrowserManager ready: 5 slots
QEMU command line becomes -accel whpx -machine virt, and the guest boots at hardware speed rather than
falling back to TCG. This was via magentic-ui's Quicksand sandbox, using the published
quicksand-cua==0.3.11 / quicksand-agent==0.4.9 / quicksand-ubuntu==0.9.11 win_arm64 fat wheels —
so no new images are needed; the existing ARM64 image chain works as-is once the accelerator flag is fixed.
Separate, optional observation — please treat independently
A few lines above, WHPX is missing from the hardware-acceleration tuple:
has_hw_accel = accelerator in (Accelerator.KVM, Accelerator.HVF)
cmd.extend(self.arch.build_cpu_args(has_hw_accel))
so WHPX never gets -cpu host and falls back to default_cpu_model.
This is not required to fix the bug above — on ARM64 the fallback is "max", which is in WHPX's accepted
set (cortex-a53, cortex-a57, host, max), and the VM boots fine with it (verified at ~5s).
I'm flagging it only because it looks unintentional. It does change x86 behaviour, so it needs your
testing rather than a blind fix: X86_64Config.default_cpu_model is "", meaning build_cpu_args currently
emits no -cpu argument at all for WHPX on x86. Adding Accelerator.WHPX to that tuple would start
emitting -cpu host there. I have no x86 Windows host to validate that on, so I'd suggest keeping it as a
separate commit from the blocker fix above.
(For what it's worth, adding it on ARM64 works — -accel whpx -cpu host boots correctly.)
Context
Found while testing whether MagenticLite's desktop build can run on Windows ARM64. Happy to test any patch
on this hardware — just ping me.
- Dominant language
- Python
- Stars
- 52
- Forks
- 7
- Avg merge
- 3d 9h
- Merged PRs (30d)
- 5
Contributor guide
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
More from microsoft/quicksand
-
Difficulty 3/5 1-2 days Newbie friendliness 52/100
-
Difficulty 4/5 3-5 days Newbie friendliness 48/100
-
Difficulty 4/5 3-5 days Newbie friendliness 35/100
All issues in microsoft/quicksand
Similar issues
-
Difficulty 2/5 1-3 hours Newbie friendliness 88/100
-
Difficulty 2/5 1-3 hours Newbie friendliness 82/100
-
Difficulty 2/5 1-3 hours Newbie friendliness 78/100
-
enhancement
Difficulty 2/5 1-3 hours Newbie friendliness 72/100
-
Difficulty 2/5 1-3 hours Newbie friendliness 74/100