page_table_generic/
lib.rs1#![cfg_attr(not(test), no_std)]
2#![feature(pointer_is_aligned_to)]
3
4use core::{alloc::Layout, fmt::Debug, ptr::NonNull};
5
6mod align;
7pub mod err;
8mod iter;
9mod page_table_entry;
10mod table;
11
12pub use table::PageTableRef;
13
14bitflags::bitflags! {
15 #[repr(transparent)]
18 #[derive(Clone, Copy, PartialEq, Eq)]
19 pub struct AccessSetting: u8 {
20 const Read = 1;
21 const Write = 1 << 2;
22 const Execute = 1 << 3;
23 }
24}
25
26impl AccessSetting {
27 pub fn readable(&self) -> bool {
28 self.contains(AccessSetting::Read)
29 }
30
31 pub fn writable(&self) -> bool {
32 self.contains(AccessSetting::Write)
33 }
34
35 pub fn executable(&self) -> bool {
36 self.contains(AccessSetting::Execute)
37 }
38}
39
40#[repr(u8)]
41#[derive(Debug, Clone, Copy, PartialEq, Eq)]
42pub enum CacheSetting {
43 Normal,
44 Device,
45 NonCache,
46}
47
48#[repr(C)]
49#[derive(Debug, Clone, Copy)]
50pub struct MapConfig {
51 pub vaddr: *const u8,
52 pub paddr: usize,
53 pub setting: PTESetting,
54}
55
56impl MapConfig {
57 pub fn new(
58 vaddr: *const u8,
59 paddr: usize,
60 privilege_access: AccessSetting,
61 cache_setting: CacheSetting,
62 ) -> Self {
63 Self {
64 vaddr,
65 paddr,
66 setting: PTESetting {
67 cache_setting,
68 privilege_access,
69 user_access: AccessSetting::empty(),
70 is_global: true,
71 },
72 }
73 }
74
75 pub fn set_user_access(&mut self, access: AccessSetting) -> Self {
76 self.setting.user_access = access;
77 *self
78 }
79}
80
81#[repr(C)]
82#[derive(Clone, Copy, PartialEq, Eq)]
83pub struct PTESetting {
84 pub is_global: bool,
85 pub privilege_access: AccessSetting,
86 pub user_access: AccessSetting,
87 pub cache_setting: CacheSetting,
88}
89
90impl Default for PTESetting {
91 fn default() -> Self {
92 Self {
93 is_global: Default::default(),
94 privilege_access: AccessSetting::empty(),
95 user_access: AccessSetting::empty(),
96 cache_setting: CacheSetting::Normal,
97 }
98 }
99}
100
101#[repr(C)]
102#[derive(Default, Clone, PartialEq, Eq)]
103pub struct PTEGeneric {
104 pub paddr: usize,
105 pub is_block: bool,
106 pub is_valid: bool,
107 pub setting: PTESetting,
108}
109
110impl PTEGeneric {
111 pub(crate) fn new(paddr: usize, is_block: bool, setting: PTESetting) -> Self {
112 Self {
113 paddr,
114 is_valid: true,
115 is_block,
116 setting,
117 }
118 }
119
120 pub fn valid(&self) -> bool {
121 self.is_valid
122 }
123}
124
125impl Debug for PTEGeneric {
126 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
127 write!(
128 f,
129 "PTE PA:{:#p} Block: {:>5} {:?}",
130 self.paddr as *const u8, self.is_block, self.setting
131 )
132 }
133}
134
135pub trait PTEArch: Sync + Send + Clone + Copy + 'static {
136 fn page_size() -> usize;
137 fn level() -> usize;
138 fn new_pte(config: PTEGeneric) -> usize;
139 fn read_pte(pte: usize) -> PTEGeneric;
140}
141
142pub trait Access {
143 fn va_offset(&self) -> usize;
145 unsafe fn alloc(&mut self, layout: Layout) -> Option<NonNull<u8>>;
151 unsafe fn dealloc(&mut self, ptr: NonNull<u8>, layout: Layout);
157}
158
159pub struct PTEInfo {
160 pub level: usize,
161 pub vaddr: *const u8,
162 pub pte: PTEGeneric,
163}
164
165impl Debug for PTESetting {
166 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
167 macro_rules! field {
168 ($i:expr,$e:ident,$name:expr) => {
169 if $i.contains(AccessSetting::$e) {
170 f.write_str($name)?
171 } else {
172 f.write_str("-")?
173 }
174 };
175 }
176
177 f.write_str("P")?;
178 field!(self.privilege_access, Read, "R");
179 field!(self.privilege_access, Write, "W");
180 field!(self.privilege_access, Execute, "X");
181 f.write_str(" | U")?;
182 field!(self.user_access, Read, "R");
183 field!(self.user_access, Write, "W");
184 field!(self.user_access, Execute, "X");
185 f.write_str(", ")?;
186 f.write_fmt(format_args!("{:?}", self.cache_setting))?;
187 f.write_str(")")
188 }
189}