1use core::ops::{Deref, DerefMut};
2
3use crate::{
4 FrameAllocator, PageTableEntry, PagingError, PagingResult, PhysAddr, TableMeta, VirtAddr,
5 frame::Frame,
6 map::{MapConfig, MapRecursiveConfig, UnmapConfig, UnmapRecursiveConfig},
7 walk::{PageTableWalker, WalkConfig},
8};
9
10pub struct PageTable<T: TableMeta, A: FrameAllocator> {
11 inner: PageTableRef<T, A>,
12}
13
14impl<T: TableMeta, A: FrameAllocator> PageTable<T, A> {
15 pub const VALID_BITS: usize = Frame::<T, A>::PT_VALID_BITS;
16
17 pub fn new(allocator: A) -> PagingResult<Self> {
19 let inner = unsafe { PageTableRef::new(allocator) }?;
20 Ok(Self { inner })
21 }
22
23 pub fn valid_bits(&self) -> usize {
24 Frame::<T, A>::PT_VALID_BITS
25 }
26}
27
28impl<T: TableMeta, A: FrameAllocator> Drop for PageTable<T, A> {
29 fn drop(&mut self) {
30 unsafe {
31 self.deallocate();
33 }
34 }
35}
36
37impl<T: TableMeta, A: FrameAllocator> Deref for PageTable<T, A> {
38 type Target = PageTableRef<T, A>;
39
40 fn deref(&self) -> &Self::Target {
41 &self.inner
42 }
43}
44
45impl<T: TableMeta, A: FrameAllocator> DerefMut for PageTable<T, A> {
46 fn deref_mut(&mut self) -> &mut Self::Target {
47 &mut self.inner
48 }
49}
50
51#[derive(Clone, Copy)]
52pub struct PageTableRef<T: TableMeta, A: FrameAllocator> {
53 pub root: Frame<T, A>,
54}
55
56impl<T: TableMeta, A: FrameAllocator> core::fmt::Debug for PageTableRef<T, A>
57where
58 T::P: core::fmt::Debug,
59{
60 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
61 f.debug_struct("PageTable")
62 .field("root_paddr", &format_args!("{:#x}", self.root.paddr.raw()))
63 .field("table_levels", &T::LEVEL_BITS.len())
64 .field("max_block_level", &T::MAX_BLOCK_LEVEL)
65 .field("page_size", &format_args!("{:#x}", T::PAGE_SIZE))
66 .finish()
67 }
68}
69
70impl<T: TableMeta, A: FrameAllocator> PageTableRef<T, A> {
71 pub unsafe fn new(allocator: A) -> PagingResult<Self> {
77 let root = Frame::new_root(allocator)?;
78 Ok(Self { root })
79 }
80
81 pub fn from_paddr(paddr: PhysAddr, allocator: A) -> Self {
82 let root = Frame::from_root_paddr(paddr, allocator);
83 Self { root }
84 }
85
86 pub fn map(&mut self, config: &MapConfig) -> PagingResult {
88 self.validate_map_config(config)?;
90
91 if config.vaddr.raw().checked_add(config.size).is_none()
93 || config.paddr.raw().checked_add(config.size).is_none()
94 {
95 return Err(PagingError::address_overflow(
96 "Virtual or physical address overflow",
97 ));
98 }
99 self.validate_address_width(config.vaddr, config.size, "map")?;
100
101 self.root.map_range_recursive(MapRecursiveConfig {
102 start_vaddr: config.vaddr,
103 start_paddr: config.paddr,
104 end_vaddr: config.vaddr + config.size,
105 level: Frame::<T, A>::PT_LEVEL,
106 allow_huge: config.allow_huge,
107 flush: config.flush,
108 pte_template: config.pte,
109 })?;
110
111 Ok(())
112 }
113
114 pub fn unmap(&mut self, start_vaddr: VirtAddr, size: usize) -> PagingResult<()> {
130 self.validate_unmap_params(start_vaddr, size)?;
132
133 let end_vaddr: VirtAddr = match start_vaddr.raw().checked_add(size) {
135 Some(end) => VirtAddr::new(end),
136 None => {
137 return Err(PagingError::address_overflow(
138 "Virtual address overflow in unmap",
139 ));
140 }
141 };
142 self.validate_address_width(start_vaddr, size, "unmap")?;
143
144 self.root.unmap_range_recursive(UnmapRecursiveConfig {
145 start_vaddr,
146 end_vaddr,
147 level: Frame::<T, A>::PT_LEVEL,
148 flush: true, })?;
150
151 Ok(())
152 }
153
154 pub fn unmap_with_config(&mut self, config: &UnmapConfig) -> PagingResult<()> {
156 self.validate_unmap_params(config.start_vaddr, config.size)?;
157
158 let end_vaddr = match config.start_vaddr.raw().checked_add(config.size) {
159 Some(end) => VirtAddr::new(end),
160 None => {
161 return Err(PagingError::address_overflow(
162 "Virtual address overflow in unmap_with_config",
163 ));
164 }
165 };
166 self.validate_address_width(config.start_vaddr, config.size, "unmap_with_config")?;
167
168 self.root.unmap_range_recursive(UnmapRecursiveConfig {
169 start_vaddr: config.start_vaddr,
170 end_vaddr,
171 level: Frame::<T, A>::PT_LEVEL,
172 flush: config.flush,
173 })?;
174
175 Ok(())
176 }
177
178 fn validate_unmap_params(&self, start_vaddr: VirtAddr, size: usize) -> PagingResult<()> {
180 if size == 0 {
181 return Err(PagingError::invalid_size("Size cannot be zero in unmap"));
182 }
183
184 if !start_vaddr.raw().is_multiple_of(T::PAGE_SIZE) {
186 return Err(PagingError::alignment_error(
187 "Start virtual address not page aligned in unmap",
188 ));
189 }
190
191 if !size.is_multiple_of(T::PAGE_SIZE) {
193 return Err(PagingError::alignment_error(
194 "Size not page aligned in unmap",
195 ));
196 }
197
198 Ok(())
199 }
200
201 pub fn walk_all(&self, config: WalkConfig) -> PageTableWalker<'_, T, A> {
203 PageTableWalker::new(self, config)
204 }
205
206 pub fn walk(
207 &self,
208 start_vaddr: VirtAddr,
209 end_vaddr: VirtAddr,
210 ) -> impl Iterator<Item = crate::walk::PteInfo<T::P>> + '_ {
211 let config = WalkConfig {
212 start_vaddr,
213 end_vaddr,
214 };
215 PageTableWalker::new(self, config).filter(|p| p.pte.to_config(false).valid)
216 }
217
218 pub fn walk_valid(&self) -> impl Iterator<Item = crate::walk::PteInfo<T::P>> + '_ {
220 self.walk(0.into(), usize::MAX.into()).filter(|p| {
221 let config = p.pte.to_config(false);
222 config.valid && p.is_final_mapping
223 })
224 }
225
226 fn validate_map_config(&self, config: &MapConfig) -> PagingResult {
228 if config.size == 0 {
229 return Err(PagingError::invalid_size("Size cannot be zero"));
230 }
231
232 if !config.vaddr.raw().is_multiple_of(T::PAGE_SIZE) {
234 return Err(PagingError::alignment_error(
235 "Virtual address not page aligned",
236 ));
237 }
238
239 if !config.paddr.raw().is_multiple_of(T::PAGE_SIZE) {
240 return Err(PagingError::alignment_error(
241 "Physical address not page aligned",
242 ));
243 }
244
245 Ok(())
246 }
247
248 fn validate_address_width(
249 &self,
250 start_vaddr: VirtAddr,
251 size: usize,
252 operation: &'static str,
253 ) -> PagingResult<()> {
254 if !T::STRICT_ADDRESS_WIDTH {
255 return Ok(());
256 }
257 let Some(end) = start_vaddr.raw().checked_add(size) else {
258 return Err(PagingError::address_overflow(
259 "Virtual address range overflow",
260 ));
261 };
262 let last = end.saturating_sub(1);
263 if !Self::is_addr_in_width(start_vaddr.raw()) || !Self::is_addr_in_width(last) {
264 return Err(PagingError::address_overflow(operation));
265 }
266 Ok(())
267 }
268
269 pub const fn page_size() -> usize {
270 T::PAGE_SIZE
271 }
272
273 pub const fn table_levels() -> usize {
274 T::LEVEL_BITS.len()
275 }
276
277 pub const fn valid_bits() -> usize {
278 Frame::<T, A>::PT_VALID_BITS
279 }
280
281 fn is_addr_in_width(addr: usize) -> bool {
282 let valid_bits = Self::valid_bits();
283 if valid_bits >= usize::BITS as usize {
284 return true;
285 }
286 addr < (1usize << valid_bits)
287 }
288
289 pub unsafe fn destroy(mut self) {
302 self.root.deallocate_recursive(Frame::<T, A>::PT_LEVEL);
303 }
304
305 pub unsafe fn deallocate(&mut self) {
320 self.root.deallocate_recursive(Frame::<T, A>::PT_LEVEL);
321 }
322
323 pub fn deallocate_range(&mut self, start_vaddr: VirtAddr, end_vaddr: VirtAddr) -> PagingResult {
328 if start_vaddr >= end_vaddr {
329 return Err(PagingError::invalid_range(
330 "Start address must be less than end address",
331 ));
332 }
333
334 Ok(())
341 }
342
343 pub fn translate(&self, vaddr: VirtAddr) -> PagingResult<(PhysAddr, T::P)> {
355 self.translate_with_level(vaddr)
356 .map(|(phys_addr, pte, _)| (phys_addr, pte))
357 }
358
359 pub fn translate_with_level(&self, vaddr: VirtAddr) -> PagingResult<(PhysAddr, T::P, usize)> {
361 if T::STRICT_ADDRESS_WIDTH && !Self::is_addr_in_width(vaddr.raw()) {
362 return Err(PagingError::address_overflow("translate"));
363 }
364
365 let (pte, level) = self
366 .root
367 .translate_recursive_with_level(vaddr, Frame::<T, A>::PT_LEVEL)?;
368
369 let pte_config = pte.to_config(level > 1);
370
371 let (phys_addr, _) = if pte_config.huge {
373 let level_size = Frame::<T, A>::level_size(level);
375 let offset_in_page = vaddr.raw() % level_size;
376 (
377 PhysAddr::new(pte_config.paddr.raw() + offset_in_page),
378 level_size,
379 )
380 } else {
381 let offset_in_page = vaddr.raw() % T::PAGE_SIZE;
383 (
384 PhysAddr::new(pte_config.paddr.raw() + offset_in_page),
385 T::PAGE_SIZE,
386 )
387 };
388
389 Ok((phys_addr, pte, level))
390 }
391
392 pub fn translate_phys(&self, vaddr: VirtAddr) -> PagingResult<PhysAddr> {
401 let (p, _) = self.translate(vaddr)?;
402 Ok(p)
403 }
404
405 pub fn is_mapped(&self, vaddr: VirtAddr) -> bool {
416 self.translate(vaddr).is_ok()
417 }
418
419 pub fn root_paddr(&self) -> crate::PhysAddr {
421 self.root.paddr
422 }
423}