WHPX: unconditional kernel-irqchip=off prevents VM boot on Windows ARM64

Open Beginner friendly
#34 1 comment 0 reactions 0 assignees View on GitHub

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

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

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

More from microsoft/quicksand

All issues in microsoft/quicksand

Similar issues

More Python issues

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.