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