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}