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::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        for i in 0..frames {
43            self.dealloc_frame(PhysAddr::from_usize(start.as_usize() + i * frame_size));
44        }
45    }
46}
47
48pub trait TableMeta: Sync + Send + Clone + Copy + 'static {
49    type P: PageTableEntry;
50
51    /// 页面大小(支持4KB、16KB、64KB等)
52    const PAGE_SIZE: usize;
53
54    /// 各级索引位数数组,从最高级到最低级
55    const LEVEL_BITS: &[usize];
56
57    /// 大页最高支持的级别
58    const MAX_BLOCK_LEVEL: usize;
59
60    /// Whether addresses must fit the address width described by [`LEVEL_BITS`].
61    const STRICT_ADDRESS_WIDTH: bool = false;
62
63    /// Converts an address reconstructed from page-table indexes into the
64    /// architecture's virtual-address representation.
65    fn canonicalize_vaddr(vaddr: VirtAddr) -> VirtAddr {
66        vaddr
67    }
68
69    /// 刷新TLB
70    fn flush(vaddr: Option<VirtAddr>);
71}
72
73pub trait PageTableEntry: Debug + Sync + Send + Clone + Copy + Sized + 'static {
74    /// Configuration understood by this concrete PTE format.
75    type PteConfig: Copy;
76
77    /// Creates a leaf or block entry.
78    fn new_page(paddr: PhysAddr, config: Self::PteConfig, is_huge: bool) -> Self;
79
80    /// Creates an entry that points to a child page-table frame.
81    fn new_table(paddr: PhysAddr) -> Self;
82
83    /// Returns the physical address encoded by this entry.
84    ///
85    /// `is_dir` lets formats with level-dependent layouts decode the address
86    /// without exposing those layout rules to the generic walker.
87    fn paddr(&self, is_dir: bool) -> PhysAddr;
88
89    /// Decodes the owner-defined leaf configuration.
90    fn config(&self, is_dir: bool) -> Self::PteConfig;
91
92    /// Returns whether this entry participates in address translation.
93    ///
94    /// Implementations must recognize both leaf mappings and child-table entries.
95    fn present(&self) -> bool;
96
97    /// Returns whether this entry is a block mapping at the current level.
98    fn huge(&self, is_dir: bool) -> bool;
99
100    /// Returns whether this entry contains no descriptor state at all.
101    ///
102    /// This is distinct from [`Self::present`]: a non-present leaf may retain its
103    /// physical address so that a later protection change can activate it.
104    fn unused(&self) -> bool;
105
106    /// Clears all descriptor state from this entry.
107    fn clear(&mut self);
108}
109
110pub trait PageTableOp: Send + 'static {
111    type PteConfig: Copy;
112
113    fn addr(&self) -> PhysAddr;
114    fn map(&mut self, config: &MapConfig<Self::PteConfig>) -> PagingResult;
115    fn unmap(&mut self, virt_start: VirtAddr, size: usize) -> Result<(), PagingError>;
116}
117
118impl<T: TableMeta, A: FrameAllocator> PageTableOp for PageTable<T, A> {
119    type PteConfig = PteConfigOf<T>;
120
121    fn addr(&self) -> PhysAddr {
122        self.root_paddr()
123    }
124
125    fn map(&mut self, config: &MapConfig<Self::PteConfig>) -> PagingResult {
126        PageTableRef::map(self, config)
127    }
128
129    fn unmap(&mut self, virt_start: VirtAddr, size: usize) -> PagingResult {
130        PageTableRef::unmap(self, virt_start, size)
131    }
132}
133
134impl<T: TableMeta, A: FrameAllocator> PageTableOp for PageTableRef<T, A> {
135    type PteConfig = PteConfigOf<T>;
136
137    fn addr(&self) -> PhysAddr {
138        self.root_paddr()
139    }
140
141    fn map(&mut self, config: &MapConfig<Self::PteConfig>) -> PagingResult {
142        self.map(config)
143    }
144
145    fn unmap(&mut self, virt_start: VirtAddr, size: usize) -> Result<(), PagingError> {
146        self.unmap(virt_start, size)
147    }
148}