Skip to content

Commit 57dc8d7

Browse files
committed
Add Vm trait
Signed-off-by: Ludvig Liljenberg <[email protected]>
1 parent 14db106 commit 57dc8d7

File tree

5 files changed

+24
-48
lines changed

5 files changed

+24
-48
lines changed

src/hyperlight_host/Cargo.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -123,7 +123,7 @@ cfg_aliases = "0.2.1"
123123
built = { version = "0.8.0", optional = true, features = ["chrono", "git2"] }
124124

125125
[features]
126-
default = ["kvm", "mshv3", "build-metadata", "init-paging", "gdb"]
126+
default = ["kvm", "mshv3", "build-metadata", "init-paging"]
127127
function_call_metrics = []
128128
executable_heap = []
129129
# This feature enables printing of debug information to stdout in debug builds

src/hyperlight_host/src/hypervisor/hyperlight_vm.rs

Lines changed: 18 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -361,15 +361,6 @@ impl HyperlightVm {
361361
host_funcs: &Arc<Mutex<FunctionRegistry>>,
362362
#[cfg(gdb)] dbg_mem_access_fn: Arc<Mutex<SandboxMemoryManager<HostSharedMemory>>>,
363363
) -> Result<()> {
364-
// ===== KILL() TIMING POINT 1: Between guest function calls =====
365-
// Clear any stale cancellation from a previous guest function call or if kill() was called too early.
366-
// This ensures that kill() called BETWEEN different guest function calls doesn't affect the next call.
367-
//
368-
// If kill() was called and ran to completion BEFORE this line executes:
369-
// - kill() has NO effect on this guest function call because CANCEL_BIT is cleared here.
370-
// - NOTE: stale signals can still be delivered, but they will be ignored.
371-
self.interrupt_handle.clear_cancel();
372-
373364
// Keeps the trace context and open spans
374365
#[cfg(feature = "trace_guest")]
375366
let mut tc = crate::sandbox::trace::TraceContext::new();
@@ -378,9 +369,12 @@ impl HyperlightVm {
378369
// ===== KILL() TIMING POINT 2: Before set_tid() =====
379370
// If kill() is called and ran to completion BEFORE this line executes:
380371
// - CANCEL_BIT will be set and we will return an early VmExit::Cancelled()
372+
// without sending any signals/WHV api calls
381373
#[cfg(any(kvm, mshv3))]
382374
self.interrupt_handle.set_tid();
383375
self.interrupt_handle.set_running();
376+
// NOTE: `set_running()`` must be called before checking `is_cancelled()`
377+
// otherwise we risk missing a call to `kill()` because the vcpu would not be marked as running yet so signals won't be sent
384378

385379
let exit_reason = if self.interrupt_handle.is_cancelled()
386380
|| self.interrupt_handle.is_debug_interrupted()
@@ -390,13 +384,10 @@ impl HyperlightVm {
390384
#[cfg(feature = "trace_guest")]
391385
tc.setup_guest_trace(Span::current().context());
392386

393-
// ===== KILL() TIMING POINT 3: Before calling run_vcpu() =====
387+
// ==== KILL() TIMING POINT 3: Before calling run() ====
394388
// If kill() is called and ran to completion BEFORE this line executes:
395-
// - CANCEL_BIT will be set, but it's too late to prevent entering the guest this iteration
396-
// - Signals will interrupt the guest (RUNNING_BIT=true), causing VmExit::Cancelled()
397-
// - If the guest completes before any signals arrive, kill() may have no effect
398-
// - If there are more iterations to do (IO/host func, etc.), the next iteration will be cancelled
399-
let exit_reason = self.vm.run_vcpu();
389+
// - Will still do a VM entry, but signals will be sent until VM exits
390+
let result = self.vm.run_vcpu();
400391

401392
// End current host trace by closing the current span that captures traces
402393
// happening when a guest exits and re-enters.
@@ -405,12 +396,15 @@ impl HyperlightVm {
405396

406397
// Handle the guest trace data if any
407398
#[cfg(feature = "trace_guest")]
408-
if let Err(e) = self.handle_trace(&mut tc, mem_mgr) {
409-
// If no trace data is available, we just log a message and continue
410-
// Is this the right thing to do?
411-
log::debug!("Error handling guest trace: {:?}", e);
399+
{
400+
let regs = self.vm.regs()?;
401+
if let Err(e) = tc.handle_trace(&regs, mem_mgr) {
402+
// If no trace data is available, we just log a message and continue
403+
// Is this the right thing to do?
404+
log::debug!("Error handling guest trace: {:?}", e);
405+
}
412406
}
413-
exit_reason
407+
result
414408
};
415409

416410
// ===== KILL() TIMING POINT 4: Before clear_running() =====
@@ -511,9 +505,9 @@ impl HyperlightVm {
511505
continue;
512506
}
513507

508+
// If the vcpu was interrupted by a debugger, we need to handle it
514509
#[cfg(gdb)]
515-
if debug_interrupted {
516-
// If the vcpu was interrupted by a debugger, we need to handle it
510+
{
517511
self.interrupt_handle.clear_debug_interrupt();
518512
if let Err(e) =
519513
self.handle_debug(dbg_mem_access_fn.clone(), VcpuStopReason::Interrupt)
@@ -772,16 +766,6 @@ impl HyperlightVm {
772766
Ok(None)
773767
}
774768
}
775-
776-
#[cfg(feature = "trace_guest")]
777-
fn handle_trace(
778-
&mut self,
779-
tc: &mut crate::sandbox::trace::TraceContext,
780-
mem_mgr: &mut SandboxMemoryManager<HostSharedMemory>,
781-
) -> Result<()> {
782-
let regs = self.vm.regs()?;
783-
tc.handle_trace(&regs, mem_mgr)
784-
}
785769
}
786770

787771
impl Drop for HyperlightVm {
@@ -798,7 +782,8 @@ enum MemoryAccess {
798782
StackGuardPageViolation,
799783
}
800784

801-
/// Determines if a memory access violation occurred at the given address with the given action type.
785+
/// Determines if a known memory access violation occurred at the given address with the given action type.
786+
/// Returns Some(reason) if violation reason could be determined, or None if violation occurred but in unmapped region.
802787
fn get_memory_access_violation<'a>(
803788
gpa: usize,
804789
tried: MemoryRegionFlags,

src/hyperlight_host/src/hypervisor/hyperv_linux.rs

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -234,7 +234,6 @@ impl DebuggableVm for MshvVm {
234234
};
235235

236236
use crate::hypervisor::gdb::arch::{BP_EX_ID, DB_EX_ID};
237-
use crate::new_error;
238237

239238
if enabled {
240239
self.vm_fd
@@ -278,7 +277,6 @@ impl DebuggableVm for MshvVm {
278277

279278
fn add_hw_breakpoint(&mut self, addr: u64) -> Result<()> {
280279
use crate::hypervisor::gdb::arch::MAX_NO_OF_HW_BP;
281-
use crate::new_error;
282280

283281
let mut debug_regs = self.vcpu_fd.get_debug_regs()?;
284282

@@ -315,8 +313,6 @@ impl DebuggableVm for MshvVm {
315313
}
316314

317315
fn remove_hw_breakpoint(&mut self, addr: u64) -> Result<()> {
318-
use crate::new_error;
319-
320316
let mut debug_regs = self.vcpu_fd.get_debug_regs()?;
321317

322318
let regs = [

src/hyperlight_host/src/hypervisor/kvm.rs

Lines changed: 2 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -149,13 +149,10 @@ impl Vm for KvmVm {
149149
exception: debug_exit.exception,
150150
}),
151151
Err(e) => match e.errno() {
152+
// InterruptHandle::kill() sends a signal (SIGRTMIN+offset) to interrupt the vcpu, which causes EINTR
152153
libc::EINTR => Ok(VmExit::Cancelled()),
153154
libc::EAGAIN => Ok(VmExit::Retry()),
154-
155-
other => Ok(VmExit::Unknown(format!(
156-
"Unknown KVM VCPU error: {}",
157-
other
158-
))),
155+
_ => Ok(VmExit::Unknown(format!("Unknown KVM VCPU error: {}", e))),
159156
},
160157
Ok(other) => Ok(VmExit::Unknown(format!(
161158
"Unknown KVM VCPU exit: {:?}",
@@ -215,7 +212,6 @@ impl DebuggableVm for KvmVm {
215212

216213
fn add_hw_breakpoint(&mut self, addr: u64) -> Result<()> {
217214
use crate::hypervisor::gdb::arch::MAX_NO_OF_HW_BP;
218-
use crate::new_error;
219215

220216
// Check if breakpoint already exists
221217
if self.debug_regs.arch.debugreg[..4].contains(&addr) {
@@ -238,8 +234,6 @@ impl DebuggableVm for KvmVm {
238234
}
239235

240236
fn remove_hw_breakpoint(&mut self, addr: u64) -> Result<()> {
241-
use crate::new_error;
242-
243237
// Find the index of the breakpoint
244238
let index = self.debug_regs.arch.debugreg[..4]
245239
.iter()

src/hyperlight_host/src/hypervisor/vm.rs

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -56,7 +56,8 @@ pub(crate) trait Vm: Send + Sync + Debug {
5656
/// Unmap memory region from this VM that has previously been mapped using `map_memory`.
5757
fn unmap_memory(&mut self, region: (u32, &MemoryRegion)) -> Result<()>;
5858

59-
/// Runs the vCPU until it exits
59+
/// Runs the vCPU until it exits.
60+
/// Note: this function should not emit any traces or spans as it is called after guest span is setup
6061
fn run_vcpu(&mut self) -> Result<VmExit>;
6162

6263
/// Get partition handle
@@ -92,7 +93,7 @@ pub(crate) enum VmExit {
9293
)
9394
)]
9495
Retry(),
95-
#[cfg(gdb)]
9696
/// The vCPU has exited due to a debug event (usually breakpoint)
97+
#[cfg(gdb)]
9798
Debug { dr6: u64, exception: u32 },
9899
}

0 commit comments

Comments
 (0)