kdmp_parser/
pxe.rs

1// Axel '0vercl0k' Souchet - June 5 2023
2//! This defines [`Pxe`] / [`Pfn`] types that makes it easier to manipulate PFNs
3//! and PXEs.
4//!
5//! # Examples
6//!
7//! ```
8//! # use kdmp_parser::pxe::{Pxe, PxeFlags, Pfn};
9//! let pxe = Pxe::new(
10//!     Pfn::new(0x6d600),
11//!     PxeFlags::USER_ACCESSIBLE | PxeFlags::ACCESSED | PxeFlags::PRESENT
12//! );
13//! let encoded = u64::from(pxe);
14//! let decoded = Pxe::from(encoded);
15//! ```
16use std::ops::{BitOr, Deref};
17
18use crate::bits::Bits;
19use crate::gxa::Gpa;
20
21/// The various bits and flags that a [`Pxe`] has.
22#[derive(Debug, Clone, Copy, Eq, Hash, PartialEq, Default, PartialOrd, Ord)]
23pub struct PxeFlags(u64);
24
25impl PxeFlags {
26    pub const ACCESSED: Self = Self(1 << 5);
27    pub const CACHE_DISABLED: Self = Self(1 << 4);
28    pub const DIRTY: Self = Self(1 << 6);
29    pub const LARGE_PAGE: Self = Self(1 << 7);
30    pub const NO_EXECUTE: Self = Self(1 << 63);
31    pub const PRESENT: Self = Self(1 << 0);
32    pub const TRANSITION: Self = Self(1 << 11);
33    pub const USER_ACCESSIBLE: Self = Self(1 << 2);
34    pub const WRITABLE: Self = Self(1 << 1);
35    pub const WRITE_THROUGH: Self = Self(1 << 3);
36
37    #[must_use]
38    pub fn new(bits: u64) -> Self {
39        Self(bits)
40    }
41
42    #[must_use]
43    pub fn present(&self) -> bool {
44        self.0.bit(0) != 0
45    }
46
47    #[must_use]
48    pub fn writable(&self) -> bool {
49        self.0.bit(1) != 0
50    }
51
52    #[must_use]
53    pub fn user_accessible(&self) -> bool {
54        self.0.bit(2) != 0
55    }
56
57    #[must_use]
58    pub fn write_through(&self) -> bool {
59        self.0.bit(3) != 0
60    }
61
62    #[must_use]
63    pub fn cache_disabled(&self) -> bool {
64        self.0.bit(4) != 0
65    }
66
67    #[must_use]
68    pub fn accessed(&self) -> bool {
69        self.0.bit(5) != 0
70    }
71
72    #[must_use]
73    pub fn dirty(&self) -> bool {
74        self.0.bit(6) != 0
75    }
76
77    #[must_use]
78    pub fn large_page(&self) -> bool {
79        self.0.bit(7) != 0
80    }
81
82    #[must_use]
83    pub fn transition(&self) -> bool {
84        self.0.bit(11) != 0
85    }
86
87    #[must_use]
88    pub fn no_execute(&self) -> bool {
89        self.0.bit(63) != 0
90    }
91}
92
93impl BitOr for PxeFlags {
94    type Output = Self;
95
96    fn bitor(self, rhs: Self) -> Self::Output {
97        Self::new(*self | *rhs)
98    }
99}
100
101impl Deref for PxeFlags {
102    type Target = u64;
103
104    fn deref(&self) -> &Self::Target {
105        &self.0
106    }
107}
108
109/// Strong type for a Page Frame Number.
110///
111/// # Examples
112///
113/// ```
114/// # use kdmp_parser::gxa::Gpa;
115/// # use kdmp_parser::pxe::Pfn;
116/// # fn main() {
117/// let pfn = Pfn::new(0x1337);
118/// assert_eq!(pfn.gpa(), Gpa::new(0x1337000));
119/// # }
120/// ```
121#[derive(Debug, Clone, Copy, Eq, Hash, PartialEq, Default, PartialOrd, Ord)]
122pub struct Pfn(u64);
123
124impl Pfn {
125    #[must_use]
126    pub const fn new(pfn: u64) -> Self {
127        Self(pfn)
128    }
129
130    #[must_use]
131    pub const fn u64(&self) -> u64 {
132        self.0
133    }
134
135    #[must_use]
136    pub const fn gpa(&self) -> Gpa {
137        Gpa::from_pfn(*self)
138    }
139
140    #[must_use]
141    pub const fn gpa_with_offset(&self, offset: u64) -> Gpa {
142        Gpa::from_pfn_with_offset(*self, offset)
143    }
144}
145
146impl From<u64> for Pfn {
147    fn from(value: u64) -> Self {
148        Self(value)
149    }
150}
151
152impl From<Pfn> for u64 {
153    fn from(value: Pfn) -> Self {
154        value.u64()
155    }
156}
157
158/// A [`Pxe`] is a set of flags ([`PxeFlags`]) and a Page Frame Number (PFN).
159#[derive(Debug, Clone, Copy, Eq, Hash, PartialEq, Default, PartialOrd, Ord)]
160pub struct Pxe {
161    /// The PFN of the next table or the final page.
162    pub pfn: Pfn,
163    /// PXE flags.
164    pub flags: PxeFlags,
165}
166
167impl Pxe {
168    /// Create a [`Pxe`] from a `pfn` and a set of `flags`.
169    ///
170    /// # Examples
171    ///
172    /// ```
173    /// # use kdmp_parser::pxe::{Pxe, PxeFlags, Pfn};
174    /// # fn main() {
175    /// let pxe = Pxe::new(
176    ///     Pfn::new(0x6d600),
177    ///     PxeFlags::USER_ACCESSIBLE | PxeFlags::ACCESSED | PxeFlags::PRESENT
178    /// );
179    /// assert_eq!(pxe.pfn.u64(), 0x6d600);
180    /// # }
181    /// ```
182    #[must_use]
183    pub fn new(pfn: Pfn, flags: PxeFlags) -> Self {
184        Self { pfn, flags }
185    }
186
187    /// Is the bit Present/Valid turned on?
188    ///
189    /// # Examples
190    ///
191    /// ```
192    /// # use kdmp_parser::pxe::{Pxe, PxeFlags, Pfn};
193    /// # fn main() {
194    /// let p = Pxe::new(
195    ///     Pfn::new(0x6d600),
196    ///     PxeFlags::PRESENT
197    /// );
198    /// assert!(p.present());
199    /// let np = Pxe::new(
200    ///     Pfn::new(0x1337),
201    ///     PxeFlags::USER_ACCESSIBLE
202    /// );
203    /// assert!(!np.present());
204    /// # }
205    /// ```
206    #[must_use]
207    pub fn present(&self) -> bool {
208        self.flags.present()
209    }
210
211    /// Is it a large page?
212    ///
213    /// # Examples
214    ///
215    /// ```
216    /// # use kdmp_parser::pxe::{Pxe, PxeFlags, Pfn};
217    /// # fn main() {
218    /// let p = Pxe::new(
219    ///     Pfn::new(0x6d600),
220    ///     PxeFlags::LARGE_PAGE
221    /// );
222    /// assert!(p.large_page());
223    /// let np = Pxe::new(
224    ///     Pfn::new(0x1337),
225    ///     PxeFlags::USER_ACCESSIBLE
226    /// );
227    /// assert!(!np.large_page());
228    /// # }
229    /// ```
230    #[must_use]
231    pub fn large_page(&self) -> bool {
232        self.flags.large_page()
233    }
234
235    /// Is it a transition PTE?
236    ///
237    /// # Examples
238    ///
239    /// ```
240    /// # use kdmp_parser::pxe::{Pxe, PxeFlags, Pfn};
241    /// # fn main() {
242    /// let p = Pxe::from(0x166B7880);
243    /// let np = Pxe::from(0xA000000077AF867);
244    /// assert!(p.transition());
245    /// assert!(!np.transition());
246    /// # }
247    /// ```
248    #[must_use]
249    pub fn transition(&self) -> bool {
250        !self.present() && self.flags.transition()
251    }
252
253    /// Is the memory described by this [`Pxe`] writable?
254    ///
255    /// # Examples
256    ///
257    /// ```
258    /// # use kdmp_parser::pxe::{Pxe, PxeFlags, Pfn};
259    /// # fn main() {
260    /// let w = Pxe::from(0x2709063);
261    /// let ro = Pxe::from(0x8A00000002C001A1);
262    /// assert!(w.writable());
263    /// assert!(!ro.writable());
264    /// # }
265    /// ```
266    #[must_use]
267    pub fn writable(&self) -> bool {
268        self.flags.writable()
269    }
270
271    /// Is the memory described by this [`Pxe`] executable?
272    ///
273    /// # Examples
274    ///
275    /// ```
276    /// # use kdmp_parser::pxe::{Pxe, PxeFlags, Pfn};
277    /// # fn main() {
278    /// let x = Pxe::from(0x270a063);
279    /// let nx = Pxe::from(0x8A00000002C001A1);
280    /// assert!(x.executable());
281    /// assert!(!nx.executable());
282    /// # }
283    /// ```
284    #[must_use]
285    pub fn executable(&self) -> bool {
286        !self.flags.no_execute()
287    }
288
289    /// Is the memory described by this [`Pxe`] accessible by user-mode?
290    ///
291    /// # Examples
292    ///
293    /// ```
294    /// # use kdmp_parser::pxe::{Pxe, PxeFlags, Pfn};
295    /// # fn main() {
296    /// let u = Pxe::from(0x8000000F34E5025);
297    /// let s = Pxe::from(0x270A063);
298    /// assert!(u.user_accessible());
299    /// assert!(!s.user_accessible());
300    /// # }
301    /// ```
302    #[must_use]
303    pub fn user_accessible(&self) -> bool {
304        self.flags.user_accessible()
305    }
306}
307
308/// Convert a [`u64`] into a [`Pxe`].
309impl From<u64> for Pxe {
310    /// Create a [`u64`] from a [`Pxe`].
311    ///
312    /// # Examples
313    ///
314    /// ```
315    /// # use kdmp_parser::pxe::{Pxe, PxeFlags, Pfn};
316    /// # fn main() {
317    /// let pxe = Pxe::from(0x6D_60_00_25);
318    /// assert_eq!(pxe.pfn.u64(), 0x6d600);
319    /// assert_eq!(pxe.flags, PxeFlags::USER_ACCESSIBLE | PxeFlags::ACCESSED | PxeFlags::PRESENT);
320    /// # }
321    /// ```
322    fn from(value: u64) -> Self {
323        const PFN_MASK: u64 = 0xffff_ffff_f000;
324        const FLAGS_MASK: u64 = !PFN_MASK;
325        let pfn = Pfn::new((value & PFN_MASK) >> 12);
326        let flags = PxeFlags::new(value & FLAGS_MASK);
327
328        Self::new(pfn, flags)
329    }
330}
331
332/// Convert a [`Pxe`] into a [`u64`].
333impl From<Pxe> for u64 {
334    /// Create a [`u64`] from a [`Pxe`].
335    ///
336    /// # Examples
337    ///
338    /// ```
339    /// # use kdmp_parser::pxe::{Pxe, PxeFlags, Pfn};
340    /// # fn main() {
341    /// let pxe = Pxe::new(
342    ///     Pfn::new(0x6d600),
343    ///     PxeFlags::USER_ACCESSIBLE | PxeFlags::ACCESSED | PxeFlags::PRESENT,
344    /// );
345    /// assert_eq!(u64::from(pxe), 0x6D_60_00_25);
346    /// # }
347    /// ```
348    fn from(pxe: Pxe) -> Self {
349        debug_assert!(pxe.pfn.u64() <= 0xf_ffff_ffffu64);
350
351        *pxe.flags | (pxe.pfn.u64() << 12u64)
352    }
353}