Skip to content

Initial aarch64/KVM support#1474

Open
syntactically wants to merge 20 commits into
mainfrom
lm/aarch64
Open

Initial aarch64/KVM support#1474
syntactically wants to merge 20 commits into
mainfrom
lm/aarch64

Conversation

@syntactically
Copy link
Copy Markdown
Member

Initial aarch64 support.

Tested:

  • Primarily on Linux 6.18 KVM, nested virt inside Hypervisor.framework MacOS Build 25F5042g
  • Secondarily on Linux 6.8.12-tegra on Nvidia Jetson T5000
  • Tertiary testing in the process of debugging on a variety of other available arm platforms

There's still some unsupported features (debug/trace/crashdump, etc) and further API surface needed to allow architecture-independent clients like Hyperlight-Wasm to access all of the virtual memory features they need; this is largely elaborated on in the commit messages.

Signed-off-by: Lucy Menon <168595099+syntactically@users.noreply.github.com>
In 137e964, the signature of
`HyperlightVm::new` changed to take `page_size`, which was previously
passed in `HyperlightVm::initialise`, so that mapping
operations (which are page-size-dependent) could take place before the
call to initialise.  However, the argument to
`HyperlightVm::initialise` was retained, creating the possibility of
passing in mis-matched page sizes. This commit removes the second
argument, in order to remove that possibility.

This commit also, while doing that, fixes compilation of the stubs in
hyperlight_vm/aarch64.rs, which was previously broken.

Signed-off-by: Lucy Menon <168595099+syntactically@users.noreply.github.com>
Signed-off-by: Lucy Menon <168595099+syntactically@users.noreply.github.com>
Signed-off-by: Lucy Menon <168595099+syntactically@users.noreply.github.com>
In the future, some of these may be reimplemented, but for now, just
gate them.

Signed-off-by: Lucy Menon <168595099+syntactically@users.noreply.github.com>
This name is a more accurate reflection of how these constants are used

Signed-off-by: Lucy Menon <168595099+syntactically@users.noreply.github.com>
Signed-off-by: Lucy Menon <168595099+syntactically@users.noreply.github.com>
This is not yet used anywhere, but will be used for aarch64 KVM (where
there is no other reasonable method of resetting all MSRs), and will
likely be used on x86_64 in the future as well.

Signed-off-by: Lucy Menon <168595099+syntactically@users.noreply.github.com>
This was never actually architecture-dependent, since it used the
virtual memory APIs from hyperlight_guest.  Extract it, so that it can
be used by aarch64 init in the near future.

Signed-off-by: Lucy Menon <168595099+syntactically@users.noreply.github.com>
This will be useful on multiple architectures.

Signed-off-by: Lucy Menon <168595099+syntactically@users.noreply.github.com>
This includes adding the concept of a fixed "IO page" to the memory
layout, to be used on architectures where MMIO is convenient. The IO
page is above the scratch region at the top of memory, and is mapped
in the guest, but not in the host, so that accesses to it will trigger
vmexits.

Signed-off-by: Lucy Menon <168595099+syntactically@users.noreply.github.com>
…specific module

This changes hyperlight_guest_bin::paging to be a reexport of the
interface of an architecture-specific implementation, much like
hyperlight_common::vmem.

Signed-off-by: Lucy Menon <168595099+syntactically@users.noreply.github.com>
Signed-off-by: Lucy Menon <168595099+syntactically@users.noreply.github.com>
This does not yet support the debug registers, and the
architecture-independent interface will have to be rationalised in the
future, since the xsave operations are unlikely to be useful on aarch64.

Signed-off-by: Lucy Menon <168595099+syntactically@users.noreply.github.com>
Signed-off-by: Lucy Menon <168595099+syntactically@users.noreply.github.com>
This is very similar to the amd64 one, but implemented with different
assembly instructions.

