Skip to main content

page_table_generic/
def.rs

1use core::ptr::NonNull;
2
3pub const KB: usize = 1024;
4pub const MB: usize = 1024 * KB;
5pub const GB: usize = 1024 * MB;
6
7macro_rules! def_addr {
8    ($name:ident, $t:ty) => {
9        #[repr(transparent)]
10        #[derive(Clone, Copy, Default, PartialEq, Eq, PartialOrd, Ord)]
11        pub struct $name($t);
12
13        impl From<$t> for $name {
14            #[inline(always)]
15            fn from(value: $t) -> Self {
16                Self(value)
17            }
18        }
19
20        impl From<$name> for $t {
21            #[inline(always)]
22            fn from(value: $name) -> Self {
23                value.0
24            }
25        }
26
27        impl $name {
28            #[inline(always)]
29            pub fn raw(&self) -> $t {
30                self.0
31            }
32
33            #[inline(always)]
34            pub const fn new(value: $t) -> Self {
35                Self(value)
36            }
37        }
38
39        impl core::ops::Add<$t> for $name {
40            type Output = Self;
41
42            #[inline(always)]
43            fn add(self, rhs: $t) -> Self::Output {
44                Self(self.0 + rhs)
45            }
46        }
47
48        impl core::ops::AddAssign<$t> for $name {
49            #[inline(always)]
50            fn add_assign(&mut self, rhs: $t) {
51                self.0 += rhs;
52            }
53        }
54
55        impl core::ops::Sub<$t> for $name {
56            type Output = Self;
57
58            #[inline(always)]
59            fn sub(self, rhs: $t) -> Self::Output {
60                Self(self.0 - rhs)
61            }
62        }
63
64        impl core::ops::Sub<Self> for $name {
65            type Output = $t;
66
67            #[inline(always)]
68            fn sub(self, rhs: Self) -> Self::Output {
69                self.0 - rhs.0
70            }
71        }
72
73        impl core::fmt::Debug for $name {
74            fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
75                write!(f, "0x{:0>16x}", self.0)
76            }
77        }
78    };
79}
80
81def_addr!(PhysAddr, usize);
82def_addr!(VirtAddr, usize);
83
84impl VirtAddr {
85    #[inline(always)]
86    pub fn as_ptr(self) -> *mut u8 {
87        self.0 as _
88    }
89}
90
91impl From<*mut u8> for VirtAddr {
92    #[inline(always)]
93    fn from(val: *mut u8) -> Self {
94        Self(val as _)
95    }
96}
97
98impl From<NonNull<u8>> for VirtAddr {
99    #[inline(always)]
100    fn from(val: NonNull<u8>) -> Self {
101        Self(val.as_ptr() as _)
102    }
103}
104
105impl From<*const u8> for VirtAddr {
106    #[inline(always)]
107    fn from(val: *const u8) -> Self {
108        Self(val as _)
109    }
110}
111
112#[cfg(target_pointer_width = "64")]
113impl From<u64> for PhysAddr {
114    #[inline(always)]
115    fn from(value: u64) -> Self {
116        Self(value as _)
117    }
118}
119
120#[cfg(target_pointer_width = "32")]
121impl From<u32> for PhysAddr {
122    #[inline(always)]
123    fn from(value: u32) -> Self {
124        Self(value as _)
125    }
126}
127
128#[derive(thiserror::Error, Clone, PartialEq, Eq)]
129pub enum PagingError {
130    #[error("Memory allocation failed")]
131    NoMemory,
132    #[error("Address alignment error: {details}")]
133    AlignmentError { details: &'static str },
134    #[error(
135        "Mapping conflict: virtual address {vaddr:#x} already mapped to physical address \
136         {existing_paddr:#x}"
137    )]
138    MappingConflict {
139        vaddr: VirtAddr,
140        existing_paddr: PhysAddr,
141    },
142    #[error("Address overflow detected: {details}")]
143    AddressOverflow { details: &'static str },
144    #[error("Invalid mapping size: {details}")]
145    InvalidSize { details: &'static str },
146    #[error("Page table hierarchy error: {details}")]
147    HierarchyError { details: &'static str },
148    #[error("Invalid address range: {details}")]
149    InvalidRange { details: &'static str },
150    #[error("Address not mapped")]
151    NotMapped,
152}
153
154impl core::fmt::LowerHex for VirtAddr {
155    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
156        write!(f, "{:#x}", self.raw())
157    }
158}
159
160impl core::fmt::LowerHex for PhysAddr {
161    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
162        write!(f, "{:#x}", self.raw())
163    }
164}
165
166impl PagingError {
167    pub fn alignment_error(msg: &'static str) -> Self {
168        Self::AlignmentError { details: msg }
169    }
170
171    pub fn mapping_conflict(vaddr: VirtAddr, existing_paddr: PhysAddr) -> Self {
172        Self::MappingConflict {
173            vaddr,
174            existing_paddr,
175        }
176    }
177
178    pub fn address_overflow(msg: &'static str) -> Self {
179        Self::AddressOverflow { details: msg }
180    }
181
182    pub fn invalid_size(msg: &'static str) -> Self {
183        Self::InvalidSize { details: msg }
184    }
185
186    pub fn hierarchy_error(msg: &'static str) -> Self {
187        Self::HierarchyError { details: msg }
188    }
189
190    pub fn invalid_range(msg: &'static str) -> Self {
191        Self::InvalidRange { details: msg }
192    }
193
194    pub fn not_mapped() -> Self {
195        Self::NotMapped
196    }
197}
198
199impl core::fmt::Debug for PagingError {
200    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
201        match self {
202            Self::NoMemory => write!(f, "NoMemory"),
203            Self::AlignmentError { details } => write!(f, "AlignmentError: {details}"),
204            Self::MappingConflict {
205                vaddr,
206                existing_paddr,
207            } => {
208                write!(
209                    f,
210                    "MappingConflict: vaddr={:#x}, existing_paddr={:#x}",
211                    vaddr.raw(),
212                    existing_paddr.raw()
213                )
214            }
215            Self::AddressOverflow { details } => write!(f, "AddressOverflow: {details}"),
216            Self::InvalidSize { details } => write!(f, "InvalidSize: {details}"),
217            Self::HierarchyError { details } => write!(f, "HierarchyError: {details}"),
218            Self::InvalidRange { details } => write!(f, "InvalidRange: {details}"),
219            Self::NotMapped => write!(f, "NotMapped"),
220        }
221    }
222}
223
224bitflags::bitflags! {
225    #[derive(Clone, Copy, Debug, PartialEq, Eq)]
226    pub struct AccessFlags: usize {
227        const READ = 1;
228        const WRITE = 1<<2;
229        const EXECUTE = 1<<3;
230        const LOWER = 1<<4;
231    }
232}
233
234#[derive(Default, Clone, Copy, Debug, PartialEq, Eq, Hash)]
235pub enum MemAttributes {
236    #[default]
237    Normal,
238    PerCpu,
239    Device,
240    Uncached,
241}
242
243#[derive(Clone, Copy, Debug, PartialEq, Eq)]
244pub struct MemConfig {
245    pub access: AccessFlags,
246    pub attrs: MemAttributes,
247}
248
249impl core::fmt::Display for MemConfig {
250    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
251        write!(
252            f,
253            "{}{}{}{}|{:?}",
254            if self.access.contains(AccessFlags::READ) {
255                "R"
256            } else {
257                "-"
258            },
259            if self.access.contains(AccessFlags::WRITE) {
260                "W"
261            } else {
262                "-"
263            },
264            if self.access.contains(AccessFlags::EXECUTE) {
265                "X"
266            } else {
267                "-"
268            },
269            if self.access.contains(AccessFlags::LOWER) {
270                "L"
271            } else {
272                "-"
273            },
274            self.attrs
275        )
276    }
277}
278
279#[derive(Default, Debug, Clone, Copy, PartialEq, Eq)]
280pub struct PteConfig {
281    pub paddr: PhysAddr,
282    pub valid: bool,
283    pub read: bool,
284    pub writable: bool,
285    pub executable: bool,
286    pub lower: bool,
287    pub dirty: bool,
288    pub global: bool,
289    pub is_dir: bool,
290    pub huge: bool,
291    pub mem_attr: MemAttributes,
292}