Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
37 commits
Select commit Hold shift + click to select a range
b944983
feat: add PIC emulation, OutBAction variants, and guest halt mechanism
danbugs Mar 3, 2026
64184b0
feat(kvm): add hardware interrupt support with in-kernel IRQ chip
danbugs Mar 3, 2026
7f5d0bc
feat(mshv): add hardware interrupt support with SynIC timer
danbugs Mar 3, 2026
e0a2dfe
feat(whp): add hardware interrupt support with software timer
danbugs Mar 3, 2026
128e94d
test: add hardware interrupt unit and integration tests
danbugs Mar 3, 2026
9b4ed3a
ci: add hw-interrupts test step to CI and Justfile
danbugs Mar 3, 2026
7a0da22
fix: add halt port IO write and restore hw_timer_interrupts test
danbugs Mar 4, 2026
4b10e06
experiment: replace in-kernel PIT with irqfd + host timer thread
danbugs Mar 5, 2026
f6e86a9
experiment: MSHV — replace SynIC timer with request_virtual_interrupt…
danbugs Mar 5, 2026
4a58433
experiment: eliminate PIC state machine — hardcode vector 0x20, no-op…
danbugs Mar 5, 2026
94806b7
fix: delete unused pic.rs file
danbugs Mar 6, 2026
5135b89
style: rustfmt fixes in kvm.rs
danbugs Mar 6, 2026
1bc420b
refactor: address PR 1272 review feedback
danbugs Mar 6, 2026
fd5f295
fix: reset timer_stop flag before spawning timer thread
danbugs Mar 7, 2026
ff96cec
Address copilot review feedback
danbugs Mar 10, 2026
329dee2
Fix formatting (rustfmt nightly)
danbugs Mar 10, 2026
b954562
Fix clippy collapsible-if in KVM timer config
danbugs Mar 10, 2026
9127f9d
fix: remove disallowed assert! macros from LAPIC helpers
danbugs Mar 10, 2026
6dbf3e7
refactor: extract hw-interrupts and default vCPU run into separate me…
danbugs Mar 10, 2026
6be5f5d
fix: preserve RAX across halt sequence in init and dispatch
danbugs Mar 10, 2026
b7dab7c
refactor: split OutBAction into OutBAction + VmAction, move hw_interr…
danbugs Mar 13, 2026
d9d6eda
fix: address PR 1272 review feedback (round 2)
danbugs Mar 18, 2026
32f6ec0
refactor: extract TimerThread struct into shared hw_interrupts module
danbugs Mar 18, 2026
38b6665
refactor: deduplicate WhpVm::new(), use #[cfg] for test exclusion
danbugs Mar 18, 2026
ad16579
style: fix rustfmt in KVM trace macro
danbugs Mar 18, 2026
f0bd850
style: fix rustfmt import ordering for TimerThread
danbugs Mar 18, 2026
a8cc679
fix: revert test exclusion to runtime ignore for hw-interrupts compat…
danbugs Mar 18, 2026
1bd2869
refactor: extract shared PvTimerConfig handler and fix timer reconfig…
danbugs Mar 18, 2026
1cfa527
refactor: extract hw-interrupts setup from constructors
danbugs Mar 18, 2026
746f294
fix(kvm): return error on unexpected VcpuExit::Hlt in hw-interrupts loop
danbugs Mar 18, 2026
2bb83cd
refactor: use shared constant for halt port in guest assembly
danbugs Mar 18, 2026
a834801
style: rustfmt
danbugs Mar 18, 2026
836cb91
fix(kvm): copy IO data before calling handle_pv_timer_config
danbugs Mar 18, 2026
fcbd2b8
style: fix rustfmt import grouping in error.rs
danbugs Mar 18, 2026
7ccb80d
fix(whp): use WHvX64LocalApicEmulationModeXApic constant
danbugs Mar 18, 2026
a105ff5
fix: resolve clippy expect_used and rustfmt rebase artifacts
danbugs Mar 18, 2026
32eaebf
fix(kvm): remove UnexpectedExit, let catch-all handle unexpected HLT
danbugs Mar 19, 2026
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
5 changes: 5 additions & 0 deletions .github/workflows/dep_build_test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -105,6 +105,11 @@ jobs:
# with only one driver enabled (kvm/mshv3 features are unix-only, no-op on Windows)
just test ${{ inputs.config }} ${{ inputs.hypervisor == 'mshv3' && 'mshv3' || 'kvm' }}
- name: Run Rust tests with hw-interrupts
run: |
# with hw-interrupts feature enabled (+ explicit driver on Linux)
just test ${{ inputs.config }} ${{ runner.os == 'Linux' && (inputs.hypervisor == 'mshv3' && 'mshv3,hw-interrupts' || 'kvm,hw-interrupts') || 'hw-interrupts' }}
- name: Run Rust Gdb tests
env:
RUST_LOG: debug
Expand Down
7 changes: 7 additions & 0 deletions Justfile
Original file line number Diff line number Diff line change
Expand Up @@ -87,6 +87,9 @@ test-like-ci config=default-target hypervisor="kvm":
@# with only one driver enabled + build-metadata
just test {{config}} build-metadata,{{ if hypervisor == "mshv3" {"mshv3"} else {"kvm"} }}