Signed-off-by: Lucy Menon <168595099+syntactically@users.noreply.github.com>
These just implement the bare minimum for stack lazy-allocation and
CoW.  There is no extension mechanism for other crates (analogous to
the raw exception handler table that is presently exported on amd64)
yet; we will shortly need to add architecture-independent interfaces
to allow other crates (e.g. hyperlight-wasm) to register
specially-behaving memory ranges and intercept other errors.

Signed-off-by: Lucy Menon <168595099+syntactically@users.noreply.github.com>
…stubs

Signed-off-by: Lucy Menon <168595099+syntactically@users.noreply.github.com>
There are a number of features not yet supported (e.g. debugging,
trace collection etc); however, this should implement a
minimal coherent subset of Hyperlight functionality.

Signed-off-by: Lucy Menon <168595099+syntactically@users.noreply.github.com>
Either by disabling them, or by rewriting them to do a similar thing
on aarch64.

Signed-off-by: Lucy Menon <168595099+syntactically@users.noreply.github.com>
Copilot AI review requested due to automatic review settings May 26, 2026 23:05
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR introduces initial aarch64 support backed by KVM, extending Hyperlight’s VM, guest runtime, and memory layout to run the existing sandbox model on arm64 (including MMIO-based “outb” equivalents, paging, and exception handling).

Changes:

  • Add an aarch64 KVM VirtualMachine implementation, including vCPU reset support and MMIO-exit handling via an IO page.
  • Implement aarch64 guest runtime pieces (paging ops, exception vectors/handler, stack init, guest exits) and adjust test guests for aarch64.
  • Refactor layout constants (MAX_GPA/MAX_GVASCRATCH_TOP_*) and map the IO page into snapshots where applicable; update build tooling (Justfile/Nix/libc build lists) for aarch64 targets.

Reviewed changes

Copilot reviewed 49 out of 49 changed files in this pull request and generated 9 comments.

