1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
use alloc::boxed::Box;
use kev::{
vcpu::{GenericVCpuState, VmexitResult},
vmcs::{BasicExitReason, ExitReason},
Probe, VmError,
};
pub struct Controller<H: HypercallAbi> {
inner: H,
}
impl<H: HypercallAbi> Controller<H> {
pub fn new(inner: H) -> Self {
Self { inner }
}
}
impl<H: HypercallAbi> kev::vmexits::VmexitController for Controller<H> {
fn handle<P: Probe>(
&mut self,
reason: ExitReason,
p: &mut P,
generic_vcpu_state: &mut GenericVCpuState,
) -> Result<VmexitResult, VmError> {
match reason.get_basic_reason() {
BasicExitReason::Vmcall => {
let hc = H::Call::resolve(generic_vcpu_state)
.ok_or(VmError::ControllerError(Box::new("Unknown hypercall")))?;
self.inner
.handle(hc, p, generic_vcpu_state)
.and_then(|r| generic_vcpu_state.vmcs.forward_rip().map(|_| r))
}
_ => Err(kev::VmError::HandleVmexitFailed(reason)),
}
}
}
pub trait HypercallAbi
where
Self: Sync + Send + 'static,
{
type Call: Hypercall;
fn handle<P: Probe>(
&mut self,
hc: Self::Call,
p: &mut P,
generic_vcpu_state: &mut GenericVCpuState,
) -> Result<VmexitResult, kev::VmError>;
}
pub trait Hypercall {
fn resolve(generic_vcpu_state: &mut GenericVCpuState) -> Option<Self>
where
Self: Sized;
}