os/arch/riscv/mm/
page_table_entry.rs

1use crate::mm::address::{Ppn, UsizeConvert};
2use crate::mm::page_table::PageTableEntry as PageTableEntryTrait;
3use crate::mm::page_table::{UniversalConvertableFlag, UniversalPTEFlag};
4
5// 使用 bitflags 宏定义 SV39 页表项的标志位
6bitflags::bitflags! {
7    pub struct SV39PTEFlags: usize {
8        const VALID = 1 << 0;       // 指示页表项是否有效
9        const READ = 1 << 1;        // 指示页面是否可读 (R)
10        const WRITE = 1 << 2;       // 指示页面是否可写 (W)
11        const EXECUTE = 1 << 3;     // 指示页面是否可执行 (X)
12        const USER = 1 << 4;        // 指示页面是否允许用户模式访问 (U)
13        const GLOBAL = 1 << 5;      // 指示页面是否为全局页 (G)
14        const ACCESSED = 1 << 6;    // 指示页面是否已被访问 (A)
15        const DIRTY = 1 << 7;       // 指示页面是否已被写入 (D)
16        const _RESERVED = 1 << 8;   // 保留位,供将来使用 (根据 SV39 规范)
17    }
18}
19
20/*
21 * SV39 页表项 (PTE) 格式:
22 * ------------------------------------------------
23 * | 位数  | 描述                                |
24 * ------------------------------------------------
25 * | 0-7   | 标志位 (有效、读、写、执行、用户、      |
26 * |       | 全局、已访问、脏)                     |
27 * ------------------------------------------------
28 * | 8-9   | 保留 (必须为零)                      |
29 * ------------------------------------------------
30 * | 10-53 | 物理页号 (PPN)                      |
31 * ------------------------------------------------
32 * | 54-63 | 保留 (必须为零)                     |
33 * ------------------------------------------------
34 */
35
36const SV39_PTE_FLAG_MASK: usize = 0xff; // SV39 PTE 标志位,占用低 8 位
37const SV39_PTE_PPN_OFFSET: usize = 10; // 物理页号 (PPN) 从第 10 位开始
38const SV39_PTE_PPN_MASK: u64 = 0x0000_ffff_ffff_fc00; // PPN 掩码,覆盖位 10-53
39
40// 实现通用标志位与 SV39 特定标志位之间的转换
41impl UniversalConvertableFlag for SV39PTEFlags {
42    // 从通用标志位转换为 SV39 标志位
43    fn from_universal(flag: UniversalPTEFlag) -> Self {
44        // 仅保留 SV39 定义的低 8 位标志
45        Self::from_bits(flag.bits() & SV39_PTE_FLAG_MASK).unwrap()
46    }
47
48    // 将 SV39 标志位转换为通用标志位
49    fn to_universal(&self) -> UniversalPTEFlag {
50        UniversalPTEFlag::from_bits(self.bits() & SV39_PTE_FLAG_MASK).unwrap()
51    }
52}
53
54// 页表项结构体,内部存储为 64 位整数
55#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord)]
56pub struct PageTableEntry(u64);
57
58// 实现页表项的通用特性 (PageTableEntryTrait)
59impl PageTableEntryTrait for PageTableEntry {
60    type Bits = u64; // 底层位类型
61
62    // 从原始位创建页表项
63    fn from_bits(bits: Self::Bits) -> Self {
64        PageTableEntry(bits)
65    }
66
67    // 获取页表项的原始位
68    fn to_bits(&self) -> Self::Bits {
69        self.0
70    }
71
72    // 创建一个空的页表项 (所有位为零)
73    fn empty() -> Self {
74        PageTableEntry(0)
75    }
76
77    // 创建一个新的叶子节点 (指向实际页面) 的页表项
78    fn new_leaf(ppn: Ppn, flags: UniversalPTEFlag) -> Self {
79        let ppn_bits: u64 = ppn.as_usize() as u64;
80        let sv39_flags = SV39PTEFlags::from_universal(flags);
81        // PPN 左移 10 位,并与标志位进行位或操作
82        PageTableEntry((ppn_bits << SV39_PTE_PPN_OFFSET) | (sv39_flags.bits() as u64))
83    }
84
85    // 创建一个新的表节点 (指向下一级页表) 的页表项
86    fn new_table(ppn: Ppn) -> Self {
87        let ppn_bits: u64 = ppn.as_usize() as u64;
88        // 表节点只需设置 VALID 标志位
89        let sv39_flags = SV39PTEFlags::VALID;
90        PageTableEntry((ppn_bits << SV39_PTE_PPN_OFFSET) | (sv39_flags.bits() as u64))
91    }
92
93    // 检查页表项是否有效 (即最低位是否设置)
94    fn is_valid(&self) -> bool {
95        (self.0 & SV39PTEFlags::VALID.bits() as u64) != 0
96    }
97
98    // 检查页表项是否代表巨页 (Huge Page)
99    fn is_huge(&self) -> bool {
100        // 在 SV39 中,我们无法仅凭 PTE 自身直接判断巨页。
101        // 如果 PTE 带有 R/W/X 权限,则被视为叶子节点 (可能是巨页或普通页),
102        // 否则它是一个指向下一级页表的中间节点。
103        let sv39_flags =
104            SV39PTEFlags::from_bits((self.0 & SV39_PTE_FLAG_MASK as u64) as usize).unwrap();
105        // 检查是否与 R 或 X 或 W 权限相交
106        sv39_flags.intersects(
107            SV39PTEFlags::union(SV39PTEFlags::READ, SV39PTEFlags::EXECUTE)
108                .union(SV39PTEFlags::WRITE),
109        )
110    }
111
112    // 检查页表项是否为空 (所有位为零)
113    fn is_empty(&self) -> bool {
114        self.0 == 0
115    }
116
117    // 获取页表项中的物理页号 (PPN)
118    fn ppn(&self) -> Ppn {
119        // 提取 PPN 位,并右移 10 位
120        let ppn = (self.0 & SV39_PTE_PPN_MASK) >> SV39_PTE_PPN_OFFSET;
121        Ppn::from_usize(ppn as usize)
122    }
123
124    // 获取页表项中的标志位 (转换为通用格式)
125    fn flags(&self) -> UniversalPTEFlag {
126        // 提取低 8 位标志
127        let sv39_flags =
128            SV39PTEFlags::from_bits((self.0 & SV39_PTE_FLAG_MASK as u64) as usize).unwrap();
129        sv39_flags.to_universal()
130    }
131
132    // 设置页表项中的物理页号 (PPN)
133    fn set_ppn(&mut self, ppn: Ppn) {
134        let ppn_bits = ppn.as_usize() as u64;
135        // 清除旧的 PPN 位,并设置新的 PPN 位
136        self.0 = (self.0 & !SV39_PTE_PPN_MASK) | (ppn_bits << SV39_PTE_PPN_OFFSET);
137    }
138
139    // 设置页表项中的标志位
140    fn set_flags(&mut self, flags: UniversalPTEFlag) {
141        let sv39_flags = SV39PTEFlags::from_universal(flags);
142        // 清除旧的标志位,并设置新的标志位
143        self.0 = (self.0 & !(SV39_PTE_FLAG_MASK as u64)) | (sv39_flags.bits() as u64);
144    }
145
146    // 清空页表项 (设置为零)
147    fn clear(&mut self) {
148        self.0 = 0;
149    }
150
151    // 移除指定的标志位 (current_flags & !flags)
152    fn remove_flags(&mut self, flags: UniversalPTEFlag) {
153        let current_flags = self.flags();
154        let new_flags = current_flags & !flags;
155        self.set_flags(new_flags);
156    }
157
158    // 添加指定的标志位 (current_flags | flags)
159    fn add_flags(&mut self, flags: UniversalPTEFlag) {
160        self.set_flags(self.flags() | flags);
161    }
162}