Skip to content

Commit a73c804

Browse files
authored
Move and rename some Vm traits (#1105)
* Move kvm,hyperv_linux/hyperv_windows into vm module Signed-off-by: Ludvig Liljenberg <4257730+ludfjig@users.noreply.github.com> Clean up import paths after file move Signed-off-by: Ludvig Liljenberg <4257730+ludfjig@users.noreply.github.com> Rename hyperv_linux to mshv, hyperv_windows to whp Signed-off-by: Ludvig Liljenberg <4257730+ludfjig@users.noreply.github.com> * Rename Hypervisor trait to Vm trait. Rename HyperlightExit to VmExit Signed-off-by: Ludvig Liljenberg <4257730+ludfjig@users.noreply.github.com> * Move hypervisor-related functions out of sandbox module Signed-off-by: Ludvig Liljenberg <4257730+ludfjig@users.noreply.github.com> * License header + cargo fmt Signed-off-by: Ludvig Liljenberg <4257730+ludfjig@users.noreply.github.com> * Update comments based on PR feedback Signed-off-by: Ludvig Liljenberg <4257730+ludfjig@users.noreply.github.com> --------- Signed-off-by: Ludvig Liljenberg <4257730+ludfjig@users.noreply.github.com>
1 parent c4ac95e commit a73c804

File tree

10 files changed

+299
-219
lines changed

10 files changed

+299
-219
lines changed

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

Lines changed: 4 additions & 3 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::virtual_machine::VirtualMachine;
3738
use crate::mem::layout::SandboxMemoryLayout;
3839
use crate::mem::memory_region::MemoryRegion;
3940
use crate::mem::mgr::SandboxMemoryManager;
@@ -275,8 +276,8 @@ pub(crate) enum DebugResponse {
275276
}
276277

277278
/// Trait for VMs that support debugging capabilities.
278-
/// This extends the base Hypervisor trait with GDB-specific functionality.
279-
pub(crate) trait DebuggableVm: Hypervisor {
279+
/// This extends the base VirtualMachine trait with GDB-specific functionality.
280+
pub(crate) trait DebuggableVm: VirtualMachine {
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: 22 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -36,30 +36,30 @@ 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;
43+
use crate::hypervisor::regs::CommonSpecialRegisters;
44+
#[cfg(not(gdb))]
45+
use crate::hypervisor::virtual_machine::VirtualMachine;
46+
#[cfg(kvm)]
47+
use crate::hypervisor::virtual_machine::kvm::KvmVm;
4548
#[cfg(mshv3)]
46-
use crate::hypervisor::hyperv_linux::MshvVm;
49+
use crate::hypervisor::virtual_machine::mshv::MshvVm;
4750
#[cfg(target_os = "windows")]
48-
use crate::hypervisor::hyperv_windows::WhpVm;
49-
#[cfg(kvm)]
50-
use crate::hypervisor::kvm::KvmVm;
51-
use crate::hypervisor::regs::CommonSpecialRegisters;
51+
use crate::hypervisor::virtual_machine::whp::WhpVm;
52+
use crate::hypervisor::virtual_machine::{HypervisorType, VmExit, get_available_hypervisor};
5253
#[cfg(target_os = "windows")]
5354
use crate::hypervisor::wrappers::HandleWrapper;
54-
use crate::hypervisor::{HyperlightExit, InterruptHandle, InterruptHandleImpl, get_max_log_level};
55+
use crate::hypervisor::{InterruptHandle, InterruptHandleImpl, get_max_log_level};
5556
use crate::mem::memory_region::{MemoryRegion, MemoryRegionFlags, MemoryRegionType};
5657
use crate::mem::mgr::SandboxMemoryManager;
5758
use crate::mem::ptr::{GuestPtr, RawPtr};
5859
use crate::mem::shared_mem::HostSharedMemory;
5960
use crate::metrics::{METRIC_ERRONEOUS_VCPU_KICKS, METRIC_GUEST_CANCELLATION};
6061
use crate::sandbox::SandboxConfiguration;
6162
use crate::sandbox::host_funcs::FunctionRegistry;
62-
use crate::sandbox::hypervisor::{HypervisorType, get_available_hypervisor};
6363
use crate::sandbox::outb::handle_outb;
6464
#[cfg(feature = "mem_profile")]
6565
use crate::sandbox::trace::MemTraceInfo;
@@ -77,7 +77,7 @@ pub(crate) struct HyperlightVm {
7777
#[cfg(gdb)]
7878
vm: Box<dyn DebuggableVm>,
7979
#[cfg(not(gdb))]
80-
vm: Box<dyn Hypervisor>,
80+
vm: Box<dyn VirtualMachine>,
8181
page_size: usize,
8282
entrypoint: u64,
8383
orig_rsp: GuestPtr,
@@ -117,7 +117,7 @@ impl HyperlightVm {
117117
#[cfg(gdb)]
118118
type VmType = Box<dyn DebuggableVm>;
119119
#[cfg(not(gdb))]
120-
type VmType = Box<dyn Hypervisor>;
120+
type VmType = Box<dyn VirtualMachine>;
121121

122122
#[cfg_attr(not(gdb), allow(unused_mut))]
123123
let mut vm: VmType = match get_available_hypervisor() {
@@ -368,7 +368,7 @@ impl HyperlightVm {
368368
let result = loop {
369369
// ===== KILL() TIMING POINT 2: Before set_tid() =====
370370
// 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()
371+
// - CANCEL_BIT will be set and we will return an early VmExit::Cancelled()
372372
// without sending any signals/WHV api calls
373373
#[cfg(any(kvm, mshv3))]
374374
self.interrupt_handle.set_tid();
@@ -379,7 +379,7 @@ impl HyperlightVm {
379379
let exit_reason = if self.interrupt_handle.is_cancelled()
380380
|| self.interrupt_handle.is_debug_interrupted()
381381
{
382-
Ok(HyperlightExit::Cancelled())
382+
Ok(VmExit::Cancelled())
383383
} else {
384384
#[cfg(feature = "trace_guest")]
385385
tc.setup_guest_trace(Span::current().context());
@@ -424,7 +424,7 @@ impl HyperlightVm {
424424
// - Signals will not be sent
425425
match exit_reason {
426426
#[cfg(gdb)]
427-
Ok(HyperlightExit::Debug { dr6, exception }) => {
427+
Ok(VmExit::Debug { dr6, exception }) => {
428428
// Handle debug event (breakpoints)
429429
let stop_reason =
430430
arch::vcpu_stop_reason(self.vm.as_mut(), dr6, self.entrypoint, exception)?;
@@ -433,13 +433,11 @@ impl HyperlightVm {
433433
}
434434
}
435435

436-
Ok(HyperlightExit::Halt()) => {
436+
Ok(VmExit::Halt()) => {
437437
break Ok(());
438438
}
439-
Ok(HyperlightExit::IoOut(port, data)) => {
440-
self.handle_io(mem_mgr, host_funcs, port, data)?
441-
}
442-
Ok(HyperlightExit::MmioRead(addr)) => {
439+
Ok(VmExit::IoOut(port, data)) => self.handle_io(mem_mgr, host_funcs, port, data)?,
440+
Ok(VmExit::MmioRead(addr)) => {
443441
let all_regions = self.sandbox_regions.iter().chain(self.get_mapped_regions());
444442
match get_memory_access_violation(
445443
addr as usize,
@@ -465,7 +463,7 @@ impl HyperlightVm {
465463
}
466464
}
467465
}
468-
Ok(HyperlightExit::MmioWrite(addr)) => {
466+
Ok(VmExit::MmioWrite(addr)) => {
469467
let all_regions = self.sandbox_regions.iter().chain(self.get_mapped_regions());
470468
match get_memory_access_violation(
471469
addr as usize,
@@ -491,15 +489,15 @@ impl HyperlightVm {
491489
}
492490
}
493491
}
494-
Ok(HyperlightExit::Cancelled()) => {
492+
Ok(VmExit::Cancelled()) => {
495493
// If cancellation was not requested for this specific guest function call,
496494
// the vcpu was interrupted by a stale cancellation. This can occur when:
497495
// - Linux: A signal from a previous call arrives late
498496
// - Windows: WHvCancelRunVirtualProcessor called right after vcpu exits but RUNNING_BIT is still true
499497
if !cancel_requested && !debug_interrupted {
500498
// Track that an erroneous vCPU kick occurred
501499
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
500+
// treat this the same as a VmExit::Retry, the cancel was not meant for this call
503501
continue;
504502
}
505503

@@ -517,10 +515,10 @@ impl HyperlightVm {
517515
metrics::counter!(METRIC_GUEST_CANCELLATION).increment(1);
518516
break Err(ExecutionCanceledByHost());
519517
}
520-
Ok(HyperlightExit::Unknown(reason)) => {
518+
Ok(VmExit::Unknown(reason)) => {
521519
break Err(new_error!("Unexpected VM Exit: {:?}", reason));
522520
}
523-
Ok(HyperlightExit::Retry()) => continue,
521+
Ok(VmExit::Retry()) => continue,
524522
Err(e) => {
525523
break Err(e);
526524
}

src/hyperlight_host/src/hypervisor/mod.rs

Lines changed: 1 addition & 90 deletions
Original file line numberDiff line numberDiff line change
@@ -16,26 +16,14 @@ 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-
23-
/// HyperV-on-linux functionality
24-
#[cfg(mshv3)]
25-
pub(crate) mod hyperv_linux;
26-
#[cfg(target_os = "windows")]
27-
pub(crate) mod hyperv_windows;
28-
2919
/// GDB debugging support
3020
#[cfg(gdb)]
3121
pub(crate) mod gdb;
3222

3323
/// Abstracts over different hypervisor register representations
3424
pub(crate) mod regs;
3525

36-
#[cfg(kvm)]
37-
/// Functionality to manipulate KVM-based virtual machines
38-
pub(crate) mod kvm;
26+
pub(crate) mod virtual_machine;
3927

4028
#[cfg(target_os = "windows")]
4129
/// Hyperlight Surrogate Process
@@ -61,83 +49,6 @@ use std::sync::atomic::{AtomicU8, Ordering};
6149
#[cfg(any(kvm, mshv3))]
6250
use std::time::Duration;
6351

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

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

Lines changed: 19 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,8 @@ use tracing::{Span, instrument};
2525

2626
#[cfg(gdb)]
2727
use crate::hypervisor::gdb::DebuggableVm;
28-
use crate::hypervisor::{HyperlightExit, Hypervisor};
28+
use crate::hypervisor::regs::{CommonFpu, CommonRegisters, CommonSpecialRegisters};
29+
use crate::hypervisor::virtual_machine::{VirtualMachine, VmExit};
2930
use crate::mem::memory_region::MemoryRegion;
3031
use crate::{Result, new_error};
3132

@@ -84,7 +85,7 @@ impl KvmVm {
8485
}
8586
}
8687

87-
impl Hypervisor for KvmVm {
88+
impl VirtualMachine for KvmVm {
8889
unsafe fn map_memory(&mut self, (slot, region): (u32, &MemoryRegion)) -> Result<()> {
8990
let mut kvm_region: kvm_userspace_memory_region = region.into();
9091
kvm_region.slot = slot;
@@ -103,61 +104,58 @@ impl Hypervisor for KvmVm {
103104
Ok(())
104105
}
105106

106-
fn run_vcpu(&mut self) -> Result<HyperlightExit> {
107+
fn run_vcpu(&mut self) -> Result<VmExit> {
107108
match self.vcpu_fd.run() {
108-
Ok(VcpuExit::Hlt) => Ok(HyperlightExit::Halt()),
109-
Ok(VcpuExit::IoOut(port, data)) => Ok(HyperlightExit::IoOut(port, data.to_vec())),
110-
Ok(VcpuExit::MmioRead(addr, _)) => Ok(HyperlightExit::MmioRead(addr)),
111-
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)),
112113
#[cfg(gdb)]
113-
Ok(VcpuExit::Debug(debug_exit)) => Ok(HyperlightExit::Debug {
114+
Ok(VcpuExit::Debug(debug_exit)) => Ok(VmExit::Debug {
114115
dr6: debug_exit.dr6,
115116
exception: debug_exit.exception,
116117
}),
117118
Err(e) => match e.errno() {
118119
// InterruptHandle::kill() sends a signal (SIGRTMIN+offset) to interrupt the vcpu, which causes EINTR
119-
libc::EINTR => Ok(HyperlightExit::Cancelled()),
120-
libc::EAGAIN => Ok(HyperlightExit::Retry()),
121-
_ => Ok(HyperlightExit::Unknown(format!(
122-
"Unknown KVM VCPU error: {}",
123-
e
124-
))),
120+
libc::EINTR => Ok(VmExit::Cancelled()),
121+
libc::EAGAIN => Ok(VmExit::Retry()),
122+
_ => Ok(VmExit::Unknown(format!("Unknown KVM VCPU error: {}", e))),
125123
},
126-
Ok(other) => Ok(HyperlightExit::Unknown(format!(
124+
Ok(other) => Ok(VmExit::Unknown(format!(
127125
"Unknown KVM VCPU exit: {:?}",
128126
other
129127
))),
130128
}
131129
}
132130

133-
fn regs(&self) -> Result<super::regs::CommonRegisters> {
131+
fn regs(&self) -> Result<CommonRegisters> {
134132
let kvm_regs = self.vcpu_fd.get_regs()?;
135133
Ok((&kvm_regs).into())
136134
}
137135

138-
fn set_regs(&self, regs: &super::regs::CommonRegisters) -> Result<()> {
136+
fn set_regs(&self, regs: &CommonRegisters) -> Result<()> {
139137
let kvm_regs: kvm_regs = regs.into();
140138
self.vcpu_fd.set_regs(&kvm_regs)?;
141139
Ok(())
142140
}
143141

144-
fn fpu(&self) -> Result<super::regs::CommonFpu> {
142+
fn fpu(&self) -> Result<CommonFpu> {
145143
let kvm_fpu = self.vcpu_fd.get_fpu()?;
146144
Ok((&kvm_fpu).into())
147145
}
148146

149-
fn set_fpu(&self, fpu: &super::regs::CommonFpu) -> Result<()> {
147+
fn set_fpu(&self, fpu: &CommonFpu) -> Result<()> {
150148
let kvm_fpu: kvm_fpu = fpu.into();
151149
self.vcpu_fd.set_fpu(&kvm_fpu)?;
152150
Ok(())
153151
}
154152

155-
fn sregs(&self) -> Result<super::regs::CommonSpecialRegisters> {
153+
fn sregs(&self) -> Result<CommonSpecialRegisters> {
156154
let kvm_sregs = self.vcpu_fd.get_sregs()?;
157155
Ok((&kvm_sregs).into())
158156
}
159157

160-
fn set_sregs(&self, sregs: &super::regs::CommonSpecialRegisters) -> Result<()> {
158+
fn set_sregs(&self, sregs: &CommonSpecialRegisters) -> Result<()> {
161159
let kvm_sregs: kvm_sregs = sregs.into();
162160
self.vcpu_fd.set_sregs(&kvm_sregs)?;
163161
Ok(())

0 commit comments

Comments
 (0)