rustubs/arch/x86_64/paging/
pagetable.rs

1//! basic paging support. code derived from the
2//! [x86_64 crate](https://docs.rs/x86_64/latest/src/x86_64/addr.rs.html)
3
4use bitflags::bitflags;
5
6#[repr(align(4096))]
7#[repr(C)]
8#[derive(Clone)]
9pub struct Pagetable {
10	pub entries: [PTE; Self::ENTRY_COUNT],
11}
12
13#[derive(Clone)]
14#[repr(transparent)]
15pub struct PTE {
16	pub entry: u64,
17}
18
19bitflags! {
20#[derive(Debug, Copy, Clone)]
21pub struct PTEFlags:u64 {
22	const ZERO      = 0;
23	const PRESENT   = 1 << 0;
24	const WRITABLE  = 1 << 1;
25	const USER      = 1 << 2;
26	const WT        = 1 << 3;
27	const NC        = 1 << 4;
28	const ACCESSED  = 1 << 5;
29	const DIRTY     = 1 << 6;
30	const HUGE_PAGE = 1 << 7;
31	const GLOBAL    = 1 << 8;
32	const B9        = 1 << 9;
33	const B10       = 1 << 10;
34	const B11       = 1 << 11;
35	// [51:12] is used for translation address
36	// [62:52] are user defined.
37	// [63] NO_EXECUTE, needs to be enabled in EFER.
38	const NE        = 1 << 63;
39}
40}
41
42impl Pagetable {
43	const ENTRY_COUNT: usize = 512;
44	/// Creates an empty page table.
45	#[inline]
46	pub const fn new() -> Self {
47		const EMPTY: PTE = PTE::new();
48		Pagetable { entries: [EMPTY; Self::ENTRY_COUNT] }
49	}
50
51	/// Clears all entries.
52	#[inline]
53	pub fn zero(&mut self) {
54		for entry in self.iter_mut() {
55			entry.set_unused();
56		}
57	}
58
59	/// Returns an iterator over the entries of the page table.
60	#[inline]
61	pub fn iter(&self) -> impl Iterator<Item = &PTE> {
62		(0..512).map(move |i| &self.entries[i])
63	}
64
65	/// Returns an iterator that allows modifying the entries of the page table.
66	#[inline]
67	pub fn iter_mut(&mut self) -> impl Iterator<Item = &mut PTE> {
68		// Note that we intentionally don't just return `self.entries.iter()`:
69		// Some users may choose to create a reference to a page table at
70		// `0xffff_ffff_ffff_f000`. This causes problems because calculating
71		// the end pointer of the page tables causes an overflow. Therefore
72		// creating page tables at that address is unsound and must be avoided.
73		// Unfortunately creating such page tables is quite common when
74		// recursive page tables are used, so we try to avoid calculating the
75		// end pointer if possible. `core::slice::Iter` calculates the end
76		// pointer to determine when it should stop yielding elements. Because
77		// we want to avoid calculating the end pointer, we don't use
78		// `core::slice::Iter`, we implement our own iterator that doesn't
79		// calculate the end pointer. This doesn't make creating page tables at
80		// that address sound, but it avoids some easy to trigger
81		// miscompilations.
82		let ptr = self.entries.as_mut_ptr();
83		(0..512).map(move |i| unsafe { &mut *ptr.add(i) })
84	}
85
86	/// Checks if the page table is empty (all entries are zero).
87	#[inline]
88	pub fn is_empty(&self) -> bool {
89		self.iter().all(|entry| entry.is_unused())
90	}
91}
92
93impl PTE {
94	#[inline]
95	pub const fn new() -> Self { PTE { entry: 0 } }
96
97	#[inline]
98	pub const fn is_unused(&self) -> bool { self.entry == 0 }
99
100	#[inline]
101	pub fn set_unused(&mut self) { self.entry = 0; }
102
103	#[inline]
104	pub const fn flags(&self) -> PTEFlags {
105		// from_bits_truncate ignores undefined bits.
106		PTEFlags::from_bits_truncate(self.entry)
107	}
108
109	#[inline]
110	pub const fn addr(&self) -> u64 { self.entry & 0x000f_ffff_ffff_f000 }
111
112	#[inline]
113	pub fn set(&mut self, pa: u64, flags: PTEFlags) {
114		self.entry = pa | flags.bits();
115	}
116}
117
118const ID_MASK: u64 = 0x1ff;
119#[inline]
120pub fn p4idx(addr: u64) -> u16 {
121	((addr >> 12 >> 9 >> 9 >> 9) & ID_MASK) as u16
122}
123#[inline]
124pub fn p3idx(addr: u64) -> u16 { ((addr >> 12 >> 9 >> 9) & ID_MASK) as u16 }
125#[inline]
126pub fn p2idx(addr: u64) -> u16 { ((addr >> 12 >> 9) & ID_MASK) as u16 }
127#[inline]
128pub fn p1idx(addr: u64) -> u16 { ((addr >> 12) & ID_MASK) as u16 }