Skip to content

Commit 0f86a4f

Browse files
committed
Implement Vm constructor + trait cleanup
Signed-off-by: Ludvig Liljenberg <[email protected]>
1 parent efafa78 commit 0f86a4f

File tree

9 files changed

+522
-1219
lines changed

9 files changed

+522
-1219
lines changed

src/hyperlight_host/src/hypervisor/hyperlight_vm.rs

Lines changed: 173 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
Copyright 2025 The Hyperlight Authors.
2+
Copyright 2024 The Hyperlight Authors.
33
44
Licensed under the Apache License, Version 2.0 (the "License");
55
you may not use this file except in compliance with the License.
@@ -14,17 +14,56 @@ See the License for the specific language governing permissions and
1414
limitations under the License.
1515
*/
1616

17-
use crate::Result;
17+
#[cfg(gdb)]
18+
use std::collections::HashMap;
19+
#[cfg(crashdump)]
20+
use std::path::Path;
21+
#[cfg(any(kvm, mshv3))]
22+
use std::sync::atomic::AtomicU64;
23+
use std::sync::atomic::{AtomicBool, AtomicU8};
24+
use std::sync::{Arc, Mutex};
25+
26+
use log::LevelFilter;
27+
use tracing::{Span, instrument};
28+
#[cfg(feature = "trace_guest")]
29+
use tracing_opentelemetry::OpenTelemetrySpanExt;
1830

19-
use crate::hypervisor::{Hypervisor, InterruptHandle};
20-
use crate::mem::memory_region::MemoryRegion;
31+
#[cfg(target_os = "windows")]
32+
use super::WindowsInterruptHandle;
33+
#[cfg(gdb)]
34+
use super::gdb::{DebugCommChannel, DebugMsg, DebugResponse, DebuggableVm, VcpuStopReason, arch};
35+
use super::regs::{CommonFpu, CommonRegisters};
36+
use crate::HyperlightError::{ExecutionCanceledByHost, NoHypervisorFound};
37+
#[cfg(not(gdb))]
38+
use crate::hypervisor::Hypervisor;
39+
#[cfg(any(kvm, mshv3))]
40+
use crate::hypervisor::LinuxInterruptHandle;
41+
#[cfg(crashdump)]
42+
use crate::hypervisor::crashdump;
43+
#[cfg(mshv3)]
44+
use crate::hypervisor::hyperv_linux::MshvVm;
45+
#[cfg(target_os = "windows")]
46+
use crate::hypervisor::hyperv_windows::WhpVm;
47+
#[cfg(kvm)]
48+
use crate::hypervisor::kvm::KvmVm;
49+
use crate::hypervisor::regs::CommonSpecialRegisters;
50+
#[cfg(target_os = "windows")]
51+
use crate::hypervisor::wrappers::HandleWrapper;
52+
use crate::hypervisor::{HyperlightExit, InterruptHandle, InterruptHandleImpl, get_max_log_level};
53+
use crate::mem::memory_region::{MemoryRegion, MemoryRegionFlags, MemoryRegionType};
2154
use crate::mem::mgr::SandboxMemoryManager;
22-
use crate::mem::ptr::RawPtr;
55+
use crate::mem::ptr::{GuestPtr, RawPtr};
2356
use crate::mem::shared_mem::HostSharedMemory;
57+
use crate::metrics::{METRIC_ERRONEOUS_VCPU_KICKS, METRIC_GUEST_CANCELLATION};
58+
use crate::sandbox::SandboxConfiguration;
2459
use crate::sandbox::host_funcs::FunctionRegistry;
25-
26-
use log::LevelFilter;
27-
use std::sync::{Arc, Mutex};
60+
use crate::sandbox::hypervisor::{HypervisorType, get_available_hypervisor};
61+
use crate::sandbox::outb::handle_outb;
62+
#[cfg(feature = "mem_profile")]
63+
use crate::sandbox::trace::MemTraceInfo;
64+
#[cfg(crashdump)]
65+
use crate::sandbox::uninitialized::SandboxRuntimeConfig;
66+
use crate::{HyperlightError, Result, log_then_return, new_error};
2867