Show a summary per file
File Description
src/tests/rust_guests/simpleguest/src/main.rs Make the Rust test guest work on aarch64 (undef instruction, executable buffers, IO-page “outb” substitute, icache sync).
src/tests/rust_guests/dummyguest/src/main.rs Add aarch64 halt/MMIO paths and switch entrypoint ABI.
src/hyperlight_libc/build.rs Add aarch64 include paths and file lists to the picolibc build.
src/hyperlight_libc/build_files.rs Introduce aarch64 libc/libm file lists.
src/hyperlight_host/tests/integration_test.rs Adjust assertions and gate x86_64-only tests for architecture differences.
src/hyperlight_host/src/sandbox/uninitialized_evolve.rs Update VM initialization call signature (page size argument removed).
src/hyperlight_host/src/sandbox/snapshot/mod.rs Map IO page into guest page tables and switch to SCRATCH_TOP_* bounds.
src/hyperlight_host/src/sandbox/initialized_multi_use.rs Adapt tests/fixtures for aarch64 instruction encodings and exception strings.
src/hyperlight_host/src/mem/mgr.rs Use SCRATCH_TOP_GVA for crashdump region sizing.
src/hyperlight_host/src/hypervisor/virtual_machine/mod.rs Add ResetVcpuError and vCPU reset capability hooks to the VM trait.
src/hyperlight_host/src/hypervisor/virtual_machine/kvm/x86_64.rs Switch CPUID max-phys-address computation to SCRATCH_TOP_GPA.
src/hyperlight_host/src/hypervisor/virtual_machine/kvm/aarch64.rs Implement aarch64 KVM backend: map/unmap, run loop, MMIO → VmExit translation, regs/fpu/sregs, vCPU reset.
src/hyperlight_host/src/hypervisor/regs/aarch64/special_regs.rs Define aarch64 special register structure and default register programming values.
src/hyperlight_host/src/hypervisor/regs/aarch64/mod.rs Wire up real aarch64 common regs/fpu/special-reg modules and KVM reg IDs.
src/hyperlight_host/src/hypervisor/regs/aarch64/kvm_reg.rs Define KVM register ID constants and typed get/set helpers for aarch64.
src/hyperlight_host/src/hypervisor/regs/aarch64/fpu.rs Adds an (apparently redundant) CommonFpu definition file.
src/hyperlight_host/src/hypervisor/regs/aarch64/common_regs.rs Define CommonRegisters for aarch64 (x0-x30, sp, pc, pstate).
src/hyperlight_host/src/hypervisor/regs/aarch64/common_fpu.rs Define CommonFpu for aarch64 (v0-v31, fpsr/fpcr).
src/hyperlight_host/src/hypervisor/mod.rs Update internal test setup to match new initialization signature and layout constants.
src/hyperlight_host/src/hypervisor/hyperlight_vm/x86_64.rs Remove page_size parameter from initialise path and store page size in the VM struct.
src/hyperlight_host/src/hypervisor/hyperlight_vm/mod.rs Plumb ResetVcpuError and add vm_can_reset_vcpu tracking in HyperlightVm.
src/hyperlight_host/src/hypervisor/hyperlight_vm/aarch64.rs Implement aarch64 HyperlightVm lifecycle: create VM, init regs, dispatch calls, reset vCPU, root PT access.
src/hyperlight_guest/src/layout.rs Switch scratch metadata pointers from MAX_GVA to SCRATCH_TOP_GVA.
src/hyperlight_guest/src/arch/amd64/prim_alloc.rs Switch allocator ceiling to SCRATCH_TOP_GPA.
src/hyperlight_guest/src/arch/aarch64/prim_alloc.rs Implement aarch64 physical page allocator using atomic add and scratch bounds checks.
src/hyperlight_guest/src/arch/aarch64/layout.rs Implement scratch size/base getters and move main stack to lower half for aarch64.
src/hyperlight_guest/src/arch/aarch64/exit.rs Implement aarch64 “out32” via IO-page MMIO writes.
src/hyperlight_guest_bin/src/paging.rs Split paging implementation into per-arch modules and re-export shared API.
src/hyperlight_guest_bin/src/lib.rs Make paging available on all arches; add shared init module.
src/hyperlight_guest_bin/src/init.rs Add shared stack init logic used by multiple architectures.
src/hyperlight_guest_bin/src/arch/amd64/paging.rs Move existing amd64 paging implementation under arch-specific module.
src/hyperlight_guest_bin/src/arch/amd64/init.rs Use shared stack init and update scratch-top constant usage.
src/hyperlight_guest_bin/src/arch/aarch64/paging.rs Add aarch64 paging implementation (volatile PTE ops, barriers, TTBR0 root).
src/hyperlight_guest_bin/src/arch/aarch64/mod.rs Implement aarch64 entrypoint, dispatch stub (with optional TLBI), VBAR init, and stack pivoting.
src/hyperlight_guest_bin/src/arch/aarch64/exception/types.rs Define saved exception context and exception origin/type enums.
src/hyperlight_guest_bin/src/arch/aarch64/exception/mod.rs Add aarch64 exception module plumbing.
src/hyperlight_guest_bin/src/arch/aarch64/exception/handle.rs Implement aarch64 exception decoding + handling for stack growth and CoW faults; emit abort diagnostics.
src/hyperlight_guest_bin/src/arch/aarch64/exception/entry.rs Provide AArch64 vector table and context save/restore in global asm.
src/hyperlight_common/src/vmem.rs Refactor shared UpdateParent* infrastructure and export aarch64 MAIR attribute index.
src/hyperlight_common/src/layout.rs Replace MAX_GPA/MAX_GVA exports with SCRATCH_TOP_* and add io_page.
src/hyperlight_common/src/arch/i686/layout.rs Rename max layout constants to scratch-top equivalents.
src/hyperlight_common/src/arch/amd64/vmem.rs Move UpdateParentTable/Root definitions into shared vmem module and tighten visibility.
src/hyperlight_common/src/arch/amd64/layout.rs Rename scratch-top constants and add io_page() stub returning None.
src/hyperlight_common/src/arch/aarch64/vmem.rs Implement aarch64 page table encode/decode and virt→phys walking logic.
src/hyperlight_common/src/arch/aarch64/layout.rs Define aarch64 scratch and IO page locations and scratch sizing logic.
Justfile Add arch-selectable guest build outputs via HYPERLIGHT_TARGET.
flake.nix Expand supported platforms (aarch64-linux) and adjust cargo-hyperlight source pinning/build.
docs/paging-development-notes.md Document aarch64 addressing assumptions (48-bit, lower-half/TTBR0).
c.just Make C guest compilation/linking target-arch aware.

