Skip to content

Commit 1d36c97

Browse files
committed
Rename Hypervisor trait to Vm trait. Rename HyperlightExit to VmExit
Signed-off-by: Ludvig Liljenberg <[email protected]>
1 parent 411b3bd commit 1d36c97

File tree

7 files changed

+142
-143
lines changed

7 files changed

+142
-143
lines changed

src/hyperlight_host/src/hypervisor/gdb/mod.rs

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -31,9 +31,10 @@ use gdbstub::target::TargetError;
3131
use thiserror::Error;
3232
use x86_64_target::HyperlightSandboxTarget;
3333

34+
use super::InterruptHandle;
3435
use super::regs::CommonRegisters;
35-
use super::{Hypervisor, InterruptHandle};
3636
use crate::hypervisor::regs::CommonFpu;
37+
use crate::hypervisor::vm::Vm;
3738
use crate::mem::layout::SandboxMemoryLayout;
3839
use crate::mem::memory_region::MemoryRegion;
3940
use crate::mem::mgr::SandboxMemoryManager;
@@ -276,7 +277,7 @@ pub(crate) enum DebugResponse {
276277

277278
/// Trait for VMs that support debugging capabilities.
278279
/// This extends the base Hypervisor trait with GDB-specific functionality.
279-
pub(crate) trait DebuggableVm: Hypervisor {
280+
pub(crate) trait DebuggableVm: Vm {
280281
/// Translates a guest virtual address to a guest physical address
281282
fn translate_gva(&self, gva: u64) -> crate::Result<u64>;
282283

src/hyperlight_host/src/hypervisor/hyperlight_vm.rs

Lines changed: 18 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -36,13 +36,13 @@ use super::regs::{CommonFpu, CommonRegisters};
3636
#[cfg(target_os = "windows")]
3737
use super::{PartitionState, WindowsInterruptHandle};
3838
use crate::HyperlightError::{ExecutionCanceledByHost, NoHypervisorFound};
39-
#[cfg(not(gdb))]
40-
use crate::hypervisor::Hypervisor;
4139
#[cfg(any(kvm, mshv3))]
4240
use crate::hypervisor::LinuxInterruptHandle;
4341
#[cfg(crashdump)]
4442
use crate::hypervisor::crashdump;
4543
use crate::hypervisor::regs::CommonSpecialRegisters;
44+
#[cfg(not(gdb))]
45+
use crate::hypervisor::virtual_machine::VirtualMachine;
4646
#[cfg(kvm)]
4747
use crate::hypervisor::virtual_machine::kvm::KvmVm;
4848
#[cfg(mshv3)]
@@ -51,7 +51,9 @@ use crate::hypervisor::virtual_machine::mshv::MshvVm;
5151
use crate::hypervisor::virtual_machine::whp::WhpVm;
5252
#[cfg(target_os = "windows")]
5353
use crate::hypervisor::wrappers::HandleWrapper;
54-
use crate::hypervisor::{HyperlightExit, InterruptHandle, InterruptHandleImpl, get_max_log_level};
54+
use crate::hypervisor::{
55+
InterruptHandle, InterruptHandleImpl, get_max_log_level, virtual_machine::VmExit,
56+
};
5557
use crate::mem::memory_region::{MemoryRegion, MemoryRegionFlags, MemoryRegionType};
5658
use crate::mem::mgr::SandboxMemoryManager;
5759
use crate::mem::ptr::{GuestPtr, RawPtr};
@@ -77,7 +79,7 @@ pub(crate) struct HyperlightVm {
7779
#[cfg(gdb)]
7880
vm: Box<dyn DebuggableVm>,
7981
#[cfg(not(gdb))]
80-
vm: Box<dyn Hypervisor>,
82+
vm: Box<dyn VirtualMachine>,
8183
page_size: usize,
8284
entrypoint: u64,
8385
orig_rsp: GuestPtr,
@@ -117,7 +119,7 @@ impl HyperlightVm {
117119
#[cfg(gdb)]
118120
type VmType = Box<dyn DebuggableVm>;
119121
#[cfg(not(gdb))]
120-
type VmType = Box<dyn Hypervisor>;
122+
type VmType = Box<dyn VirtualMachine>;
121123

122124
#[cfg_attr(not(gdb), allow(unused_mut))]
123125
let mut vm: VmType = match get_available_hypervisor() {
@@ -368,7 +370,7 @@ impl HyperlightVm {
368370
let result = loop {
369371
// ===== KILL() TIMING POINT 2: Before set_tid() =====
370372
// If kill() is called and ran to completion BEFORE this line executes:
371-
// - CANCEL_BIT will be set and we will return an early HyperlightExit::Cancelled()
373+
// - CANCEL_BIT will be set and we will return an early VmExit::Cancelled()
372374
// without sending any signals/WHV api calls
373375
#[cfg(any(kvm, mshv3))]
374376
self.interrupt_handle.set_tid();
@@ -379,7 +381,7 @@ impl HyperlightVm {
379381
let exit_reason = if self.interrupt_handle.is_cancelled()
380382
|| self.interrupt_handle.is_debug_interrupted()
381383
{
382-
Ok(HyperlightExit::Cancelled())
384+
Ok(VmExit::Cancelled())
383385
} else {
384386
#[cfg(feature = "trace_guest")]
385387
tc.setup_guest_trace(Span::current().context());
@@ -424,7 +426,7 @@ impl HyperlightVm {
424426
// - Signals will not be sent
425427
match exit_reason {
426428
#[cfg(gdb)]
427-
Ok(HyperlightExit::Debug { dr6, exception }) => {
429+
Ok(VmExit::Debug { dr6, exception }) => {
428430
// Handle debug event (breakpoints)
429431
let stop_reason =
430432
arch::vcpu_stop_reason(self.vm.as_mut(), dr6, self.entrypoint, exception)?;
@@ -433,13 +435,11 @@ impl HyperlightVm {
433435
}
434436
}
435437

436-
Ok(HyperlightExit::Halt()) => {
438+
Ok(VmExit::Halt()) => {
437439
break Ok(());
438440
}
439-
Ok(HyperlightExit::IoOut(port, data)) => {
440-
self.handle_io(mem_mgr, host_funcs, port, data)?
441-
}
442-
Ok(HyperlightExit::MmioRead(addr)) => {
441+
Ok(VmExit::IoOut(port, data)) => self.handle_io(mem_mgr, host_funcs, port, data)?,
442+
Ok(VmExit::MmioRead(addr)) => {
443443
let all_regions = self.sandbox_regions.iter().chain(self.get_mapped_regions());
444444
match get_memory_access_violation(
445445
addr as usize,
@@ -465,7 +465,7 @@ impl HyperlightVm {
465465
}
466466
}
467467
}
468-
Ok(HyperlightExit::MmioWrite(addr)) => {
468+
Ok(VmExit::MmioWrite(addr)) => {
469469
let all_regions = self.sandbox_regions.iter().chain(self.get_mapped_regions());
470470
match get_memory_access_violation(
471471
addr as usize,
@@ -491,15 +491,15 @@ impl HyperlightVm {
491491
}
492492
}
493493
}
494-
Ok(HyperlightExit::Cancelled()) => {
494+
Ok(VmExit::Cancelled()) => {
495495
// If cancellation was not requested for this specific guest function call,
496496
// the vcpu was interrupted by a stale cancellation. This can occur when:
497497
// - Linux: A signal from a previous call arrives late
498498
// - Windows: WHvCancelRunVirtualProcessor called right after vcpu exits but RUNNING_BIT is still true
499499
if !cancel_requested && !debug_interrupted {
500500
// Track that an erroneous vCPU kick occurred
501501
metrics::counter!(METRIC_ERRONEOUS_VCPU_KICKS).increment(1);
502-
// treat this the same as a HyperlightExit::Retry, the cancel was not meant for this call
502+
// treat this the same as a VmExit::Retry, the cancel was not meant for this call
503503
continue;
504504
}
505505

@@ -517,10 +517,10 @@ impl HyperlightVm {
517517
metrics::counter!(METRIC_GUEST_CANCELLATION).increment(1);
518518
break Err(ExecutionCanceledByHost());
519519
}
520-
Ok(HyperlightExit::Unknown(reason)) => {
520+
Ok(VmExit::Unknown(reason)) => {
521521
break Err(new_error!("Unexpected VM Exit: {:?}", reason));
522522
}
523-
Ok(HyperlightExit::Retry()) => continue,
523+
Ok(VmExit::Retry()) => continue,
524524
Err(e) => {
525525
break Err(e);
526526
}

src/hyperlight_host/src/hypervisor/mod.rs

Lines changed: 0 additions & 81 deletions
Original file line numberDiff line numberDiff line change
@@ -16,10 +16,6 @@ limitations under the License.
1616

1717
use log::LevelFilter;
1818

19-
use crate::Result;
20-
use crate::hypervisor::regs::{CommonFpu, CommonRegisters, CommonSpecialRegisters};
21-
use crate::mem::memory_region::MemoryRegion;
22-
2319
/// GDB debugging support
2420
#[cfg(gdb)]
2521
pub(crate) mod gdb;
@@ -53,83 +49,6 @@ use std::sync::atomic::{AtomicU8, Ordering};
5349
#[cfg(any(kvm, mshv3))]
5450
use std::time::Duration;
5551

56-
pub(crate) enum HyperlightExit {
57-
/// The vCPU has exited due to a debug event (usually breakpoint)
58-
#[cfg(gdb)]
59-
Debug { dr6: u64, exception: u32 },
60-
/// The vCPU has halted
61-
Halt(),
62-
/// The vCPU has issued a write to the given port with the given value
63-
IoOut(u16, Vec<u8>),
64-
/// The vCPU tried to read from the given (unmapped) addr
65-
MmioRead(u64),
66-
/// The vCPU tried to write to the given (unmapped) addr
67-
MmioWrite(u64),
68-
/// The vCPU execution has been cancelled
69-
Cancelled(),
70-
/// The vCPU has exited for a reason that is not handled by Hyperlight
71-
Unknown(String),
72-
/// The operation should be retried, for example this can happen on Linux where a call to run the CPU can return EAGAIN
73-
#[cfg_attr(
74-
target_os = "windows",
75-
expect(
76-
dead_code,
77-
reason = "Retry() is never constructed on Windows, but it is still matched on (which dead_code lint ignores)"
78-
)
79-
)]
80-
Retry(),
81-
}
82-
83-
/// Trait for single-vCPU VMs. Provides a common interface for basic VM operations.
84-
/// Abstracts over differences between KVM, MSHV and WHP implementations.
85-
pub(crate) trait Hypervisor: Debug + Send {
86-
/// Map memory region into this VM
87-
///
88-
/// # Safety
89-
/// The caller must ensure that the memory region is valid and points to valid memory,
90-
/// and lives long enough for the VM to use it.
91-
/// The caller must ensure that the given u32 is not already mapped, otherwise previously mapped
92-
/// memory regions may be overwritten.
93-
/// The memory region must not overlap with an existing region, and depending on platform, must be aligned to page boundaries.
94-
unsafe fn map_memory(&mut self, region: (u32, &MemoryRegion)) -> Result<()>;
95-
96-
/// Unmap memory region from this VM that has previously been mapped using `map_memory`.
97-
fn unmap_memory(&mut self, region: (u32, &MemoryRegion)) -> Result<()>;
98-
99-
/// Runs the vCPU until it exits.
100-
/// Note: this function should not emit any traces or spans as it is called after guest span is setup
101-
fn run_vcpu(&mut self) -> Result<HyperlightExit>;
102-
103-
/// Get regs
104-
#[allow(dead_code)]
105-
fn regs(&self) -> Result<CommonRegisters>;
106-
/// Set regs
107-
fn set_regs(&self, regs: &CommonRegisters) -> Result<()>;
108-
/// Get fpu regs
109-
#[allow(dead_code)]
110-
fn fpu(&self) -> Result<CommonFpu>;
111-
/// Set fpu regs
112-
fn set_fpu(&self, fpu: &CommonFpu) -> Result<()>;
113-
/// Get special regs
114-
#[allow(dead_code)]
115-
fn sregs(&self) -> Result<CommonSpecialRegisters>;
116-
/// Set special regs
117-
fn set_sregs(&self, sregs: &CommonSpecialRegisters) -> Result<()>;
118-
119-
/// xsave
120-
#[cfg(crashdump)]
121-
fn xsave(&self) -> Result<Vec<u8>>;
122-
123-
/// Get partition handle
124-
#[cfg(target_os = "windows")]
125-
fn partition_handle(&self) -> windows::Win32::System::Hypervisor::WHV_PARTITION_HANDLE;
126-
127-
/// Mark that initial memory setup is complete. After this, map_memory will fail.
128-
/// This is only needed on Windows where dynamic memory mapping is not yet supported.
129-
#[cfg(target_os = "windows")]
130-
fn complete_initial_memory_setup(&mut self);
131-
}
132-
13352
/// Get the logging level to pass to the guest entrypoint
13453
fn get_max_log_level() -> u32 {
13554
// Check to see if the RUST_LOG environment variable is set

src/hyperlight_host/src/hypervisor/virtual_machine/kvm.rs

Lines changed: 12 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ use tracing::{Span, instrument};
2626
#[cfg(gdb)]
2727
use crate::hypervisor::gdb::DebuggableVm;
2828
use crate::hypervisor::regs::{CommonFpu, CommonRegisters, CommonSpecialRegisters};
29-
use crate::hypervisor::{HyperlightExit, Hypervisor};
29+
use crate::hypervisor::virtual_machine::{VirtualMachine, VmExit};
3030
use crate::mem::memory_region::MemoryRegion;
3131
use crate::{Result, new_error};
3232

@@ -85,7 +85,7 @@ impl KvmVm {
8585
}
8686
}
8787

88-
impl Hypervisor for KvmVm {
88+
impl VirtualMachine for KvmVm {
8989
unsafe fn map_memory(&mut self, (slot, region): (u32, &MemoryRegion)) -> Result<()> {
9090
let mut kvm_region: kvm_userspace_memory_region = region.into();
9191
kvm_region.slot = slot;
@@ -104,27 +104,24 @@ impl Hypervisor for KvmVm {
104104
Ok(())
105105
}
106106

107-
fn run_vcpu(&mut self) -> Result<HyperlightExit> {
107+
fn run_vcpu(&mut self) -> Result<VmExit> {
108108
match self.vcpu_fd.run() {
109-
Ok(VcpuExit::Hlt) => Ok(HyperlightExit::Halt()),
110-
Ok(VcpuExit::IoOut(port, data)) => Ok(HyperlightExit::IoOut(port, data.to_vec())),
111-
Ok(VcpuExit::MmioRead(addr, _)) => Ok(HyperlightExit::MmioRead(addr)),
112-
Ok(VcpuExit::MmioWrite(addr, _)) => Ok(HyperlightExit::MmioWrite(addr)),
109+
Ok(VcpuExit::Hlt) => Ok(VmExit::Halt()),
110+
Ok(VcpuExit::IoOut(port, data)) => Ok(VmExit::IoOut(port, data.to_vec())),
111+
Ok(VcpuExit::MmioRead(addr, _)) => Ok(VmExit::MmioRead(addr)),
112+
Ok(VcpuExit::MmioWrite(addr, _)) => Ok(VmExit::MmioWrite(addr)),
113113
#[cfg(gdb)]
114-
Ok(VcpuExit::Debug(debug_exit)) => Ok(HyperlightExit::Debug {
114+
Ok(VcpuExit::Debug(debug_exit)) => Ok(VmExit::Debug {
115115
dr6: debug_exit.dr6,
116116
exception: debug_exit.exception,
117117
}),
118118
Err(e) => match e.errno() {
119119
// InterruptHandle::kill() sends a signal (SIGRTMIN+offset) to interrupt the vcpu, which causes EINTR
120-
libc::EINTR => Ok(HyperlightExit::Cancelled()),
121-
libc::EAGAIN => Ok(HyperlightExit::Retry()),
122-
_ => Ok(HyperlightExit::Unknown(format!(
123-
"Unknown KVM VCPU error: {}",
124-
e
125-
))),
120+
libc::EINTR => Ok(VmExit::Cancelled()),
121+
libc::EAGAIN => Ok(VmExit::Retry()),
122+
_ => Ok(VmExit::Unknown(format!("Unknown KVM VCPU error: {}", e))),
126123
},
127-
Ok(other) => Ok(HyperlightExit::Unknown(format!(
124+
Ok(other) => Ok(VmExit::Unknown(format!(
128125
"Unknown KVM VCPU exit: {:?}",
129126
other
130127
))),

src/hyperlight_host/src/hypervisor/virtual_machine/mod.rs

Lines changed: 82 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,8 @@
1+
use crate::Result;
2+
use crate::hypervisor::regs::{CommonFpu, CommonRegisters, CommonSpecialRegisters};
3+
use crate::mem::memory_region::MemoryRegion;
4+
use std::fmt::Debug;
5+
16
#[cfg(kvm)]
27
/// Functionality to manipulate KVM-based virtual machines
38
pub(crate) mod kvm;
@@ -6,3 +11,80 @@ pub(crate) mod kvm;
611
pub(crate) mod mshv;
712
#[cfg(target_os = "windows")]
813
pub(crate) mod whp;
14+
15+
pub(crate) enum VmExit {
16+
/// The vCPU has exited due to a debug event (usually breakpoint)
17+
#[cfg(gdb)]
18+
Debug { dr6: u64, exception: u32 },
19+
/// The vCPU has halted
20+
Halt(),
21+
/// The vCPU has issued a write to the given port with the given value
22+
IoOut(u16, Vec<u8>),
23+
/// The vCPU tried to read from the given (unmapped) addr
24+
MmioRead(u64),
25+
/// The vCPU tried to write to the given (unmapped) addr
26+
MmioWrite(u64),
27+
/// The vCPU execution has been cancelled
28+
Cancelled(),
29+
/// The vCPU has exited for a reason that is not handled by Hyperlight
30+
Unknown(String),
31+
/// The operation should be retried, for example this can happen on Linux where a call to run the CPU can return EAGAIN
32+
#[cfg_attr(
33+
target_os = "windows",
34+
expect(
35+
dead_code,
36+
reason = "Retry() is never constructed on Windows, but it is still matched on (which dead_code lint ignores)"
37+
)
38+
)]
39+
Retry(),
40+
}
41+
42+
/// Trait for single-vCPU VMs. Provides a common interface for basic VM operations.
43+
/// Abstracts over differences between KVM, MSHV and WHP implementations.
44+
pub(crate) trait VirtualMachine: Debug + Send {
45+
/// Map memory region into this VM
46+
///
47+
/// # Safety
48+
/// The caller must ensure that the memory region is valid and points to valid memory,
49+
/// and lives long enough for the VM to use it.
50+
/// The caller must ensure that the given u32 is not already mapped, otherwise previously mapped
51+
/// memory regions may be overwritten.
52+
/// The memory region must not overlap with an existing region, and depending on platform, must be aligned to page boundaries.
53+
unsafe fn map_memory(&mut self, region: (u32, &MemoryRegion)) -> Result<()>;
54+
55+
/// Unmap memory region from this VM that has previously been mapped using `map_memory`.
56+
fn unmap_memory(&mut self, region: (u32, &MemoryRegion)) -> Result<()>;
57+
58+
/// Runs the vCPU until it exits.
59+
/// Note: this function should not emit any traces or spans as it is called after guest span is setup
60+
fn run_vcpu(&mut self) -> Result<VmExit>;
61+
62+
/// Get regs
63+
#[allow(dead_code)]
64+
fn regs(&self) -> Result<CommonRegisters>;
65+
/// Set regs
66+
fn set_regs(&self, regs: &CommonRegisters) -> Result<()>;
67+
/// Get fpu regs
68+
#[allow(dead_code)]
69+
fn fpu(&self) -> Result<CommonFpu>;
70+
/// Set fpu regs
71+
fn set_fpu(&self, fpu: &CommonFpu) -> Result<()>;
72+
/// Get special regs
73+
#[allow(dead_code)]
74+
fn sregs(&self) -> Result<CommonSpecialRegisters>;
75+
/// Set special regs
76+
fn set_sregs(&self, sregs: &CommonSpecialRegisters) -> Result<()>;
77+
78+
/// xsave
79+
#[cfg(crashdump)]
80+
fn xsave(&self) -> Result<Vec<u8>>;
81+
82+
/// Get partition handle
83+
#[cfg(target_os = "windows")]
84+
fn partition_handle(&self) -> windows::Win32::System::Hypervisor::WHV_PARTITION_HANDLE;
85+
86+
/// Mark that initial memory setup is complete. After this, map_memory will fail.
87+
/// This is only needed on Windows where dynamic memory mapping is not yet supported.
88+
#[cfg(target_os = "windows")]
89+
fn complete_initial_memory_setup(&mut self);
90+
}

0 commit comments

Comments
 (0)