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}