Skip to content

Commit 404a655

Browse files
cshungCopilot
andcommitted
feat(aarch64): add WHP backend for ARM64 Windows
Implements the WHP hypervisor backend for aarch64, enabling Hyperlight to run micro-VMs on Windows ARM64 systems with Hyper-V. 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>
1 parent f3aab80 commit 404a655

11 files changed

Lines changed: 1104 additions & 19 deletions

File tree

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
# yaml-language-server: $schema=https://json.schemastore.org/github-workflow.json
2+
3+
name: Windows ARM64 Smoke Test
4+
5+
on:
6+
workflow_dispatch:
7+
pull_request:
8+
9+
env:
10+
CARGO_TERM_COLOR: always
11+
RUST_BACKTRACE: full
12+
13+
permissions:
14+
contents: read
15+
16+
defaults:
17+
run:
18+
shell: pwsh
19+
20+
jobs:
21+
smoke:
22+
runs-on: ["self-hosted", "Windows", "ARM64", "1ES.Pool=hl-windows-arm"]
23+
timeout-minutes: 30
24+
steps:
25+
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
26+
27+
- name: Install Rust toolchain
28+
run: |
29+
rustup toolchain install 1.94 --profile minimal
30+
rustup default 1.94
31+
32+
- name: Check environment
33+
run: |
34+
rustc --version
35+
cargo --version
36+
systeminfo | Select-String "OS Name","OS Version","System Type"
37+
38+
- name: Build hyperlight-host
39+
run: cargo build -p hyperlight-host
40+
41+
- name: Run hyperlight-host tests
42+
run: cargo test -p hyperlight-host

