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}