Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
22 commits
Select commit Hold shift + click to select a range
edfabe0
feat: add PIC emulation, OutBAction variants, and guest halt mechanism
danbugs Mar 3, 2026
84c445d
feat(kvm): add hardware interrupt support with in-kernel IRQ chip
danbugs Mar 3, 2026
e41d70f
feat(mshv): add hardware interrupt support with SynIC timer
danbugs Mar 3, 2026
cb4c57b
feat(whp): add hardware interrupt support with software timer
danbugs Mar 3, 2026
98ce71b
test: add hardware interrupt unit and integration tests
danbugs Mar 3, 2026
9d3da8d
ci: add hw-interrupts test step to CI and Justfile
danbugs Mar 3, 2026
99c6a5c
fix: add halt port IO write and restore hw_timer_interrupts test
danbugs Mar 4, 2026
3485143
style: add trailing newline to integration_test.rs
danbugs Mar 4, 2026
48be92f
experiment: replace in-kernel PIT with irqfd + host timer thread
danbugs Mar 5, 2026
080e907
experiment: MSHV — replace SynIC timer with request_virtual_interrupt…
danbugs Mar 5, 2026
ff51d34
experiment: eliminate PIC state machine — hardcode vector 0x20, no-op…
danbugs Mar 5, 2026
97e41df
fix: delete unused pic.rs file
danbugs Mar 6, 2026
a33bf5d
style: rustfmt fixes in kvm.rs
danbugs Mar 6, 2026
6db012b
refactor: address PR 1272 review feedback
danbugs Mar 6, 2026
246718e
fix: reset timer_stop flag before spawning timer thread
danbugs Mar 7, 2026
5d0530e
Address copilot review feedback
danbugs Mar 10, 2026
90fc669
Fix formatting (rustfmt nightly)
danbugs Mar 10, 2026
0a2b317
Fix clippy collapsible-if in KVM timer config
danbugs Mar 10, 2026
02622fa
fix: remove disallowed assert! macros from LAPIC helpers
danbugs Mar 10, 2026
9a702c8
refactor: extract hw-interrupts and default vCPU run into separate me…
danbugs Mar 10, 2026
8014fb5
fix: preserve RAX across halt sequence in init and dispatch
danbugs Mar 10, 2026
14c13a1
refactor: split OutBAction into OutBAction + VmAction, move hw_interr…
danbugs Mar 13, 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)),
}
}
}
3 changes: 3 additions & 0 deletions src/hyperlight_guest_bin/src/arch/amd64/dispatch.rs
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,9 @@ core::arch::global_asm!("
mov cr4, rdi
flush_done:
call {internal_dispatch_function}\n
mov dx, 108\n
out dx, eax\n
cli\n
hlt\n
.cfi_endproc
", internal_dispatch_function = sym crate::guest_function::call::internal_dispatch_function);
3 changes: 3 additions & 0 deletions src/hyperlight_guest_bin/src/arch/amd64/init.rs
Original file line number Diff line number Diff line change
Expand Up @@ -173,6 +173,9 @@ core::arch::global_asm!("
mov rsp, r8\n
xor ebp, ebp\n
call {generic_init}\n
mov dx, 108\n
out dx, eax\n
cli\n
hlt\n
.cfi_endproc\n
", generic_init = sym crate::generic_init);
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