1use crate::{
2 FrameAllocator, PageTableEntry, PagingError, PagingResult, PhysAddr, PteConfig, 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.raw()))
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 let config = pte.to_config(level > 1);
95 Self::from_paddr(config.paddr, allocator)
96 }
97
98 pub fn as_slice_mut(&mut self) -> &mut [T::P] {
100 let vaddr = self.allocator.phys_to_virt(self.paddr);
101 unsafe { core::slice::from_raw_parts_mut(vaddr as *mut T::P, self.len()) }
102 }
103
104 pub fn as_slice(&self) -> &[T::P] {
106 let vaddr = self.allocator.phys_to_virt(self.paddr);
107 unsafe { core::slice::from_raw_parts(vaddr as *const T::P, self.len()) }
108 }
109
110 pub fn len(&self) -> usize {
111 self.frames * Self::LEN
112 }
113
114 pub fn is_empty(&self) -> bool {
116 self.len() == 0
117 }
118
119 pub fn level_size(level: usize) -> usize {
125 if level == 1 {
126 return T::PAGE_SIZE;
127 }
128 let total_levels = T::LEVEL_BITS.len();
131 let shift = T::LEVEL_BITS
132 .iter()
133 .skip(total_levels - level + 1)
134 .sum::<usize>();
135 T::PAGE_SIZE << shift
136 }
137
138 pub fn virt_to_index(vaddr: VirtAddr, level: usize) -> usize {
141 if level == 0 || level > Self::PT_LEVEL {
142 panic!("Invalid level: {} (valid: 1..={})", level, Self::PT_LEVEL);
143 }
144
145 let page_shift = T::PAGE_SIZE.trailing_zeros() as usize;
151 let total_levels = T::LEVEL_BITS.len();
152
153 let shift = if level == 1 {
155 page_shift
156 } else {
157 page_shift
158 + T::LEVEL_BITS
159 .iter()
160 .skip(total_levels - level + 1)
161 .sum::<usize>()
162 };
163
164 let level_index_bits = T::LEVEL_BITS[total_levels - level];
166 let mask = (1 << level_index_bits) - 1;
167
168 (vaddr.raw() >> shift) & mask
169 }
170
171 pub fn reconstruct_vaddr(index: usize, level: usize, base_vaddr: VirtAddr) -> VirtAddr {
174 let entry_size = Self::level_size(level);
175 base_vaddr + index * entry_size
176 }
177
178 pub fn deallocate_recursive(&mut self, level: usize) {
195 self.deallocate_children(level);
197
198 self.allocator
200 .dealloc_frames(self.paddr, self.frames, T::PAGE_SIZE);
201 }
202
203 pub fn deallocate_children(&mut self, level: usize) {
212 for i in (0..self.len()).rev() {
214 let entry_info = {
216 let entries = self.as_slice();
217 if i < entries.len() {
218 let config = entries[i].to_config(level > 1);
219 (config.valid, config.huge, config.paddr)
220 } else {
221 (false, false, crate::PhysAddr::new(0))
222 }
223 };
224
225 let (is_valid, is_huge, paddr) = entry_info;
226
227 if !is_valid {
228 continue;
229 }
230
231 if is_huge || level == 1 {
233 continue;
234 }
235 else {
237 let mut child_frame = Frame::<T, A>::from_paddr(paddr, self.allocator.clone());
238 child_frame.deallocate_recursive(level - 1);
239
240 let entries_mut = self.as_slice_mut();
242 let invalid_config = PteConfig {
243 valid: false,
244 ..Default::default()
245 };
246 entries_mut[i] = T::P::from_config(invalid_config);
247 }
248 }
249 }
250
251 pub fn translate_recursive(&self, vaddr: VirtAddr, level: usize) -> PagingResult<T::P> {
261 let (pte, _) = self.translate_recursive_with_level(vaddr, level)?;
262 Ok(pte)
263 }
264
265 pub fn translate_recursive_with_level(
275 &self,
276 vaddr: VirtAddr,
277 level: usize,
278 ) -> PagingResult<(T::P, usize)> {
279 let index = Self::virt_to_index(vaddr, level);
281
282 let entries = self.as_slice();
284 let pte = entries[index];
285
286 let config = pte.to_config(level > 1);
288 if !config.valid {
289 return Err(PagingError::not_mapped());
290 }
291
292 if config.huge || level == 1 {
294 return Ok((pte, level));
295 }
296
297 if level > 1 {
299 let child_frame: Frame<T, A> = Frame::from_pte(&pte, level, self.allocator.clone());
300 return child_frame.translate_recursive_with_level(vaddr, level - 1);
301 }
302
303 Err(PagingError::hierarchy_error(
305 "Invalid page table level during translation",
306 ))
307 }
308
309 pub fn dealloc_entry_recursive(&mut self, index: usize, level: usize) -> bool {
320 if index >= self.len() || level <= 1 {
321 return false;
322 }
323
324 let entries = self.as_slice();
325 let entry = &entries[index];
326 let config = entry.to_config(level > 1);
327
328 if config.valid && !config.huge {
329 let mut child_frame = Frame::<T, A>::from_pte(entry, level, self.allocator.clone());
331 child_frame.deallocate_recursive(level - 1);
332
333 let entries_mut = self.as_slice_mut();
335 let invalid_config = PteConfig {
336 valid: false,
337 ..Default::default()
338 };
339 entries_mut[index] = T::P::from_config(invalid_config);
340
341 true
342 } else {
343 false
344 }
345 }
346}
347
348const fn cal_index_bits<T: TableMeta>() -> usize {
349 let mut bits = 0;
350 let len = T::LEVEL_BITS.len();
351 let mut i = 0;
352 while i < len {
353 bits += T::LEVEL_BITS[i];
354 i += 1;
355 }
356 bits
357}