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}