@# with hw-interrupts enabled (+ explicit driver on Linux)
{{ if os() == "linux" { if hypervisor == "mshv3" { "just test " + config + " mshv3,hw-interrupts" } else { "just test " + config + " kvm,hw-interrupts" } } else { "just test " + config + " hw-interrupts" } }}

@# make sure certain cargo features compile
just check

Expand Down Expand Up @@ -151,6 +154,9 @@ build-test-like-ci config=default-target hypervisor="kvm":
@# Run Rust tests with single driver
{{ if os() == "linux" { "just test " + config+ " " + if hypervisor == "mshv3" { "mshv3" } else { "kvm" } } else { "" } }}

@# Run Rust tests with hw-interrupts
{{ if os() == "linux" { if hypervisor == "mshv3" { "just test " + config + " mshv3,hw-interrupts" } else { "just test " + config + " kvm,hw-interrupts" } } else { "just test " + config + " hw-interrupts" } }}

@# Run Rust Gdb tests
just test-rust-gdb-debugging {{config}}

Expand Down Expand Up @@ -286,6 +292,7 @@ check:
{{ cargo-cmd }} check -p hyperlight-host --features trace_guest,mem_profile {{ target-triple-flag }}
{{ cargo-cmd }} check -p hyperlight-host --features nanvix-unstable {{ target-triple-flag }}
{{ cargo-cmd }} check -p hyperlight-host --features nanvix-unstable,executable_heap {{ target-triple-flag }}
{{ cargo-cmd }} check -p hyperlight-host --features hw-interrupts {{ target-triple-flag }}

fmt-check: (ensure-nightly-fmt)
cargo +nightly fmt --all -- --check
Expand Down
28 changes: 28 additions & 0 deletions src/hyperlight_common/src/outb.rs
Original file line number Diff line number Diff line change
Expand Up @@ -86,6 +86,7 @@ impl TryFrom<u8> for Exception {
}

/// Supported actions when issuing an OUTB actions by Hyperlight.
/// These are handled by the sandbox-level outb dispatcher.
/// - Log: for logging,
/// - CallFunction: makes a call to a host function,
/// - Abort: aborts the execution of the guest,
Expand All @@ -106,6 +107,22 @@ pub enum OutBAction {
TraceMemoryFree = 106,
}

/// IO-port actions intercepted at the hypervisor level (in `run_vcpu`)
/// before they ever reach the sandbox outb handler. These are split
/// from [`OutBAction`] so the outb handler does not need unreachable
/// match arms for ports it can never see.
pub enum VmAction {
/// IO port for PV timer configuration. The guest writes a 32-bit
/// LE value representing the desired timer period in microseconds.
/// A value of 0 disables the timer.
PvTimerConfig = 107,
/// IO port the guest writes to signal "I'm done" to the host.
/// This replaces the `hlt` instruction for halt signaling so that
/// KVM's in-kernel LAPIC (which absorbs HLT exits) does not interfere
/// with hyperlight's halt-based guest-host protocol.
Halt = 108,
}

impl TryFrom<u16> for OutBAction {
type Error = anyhow::Error;
fn try_from(val: u16) -> anyhow::Result<Self> {
Expand All @@ -124,3 +141,14 @@ impl TryFrom<u16> for OutBAction {
}
}
}