src/hyperlight_host/Cargo.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,6 @@ tracing-core = "0.1.36"
4242
tracing-opentelemetry = { version = "0.33.0", optional = true }
4343
hyperlight-common = { workspace = true, default-features = true, features = [ "std" ] }
4444
hyperlight-guest-tracing = { workspace = true, default-features = true, optional = true }
45-
vmm-sys-util = "0.15.0"
4645
crossbeam-channel = "0.5.15"
4746
thiserror = "2.0.18"
4847
chrono = { version = "0.4", optional = true }
@@ -84,6 +83,7 @@ kvm-bindings = { version = "0.14", features = ["fam-wrappers"], optional = true
8483
kvm-ioctls = { version = "0.25", optional = true }
8584
mshv-bindings = { version = "0.6", optional = true }
8685
mshv-ioctls = { version = "0.6", optional = true}
86+
vmm-sys-util = "0.15.0"
8787

8888
[dev-dependencies]
8989
uuid = { version = "1.23.3", features = ["v4"] }

src/hyperlight_host/src/hypervisor/hyperlight_vm/aarch64.rs

Lines changed: 14 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -35,10 +35,16 @@ use crate::hypervisor::regs::{CommonFpu, CommonRegisters, CommonSpecialRegisters
3535
use crate::hypervisor::virtual_machine::hvf::HvfVm;
3636
#[cfg(kvm)]
3737
use crate::hypervisor::virtual_machine::kvm::KvmVm;
38+
#[cfg(target_os = "windows")]
39+
use crate::hypervisor::virtual_machine::whp::WhpVm;
3840
use crate::hypervisor::virtual_machine::{
3941
HypervisorType, RegisterError, ResetVcpuError, VirtualMachine, VmError,
4042
get_available_hypervisor,
4143
};
44+
#[cfg(target_os = "linux")]
45+
use crate::hypervisor::LinuxInterruptHandle;
46+
#[cfg(target_os = "windows")]
47+
use crate::hypervisor::WindowsInterruptHandle;
4248
use crate::mem::mgr::{SandboxMemoryManager, SnapshotSharedMemory};
4349
use crate::mem::shared_mem::{GuestSharedMemory, HostSharedMemory};
4450
use crate::sandbox::SandboxConfiguration;
@@ -59,7 +65,7 @@ impl HyperlightVm {
5965
next_action: NextAction,
6066
rsp_gva: u64,
6167
page_size: usize,
62-
config: &SandboxConfiguration,
68+
#[cfg_attr(target_os = "windows", allow(unused_variables))] config: &SandboxConfiguration,
6369
#[cfg(gdb)] _gdb_conn: Option<DebugCommChannel<DebugResponse, DebugMsg>>,
6470
#[cfg(crashdump)] _rt_cfg: SandboxRuntimeConfig,
6571
#[cfg(feature = "mem_profile")] _trace_info: MemTraceInfo,
@@ -72,13 +78,14 @@ impl HyperlightVm {
7278
let mut vm: VmType = match get_available_hypervisor() {
7379
#[cfg(kvm)]
7480
Some(HypervisorType::Kvm) => Box::new(KvmVm::new().map_err(VmError::CreateVm)?),
75-
// TODO: mshv support
7681
#[cfg(mshv3)]
7782
Some(HypervisorType::Mshv) => return Err(CreateHyperlightVmError::NoHypervisorFound),
7883
#[cfg(hvf)]
7984
Some(HypervisorType::Hvf) => {
8085
Box::new(HvfVm::new(interrupt_handle.clone()).map_err(VmError::CreateVm)?)
8186
}
87+
#[cfg(target_os = "windows")]
88+
Some(HypervisorType::Whp) => Box::new(WhpVm::new().map_err(VmError::CreateVm)?),
8289
None => return Err(CreateHyperlightVmError::NoHypervisorFound),
8390
};
8491
vm.set_sregs(&CommonSpecialRegisters::defaults(root_pt_addr))
@@ -87,6 +94,10 @@ impl HyperlightVm {
8794
let interrupt_handle: Arc<dyn InterruptHandleImpl> =
8895
Arc::new(LinuxInterruptHandle::new(config));
8996

97+
#[cfg(target_os = "windows")]
98+
let interrupt_handle: Arc<dyn InterruptHandleImpl> =
99+
Arc::new(WindowsInterruptHandle::new(vm.partition_handle()));
100+
90101
let snapshot_slot = 0u32;
91102
let scratch_slot = 1u32;
92103
let vm_can_reset_vcpu = vm.can_reset_vcpu();
@@ -206,7 +217,7 @@ impl HyperlightVm {
206217
self.vm_can_reset_vcpu,
207218
"No fallback path for vcpu reset on aarch64"
208219
);
209-
self.vm.reset_vcpu()?;
220+
self.interrupt_handle.reset_vcpu(self.vm.as_mut())?;
210221
self.apply_sregs(cr3, sregs)?;
211222
Ok(())
212223
}

src/hyperlight_host/src/hypervisor/mod.rs

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,9 @@ use std::sync::atomic::{AtomicU8, Ordering};
4545
#[cfg(any(kvm, mshv3, hvf))]
4646
use std::time::Duration;
4747

48+
#[cfg(target_arch = "aarch64")]
49+
use self::virtual_machine::{ResetVcpuError, VirtualMachine};
50+
4851
#[derive(Debug)]
4952
pub(crate) struct InterruptHandleStateMachine(AtomicU8);
5053
impl InterruptHandleStateMachine {
@@ -142,6 +145,12 @@ pub(crate) trait InterruptHandleImpl: InterruptHandle {
142145

143146
/// Mark the handle as dropped
144147
fn set_dropped(&self);
148+
149+
/// Reset the vCPU while honoring platform lifecycle synchronization.
150+
#[cfg(target_arch = "aarch64")]
151+
fn reset_vcpu(&self, vm: &mut dyn VirtualMachine) -> Result<(), ResetVcpuError> {
152+
vm.reset_vcpu()
153+
}
145154
}
146155

147156
pub(crate) trait InterruptHandleInternal {
@@ -375,6 +384,20 @@ impl<T: SynchronousInterruptState> InterruptHandleImpl for SynchronousInterruptH
375384
}
376385
}
377386
}
387+
388+
#[cfg(target_arch = "aarch64")]
389+
fn reset_vcpu(&self, vm: &mut dyn VirtualMachine) -> Result<(), ResetVcpuError> {
390+
let guard = self
391+
.dropped_state
392+
.write()
393+
.map_err(|e| ResetVcpuError::Unknown(e.to_string()))?;
394+
if guard.0 {
395+
return Err(ResetVcpuError::Unknown(
396+
"cannot reset a dropped partition".to_string(),
397+
));
398+
}
399+
vm.reset_vcpu()
400+
}
378401
}
379402

380403
#[cfg(any(target_os = "windows", hvf))]

src/hyperlight_host/src/hypervisor/regs.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -21,13 +21,13 @@ pub(crate) use x86_64::*;
2121

2222
#[cfg(target_arch = "aarch64")]
2323
mod aarch64;
24-
#[cfg(target_os = "windows")]
24+
#[cfg(all(target_arch = "x86_64", target_os = "windows"))]
2525
use std::collections::HashSet;
2626

2727
#[cfg(target_arch = "aarch64")]
2828
pub(crate) use aarch64::*;
2929

30-
#[cfg(target_os = "windows")]
30+
#[cfg(all(target_arch = "x86_64", target_os = "windows"))]
3131
#[derive(Debug, PartialEq)]
3232
pub(crate) enum FromWhpRegisterError {
3333
MissingRegister(HashSet<i32>),

0 commit comments

Comments
 (0)