Skip to content
Merged
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
22 changes: 12 additions & 10 deletions src/hyperlight_host/src/hypervisor/hyperv_linux.rs
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@ use super::gdb::{
DebugCommChannel, DebugMemoryAccess, DebugMsg, DebugResponse, GuestDebug, MshvDebug,
VcpuStopReason,
};
use super::{HyperlightExit, Hypervisor, InterruptHandle, LinuxInterruptHandle, VirtualCPU};
use super::{HyperlightExit, Hypervisor, LinuxInterruptHandle, VirtualCPU};
#[cfg(gdb)]
use crate::HyperlightError;
use crate::hypervisor::get_memory_access_violation;
Expand Down Expand Up @@ -647,11 +647,15 @@ impl Hypervisor for HypervLinuxDriver {
.tid
.store(unsafe { libc::pthread_self() as u64 }, Ordering::Release);
// Note: if `InterruptHandle::kill()` is called while this thread is **here**
// Cast to internal trait for access to internal methods
let interrupt_handle_internal =
self.interrupt_handle.as_ref() as &dyn super::InterruptHandleInternal;

// (after set_running_bit but before checking cancel_requested):
// - kill() will stamp cancel_requested with the current generation
// - We will check cancel_requested below and skip the VcpuFd::run() call
// - This is the desired behavior - the kill takes effect immediately
let generation = self.interrupt_handle.set_running_bit();
let generation = interrupt_handle_internal.set_running_bit();

#[cfg(not(gdb))]
let debug_interrupt = false;
Expand All @@ -668,8 +672,7 @@ impl Hypervisor for HypervLinuxDriver {
// - kill() will stamp cancel_requested with the current generation
// - We will proceed with vcpu.run(), but signals will be sent to interrupt it
// - The vcpu will be interrupted and return EINTR (handled below)
let exit_reason = if self
.interrupt_handle
let exit_reason = if interrupt_handle_internal
.is_cancel_requested_for_generation(generation)
|| debug_interrupt
{
Expand All @@ -690,9 +693,8 @@ impl Hypervisor for HypervLinuxDriver {
// - kill() continues sending signals to this thread (running bit is still set)
// - The signals are harmless (no-op handler), we just need to check cancel_requested
// - We load cancel_requested below to determine if this run was cancelled
let cancel_requested = self
.interrupt_handle
.is_cancel_requested_for_generation(generation);
let cancel_requested =
interrupt_handle_internal.is_cancel_requested_for_generation(generation);
#[cfg(gdb)]
let debug_interrupt = self
.interrupt_handle
Expand All @@ -704,7 +706,7 @@ impl Hypervisor for HypervLinuxDriver {
// - kill() continues sending signals until running bit is cleared
// - The newly stamped cancel_requested will affect the NEXT vcpu.run() call
// - Signals sent now are harmless (no-op handler)
self.interrupt_handle.clear_running_bit();
interrupt_handle_internal.clear_running_bit();
// At this point, running bit is clear so kill() will stop sending signals.
// However, we may still receive delayed signals that were sent before clear_running_bit.
// These stale signals are harmless because:
Expand Down Expand Up @@ -799,7 +801,7 @@ impl Hypervisor for HypervLinuxDriver {
// - A signal meant for a different sandbox on the same thread
// In these cases, we return Retry to continue execution.
if cancel_requested {
self.interrupt_handle.clear_cancel_requested();
interrupt_handle_internal.clear_cancel_requested();
HyperlightExit::Cancelled()
} else {
#[cfg(gdb)]
Expand Down Expand Up @@ -868,7 +870,7 @@ impl Hypervisor for HypervLinuxDriver {
self as &mut dyn Hypervisor
}

fn interrupt_handle(&self) -> Arc<dyn InterruptHandle> {
fn interrupt_handle(&self) -> Arc<dyn super::InterruptHandleInternal> {
self.interrupt_handle.clone()
}

Expand Down
33 changes: 19 additions & 14 deletions src/hyperlight_host/src/hypervisor/hyperv_windows.rs
Original file line number Diff line number Diff line change
Expand Up @@ -45,8 +45,8 @@ use super::surrogate_process_manager::*;
use super::windows_hypervisor_platform::{VMPartition, VMProcessor};
use super::wrappers::HandleWrapper;
use super::{HyperlightExit, Hypervisor, InterruptHandle, VirtualCPU};
use crate::hypervisor::get_memory_access_violation;
use crate::hypervisor::regs::{CommonFpu, CommonRegisters};
use crate::hypervisor::{InterruptHandleInternal, get_memory_access_violation};
use crate::mem::memory_region::{MemoryRegion, MemoryRegionFlags};
use crate::mem::mgr::SandboxMemoryManager;
use crate::mem::ptr::{GuestPtr, RawPtr};
Expand Down Expand Up @@ -550,8 +550,12 @@ impl Hypervisor for HypervWindowsDriver {
&mut self,
#[cfg(feature = "trace_guest")] tc: &mut crate::sandbox::trace::TraceContext,
) -> Result<super::HyperlightExit> {
// Cast to internal trait for access to internal methods
let interrupt_handle_internal =
self.interrupt_handle.as_ref() as &dyn super::InterruptHandleInternal;

// Get current generation and set running bit
let generation = self.interrupt_handle.set_running_bit();
let generation = interrupt_handle_internal.set_running_bit();

#[cfg(not(gdb))]
let debug_interrupt = false;
Expand All @@ -562,8 +566,7 @@ impl Hypervisor for HypervWindowsDriver {
.load(Ordering::Relaxed);

// Check if cancellation was requested for THIS generation
let exit_context = if self
.interrupt_handle
let exit_context = if interrupt_handle_internal
.is_cancel_requested_for_generation(generation)
|| debug_interrupt
{
Expand All @@ -581,18 +584,17 @@ impl Hypervisor for HypervWindowsDriver {
};

// Clear running bit
self.interrupt_handle.clear_running_bit();
interrupt_handle_internal.clear_running_bit();

let is_canceled = exit_context.ExitReason == WHV_RUN_VP_EXIT_REASON(8193i32); // WHvRunVpExitReasonCanceled

// Check if this was a manual cancellation (vs internal Windows cancellation)
let cancel_was_requested_manually = self
.interrupt_handle
.is_cancel_requested_for_generation(generation);
let cancel_was_requested_manually =
interrupt_handle_internal.is_cancel_requested_for_generation(generation);

// Only clear cancel_requested if we're actually processing a cancellation for this generation
if is_canceled && cancel_was_requested_manually {
self.interrupt_handle.clear_cancel_requested();
interrupt_handle_internal.clear_cancel_requested();
}

#[cfg(gdb)]
Expand Down Expand Up @@ -752,7 +754,7 @@ impl Hypervisor for HypervWindowsDriver {
self.processor.set_sregs(sregs)
}

fn interrupt_handle(&self) -> Arc<dyn InterruptHandle> {
fn interrupt_handle(&self) -> Arc<dyn super::InterruptHandleInternal> {
self.interrupt_handle.clone()
}

Expand Down Expand Up @@ -1045,19 +1047,22 @@ impl InterruptHandle for WindowsInterruptHandle {
// Only call WHvCancelRunVirtualProcessor if VCPU is actually running in guest mode
running && unsafe { WHvCancelRunVirtualProcessor(self.partition_handle, 0, 0).is_ok() }
}

#[cfg(gdb)]
fn kill_from_debugger(&self) -> bool {
self.debug_interrupt.store(true, Ordering::Relaxed);
let (running, _) = self.get_running_and_generation();
running && unsafe { WHvCancelRunVirtualProcessor(self.partition_handle, 0, 0).is_ok() }
}

fn get_call_active(&self) -> &AtomicBool {
&self.call_active
fn dropped(&self) -> bool {
self.dropped.load(Ordering::Relaxed)
}
}

fn get_dropped(&self) -> &AtomicBool {
&self.dropped
impl InterruptHandleInternal for WindowsInterruptHandle {
fn get_call_active(&self) -> &AtomicBool {
&self.call_active
}

fn get_running(&self) -> &AtomicU64 {
Expand Down
22 changes: 12 additions & 10 deletions src/hyperlight_host/src/hypervisor/kvm.rs
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ use super::gdb::{
DebugCommChannel, DebugMemoryAccess, DebugMsg, DebugResponse, GuestDebug, KvmDebug,
VcpuStopReason,
};
use super::{HyperlightExit, Hypervisor, InterruptHandle, LinuxInterruptHandle, VirtualCPU};
use super::{HyperlightExit, Hypervisor, LinuxInterruptHandle, VirtualCPU};
#[cfg(gdb)]
use crate::HyperlightError;
use crate::hypervisor::get_memory_access_violation;
Expand Down Expand Up @@ -623,11 +623,15 @@ impl Hypervisor for KVMDriver {
.tid
.store(unsafe { libc::pthread_self() as u64 }, Ordering::Release);
// Note: if `InterruptHandle::kill()` is called while this thread is **here**
// Cast to internal trait for access to internal methods
let interrupt_handle_internal =
self.interrupt_handle.as_ref() as &dyn super::InterruptHandleInternal;

// (after set_running_bit but before checking cancel_requested):
// - kill() will stamp cancel_requested with the current generation
// - We will check cancel_requested below and skip the VcpuFd::run() call
// - This is the desired behavior - the kill takes effect immediately
let generation = self.interrupt_handle.set_running_bit();
let generation = interrupt_handle_internal.set_running_bit();

#[cfg(not(gdb))]
let debug_interrupt = false;
Expand All @@ -643,8 +647,7 @@ impl Hypervisor for KVMDriver {
// - kill() will stamp cancel_requested with the current generation
// - We will proceed with vcpu.run(), but signals will be sent to interrupt it
// - The vcpu will be interrupted and return EINTR (handled below)
let exit_reason = if self
.interrupt_handle
let exit_reason = if interrupt_handle_internal
.is_cancel_requested_for_generation(generation)
|| debug_interrupt
{
Expand All @@ -666,9 +669,8 @@ impl Hypervisor for KVMDriver {
// - kill() continues sending signals to this thread (running bit is still set)
// - The signals are harmless (no-op handler), we just need to check cancel_requested
// - We load cancel_requested below to determine if this run was cancelled
let cancel_requested = self
.interrupt_handle
.is_cancel_requested_for_generation(generation);
let cancel_requested =
interrupt_handle_internal.is_cancel_requested_for_generation(generation);
#[cfg(gdb)]
let debug_interrupt = self
.interrupt_handle
Expand All @@ -680,7 +682,7 @@ impl Hypervisor for KVMDriver {
// - kill() continues sending signals until running bit is cleared
// - The newly stamped cancel_requested will affect the NEXT vcpu.run() call
// - Signals sent now are harmless (no-op handler)
self.interrupt_handle.clear_running_bit();
interrupt_handle_internal.clear_running_bit();
// At this point, running bit is clear so kill() will stop sending signals.
// However, we may still receive delayed signals that were sent before clear_running_bit.
// These stale signals are harmless because:
Expand Down Expand Up @@ -744,7 +746,7 @@ impl Hypervisor for KVMDriver {
// - A signal meant for a different sandbox on the same thread
// In these cases, we return Retry to continue execution.
if cancel_requested {
self.interrupt_handle.clear_cancel_requested();
interrupt_handle_internal.clear_cancel_requested();
HyperlightExit::Cancelled()
} else {
#[cfg(gdb)]
Expand Down Expand Up @@ -818,7 +820,7 @@ impl Hypervisor for KVMDriver {
self as &mut dyn Hypervisor
}

fn interrupt_handle(&self) -> Arc<dyn InterruptHandle> {
fn interrupt_handle(&self) -> Arc<dyn super::InterruptHandleInternal> {
self.interrupt_handle.clone()
}

Expand Down
Loading