Skip to content

Commit 805d3e8

Browse files
committed
Removed the OutBHandler and MemAccessHandler abstractions and related implementations.
Signed-off-by: Simon Davies <[email protected]>
1 parent 1a155a7 commit 805d3e8

File tree

9 files changed

+223
-306
lines changed

9 files changed

+223
-306
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 & 24 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,11 +77,14 @@ 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};
81-
use crate::sandbox::SandboxConfiguration;
80+
use crate::mem::shared_mem::HostSharedMemory;
8281
#[cfg(feature = "trace_guest")]
8382
use crate::sandbox::TraceInfo;
83+
use crate::sandbox::host_funcs::FunctionRegistry;
84+
use crate::sandbox::outb::handle_outb;
8485
#[cfg(crashdump)]
8586
use crate::sandbox::uninitialized::SandboxRuntimeConfig;
87+
use crate::sandbox::{MemMgrWrapper, SandboxConfiguration};
8688
use crate::{Result, log_then_return, new_error};
8789

8890
#[cfg(gdb)]
@@ -313,7 +315,8 @@ pub(crate) struct HypervLinuxDriver {
313315
mem_regions: Vec<MemoryRegion>,
314316
orig_rsp: GuestPtr,
315317
interrupt_handle: Arc<LinuxInterruptHandle>,
316-
318+
mem_mgr: Option<MemMgrWrapper<HostSharedMemory>>,
319+
host_funcs: Option<Arc<Mutex<FunctionRegistry>>>,
317320
#[cfg(gdb)]
318321
debug: Option<MshvDebug>,
319322
#[cfg(gdb)]
@@ -447,6 +450,8 @@ impl HypervLinuxDriver {
447450
entrypoint: entrypoint_ptr.absolute()?,
448451
orig_rsp: rsp_ptr,
449452
interrupt_handle: interrupt_handle.clone(),
453+
mem_mgr: None,
454+
host_funcs: None,
450455
#[cfg(gdb)]
451456
debug,
452457
#[cfg(gdb)]
@@ -574,11 +579,13 @@ impl Hypervisor for HypervLinuxDriver {
574579
peb_addr: RawPtr,
575580
seed: u64,
576581
page_size: u32,
577-
outb_hdl: OutBHandlerWrapper,
578-
mem_access_hdl: MemAccessHandlerWrapper,
582+
mem_mgr: MemMgrWrapper<HostSharedMemory>,
583+
host_funcs: Arc<Mutex<FunctionRegistry>>,
579584
max_guest_log_level: Option<LevelFilter>,
580585
#[cfg(gdb)] dbg_mem_access_fn: DbgMemAccessHandlerWrapper,
581586
) -> Result<()> {
587+
self.mem_mgr = Some(mem_mgr);
588+
self.host_funcs = Some(host_funcs);
582589
self.page_size = page_size as usize;
583590

584591
let max_guest_log_level: u64 = match max_guest_log_level {
@@ -601,13 +608,22 @@ impl Hypervisor for HypervLinuxDriver {
601608
};
602609
self.vcpu_fd.set_regs(&regs)?;
603610

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

612628
Ok(())
613629
}
@@ -647,8 +663,7 @@ impl Hypervisor for HypervLinuxDriver {
647663
fn dispatch_call_from_host(
648664
&mut self,
649665
dispatch_func_addr: RawPtr,
650-
outb_handle_fn: OutBHandlerWrapper,
651-
mem_access_fn: MemAccessHandlerWrapper,
666+
mem_mgr: &MemMgrWrapper<HostSharedMemory>,
652667
#[cfg(gdb)] dbg_mem_access_fn: DbgMemAccessHandlerWrapper,
653668
) -> Result<()> {
654669
// Reset general purpose registers, then set RIP and RSP
@@ -672,8 +687,7 @@ impl Hypervisor for HypervLinuxDriver {
672687
// run
673688
VirtualCPU::run(
674689
self.as_mut_hypervisor(),
675-
outb_handle_fn,
676-
mem_access_fn,
690+
mem_mgr,
677691
#[cfg(gdb)]
678692
dbg_mem_access_fn,
679693
)?;
@@ -688,22 +702,47 @@ impl Hypervisor for HypervLinuxDriver {
688702
data: Vec<u8>,
689703
rip: u64,
690704
instruction_length: u64,
691-
outb_handle_fn: OutBHandlerWrapper,
692705
) -> Result<()> {
693706
let mut padded = [0u8; 4];
694707
let copy_len = data.len().min(4);
695708
padded[..copy_len].copy_from_slice(&data[..copy_len]);
696709
let val = u32::from_le_bytes(padded);
697710

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-
)?;
711+
#[cfg(feature = "trace_guest")]
712+
{
713+
// We need to handle the borrow checker issue where we need both:
714+
// - &mut MemMgrWrapper (from self.mem_mgr.as_mut())
715+
// - &mut dyn Hypervisor (from self)
716+
// We'll use a temporary approach to extract the mem_mgr temporarily
717+
let mem_mgr_option = self.mem_mgr.take();
718+
let mut mem_mgr = mem_mgr_option
719+
.ok_or_else(|| new_error!("mem_mgr should be initialized before handling IO"))?;
720+
let host_funcs = self
721+
.host_funcs
722+
.as_ref()
723+
.ok_or_else(|| new_error!("host_funcs should be initialized before handling IO"))?
724+
.clone();
725+
726+
handle_outb(&mut mem_mgr, host_funcs, self, port, val)?;
727+
728+
// Put the mem_mgr back
729+
self.mem_mgr = Some(mem_mgr);
730+
}
731+
732+
#[cfg(not(feature = "trace_guest"))]
733+
{
734+
let mem_mgr = self
735+
.mem_mgr
736+
.as_mut()
737+
.ok_or_else(|| new_error!("mem_mgr should be initialized before handling IO"))?;
738+
let host_funcs = self
739+
.host_funcs
740+
.as_ref()
741+
.ok_or_else(|| new_error!("host_funcs should be initialized before handling IO"))?
742+
.clone();
743+
744+
handle_outb(mem_mgr, host_funcs, port, val)?;
745+
}
707746

708747
// update rip
709748
self.vcpu_fd.set_reg(&[hv_register_assoc {

0 commit comments

Comments
 (0)