Skip to main content

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    /// Extracts the offset within a page from a physical address.
91    ///
92    /// # Architecture-specific
93    ///
94    /// - **AMD64**: `offset = pa & 0xfff`
95    fn pa_offset(pa: Pa) -> u64;
96
97    /// Aligns a virtual address down to the nearest page boundary.
98    ///
99    /// # Architecture-specific
100    ///
101    /// - **AMD64**: `va & ~0xfff`
102    fn va_align_down(va: Va) -> Va;
103
104    /// Aligns a virtual address down to the nearest page boundary for a given
105    /// page table level.
106    fn va_align_down_for(va: Va, level: Self::PageTableLevel) -> Va;
107
108    /// Aligns a virtual address up to the nearest page boundary.
109    ///
110    /// # Architecture-specific
111    ///
112    /// - **AMD64**: `(va + 0xfff) & ~0xfff`
113    fn va_align_up(va: Va) -> Va;
114
115    /// Aligns a virtual address up to the nearest page boundary for a given
116    /// page table level.
117    fn va_align_up_for(va: Va, level: Self::PageTableLevel) -> Va;
118
119    /// Extracts the offset within a page from a virtual address.
120    ///
121    /// # Architecture-specific
122    ///
123    /// - **AMD64**: `offset = va & 0xfff`
124    fn va_offset(va: Va) -> u64;
125
126    /// Calculates the offset within a page for a given virtual address and
127    /// page table level.
128    fn va_offset_for(va: Va, level: Self::PageTableLevel) -> u64;
129
130    /// Calculates the index into the lowest level page table for a given
131    /// virtual address.
132    ///
133    /// # Architecture-specific
134    ///
135    /// - **AMD64**: `index = va & 0x1ff`
136    fn va_index(va: Va) -> u64;
137
138    /// Calculates the index into the specified level of the page table
139    /// hierarchy for a given virtual address.
140    fn va_index_for(va: Va, level: Self::PageTableLevel) -> u64;
141
142    /// Performs a full page table walk to translate a virtual address to a
143    /// physical address.
144    fn translate_address<Driver>(vmi: &VmiCore<Driver>, va: Va, root: Pa) -> Result<Pa, VmiError>
145    where
146        Driver: VmiRead<Architecture = Self>;
147}
148
149/// General-purpose register set for a specific architecture.
150///
151/// Marker trait for the concrete GP register struct exposed by each
152/// architecture.
153///
154/// # Architecture-specific
155///
156/// - **AMD64**: `RAX`, `RBX`, `RCX`, `RDX`, `RSI`, `RDI`, `RSP`, `RBP`,
157///   `R8`-`R15`, `RIP` and `RFLAGS`.
158pub trait GpRegisters: Debug + Default + Clone + Copy {
159    /// The specific CPU architecture implementation.
160    type Architecture: Architecture;
161
162    /// Returns the current value of the instruction pointer.
163    ///
164    /// # Architecture-specific
165    ///
166    /// - **AMD64**: `RIP`
167    fn instruction_pointer(&self) -> u64;
168
169    /// Sets the value of the instruction pointer.
170    ///
171    /// # Architecture-specific
172    ///
173    /// - **AMD64**: `RIP`
174    fn set_instruction_pointer(&mut self, ip: u64);
175
176    /// Returns the current value of the stack pointer.
177    ///
178    /// # Architecture-specific
179    ///
180    /// - **AMD64**: `RSP`
181    fn stack_pointer(&self) -> u64;
182
183    /// Sets the value of the stack pointer.
184    ///
185    /// # Architecture-specific
186    ///
187    /// - **AMD64**: `RSP`
188    fn set_stack_pointer(&mut self, sp: u64);
189
190    /// Returns the current value of the result register.
191    ///
192    /// # Architecture-specific
193    ///
194    /// - **AMD64**: `RAX`
195    fn result(&self) -> u64;
196
197    /// Sets the value of the result register.
198    ///
199    /// # Architecture-specific
200    ///
201    /// - **AMD64**: `RAX`
202    fn set_result(&mut self, result: u64);
203}
204
205/// Complete set of CPU registers for a specific architecture.
206///
207/// Provides methods to access and modify key registers and register sets.
208pub trait Registers: Debug + Default + Clone + Copy {
209    /// The specific CPU architecture implementation.
210    type Architecture: Architecture<Registers = Self>;
211
212    /// General-purpose registers of the architecture.
213    ///
214    /// # Architecture-specific
215    ///
216    /// - **AMD64**: `RAX`, `RBX`, `RCX`, `RDX`, `RSI`, `RDI`, `RSP`, `RBP`,
217    ///   `R8`-`R15`, `RIP` and `RFLAGS`.
218    type GpRegisters: GpRegisters<Architecture = Self::Architecture>;
219
220    /// Returns the current value of the instruction pointer.
221    ///
222    /// # Architecture-specific
223    ///
224    /// - **AMD64**: `RIP`
225    fn instruction_pointer(&self) -> u64;
226
227    /// Sets the value of the instruction pointer.
228    ///
229    /// # Architecture-specific
230    ///
231    /// - **AMD64**: `RIP`
232    fn set_instruction_pointer(&mut self, ip: u64);
233
234    /// Returns the current value of the stack pointer.
235    ///
236    /// # Architecture-specific
237    ///
238    /// - **AMD64**: `RSP`
239    fn stack_pointer(&self) -> u64;
240
241    /// Sets the value of the stack pointer.
242    ///
243    /// # Architecture-specific
244    ///
245    /// - **AMD64**: `RSP`
246    fn set_stack_pointer(&mut self, sp: u64);
247
248    /// Returns the current value of the result register.
249    ///
250    /// # Architecture-specific
251    ///
252    /// - **AMD64**: `RAX`
253    fn result(&self) -> u64;
254
255    /// Sets the value of the result register.
256    ///
257    /// # Architecture-specific
258    ///
259    /// - **AMD64**: `RAX`
260    fn set_result(&mut self, result: u64);
261
262    /// Returns a copy of all general-purpose registers.
263    fn gp_registers(&self) -> Self::GpRegisters;
264
265    /// Sets all general-purpose registers.
266    fn set_gp_registers(&mut self, gp: &Self::GpRegisters);
267
268    /// Returns the native address width (i.e. pointer size) of the architecture
269    /// in bytes.
270    ///
271    /// # Architecture-specific
272    ///
273    /// - **AMD64**: 8 bytes if the `CR4.PAE` bit is set, otherwise 4 bytes
274    fn address_width(&self) -> usize;
275
276    /// Returns the effective address width, which may differ from the native
277    /// width (e.g., in compatibility modes).
278    ///
279    /// # Architecture-specific
280    ///
281    /// - **AMD64**: 8 bytes if the `CS.L` bit is set, otherwise 4 bytes
282    fn effective_address_width(&self) -> usize;
283
284    /// Creates an access context for a given virtual address.
285    fn access_context(&self, va: Va) -> AccessContext;
286
287    /// Creates an address context for a given virtual address.
288    fn address_context(&self, va: Va) -> AddressContext;
289
290    /// Returns the physical address of the root of the current page table
291    /// hierarchy for a given virtual address.
292    ///
293    /// # Architecture-specific
294    ///
295    /// - **AMD64**: `CR3 & 0x0000FFFFFFFFF000`
296    fn translation_root(&self, va: Va) -> Pa;
297
298    /// Attempts to determine the return address of the current function call.
299    ///
300    /// # Architecture-specific
301    ///
302    /// - **AMD64**: Value at the top of the stack (i.e. `RSP`)
303    fn return_address<Driver>(&self, vmi: &VmiCore<Driver>) -> Result<Va, VmiError>
304    where
305        Driver: VmiRead<Architecture = Self::Architecture>;
306}
307
308/// A memory access event, providing details about the accessed memory.
309pub trait EventMemoryAccess: Debug + Clone + Copy {
310    /// The specific CPU architecture implementation.
311    type Architecture: Architecture;
312
313    /// Returns the physical address of the memory access.
314    fn pa(&self) -> Pa;
315
316    /// Returns the virtual address of the memory access.
317    fn va(&self) -> Va;
318
319    /// Returns the type of memory access (e.g., read, write, execute).
320    fn access(&self) -> MemoryAccess;
321}
322
323/// An interrupt event, providing details about the interrupt.
324pub trait EventInterrupt: Debug + Clone + Copy {
325    /// The specific CPU architecture implementation.
326    type Architecture: Architecture;
327
328    /// Returns the guest frame number where the interrupt occurred.
329    /// Effectively, this is GFN of the current instruction pointer.
330    fn gfn(&self) -> Gfn;
331}
332
333/// The reason for a VM exit or similar event, allowing for type-safe access
334/// to specific event details.
335pub trait EventReason: Debug + Clone + Copy {
336    /// The specific CPU architecture implementation.
337    type Architecture: Architecture<EventReason = Self>;
338
339    /// If the event was caused by a memory access, returns the details
340    /// of that access.
341    fn as_memory_access(
342        &self,
343    ) -> Option<&impl EventMemoryAccess<Architecture = Self::Architecture>>;
344
345    /// If the event was caused by an interrupt, returns the details
346    /// of that interrupt.
347    fn as_interrupt(&self) -> Option<&impl EventInterrupt<Architecture = Self::Architecture>>;
348
349    /// If the event was caused by a software breakpoint, returns the details
350    /// of that breakpoint.
351    fn as_software_breakpoint(
352        &self,
353    ) -> Option<&impl EventInterrupt<Architecture = Self::Architecture>>;
354}