os/arch/riscv/mm/
page_table.rs

1// TODO: 这个模块的安全性论证没有完成
2use super::PageTableEntry;
3use crate::mm::address::{ConvertablePaddr, Paddr, PageNum, Ppn, UsizeConvert, Vaddr, Vpn};
4use crate::mm::frame_allocator::{FrameTracker, alloc_frame};
5use crate::mm::page_table::{
6    PageSize, PageTableEntry as PageTableEntryTrait, PageTableInner as PageTableInnerTrait,
7    PagingError, PagingResult, UniversalPTEFlag,
8};
9use alloc::vec::Vec;
10
11#[derive(Debug)]
12pub struct PageTableInner {
13    root: Ppn, // 页表的根物理页号 (Root PPN)
14    // 仅用于存储中间层页表的物理帧,以便在 PageTableInner 析构时自动释放
15    frames: Vec<FrameTracker>,
16    is_user: bool, // 标识是否为用户页表
17}
18
19// RISC-V SV39 架构相关的 PageTableInner 实现
20impl PageTableInnerTrait<PageTableEntry> for PageTableInner {
21    const LEVELS: usize = 3; // SV39 分页方案有 3 级 (0, 1, 2)
22    const MAX_VA_BITS: usize = 39; // 最大有效虚拟地址位数为 39 位
23    const MAX_PA_BITS: usize = 56; // 最大有效物理地址位数为 56 位
24
25    // 对指定虚拟页号 (VPN) 进行 TLB 刷新
26    fn tlb_flush(vpn: Vpn) {
27        let vaddr = vpn.start_addr();
28        // Safe: 使用 RISC-V 指令 sfence.vma 刷新指定虚拟地址的 TLB 条目
29        //      指令正确性: sfence.vma (Synchronize Fence Virtual Memory) 是 RISC-V 规范定义的指令,
30        //                 用于保证 TLB 一致性。它不会导致未定义的行为或内存安全问题。
31        //      权限正确性: 只有在 Supervisor (S) 模式 或更高特权级才能执行 sfence.vma。在操作系统内核中,
32        //                 我们假设这段代码总是在 S 模式下执行,因此指令是合法的。
33        //      参数正确性: 该函数只是将 vpn 转换后的虚拟地址传入指令,该操作不会对内核的内存安全不变性造成破坏。
34        //                 调用此函数是为了修复页表更新后可能存在的 TLB 过期问题,是恢复系统正确状态的必要操作。
35        //      RISC-V 约定: sfence.vma {0}, zero 形式,其中 asid 字段为 zero,表示刷新当前地址空间(ASID)
36        //                 中与该虚拟地址相关的 TLB 条目,或者如果 ASID 机制未使用,则等同于全局刷新。
37        //                 此用法符合 RISC-V 规范。
38        unsafe {
39            // RISC-V 指令:sfence.vma vaddr, asid (asid 为 zero 表示全局刷新或当前 asid)
40            core::arch::asm!(
41                "sfence.vma {0}, zero",
42                in(reg) vaddr.as_usize()
43            )
44        }
45    }
46
47    // 全局 TLB 刷新
48    fn tlb_flush_all() {
49        // Safe: 使用 RISC-V 指令 sfence.vma 刷新所有 TLB 条目
50        unsafe { core::arch::asm!("sfence.vma") }
51    }
52
53    // 检查是否为用户页表
54    fn is_user_table(&self) -> bool {
55        self.is_user
56    }
57
58    // 激活页表 (将页表根 PPN 写入 satp 寄存器)
59    fn activate(ppn: Ppn) {
60        let satp_value = ppn_to_satp(ppn);
61        // Safe: 写入 satp 寄存器并执行全局 TLB 刷新
62        unsafe {
63            // 写入 satp 寄存器并执行全局 TLB 刷新
64            core::arch::asm!(
65                "csrw satp, {0}",
66                "sfence.vma",
67                in(reg) satp_value
68            )
69        }
70    }
71
72    // 获取当前活动的页表根 PPN (从 satp 寄存器读取)
73    fn activating_table_ppn() -> Ppn {
74        let satp_value: usize;
75        unsafe {
76            // 从 satp 寄存器读取值
77            core::arch::asm!("csrr {0}, satp", out(reg) satp_value);
78        }
79        // SV39 中 PPN 位于 satp 值的低 44 位
80        let ppn = satp_value & ((1usize << 44) - 1);
81        Ppn::from_usize(ppn)
82    }
83
84    // 创建一个新的用户页表
85    fn new() -> Self {
86        let frame = alloc_frame().unwrap(); // 分配根页表帧
87        Self {
88            root: frame.ppn(),
89            frames: alloc::vec![frame], // 存储根帧
90            is_user: true,
91        }
92    }
93
94    // 从已有的 PPN 创建页表 (用于内核页表等,不拥有其帧)
95    fn from_ppn(ppn: Ppn) -> Self {
96        Self {
97            root: ppn,
98            frames: Vec::new(), // 不拥有任何中间帧的所有权
99            is_user: true,
100        }
101    }
102
103    // 创建一个新的内核页表
104    fn new_as_kernel_table() -> Self {
105        let frame = alloc_frame().unwrap(); // 分配根页表帧
106        Self {
107            root: frame.ppn(),
108            frames: alloc::vec![frame],
109            is_user: false,
110        }
111    }
112
113    // 获取页表根 PPN
114    fn root_ppn(&self) -> Ppn {
115        self.root
116    }
117
118    // 查找指定级别 (level) 的页表项 (PTE)
119    fn get_entry(&self, vpn: Vpn, level: usize) -> Option<(PageTableEntry, PageSize)> {
120        if level >= Self::LEVELS {
121            return None;
122        }
123
124        let mut ppn = self.root;
125        let vpn_value = vpn.as_usize();
126
127        // 从根级别 (LEVELS-1) 遍历到目标级别 (level)
128        for current_level in (level..Self::LEVELS).rev() {
129            // 计算当前级别的页表项索引:[9 * current_level]
130            let idx = (vpn_value >> (9 * current_level)) & 0x1ff;
131
132            // Unsafe: 将 PPN 转换为虚拟地址并获取页表项数组的不可变引用
133            let pte_array = unsafe {
134                core::slice::from_raw_parts(
135                    ppn.start_addr().to_vaddr().as_usize() as *const PageTableEntry,
136                    512, // 每级页表有 512 个 PTE
137                )
138            };
139            let pte = &pte_array[idx];
140
141            if !pte.is_valid() {
142                return None; // 无效 PTE
143            }
144
145            if current_level == level {
146                // 已到达目标级别
147                // TODO(暂时注释): 当前仅支持4K页
148                // let page_size = match level {
149                //     2 => PageSize::Size1G,
150                //     1 => PageSize::Size2M,
151                //     0 => PageSize::Size4K,
152                //     _ => unreachable!(),
153                // };
154                let page_size = PageSize::Size4K; // 仅支持4K页
155                return Some((*pte, page_size));
156            }
157
158            // 继续下一级页表
159            ppn = pte.ppn();
160        }
161
162        None
163    }
164
165    // 虚拟地址到物理地址的转换 (Translate)
166    fn translate(&self, vaddr: Vaddr) -> Option<Paddr> {
167        let vpn = Vpn::from_addr_ceil(vaddr);
168        // 页内偏移量:低 12 位
169        let offset = vaddr.as_usize() & 0xfff;
170
171        // TODO(暂时注释): 当前仅支持4K页,大页translation逻辑已禁用
172        match self.walk(vpn) {
173            Ok((ppn, page_size, _flags)) => {
174                let paddr_base = match page_size {
175                    PageSize::Size4K => ppn.start_addr().as_usize(),
176                    // TODO(暂时注释): 大页偏移计算
177                    // PageSize::Size2M => {
178                    //     // 对于 2M 页,保留 vaddr 的低 21 位作为页内偏移
179                    //     let offset_2m = vaddr.as_usize() & 0x1f_ffff;
180                    //     ppn.start_addr().as_usize() + offset_2m - offset
181                    // }
182                    // PageSize::Size1G => {
183                    //     // 对于 1G 页,保留 vaddr 的低 30 位作为页内偏移
184                    //     let offset_1g = vaddr.as_usize() & 0x3fff_ffff;
185                    //     ppn.start_addr().as_usize() + offset_1g - offset
186                    // }
187                    _ => ppn.start_addr().as_usize(), // 默认按 4K 页处理基地址
188                };
189                // 物理地址 = 物理页基地址 + 页内偏移
190                Some(Paddr::from_usize(paddr_base + offset))
191            }
192            Err(_) => None,
193        }
194    }
195
196    // 建立虚拟页号 (VPN) 到物理页号 (PPN) 的映射 (Map)
197    fn map(
198        &mut self,
199        vpn: Vpn,
200        ppn: Ppn,
201        _page_size: PageSize,
202        flags: UniversalPTEFlag,
203    ) -> PagingResult<()> {
204        // 验证标志位:叶子节点必须至少有 R/W/X 之一被设置
205        if !flags.intersects(
206            UniversalPTEFlag::READABLE | UniversalPTEFlag::WRITEABLE | UniversalPTEFlag::EXECUTABLE,
207        ) {
208            return Err(PagingError::InvalidFlags);
209        }
210
211        // TODO(暂时注释): 当前仅支持4K页,强制使用 level 0
212        // 根据页大小确定目标级别
213        // let target_level = match page_size {
214        //     PageSize::Size1G => 2,
215        //     PageSize::Size2M => 1,
216        //     PageSize::Size4K => 0,
217        // };
218        let target_level = 0; // 仅支持 4K 页
219
220        let mut current_ppn = self.root;
221        let vpn_value = vpn.as_usize();
222
223        // 从根级别 (LEVELS-1) 遍历到目标级别 (target_level)
224        for level in (target_level..Self::LEVELS).rev() {
225            let idx = (vpn_value >> (9 * level)) & 0x1ff;
226
227            // Unsafe: 获取可变的页表项数组引用
228            let pte_array = unsafe {
229                core::slice::from_raw_parts_mut(
230                    current_ppn.start_addr().to_vaddr().as_usize() as *mut PageTableEntry,
231                    512,
232                )
233            };
234            let pte = &mut pte_array[idx];
235
236            if level == target_level {
237                // 已到达目标级别,创建叶子节点
238                if pte.is_valid() {
239                    return Err(PagingError::AlreadyMapped); // 已被映射
240                }
241                // 创建新的叶子 PTE,设置 PPN 和标志位 (VALID 必须设置)
242                *pte = PageTableEntry::new_leaf(ppn, flags | UniversalPTEFlag::VALID);
243
244                // 刷新 TLB 确保新映射对 CPU 可见
245                // 这对于已激活的页表尤其重要,可防止 TLB 中的过时条目
246                Self::tlb_flush(vpn);
247                return Ok(());
248            } else {
249                // 中间级别 - 需要继续向下遍历
250                if !pte.is_valid() {
251                    // 页表项无效,需要分配一个新的页表
252                    let new_frame = alloc_frame().ok_or(PagingError::FrameAllocFailed)?;
253                    let new_ppn = new_frame.ppn();
254
255                    // 清空新的页表(即新分配的物理页)
256                    // Unsafe: 获取可变的页表项数组引用并清零
257                    let new_table = unsafe {
258                        core::slice::from_raw_parts_mut(
259                            new_ppn.start_addr().to_vaddr().as_usize() as *mut PageTableEntry,
260                            512,
261                        )
262                    };
263                    for entry in new_table.iter_mut() {
264                        *entry = PageTableEntry::empty();
265                    }
266
267                    // 更新当前级别的 PTE,指向新分配的页表 (VALID 标志在 new_table 中设置)
268                    *pte = PageTableEntry::new_table(new_ppn);
269                    self.frames.push(new_frame); // 将新帧加入向量,以便自动释放
270                } else if pte.is_huge() {
271                    // 此处已有一个巨页映射,产生冲突
272                    return Err(PagingError::HugePageConflict);
273                }
274
275                // 准备下一轮循环,进入下一级页表
276                current_ppn = pte.ppn();
277            }
278        }
279
280        Err(PagingError::InvalidAddress) // 理论上不应该到达
281    }
282
283    // 解除虚拟页号 (VPN) 映射 (Unmap)
284    fn unmap(&mut self, vpn: Vpn) -> PagingResult<()> {
285        let mut current_ppn = self.root;
286        let vpn_value = vpn.as_usize();
287
288        // 遍历页表以找到叶子节点
289        for level in (0..Self::LEVELS).rev() {
290            let idx = (vpn_value >> (9 * level)) & 0x1ff;
291
292            // Unsafe: 获取可变的页表项数组引用
293            let pte_array = unsafe {
294                core::slice::from_raw_parts_mut(
295                    current_ppn.start_addr().to_vaddr().as_usize() as *mut PageTableEntry,
296                    512,
297                )
298            };
299            let pte = &mut pte_array[idx];
300
301            if !pte.is_valid() {
302                return Err(PagingError::NotMapped); // 未映射
303            }
304
305            // 检查是否为叶子节点 (具有 R/W/X 权限或已到达 level 0)
306            if pte.is_huge() || level == 0 {
307                // 清空 PTE 以解除映射
308                pte.clear();
309                Self::tlb_flush(vpn); // 刷新 TLB
310                return Ok(());
311            }
312
313            // 继续下一级页表
314            current_ppn = pte.ppn();
315        }
316
317        Err(PagingError::NotMapped) // 理论上不应该到达
318    }
319
320    // 移动映射 (先解除旧映射,再建立新映射)
321    fn mvmap(
322        &mut self,
323        vpn: Vpn,
324        target_ppn: Ppn,
325        page_size: PageSize,
326        flags: UniversalPTEFlag,
327    ) -> PagingResult<()> {
328        // 先解除旧映射
329        self.unmap(vpn)?;
330        // 再映射到新的物理页
331        self.map(vpn, target_ppn, page_size, flags)
332    }
333
334    // 更新指定 VPN 的页表项标志位
335    fn update_flags(&mut self, vpn: Vpn, flags: UniversalPTEFlag) -> PagingResult<()> {
336        let mut current_ppn = self.root;
337        let vpn_value = vpn.as_usize();
338
339        // 遍历页表以找到叶子节点
340        for level in (0..Self::LEVELS).rev() {
341            let idx = (vpn_value >> (9 * level)) & 0x1ff;
342
343            // Unsafe: 获取可变的页表项数组引用
344            let pte_array = unsafe {
345                core::slice::from_raw_parts_mut(
346                    current_ppn.start_addr().to_vaddr().as_usize() as *mut PageTableEntry,
347                    512,
348                )
349            };
350            let pte = &mut pte_array[idx];
351
352            if !pte.is_valid() {
353                return Err(PagingError::NotMapped); // 未映射
354            }
355
356            // 检查是否为叶子节点
357            if pte.is_huge() || level == 0 {
358                // 设置新的标志位 (VALID 必须保持设置)
359                pte.set_flags(flags | UniversalPTEFlag::VALID);
360                Self::tlb_flush(vpn); // 刷新 TLB
361                return Ok(());
362            }
363
364            // 继续下一级页表
365            current_ppn = pte.ppn();
366        }
367
368        Err(PagingError::NotMapped) // 理论上不应该到达
369    }
370
371    // 遍历页表 (Walk),查找指定 VPN 的映射信息
372    fn walk(&self, vpn: Vpn) -> PagingResult<(Ppn, PageSize, UniversalPTEFlag)> {
373        let mut ppn = self.root;
374        let vpn_value = vpn.as_usize();
375
376        // SV39 级别划分:VPN[2] = 位[38:30], VPN[1] = 位[29:21], VPN[0] = 位[20:12]
377        // 从最高级 (Level 2) 遍历到最低级 (Level 0)
378        for level in (0..Self::LEVELS).rev() {
379            let idx = (vpn_value >> (9 * level)) & 0x1ff;
380
381            // Unsafe: 获取页表项数组的不可变引用
382            let pte_array = unsafe {
383                core::slice::from_raw_parts(
384                    ppn.start_addr().to_vaddr().as_usize() as *const PageTableEntry,
385                    512,
386                )
387            };
388            let pte = &pte_array[idx];
389
390            if !pte.is_valid() {
391                return Err(PagingError::NotMapped); // 无效 PTE
392            }
393
394            // 检查是否为叶子节点
395            if pte.is_huge() || level == 0 {
396                // 找到叶子节点
397                // TODO(暂时注释): 当前仅支持4K页
398                // let page_size = match level {
399                //     2 => PageSize::Size1G,
400                //     1 => PageSize::Size2M,
401                //     0 => PageSize::Size4K,
402                //     _ => unreachable!(),
403                // };
404                let page_size = PageSize::Size4K; // 仅支持 4K 页
405                return Ok((pte.ppn(), page_size, pte.flags()));
406            }
407
408            // 继续下一级页表
409            ppn = pte.ppn();
410        }
411
412        Err(PagingError::NotMapped) // 未找到映射
413    }
414}
415
416// 辅助函数:将 PPN 转换为 satp 寄存器的值
417fn ppn_to_satp(ppn: Ppn) -> usize {
418    // 设置 MODE=8 (SV39) 并与 PPN 进行位或操作
419    ppn.as_usize() | (8usize << 60)
420}
421
422// 单元测试模块
423#[cfg(test)]
424mod page_table_tests {
425    use super::*;
426    use crate::mm::page_table::PageTableInner as PageTableInnerTrait;
427    use crate::{kassert, test_case};
428
429    // 1. 页表创建测试
430    test_case!(test_pt_create, {
431        let pt = PageTableInner::new();
432        // 根 PPN 应该有效 (大于 0)
433        kassert!(pt.root_ppn().as_usize() > 0);
434        // 默认创建为用户页表
435        kassert!(pt.is_user_table());
436    });
437
438    // 2. 映射与转换测试
439    test_case!(test_pt_map_translate, {
440        let mut pt = PageTableInner::new();
441        let vpn = Vpn::from_usize(0x1000);
442        let ppn = Ppn::from_usize(0x80000);
443
444        // 映射 vpn -> ppn
445        let result = pt.map(vpn, ppn, PageSize::Size4K, UniversalPTEFlag::kernel_rw());
446        kassert!(result.is_ok());
447
448        // 转换验证 - 使用 vpn.start_addr() 获取正确的虚拟地址
449        let vaddr = vpn.start_addr();
450        let translated = pt.translate(vaddr);
451        kassert!(translated.is_some());
452        let paddr = translated.unwrap();
453        // 验证转换后的物理页号是否正确
454        kassert!(paddr.as_usize() >> 12 == ppn.as_usize());
455    });
456
457    // 3. 解除映射测试
458    test_case!(test_pt_unmap, {
459        let mut pt = PageTableInner::new();
460        let vpn = Vpn::from_usize(0x1000);
461        let ppn = Ppn::from_usize(0x80000);
462
463        // 先映射
464        pt.map(vpn, ppn, PageSize::Size4K, UniversalPTEFlag::kernel_rw())
465            .unwrap();
466
467        // 解除映射
468        let result = pt.unmap(vpn);
469        kassert!(result.is_ok());
470
471        // 应该不再被映射
472        let vaddr = vpn.start_addr();
473        let translated = pt.translate(vaddr);
474        kassert!(translated.is_none());
475    });
476
477    // 4. 错误测试:已映射
478    test_case!(test_pt_error_already_mapped, {
479        let mut pt = PageTableInner::new();
480        let vpn = Vpn::from_usize(0x1000);
481
482        // 第一次映射成功
483        let result1 = pt.map(
484            vpn,
485            Ppn::from_usize(0x80000),
486            PageSize::Size4K,
487            UniversalPTEFlag::kernel_rw(),
488        );
489        kassert!(result1.is_ok());
490
491        // 第二次映射应该失败 (返回 AlreadyMapped 错误)
492        let result2 = pt.map(
493            vpn,
494            Ppn::from_usize(0x80001),
495            PageSize::Size4K,
496            UniversalPTEFlag::kernel_rw(),
497        );
498        kassert!(result2.is_err());
499    });
500
501    // 5. 页表遍历 (Walk) 测试
502    test_case!(test_pt_walk, {
503        let mut pt = PageTableInner::new();
504        let vpn = Vpn::from_usize(0x1000);
505        let ppn = Ppn::from_usize(0x80000);
506        let original_flags = UniversalPTEFlag::kernel_rw();
507
508        // 先映射
509        pt.map(vpn, ppn, PageSize::Size4K, original_flags).unwrap();
510
511        // 遍历获取映射信息
512        let walk_result = pt.walk(vpn);
513        kassert!(walk_result.is_ok());
514
515        let (mapped_ppn, _, mapped_flags) = walk_result.unwrap();
516        kassert!(mapped_ppn == ppn);
517        // 创建新的flags实例用于比较,避免所有权问题
518        let expected_flags = UniversalPTEFlag::kernel_rw();
519        kassert!(mapped_flags.bits() == expected_flags.bits());
520    });
521
522    // 6. 更新标志位测试
523    test_case!(test_pt_update_flags, {
524        let mut pt = PageTableInner::new();
525        let vpn = Vpn::from_usize(0x1000);
526        let ppn = Ppn::from_usize(0x80000);
527
528        // 初始映射为 kernel_rw
529        pt.map(vpn, ppn, PageSize::Size4K, UniversalPTEFlag::kernel_rw())
530            .unwrap();
531
532        // 更新为内核只读 (kernel_r)
533        let update_flags = UniversalPTEFlag::kernel_r();
534        let result = pt.update_flags(vpn, update_flags);
535        kassert!(result.is_ok());
536
537        // 验证标志位是否已更改
538        let (_, _, flags) = pt.walk(vpn).unwrap();
539        // 创建新的flags实例用于比较,避免所有权问题
540        let expected_flags = UniversalPTEFlag::kernel_r();
541        kassert!(flags.bits() == expected_flags.bits());
542    });
543
544    // 7. 多重映射测试
545    test_case!(test_pt_multiple_mappings, {
546        let mut pt = PageTableInner::new();
547
548        // 映射多个 VPN
549        for i in 0..10 {
550            let vpn = Vpn::from_usize(0x1000 + i);
551            let ppn = Ppn::from_usize(0x80000 + i);
552            let result = pt.map(vpn, ppn, PageSize::Size4K, UniversalPTEFlag::kernel_rw());
553            kassert!(result.is_ok());
554        }
555
556        // 验证所有映射
557        for i in 0..10 {
558            let vpn = Vpn::from_usize(0x1000 + i);
559            let expected_ppn = Ppn::from_usize(0x80000 + i);
560            let (mapped_ppn, _, _) = pt.walk(vpn).unwrap();
561            kassert!(mapped_ppn == expected_ppn);
562        }
563    });
564}