Skip to main content

page_table_generic/
frame.rs

1use crate::{
2    FrameAllocator, PageTableEntry, PagingError, PagingResult, PhysAddr, PteConfig, TableMeta,
3    VirtAddr,
4};
5
6/// 页表帧,代表一个物理页面上的页表
7#[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    /// 创建新的页表帧(分配并清零)
38    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    /// 创建新的根页表帧。
54    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    /// 从物理地址创建Frame(不分配)
73    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    /// 从根页表物理地址创建Frame(不分配)
83    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    /// 从PTE创建子Frame(用于遍历子页表)
93    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    /// 获取页表项的可变切片
99    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    /// 获取页表项的不可变切片
105    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    /// Returns whether this frame range contains no page-table entries.
115    pub fn is_empty(&self) -> bool {
116        self.len() == 0
117    }
118
119    /// 计算指定级别对应的映射大小
120    /// - Level 1 (叶子): PAGE_SIZE
121    /// - Level 2: PAGE_SIZE << LEVEL_BITS[最后一级]
122    /// - Level 3: PAGE_SIZE << (LEVEL_BITS[最后一级] + LEVEL_BITS[倒数第二级])
123    /// - Level N: PAGE_SIZE << (sum of LEVEL_BITS from last to N-1)
124    pub fn level_size(level: usize) -> usize {
125        if level == 1 {
126            return T::PAGE_SIZE;
127        }
128        // 从最后一级开始累加位数,直到当前级别的前一级
129        // 例如:对于 4 级页表 [9,9,9,9],level=3 时,累加 LEVEL_BITS[3] (即最后一级 9 位)
130        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    /// 计算指定级别的页表索引
139    /// 从虚拟地址中提取对应级别的索引位
140    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        // 计算需要跳过的位数(页面偏移 + 低级别索引位)
146        // Level 1 (叶子): shift = page_shift(只跳过页面偏移)
147        // Level 2: shift = page_shift + LEVEL_BITS[最后一级]
148        // Level 3: shift = page_shift + LEVEL_BITS[最后一级] + LEVEL_BITS[倒数第二级]
149        // Level N: shift = page_shift + sum(LEVEL_BITS[N+1..end])
150        let page_shift = T::PAGE_SIZE.trailing_zeros() as usize;
151        let total_levels = T::LEVEL_BITS.len();
152
153        // 累加从最后一级到当前级别之后的所有位数
154        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        // 当前级别的索引位数
165        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    /// 重建完整的虚拟地址
172    /// 从基地址和索引计算完整的虚拟地址
173    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    /// 递归释放当前帧及所有子帧
179    ///
180    /// 此方法会:
181    /// 1. 递归释放所有有效的子页表帧
182    /// 2. 清除所有页表项(设为invalid)
183    /// 3. 释放当前帧
184    ///
185    /// 注意:只释放页表帧,不释放映射的物理页(数据页/大页)
186    ///
187    /// # Parameters
188    /// - `level`: 当前帧所在的页表级别(1=叶子,数字越大级别越高)
189    ///
190    /// # Safety
191    /// 调用者必须确保:
192    /// - 没有其他代码在访问这些页表
193    /// - 没有CPU正在使用这些页表进行地址翻译
194    pub fn deallocate_recursive(&mut self, level: usize) {
195        // 先递归释放所有子帧
196        self.deallocate_children(level);
197
198        // 再释放当前帧
199        self.allocator
200            .dealloc_frames(self.paddr, self.frames, T::PAGE_SIZE);
201    }
202
203    /// 只释放子页表帧,保留当前帧
204    ///
205    /// 遍历当前帧中的所有页表项:
206    /// - 如果是大页或叶子级别的数据页:跳过(不释放物理页,也不清除映射)
207    /// - 如果是非叶子级别的页表指针:递归释放子页表帧,并清除PTE
208    ///
209    /// # Parameters
210    /// - `level`: 当前帧所在的页表级别(1=叶子,数字越大级别越高)
211    pub fn deallocate_children(&mut self, level: usize) {
212        // 反向遍历以避免索引变化问题
213        for i in (0..self.len()).rev() {
214            // 先获取当前PTE的状态
215            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            // 如果是大页或叶子级别的数据页:跳过,保持映射不变
232            if is_huge || level == 1 {
233                continue;
234            }
235            // 否则是非叶子级别的页表指针,递归释放子页表帧
236            else {
237                let mut child_frame = Frame::<T, A>::from_paddr(paddr, self.allocator.clone());
238                child_frame.deallocate_recursive(level - 1);
239
240                // 子页表帧已释放,清除PTE
241                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    /// 递归查找虚拟地址对应的页表项
252    ///
253    /// # 参数
254    /// - `vaddr`: 要查找的虚拟地址
255    /// - `level`: 当前页表级别
256    ///
257    /// # 返回值
258    /// - `Ok(T::P)`: 找到的页表项
259    /// - `Err(PagingError)`: 查找失败
260    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    /// 递归查找虚拟地址对应的页表项,同时返回该PTE所在的级别
266    ///
267    /// # 参数
268    /// - `vaddr`: 要查找的虚拟地址
269    /// - `level`: 当前页表级别
270    ///
271    /// # 返回值
272    /// - `Ok((T::P, usize))`: 找到的页表项及其所在的级别
273    /// - `Err(PagingError)`: 查找失败
274    pub fn translate_recursive_with_level(
275        &self,
276        vaddr: VirtAddr,
277        level: usize,
278    ) -> PagingResult<(T::P, usize)> {
279        // 计算当前级别的页表索引
280        let index = Self::virt_to_index(vaddr, level);
281
282        // 获取页表项
283        let entries = self.as_slice();
284        let pte = entries[index];
285
286        // 检查页表项是否有效
287        let config = pte.to_config(level > 1);
288        if !config.valid {
289            return Err(PagingError::not_mapped());
290        }
291
292        // 如果是大页映射或叶子级别,直接返回页表项及其级别
293        if config.huge || level == 1 {
294            return Ok((pte, level));
295        }
296
297        // 否则,继续递归到下一级页表
298        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        // 不应该到达这里
304        Err(PagingError::hierarchy_error(
305            "Invalid page table level during translation",
306        ))
307    }
308
309    /// 递归释放指定的单个页表项
310    ///
311    /// 如果该PTE指向有效的子页表,则递归释放该子页表及其所有子帧
312    /// 在释放前将PTE设为invalid
313    ///
314    /// 注意:只释放页表帧,不释放映射的物理页
315    ///
316    /// # Parameters
317    /// - `index`: 要释放的PTE索引
318    /// - `level`: 当前帧所在的页表级别
319    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            // 递归释放子帧(子帧的级别是 level - 1)
330            let mut child_frame = Frame::<T, A>::from_pte(entry, level, self.allocator.clone());
331            child_frame.deallocate_recursive(level - 1);
332
333            // 将当前PTE设为invalid
334            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}