kdmp_parser/gxa.rs
1// Axel '0vercl0k' Souchet - May 30 2023
2//! This contains types that are useful to manipulate
3//! Guest Virtual Addresses ([`Gva`]) and Guest Physical Addresses ([`Gpa`]).
4//! Because ultimately they are both [`u64`] under the hood, a lot of operations
5//! apply to both [`Gva`] & [`Gpa`] ([`Gxa::page_align`], etc.) and those are
6//! implemented into the parent trait [`Gxa`].
7//!
8//! # Examples
9//!
10//! ```
11//! use kdmp_parser::{Gxa, Gva};
12//! let gva = Gva::new(1337);
13//! let page_aligned_gva = gva.page_align();
14//! let page_offset = gva.offset();
15//! ```
16use std::fmt::Display;
17use std::num::ParseIntError;
18use std::ops::AddAssign;
19use std::str::FromStr;
20
21use crate::pxe::Pfn;
22use crate::structs::PageKind;
23
24/// A bunch of useful methods to manipulate 64-bit addresses of
25/// any kind.
26pub trait Gxa: Sized + Default + Copy + From<u64> {
27 /// Get the underlying [`u64`] out of it.
28 fn u64(&self) -> u64;
29
30 /// Get the page offset.
31 fn offset(&self) -> u64 {
32 self.u64() & 0xf_ff
33 }
34
35 /// Is it page aligned?
36 fn page_aligned(&self) -> bool {
37 self.offset() == 0
38 }
39
40 /// Page-align it.
41 fn page_align(&self) -> Self {
42 Self::from(self.u64() & !0xf_ff)
43 }
44
45 /// Get the next aligned page.
46 fn next_aligned_page(self) -> Self {
47 Self::from(
48 self.page_align()
49 .u64()
50 .checked_add(PageKind::Normal.size())
51 .expect("Cannot overflow"),
52 )
53 }
54}
55
56/// Strong type for Guest Physical Addresses.
57///
58/// # Examples
59///
60/// ```
61/// # use kdmp_parser::{Gxa, Gpa};
62/// # fn main() {
63/// let gpa = Gpa::new(0x1337_123);
64/// assert_eq!(gpa.offset(), 0x123);
65/// assert_eq!(gpa.page_aligned(), false);
66/// let aligned_gpa = gpa.page_align();
67/// assert_eq!(aligned_gpa.u64(), 0x1337_000);
68/// assert_eq!(aligned_gpa.page_aligned(), true);
69/// let next_gpa = gpa.next_aligned_page();
70/// assert_eq!(next_gpa.u64(), 0x1338_000);
71/// # }
72/// ```
73#[derive(Debug, Clone, Copy, Eq, Hash, PartialEq, Default, PartialOrd, Ord)]
74pub struct Gpa(u64);
75
76impl Gpa {
77 /// Create a new [`Gpa`].
78 ///
79 /// # Examples
80 ///
81 /// ```
82 /// # use kdmp_parser::{Gxa, Gpa};
83 /// # fn main() {
84 /// let gpa = Gpa::new(1337);
85 /// # }
86 /// ```
87 pub const fn new(addr: u64) -> Self {
88 Self(addr)
89 }
90
91 /// Create a new [`Gpa`] from a Page Frame Number or PFN.
92 ///
93 /// # Examples
94 ///
95 /// ```
96 /// # use kdmp_parser::{Gxa, Gpa, Pfn};
97 /// # fn main() {
98 /// let gpa = Gpa::from_pfn(Pfn::new(0x1337));
99 /// assert_eq!(gpa.u64(), 0x1337_000);
100 /// # }
101 /// ```
102 pub const fn from_pfn(pfn: Pfn) -> Self {
103 Self(pfn.u64() << (4 * 3))
104 }
105
106 /// Create a new [`Gpa`] from a Page Frame Number or PFN and an added
107 /// offset.
108 ///
109 /// # Examples
110 ///
111 /// ```
112 /// # use kdmp_parser::{Gxa, Gpa, Pfn};
113 /// # fn main() {
114 /// let gpa = Gpa::from_pfn_with_offset(Pfn::new(0x1337), 0x11);
115 /// assert_eq!(gpa.u64(), 0x1337_011);
116 /// # }
117 /// ```
118 pub const fn from_pfn_with_offset(pfn: Pfn, offset: u64) -> Self {
119 let base = pfn.u64() << (4 * 3);
120
121 Self(base + offset)
122 }
123
124 /// Get the Page Frame Number from a [`Gpa`].
125 ///
126 /// # Examples
127 ///
128 /// ```
129 /// # use kdmp_parser::{Gxa, Gpa};
130 /// # fn main() {
131 /// let gpa = Gpa::new(0x1337_337);
132 /// assert_eq!(gpa.pfn(), 0x1337);
133 /// # }
134 /// ```
135 pub const fn pfn(&self) -> u64 {
136 self.0 >> (4 * 3)
137 }
138}
139
140/// Operator += for [`Gpa`].
141impl AddAssign for Gpa {
142 fn add_assign(&mut self, rhs: Self) {
143 self.0 += rhs.0
144 }
145}
146
147impl Gxa for Gpa {
148 /// Get the underlying [`u64`].
149 ///
150 /// # Examples
151 ///
152 /// ```
153 /// # use kdmp_parser::{Gxa, Gpa};
154 /// # fn main() {
155 /// let gpa = Gpa::new(1337);
156 /// assert_eq!(gpa.u64(), 1337);
157 /// # }
158 /// ```
159 fn u64(&self) -> u64 {
160 self.0
161 }
162}
163
164/// Convert a [`u64`] into a [`Gpa`].
165impl From<u64> for Gpa {
166 /// Create a [`Gpa`] from a [`u64`].
167 ///
168 /// # Examples
169 ///
170 /// ```
171 /// # use kdmp_parser::{Gxa, Gpa};
172 /// # fn main() {
173 /// let gpa = Gpa::from(0xdeadbeef_baadc0de);
174 /// assert_eq!(u64::from(gpa), 0xdeadbeef_baadc0de);
175 /// # }
176 /// ```
177 fn from(value: u64) -> Self {
178 Gpa(value)
179 }
180}
181
182/// Convert a [`Gpa`] into a [`u64`].
183impl From<Gpa> for u64 {
184 /// Create a [`u64`] from a [`Gpa`].
185 ///
186 /// # Examples
187 ///
188 /// ```
189 /// # use kdmp_parser::{Gxa, Gpa};
190 /// # fn main() {
191 /// let gpa = Gpa::new(0xdeadbeef_baadc0de);
192 /// let gpa_u64: u64 = gpa.into();
193 /// assert_eq!(gpa_u64, 0xdeadbeef_baadc0de);
194 /// assert_eq!(u64::from(gpa), 0xdeadbeef_baadc0de);
195 /// # }
196 /// ```
197 fn from(value: Gpa) -> Self {
198 value.0
199 }
200}
201
202/// Convert a [`&Gpa`][`Gpa`] into a [`u64`].
203impl From<&Gpa> for u64 {
204 /// Create a [`u64`] from a [`&Gpa`][`Gpa`].
205 ///
206 /// # Examples
207 ///
208 /// ```
209 /// # use kdmp_parser::{Gxa, Gpa};
210 /// # fn main() {
211 /// let gpa = Gpa::new(0xdeadbeef_baadc0de);
212 /// let gpa_p = &gpa;
213 /// let gpa_u64: u64 = gpa_p.into();
214 /// assert_eq!(gpa_u64, 0xdeadbeef_baadc0de);
215 /// assert_eq!(u64::from(gpa_p), 0xdeadbeef_baadc0de);
216 /// # }
217 /// ```
218 fn from(value: &Gpa) -> Self {
219 value.0
220 }
221}
222
223/// Format a [`Gpa`] as a string.
224impl Display for Gpa {
225 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
226 write!(f, "GPA:{:#x}", self.0)
227 }
228}
229
230/// Parse a [`Gpa`] from a string.
231impl FromStr for Gpa {
232 type Err = ParseIntError;
233
234 fn from_str(s: &str) -> Result<Self, Self::Err> {
235 let s = s.replace('`', "");
236
237 Ok(Gpa::new(u64::from_str_radix(
238 s.trim_start_matches("0x"),
239 16,
240 )?))
241 }
242}
243
244/// Strong type for Guest Virtual Addresses.
245///
246/// # Examples
247///
248/// ```
249/// # use kdmp_parser::{Gxa, Gva};
250/// # fn main() {
251/// let gva = Gva::new(0x1337_fff);
252/// assert_eq!(gva.offset(), 0xfff);
253/// assert_eq!(gva.page_aligned(), false);
254/// let aligned_gva = gva.page_align();
255/// assert_eq!(aligned_gva.u64(), 0x1337_000);
256/// assert_eq!(aligned_gva.page_aligned(), true);
257/// let next_gva = gva.next_aligned_page();
258/// assert_eq!(next_gva.u64(), 0x1338_000);
259/// # }
260/// ```
261#[derive(Debug, Clone, Copy, Eq, Hash, PartialEq, Default, PartialOrd, Ord)]
262pub struct Gva(u64);
263
264impl Gva {
265 /// Create a new [`Gva`].
266 ///
267 /// # Examples
268 ///
269 /// ```
270 /// # use kdmp_parser::{Gxa, Gva};
271 /// # fn main() {
272 /// let gva = Gva::new(0xdeadbeef);
273 /// # }
274 /// ```
275 pub const fn new(addr: u64) -> Self {
276 Self(addr)
277 }
278
279 /// Get the PTE index of the [`Gva`].
280 ///
281 /// # Examples
282 ///
283 /// ```
284 /// # use kdmp_parser::{Gxa, Gva};
285 /// # fn main() {
286 /// let first = Gva::new(0xff_ff_b9_dc_ee_77_31_37);
287 /// assert_eq!(first.pte_idx(), 371);
288 /// let second = Gva::new(0xff_ff_11_22_33_44_55_66);
289 /// assert_eq!(second.pte_idx(), 0x45);
290 /// # }
291 /// ```
292 #[allow(clippy::erasing_op, clippy::identity_op)]
293 pub const fn pte_idx(&self) -> u64 {
294 (self.0 >> (12 + (9 * 0))) & 0b1_1111_1111
295 }
296
297 /// Get the PDE index of the [`Gva`].
298 ///
299 /// # Examples
300 ///
301 /// ```
302 /// # use kdmp_parser::{Gxa, Gva};
303 /// # fn main() {
304 /// let first = Gva::new(0xff_ff_b9_dc_ee_77_31_37);
305 /// assert_eq!(first.pde_idx(), 371);
306 /// let second = Gva::new(0xff_ff_11_22_33_44_55_66);
307 /// assert_eq!(second.pde_idx(), 0x19a);
308 /// # }
309 /// ```
310 #[allow(clippy::identity_op)]
311 pub const fn pde_idx(&self) -> u64 {
312 (self.0 >> (12 + (9 * 1))) & 0b1_1111_1111
313 }
314
315 /// Get the PDPE offset of the [`Gva`].
316 ///
317 /// # Examples
318 ///
319 /// ```
320 /// # use kdmp_parser::{Gxa, Gva};
321 /// # fn main() {
322 /// let first = Gva::new(0xff_ff_b9_dc_ee_77_31_37);
323 /// assert_eq!(first.pdpe_idx(), 371);
324 /// let second = Gva::new(0xff_ff_11_22_33_44_55_66);
325 /// assert_eq!(second.pdpe_idx(), 0x88);
326 /// # }
327 /// ```
328 pub const fn pdpe_idx(&self) -> u64 {
329 (self.0 >> (12 + (9 * 2))) & 0b1_1111_1111
330 }
331
332 /// Get the PML4 index of the [`Gva`].
333 ///
334 /// # Examples
335 ///
336 /// ```
337 /// # use kdmp_parser::{Gxa, Gva};
338 /// # fn main() {
339 /// let first = Gva::new(0xff_ff_b9_dc_ee_77_31_37);
340 /// assert_eq!(first.pml4e_idx(), 371);
341 /// let second = Gva::new(0xff_ff_11_22_33_44_55_66);
342 /// assert_eq!(second.pml4e_idx(), 0x22);
343 /// # }
344 /// ```
345 pub fn pml4e_idx(&self) -> u64 {
346 (self.0 >> (12 + (9 * 3))) & 0b1_1111_1111
347 }
348}
349
350/// Operator += for [`Gva`].
351impl AddAssign for Gva {
352 fn add_assign(&mut self, rhs: Self) {
353 self.0 += rhs.0
354 }
355}
356
357impl Gxa for Gva {
358 /// Get the underlying `u64`.
359 ///
360 /// # Examples
361 ///
362 /// ```
363 /// # use kdmp_parser::{Gxa, Gva};
364 /// # fn main() {
365 /// let gva = Gva::new(0xdeadbeef);
366 /// assert_eq!(gva.u64(), 0xdeadbeef);
367 /// # }
368 /// ```
369 fn u64(&self) -> u64 {
370 self.0
371 }
372}
373
374/// Convert a [`Gva`] into a [`u64`].
375impl From<u64> for Gva {
376 /// Create a [`Gva`] from a [`u64`].
377 ///
378 /// # Examples
379 ///
380 /// ```
381 /// # use kdmp_parser::{Gxa, Gva};
382 /// # fn main() {
383 /// let gva = Gva::from(0xbaadc0de_deadbeef);
384 /// assert_eq!(u64::from(gva), 0xbaadc0de_deadbeef);
385 /// # }
386 /// ```
387 fn from(value: u64) -> Self {
388 Gva(value)
389 }
390}
391
392/// Convert a [`Gva`] into a [`u64`].
393impl From<Gva> for u64 {
394 /// Create a [`u64`] from a [`Gva`].
395 ///
396 /// # Examples
397 ///
398 /// ```
399 /// # use kdmp_parser::{Gxa, Gva};
400 /// # fn main() {
401 /// let gva = Gva::new(0xbaadc0de_deadbeef);
402 /// let gva_u64: u64 = gva.into();
403 /// assert_eq!(gva_u64, 0xbaadc0de_deadbeef);
404 /// assert_eq!(u64::from(gva), 0xbaadc0de_deadbeef);
405 /// # }
406 /// ```
407 fn from(value: Gva) -> Self {
408 value.0
409 }
410}
411
412/// Convert a [`&Gva`][Gva] into a [`u64`].
413impl From<&Gva> for u64 {
414 /// Create a [`u64`] from a [&Gpa][`Gpa`].
415 ///
416 /// # Examples
417 ///
418 /// ```
419 /// # use kdmp_parser::{Gxa, Gpa};
420 /// # fn main() {
421 /// let gva = Gpa::new(0xbaadc0de_deadbeef);
422 /// let gva_p = &gva;
423 /// let gva_u64: u64 = gva_p.into();
424 /// assert_eq!(gva_u64, 0xbaadc0de_deadbeef);
425 /// assert_eq!(u64::from(gva_p), 0xbaadc0de_deadbeef);
426 /// # }
427 /// ```
428 fn from(value: &Gva) -> Self {
429 value.0
430 }
431}
432
433/// Format [`Gva`] as a string.
434impl Display for Gva {
435 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
436 write!(f, "Gva:{:#x}", self.0)
437 }
438}