2968
pub(crate) struct HyperlightVm {
3069
#[cfg(gdb)]
@@ -52,8 +91,124 @@ pub(crate) struct HyperlightVm {
5291
}
5392

5493
impl HyperlightVm {
55-
pub(crate) fn new(inner: Box<dyn Hypervisor>) -> Self {
56-
Self { vm: inner }
94+
/// Create a new HyperlightVm instance (will not run vm until calling `initialise`)
95+
#[instrument(err(Debug), skip_all, parent = Span::current(), level = "Trace")]
96+
#[allow(clippy::too_many_arguments)]
97+
pub(crate) fn new(
98+
mem_regions: Vec<MemoryRegion>,
99+
_pml4_addr: u64,
100+
entrypoint: u64,
101+
rsp: u64,
102+
#[cfg_attr(not(any(kvm, mshv3)), allow(unused_variables))] config: &SandboxConfiguration,
103+
#[cfg(target_os = "windows")] handle: HandleWrapper,
104+
#[cfg(target_os = "windows")] raw_size: usize,
105+
#[cfg(gdb)] gdb_conn: Option<DebugCommChannel<DebugResponse, DebugMsg>>,
106+
#[cfg(crashdump)] rt_cfg: SandboxRuntimeConfig,
107+
#[cfg(feature = "mem_profile")] trace_info: MemTraceInfo,
108+
) -> Result<Self> {
109+
#[cfg(gdb)]
110+
type VmType = Box<dyn DebuggableVm>;
111+
#[cfg(not(gdb))]
112+
type VmType = Box<dyn Hypervisor>;
113+
114+
#[allow(unused_mut)] // needs to be mutable when gdb is enabled
115+
let mut vm: VmType = match get_available_hypervisor() {
116+
#[cfg(kvm)]
117+
Some(HypervisorType::Kvm) => Box::new(KvmVm::new()?),
118+
#[cfg(mshv3)]
119+
Some(HypervisorType::Mshv) => Box::new(MshvVm::new()?),
120+
#[cfg(target_os = "windows")]
121+
Some(HypervisorType::Whp) => Box::new(WhpVm::new(handle, raw_size)?),
122+
None => return Err(NoHypervisorFound()),
123+
};
124+
125+
for (i, region) in mem_regions.iter().enumerate() {
126+
// Safety: slots are unique and region points to valid memory since we created the regions
127+
unsafe { vm.map_memory((i as u32, region))? };
128+
}
129+
130+
// Mark initial setup as complete for Windows - subsequent map_memory calls will fail
131+
#[cfg(target_os = "windows")]
132+
vm.complete_initial_memory_setup();
133+
134+
#[cfg(feature = "init-paging")]
135+
vm.set_sregs(&CommonSpecialRegisters::standard_64bit_defaults(_pml4_addr))?;
136+
#[cfg(not(feature = "init-paging"))]
137+
vm.set_sregs(&CommonSpecialRegisters::standard_real_mode_defaults())?;
138+
139+
#[cfg(gdb)]
140+
let gdb_conn = if let Some(gdb_conn) = gdb_conn {
141+
// Add breakpoint to the entry point address
142+
vm.set_debug(true)?;
143+
vm.add_hw_breakpoint(entrypoint)?;
144+
145+
Some(gdb_conn)
146+
} else {
147+
None
148+
};
149+
150+
let rsp_gp = GuestPtr::try_from(RawPtr::from(rsp))?;
151+
152+
#[cfg(any(kvm, mshv3))]
153+
let interrupt_handle: Arc<dyn InterruptHandleImpl> = Arc::new(LinuxInterruptHandle {
154+
state: AtomicU8::new(0),
155+
#[cfg(all(
156+
target_arch = "x86_64",
157+
target_vendor = "unknown",
158+
target_os = "linux",
159+
target_env = "musl"
160+
))]
161+
tid: AtomicU64::new(unsafe { libc::pthread_self() as u64 }),
162+
#[cfg(not(all(
163+
target_arch = "x86_64",
164+
target_vendor = "unknown",
165+
target_os = "linux",
166+
target_env = "musl"
167+
)))]
168+
tid: AtomicU64::new(unsafe { libc::pthread_self() }),
169+
retry_delay: config.get_interrupt_retry_delay(),
170+
sig_rt_min_offset: config.get_interrupt_vcpu_sigrtmin_offset(),
171+
dropped: AtomicBool::new(false),
172+
});
173+
174+
#[cfg(target_os = "windows")]
175+
let interrupt_handle: Arc<dyn InterruptHandleImpl> = Arc::new(WindowsInterruptHandle {
176+
state: AtomicU8::new(0),
177+
partition_handle: vm.partition_handle(),
178+
dropped: AtomicBool::new(false),
179+
});
180+
181+
#[allow(unused_mut)] // needs to be mutable when gdb is enabled
182+
let mut ret = Self {
183+
vm,
184+
entrypoint,
185+
orig_rsp: rsp_gp,
186+
interrupt_handle,
187+
page_size: 0, // Will be set in `initialise`
188+
189+
next_slot: mem_regions.len() as u32,
190+
sandbox_regions: mem_regions,
191+
mmap_regions: Vec::new(),
192+
freed_slots: Vec::new(),
193+
194+
#[cfg(gdb)]
195+
gdb_conn,
196+
#[cfg(gdb)]
197+
sw_breakpoints: HashMap::new(),
198+
#[cfg(feature = "mem_profile")]
199+
trace_info,
200+
#[cfg(crashdump)]
201+
rt_cfg,
202+
};
203+
204+
// Send the interrupt handle to the GDB thread if debugging is enabled
205+
// This is used to allow the GDB thread to stop the vCPU
206+
#[cfg(gdb)]
207+
if ret.gdb_conn.is_some() {
208+
ret.send_dbg_msg(DebugResponse::InterruptHandle(ret.interrupt_handle.clone()))?;
209+
}
210+
211+
Ok(ret)
57212
}
58213

59214
/// Initialise the internally stored vCPU with the given PEB address and
@@ -178,14 +333,14 @@ impl HyperlightVm {
178333
}
179334

180335
pub(crate) fn interrupt_handle(&self) -> Arc<dyn InterruptHandle> {
181-
self.vm.interrupt_handle()
336+
self.interrupt_handle.clone()
182337
}
183338

184339
pub(crate) fn clear_cancel(&self) {
185-
self.vm.clear_cancel()
340+
self.interrupt_handle.clear_cancel();
186341
}
187342

188-
fn run(
343+
fn run(
189344
&mut self,
190345
mem_mgr: &mut SandboxMemoryManager<HostSharedMemory>,
191346
host_funcs: &Arc<Mutex<FunctionRegistry>>,
@@ -626,7 +781,11 @@ impl HyperlightVm {
626781
}
627782
}
628783
}
629-
}
784+
785+
impl Drop for HyperlightVm {
786+
fn drop(&mut self) {
787+
self.interrupt_handle.set_dropped();
788+
}
630789
}
631790

632791
/// The vCPU tried to access the given addr

0 commit comments

Comments
 (0)