vmi_core/core/
access_context.rs

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