rustubs/arch/x86_64/paging/pagetable.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
//! basic paging support. code derived from the
//! [x86_64 crate](https://docs.rs/x86_64/latest/src/x86_64/addr.rs.html)
use bitflags::bitflags;
#[repr(align(4096))]
#[repr(C)]
#[derive(Clone)]
pub struct Pagetable {
pub entries: [PTE; Self::ENTRY_COUNT],
}
#[derive(Clone)]
#[repr(transparent)]
pub struct PTE {
pub entry: u64,
}
bitflags! {
#[derive(Debug, Copy, Clone)]
pub struct PTEFlags:u64 {
const ZERO = 0;
const PRESENT = 1 << 0;
const WRITABLE = 1 << 1;
const USER = 1 << 2;
const WT = 1 << 3;
const NC = 1 << 4;
const ACCESSED = 1 << 5;
const DIRTY = 1 << 6;
const HUGE_PAGE = 1 << 7;
const GLOBAL = 1 << 8;
const B9 = 1 << 9;
const B10 = 1 << 10;
const B11 = 1 << 11;
// [51:12] is used for translation address
// [62:52] are user defined.
// [63] NO_EXECUTE, needs to be enabled in EFER.
const NE = 1 << 63;
}
}
impl Pagetable {
const ENTRY_COUNT: usize = 512;
/// Creates an empty page table.
#[inline]
pub const fn new() -> Self {
const EMPTY: PTE = PTE::new();
Pagetable { entries: [EMPTY; Self::ENTRY_COUNT] }
}
/// Clears all entries.
#[inline]
pub fn zero(&mut self) {
for entry in self.iter_mut() {
entry.set_unused();
}
}
/// Returns an iterator over the entries of the page table.
#[inline]
pub fn iter(&self) -> impl Iterator<Item = &PTE> {
(0..512).map(move |i| &self.entries[i])
}
/// Returns an iterator that allows modifying the entries of the page table.
#[inline]
pub fn iter_mut(&mut self) -> impl Iterator<Item = &mut PTE> {
// Note that we intentionally don't just return `self.entries.iter()`:
// Some users may choose to create a reference to a page table at
// `0xffff_ffff_ffff_f000`. This causes problems because calculating
// the end pointer of the page tables causes an overflow. Therefore
// creating page tables at that address is unsound and must be avoided.
// Unfortunately creating such page tables is quite common when
// recursive page tables are used, so we try to avoid calculating the
// end pointer if possible. `core::slice::Iter` calculates the end
// pointer to determine when it should stop yielding elements. Because
// we want to avoid calculating the end pointer, we don't use
// `core::slice::Iter`, we implement our own iterator that doesn't
// calculate the end pointer. This doesn't make creating page tables at
// that address sound, but it avoids some easy to trigger
// miscompilations.
let ptr = self.entries.as_mut_ptr();
(0..512).map(move |i| unsafe { &mut *ptr.add(i) })
}
/// Checks if the page table is empty (all entries are zero).
#[inline]
pub fn is_empty(&self) -> bool {
self.iter().all(|entry| entry.is_unused())
}
}
impl PTE {
#[inline]
pub const fn new() -> Self { PTE { entry: 0 } }
#[inline]
pub const fn is_unused(&self) -> bool { self.entry == 0 }
#[inline]
pub fn set_unused(&mut self) { self.entry = 0; }
#[inline]
pub const fn flags(&self) -> PTEFlags {
// from_bits_truncate ignores undefined bits.
PTEFlags::from_bits_truncate(self.entry)
}
#[inline]
pub const fn addr(&self) -> u64 { self.entry & 0x000f_ffff_ffff_f000 }
#[inline]
pub fn set(&mut self, pa: u64, flags: PTEFlags) {
self.entry = pa | flags.bits();
}
}
const ID_MASK: u64 = 0x1ff;
#[inline]
pub fn p4idx(addr: u64) -> u16 {
((addr >> 12 >> 9 >> 9 >> 9) & ID_MASK) as u16
}
#[inline]
pub fn p3idx(addr: u64) -> u16 { ((addr >> 12 >> 9 >> 9) & ID_MASK) as u16 }
#[inline]
pub fn p2idx(addr: u64) -> u16 { ((addr >> 12 >> 9) & ID_MASK) as u16 }
#[inline]
pub fn p1idx(addr: u64) -> u16 { ((addr >> 12) & ID_MASK) as u16 }