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, PxeFlags, Pfn};
9//! let pxe = Pxe::new(
10//!     Pfn::new(0x6d600),
11//!     PxeFlags::UserAccessible | PxeFlags::Accessed | PxeFlags::Present
12//! );
13//! let encoded = u64::from(pxe);
14//! let decoded = Pxe::from(encoded);
15//! ```
16use bitflags::bitflags;
17
18use crate::Gpa;
19
20bitflags! {
21    /// The various bits and flags that a [`Pxe`] has.
22    #[derive(Debug, Clone, Copy, Eq, Hash, PartialEq, Default, PartialOrd, Ord)]
23    pub struct PxeFlags : u64 {
24        const Present = 1 << 0;
25        const Writable = 1 << 1;
26        const UserAccessible = 1 << 2;
27        const WriteThrough = 1 << 3;
28        const CacheDisabled = 1 << 4;
29        const Accessed = 1 << 5;
30        const Dirty = 1 << 6;
31        const LargePage = 1 << 7;
32        const Transition = 1 << 11;
33        const NoExecute = 1 << 63;
34    }
35}
36
37/// Strong type for a Page Frame Number.
38///
39/// # Examples
40///
41/// ```
42/// # use kdmp_parser::{Pfn, Gpa};
43/// # fn main() {
44/// let pfn = Pfn::new(0x1337);
45/// assert_eq!(pfn.gpa(), Gpa::new(0x1337000));
46/// # }
47/// ```
48#[derive(Debug, Clone, Copy, Eq, Hash, PartialEq, Default, PartialOrd, Ord)]
49pub struct Pfn(u64);
50
51impl Pfn {
52    pub const fn new(pfn: u64) -> Self {
53        Self(pfn)
54    }
55
56    pub const fn u64(&self) -> u64 {
57        self.0
58    }
59
60    pub const fn gpa(&self) -> Gpa {
61        Gpa::from_pfn(*self)
62    }
63
64    pub const fn gpa_with_offset(&self, offset: u64) -> Gpa {
65        Gpa::from_pfn_with_offset(*self, offset)
66    }
67}
68
69impl From<u64> for Pfn {
70    fn from(value: u64) -> Self {
71        Self(value)
72    }
73}
74
75impl From<Pfn> for u64 {
76    fn from(value: Pfn) -> Self {
77        value.u64()
78    }
79}
80
81/// A [`Pxe`] is a set of flags ([`PxeFlags`]) and a Page Frame Number (PFN).
82/// This representation takes more space than a regular `PXE` but it is more
83/// convenient to split the flags / the pfn as [`bitflags!`] doesn't seem to
84/// support bitfields.
85#[derive(Debug, Clone, Copy, Eq, Hash, PartialEq, Default, PartialOrd, Ord)]
86pub struct Pxe {
87    /// The PFN of the next table or the final page.
88    pub pfn: Pfn,
89    /// PXE flags.
90    pub flags: PxeFlags,
91}
92
93impl Pxe {
94    /// Create a [`Pxe`] from a `pfn` and a set of `flags`.
95    ///
96    /// # Examples
97    ///
98    /// ```
99    /// # use kdmp_parser::{Pxe, PxeFlags, Pfn};
100    /// # fn main() {
101    /// let pxe = Pxe::new(
102    ///     Pfn::new(0x6d600),
103    ///     PxeFlags::UserAccessible | PxeFlags::Accessed | PxeFlags::Present
104    /// );
105    /// assert_eq!(pxe.pfn.u64(), 0x6d600);
106    /// # }
107    /// ```
108    pub fn new(pfn: Pfn, flags: PxeFlags) -> Self {
109        Self { pfn, flags }
110    }
111
112    /// Is the bit Present/Valid turned on?
113    ///
114    /// # Examples
115    ///
116    /// ```
117    /// # use kdmp_parser::{Pxe, PxeFlags, Pfn};
118    /// # fn main() {
119    /// let p = Pxe::new(
120    ///     Pfn::new(0x6d600),
121    ///     PxeFlags::Present
122    /// );
123    /// assert!(p.present());
124    /// let np = Pxe::new(
125    ///     Pfn::new(0x1337),
126    ///     PxeFlags::UserAccessible
127    /// );
128    /// assert!(!np.present());
129    /// # }
130    /// ```
131    pub fn present(&self) -> bool {
132        self.flags.contains(PxeFlags::Present)
133    }
134
135    /// Is it a large page?
136    ///
137    /// # Examples
138    ///
139    /// ```
140    /// # use kdmp_parser::{Pxe, PxeFlags, Pfn};
141    /// # fn main() {
142    /// let p = Pxe::new(
143    ///     Pfn::new(0x6d600),
144    ///     PxeFlags::LargePage
145    /// );
146    /// assert!(p.large_page());
147    /// let np = Pxe::new(
148    ///     Pfn::new(0x1337),
149    ///     PxeFlags::UserAccessible
150    /// );
151    /// assert!(!np.large_page());
152    /// # }
153    /// ```
154    pub fn large_page(&self) -> bool {
155        self.flags.contains(PxeFlags::LargePage)
156    }
157
158    /// Is it a transition PTE?
159    ///
160    /// # Examples
161    ///
162    /// ```
163    /// # use kdmp_parser::{Pxe, PxeFlags, Pfn};
164    /// # fn main() {
165    /// let p = Pxe::from(0x166B7880);
166    /// let np = Pxe::from(0xA000000077AF867);
167    /// assert!(p.transition());
168    /// assert!(!np.transition());
169    /// # }
170    /// ```
171    pub fn transition(&self) -> bool {
172        !self.present() && self.flags.contains(PxeFlags::Transition)
173    }
174
175    /// Is the memory described by this [`Pxe`] writable?
176    ///
177    /// # Examples
178    ///
179    /// ```
180    /// # use kdmp_parser::{Pxe, PxeFlags, Pfn};
181    /// # fn main() {
182    /// let w = Pxe::from(0x2709063);
183    /// let ro = Pxe::from(0x8A00000002C001A1);
184    /// assert!(w.writable());
185    /// assert!(!ro.writable());
186    /// # }
187    /// ```
188    pub fn writable(&self) -> bool {
189        self.flags.contains(PxeFlags::Writable)
190    }
191
192    /// Is the memory described by this [`Pxe`] executable?
193    ///
194    /// # Examples
195    ///
196    /// ```
197    /// # use kdmp_parser::{Pxe, PxeFlags, Pfn};
198    /// # fn main() {
199    /// let x = Pxe::from(0x270a063);
200    /// let nx = Pxe::from(0x8A00000002C001A1);
201    /// assert!(x.executable());
202    /// assert!(!nx.executable());
203    /// # }
204    /// ```
205    pub fn executable(&self) -> bool {
206        !self.flags.contains(PxeFlags::NoExecute)
207    }
208
209    /// Is the memory described by this [`Pxe`] accessible by user-mode?
210    ///
211    /// # Examples
212    ///
213    /// ```
214    /// # use kdmp_parser::{Pxe, PxeFlags, Pfn};
215    /// # fn main() {
216    /// let u = Pxe::from(0x8000000F34E5025);
217    /// let s = Pxe::from(0x270A063);
218    /// assert!(u.user_accessible());
219    /// assert!(!s.user_accessible());
220    /// # }
221    /// ```
222    pub fn user_accessible(&self) -> bool {
223        self.flags.contains(PxeFlags::UserAccessible)
224    }
225}
226
227/// Convert a [`u64`] into a [`Pxe`].
228impl From<u64> for Pxe {
229    /// Create a [`u64`] from a [`Pxe`].
230    ///
231    /// # Examples
232    ///
233    /// ```
234    /// # use kdmp_parser::{Pxe, PxeFlags, Pfn};
235    /// # fn main() {
236    /// let pxe = Pxe::from(0x6D_60_00_25);
237    /// assert_eq!(pxe.pfn.u64(), 0x6d600);
238    /// assert_eq!(pxe.flags, PxeFlags::UserAccessible | PxeFlags::Accessed | PxeFlags::Present);
239    /// # }
240    /// ```
241    fn from(value: u64) -> Self {
242        let pfn = Pfn::new((value >> 12) & 0xf_ffff_ffff);
243        let flags = PxeFlags::from_bits(value & PxeFlags::all().bits()).expect("PxeFlags");
244
245        Self::new(pfn, flags)
246    }
247}
248
249/// Convert a [`Pxe`] into a [`u64`].
250impl From<Pxe> for u64 {
251    /// Create a [`u64`] from a [`Pxe`].
252    ///
253    /// # Examples
254    ///
255    /// ```
256    /// # use kdmp_parser::{Pxe, PxeFlags, Pfn};
257    /// # fn main() {
258    /// let pxe = Pxe::new(
259    ///     Pfn::new(0x6d600),
260    ///     PxeFlags::UserAccessible | PxeFlags::Accessed | PxeFlags::Present,
261    /// );
262    /// assert_eq!(u64::from(pxe), 0x6D_60_00_25);
263    /// # }
264    /// ```
265    fn from(pxe: Pxe) -> Self {
266        debug_assert!(pxe.pfn.u64() <= 0xf_ffff_ffffu64);
267
268        pxe.flags.bits() | (pxe.pfn.u64() << 12u64)
269    }
270}