page_table_entry/arch/
x86_64.rs

1//! x86 page table entries on 64-bit paging.
2
3use core::fmt;
4
5use memory_addr::PhysAddr;
6pub use x86_64::structures::paging::page_table::PageTableFlags as PTF;
7
8use crate::{GenericPTE, MappingFlags};
9
10impl From<PTF> for MappingFlags {
11    fn from(f: PTF) -> Self {
12        if !f.contains(PTF::PRESENT) {
13            return Self::empty();
14        }
15        let mut ret = Self::READ;
16        if f.contains(PTF::WRITABLE) {
17            ret |= Self::WRITE;
18        }
19        if !f.contains(PTF::NO_EXECUTE) {
20            ret |= Self::EXECUTE;
21        }
22        if f.contains(PTF::USER_ACCESSIBLE) {
23            ret |= Self::USER;
24        }
25        if f.contains(PTF::NO_CACHE) {
26            ret |= Self::UNCACHED;
27        }
28        ret
29    }
30}
31
32impl From<MappingFlags> for PTF {
33    fn from(f: MappingFlags) -> Self {
34        if f.is_empty() {
35            return Self::empty();
36        }
37        let mut ret = Self::PRESENT;
38        if f.contains(MappingFlags::WRITE) {
39            ret |= Self::WRITABLE;
40        }
41        if !f.contains(MappingFlags::EXECUTE) {
42            ret |= Self::NO_EXECUTE;
43        }
44        if f.contains(MappingFlags::USER) {
45            ret |= Self::USER_ACCESSIBLE;
46        }
47        if f.contains(MappingFlags::DEVICE) || f.contains(MappingFlags::UNCACHED) {
48            ret |= Self::NO_CACHE | Self::WRITE_THROUGH;
49        }
50        ret
51    }
52}
53
54/// An x86_64 page table entry.
55#[derive(Clone, Copy)]
56#[repr(transparent)]
57pub struct X64PTE(u64);
58
59impl X64PTE {
60    // bits 12..52
61    const PHYS_ADDR_MASK: u64 = 0x000f_ffff_ffff_f000;
62
63    /// Creates an empty descriptor with all bits set to zero.
64    pub const fn empty() -> Self {
65        Self(0)
66    }
67}
68
69impl GenericPTE for X64PTE {
70    fn new_page(paddr: PhysAddr, flags: MappingFlags, is_huge: bool) -> Self {
71        let mut flags = PTF::from(flags);
72        if is_huge {
73            flags |= PTF::HUGE_PAGE;
74        }
75        Self(flags.bits() | (paddr.as_usize() as u64 & Self::PHYS_ADDR_MASK))
76    }
77
78    fn new_table(paddr: PhysAddr) -> Self {
79        let flags = PTF::PRESENT | PTF::WRITABLE | PTF::USER_ACCESSIBLE;
80        Self(flags.bits() | (paddr.as_usize() as u64 & Self::PHYS_ADDR_MASK))
81    }
82
83    fn paddr(&self) -> PhysAddr {
84        PhysAddr::from((self.0 & Self::PHYS_ADDR_MASK) as usize)
85    }
86
87    fn flags(&self) -> MappingFlags {
88        PTF::from_bits_truncate(self.0).into()
89    }
90
91    fn set_paddr(&mut self, paddr: PhysAddr) {
92        self.0 = (self.0 & !Self::PHYS_ADDR_MASK) | (paddr.as_usize() as u64 & Self::PHYS_ADDR_MASK)
93    }
94
95    fn set_flags(&mut self, flags: MappingFlags, is_huge: bool) {
96        let mut flags = PTF::from(flags);
97        if is_huge {
98            flags |= PTF::HUGE_PAGE;
99        }
100        self.0 = (self.0 & Self::PHYS_ADDR_MASK) | flags.bits()
101    }
102
103    fn bits(self) -> usize {
104        self.0 as usize
105    }
106
107    fn is_unused(&self) -> bool {
108        self.0 == 0
109    }
110
111    fn is_present(&self) -> bool {
112        PTF::from_bits_truncate(self.0).contains(PTF::PRESENT)
113    }
114
115    fn is_huge(&self) -> bool {
116        PTF::from_bits_truncate(self.0).contains(PTF::HUGE_PAGE)
117    }
118
119    fn clear(&mut self) {
120        self.0 = 0
121    }
122}
123
124impl fmt::Debug for X64PTE {
125    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
126        let mut f = f.debug_struct("X64PTE");
127        f.field("raw", &self.0)
128            .field("paddr", &self.paddr())
129            .field("flags", &self.flags())
130            .finish()
131    }
132}