1use crate::{
2 FrameAllocator, PageTableEntry, PagingError, PagingResult, PhysAddr, PteConfigOf, TableMeta,
3 VirtAddr,
4};
5
6#[derive(Clone, Copy)]
8pub struct Frame<T: TableMeta, A: FrameAllocator> {
9 pub paddr: PhysAddr,
10 pub allocator: A,
11 frames: usize,
12 _marker: core::marker::PhantomData<T>,
13}
14
15impl<T: TableMeta, A: FrameAllocator> core::fmt::Debug for Frame<T, A> {
16 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
17 f.debug_struct("Frame")
18 .field("paddr", &format_args!("{:#x}", self.paddr.as_usize()))
19 .finish()
20 }
21}
22
23impl<T, A> Frame<T, A>
24where
25 T: TableMeta,
26 A: FrameAllocator,
27{
28 pub(crate) const PT_INDEX_SHIFT: usize = T::PAGE_SIZE.trailing_zeros() as usize;
29 pub(crate) const PT_INDEX_BITS: usize = cal_index_bits::<T>();
30 pub(crate) const PT_VALID_BITS: usize = Self::PT_INDEX_BITS + Self::PT_INDEX_SHIFT;
31 pub(crate) const LEN: usize = T::PAGE_SIZE / core::mem::size_of::<T::P>();
32 pub(crate) const ROOT_LEN: usize = 1usize << T::LEVEL_BITS[0];
33 pub(crate) const ROOT_FRAMES: usize =
34 (Self::ROOT_LEN * core::mem::size_of::<T::P>()).div_ceil(T::PAGE_SIZE);
35 pub(crate) const PT_LEVEL: usize = T::LEVEL_BITS.len();
36
37 pub fn new(allocator: A) -> PagingResult<Self> {
39 let paddr = allocator.alloc_frame().ok_or(PagingError::NoMemory)?;
40 unsafe {
41 let vaddr = allocator.phys_to_virt(paddr);
42 core::ptr::write_bytes(vaddr, 0, T::PAGE_SIZE);
43 }
44
45 Ok(Self {
46 paddr,
47 allocator,
48 frames: 1,
49 _marker: core::marker::PhantomData,
50 })
51 }
52
53 pub fn new_root(allocator: A) -> PagingResult<Self> {
55 let align = T::PAGE_SIZE * Self::ROOT_FRAMES;
56 let paddr = allocator
57 .alloc_frames(Self::ROOT_FRAMES, align)
58 .ok_or(PagingError::NoMemory)?;
59 unsafe {
60 let vaddr = allocator.phys_to_virt(paddr);
61 core::ptr::write_bytes(vaddr, 0, T::PAGE_SIZE * Self::ROOT_FRAMES);
62 }
63
64 Ok(Self {
65 paddr,
66 allocator,
67 frames: Self::ROOT_FRAMES,
68 _marker: core::marker::PhantomData,
69 })
70 }
71
72 pub fn from_paddr(paddr: PhysAddr, allocator: A) -> Self {
74 Self {
75 paddr,
76 allocator,
77 frames: 1,
78 _marker: core::marker::PhantomData,
79 }
80 }
81
82 pub fn from_root_paddr(paddr: PhysAddr, allocator: A) -> Self {
84 Self {
85 paddr,
86 allocator,
87 frames: Self::ROOT_FRAMES,
88 _marker: core::marker::PhantomData,
89 }
90 }
91
92 pub fn from_pte(pte: &T::P, level: usize, allocator: A) -> Self {
94 Self::from_paddr(pte.paddr(level > 1), allocator)
95 }
96
97 pub fn as_slice_mut(&mut self) -> &mut [T::P] {
99 let vaddr = self.allocator.phys_to_virt(self.paddr);
100 unsafe { core::slice::from_raw_parts_mut(vaddr as *mut T::P, self.len()) }
101 }
102
103 pub fn as_slice(&self) -> &[T::P] {
105 let vaddr = self.allocator.phys_to_virt(self.paddr);
106 unsafe { core::slice::from_raw_parts(vaddr as *const T::P, self.len()) }
107 }
108
109 pub fn len(&self) -> usize {
110 self.frames * Self::LEN
111 }
112
113 pub fn is_empty(&self) -> bool {
115 self.len() == 0
116 }
117
118 pub fn level_size(level: usize) -> usize {
124 if level == 1 {
125 return T::PAGE_SIZE;
126 }
127 let total_levels = T::LEVEL_BITS.len();
130 let shift = T::LEVEL_BITS
131 .iter()
132 .skip(total_levels - level + 1)
133 .sum::<usize>();
134 T::PAGE_SIZE << shift
135 }
136
137 pub fn virt_to_index(vaddr: VirtAddr, level: usize) -> usize {
140 if level == 0 || level > Self::PT_LEVEL {
141 panic!("Invalid level: {} (valid: 1..={})", level, Self::PT_LEVEL);
142 }
143
144 let page_shift = T::PAGE_SIZE.trailing_zeros() as usize;
150 let total_levels = T::LEVEL_BITS.len();
151
152 let shift = if level == 1 {
154 page_shift
155 } else {
156 page_shift
157 + T::LEVEL_BITS
158 .iter()
159 .skip(total_levels - level + 1)
160 .sum::<usize>()
161 };
162
163 let level_index_bits = T::LEVEL_BITS[total_levels - level];
165 let mask = (1 << level_index_bits) - 1;
166
167 (vaddr.as_usize() >> shift) & mask
168 }
169
170 pub(crate) fn level_for_page_size(page_size: usize) -> Option<usize> {
171 (1..=Self::PT_LEVEL).find(|level| Self::level_size(*level) == page_size)
172 }
173
174 pub fn protect_recursive(
175 &mut self,
176 vaddr: VirtAddr,
177 config: PteConfigOf<T>,
178 level: usize,
179 ) -> PagingResult<usize> {
180 let index = Self::virt_to_index(vaddr, level);
181 let entry = self.as_slice()[index];
182 if entry.unused() {
183 return Err(PagingError::not_mapped());
184 }
185 let is_dir = level > 1;
186 let is_huge = entry.huge(is_dir);
187 if is_huge || level == 1 {
188 self.as_slice_mut()[index] = T::P::new_page(entry.paddr(is_dir), config, is_huge);
189 return Ok(Self::level_size(level));
190 }
191 if !entry.present() {
192 return Err(PagingError::not_mapped());
193 }
194
195 let mut child = Self::from_paddr(entry.paddr(is_dir), self.allocator.clone());
196 child.protect_recursive(vaddr, config, level - 1)
197 }
198
199 pub fn remap_recursive(
200 &mut self,
201 vaddr: VirtAddr,
202 paddr: PhysAddr,
203 config: PteConfigOf<T>,
204 level: usize,
205 ) -> PagingResult<usize> {
206 let index = Self::virt_to_index(vaddr, level);
207 let entry = self.as_slice()[index];
208 if entry.unused() {
209 return Err(PagingError::not_mapped());
210 }
211 let is_dir = level > 1;
212 let is_huge = entry.huge(is_dir);
213 if is_huge || level == 1 {
214 let page_size = Self::level_size(level);
215 let aligned_paddr = PhysAddr::from_usize(paddr.as_usize() & !(page_size - 1));
216 self.as_slice_mut()[index] = T::P::new_page(aligned_paddr, config, is_huge);
217 return Ok(page_size);
218 }
219 if !entry.present() {
220 return Err(PagingError::not_mapped());
221 }
222
223 let mut child = Self::from_paddr(entry.paddr(is_dir), self.allocator.clone());
224 child.remap_recursive(vaddr, paddr, config, level - 1)
225 }
226
227 pub fn reconstruct_vaddr(index: usize, level: usize, base_vaddr: VirtAddr) -> VirtAddr {
230 let entry_size = Self::level_size(level);
231 base_vaddr + index * entry_size
232 }
233
234 pub fn deallocate_recursive(&mut self, level: usize) {
251 self.deallocate_children(level);
253
254 self.allocator
256 .dealloc_frames(self.paddr, self.frames, T::PAGE_SIZE);
257 }
258
259 pub fn deallocate_children(&mut self, level: usize) {
268 for i in (0..self.len()).rev() {
270 let entry_info = {
272 let entries = self.as_slice();
273 if i < entries.len() {
274 let entry = entries[i];
275 (
276 entry.present(),
277 entry.huge(level > 1),
278 entry.paddr(level > 1),
279 )
280 } else {
281 (false, false, crate::PhysAddr::from_usize(0))
282 }
283 };
284
285 let (is_valid, is_huge, paddr) = entry_info;
286
287 if !is_valid {
288 continue;
289 }
290
291 if is_huge || level == 1 {
293 continue;
294 }
295 else {
297 let mut child_frame = Frame::<T, A>::from_paddr(paddr, self.allocator.clone());
298 child_frame.deallocate_recursive(level - 1);
299
300 let entries_mut = self.as_slice_mut();
302 entries_mut[i].clear();
303 }
304 }
305 }
306
307 pub fn translate_recursive(&self, vaddr: VirtAddr, level: usize) -> PagingResult<T::P> {
317 let (pte, _) = self.translate_recursive_with_level(vaddr, level)?;
318 Ok(pte)
319 }
320
321 pub fn translate_recursive_with_level(
331 &self,
332 vaddr: VirtAddr,
333 level: usize,
334 ) -> PagingResult<(T::P, usize)> {
335 let (pte, level) = self.find_occupied_leaf(vaddr, level)?;
336 if !pte.present() {
337 return Err(PagingError::not_mapped());
338 }
339 Ok((pte, level))
340 }
341
342 pub(crate) fn find_occupied_leaf(
343 &self,
344 vaddr: VirtAddr,
345 level: usize,
346 ) -> PagingResult<(T::P, usize)> {
347 let index = Self::virt_to_index(vaddr, level);
349
350 let entries = self.as_slice();
352 let pte = entries[index];
353
354 if pte.unused() {
355 return Err(PagingError::not_mapped());
356 }
357
358 if pte.huge(level > 1) || level == 1 {
360 return Ok((pte, level));
361 }
362
363 if level > 1 {
365 if !pte.present() {
366 return Err(PagingError::hierarchy_error(
367 "Non-present intermediate entry is not a leaf",
368 ));
369 }
370 let child_frame: Frame<T, A> = Frame::from_pte(&pte, level, self.allocator.clone());
371 return child_frame.find_occupied_leaf(vaddr, level - 1);
372 }
373
374 Err(PagingError::hierarchy_error(
376 "Invalid page table level during translation",
377 ))
378 }
379
380 pub fn dealloc_entry_recursive(&mut self, index: usize, level: usize) -> bool {
391 if index >= self.len() || level <= 1 {
392 return false;
393 }
394
395 let entries = self.as_slice();
396 let entry = &entries[index];
397 if entry.present() && !entry.huge(true) {
398 let mut child_frame = Frame::<T, A>::from_pte(entry, level, self.allocator.clone());
400 child_frame.deallocate_recursive(level - 1);
401
402 let entries_mut = self.as_slice_mut();
404 entries_mut[index].clear();
405
406 true
407 } else {
408 false
409 }
410 }
411
412 pub(crate) fn clone_entry_from(
413 &mut self,
414 source: &Self,
415 index: usize,
416 level: usize,
417 ) -> PagingResult<bool> {
418 if index >= self.len() || index >= source.len() {
419 return Err(PagingError::hierarchy_error(
420 "Entry index exceeds page-table frame size",
421 ));
422 }
423 if !self.as_slice()[index].unused() {
424 return Ok(false);
425 }
426
427 let source_entry = source.as_slice()[index];
428 if source_entry.unused() {
429 return Ok(false);
430 }
431 if level == 1 || source_entry.huge(true) {
432 self.as_slice_mut()[index] = source_entry;
433 return Ok(true);
434 }
435 if !source_entry.present() {
436 return Err(PagingError::hierarchy_error(
437 "Non-present intermediate entry is not a leaf",
438 ));
439 }
440
441 let source_child = Self::from_paddr(source_entry.paddr(true), source.allocator.clone());
442 let mut target_child = Self::new(self.allocator.clone())?;
443 if let Err(err) = target_child.clone_children_from(&source_child, level - 1) {
444 target_child.deallocate_recursive(level - 1);
445 return Err(err);
446 }
447
448 self.as_slice_mut()[index] = T::P::new_table(target_child.paddr);
449 Ok(true)
450 }
451
452 fn clone_children_from(&mut self, source: &Self, level: usize) -> PagingResult {
453 for index in 0..source.len() {
454 self.clone_entry_from(source, index, level)?;
455 }
456 Ok(())
457 }
458}
459
460const fn cal_index_bits<T: TableMeta>() -> usize {
461 let mut bits = 0;
462 let len = T::LEVEL_BITS.len();
463 let mut i = 0;
464 while i < len {
465 bits += T::LEVEL_BITS[i];
466 i += 1;
467 }
468 bits
469}