feat(aarch64): add WHP backend for ARM64 Windows#1638
Conversation
Implement the WHP hypervisor backend for aarch64 Windows, enabling
hyperlight to run micro-VMs on Windows ARM64 systems.
Changes:
- Restructure whp.rs into whp/ directory (whp/mod.rs + whp/x86_64.rs)
to support per-architecture implementations (matching kvm/mshv pattern)
- Add whp/aarch64.rs with full VirtualMachine trait implementation:
- Manual FFI bindings for ARM64 WHP register names, exit reasons, and
exit context layout (from Windows SDK WinHvPlatformDefs.h)
- Run loop handling MMIO-based I/O (ARM64 has no IO ports)
- Register get/set via WHvGet/SetVirtualProcessorRegisters
- Surrogate process support (same pattern as x86_64)
- Wire WhpVm into hyperlight_vm/aarch64.rs for Windows platform
- Fix super::x86_64::hw_interrupts path after directory restructure
Resolves: hyperlight-dev#1544
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copilot-Session: 6f20a05d-6bee-4e2e-b320-12f8d9759bbc
Signed-off-by: cshung <3410332+cshung@users.noreply.github.com>
- Move vmm-sys-util to unix-only dependencies (it doesn't compile on Windows) - Fix WHV_UINT128 field access (requires Anonymous wrapper on windows crate) - Add CpuVendor::current() for aarch64 Windows target - Remove redundant partition_handle inherent method and unused cancelled field - Fix unused import warnings - Add #[allow(dead_code)] on exit reason constants module Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Copilot-Session: 6f20a05d-6bee-4e2e-b320-12f8d9759bbc Signed-off-by: cshung <3410332+cshung@users.noreply.github.com>
There was a problem hiding this comment.
Pull request overview
Adds a Windows Hypervisor Platform (WHP) backend for Windows/aarch64 so Hyperlight can run micro-VMs on ARM64 Windows systems, aligning WHP’s structure with existing per-arch hypervisor layouts.
Changes:
- Introduces
whp/aarch64.rsimplementing theVirtualMachinetrait for ARM64 WHP, including MMIO-based exit handling and register get/set viaWHvGet/SetVirtualProcessorRegisters. - Restructures the WHP backend into
whp/with per-architecture modules and fixes x86_64 interrupt helper module paths. - Wires WHP into the aarch64 Hyperlight VM path on Windows and moves
vmm-sys-utilinto unix-only dependencies to fix Windows builds.
Reviewed changes
Copilot reviewed 6 out of 6 changed files in this pull request and generated 5 comments.
Show a summary per file
| File | Description |
|---|---|
| src/hyperlight_host/src/sandbox/snapshot/file/config.rs | Adds Windows/aarch64 CPU vendor token for snapshot config. |
| src/hyperlight_host/src/hypervisor/virtual_machine/whp/x86_64.rs | Updates hw_interrupts module paths after WHP directory restructure. |
| src/hyperlight_host/src/hypervisor/virtual_machine/whp/mod.rs | New per-arch WHP module dispatcher (x86_64 vs aarch64). |
| src/hyperlight_host/src/hypervisor/virtual_machine/whp/aarch64.rs | New ARM64 WHP backend implementation and manual ARM64 WHP FFI bindings. |
| src/hyperlight_host/src/hypervisor/hyperlight_vm/aarch64.rs | Selects WHP on Windows/aarch64 and adds Windows interrupt handle wiring. |
| src/hyperlight_host/Cargo.toml | Makes vmm-sys-util unix-only to avoid Windows compilation failures. |
| return Ok(VmExit::IoOut( | ||
| port as u16, | ||
| (off as u64).to_le_bytes().to_vec(), | ||
| )); |
| let fpsr = self.get_reg64(WHV_ARM64_REGISTER_FPSR).map_err(|_| { | ||
| RegisterError::GetFpu(super::super::HypervisorError::WindowsError( | ||
| windows_result::Error::from_hresult(HRESULT(0)), | ||
| )) | ||
| })? as u32; | ||
| let fpcr = self.get_reg64(WHV_ARM64_REGISTER_FPCR).map_err(|_| { | ||
| RegisterError::GetFpu(super::super::HypervisorError::WindowsError( | ||
| windows_result::Error::from_hresult(HRESULT(0)), | ||
| )) | ||
| })? as u32; |
| self.set_reg64(WHV_ARM64_REGISTER_FPSR, fpu.fpsr as u64) | ||
| .map_err(|_| { | ||
| RegisterError::SetFpu(super::super::HypervisorError::WindowsError( | ||
| windows_result::Error::from_hresult(HRESULT(0)), | ||
| )) | ||
| })?; | ||
| self.set_reg64(WHV_ARM64_REGISTER_FPCR, fpu.fpcr as u64) | ||
| .map_err(|_| { | ||
| RegisterError::SetFpu(super::super::HypervisorError::WindowsError( | ||
| windows_result::Error::from_hresult(HRESULT(0)), | ||
| )) | ||
| })?; |
| let module = unsafe { LoadLibraryA(s!("winhvplatform.dll"))? }; | ||
| let proc = unsafe { GetProcAddress(module, s!("WHvMapGpaRange2")) }; | ||
| match proc { | ||
| Some(f) => Ok(unsafe { std::mem::transmute(f) }), | ||
| None => { | ||
| unsafe { | ||
| windows::Win32::Foundation::FreeLibrary(module).ok(); | ||
| } | ||
| Err(windows_result::Error::from_hresult(HRESULT(-1))) | ||
| } |
| // Windows does not expose MIDR_EL1 directly; use a fixed vendor | ||
| // string. All current Windows ARM64 devices use Qualcomm/ARM cores. |
| #[cfg(all(target_arch = "aarch64", target_os = "windows"))] | ||
| { | ||
| // Windows does not expose MIDR_EL1 directly; use a fixed vendor | ||
| // string. All current Windows ARM64 devices use Qualcomm/ARM cores. |
There was a problem hiding this comment.
This is not true---the surface laptop ultra uses an NVidia SoC.
However, the reason why we differentiate Intel and AMD for x86-64 is that they have totally different virtualisation extensions (VT-x vs AMD-v), which have significantly different capabilities/interfaces. This is not the case on aarch64, so I don't necessarily think that we need to record the cpu implementor at all in that case. Instead, if we rely on specific FEAT_x or other capabilities, we can introduce specific feature bits for those capabilities in the future.
Summary
Implements the WHP (Windows Hypervisor Platform) hypervisor backend for aarch64, enabling hyperlight to run micro-VMs on Windows ARM64 systems.
Resolves #1544
Changes
Structural
whp.rsintowhp/directory (mod.rs+x86_64.rs) to support per-architecture implementations, matching the existingkvm/andmshv/patternsuper::x86_64::hw_interruptsmodule path after directory restructureNew:
whp/aarch64.rsWinHvPlatformDefs.h)VirtualMachinetrait implementation with:WHvGet/SetVirtualProcessorRegistersIntegration
WhpVmintohyperlight_vm/aarch64.rsfor Windows platformWindowsInterruptHandlefor aarch64 WindowsCpuVendor::current()for aarch64 Windows targetCross-compilation fix
vmm-sys-utilto unix-only dependencies (it doesn't compile on Windows)Verification
Verified compilation on three targets:
just clippy debug/releasepasscargo checkpassescargo check --features kvmpassesWhy manual FFI bindings?
The
windowscrate (v0.62) does not expose ARM64 WHP types (register names, exit reasons, exit context structs). All definitions were extracted from the Windows SDK headerWinHvPlatformDefs.h(SDK 10.0.26100.0) which has full ARM64 support behind#ifdef _ARM64_.