Skip to main content

vmi_arch_amd64/
event.rs

1use vmi_core::{Gfn, MemoryAccess, Pa, Va};
2
3use crate::{ControlRegister, ExceptionVector, Interrupt, Msr};
4
5bitflags::bitflags! {
6    /// Flags describing a memory access event.
7    #[derive(Debug, Default, Clone, Copy, PartialEq, Eq)]
8    pub struct MemoryAccessFlags: u8 {
9        /// The [`EventMemoryAccess::va`] field holds a guest VA associated with the event.
10        const GLA_VALID        = (1 << 3);
11
12        /// The `MemoryAccess` event was triggered by accessing a guest linear address.
13        const FAULT_WITH_GLA   = (1 << 4);
14
15        /// The `MemoryAccess` event was triggered during translating a guest linear address.
16        const FAULT_IN_GPT     = (1 << 5);
17    }
18}
19
20/// Event generated when monitored memory is accessed.
21#[derive(Debug, Clone, Copy)]
22pub struct EventMemoryAccess {
23    /// Physical address that was accessed.
24    pub pa: Pa,
25
26    /// Virtual address that was accessed.
27    pub va: Va,
28
29    /// Type of access that occurred (read/write/execute).
30    pub access: MemoryAccess,
31
32    /// Additional flags describing the access.
33    pub flags: MemoryAccessFlags,
34}
35
36/// Event generated when a control register is written to.
37#[derive(Debug, Clone, Copy)]
38pub struct EventWriteCr {
39    /// The control register that was written to (CR0, CR3, CR4 or XCR0).
40    pub register: ControlRegister,
41
42    /// New value of the control register.
43    pub new_value: u64,
44
45    /// Old value of the control register.
46    pub old_value: u64,
47}
48
49/// Event generated when a model-specific register (MSR) is written to.
50#[derive(Debug, Clone, Copy)]
51pub struct EventWriteMsr {
52    /// The MSR that was written to.
53    pub register: u32,
54
55    /// New value of the MSR.
56    pub new_value: u64,
57
58    /// Old value of the MSR.
59    pub old_value: u64,
60}
61
62/// Event generated when an interrupt or exception occurs.
63#[derive(Debug, Clone, Copy)]
64pub struct EventInterrupt {
65    /// GFN of the instruction that caused the interrupt.
66    /// Effectively, this is GFN of the current instruction pointer.
67    pub gfn: Gfn,
68
69    /// Information about the interrupt/exception.
70    pub interrupt: Interrupt,
71}
72
73/// Event generated when a singlestep event occurs.
74#[derive(Debug, Clone, Copy)]
75pub struct EventSinglestep {
76    /// GFN of the instruction that caused the singlestep.
77    pub gfn: Gfn,
78}
79
80/// Event generated when a VMCALL instruction is executed.
81#[derive(Debug, Clone, Copy)]
82pub struct EventHypercall {
83    /// Length of the VMCALL instruction.
84    pub instruction_length: u8,
85}
86
87/// Event generated when a CPUID instruction is executed.
88#[derive(Debug, Clone, Copy)]
89pub struct EventCpuId {
90    /// CPUID leaf (EAX).
91    pub leaf: u32,
92
93    /// CPUID subleaf (ECX).
94    pub subleaf: u32,
95
96    /// Length of the CPUID instruction.
97    pub instruction_length: u8,
98}
99
100/// Direction of the I/O port access.
101#[derive(Debug, Clone, Copy)]
102pub enum EventIoDirection {
103    /// I/O port read.
104    In,
105
106    /// I/O port write.
107    Out,
108}
109
110/// Event generated when an I/O port is accessed.
111#[derive(Debug, Clone, Copy)]
112pub struct EventIo {
113    /// I/O port that was accessed.
114    pub port: u16,
115
116    /// Number of bytes transferred.
117    pub length: u32,
118
119    /// Direction of transfer (in/out).
120    pub direction: EventIoDirection,
121
122    /// True for string I/O instructions (INS/OUTS).
123    pub string: bool,
124}
125
126/// Reason for an event.
127#[derive(Debug, Clone, Copy)]
128pub enum EventReason {
129    /// Memory access event (read/write/execute).
130    MemoryAccess(EventMemoryAccess),
131
132    /// Control register write event.
133    WriteCr(EventWriteCr),
134
135    /// MSR write event.
136    WriteMsr(EventWriteMsr),
137
138    /// Interrupt or exception event.
139    Interrupt(EventInterrupt),
140
141    /// Singlestep event.
142    Singlestep(EventSinglestep),
143
144    /// Hypercall event (VMCALL).
145    Hypercall(EventHypercall),
146
147    /// CPUID instruction event.
148    CpuId(EventCpuId),
149
150    /// I/O port access event.
151    Io(EventIo),
152}
153
154impl EventReason {
155    /// Returns the memory access event.
156    ///
157    /// # Panics
158    ///
159    /// Panics if the event reason is not a memory access event.
160    pub fn as_memory_access(&self) -> &EventMemoryAccess {
161        match self {
162            Self::MemoryAccess(memory_access) => memory_access,
163            _ => panic!("EventReason is not a MemoryAccess"),
164        }
165    }
166
167    /// Returns the control register write event.
168    ///
169    /// # Panics
170    ///
171    /// Panics if the event reason is not a control register write event.
172    pub fn as_write_cr(&self) -> &EventWriteCr {
173        match self {
174            Self::WriteCr(write_cr) => write_cr,
175            _ => panic!("EventReason is not a WriteCr"),
176        }
177    }
178
179    /// Returns the MSR write event.
180    ///
181    /// # Panics
182    ///
183    /// Panics if the event reason is not an MSR write event.
184    pub fn as_write_msr(&self) -> &EventWriteMsr {
185        match self {
186            Self::WriteMsr(write_msr) => write_msr,
187            _ => panic!("EventReason is not a WriteMsr"),
188        }
189    }
190
191    /// Returns the interrupt or exception event.
192    ///
193    /// # Panics
194    ///
195    /// Panics if the event reason is not an interrupt or exception event.
196    pub fn as_interrupt(&self) -> &EventInterrupt {
197        match self {
198            Self::Interrupt(interrupt) => interrupt,
199            _ => panic!("EventReason is not an Interrupt"),
200        }
201    }
202
203    /// Returns the singlestep event.
204    ///
205    /// # Panics
206    ///
207    /// Panics if the event reason is not a singlestep event.
208    pub fn as_singlestep(&self) -> &EventSinglestep {
209        match self {
210            Self::Singlestep(singlestep) => singlestep,
211            _ => panic!("EventReason is not a Singlestep"),
212        }
213    }
214
215    /// Returns the hypercall event.
216    ///
217    /// # Panics
218    ///
219    /// Panics if the event reason is not a hypercall event.
220    pub fn as_hypercall(&self) -> &EventHypercall {
221        match self {
222            Self::Hypercall(hypercall) => hypercall,
223            _ => panic!("EventReason is not a Hypercall"),
224        }
225    }
226
227    /// Returns the CPUID instruction event.
228    ///
229    /// # Panics
230    ///
231    /// Panics if the event reason is not a CPUID instruction event.
232    pub fn as_cpuid(&self) -> &EventCpuId {
233        match self {
234            Self::CpuId(cpuid) => cpuid,
235            _ => panic!("EventReason is not a CpuId"),
236        }
237    }
238
239    /// Returns the I/O port access event.
240    ///
241    /// # Panics
242    ///
243    /// Panics if the event reason is not an I/O port access event.
244    pub fn as_io(&self) -> &EventIo {
245        match self {
246            Self::Io(io) => io,
247            _ => panic!("EventReason is not an Io"),
248        }
249    }
250}
251
252/// Specifies which hardware events should be monitored.
253///
254/// This enum is used to specify which hardware events should be monitored by
255/// the VMI system.
256#[derive(Debug, Clone, Copy)]
257pub enum EventMonitor {
258    // MemoryAccess, (implicit)
259    /// Monitor writes to a specific control register.
260    ///
261    /// This method allows for setting up event triggers when certain CPU
262    /// registers are accessed or modified. The specific registers that can
263    /// be monitored are defined by the [`ControlRegister`] enum.
264    ///
265    /// When enabled, relevant events will be passed to the event callback
266    /// function.
267    Register(ControlRegister),
268
269    /// Monitor writes to a specific model-specific register (MSR).
270    ///
271    /// When enabled, this method generates an event each time the specified
272    /// MSR is written to via the WRMSR instruction. This can be useful for
273    /// detecting changes to system configuration, such as SYSCALL entry
274    /// points ([`Msr::LSTAR`]), segment base addresses ([`Msr::FS_BASE`],
275    /// [`Msr::GS_BASE`]), or extended feature settings ([`Msr::EFER`]).
276    ///
277    /// MSR write events will be passed to the event callback function when
278    /// they occur.
279    Msr(Msr),
280
281    /// Monitor specific hardware interrupts or exception vectors.
282    ///
283    /// This method sets up event triggers for specified interrupt events. The
284    /// types of interrupts that can be monitored are defined by the
285    /// [`ExceptionVector`] enum.
286    ///
287    /// When an interrupt event occurs, it will be passed to the event callback
288    /// function.
289    Interrupt(ExceptionVector),
290
291    /// Monitor singlestep execution of instructions.
292    ///
293    /// When enabled, this method causes the VMI system to generate an event
294    /// after each instruction execution in the guest. This can be useful
295    /// for detailed analysis of guest behavior, but may have a significant
296    /// performance impact.
297    ///
298    /// Single-step events will be passed to the event callback function when
299    /// they occur.
300    Singlestep,
301
302    /// Monitor execution of VMCALL instructions.
303    ///
304    /// When enabled, this method generates an event each time a VMCALL
305    /// instruction is executed in the guest. This can be useful for
306    /// implementing custom hypercalls or for implementing custom
307    /// virtual device behavior.
308    ///
309    /// VMCALL events will be passed to the event callback function when they
310    /// occur.
311    Hypercall {
312        /// Allow userspace to handle the VMCALL.
313        allow_userspace: bool,
314    },
315
316    /// Monitor execution of CPUID instructions.
317    ///
318    /// When enabled, this method generates an event each time a CPUID
319    /// instruction is executed in the guest. This can be useful for
320    /// analyzing how the guest queries CPU features or for implementing CPU
321    /// feature spoofing.
322    ///
323    /// CPUID events will be passed to the event callback function when they
324    /// occur.
325    CpuId,
326
327    /// Monitor I/O port accesses.
328    ///
329    /// When enabled, this method generates events for I/O port read and write
330    /// operations performed by the guest. This can be useful for analyzing
331    /// guest interactions with virtual hardware or for implementing custom
332    /// virtual device behavior.
333    ///
334    /// I/O port events will be passed to the event callback function when they
335    /// occur.
336    Io,
337}