Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
60 changes: 60 additions & 0 deletions .github/workflows/WindowsArm64Smoke.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
# yaml-language-server: $schema=https://json.schemastore.org/github-workflow.json

name: Windows ARM64 Smoke Test

on:
workflow_dispatch:
pull_request:

env:
CARGO_TERM_COLOR: always
RUST_BACKTRACE: full

permissions:
contents: read

defaults:
run:
shell: pwsh

jobs:
smoke:
runs-on: ["self-hosted", "Windows", "ARM64", "1ES.Pool=hl-windows-arm"]
timeout-minutes: 30
steps:
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1

- uses: hyperlight-dev/ci-setup-workflow@2f4142ba17cf573af44fc1e1f1ffc743daded5b3 # v1.10.0
with:
rust-toolchain: "1.94"
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}

- name: Check environment
run: |
rustc --version
cargo --version
systeminfo | Select-String "OS Name","OS Version","System Type"

- name: Configure ARM64 libclang
run: |
$vswhere = "${env:ProgramFiles(x86)}\Microsoft Visual Studio\Installer\vswhere.exe"
$installPath = & $vswhere -latest -products * -property installationPath
$libclang = Join-Path $installPath "VC\Tools\Llvm\ARM64\bin\libclang.dll"
if (-not (Test-Path $libclang)) {
throw "ARM64 libclang not found at '$libclang'"
}
$llvmPath = Split-Path $libclang
"LIBCLANG_PATH=$llvmPath" >> $env:GITHUB_ENV
$llvmPath >> $env:GITHUB_PATH

- name: Build hyperlight-host
run: cargo build -p hyperlight-host

- name: Build guests
run: just guests
env:
HYPERLIGHT_TARGET: aarch64

