页表实现与核心函数
本节将详细解析页表项 (PageTableEntry) 的结构以及多级页表 (PageTable) 的管理逻辑,特别是涉及到映射建立与拆除的核心函数。
页表项 PageTableEntry
Section titled “页表项 PageTableEntry”RISC-V SV39 架构规定,每个页表项 (PTE) 占据 8 字节(64 位)。
PTEFlags 定义了页表项的权限和状态:
| 标志位 | 名称 | 含义 |
|---|---|---|
| V | Valid | 该页表项是否有效。如果 V=0,访问该页会触发 Page Fault。 |
| R | Readable | 是否可读。 |
| W | Writable | 是否可写。 |
| X | Executable | 是否可执行(是否包含指令)。 |
| U | User | 用户态 (U-mode) 是否可访问。若 U=0,仅 S-mode 可访问。 |
| G | Global | 全局映射(通常用于内核共享区域,本实验不深入讨论)。 |
| A | Accessed | 访问位。当该页被访问(读/写/执行)时,硬件会自动置位。 |
| D | Dirty | 脏位。当该页被写入时,硬件会自动置位。 |
页表结构 PageTable
Section titled “页表结构 PageTable”PageTable 结构体负责管理根页表以及在映射过程中动态分配的中间页表帧:
我们使用 frames 向量持有所有中间页表节点的 FrameTracker。利用 Rust 的 RAII 机制,当 PageTable 被销毁时,这些物理帧会被自动释放,防止内存泄漏。
核心映射函数
Section titled “核心映射函数”在 kernel/src/mm/page_table.rs 中,我们需要实现以下关键函数来管理虚拟内存映射。
查找并创建页表项 find_pte_create
Section titled “查找并创建页表项 find_pte_create”功能:根据给定的虚拟页号 (vpn),在三级页表中查找对应的叶子页表项。
- 如果中间级页表不存在,则从物理内存分配器申请一个新的物理帧,初始化为新的页表,并将其添加到
frames中管理。 - 最终返回指向叶子 PTE 的可变引用,以便后续修改权限或映射物理页。
逻辑流程:
- 从根页表开始,依次根据
vpn的索引(level 2 -> 1 -> 0)查找 PTE。 - 遇到无效的 PTE(V=0),分配新帧,建立链接,继续下一级。
- 到达第三级(level 0)时,返回该 PTE 的引用。
遍历过程(逐级下沉):
三级查找 (只读) find_pte
Section titled “三级查找 (只读) find_pte”函数签名:
作用:找到 VPN 对应的叶子 PTE 的可变引用。若任意中间节点无效,返回 None。
与 find_pte_create 的区别:
find_pte_create | find_pte | |
|---|---|---|
| 接收者 | &mut self | &self |
| 中间节点缺失 | 分配新帧并创建节点 | 返回 None |
| 用途 | 建立新映射(map) | 查询/删除现有映射(translate, unmap) |
参考
find_pte_create函数,仔细思考其中区别
建立映射 map
Section titled “建立映射 map”函数签名:
作用:在页表中建立一个虚拟页到物理页的映射。
实现逻辑:
删除映射 unmap
Section titled “删除映射 unmap”函数签名:
作用:将 VPN 对应的叶子 PTE 清零,解除映射。
实现逻辑:
完整调用链示意
Section titled “完整调用链示意”MapArea::map_one(vpn, page_table) 为例(Framed 映射):
translate 与地址翻译辅助函数
Section titled “translate 与地址翻译辅助函数”translated_byte_buffer 通过上述接口,将用户程序传入的虚拟地址指针
实现用户物理页内的数据复制。