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    _marker: core::marker::PhantomData<T>,
12}
13
14impl<T: TableMeta, A: FrameAllocator> core::fmt::Debug for Frame<T, A> {
15    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
16        f.debug_struct("Frame")
17            .field("paddr", &format_args!("{:#x}", self.paddr.raw()))
18            .finish()
19    }
20}
21
22impl<T, A> Frame<T, A>
23where
24    T: TableMeta,
25    A: FrameAllocator,
26{
27    pub(crate) const PT_INDEX_SHIFT: usize = T::PAGE_SIZE.trailing_zeros() as usize;
28    pub(crate) const PT_INDEX_BITS: usize = cal_index_bits::<T>();
29    pub(crate) const PT_VALID_BITS: usize = Self::PT_INDEX_BITS + Self::PT_INDEX_SHIFT;
30    pub(crate) const LEN: usize = T::PAGE_SIZE / core::mem::size_of::<T::P>();
31    pub(crate) const PT_LEVEL: usize = T::LEVEL_BITS.len();
32
33    /// 创建新的页表帧(分配并清零)
34    pub fn new(allocator: A) -> PagingResult<Self> {
35        let paddr = allocator.alloc_frame().ok_or(PagingError::NoMemory)?;
36        unsafe {
37            let vaddr = allocator.phys_to_virt(paddr);
38            core::ptr::write_bytes(vaddr, 0, T::PAGE_SIZE);
39        }
40
41        Ok(Self {
42            paddr,
43            allocator,
44            _marker: core::marker::PhantomData,
45        })
46    }
47
48    /// 从物理地址创建Frame(不分配)
49    pub fn from_paddr(paddr: PhysAddr, allocator: A) -> Self {
50        Self {
51            paddr,
52            allocator,
53            _marker: core::marker::PhantomData,
54        }
55    }
56
57    /// 从PTE创建子Frame(用于遍历子页表)
58    pub fn from_pte(pte: &T::P, level: usize, allocator: A) -> Self {
59        let config = pte.to_config(level > 1);
60        Self::from_paddr(config.paddr, allocator)
61    }
62
63    /// 获取页表项的可变切片
64    pub fn as_slice_mut(&mut self) -> &mut [T::P] {
65        let vaddr = self.allocator.phys_to_virt(self.paddr);
66        unsafe { core::slice::from_raw_parts_mut(vaddr as *mut T::P, Self::LEN) }
67    }
68
69    /// 获取页表项的不可变切片
70    pub fn as_slice(&self) -> &[T::P] {
71        let vaddr = self.allocator.phys_to_virt(self.paddr);
72        unsafe { core::slice::from_raw_parts(vaddr as *const T::P, Self::LEN) }
73    }
74
75    /// 计算指定级别对应的映射大小
76    /// - Level 1 (叶子): PAGE_SIZE
77    /// - Level 2: PAGE_SIZE << LEVEL_BITS[最后一级]
78    /// - Level 3: PAGE_SIZE << (LEVEL_BITS[最后一级] + LEVEL_BITS[倒数第二级])
79    /// - Level N: PAGE_SIZE << (sum of LEVEL_BITS from last to N-1)
80    pub fn level_size(level: usize) -> usize {
81        if level == 1 {
82            return T::PAGE_SIZE;
83        }
84        // 从最后一级开始累加位数,直到当前级别的前一级
85        // 例如:对于 4 级页表 [9,9,9,9],level=3 时,累加 LEVEL_BITS[3] (即最后一级 9 位)
86        let total_levels = T::LEVEL_BITS.len();
87        let shift = T::LEVEL_BITS
88            .iter()
89            .skip(total_levels - level + 1)
90            .sum::<usize>();
91        T::PAGE_SIZE << shift
92    }
93
94    /// 计算指定级别的页表索引
95    /// 从虚拟地址中提取对应级别的索引位
96    pub fn virt_to_index(vaddr: VirtAddr, level: usize) -> usize {
97        if level == 0 || level > Self::PT_LEVEL {
98            panic!("Invalid level: {} (valid: 1..={})", level, Self::PT_LEVEL);
99        }
100
101        // 计算需要跳过的位数(页面偏移 + 低级别索引位)
102        // Level 1 (叶子): shift = page_shift(只跳过页面偏移)
103        // Level 2: shift = page_shift + LEVEL_BITS[最后一级]
104        // Level 3: shift = page_shift + LEVEL_BITS[最后一级] + LEVEL_BITS[倒数第二级]
105        // Level N: shift = page_shift + sum(LEVEL_BITS[N+1..end])
106        let page_shift = T::PAGE_SIZE.trailing_zeros() as usize;
107        let total_levels = T::LEVEL_BITS.len();
108
109        // 累加从最后一级到当前级别之后的所有位数
110        let shift = if level == 1 {
111            page_shift
112        } else {
113            page_shift
114                + T::LEVEL_BITS
115                    .iter()
116                    .skip(total_levels - level + 1)
117                    .sum::<usize>()
118        };
119
120        // 当前级别的索引位数
121        let level_index_bits = T::LEVEL_BITS[total_levels - level];
122        let mask = (1 << level_index_bits) - 1;
123
124        (vaddr.raw() >> shift) & mask
125    }
126
127    /// 重建完整的虚拟地址
128    /// 从基地址和索引计算完整的虚拟地址
129    pub fn reconstruct_vaddr(index: usize, level: usize, base_vaddr: VirtAddr) -> VirtAddr {
130        let entry_size = Self::level_size(level);
131        base_vaddr + index * entry_size
132    }
133
134    /// 递归释放当前帧及所有子帧
135    ///
136    /// 此方法会:
137    /// 1. 递归释放所有有效的子页表帧
138    /// 2. 清除所有页表项(设为invalid)
139    /// 3. 释放当前帧
140    ///
141    /// 注意:只释放页表帧,不释放映射的物理页(数据页/大页)
142    ///
143    /// # Parameters
144    /// - `level`: 当前帧所在的页表级别(1=叶子,数字越大级别越高)
145    ///
146    /// # Safety
147    /// 调用者必须确保:
148    /// - 没有其他代码在访问这些页表
149    /// - 没有CPU正在使用这些页表进行地址翻译
150    pub fn deallocate_recursive(&mut self, level: usize) {
151        // 先递归释放所有子帧
152        self.deallocate_children(level);
153
154        // 再释放当前帧
155        self.allocator.dealloc_frame(self.paddr);
156    }
157
158    /// 只释放子页表帧,保留当前帧
159    ///
160    /// 遍历当前帧中的所有页表项:
161    /// - 如果是大页或叶子级别的数据页:跳过(不释放物理页,也不清除映射)
162    /// - 如果是非叶子级别的页表指针:递归释放子页表帧,并清除PTE
163    ///
164    /// # Parameters
165    /// - `level`: 当前帧所在的页表级别(1=叶子,数字越大级别越高)
166    pub fn deallocate_children(&mut self, level: usize) {
167        // 反向遍历以避免索引变化问题
168        for i in (0..Self::LEN).rev() {
169            // 先获取当前PTE的状态
170            let entry_info = {
171                let entries = self.as_slice();
172                if i < entries.len() {
173                    let config = entries[i].to_config(level > 1);
174                    (config.valid, config.huge, config.paddr)
175                } else {
176                    (false, false, crate::PhysAddr::new(0))
177                }
178            };
179
180            let (is_valid, is_huge, paddr) = entry_info;
181
182            if !is_valid {
183                continue;
184            }
185
186            // 如果是大页或叶子级别的数据页:跳过,保持映射不变
187            if is_huge || level == 1 {
188                continue;
189            }
190            // 否则是非叶子级别的页表指针,递归释放子页表帧
191            else {
192                let mut child_frame = Frame::<T, A>::from_paddr(paddr, self.allocator.clone());
193                child_frame.deallocate_recursive(level - 1);
194
195                // 子页表帧已释放,清除PTE
196                let entries_mut = self.as_slice_mut();
197                let invalid_config = PteConfig {
198                    valid: false,
199                    ..Default::default()
200                };
201                entries_mut[i] = T::P::from_config(invalid_config);
202            }
203        }
204    }
205
206    /// 递归查找虚拟地址对应的页表项
207    ///
208    /// # 参数
209    /// - `vaddr`: 要查找的虚拟地址
210    /// - `level`: 当前页表级别
211    ///
212    /// # 返回值
213    /// - `Ok(T::P)`: 找到的页表项
214    /// - `Err(PagingError)`: 查找失败
215    pub fn translate_recursive(&self, vaddr: VirtAddr, level: usize) -> PagingResult<T::P> {
216        let (pte, _) = self.translate_recursive_with_level(vaddr, level)?;
217        Ok(pte)
218    }
219
220    /// 递归查找虚拟地址对应的页表项,同时返回该PTE所在的级别
221    ///
222    /// # 参数
223    /// - `vaddr`: 要查找的虚拟地址
224    /// - `level`: 当前页表级别
225    ///
226    /// # 返回值
227    /// - `Ok((T::P, usize))`: 找到的页表项及其所在的级别
228    /// - `Err(PagingError)`: 查找失败
229    pub fn translate_recursive_with_level(
230        &self,
231        vaddr: VirtAddr,
232        level: usize,
233    ) -> PagingResult<(T::P, usize)> {
234        // 计算当前级别的页表索引
235        let index = Self::virt_to_index(vaddr, level);
236
237        // 获取页表项
238        let entries = self.as_slice();
239        let pte = entries[index];
240
241        // 检查页表项是否有效
242        let config = pte.to_config(level > 1);
243        if !config.valid {
244            return Err(PagingError::not_mapped());
245        }
246
247        // 如果是大页映射或叶子级别,直接返回页表项及其级别
248        if config.huge || level == 1 {
249            return Ok((pte, level));
250        }
251
252        // 否则,继续递归到下一级页表
253        if level > 1 {
254            let child_frame: Frame<T, A> = Frame::from_pte(&pte, level, self.allocator.clone());
255            return child_frame.translate_recursive_with_level(vaddr, level - 1);
256        }
257
258        // 不应该到达这里
259        Err(PagingError::hierarchy_error(
260            "Invalid page table level during translation",
261        ))
262    }
263
264    /// 递归释放指定的单个页表项
265    ///
266    /// 如果该PTE指向有效的子页表,则递归释放该子页表及其所有子帧
267    /// 在释放前将PTE设为invalid
268    ///
269    /// 注意:只释放页表帧,不释放映射的物理页
270    ///
271    /// # Parameters
272    /// - `index`: 要释放的PTE索引
273    /// - `level`: 当前帧所在的页表级别
274    pub fn dealloc_entry_recursive(&mut self, index: usize, level: usize) -> bool {
275        if index >= Self::LEN || level <= 1 {
276            return false;
277        }
278
279        let entries = self.as_slice();
280        let entry = &entries[index];
281        let config = entry.to_config(level > 1);
282
283        if config.valid && !config.huge {
284            // 递归释放子帧(子帧的级别是 level - 1)
285            let mut child_frame = Frame::<T, A>::from_pte(entry, level, self.allocator.clone());
286            child_frame.deallocate_recursive(level - 1);
287
288            // 将当前PTE设为invalid
289            let entries_mut = self.as_slice_mut();
290            let invalid_config = PteConfig {
291                valid: false,
292                ..Default::default()
293            };
294            entries_mut[index] = T::P::from_config(invalid_config);
295
296            true
297        } else {
298            false
299        }
300    }
301}
302
303const fn cal_index_bits<T: TableMeta>() -> usize {
304    let mut bits = 0;
305    let len = T::LEVEL_BITS.len();
306    let mut i = 0;
307    while i < len {
308        bits += T::LEVEL_BITS[i];
309        i += 1;
310    }
311    bits
312}