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}