mmu/amd64/
page_table.rs

1use super::*;
2
3/// Defines a mapping from virtual to physical address space.
4#[repr(align(4096))]
5pub struct PageTable {
6    pub entries: [Entry; 512],
7}
8
9/// Page table entry.
10#[derive(Debug, Clone, Copy)]
11pub struct Entry {
12    entry: u64,
13}
14
15/// Properties of a page table entry.
16#[repr(u64)]
17#[derive(Debug, Clone, Copy)]
18pub enum Bit {
19    Present  = 0,
20    Writable = 1,
21    User     = 2,
22    Direct   = 3,
23    Nocache  = 4,
24    Accessed = 5,
25    Dirty    = 6,
26    Huge     = 7,
27    Global   = 8,
28    Noexec   = 63,
29}
30
31add_indexing!(PageTable, Entry);
32
33impl PageTable {
34    /// Create a new PageTable.
35    pub const fn new() -> Self {
36        PageTable {
37            entries: [Entry::new(); 512],
38        }
39    }
40
41    /// Clear the page table.
42    pub fn clear(&mut self) {
43        for entry in self.entries.iter_mut() {
44            entry.clear();
45        }
46    }
47}
48
49impl Entry {
50    /// Create a new page table entry.
51    pub const fn new() -> Self {
52        Entry {
53            entry: 0,
54        }
55    }
56
57    /// Volatile read of the entry.
58    fn read(&self) -> u64 {
59        let entry_ptr = &self.entry as *const u64;
60        unsafe { core::ptr::read_volatile(entry_ptr) }
61    }
62
63    /// Volatile write of the entry.
64    fn write(&mut self, entry: u64) {
65        let entry_ptr = &mut self.entry as *mut u64;
66        unsafe { core::ptr::write_volatile(entry_ptr, entry); }
67    }
68
69    /// Update the entry value using volatile read/write.
70    fn update<F>(&mut self, f: F) where F: Fn(u64) -> u64 {
71        self.write(f(self.read()));
72    }
73
74    /// Set the entry to 0.
75    pub fn clear(&mut self) {
76        self.write(0);
77    }
78
79    /// Physical memory address referenced by this entry.
80    pub fn address(&self) -> PhysicalAddress {
81        self.read() & 0x000ffffffffff000
82    }
83
84    /// Set the physical memory address of this entry.
85    pub fn set_address(&mut self, address: PhysicalAddress) -> &mut Self {
86        assert!(address % 0x1000 == 0);
87        assert!(address < 0xfff0_0000_0000_0000);
88        self.update(|entry| {
89            (entry & !0x000ffffffffff000) | address
90        });
91        self
92    }
93
94    /// Bits available to operating system.
95    pub fn avail(&self) -> u8 {
96        ((self.read() & 0x0e00) >> 9) as u8
97    }
98
99    /// Set available bits.
100    pub fn set_avail(&mut self, val: u8) -> &mut Self {
101        if val > 7 {
102            panic!("Avail value out ouf bounds");
103        }
104        self.update(|entry| {
105           (entry & !0x0e00) | ((val as u64) << 9)
106        });
107        self
108    }
109
110    /// Whether a certain bit is set.
111    pub fn bit(&self, bit: Bit) -> bool {
112        get_bit!(self.read(), bit as u64)
113    }
114
115    /// Set or unset a bit.
116    fn modify_bit(&mut self, bit: Bit, val: bool) {
117        self.update(|mut entry| {
118            set_bit!(entry, bit as u64, val);
119            entry
120        });
121    }
122
123    /// Set a bit.
124    pub fn set_bit(&mut self, bit: Bit) -> &mut Self {
125        self.modify_bit(bit, true);
126        self
127    }
128
129    /// Unset a bit.
130    pub fn unset_bit(&mut self, bit: Bit) -> &mut Self {
131        self.modify_bit(bit, false);
132        self
133    }
134}
135
136#[test]
137fn int_consistency() {
138    let mut entry = Entry::new();
139    entry.set_address(0x4242000);
140    assert_eq!(entry.address(), 0x4242000);
141
142    entry.set_avail(7);
143    assert_eq!(entry.avail(), 7);
144    entry.set_avail(0);
145    assert_eq!(entry.avail(), 0);
146}
147
148#[test]
149fn bit_consistency() {
150    let mut entry = Entry::new();
151    entry.set_address(0x000ffffffffff000);
152    assert!(!entry.bit(Bit::Present));
153    assert!(!entry.bit(Bit::Writable));
154    assert!(!entry.bit(Bit::User));
155    assert!(!entry.bit(Bit::Direct));
156    assert!(!entry.bit(Bit::Nocache));
157    assert!(!entry.bit(Bit::Accessed));
158    assert!(!entry.bit(Bit::Dirty));
159    assert!(!entry.bit(Bit::Huge));
160    assert!(!entry.bit(Bit::Global));
161    assert!(!entry.bit(Bit::Noexec));
162
163    entry.set_bit(Bit::Present);
164    assert!(entry.bit(Bit::Present));
165    entry.unset_bit(Bit::Present);
166
167    entry.set_bit(Bit::Writable);
168    assert!(entry.bit(Bit::Writable));
169    entry.unset_bit(Bit::Writable);
170
171    entry.set_bit(Bit::User);
172    assert!(entry.bit(Bit::User));
173    entry.unset_bit(Bit::User);
174
175    entry.set_bit(Bit::Direct);
176    assert!(entry.bit(Bit::Direct));
177    entry.unset_bit(Bit::Direct);
178
179    entry.set_bit(Bit::Nocache);
180    assert!(entry.bit(Bit::Nocache));
181    entry.unset_bit(Bit::Nocache);
182
183    entry.set_bit(Bit::Accessed);
184    assert!(entry.bit(Bit::Accessed));
185    entry.unset_bit(Bit::Accessed);
186
187    entry.set_bit(Bit::Dirty);
188    assert!(entry.bit(Bit::Dirty));
189    entry.unset_bit(Bit::Dirty);
190
191    entry.set_bit(Bit::Huge);
192    assert!(entry.bit(Bit::Huge));
193    entry.unset_bit(Bit::Huge);
194
195    entry.set_bit(Bit::Global);
196    assert!(entry.bit(Bit::Global));
197    entry.unset_bit(Bit::Global);
198
199    entry.set_bit(Bit::Noexec);
200    assert!(entry.bit(Bit::Noexec));
201    entry.unset_bit(Bit::Noexec);
202}
203