vmi_core/arch.rs
1#![doc = include_str!("../docs/arch.md")]
2
3use std::fmt::Debug;
4
5use crate::{AccessContext, AddressContext, Gfn, MemoryAccess, Pa, Va, VmiCore, VmiError, VmiRead};
6
7/// Defines an interface for CPU architecture-specific operations and constants.
8///
9/// The `Architecture` trait provides generic abstraction for interacting with
10/// different CPU architectures in the context of virtual machine introspection.
11///
12/// This trait encapsulates the key characteristics and operations that vary
13/// across different CPU architectures, allowing for the implementation of
14/// architecture-agnostic tools and libraries.
15pub trait Architecture {
16 /// The size of a memory page in bytes for the given architecture.
17 ///
18 /// # Architecture-specific
19 ///
20 /// - **AMD64**: `0x1000` (4096 bytes)
21 const PAGE_SIZE: u64;
22
23 /// The number of bits to shift when converting between page numbers and
24 /// physical addresses.
25 ///
26 /// # Architecture-specific
27 ///
28 /// - **AMD64**: `12` (2^12 = 4096)
29 const PAGE_SHIFT: u64;
30
31 /// A bitmask used to isolate the page number from a full address.
32 ///
33 /// # Architecture-specific
34 ///
35 /// - **AMD64**: `0xFFFFFFFFFFFFF000`
36 const PAGE_MASK: u64;
37
38 /// The machine code for a breakpoint instruction in the given architecture.
39 ///
40 /// # Architecture-specific
41 ///
42 /// - **AMD64**: `&[0xcc]` (`INT3` instruction)
43 const BREAKPOINT: &'static [u8];
44
45 /// The complete set of CPU registers for the architecture.
46 ///
47 /// This type should include general-purpose registers, and all control and
48 /// special registers.
49 type Registers: Registers<Architecture = Self>;
50
51 /// An enumeration representing the levels of page tables in the
52 /// architecture's paging structure.
53 ///
54 /// # Architecture-specific
55 ///
56 /// - **AMD64**: PML5, PML4, PDPT, PD, PT
57 type PageTableLevel: Debug + Clone + Copy;
58
59 /// Various types of interrupts that can occur in the architecture.
60 type Interrupt: Debug + Clone + Copy;
61
62 /// Represents special-purpose registers in the architecture.
63 ///
64 /// # Architecture-specific
65 ///
66 /// - **AMD64**: May represent control registers like `CR0`, `CR2`, `CR3`,
67 /// `CR4`
68 type SpecialRegister: Debug + Clone + Copy;
69
70 /// Options for monitoring.
71 type EventMonitor;
72
73 /// Architecture-specific event details.
74 type EventReason: EventReason<Architecture = Self>;
75
76 /// Converts a guest physical address (GPA) to a guest frame number (GFN).
77 ///
78 /// # Architecture-specific
79 ///
80 /// - **AMD64**: `gfn = pa >> 12`
81 fn gfn_from_pa(pa: Pa) -> Gfn;
82
83 /// Converts a guest frame number (GFN) to a guest physical address (GPA).
84 ///
85 /// # Architecture-specific
86 ///
87 /// - **AMD64**: `pa = gfn << 12`
88 fn pa_from_gfn(gfn: Gfn) -> Pa;
89
90 /// Combines a guest frame number (GFN) with the in-page offset of a
91 /// virtual address to form a guest physical address (GPA).
92 ///
93 /// # Architecture-specific
94 ///
95 /// - **AMD64**: `pa = (gfn << 12) + (va & 0xfff)`
96 fn pa_in_gfn(gfn: Gfn, va: Va) -> Pa;
97
98 /// Combines a guest frame number (GFN) with the in-page offset of a
99 /// virtual address for a given page table level to form a guest
100 /// physical address (GPA).
101 fn pa_in_gfn_for(gfn: Gfn, va: Va, level: Self::PageTableLevel) -> Pa;
102
103 /// Extracts the offset within a page from a physical address.
104 ///
105 /// # Architecture-specific
106 ///
107 /// - **AMD64**: `offset = pa & 0xfff`
108 fn pa_offset(pa: Pa) -> u64;
109
110 /// Aligns a virtual address down to the nearest page boundary.
111 ///
112 /// # Architecture-specific
113 ///
114 /// - **AMD64**: `va & ~0xfff`
115 fn va_align_down(va: Va) -> Va;
116
117 /// Aligns a virtual address down to the nearest page boundary for a given
118 /// page table level.
119 fn va_align_down_for(va: Va, level: Self::PageTableLevel) -> Va;
120
121 /// Aligns a virtual address up to the nearest page boundary.
122 ///
123 /// # Architecture-specific
124 ///
125 /// - **AMD64**: `(va + 0xfff) & ~0xfff`
126 fn va_align_up(va: Va) -> Va;
127
128 /// Aligns a virtual address up to the nearest page boundary for a given
129 /// page table level.
130 fn va_align_up_for(va: Va, level: Self::PageTableLevel) -> Va;
131
132 /// Extracts the offset within a page from a virtual address.
133 ///
134 /// # Architecture-specific
135 ///
136 /// - **AMD64**: `offset = va & 0xfff`
137 fn va_offset(va: Va) -> u64;
138
139 /// Calculates the offset within a page for a given virtual address and
140 /// page table level.
141 fn va_offset_for(va: Va, level: Self::PageTableLevel) -> u64;
142
143 /// Calculates the index into the lowest level page table for a given
144 /// virtual address.
145 ///
146 /// # Architecture-specific
147 ///
148 /// - **AMD64**: `index = va & 0x1ff`
149 fn va_index(va: Va) -> u64;
150
151 /// Calculates the index into the specified level of the page table
152 /// hierarchy for a given virtual address.
153 fn va_index_for(va: Va, level: Self::PageTableLevel) -> u64;
154
155 /// Performs a full page table walk to translate a virtual address to a
156 /// physical address.
157 fn translate_address<Driver>(vmi: &VmiCore<Driver>, va: Va, root: Pa) -> Result<Pa, VmiError>
158 where
159 Driver: VmiRead<Architecture = Self>;
160}
161
162/// General-purpose register set for a specific architecture.
163///
164/// Marker trait for the concrete GP register struct exposed by each
165/// architecture.
166///
167/// # Architecture-specific
168///
169/// - **AMD64**: `RAX`, `RBX`, `RCX`, `RDX`, `RSI`, `RDI`, `RSP`, `RBP`,
170/// `R8`-`R15`, `RIP` and `RFLAGS`.
171pub trait GpRegisters: Debug + Default + Clone + Copy {
172 /// The specific CPU architecture implementation.
173 type Architecture: Architecture;
174
175 /// Returns the current value of the instruction pointer.
176 ///
177 /// # Architecture-specific
178 ///
179 /// - **AMD64**: `RIP`
180 fn instruction_pointer(&self) -> u64;
181
182 /// Sets the value of the instruction pointer.
183 ///
184 /// # Architecture-specific
185 ///
186 /// - **AMD64**: `RIP`
187 fn set_instruction_pointer(&mut self, ip: u64);
188
189 /// Returns the current value of the stack pointer.
190 ///
191 /// # Architecture-specific
192 ///
193 /// - **AMD64**: `RSP`
194 fn stack_pointer(&self) -> u64;
195
196 /// Sets the value of the stack pointer.
197 ///
198 /// # Architecture-specific
199 ///
200 /// - **AMD64**: `RSP`
201 fn set_stack_pointer(&mut self, sp: u64);
202
203 /// Returns the current value of the result register.
204 ///
205 /// # Architecture-specific
206 ///
207 /// - **AMD64**: `RAX`
208 fn result(&self) -> u64;
209
210 /// Sets the value of the result register.
211 ///
212 /// # Architecture-specific
213 ///
214 /// - **AMD64**: `RAX`
215 fn set_result(&mut self, result: u64);
216}
217
218/// Complete set of CPU registers for a specific architecture.
219///
220/// Provides methods to access and modify key registers and register sets.
221pub trait Registers: Debug + Default + Clone + Copy {
222 /// The specific CPU architecture implementation.
223 type Architecture: Architecture<Registers = Self>;
224
225 /// General-purpose registers of the architecture.
226 ///
227 /// # Architecture-specific
228 ///
229 /// - **AMD64**: `RAX`, `RBX`, `RCX`, `RDX`, `RSI`, `RDI`, `RSP`, `RBP`,
230 /// `R8`-`R15`, `RIP` and `RFLAGS`.
231 type GpRegisters: GpRegisters<Architecture = Self::Architecture>;
232
233 /// Returns the current value of the instruction pointer.
234 ///
235 /// # Architecture-specific
236 ///
237 /// - **AMD64**: `RIP`
238 fn instruction_pointer(&self) -> u64;
239
240 /// Sets the value of the instruction pointer.
241 ///
242 /// # Architecture-specific
243 ///
244 /// - **AMD64**: `RIP`
245 fn set_instruction_pointer(&mut self, ip: u64);
246
247 /// Returns the current value of the stack pointer.
248 ///
249 /// # Architecture-specific
250 ///
251 /// - **AMD64**: `RSP`
252 fn stack_pointer(&self) -> u64;
253
254 /// Sets the value of the stack pointer.
255 ///
256 /// # Architecture-specific
257 ///
258 /// - **AMD64**: `RSP`
259 fn set_stack_pointer(&mut self, sp: u64);
260
261 /// Returns the current value of the result register.
262 ///
263 /// # Architecture-specific
264 ///
265 /// - **AMD64**: `RAX`
266 fn result(&self) -> u64;
267
268 /// Sets the value of the result register.
269 ///
270 /// # Architecture-specific
271 ///
272 /// - **AMD64**: `RAX`
273 fn set_result(&mut self, result: u64);
274
275 /// Returns a copy of all general-purpose registers.
276 fn gp_registers(&self) -> Self::GpRegisters;
277
278 /// Sets all general-purpose registers.
279 fn set_gp_registers(&mut self, gp: &Self::GpRegisters);
280
281 /// Returns the native address width (i.e. pointer size) of the architecture
282 /// in bytes.
283 ///
284 /// # Architecture-specific
285 ///
286 /// - **AMD64**: 8 bytes if the `CR4.PAE` bit is set, otherwise 4 bytes
287 fn address_width(&self) -> usize;
288
289 /// Returns the effective address width, which may differ from the native
290 /// width (e.g., in compatibility modes).
291 ///
292 /// # Architecture-specific
293 ///
294 /// - **AMD64**: 8 bytes if the `CS.L` bit is set, otherwise 4 bytes
295 fn effective_address_width(&self) -> usize;
296
297 /// Creates an access context for a given virtual address.
298 fn access_context(&self, va: Va) -> AccessContext;
299
300 /// Creates an address context for a given virtual address.
301 fn address_context(&self, va: Va) -> AddressContext;
302
303 /// Returns the physical address of the root of the current page table
304 /// hierarchy for a given virtual address.
305 ///
306 /// # Architecture-specific
307 ///
308 /// - **AMD64**: `CR3 & 0x0000FFFFFFFFF000`
309 fn translation_root(&self, va: Va) -> Pa;
310
311 /// Sets the physical address of the root of the current page table hierarchy
312 /// for a given virtual address.
313 ///
314 /// # Architecture-specific
315 ///
316 /// - **AMD64**: `CR3`
317 fn set_translation_root(&mut self, root: u64, va: Va);
318
319 /// Attempts to determine the return address of the current function call.
320 ///
321 /// # Architecture-specific
322 ///
323 /// - **AMD64**: Value at the top of the stack (i.e. `RSP`)
324 fn return_address<Driver>(&self, vmi: &VmiCore<Driver>) -> Result<Va, VmiError>
325 where
326 Driver: VmiRead<Architecture = Self::Architecture>;
327
328 /// Builds the general-purpose registers that make the current function
329 /// return `value` to its caller without executing its body.
330 ///
331 /// # Architecture-specific
332 ///
333 /// - **AMD64**: Sets `RAX` to `value`, sets `RIP` to the value read from
334 /// the stack at `RSP`, and advances `RSP` by the effective address width
335 /// to consume the return address.
336 fn return_from_function<Driver>(
337 &self,
338 vmi: &VmiCore<Driver>,
339 value: u64,
340 ) -> Result<Self::GpRegisters, VmiError>
341 where
342 Driver: VmiRead<Architecture = Self::Architecture>;
343}
344
345/// A memory access event, providing details about the accessed memory.
346pub trait EventMemoryAccess: Debug + Clone + Copy {
347 /// The specific CPU architecture implementation.
348 type Architecture: Architecture;
349
350 /// Returns the physical address of the memory access.
351 fn pa(&self) -> Pa;
352
353 /// Returns the virtual address of the memory access.
354 fn va(&self) -> Va;
355
356 /// Returns the type of memory access (e.g., read, write, execute).
357 fn access(&self) -> MemoryAccess;
358}
359
360/// An interrupt event, providing details about the interrupt.
361pub trait EventInterrupt: Debug + Clone + Copy {
362 /// The specific CPU architecture implementation.
363 type Architecture: Architecture;
364
365 /// Returns the guest frame number where the interrupt occurred.
366 /// Effectively, this is GFN of the current instruction pointer.
367 fn gfn(&self) -> Gfn;
368}
369
370/// The reason for a VM exit or similar event, allowing for type-safe access
371/// to specific event details.
372pub trait EventReason: Debug + Clone + Copy {
373 /// The specific CPU architecture implementation.
374 type Architecture: Architecture<EventReason = Self>;
375
376 /// If the event was caused by a memory access, returns the details
377 /// of that access.
378 fn as_memory_access(
379 &self,
380 ) -> Option<&impl EventMemoryAccess<Architecture = Self::Architecture>>;
381
382 /// If the event was caused by an interrupt, returns the details
383 /// of that interrupt.
384 fn as_interrupt(&self) -> Option<&impl EventInterrupt<Architecture = Self::Architecture>>;
385
386 /// If the event was caused by a software breakpoint, returns the details
387 /// of that breakpoint.
388 fn as_software_breakpoint(
389 &self,
390 ) -> Option<&impl EventInterrupt<Architecture = Self::Architecture>>;
391}