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}