Skip to content

Commit e9d9e18

Browse files
authored
Removed the OutBHandler and MemAccessHandler abstractions and related implementations. (#732)
* Update hypervisor trait and handler to remove outb and mem access wrappers and to remove sync requirement Signed-off-by: Simon Davies <[email protected]> * Remove the outbhandler and memaccesshandler traits and types Signed-off-by: Simon Davies <[email protected]> * Remove mem_access_handler_wrapper function Signed-off-by: Simon Davies <[email protected]> * Remove outb_handler_wrapper function Signed-off-by: Simon Davies <[email protected]> * Remove outbhandler and memaccesshandler traits from MultiUseSandbox Signed-off-by: Simon Davies <[email protected]> * Remove OutBhandler and MemAccessHandler traits from evolve and provide new values to vm.initialise Signed-off-by: Simon Davies <[email protected]> --------- Signed-off-by: Simon Davies <[email protected]>
1 parent 6264bb0 commit e9d9e18

File tree

9 files changed

+244
-312
lines changed

9 files changed

+244
-312
lines changed

src/hyperlight_host/src/hypervisor/handlers.rs

Lines changed: 1 addition & 109 deletions
Original file line numberDiff line numberDiff line change
@@ -16,118 +16,11 @@ limitations under the License.
1616

1717
use std::sync::{Arc, Mutex};
1818

19-
use tracing::{Span, instrument};
20-
21-
#[cfg(feature = "trace_guest")]
22-
use super::Hypervisor;
23-
use crate::{Result, new_error};
24-
25-
/// The trait representing custom logic to handle the case when
26-
/// a Hypervisor's virtual CPU (vCPU) informs Hyperlight the guest
27-
/// has initiated an outb operation.
28-
pub(crate) trait OutBHandlerCaller: Sync + Send {
29-
/// Function that gets called when an outb operation has occurred.
30-
fn call(
31-
&mut self,
32-
#[cfg(feature = "trace_guest")] hv: &mut dyn Hypervisor,
33-
port: u16,
34-
payload: u32,
35-
) -> Result<()>;
36-
}
37-
38-
/// A convenient type representing a common way `OutBHandler` implementations
39-
/// are passed as parameters to functions
40-
///
41-
/// Note: This needs to be wrapped in a Mutex to be able to grab a mutable
42-
/// reference to the underlying data (i.e., handle_outb in `Sandbox` takes
43-
/// a &mut self).
44-
pub(crate) type OutBHandlerWrapper = Arc<Mutex<dyn OutBHandlerCaller>>;
45-
46-
#[cfg(feature = "trace_guest")]
47-
pub(crate) type OutBHandlerFunction =
48-
Box<dyn FnMut(&mut dyn Hypervisor, u16, u32) -> Result<()> + Send>;
49-
#[cfg(not(feature = "trace_guest"))]
50-
pub(crate) type OutBHandlerFunction = Box<dyn FnMut(u16, u32) -> Result<()> + Send>;
51-
52-
/// A `OutBHandler` implementation using a `OutBHandlerFunction`
53-
///
54-
/// Note: This handler must live no longer than the `Sandbox` to which it belongs
55-
pub(crate) struct OutBHandler(Arc<Mutex<OutBHandlerFunction>>);
56-
57-
impl From<OutBHandlerFunction> for OutBHandler {
58-
#[instrument(skip_all, parent = Span::current(), level= "Trace")]
59-
fn from(func: OutBHandlerFunction) -> Self {
60-
Self(Arc::new(Mutex::new(func)))
61-
}
62-
}
63-
64-
impl OutBHandlerCaller for OutBHandler {
65-
#[instrument(err(Debug), skip_all, parent = Span::current(), level= "Trace")]
66-
fn call(
67-
&mut self,
68-
#[cfg(feature = "trace_guest")] hv: &mut dyn Hypervisor,
69-
port: u16,
70-
payload: u32,
71-
) -> Result<()> {
72-
let mut func = self
73-
.0
74-
.try_lock()
75-
.map_err(|e| new_error!("Error locking at {}:{}: {}", file!(), line!(), e))?;
76-
func(
77-
#[cfg(feature = "trace_guest")]
78-
hv,
79-
port,
80-
payload,
81-
)
82-
}
83-
}
84-
85-
/// The trait representing custom logic to handle the case when
86-
/// a Hypervisor's virtual CPU (vCPU) informs Hyperlight a memory access
87-
/// outside the designated address space has occurred.
88-
pub trait MemAccessHandlerCaller: Send {
89-
/// Function that gets called when unexpected memory access has occurred.
90-
fn call(&mut self) -> Result<()>;
91-
}
92-
93-
/// A convenient type representing a common way `MemAccessHandler` implementations
94-
/// are passed as parameters to functions
95-
///
96-
/// Note: This needs to be wrapped in a Mutex to be able to grab a mutable
97-
/// reference to the underlying data (i.e., handle_mmio_exit in `Sandbox` takes
98-
/// a &mut self).
99-
pub type MemAccessHandlerWrapper = Arc<Mutex<dyn MemAccessHandlerCaller>>;
100-
101-
pub(crate) type MemAccessHandlerFunction = Box<dyn FnMut() -> Result<()> + Send>;
102-
103-
/// A `MemAccessHandler` implementation using `MemAccessHandlerFunction`.
104-
///
105-
/// Note: This handler must live for as long as its Sandbox or for
106-
/// static in the case of its C API usage.
107-
pub(crate) struct MemAccessHandler(Arc<Mutex<MemAccessHandlerFunction>>);
108-
109-
impl From<MemAccessHandlerFunction> for MemAccessHandler {
110-
#[instrument(skip_all, parent = Span::current(), level= "Trace")]
111-
fn from(func: MemAccessHandlerFunction) -> Self {
112-
Self(Arc::new(Mutex::new(func)))
113-
}
114-
}
115-
116-
impl MemAccessHandlerCaller for MemAccessHandler {
117-
#[instrument(err(Debug), skip_all, parent = Span::current(), level= "Trace")]
118-
fn call(&mut self) -> Result<()> {
119-
let mut func = self
120-
.0
121-
.try_lock()
122-
.map_err(|e| new_error!("Error locking at {}:{}: {}", file!(), line!(), e))?;
123-
func()
124-
}
125-
}
19+
use crate::Result;
12620

12721
/// The trait representing custom logic to handle the case when
12822
/// a Hypervisor's virtual CPU (vCPU) informs Hyperlight a debug memory access
12923
/// has been requested.
130-
#[cfg(gdb)]
13124
pub trait DbgMemAccessHandlerCaller: Send {
13225
/// Function that gets called when a read is requested.
13326
fn read(&mut self, addr: usize, data: &mut [u8]) -> Result<()>;
@@ -143,5 +36,4 @@ pub trait DbgMemAccessHandlerCaller: Send {
14336
///
14437
/// Note: This needs to be wrapped in a Mutex to be able to grab a mutable
14538
/// reference to the underlying data
146-
#[cfg(gdb)]
14739
pub type DbgMemAccessHandlerWrapper = Arc<Mutex<dyn DbgMemAccessHandlerCaller>>;

src/hyperlight_host/src/hypervisor/hyperv_linux.rs

Lines changed: 63 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -25,8 +25,8 @@ extern crate mshv_bindings3 as mshv_bindings;
2525
extern crate mshv_ioctls3 as mshv_ioctls;
2626

2727
use std::fmt::{Debug, Formatter};
28-
use std::sync::Arc;
2928
use std::sync::atomic::{AtomicBool, AtomicU64, Ordering};
29+
use std::sync::{Arc, Mutex};
3030

3131
use log::{LevelFilter, error};
3232
#[cfg(mshv2)]
@@ -67,7 +67,6 @@ use super::gdb::{
6767
};
6868
#[cfg(gdb)]
6969
use super::handlers::DbgMemAccessHandlerWrapper;
70-
use super::handlers::{MemAccessHandlerWrapper, OutBHandlerWrapper};
7170
#[cfg(feature = "init-paging")]
7271
use super::{
7372
CR0_AM, CR0_ET, CR0_MP, CR0_NE, CR0_PE, CR0_PG, CR0_WP, CR4_OSFXSR, CR4_OSXMMEXCPT, CR4_PAE,
@@ -78,9 +77,13 @@ use super::{HyperlightExit, Hypervisor, InterruptHandle, LinuxInterruptHandle, V
7877
use crate::HyperlightError;
7978
use crate::mem::memory_region::{MemoryRegion, MemoryRegionFlags};
8079
use crate::mem::ptr::{GuestPtr, RawPtr};
80+
use crate::mem::shared_mem::HostSharedMemory;
8181
use crate::sandbox::SandboxConfiguration;
8282
#[cfg(feature = "trace_guest")]
8383
use crate::sandbox::TraceInfo;
84+
use crate::sandbox::host_funcs::FunctionRegistry;
85+
use crate::sandbox::mem_mgr::MemMgrWrapper;
86+
use crate::sandbox::outb::handle_outb;
8487
#[cfg(crashdump)]
8588
use crate::sandbox::uninitialized::SandboxRuntimeConfig;
8689
use crate::{Result, log_then_return, new_error};
@@ -313,7 +316,8 @@ pub(crate) struct HypervLinuxDriver {
313316
mem_regions: Vec<MemoryRegion>,
314317
orig_rsp: GuestPtr,
315318
interrupt_handle: Arc<LinuxInterruptHandle>,
316-
319+
mem_mgr: Option<MemMgrWrapper<HostSharedMemory>>,
320+
host_funcs: Option<Arc<Mutex<FunctionRegistry>>>,
317321
#[cfg(gdb)]
318322
debug: Option<MshvDebug>,
319323
#[cfg(gdb)]
@@ -447,6 +451,8 @@ impl HypervLinuxDriver {
447451
entrypoint: entrypoint_ptr.absolute()?,
448452
orig_rsp: rsp_ptr,
449453
interrupt_handle: interrupt_handle.clone(),
454+
mem_mgr: None,
455+
host_funcs: None,
450456
#[cfg(gdb)]
451457
debug,
452458
#[cfg(gdb)]
@@ -574,11 +580,13 @@ impl Hypervisor for HypervLinuxDriver {
574580
peb_addr: RawPtr,
575581
seed: u64,
576582
page_size: u32,
577-
outb_hdl: OutBHandlerWrapper,
578-
mem_access_hdl: MemAccessHandlerWrapper,
583+
mem_mgr: MemMgrWrapper<HostSharedMemory>,
584+
host_funcs: Arc<Mutex<FunctionRegistry>>,
579585
max_guest_log_level: Option<LevelFilter>,
580586
#[cfg(gdb)] dbg_mem_access_fn: DbgMemAccessHandlerWrapper,
581587
) -> Result<()> {
588+
self.mem_mgr = Some(mem_mgr);
589+
self.host_funcs = Some(host_funcs);
582590
self.page_size = page_size as usize;
583591

584592
let max_guest_log_level: u64 = match max_guest_log_level {
@@ -601,13 +609,22 @@ impl Hypervisor for HypervLinuxDriver {
601609
};
602610
self.vcpu_fd.set_regs(&regs)?;
603611

604-
VirtualCPU::run(
612+
// Extract mem_mgr to avoid borrowing conflicts
613+
let mem_mgr = self
614+
.mem_mgr
615+
.take()
616+
.ok_or_else(|| new_error!("mem_mgr should be initialized"))?;
617+
618+
let result = VirtualCPU::run(
605619
self.as_mut_hypervisor(),
606-
outb_hdl,
607-
mem_access_hdl,
620+
&mem_mgr,
608621
#[cfg(gdb)]
609622
dbg_mem_access_fn,
610-
)?;
623+
);
624+
625+
// Put mem_mgr back
626+
self.mem_mgr = Some(mem_mgr);
627+
result?;
611628

612629
Ok(())
613630
}
@@ -647,8 +664,7 @@ impl Hypervisor for HypervLinuxDriver {
647664
fn dispatch_call_from_host(
648665
&mut self,
649666
dispatch_func_addr: RawPtr,
650-
outb_handle_fn: OutBHandlerWrapper,
651-
mem_access_fn: MemAccessHandlerWrapper,
667+
mem_mgr: &MemMgrWrapper<HostSharedMemory>,
652668
#[cfg(gdb)] dbg_mem_access_fn: DbgMemAccessHandlerWrapper,
653669
) -> Result<()> {
654670
// Reset general purpose registers, then set RIP and RSP
@@ -672,8 +688,7 @@ impl Hypervisor for HypervLinuxDriver {
672688
// run
673689
VirtualCPU::run(
674690
self.as_mut_hypervisor(),
675-
outb_handle_fn,
676-
mem_access_fn,
691+
mem_mgr,
677692
#[cfg(gdb)]
678693
dbg_mem_access_fn,
679694
)?;
@@ -688,22 +703,47 @@ impl Hypervisor for HypervLinuxDriver {
688703
data: Vec<u8>,
689704
rip: u64,
690705
instruction_length: u64,
691-
outb_handle_fn: OutBHandlerWrapper,
692706
) -> Result<()> {
693707
let mut padded = [0u8; 4];
694708
let copy_len = data.len().min(4);
695709
padded[..copy_len].copy_from_slice(&data[..copy_len]);
696710
let val = u32::from_le_bytes(padded);
697711

698-
outb_handle_fn
699-
.try_lock()
700-
.map_err(|e| new_error!("Error locking at {}:{}: {}", file!(), line!(), e))?
701-
.call(
702-
#[cfg(feature = "trace_guest")]
703-
self,
704-
port,
705-
val,
706-
)?;
712+
#[cfg(feature = "trace_guest")]
713+
{
714+
// We need to handle the borrow checker issue where we need both:
715+
// - &mut MemMgrWrapper (from self.mem_mgr.as_mut())
716+
// - &mut dyn Hypervisor (from self)
717+
// We'll use a temporary approach to extract the mem_mgr temporarily
718+
let mem_mgr_option = self.mem_mgr.take();
719+
let mut mem_mgr = mem_mgr_option
720+
.ok_or_else(|| new_error!("mem_mgr should be initialized before handling IO"))?;
721+
let host_funcs = self
722+
.host_funcs
723+
.as_ref()
724+
.ok_or_else(|| new_error!("host_funcs should be initialized before handling IO"))?
725+
.clone();
726+
727+
handle_outb(&mut mem_mgr, host_funcs, self, port, val)?;
728+
729+
// Put the mem_mgr back
730+
self.mem_mgr = Some(mem_mgr);
731+
}
732+
733+
#[cfg(not(feature = "trace_guest"))]
734+
{
735+
let mem_mgr = self
736+
.mem_mgr
737+
.as_mut()
738+
.ok_or_else(|| new_error!("mem_mgr should be initialized before handling IO"))?;
739+
let host_funcs = self
740+
.host_funcs
741+
.as_ref()
742+
.ok_or_else(|| new_error!("host_funcs should be initialized before handling IO"))?
743+
.clone();
744+
745+
handle_outb(mem_mgr, host_funcs, port, val)?;
746+
}
707747

708748
// update rip
709749
self.vcpu_fd.set_reg(&[hv_register_assoc {

0 commit comments

Comments
 (0)