Skip to main content

vmi_core/core/
access_context.rs

1use serde::{Deserialize, Serialize};
2
3use super::impl_ops;
4use crate::AddressContext;
5
6impl_ops! {
7    /// A Guest Frame Number.
8    Gfn, u64
9}
10
11impl_ops! {
12    /// A Guest Physical Address.
13    Pa, u64
14}
15
16impl_ops! {
17    /// A Guest Virtual Address.
18    Va, u64
19}
20
21impl Va {
22    /// Checks if the virtual address is NULL.
23    pub fn is_null(self) -> bool {
24        self.0 == 0
25    }
26}
27
28/// A trait for types that have a virtual address.
29pub trait VmiVa {
30    /// Returns the virtual address.
31    fn va(&self) -> Va;
32}
33
34/// The mechanism used for translating virtual addresses to physical addresses.
35///
36/// Understanding and navigating the memory translation mechanisms of the target
37/// system is crucial. This enum allows specifying whether a direct mapping or a
38/// paging-based translation should be used for memory accesses.
39#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Serialize, Deserialize)]
40pub enum TranslationMechanism {
41    /// Direct mapping (no translation).
42    ///
43    /// In this mode, the provided address is treated as a physical address.
44    /// This is useful for accessing physical memory directly.
45    Direct,
46
47    /// Paging-based translation.
48    ///
49    /// This mode uses the paging structures of the target system to translate
50    /// virtual addresses to physical addresses. It's the common mode for
51    /// accessing memory in most modern operating systems.
52    Paging {
53        /// Optionally specifies the root of the paging structure (e.g., CR3
54        /// value in x86 architecture). If `None`, the current active
55        /// paging structure of the target system should be used.
56        root: Option<Pa>,
57    },
58}
59
60/// Defines the context for memory access operations in VMI.
61///
62/// This struct encapsulates the necessary information to perform a memory
63/// access, including the target address and the mechanism to use for address
64/// translation. It's typically used in conjunction with memory read or write
65/// operations in a VMI tool.
66#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Serialize, Deserialize)]
67pub struct AccessContext {
68    /// The address to access.
69    ///
70    /// Depending on the [`mechanism`] field, this could be interpreted
71    /// as either a virtual address or a physical address.
72    ///
73    /// [`mechanism`]: Self::mechanism
74    pub address: u64,
75
76    /// The mechanism used for address translation.
77    ///
78    /// This field determines how the [`address`] should be interpreted and
79    /// processed during the memory access operation. It allows for
80    /// flexibility in handling different memory layouts and translation
81    /// schemes in the target system.
82    ///
83    /// [`address`]: Self::address
84    pub mechanism: TranslationMechanism,
85}
86
87impl AccessContext {
88    /// Creates a new `AccessContext` with direct mapping.
89    pub fn direct(address: impl Into<Pa>) -> Self {
90        Self {
91            address: u64::from(address.into()),
92            mechanism: TranslationMechanism::Direct,
93        }
94    }
95
96    /// Creates a new `AccessContext` with paging-based translation.
97    pub fn paging(address: impl Into<Va>, root: impl Into<Pa>) -> Self {
98        Self {
99            address: address.into().0,
100            mechanism: TranslationMechanism::Paging {
101                root: Some(root.into()),
102            },
103        }
104    }
105}
106
107impl From<Pa> for AccessContext {
108    fn from(value: Pa) -> Self {
109        Self::direct(value)
110    }
111}
112
113impl From<(Va, Pa)> for AccessContext {
114    fn from(value: (Va, Pa)) -> Self {
115        Self::paging(value.0, value.1)
116    }
117}
118
119impl From<AddressContext> for AccessContext {
120    fn from(value: AddressContext) -> Self {
121        Self {
122            address: value.va.0,
123            mechanism: TranslationMechanism::Paging {
124                root: Some(value.root),
125            },
126        }
127    }
128}
129
130impl ::std::ops::Add<u64> for AccessContext {
131    type Output = AccessContext;
132
133    fn add(self, rhs: u64) -> Self::Output {
134        Self {
135            address: self.address + rhs,
136            ..self
137        }
138    }
139}
140
141impl ::std::ops::Add<AccessContext> for AccessContext {
142    type Output = AccessContext;
143
144    fn add(self, rhs: AccessContext) -> Self::Output {
145        Self {
146            address: self.address + rhs.address,
147            ..self
148        }
149    }
150}
151
152impl ::std::ops::AddAssign<u64> for AccessContext {
153    fn add_assign(&mut self, rhs: u64) {
154        self.address += rhs;
155    }
156}
157
158impl ::std::ops::AddAssign<AccessContext> for AccessContext {
159    fn add_assign(&mut self, rhs: AccessContext) {
160        self.address += rhs.address;
161    }
162}
163
164impl ::std::ops::Sub<u64> for AccessContext {
165    type Output = AccessContext;
166
167    fn sub(self, rhs: u64) -> Self::Output {
168        Self {
169            address: self.address - rhs,
170            ..self
171        }
172    }
173}
174
175impl ::std::ops::Sub<AccessContext> for AccessContext {
176    type Output = AccessContext;
177
178    fn sub(self, rhs: AccessContext) -> Self::Output {
179        Self {
180            address: self.address - rhs.address,
181            ..self
182        }
183    }
184}
185
186impl ::std::ops::SubAssign<u64> for AccessContext {
187    fn sub_assign(&mut self, rhs: u64) {
188        self.address -= rhs;
189    }
190}
191
192impl ::std::ops::SubAssign<AccessContext> for AccessContext {
193    fn sub_assign(&mut self, rhs: AccessContext) {
194        self.address -= rhs.address;
195    }
196}
197
198impl ::std::ops::Mul<u64> for AccessContext {
199    type Output = AccessContext;
200
201    fn mul(self, rhs: u64) -> Self::Output {
202        Self {
203            address: self.address * rhs,
204            ..self
205        }
206    }
207}
208
209impl ::std::ops::Mul<AccessContext> for AccessContext {
210    type Output = AccessContext;
211
212    fn mul(self, rhs: AccessContext) -> Self::Output {
213        Self {
214            address: self.address * rhs.address,
215            ..self
216        }
217    }
218}
219
220impl ::std::ops::MulAssign<u64> for AccessContext {
221    fn mul_assign(&mut self, rhs: u64) {
222        self.address *= rhs;
223    }
224}
225
226impl ::std::ops::MulAssign<AccessContext> for AccessContext {
227    fn mul_assign(&mut self, rhs: AccessContext) {
228        self.address *= rhs.address;
229    }
230}
231
232impl ::std::ops::Div<u64> for AccessContext {
233    type Output = AccessContext;
234
235    fn div(self, rhs: u64) -> Self::Output {
236        Self {
237            address: self.address / rhs,
238            ..self
239        }
240    }
241}
242
243impl ::std::ops::Div<AccessContext> for AccessContext {
244    type Output = AccessContext;
245
246    fn div(self, rhs: AccessContext) -> Self::Output {
247        Self {
248            address: self.address / rhs.address,
249            ..self
250        }
251    }
252}
253
254impl ::std::ops::DivAssign<u64> for AccessContext {
255    fn div_assign(&mut self, rhs: u64) {
256        self.address /= rhs;
257    }
258}
259
260impl ::std::ops::DivAssign<AccessContext> for AccessContext {
261    fn div_assign(&mut self, rhs: AccessContext) {
262        self.address /= rhs.address;
263    }
264}
265
266impl ::std::ops::BitAnd<u64> for AccessContext {
267    type Output = AccessContext;
268
269    fn bitand(self, rhs: u64) -> Self::Output {
270        Self {
271            address: self.address & rhs,
272            ..self
273        }
274    }
275}
276
277impl ::std::ops::BitAndAssign<u64> for AccessContext {
278    fn bitand_assign(&mut self, rhs: u64) {
279        self.address &= rhs;
280    }
281}
282
283impl ::std::ops::BitOr<u64> for AccessContext {
284    type Output = AccessContext;
285
286    fn bitor(self, rhs: u64) -> Self::Output {
287        Self {
288            address: self.address | rhs,
289            ..self
290        }
291    }
292}
293
294impl ::std::ops::BitOrAssign<u64> for AccessContext {
295    fn bitor_assign(&mut self, rhs: u64) {
296        self.address |= rhs;
297    }
298}