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 @@ -84,6 +83,7 @@ kvm-bindings = { version = "0.14", features = ["fam-wrappers"], optional = true
kvm-ioctls = { version = "0.25", optional = true }
mshv-bindings = { version = "0.6", optional = true }
mshv-ioctls = { version = "0.6", optional = true}
vmm-sys-util = "0.15.0"

[dev-dependencies]
uuid = { version = "1.23.3", features = ["v4"] }
Expand Down
17 changes: 13 additions & 4 deletions src/hyperlight_host/src/hypervisor/hyperlight_vm/aarch64.rs
Original file line number Diff line number Diff line change
Expand Up @@ -25,8 +25,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 @@ -35,6 +37,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 @@ -59,7 +63,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 @@ -72,13 +76,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 @@ -87,6 +92,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 Expand Up @@ -206,7 +215,7 @@ impl HyperlightVm {
self.vm_can_reset_vcpu,
"No fallback path for vcpu reset on aarch64"
);
self.vm.reset_vcpu()?;
self.interrupt_handle.reset_vcpu(self.vm.as_mut())?;
self.apply_sregs(cr3, sregs)?;
Ok(())
}
Expand Down
23 changes: 23 additions & 0 deletions src/hyperlight_host/src/hypervisor/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,9 @@ use std::sync::atomic::{AtomicU8, Ordering};
#[cfg(any(kvm, mshv3, hvf))]
use std::time::Duration;

#[cfg(target_arch = "aarch64")]
use self::virtual_machine::{ResetVcpuError, VirtualMachine};

#[derive(Debug)]
pub(crate) struct InterruptHandleStateMachine(AtomicU8);
impl InterruptHandleStateMachine {
Expand Down Expand Up @@ -142,6 +145,12 @@ pub(crate) trait InterruptHandleImpl: InterruptHandle {

/// Mark the handle as dropped
fn set_dropped(&self);

/// Reset the vCPU while honoring platform lifecycle synchronization.
#[cfg(target_arch = "aarch64")]
fn reset_vcpu(&self, vm: &mut dyn VirtualMachine) -> Result<(), ResetVcpuError> {
vm.reset_vcpu()
}
}

pub(crate) trait InterruptHandleInternal {
Expand Down Expand Up @@ -375,6 +384,20 @@ impl<T: SynchronousInterruptState> InterruptHandleImpl for SynchronousInterruptH
}
}
}

#[cfg(target_arch = "aarch64")]
fn reset_vcpu(&self, vm: &mut dyn VirtualMachine) -> Result<(), ResetVcpuError> {
let guard = self
.dropped_state
.write()
.map_err(|e| ResetVcpuError::Unknown(e.to_string()))?;
if guard.0 {
return Err(ResetVcpuError::Unknown(
"cannot reset a dropped partition".to_string(),
));
}
vm.reset_vcpu()
}
}

#[cfg(any(target_os = "windows", hvf))]
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 @@ -21,13 +21,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
Loading
Loading