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