x86_64/structures/paging/
page_table.rs1use core::fmt;
4#[cfg(feature = "step_trait")]
5use core::iter::Step;
6use core::ops::{Index, IndexMut};
7#[cfg(feature = "memory_encryption")]
8use core::sync::atomic::{AtomicU64, Ordering};
9
10use super::{PageSize, PhysFrame, Size4KiB};
11use crate::addr::PhysAddr;
12
13use bitflags::bitflags;
14use dep_const_fn::const_fn;
15
16#[derive(Debug, Clone, Copy, PartialEq)]
18pub enum FrameError {
19 FrameNotPresent,
21 HugeFrame,
24}
25
26#[cfg(feature = "memory_encryption")]
28pub(crate) static PHYSICAL_ADDRESS_MASK: AtomicU64 = AtomicU64::new(0x000f_ffff_ffff_f000u64);
29
30#[derive(Clone)]
32#[repr(transparent)]
33pub struct PageTableEntry {
34 entry: u64,
35}
36
37impl PageTableEntry {
38 #[inline]
40 pub const fn new() -> Self {
41 PageTableEntry { entry: 0 }
42 }
43
44 #[inline]
46 pub const fn is_unused(&self) -> bool {
47 self.entry == 0
48 }
49
50 #[inline]
52 pub fn set_unused(&mut self) {
53 self.entry = 0;
54 }
55
56 #[inline]
58 #[const_fn(cfg(not(feature = "memory_encryption")))]
59 pub const fn flags(&self) -> PageTableFlags {
60 PageTableFlags::from_bits_retain(self.entry & !Self::physical_address_mask())
61 }
62
63 #[inline]
65 pub fn addr(&self) -> PhysAddr {
66 PhysAddr::new(self.entry & Self::physical_address_mask())
67 }
68
69 #[inline]
77 pub fn frame(&self) -> Result<PhysFrame, FrameError> {
78 if !self.flags().contains(PageTableFlags::PRESENT) {
79 Err(FrameError::FrameNotPresent)
80 } else if self.flags().contains(PageTableFlags::HUGE_PAGE) {
81 Err(FrameError::HugeFrame)
82 } else {
83 Ok(PhysFrame::containing_address(self.addr()))
84 }
85 }
86
87 #[inline]
89 pub fn set_addr(&mut self, addr: PhysAddr, flags: PageTableFlags) {
90 assert!(addr.is_aligned(Size4KiB::SIZE));
91 self.entry = (addr.as_u64()) | flags.bits();
92 }
93
94 #[inline]
96 pub fn set_frame(&mut self, frame: PhysFrame, flags: PageTableFlags) {
97 assert!(!flags.contains(PageTableFlags::HUGE_PAGE));
98 self.set_addr(frame.start_address(), flags)
99 }
100
101 #[inline]
103 pub fn set_flags(&mut self, flags: PageTableFlags) {
104 self.entry = self.addr().as_u64() | flags.bits();
105 }
106
107 #[inline(always)]
108 #[cfg(not(feature = "memory_encryption"))]
109 const fn physical_address_mask() -> u64 {
110 0x000f_ffff_ffff_f000u64
111 }
112
113 #[inline(always)]
114 #[cfg(feature = "memory_encryption")]
115 fn physical_address_mask() -> u64 {
116 PHYSICAL_ADDRESS_MASK.load(Ordering::Relaxed)
117 }
118}
119
120impl Default for PageTableEntry {
121 #[inline]
122 fn default() -> Self {
123 Self::new()
124 }
125}
126
127impl fmt::Debug for PageTableEntry {
128 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
129 let mut f = f.debug_struct("PageTableEntry");
130 f.field("addr", &self.addr());
131 f.field("flags", &self.flags());
132 f.finish()
133 }
134}
135
136bitflags! {
137 #[derive(PartialEq, Eq, PartialOrd, Ord, Hash, Debug, Clone, Copy)]
139 pub struct PageTableFlags: u64 {
140 const PRESENT = 1;
142 const WRITABLE = 1 << 1;
148 const USER_ACCESSIBLE = 1 << 2;
150 const WRITE_THROUGH = 1 << 3;
153 const NO_CACHE = 1 << 4;
155 const ACCESSED = 1 << 5;
157 const DIRTY = 1 << 6;
159 const HUGE_PAGE = 1 << 7;
162 const GLOBAL = 1 << 8;
165 const BIT_9 = 1 << 9;
167 const BIT_10 = 1 << 10;
169 const BIT_11 = 1 << 11;
171 const BIT_52 = 1 << 52;
173 const BIT_53 = 1 << 53;
175 const BIT_54 = 1 << 54;
177 const BIT_55 = 1 << 55;
179 const BIT_56 = 1 << 56;
181 const BIT_57 = 1 << 57;
183 const BIT_58 = 1 << 58;
185 const BIT_59 = 1 << 59;
187 const BIT_60 = 1 << 60;
189 const BIT_61 = 1 << 61;
191 const BIT_62 = 1 << 62;
193 const NO_EXECUTE = 1 << 63;
198 }
199}
200
201const ENTRY_COUNT: usize = 512;
203
204#[repr(align(4096))]
214#[repr(C)]
215#[derive(Clone)]
216pub struct PageTable {
217 entries: [PageTableEntry; ENTRY_COUNT],
218}
219
220impl PageTable {
221 #[inline]
223 pub const fn new() -> Self {
224 const EMPTY: PageTableEntry = PageTableEntry::new();
225 PageTable {
226 entries: [EMPTY; ENTRY_COUNT],
227 }
228 }
229
230 #[inline]
232 pub fn zero(&mut self) {
233 for entry in self.iter_mut() {
234 entry.set_unused();
235 }
236 }
237
238 #[inline]
240 pub fn iter(&self) -> impl Iterator<Item = &PageTableEntry> {
241 (0..512).map(move |i| &self.entries[i])
242 }
243
244 #[inline]
246 pub fn iter_mut(&mut self) -> impl Iterator<Item = &mut PageTableEntry> {
247 let ptr = self.entries.as_mut_ptr();
262 (0..512).map(move |i| unsafe { &mut *ptr.add(i) })
263 }
264
265 #[inline]
267 pub fn is_empty(&self) -> bool {
268 self.iter().all(|entry| entry.is_unused())
269 }
270}
271
272impl Index<usize> for PageTable {
273 type Output = PageTableEntry;
274
275 #[inline]
276 fn index(&self, index: usize) -> &Self::Output {
277 &self.entries[index]
278 }
279}
280
281impl IndexMut<usize> for PageTable {
282 #[inline]
283 fn index_mut(&mut self, index: usize) -> &mut Self::Output {
284 &mut self.entries[index]
285 }
286}
287
288impl Index<PageTableIndex> for PageTable {
289 type Output = PageTableEntry;
290
291 #[inline]
292 fn index(&self, index: PageTableIndex) -> &Self::Output {
293 &self.entries[usize::from(index)]
294 }
295}
296
297impl IndexMut<PageTableIndex> for PageTable {
298 #[inline]
299 fn index_mut(&mut self, index: PageTableIndex) -> &mut Self::Output {
300 &mut self.entries[usize::from(index)]
301 }
302}
303
304impl Default for PageTable {
305 fn default() -> Self {
306 Self::new()
307 }
308}
309
310impl fmt::Debug for PageTable {
311 #[inline]
312 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
313 self.entries[..].fmt(f)
314 }
315}
316
317#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
323pub struct PageTableIndex(u16);
324
325impl PageTableIndex {
326 #[inline]
328 pub const fn new(index: u16) -> Self {
329 assert!((index as usize) < ENTRY_COUNT);
330 Self(index)
331 }
332
333 #[inline]
335 pub const fn new_truncate(index: u16) -> Self {
336 Self(index % ENTRY_COUNT as u16)
337 }
338
339 #[inline]
340 pub(crate) const fn into_u64(self) -> u64 {
341 self.0 as u64
342 }
343}
344
345impl From<PageTableIndex> for u16 {
346 #[inline]
347 fn from(index: PageTableIndex) -> Self {
348 index.0
349 }
350}
351
352impl From<PageTableIndex> for u32 {
353 #[inline]
354 fn from(index: PageTableIndex) -> Self {
355 u32::from(index.0)
356 }
357}
358
359impl From<PageTableIndex> for u64 {
360 #[inline]
361 fn from(index: PageTableIndex) -> Self {
362 index.into_u64()
363 }
364}
365
366impl From<PageTableIndex> for usize {
367 #[inline]
368 fn from(index: PageTableIndex) -> Self {
369 usize::from(index.0)
370 }
371}
372
373#[cfg(feature = "step_trait")]
374impl Step for PageTableIndex {
375 #[inline]
376 fn steps_between(start: &Self, end: &Self) -> (usize, Option<usize>) {
377 Step::steps_between(&start.0, &end.0)
378 }
379
380 #[inline]
381 fn forward_checked(start: Self, count: usize) -> Option<Self> {
382 let idx = usize::from(start).checked_add(count)?;
383 (idx < ENTRY_COUNT).then(|| Self::new(idx as u16))
384 }
385
386 #[inline]
387 fn backward_checked(start: Self, count: usize) -> Option<Self> {
388 let idx = usize::from(start).checked_sub(count)?;
389 Some(Self::new(idx as u16))
390 }
391}
392
393#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
399pub struct PageOffset(u16);
400
401impl PageOffset {
402 #[inline]
404 pub fn new(offset: u16) -> Self {
405 assert!(offset < (1 << 12));
406 Self(offset)
407 }
408
409 #[inline]
411 pub const fn new_truncate(offset: u16) -> Self {
412 Self(offset % (1 << 12))
413 }
414}
415
416impl From<PageOffset> for u16 {
417 #[inline]
418 fn from(offset: PageOffset) -> Self {
419 offset.0
420 }
421}
422
423impl From<PageOffset> for u32 {
424 #[inline]
425 fn from(offset: PageOffset) -> Self {
426 u32::from(offset.0)
427 }
428}
429
430impl From<PageOffset> for u64 {
431 #[inline]
432 fn from(offset: PageOffset) -> Self {
433 u64::from(offset.0)
434 }
435}
436
437impl From<PageOffset> for usize {
438 #[inline]
439 fn from(offset: PageOffset) -> Self {
440 usize::from(offset.0)
441 }
442}
443
444#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
445pub enum PageTableLevel {
447 One = 1,
449 Two,
451 Three,
453 Four,
455}
456
457impl PageTableLevel {
458 pub const fn next_lower_level(self) -> Option<Self> {
460 match self {
461 PageTableLevel::Four => Some(PageTableLevel::Three),
462 PageTableLevel::Three => Some(PageTableLevel::Two),
463 PageTableLevel::Two => Some(PageTableLevel::One),
464 PageTableLevel::One => None,
465 }
466 }
467
468 pub const fn next_higher_level(self) -> Option<Self> {
470 match self {
471 PageTableLevel::Four => None,
472 PageTableLevel::Three => Some(PageTableLevel::Four),
473 PageTableLevel::Two => Some(PageTableLevel::Three),
474 PageTableLevel::One => Some(PageTableLevel::Two),
475 }
476 }
477
478 pub const fn table_address_space_alignment(self) -> u64 {
480 1u64 << (self as u8 * 9 + 12)
481 }
482
483 pub const fn entry_address_space_alignment(self) -> u64 {
485 1u64 << (((self as u8 - 1) * 9) + 12)
486 }
487}