impl TryFrom<u16> for VmAction {
type Error = anyhow::Error;
fn try_from(val: u16) -> anyhow::Result<Self> {
match val {
107 => Ok(VmAction::PvTimerConfig),
108 => Ok(VmAction::Halt),
_ => Err(anyhow::anyhow!("Invalid VmAction value: {}", val)),
}
}
}
8 changes: 7 additions & 1 deletion src/hyperlight_guest_bin/src/arch/amd64/dispatch.rs
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,12 @@ core::arch::global_asm!("
mov cr4, rdi
flush_done:
call {internal_dispatch_function}\n
mov dx, {halt_port}\n
out dx, eax\n
cli\n
hlt\n
.cfi_endproc
", internal_dispatch_function = sym crate::guest_function::call::internal_dispatch_function);
",
internal_dispatch_function = sym crate::guest_function::call::internal_dispatch_function,
halt_port = const hyperlight_common::outb::VmAction::Halt as u16,
);
8 changes: 7 additions & 1 deletion src/hyperlight_guest_bin/src/arch/amd64/init.rs
Original file line number Diff line number Diff line change
Expand Up @@ -173,6 +173,12 @@ core::arch::global_asm!("
mov rsp, r8\n
xor ebp, ebp\n
call {generic_init}\n
mov dx, {halt_port}\n
out dx, eax\n
cli\n
hlt\n
.cfi_endproc\n
", generic_init = sym crate::generic_init);
",
generic_init = sym crate::generic_init,
halt_port = const hyperlight_common::outb::VmAction::Halt as u16,
);
1 change: 1 addition & 0 deletions src/hyperlight_host/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -133,6 +133,7 @@ trace_guest = ["dep:opentelemetry", "dep:tracing-opentelemetry", "dep:hyperlight
mem_profile = [ "trace_guest", "dep:framehop", "dep:fallible-iterator", "hyperlight-common/mem_profile" ]
kvm = ["dep:kvm-bindings", "dep:kvm-ioctls"]
mshv3 = ["dep:mshv-bindings", "dep:mshv-ioctls"]
hw-interrupts = []
# This enables easy debug in the guest
gdb = ["dep:gdbstub", "dep:gdbstub_arch"]
fuzzing = ["hyperlight-common/fuzzing"]
Expand Down
6 changes: 6 additions & 0 deletions src/hyperlight_host/src/hypervisor/hyperlight_vm/x86_64.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1550,6 +1550,7 @@ mod tests {
// Tests
// ==========================================================================

#[cfg_attr(feature = "hw-interrupts", ignore)]
#[test]
fn reset_vcpu_simple() {
// push rax; hlt - aligns stack to 16 bytes
Expand Down Expand Up @@ -1695,6 +1696,7 @@ mod tests {

use super::*;

#[cfg_attr(feature = "hw-interrupts", ignore)]
#[test]
fn reset_vcpu_regs() {
let mut a = CodeAssembler::new(64).unwrap();
Expand Down Expand Up @@ -1754,6 +1756,7 @@ mod tests {
assert_regs_reset(hyperlight_vm.vm.as_ref());
}

#[cfg_attr(feature = "hw-interrupts", ignore)]
#[test]
fn reset_vcpu_fpu() {
#[cfg(kvm)]
Expand Down Expand Up @@ -1885,6 +1888,7 @@ mod tests {
}
}

#[cfg_attr(feature = "hw-interrupts", ignore)]
#[test]
fn reset_vcpu_debug_regs() {
let mut a = CodeAssembler::new(64).unwrap();
Expand Down Expand Up @@ -1927,6 +1931,7 @@ mod tests {
assert_debug_regs_reset(hyperlight_vm.vm.as_ref());
}

#[cfg_attr(feature = "hw-interrupts", ignore)]
#[test]
fn reset_vcpu_sregs() {
// Build code that modifies special registers and halts
Expand Down Expand Up @@ -1980,6 +1985,7 @@ mod tests {

/// Verifies guest-visible FPU state (via FXSAVE) is properly reset.
/// Unlike tests using hypervisor API, this runs actual guest code with FXSAVE.
#[cfg_attr(feature = "hw-interrupts", ignore)]
#[test]
fn reset_vcpu_fpu_guest_visible_state() {
let mut ctx = hyperlight_vm_with_mem_mgr_fxsave();
Expand Down
1 change: 1 addition & 0 deletions src/hyperlight_host/src/hypervisor/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -469,6 +469,7 @@ pub(crate) mod tests {
use crate::sandbox::{SandboxConfiguration, UninitializedSandbox};
use crate::{Result, is_hypervisor_present, new_error};

#[cfg_attr(feature = "hw-interrupts", ignore)]
#[test]
fn test_initialise() -> Result<()> {
if !is_hypervisor_present() {
Expand Down
Loading
Loading