Skip to main content

vmi_core/
event.rs

1use crate::{Architecture, Registers, VcpuId, View};
2
3bitflags::bitflags! {
4    /// Flags that can be set in a VMI event.
5    #[derive(Debug, Default, Clone, Copy, PartialEq, Eq)]
6    pub struct VmiEventFlags: u8 {
7        /// The virtual CPU is paused.
8        const VCPU_PAUSED = 1 << 0;
9    }
10}
11
12/// An event that occurred during VMI.
13#[derive(Debug, Clone, Copy)]
14pub struct VmiEvent<Arch>
15where
16    Arch: Architecture,
17{
18    /// The ID of the virtual CPU where the event occurred.
19    vcpu_id: VcpuId,
20
21    /// Flags associated with the event.
22    flags: VmiEventFlags,
23
24    /// The view associated with the event, if any.
25    view: Option<View>,
26
27    /// The CPU register state at the time of the event.
28    registers: Arch::Registers,
29
30    /// The reason for the event.
31    reason: Arch::EventReason,
32}
33
34impl<Arch> VmiEvent<Arch>
35where
36    Arch: Architecture,
37{
38    /// Creates a new VMI event.
39    pub fn new(
40        vcpu_id: VcpuId,
41        flags: VmiEventFlags,
42        view: Option<View>,
43        registers: Arch::Registers,
44        reason: Arch::EventReason,
45    ) -> Self {
46        Self {
47            vcpu_id,
48            flags,
49            view,
50            registers,
51            reason,
52        }
53    }
54
55    /// Returns the ID of the virtual CPU where the event occurred.
56    pub fn vcpu_id(&self) -> VcpuId {
57        self.vcpu_id
58    }
59
60    /// Returns flags associated with the event.
61    pub fn flags(&self) -> VmiEventFlags {
62        self.flags
63    }
64
65    /// Returns the view associated with the event, if any.
66    pub fn view(&self) -> Option<View> {
67        self.view
68    }
69
70    /// Returns a reference to the CPU registers at the time of the event.
71    pub fn registers(&self) -> &Arch::Registers {
72        &self.registers
73    }
74
75    /// Returns a reference to the reason for the event.
76    pub fn reason(&self) -> &Arch::EventReason {
77        &self.reason
78    }
79}
80
81/// The primary action to take when resuming from a VMI event.
82///
83/// These actions are mutually exclusive. Each variant maps to a distinct
84/// hypervisor resume behavior.
85#[derive(Debug, Default, Clone, Copy, PartialEq, Eq)]
86pub enum VmiEventAction {
87    /// Resume the vCPU normally, allowing the trapped instruction to
88    /// proceed with its original side effects.
89    #[default]
90    Continue,
91
92    /// Deny the event (suppress CR/MSR write side effects).
93    ///
94    /// The instruction has already executed and RIP has advanced, but the
95    /// register write is not committed. Effectively makes the instruction
96    /// a no-op.
97    Deny,
98
99    /// Reinject the interrupt back into the guest.
100    ///
101    /// Used when a monitored interrupt (e.g. INT3) was not placed by us
102    /// and should be delivered to the guest's own interrupt handler.
103    ReinjectInterrupt,
104
105    /// Single-step one instruction.
106    ///
107    /// When returned from a non-singlestep event, enables singlestep for
108    /// the next instruction. When returned from a singlestep event,
109    /// continues singlestepping for one more instruction. When absent
110    /// from a singlestep event response, singlestep is automatically
111    /// disabled.
112    Singlestep,
113
114    /// Fast single-step one instruction in the response's view, then
115    /// silently switch back to the event's original view. Unlike regular
116    /// singlestep, this never generates a VMI event.
117    FastSinglestep,
118
119    /// Emulate the faulting instruction inside the hypervisor instead of
120    /// returning to the guest. Useful for handling read/write memory
121    /// access events without switching views.
122    Emulate,
123}
124
125/// A response to a VMI event.
126#[derive(Debug)]
127pub struct VmiEventResponse<Arch>
128where
129    Arch: Architecture,
130{
131    /// The primary action to take when resuming.
132    pub action: VmiEventAction,
133
134    /// The view to set for the vCPU.
135    pub view: Option<View>,
136
137    /// The vCPU registers to set.
138    pub registers: Option<<Arch::Registers as Registers>::GpRegisters>,
139}
140
141impl<Arch> Default for VmiEventResponse<Arch>
142where
143    Arch: Architecture,
144{
145    fn default() -> Self {
146        Self {
147            action: VmiEventAction::Continue,
148            view: None,
149            registers: None,
150        }
151    }
152}
153
154impl<Arch> VmiEventResponse<Arch>
155where
156    Arch: Architecture,
157{
158    /// Creates a response to deny the event.
159    pub fn deny() -> Self {
160        Self {
161            action: VmiEventAction::Deny,
162            ..Self::default()
163        }
164    }
165
166    /// Creates a response to reinject an interrupt.
167    pub fn reinject_interrupt() -> Self {
168        Self {
169            action: VmiEventAction::ReinjectInterrupt,
170            ..Self::default()
171        }
172    }
173
174    /// Creates a response to single-step one instruction.
175    pub fn singlestep() -> Self {
176        Self {
177            action: VmiEventAction::Singlestep,
178            ..Self::default()
179        }
180    }
181
182    /// Creates a response to fast single-step one instruction in the
183    /// specified view. Unlike regular singlestep, fast singlestep never
184    /// generates a VMI event.
185    pub fn fast_singlestep(view: View) -> Self {
186        Self {
187            action: VmiEventAction::FastSinglestep,
188            view: Some(view),
189            ..Self::default()
190        }
191    }
192
193    /// Creates a response to emulate the instruction.
194    pub fn emulate() -> Self {
195        Self {
196            action: VmiEventAction::Emulate,
197            ..Self::default()
198        }
199    }
200
201    /// Sets a specific view for the response.
202    pub fn with_view(self, view: View) -> Self {
203        Self {
204            view: Some(view),
205            ..self
206        }
207    }
208
209    /// Sets specific CPU registers for the response.
210    pub fn with_registers(self, registers: <Arch::Registers as Registers>::GpRegisters) -> Self {
211        Self {
212            registers: Some(registers),
213            ..self
214        }
215    }
216}