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;
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;
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
159where
160 Self: Debug + Default + Clone + Copy,
161{
162}
163
164/// Complete set of CPU registers for a specific architecture.
165///
166/// Provides methods to access and modify key registers and register sets.
167pub trait Registers
168where
169 Self: Debug + Default + Clone + Copy,
170{
171 /// The specific CPU architecture implementation.
172 type Architecture: Architecture;
173
174 /// General-purpose registers of the architecture.
175 ///
176 /// # Architecture-specific
177 ///
178 /// - **AMD64**: `RAX`, `RBX`, `RCX`, `RDX`, `RSI`, `RDI`, `RSP`, `RBP`,
179 /// `R8`-`R15`, `RIP` and `RFLAGS`.
180 type GpRegisters: GpRegisters;
181
182 /// Returns the current value of the instruction pointer.
183 ///
184 /// # Architecture-specific
185 ///
186 /// - **AMD64**: `RIP`
187 fn instruction_pointer(&self) -> u64;
188
189 /// Sets the value of the instruction pointer.
190 ///
191 /// # Architecture-specific
192 ///
193 /// - **AMD64**: `RIP`
194 fn set_instruction_pointer(&mut self, ip: u64);
195
196 /// Returns the current value of the stack pointer.
197 ///
198 /// # Architecture-specific
199 ///
200 /// - **AMD64**: `RSP`
201 fn stack_pointer(&self) -> u64;
202
203 /// Sets the value of the stack pointer.
204 ///
205 /// # Architecture-specific
206 ///
207 /// - **AMD64**: `RSP`
208 fn set_stack_pointer(&mut self, sp: u64);
209
210 /// Returns the current value of the result register.
211 ///
212 /// # Architecture-specific
213 ///
214 /// - **AMD64**: `RAX`
215 fn result(&self) -> u64;
216
217 /// Sets the value of the result register.
218 ///
219 /// # Architecture-specific
220 ///
221 /// - **AMD64**: `RAX`
222 fn set_result(&mut self, result: u64);
223
224 /// Returns a copy of all general-purpose registers.
225 fn gp_registers(&self) -> Self::GpRegisters;
226
227 /// Sets all general-purpose registers.
228 fn set_gp_registers(&mut self, gp: &Self::GpRegisters);
229
230 /// Returns the native address width (i.e. pointer size) of the architecture
231 /// in bytes.
232 ///
233 /// # Architecture-specific
234 ///
235 /// - **AMD64**: 8 bytes if the `CR4.PAE` bit is set, otherwise 4 bytes
236 fn address_width(&self) -> usize;
237
238 /// Returns the effective address width, which may differ from the native
239 /// width (e.g., in compatibility modes).
240 ///
241 /// # Architecture-specific
242 ///
243 /// - **AMD64**: 8 bytes if the `CS.L` bit is set, otherwise 4 bytes
244 fn effective_address_width(&self) -> usize;
245
246 /// Creates an access context for a given virtual address.
247 fn access_context(&self, va: Va) -> AccessContext;
248
249 /// Creates an address context for a given virtual address.
250 fn address_context(&self, va: Va) -> AddressContext;
251
252 /// Returns the physical address of the root of the current page table
253 /// hierarchy for a given virtual address.
254 ///
255 /// # Architecture-specific
256 ///
257 /// - **AMD64**: `CR3 & 0x0000FFFFFFFFF000`
258 fn translation_root(&self, va: Va) -> Pa;
259
260 /// Attempts to determine the return address of the current function call.
261 ///
262 /// # Architecture-specific
263 ///
264 /// - **AMD64**: Value at the top of the stack (i.e. `RSP`)
265 fn return_address<Driver>(&self, vmi: &VmiCore<Driver>) -> Result<Va, VmiError>
266 where
267 Driver: VmiRead;
268}
269
270/// A memory access event, providing details about the accessed memory.
271pub trait EventMemoryAccess
272where
273 Self: Debug + Clone + Copy,
274{
275 /// The specific CPU architecture implementation.
276 type Architecture: Architecture;
277
278 /// Returns the physical address of the memory access.
279 fn pa(&self) -> Pa;
280
281 /// Returns the virtual address of the memory access.
282 fn va(&self) -> Va;
283
284 /// Returns the type of memory access (e.g., read, write, execute).
285 fn access(&self) -> MemoryAccess;
286}
287
288/// An interrupt event, providing details about the interrupt.
289pub trait EventInterrupt
290where
291 Self: Debug + Clone + Copy,
292{
293 /// The specific CPU architecture implementation.
294 type Architecture: Architecture;
295
296 /// Returns the guest frame number where the interrupt occurred.
297 /// Effectively, this is GFN of the current instruction pointer.
298 fn gfn(&self) -> Gfn;
299}
300
301/// The reason for a VM exit or similar event, allowing for type-safe access
302/// to specific event details.
303pub trait EventReason
304where
305 Self: Debug + Clone + Copy,
306{
307 /// The specific CPU architecture implementation.
308 type Architecture: Architecture;
309
310 /// If the event was caused by a memory access, returns the details
311 /// of that access.
312 fn as_memory_access(
313 &self,
314 ) -> Option<&impl EventMemoryAccess<Architecture = Self::Architecture>>;
315
316 /// If the event was caused by an interrupt, returns the details
317 /// of that interrupt.
318 fn as_interrupt(&self) -> Option<&impl EventInterrupt<Architecture = Self::Architecture>>;
319
320 /// If the event was caused by a software breakpoint, returns the details
321 /// of that breakpoint.
322 fn as_software_breakpoint(
323 &self,
324 ) -> Option<&impl EventInterrupt<Architecture = Self::Architecture>>;
325}