mem_mgr,
host_funcs,
#[cfg(gdb)]
mem_access_fn,
Comment on lines +118 to +122
decl_core_reg!(V30, 0xcc, U128);
decl_core_reg!(V31, 0xd0, U128);
decl_core_reg!(FPSR, 0xd4, U32);
decl_core_reg!(FPCR, 0xd4, U32);

Comment on lines +1 to +6
#[derive(Debug, Default, Copy, Clone, PartialEq1)]
pub(crate) struct CommonFpu {
pub(crate) v: [u128; 32],
pub(crate) fpsr: u32,
pub(crate) fpcr: u32,
}
Comment on lines +44 to +48
#[cfg(target_arch = "aarch64")]
asm!(
"str {val}, [{addr}]",
val = in(reg) 0, addr = in(reg) 0xffff_ffff_e000u64 + 108 * 8,
);
Comment on lines 52 to 60
fn mmio_read() {
unsafe {
#[cfg(target_arch = "x86_64")]
asm!("mov al, [0x8000]");

let mut out: u8;
#[cfg(target_arch = "aarch64")]
asm!("ldr {0:x}, [{1}]", out(reg) out, in(reg) 0x8000);
}
Comment on lines +22 to +29
pub(crate) unsafe fn out32(port: u16, val: u32) {
if port as usize > (hyperlight_common::vmem::PAGE_SIZE / core::mem::size_of::<u64>()) {
panic!("aarch64 mmio: unsupported hypercall number {}", port);
}
unsafe {
(IO_PAGE_GVA as *mut u64)
.wrapping_add(port as usize)
.write_volatile(val as u64);
Comment on lines +27 to +35
let mut prev_base: u64 = 0;
unsafe {
// todo: actually check for FEAT_LSE presence.
core::arch::asm!("
ldadd {nbytes}, {prev_base}, [{addr}]
",
addr = in(reg) addr,
nbytes = in(reg) nbytes,
prev_base = out(reg) prev_base,
Comment on lines +67 to +86
if vm_fd.check_extension_raw(KVM_CAP_ARM_NISV_TO_USER as u64) != 0 {
// Available since Linux 5.5. Needed for the workaround
// described below for KVM mis-behaviour when a cache
// maintenance operation is applied to a VA that is paged
// out at Stage 2.
//
// When this cap is not available, there is a (small)
// chance that self-modifying code inside the VM will
// cause [`run_vcpu`] to fail, ultimately poisoning the
// sandbox. With this capability, the relevant code will
// instead be retried.
let cap: kvm_enable_cap = kvm_enable_cap {
cap: KVM_CAP_ARM_NISV_TO_USER,
..Default::default()
};
unsafe {
vmm_sys_util::ioctl_iow_nr!(KVM_ENABLE_CAP, KVMIO, 0xa3, kvm_enable_cap);
vmm_sys_util::ioctl::ioctl_with_ref(&vm_fd, KVM_ENABLE_CAP(), &cap);
}
}
Comment on lines +239 to +244
Ok(VcpuExit::MmioWrite(addr, data)) => {
let io_page_gpa = const { hyperlight_common::layout::io_page().unwrap().0 };
if addr > io_page_gpa
&& let off = (addr - io_page_gpa) as usize
&& off < hyperlight_common::vmem::PAGE_SIZE
{
@syntactically syntactically added the kind/enhancement For PRs adding features, improving functionality, docs, tests, etc. label May 27, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

kind/enhancement For PRs adding features, improving functionality, docs, tests, etc.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants