hyperlight_host/hypervisor/handlers.rs
1/*
2Copyright 2024 The Hyperlight Authors.
3
4Licensed under the Apache License, Version 2.0 (the "License");
5you may not use this file except in compliance with the License.
6You may obtain a copy of the License at
7
8 http://www.apache.org/licenses/LICENSE-2.0
9
10Unless required by applicable law or agreed to in writing, software
11distributed under the License is distributed on an "AS IS" BASIS,
12WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13See the License for the specific language governing permissions and
14limitations under the License.
15*/
16
17use std::sync::{Arc, Mutex};
18
19use tracing::{instrument, Span};
20
21use crate::{new_error, Result};
22
23/// The trait representing custom logic to handle the case when
24/// a Hypervisor's virtual CPU (vCPU) informs Hyperlight the guest
25/// has initiated an outb operation.
26pub trait OutBHandlerCaller: Sync + Send {
27 /// Function that gets called when an outb operation has occurred.
28 fn call(&mut self, port: u16, payload: u64) -> Result<()>;
29}
30
31/// A convenient type representing a common way `OutBHandler` implementations
32/// are passed as parameters to functions
33///
34/// Note: This needs to be wrapped in a Mutex to be able to grab a mutable
35/// reference to the underlying data (i.e., handle_outb in `Sandbox` takes
36/// a &mut self).
37pub type OutBHandlerWrapper = Arc<Mutex<dyn OutBHandlerCaller>>;
38
39pub(crate) type OutBHandlerFunction = Box<dyn FnMut(u16, u64) -> Result<()> + Send>;
40
41/// A `OutBHandler` implementation using a `OutBHandlerFunction`
42///
43/// Note: This handler must live no longer than the `Sandbox` to which it belongs
44pub(crate) struct OutBHandler(Arc<Mutex<OutBHandlerFunction>>);
45
46impl From<OutBHandlerFunction> for OutBHandler {
47 #[instrument(skip_all, parent = Span::current(), level= "Trace")]
48 fn from(func: OutBHandlerFunction) -> Self {
49 Self(Arc::new(Mutex::new(func)))
50 }
51}
52
53impl OutBHandlerCaller for OutBHandler {
54 #[instrument(err(Debug), skip_all, parent = Span::current(), level= "Trace")]
55 fn call(&mut self, port: u16, payload: u64) -> Result<()> {
56 let mut func = self
57 .0
58 .try_lock()
59 .map_err(|e| new_error!("Error locking at {}:{}: {}", file!(), line!(), e))?;
60 func(port, payload)
61 }
62}
63
64/// The trait representing custom logic to handle the case when
65/// a Hypervisor's virtual CPU (vCPU) informs Hyperlight a memory access
66/// outside the designated address space has occurred.
67pub trait MemAccessHandlerCaller: Send {
68 /// Function that gets called when unexpected memory access has occurred.
69 fn call(&mut self) -> Result<()>;
70}
71
72/// A convenient type representing a common way `MemAccessHandler` implementations
73/// are passed as parameters to functions
74///
75/// Note: This needs to be wrapped in a Mutex to be able to grab a mutable
76/// reference to the underlying data (i.e., handle_mmio_exit in `Sandbox` takes
77/// a &mut self).
78pub type MemAccessHandlerWrapper = Arc<Mutex<dyn MemAccessHandlerCaller>>;
79
80pub(crate) type MemAccessHandlerFunction = Box<dyn FnMut() -> Result<()> + Send>;
81
82/// A `MemAccessHandler` implementation using `MemAccessHandlerFunction`.
83///
84/// Note: This handler must live for as long as its Sandbox or for
85/// static in the case of its C API usage.
86pub(crate) struct MemAccessHandler(Arc<Mutex<MemAccessHandlerFunction>>);
87
88impl From<MemAccessHandlerFunction> for MemAccessHandler {
89 #[instrument(skip_all, parent = Span::current(), level= "Trace")]
90 fn from(func: MemAccessHandlerFunction) -> Self {
91 Self(Arc::new(Mutex::new(func)))
92 }
93}
94
95impl MemAccessHandlerCaller for MemAccessHandler {
96 #[instrument(err(Debug), skip_all, parent = Span::current(), level= "Trace")]
97 fn call(&mut self) -> Result<()> {
98 let mut func = self
99 .0
100 .try_lock()
101 .map_err(|e| new_error!("Error locking at {}:{}: {}", file!(), line!(), e))?;
102 func()
103 }
104}
105
106/// The trait representing custom logic to handle the case when
107/// a Hypervisor's virtual CPU (vCPU) informs Hyperlight a debug memory access
108/// has been requested.
109#[cfg(gdb)]
110pub trait DbgMemAccessHandlerCaller: Send {
111 /// Function that gets called when a read is requested.
112 fn read(&mut self, addr: usize, data: &mut [u8]) -> Result<()>;
113
114 /// Function that gets called when a write is requested.
115 fn write(&mut self, addr: usize, data: &[u8]) -> Result<()>;
116
117 /// Function that gets called for a request to get guest code offset.
118 fn get_code_offset(&mut self) -> Result<usize>;
119}
120
121/// A convenient type representing an implementer of `DbgMemAccessHandlerCaller`
122///
123/// Note: This needs to be wrapped in a Mutex to be able to grab a mutable
124/// reference to the underlying data
125#[cfg(gdb)]
126pub type DbgMemAccessHandlerWrapper = Arc<Mutex<dyn DbgMemAccessHandlerCaller>>;