os/mm/address/
page_num.rs

1//! 页码抽象模块
2//!
3//! 此模块定义了表示页码 (Page Number) 的 Trait 和具体的页码类型 (Ppn, Vpn),
4//! 以及用于处理连续页码的范围结构 (PageNumRange)。
5//!
6//! 页码是地址空间中页 (Page) 的索引,它将内存管理抽象与底层硬件地址解耦。
7
8use crate::config::PAGE_SIZE;
9use crate::mm::address::address::{Address, Paddr, Vaddr};
10use crate::mm::address::operations::{AlignOps, CalcOps, UsizeConvert};
11use core::ops::Range;
12
13/// [PageNum] Trait
14/// ---------------------
15/// 表示一个页码的 Trait。所有页码类型 (如 Ppn 和 Vpn) 必须实现此 Trait。
16///
17/// 它依赖于 `CalcOps` (算术和位操作) 和 `UsizeConvert` (与 usize 转换)。
18pub trait PageNum:
19    CalcOps + UsizeConvert + Copy + Clone + PartialEq + PartialOrd + Eq + Ord
20{
21    /// 此页码类型关联的地址类型(例如 Ppn 关联 Paddr,Vpn 关联 Vaddr)。
22    type TAddress: Address + AlignOps; // PageNum 的地址需要支持 AlignOps
23
24    /// 将页码增加 1。
25    fn step(&mut self) {
26        self.step_by(1);
27    }
28
29    /// 将页码增加给定的偏移量 (页数)。
30    ///
31    /// # 参数
32    /// * `offset`: 要增加的页数。
33    fn step_by(&mut self, offset: usize) {
34        *self = Self::from_usize(self.as_usize() + offset);
35    }
36
37    /// 将页码减少 1。
38    fn step_back(&mut self) {
39        self.step_back_by(1);
40    }
41
42    /// 将页码减少给定的偏移量 (页数)。
43    ///
44    /// # 参数
45    /// * `offset`: 要减少的页数。
46    fn step_back_by(&mut self, offset: usize) {
47        *self = Self::from_usize(self.as_usize() - offset);
48    }
49
50    /// 将地址转换为页码 (向下取整,即页的起始页码)。
51    ///
52    /// # 参数
53    /// * `addr`: 要转换的地址。
54    ///
55    /// # 返回
56    /// 包含该地址的页的页码。
57    fn from_addr_floor(addr: Self::TAddress) -> Self {
58        // 先向下对齐到页边界,再除以页大小 PAGE_SIZE
59        Self::from_usize(addr.align_down_to_page().as_usize() / PAGE_SIZE)
60    }
61
62    /// 将地址转换为页码 (向上取整,即如果地址未对齐,则指向下一个页码)。
63    ///
64    /// # 参数
65    /// * `addr`: 要转换的地址。
66    ///
67    /// # 返回
68    /// 包含该地址的页码。如果地址位于页内,则返回该页页码;如果地址是页的起始,则返回该页页码;
69    /// 如果地址是页的结束(例如 0x1000),则返回下一页的页码(例如 1)。
70    fn from_addr_ceil(addr: Self::TAddress) -> Self {
71        // 先向上对齐到页边界,再除以页大小 PAGE_SIZE
72        Self::from_usize(addr.align_up_to_page().as_usize() / PAGE_SIZE)
73    }
74
75    /// 获取该页码对应的起始地址。
76    ///
77    /// # 返回
78    /// 页的起始地址。
79    fn start_addr(self) -> Self::TAddress {
80        Self::TAddress::from_usize(self.as_usize() * PAGE_SIZE)
81    }
82
83    /// 获取该页码对应的结束地址 (即下一页的起始地址)。
84    ///
85    /// # 返回
86    /// 页的结束地址 (不包含在页内)。
87    fn end_addr(self) -> Self::TAddress {
88        Self::TAddress::from_usize((self.as_usize() + 1) * PAGE_SIZE)
89    }
90
91    /// 计算两个页码之间的页数差。
92    ///
93    /// # 参数
94    /// * `other`: 另一个页码。
95    ///
96    /// # 返回
97    /// 两个页码之间的带符号整数差值。
98    fn diff(self, other: Self) -> isize {
99        self.as_usize() as isize - other.as_usize() as isize
100    }
101}
102
103/// `impl_page_num!` 宏
104/// ---------------------
105/// 快速为给定类型实现 `UsizeConvert` 和 `PageNum` Trait。
106///
107/// 此宏同时调用 `impl_calc_ops!` 来实现所有的算术和位操作。
108///
109/// # 使用示例
110/// ```ignore
111/// #[repr(transparent)]
112/// #[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Debug)]
113/// pub struct MyPpn(pub usize);
114/// impl_page_num!(MyPpn, Paddr); // Paddr 是关联的地址类型
115/// ```
116#[macro_export]
117macro_rules! impl_page_num {
118    ($type:ty, $addr_type:ty) => {
119        // 1. 实现 UsizeConvert,允许与 usize 互相转换
120        impl $crate::mm::address::operations::UsizeConvert for $type {
121            fn as_usize(&self) -> usize {
122                self.0
123            }
124
125            fn from_usize(value: usize) -> Self {
126                Self(value)
127            }
128        }
129
130        // 2. 自动实现 CalcOps (算术和位运算)
131        $crate::impl_calc_ops!($type);
132
133        // 3. 实现 PageNum Trait,绑定地址类型
134        impl $crate::mm::address::page_num::PageNum for $type {
135            type TAddress = $addr_type;
136        }
137    };
138}
139
140/// [Ppn] (Physical Page Number)
141/// ---------------------
142/// 物理页码,对应物理地址 (Paddr)。
143#[repr(transparent)]
144#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Debug)]
145pub struct Ppn(pub usize);
146impl_page_num!(Ppn, Paddr);
147
148/// [Vpn] (Virtual Page Number)
149/// ---------------------
150/// 虚拟页码,对应虚拟地址 (Vaddr)。
151#[repr(transparent)]
152#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Debug)]
153pub struct Vpn(pub usize);
154impl_page_num!(Vpn, Vaddr);
155
156/// [PageNumRange]
157/// ---------------------
158/// 泛型页码范围结构,表示一个半开半闭的区间 `[start, end)`。
159#[repr(C)]
160#[derive(Clone, Copy, Debug, PartialEq, Eq)]
161pub struct PageNumRange<T>
162where
163    T: PageNum,
164{
165    /// 范围的起始页码 (包含)。
166    pub start: T,
167    /// 范围的结束页码 (不包含)。
168    pub end: T,
169}
170
171impl<T> PageNumRange<T>
172where
173    T: PageNum,
174{
175    /// 创建一个新的页码范围。
176    pub fn new(start: T, end: T) -> Self {
177        Self { start, end }
178    }
179
180    /// 从 Rust 标准库的 `Range<T>` 创建一个页码范围。
181    pub fn from_range(range: Range<T>) -> Self {
182        Self {
183            start: range.start,
184            end: range.end,
185        }
186    }
187
188    /// 从起始页码和长度 (页数) 创建一个页码范围。
189    pub fn from_start_len(start: T, len: usize) -> Self {
190        Self {
191            start,
192            end: T::from_usize(start.as_usize() + len),
193        }
194    }
195
196    /// 获取起始页码。
197    pub fn start(&self) -> T {
198        self.start
199    }
200
201    /// 获取结束页码 (不包含)。
202    pub fn end(&self) -> T {
203        self.end
204    }
205
206    /// 获取范围内的页数。
207    pub fn len(&self) -> usize {
208        debug_assert!(self.end.as_usize() >= self.start.as_usize());
209        self.end.as_usize() - self.start.as_usize()
210    }
211
212    /// 检查范围是否为空 (即 start == end)。
213    pub fn empty(&self) -> bool {
214        self.start == self.end
215    }
216
217    /// 检查范围是否包含给定的页码。
218    pub fn contains(&self, addr: T) -> bool {
219        addr >= self.start && addr < self.end
220    }
221
222    /// 检查范围是否包含另一个范围。
223    pub fn contains_range(&self, other: &Self) -> bool {
224        other.start >= self.start && other.end <= self.end
225    }
226
227    /// 检查此范围是否包含在另一个范围中。
228    pub fn contains_in(&self, other: &Self) -> bool {
229        self.start >= other.start && self.end <= other.end
230    }
231
232    /// 检查两个范围是否重叠。
233    ///
234    /// 注意: PageNumRange 是 [start, end),相邻的范围不视为重叠。
235    pub fn overlaps(&self, other: &Self) -> bool {
236        !(self.end <= other.start || self.start >= other.end)
237    }
238
239    /// 获取范围的迭代器。
240    pub fn iter(&self) -> PageNumRangeIterator<T> {
241        PageNumRangeIterator {
242            range: *self,
243            current: self.start,
244        }
245    }
246}
247
248impl<T> IntoIterator for PageNumRange<T>
249where
250    T: PageNum,
251{
252    type Item = T;
253    type IntoIter = PageNumRangeIterator<T>;
254
255    fn into_iter(self) -> Self::IntoIter {
256        self.iter()
257    }
258}
259
260/// [PageNumRangeIterator]
261/// ---------------------
262/// 页码范围的迭代器,按升序返回范围内的每个页码。
263pub struct PageNumRangeIterator<T>
264where
265    T: PageNum,
266{
267    range: PageNumRange<T>,
268    current: T,
269}
270
271impl<T> Iterator for PageNumRangeIterator<T>
272where
273    T: PageNum,
274{
275    type Item = T;
276
277    fn next(&mut self) -> Option<Self::Item> {
278        if self.current >= self.range.end {
279            return None;
280        }
281        let result = self.current;
282        self.current.step(); // 步进到下一页
283        Some(result)
284    }
285}
286
287/// 物理页码范围的类型别名
288pub type PpnRange = PageNumRange<Ppn>;
289/// 虚拟页码范围的类型别名
290pub type VpnRange = PageNumRange<Vpn>;
291
292#[cfg(test)]
293mod page_num_tests {
294    use super::*;
295    use crate::mm::address::{Paddr, PageNum, Ppn, Vpn};
296    use crate::{kassert, test_case};
297
298    // 1. Ppn/Vpn 基本转换测试
299    test_case!(test_pagenum_from_usize, {
300        // 假设 PAGE_SIZE = 0x1000 (4KB)
301        let ppn = Ppn::from_usize(0x80000); // 对应的地址是 0x8000_0000
302        kassert!(ppn.as_usize() == 0x80000);
303
304        let vpn = Vpn::from_usize(0x000F_FFFF_FC08_0000);
305        kassert!(vpn.as_usize() == 0x000F_FFFF_FC08_0000);
306    });
307
308    // 2. 地址到页码的转换测试
309    test_case!(test_pagenum_from_addr, {
310        let paddr = Paddr::from_usize(0x8000_1234);
311
312        // 向下取整 (floor): 0x8000_1234 位于页 0x80001
313        let ppn_floor = Ppn::from_addr_floor(paddr);
314        kassert!(ppn_floor.as_usize() == 0x80001); // 0x80001000 / PAGE_SIZE
315
316        // 向上取整 (ceil): 0x8000_1234 向上对齐到 0x8000_2000,页码为 0x80002
317        let ppn_ceil = Ppn::from_addr_ceil(paddr);
318        kassert!(ppn_ceil.as_usize() == 0x80002);
319    });
320
321    // 3. 页码到地址的转换测试
322    test_case!(test_pagenum_to_addr, {
323        let ppn = Ppn::from_usize(0x80000);
324
325        // 起始地址 (Paddr::from_usize(0x80000 * 0x1000))
326        let start = ppn.start_addr();
327        kassert!(start.as_usize() == 0x8000_0000);
328
329        // 结束地址 (下一页的起始地址)
330        let end = ppn.end_addr();
331        kassert!(end.as_usize() == 0x8000_1000);
332    });
333
334    // 4. 页码步进操作测试
335    test_case!(test_pagenum_step, {
336        let mut ppn = Ppn::from_usize(0x80000);
337
338        ppn.step();
339        kassert!(ppn.as_usize() == 0x80001);
340
341        ppn.step_back();
342        kassert!(ppn.as_usize() == 0x80000);
343    });
344
345    // 5. 页码范围基本属性测试
346    test_case!(test_pagenum_range, {
347        let start = Ppn::from_usize(0x80000);
348        let end = Ppn::from_usize(0x80003); // 范围 [0x80000, 0x80001, 0x80002]
349        let range = PpnRange::new(start, end);
350
351        kassert!(range.start().as_usize() == 0x80000);
352        kassert!(range.end().as_usize() == 0x80003);
353        kassert!(range.len() == 3); // 页数差
354    });
355
356    // 6. 页码范围迭代测试
357    test_case!(test_pagenum_range_iter, {
358        let range = PpnRange::new(Ppn::from_usize(0x80000), Ppn::from_usize(0x80003));
359
360        let mut count = 0;
361        // 迭代器应该返回 0x80000, 0x80001, 0x80002
362        for ppn in range {
363            kassert!(ppn.as_usize() >= 0x80000);
364            kassert!(ppn.as_usize() < 0x80003);
365            count += 1;
366        }
367        kassert!(count == 3);
368    });
369
370    // 7. floor 和 ceil 转换的差异测试
371    test_case!(test_floor_ceil_difference, {
372        // 对齐的地址: floor == ceil (页码一样)
373        let aligned = Paddr::from_usize(0x8000_0000);
374        let floor1 = Ppn::from_addr_floor(aligned);
375        let ceil1 = Ppn::from_addr_ceil(aligned);
376        kassert!(floor1.as_usize() == ceil1.as_usize());
377
378        // 未对齐的地址: ceil = floor + 1 (向上取整到下一页)
379        let unaligned = Paddr::from_usize(0x8000_0001);
380        let floor2 = Ppn::from_addr_floor(unaligned); // 0x80000
381        let ceil2 = Ppn::from_addr_ceil(unaligned); // 0x80001
382        kassert!(ceil2.as_usize() == floor2.as_usize() + 1);
383    });
384
385    // 8. 页码比较测试
386    test_case!(test_pagenum_comparison, {
387        let ppn1 = Ppn::from_usize(0x80000);
388        let ppn2 = Ppn::from_usize(0x80000);
389        let ppn3 = Ppn::from_usize(0x80001);
390
391        kassert!(ppn1 == ppn2);
392        kassert!(ppn1 < ppn3);
393        kassert!(ppn3 > ppn1);
394    });
395}