vmi_arch_amd64/
paging.rs

1use zerocopy::{FromBytes, Immutable, IntoBytes, KnownLayout};
2
3use crate::Gfn;
4
5/// Supported paging modes.
6#[derive(Debug, Clone, Copy, PartialEq, Eq)]
7pub enum PagingMode {
8    /// 32-bit paging (4KB pages).
9    Legacy,
10
11    /// Physical Address Extension (allows 64GB of physical memory to be
12    /// addressed by 32-bit systems).
13    PAE,
14
15    /// 64-bit paging (4-level paging).
16    Ia32e,
17
18    /// 64-bit paging with 5-level paging (allows for 57-bit linear addresses).
19    Ia32eLA57,
20}
21
22impl PagingMode {
23    /// Returns the address width (i.e. pointer size) of the paging mode in
24    /// bytes.
25    pub fn address_width(self) -> usize {
26        match self {
27            Self::Legacy => 4,
28            Self::PAE => 4,
29            Self::Ia32e => 8,
30            Self::Ia32eLA57 => 8,
31        }
32    }
33}
34
35/// The levels in the page table hierarchy.
36#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
37#[repr(u8)]
38pub enum PageTableLevel {
39    /// Page Table (PT) - the lowest level, pointing directly to 4KB pages.
40    Pt,
41
42    /// Page Directory (PD) - can point to PTs or 2MB large pages.
43    Pd,
44
45    /// Page Directory Pointer Table (PDPT) - can point to PDs or 1GB large.
46    /// pages
47    Pdpt,
48
49    /// Page Map Level 4 (PML4) - the highest level in 4-level paging.
50    Pml4,
51}
52
53impl PageTableLevel {
54    /// Returns the next lower level in the page table hierarchy.
55    pub fn next(self) -> Option<Self> {
56        match self {
57            Self::Pt => None,
58            Self::Pd => Some(Self::Pt),
59            Self::Pdpt => Some(Self::Pd),
60            Self::Pml4 => Some(Self::Pdpt),
61        }
62    }
63
64    /// Returns the next higher level in the page table hierarchy.
65    pub fn previous(self) -> Option<Self> {
66        match self {
67            Self::Pt => Some(Self::Pd),
68            Self::Pd => Some(Self::Pdpt),
69            Self::Pdpt => Some(Self::Pml4),
70            Self::Pml4 => None,
71        }
72    }
73}
74
75/// A page table entry in the paging structures.
76#[repr(transparent)]
77#[derive(Default, Clone, Copy, PartialEq, Eq, FromBytes, IntoBytes, Immutable, KnownLayout)]
78pub struct PageTableEntry(pub u64);
79
80impl PageTableEntry {
81    /// Checks if the page is present in physical memory.
82    pub fn present(self) -> bool {
83        self.0 & 1 != 0
84    }
85
86    /// Checks if the page is writable.
87    pub fn write(self) -> bool {
88        (self.0 >> 1) & 1 != 0
89    }
90
91    /// Checks if the page is accessible in user mode.
92    /// Note: Returns true for user mode, false for supervisor mode.
93    pub fn supervisor(self) -> bool {
94        (self.0 >> 2) & 1 != 0
95    }
96
97    /// Checks if write-through caching is enabled for the page.
98    pub fn page_level_write_through(self) -> bool {
99        (self.0 >> 3) & 1 != 0
100    }
101
102    /// Checks if caching is disabled for the page.
103    pub fn page_level_cache_disable(self) -> bool {
104        (self.0 >> 4) & 1 != 0
105    }
106
107    /// Checks if the page has been accessed.
108    pub fn accessed(self) -> bool {
109        (self.0 >> 5) & 1 != 0
110    }
111
112    /// Checks if the page has been written to.
113    pub fn dirty(self) -> bool {
114        (self.0 >> 6) & 1 != 0
115    }
116
117    /// Checks if this entry refers to a large page.
118    pub fn large(self) -> bool {
119        (self.0 >> 7) & 1 != 0
120    }
121
122    /// Checks if the page is global (shared between all processes).
123    pub fn global(self) -> bool {
124        (self.0 >> 8) & 1 != 0
125    }
126
127    /// Extracts the page frame number from the entry.
128    pub fn pfn(self) -> Gfn {
129        const BITS: u64 = 40;
130        const MASK: u64 = (1 << BITS) - 1;
131        Gfn::new((self.0 >> 12) & MASK)
132    }
133}
134
135impl std::fmt::Debug for PageTableEntry {
136    fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
137        f.debug_struct("PageTableEntry")
138            .field("present", &self.present())
139            .field("write", &self.write())
140            .field("supervisor", &self.supervisor())
141            .field("page_level_write_through", &self.page_level_write_through())
142            .field("page_level_cache_disable", &self.page_level_cache_disable())
143            .field("accessed", &self.accessed())
144            .field("dirty", &self.dirty())
145            .field("large", &self.large())
146            .field("global", &self.global())
147            .field("pfn", &self.pfn())
148            .finish()
149    }
150}