1use super::*;
2
3#[repr(align(4096))]
5pub struct PageTable {
6 pub entries: [Entry; 512],
7}
8
9#[derive(Debug, Clone, Copy)]
11pub struct Entry {
12 entry: u64,
13}
14
15#[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 pub const fn new() -> Self {
36 PageTable {
37 entries: [Entry::new(); 512],
38 }
39 }
40
41 pub fn clear(&mut self) {
43 for entry in self.entries.iter_mut() {
44 entry.clear();
45 }
46 }
47}
48
49impl Entry {
50 pub const fn new() -> Self {
52 Entry {
53 entry: 0,
54 }
55 }
56
57 fn read(&self) -> u64 {
59 let entry_ptr = &self.entry as *const u64;
60 unsafe { core::ptr::read_volatile(entry_ptr) }
61 }
62
63 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 fn update<F>(&mut self, f: F) where F: Fn(u64) -> u64 {
71 self.write(f(self.read()));
72 }
73
74 pub fn clear(&mut self) {
76 self.write(0);
77 }
78
79 pub fn address(&self) -> PhysicalAddress {
81 self.read() & 0x000ffffffffff000
82 }
83
84 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 pub fn avail(&self) -> u8 {
96 ((self.read() & 0x0e00) >> 9) as u8
97 }
98
99 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 pub fn bit(&self, bit: Bit) -> bool {
112 get_bit!(self.read(), bit as u64)
113 }
114
115 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 pub fn set_bit(&mut self, bit: Bit) -> &mut Self {
125 self.modify_bit(bit, true);
126 self
127 }
128
129 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