vmi_core/
arch.rs

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