Skip to main content

page_table_generic/
lib.rs

1#![no_std]
2
3use core::fmt::Debug;
4
5mod def;
6pub mod frame;
7mod map;
8mod table;
9mod walk;
10
11pub use def::*;
12pub use frame::{DetachedPageTableFrame, Frame};
13pub use map::*;
14pub use table::*;
15pub use walk::*;
16
17pub type PagingResult<T = ()> = Result<T, PagingError>;
18
19/// The opaque leaf-entry configuration used by a page-table metadata type.
20pub type PteConfigOf<T> = <<T as TableMeta>::P as PageTableEntry>::PteConfig;
21
22pub trait FrameAllocator: Clone + Sync + Send + 'static {
23    fn alloc_frame(&self) -> Option<PhysAddr>;
24
25    fn dealloc_frame(&self, frame: PhysAddr);
26
27    fn phys_to_virt(&self, paddr: PhysAddr) -> *mut u8;
28
29    fn alloc_frames(&self, frames: usize, _align: usize) -> Option<PhysAddr> {
30        if frames == 1 {
31            self.alloc_frame()
32        } else {
33            None
34        }
35    }
36
37    fn dealloc_frames(&self, start: PhysAddr, frames: usize, frame_size: usize) {
38        if frames == 1 {
39            self.dealloc_frame(start);
40            return;
41        }
42        // A malformed frame count/stride must never wrap back into a live
43        // allocation.  Allocator implementations cannot return an error from
44        // this legacy hook, so stop before the first unrepresentable address;
45        // callers using the fallible detached-frame API get the full checked
46        // range validation before reaching this path.
47        for i in 0..frames {
48            let Some(offset) = i.checked_mul(frame_size) else {
49                break;
50            };
51            let Some(address) = start.as_usize().checked_add(offset) else {
52                break;
53            };
54            self.dealloc_frame(PhysAddr::from_usize(address));
55        }
56    }
57}
58
59pub trait TableMeta: Sync + Send + Clone + Copy + 'static {
60    type P: PageTableEntry;
61
62    /// 页面大小(支持4KB、16KB、64KB等)
63    const PAGE_SIZE: usize;
64
65    /// 各级索引位数数组,从最高级到最低级
66    const LEVEL_BITS: &[usize];
67
68    /// 大页最高支持的级别
69    const MAX_BLOCK_LEVEL: usize;
70
71    /// Whether addresses must fit the address width described by [`LEVEL_BITS`].
72    const STRICT_ADDRESS_WIDTH: bool = false;
73
74    /// Converts an address reconstructed from page-table indexes into the
75    /// architecture's virtual-address representation.
76    fn canonicalize_vaddr(vaddr: VirtAddr) -> VirtAddr {
77        vaddr
78    }
79
80    /// 刷新TLB
81    fn flush(vaddr: Option<VirtAddr>);
82}
83
84pub trait PageTableEntry: Debug + Sync + Send + Clone + Copy + Sized + 'static {
85    /// Configuration understood by this concrete PTE format.
86    type PteConfig: Copy;
87
88    /// Creates a leaf or block entry.
89    fn new_page(paddr: PhysAddr, config: Self::PteConfig, is_huge: bool) -> Self;
90
91    /// Creates an entry that points to a child page-table frame.
92    fn new_table(paddr: PhysAddr) -> Self;
93
94    /// Returns the physical address encoded by this entry.
95    ///
96    /// `is_dir` lets formats with level-dependent layouts decode the address
97    /// without exposing those layout rules to the generic walker.
98    fn paddr(&self, is_dir: bool) -> PhysAddr;
99
100    /// Decodes the owner-defined leaf configuration.
101    fn config(&self, is_dir: bool) -> Self::PteConfig;
102
103    /// Returns whether this entry participates in address translation.
104    ///
105    /// Implementations must recognize both leaf mappings and child-table entries.
106    fn present(&self) -> bool;
107
108    /// Returns whether this entry is a block mapping at the current level.
109    ///
110    /// CPU page-table formats should preserve this structural answer for a
111    /// retained non-present block. Formats that encode an empty-permission
112    /// block as zero may return `false`; typed split then reports `NotMapped`.
113    fn huge(&self, is_dir: bool) -> bool;
114
115    /// Returns whether this entry contains no descriptor state at all.
116    ///
117    /// This is distinct from [`Self::present`]: a non-present leaf may retain its
118    /// physical address so that a later protection change can activate it.
119    fn unused(&self) -> bool;
120
121    /// Clears all descriptor state from this entry.
122    fn clear(&mut self);
123}
124
125pub trait PageTableOp: Send + 'static {
126    type PteConfig: Copy;
127
128    fn addr(&self) -> PhysAddr;
129    fn map(&mut self, config: &MapConfig<Self::PteConfig>) -> PagingResult;
130    fn unmap(&mut self, virt_start: VirtAddr, size: usize) -> Result<(), PagingError>;
131}
132
133impl<T: TableMeta, A: FrameAllocator> PageTableOp for PageTable<T, A> {
134    type PteConfig = PteConfigOf<T>;
135
136    fn addr(&self) -> PhysAddr {
137        self.root_paddr()
138    }
139
140    fn map(&mut self, config: &MapConfig<Self::PteConfig>) -> PagingResult {
141        PageTableRef::map(self, config)
142    }
143
144    fn unmap(&mut self, virt_start: VirtAddr, size: usize) -> PagingResult {
145        PageTableRef::unmap(self, virt_start, size)
146    }
147}
148
149impl<T: TableMeta, A: FrameAllocator> PageTableOp for PageTableRef<T, A> {
150    type PteConfig = PteConfigOf<T>;
151
152    fn addr(&self) -> PhysAddr {
153        self.root_paddr()
154    }
155
156    fn map(&mut self, config: &MapConfig<Self::PteConfig>) -> PagingResult {
157        self.map(config)
158    }
159
160    fn unmap(&mut self, virt_start: VirtAddr, size: usize) -> Result<(), PagingError> {
161        self.unmap(virt_start, size)
162    }
163}