- name: Run hyperlight-host tests
run: cargo test -p hyperlight-host -- --test-threads=1
2 changes: 1 addition & 1 deletion src/hyperlight_host/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,6 @@ tracing-core = "0.1.36"
tracing-opentelemetry = { version = "0.33.0", optional = true }
hyperlight-common = { workspace = true, default-features = true, features = [ "std" ] }
hyperlight-guest-tracing = { workspace = true, default-features = true, optional = true }
vmm-sys-util = "0.15.0"
crossbeam-channel = "0.5.15"
thiserror = "2.0.18"
chrono = { version = "0.4", optional = true }
Expand Down Expand Up @@ -90,6 +89,7 @@ kvm-bindings = { version = "0.14", features = ["fam-wrappers"], optional = true
kvm-ioctls = { version = "0.25", optional = true }
mshv-bindings = { version = "0.7", optional = true }
mshv-ioctls = { version = "0.7", optional = true}
vmm-sys-util = "0.15.0"

[dev-dependencies]
uuid = { version = "1.23.3", features = ["v4"] }
Expand Down
15 changes: 12 additions & 3 deletions src/hyperlight_host/src/hypervisor/hyperlight_vm/aarch64.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,10 @@ use super::{
#[cfg(hvf)]
use crate::hypervisor::HvfInterruptHandle;
use crate::hypervisor::InterruptHandleImpl;
#[cfg(any(kvm, mshv3))]
#[cfg(target_os = "linux")]
use crate::hypervisor::LinuxInterruptHandle;
#[cfg(target_os = "windows")]
use crate::hypervisor::WindowsInterruptHandle;
#[cfg(gdb)]
use crate::hypervisor::gdb::{DebugCommChannel, DebugMsg, DebugResponse};
use crate::hypervisor::hyperlight_vm::get_guest_log_filter;
Expand All @@ -22,6 +24,8 @@ use crate::hypervisor::regs::{CommonFpu, CommonRegisters, CommonSpecialRegisters
use crate::hypervisor::virtual_machine::hvf::HvfVm;
#[cfg(kvm)]
use crate::hypervisor::virtual_machine::kvm::KvmVm;
#[cfg(target_os = "windows")]
use crate::hypervisor::virtual_machine::whp::WhpVm;
use crate::hypervisor::virtual_machine::{
HypervisorType, RegisterError, ResetVcpuError, VirtualMachine, VmError,
get_available_hypervisor,
Expand All @@ -46,7 +50,7 @@ impl HyperlightVm {
next_action: NextAction,
rsp_gva: u64,
page_size: usize,
config: &SandboxConfiguration,
#[cfg_attr(target_os = "windows", allow(unused_variables))] config: &SandboxConfiguration,
#[cfg(gdb)] _gdb_conn: Option<DebugCommChannel<DebugResponse, DebugMsg>>,
#[cfg(crashdump)] _rt_cfg: SandboxRuntimeConfig,
#[cfg(feature = "mem_profile")] _trace_info: MemTraceInfo,
Expand All @@ -59,13 +63,14 @@ impl HyperlightVm {
let mut vm: VmType = match get_available_hypervisor() {
#[cfg(kvm)]
Some(HypervisorType::Kvm) => Box::new(KvmVm::new().map_err(VmError::CreateVm)?),
// TODO: mshv support
#[cfg(mshv3)]
Some(HypervisorType::Mshv) => return Err(CreateHyperlightVmError::NoHypervisorFound),
#[cfg(hvf)]
Some(HypervisorType::Hvf) => {
Box::new(HvfVm::new(interrupt_handle.clone()).map_err(VmError::CreateVm)?)
}
#[cfg(target_os = "windows")]
Some(HypervisorType::Whp) => Box::new(WhpVm::new().map_err(VmError::CreateVm)?),
None => return Err(CreateHyperlightVmError::NoHypervisorFound),
};
vm.set_sregs(&CommonSpecialRegisters::defaults(root_pt_addr))
Expand All @@ -74,6 +79,10 @@ impl HyperlightVm {
let interrupt_handle: Arc<dyn InterruptHandleImpl> =
Arc::new(LinuxInterruptHandle::new(config));

#[cfg(target_os = "windows")]
let interrupt_handle: Arc<dyn InterruptHandleImpl> =
Arc::new(WindowsInterruptHandle::new(vm.partition_handle()));

let snapshot_slot = 0u32;
let scratch_slot = 1u32;
let vm_can_reset_vcpu = vm.can_reset_vcpu();
Expand Down
4 changes: 2 additions & 2 deletions src/hyperlight_host/src/hypervisor/regs.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,13 +8,13 @@ pub(crate) use x86_64::*;

#[cfg(target_arch = "aarch64")]
mod aarch64;
#[cfg(target_os = "windows")]
#[cfg(all(target_arch = "x86_64", target_os = "windows"))]
use std::collections::HashSet;

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

#[cfg(target_os = "windows")]
#[cfg(all(target_arch = "x86_64", target_os = "windows"))]
#[derive(Debug, PartialEq)]
pub(crate) enum FromWhpRegisterError {
MissingRegister(HashSet<i32>),
Expand Down
3 changes: 3 additions & 0 deletions src/hyperlight_host/src/hypervisor/regs/aarch64/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -19,3 +19,6 @@ pub(crate) struct CommonDebugRegs {

#[cfg(kvm)]
pub(crate) mod kvm_reg;

#[cfg(target_os = "windows")]
pub(crate) mod whp_reg;
49 changes: 49 additions & 0 deletions src/hyperlight_host/src/hypervisor/regs/aarch64/whp_reg.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
// SPDX-License-Identifier: Apache-2.0
// Copyright 2026 The Hyperlight Authors.

use windows::Win32::System::Hypervisor::{WHV_REGISTER_NAME, WHV_REGISTER_VALUE};

#[repr(C, align(16))]
#[derive(Clone, Copy, Default)]
pub(crate) struct Align16<T>(pub(crate) T);

const _: () = {
assert!(core::mem::size_of::<WHV_REGISTER_VALUE>() == 16);
assert!(core::mem::size_of::<Align16<WHV_REGISTER_VALUE>>() == 16);
assert!(core::mem::align_of::<Align16<WHV_REGISTER_VALUE>>() == 16);
};

pub(crate) const WHV_ARM64_REGISTER_X0: WHV_REGISTER_NAME = WHV_REGISTER_NAME(0x00020000);
pub(crate) const WHV_ARM64_REGISTER_FP: WHV_REGISTER_NAME = WHV_REGISTER_NAME(0x0002001D);
pub(crate) const WHV_ARM64_REGISTER_LR: WHV_REGISTER_NAME = WHV_REGISTER_NAME(0x0002001E);
pub(crate) const WHV_ARM64_REGISTER_SP_EL0: WHV_REGISTER_NAME = WHV_REGISTER_NAME(0x00020020);
pub(crate) const WHV_ARM64_REGISTER_SP_EL1: WHV_REGISTER_NAME = WHV_REGISTER_NAME(0x00020021);
pub(crate) const WHV_ARM64_REGISTER_PC: WHV_REGISTER_NAME = WHV_REGISTER_NAME(0x00020022);
pub(crate) const WHV_ARM64_REGISTER_PSTATE: WHV_REGISTER_NAME = WHV_REGISTER_NAME(0x00020023);

pub(crate) const WHV_ARM64_REGISTER_Q0: WHV_REGISTER_NAME = WHV_REGISTER_NAME(0x00030000);

pub(crate) const WHV_ARM64_REGISTER_SCTLR_EL1: WHV_REGISTER_NAME = WHV_REGISTER_NAME(0x00040002);
pub(crate) const WHV_ARM64_REGISTER_CPACR_EL1: WHV_REGISTER_NAME = WHV_REGISTER_NAME(0x00040004);
pub(crate) const WHV_ARM64_REGISTER_TTBR0_EL1: WHV_REGISTER_NAME = WHV_REGISTER_NAME(0x00040005);
pub(crate) const WHV_ARM64_REGISTER_TCR_EL1: WHV_REGISTER_NAME = WHV_REGISTER_NAME(0x00040007);
pub(crate) const WHV_ARM64_REGISTER_MAIR_EL1: WHV_REGISTER_NAME = WHV_REGISTER_NAME(0x0004000B);
pub(crate) const WHV_ARM64_REGISTER_VBAR_EL1: WHV_REGISTER_NAME = WHV_REGISTER_NAME(0x0004000C);
pub(crate) const WHV_ARM64_REGISTER_FPCR: WHV_REGISTER_NAME = WHV_REGISTER_NAME(0x00040012);
pub(crate) const WHV_ARM64_REGISTER_FPSR: WHV_REGISTER_NAME = WHV_REGISTER_NAME(0x00040013);
pub(crate) const WHV_ARM64_REGISTER_GICR_BASE_GPA: WHV_REGISTER_NAME =
WHV_REGISTER_NAME(0x00063000);

pub(crate) fn xreg(index: u32) -> WHV_REGISTER_NAME {
match index {
0..=28 => WHV_REGISTER_NAME(WHV_ARM64_REGISTER_X0.0 + index as i32),
29 => WHV_ARM64_REGISTER_FP,
30 => WHV_ARM64_REGISTER_LR,
_ => panic!("Invalid ARM64 GP register index: {index}"),
}
}

pub(crate) fn qreg(index: u32) -> WHV_REGISTER_NAME {
debug_assert!(index < 32, "Invalid ARM64 SIMD register index: {index}");
WHV_REGISTER_NAME(WHV_ARM64_REGISTER_Q0.0 + index as i32)
}
3 changes: 3 additions & 0 deletions src/hyperlight_host/src/hypervisor/virtual_machine/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -225,6 +225,9 @@ pub enum CreateVmError {
#[cfg(target_os = "windows")]
#[error("Surrogate process creation failed: {0}")]
SurrogateProcess(String),
#[cfg(all(target_os = "windows", target_arch = "aarch64"))]
#[error("Timed out waiting for an ARM64 WHP partition slot")]
WhpPartitionLimit,
}

/// RunVCPU error
Expand Down
Loading
Loading