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