1use crate::{mask, VmMeta};
2use core::{
3 fmt,
4 marker::PhantomData,
5 ops::{Add, AddAssign, Range},
6};
7
8#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
10#[repr(transparent)]
11pub struct PageNumber<Meta: VmMeta, S: Space>(usize, PhantomData<Meta>, PhantomData<S>);
12
13pub trait Space: Clone + Copy + PartialEq + Eq + PartialOrd + Ord + fmt::Debug {}
15
16#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Debug)]
18pub struct Physical;
19
20#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Debug)]
22pub struct Virtual;
23
24impl Space for Physical {}
25impl Space for Virtual {}
26
27impl<Meta: VmMeta, S: Space> PageNumber<Meta, S> {
28 pub const ZERO: Self = Self::new(0);
30
31 pub const MIN: Self = Self::ZERO;
33
34 #[inline]
36 pub const fn new(n: usize) -> Self {
37 Self(n, PhantomData, PhantomData)
38 }
39
40 #[inline]
42 pub const fn val(self) -> usize {
43 self.0
44 }
45}
46
47impl<Meta: VmMeta, S: Space> Add<usize> for PageNumber<Meta, S> {
48 type Output = Self;
49
50 #[inline]
51 fn add(self, rhs: usize) -> Self {
52 Self::new(self.0.wrapping_add(rhs))
53 }
54}
55
56impl<Meta: VmMeta, S: Space> AddAssign<usize> for PageNumber<Meta, S> {
57 #[inline]
58 fn add_assign(&mut self, rhs: usize) {
59 self.0 = self.0.wrapping_add(rhs);
60 }
61}
62
63pub type PPN<Meta> = PageNumber<Meta, Physical>;
65
66pub type VPN<Meta> = PageNumber<Meta, Virtual>;
68
69impl<Meta: VmMeta> PPN<Meta> {
70 pub const INVALID: Self = Self::new(1 << (Meta::P_ADDR_BITS - Meta::PAGE_BITS));
74
75 pub const MAX: Self = Self::new(Self::INVALID.val() - 1);
77}
78
79impl<Meta: VmMeta> fmt::Debug for PPN<Meta> {
80 #[inline]
81 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
82 write!(f, "PPN({:#x})", self.0)
83 }
84}
85
86impl<Meta: VmMeta> VPN<Meta> {
87 pub const MAX: Self = Self::new(mask(Meta::V_ADDR_BITS - Meta::PAGE_BITS));
89
90 #[inline]
92 pub const fn base(self) -> VAddr<Meta> {
93 VAddr::new(self.0 << Meta::PAGE_BITS)
94 }
95
96 #[inline]
98 pub fn index_in(self, level: usize) -> usize {
99 (self.0 >> Self::bits_until(level)) & mask(Meta::LEVEL_BITS[level])
100 }
101
102 #[inline]
104 pub fn floor(self, level: usize) -> Self {
105 let bits = Self::bits_until(level);
106 Self::new(self.0 & !mask(bits))
107 }
108
109 #[inline]
111 pub fn ceil(self, level: usize) -> usize {
112 let bits = Self::bits_until(level);
113 (self.0 + mask(bits)) >> bits
114 }
115
116 #[inline]
118 pub fn vaddr_range(self, level: usize) -> Range<VAddr<Meta>> {
119 let base = self.base();
120 base..base + Meta::bytes_in_page(level)
121 }
122
123 #[inline]
125 pub fn align_level(self) -> usize {
126 let mut n = self.0;
127 for (i, bits) in Meta::LEVEL_BITS[..Meta::MAX_LEVEL].iter().rev().enumerate() {
128 if n & mask(*bits) != 0 {
129 return i;
130 }
131 n >>= bits;
132 }
133 Meta::MAX_LEVEL
134 }
135
136 #[inline]
138 fn bits_until(level: usize) -> usize {
139 Meta::LEVEL_BITS[..level].iter().sum::<usize>()
140 }
141}
142
143impl<Meta: VmMeta> fmt::Debug for VPN<Meta> {
144 #[inline]
145 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
146 write!(f, "VPN({:#x})", self.0)
147 }
148}
149
150#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
152#[repr(transparent)]
153pub struct MaybeInvalidPPN<Meta: VmMeta>(PPN<Meta>);
154
155impl<Meta: VmMeta> MaybeInvalidPPN<Meta> {
156 #[inline]
158 pub const fn new(n: PPN<Meta>) -> Self {
159 Self(n)
160 }
161
162 #[inline]
164 pub const fn invalid() -> Self {
165 Self(PPN::INVALID)
166 }
167
168 #[inline]
170 pub const fn get(&self) -> Option<PPN<Meta>> {
171 if self.0.val() > PPN::<Meta>::MAX.val() {
172 None
173 } else {
174 Some(self.0)
175 }
176 }
177}
178
179#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
181#[repr(transparent)]
182pub struct VAddr<Meta: VmMeta>(usize, PhantomData<Meta>);
183
184impl<Meta: VmMeta> Add<usize> for VAddr<Meta> {
185 type Output = Self;
186
187 #[inline]
188 fn add(self, rhs: usize) -> Self {
189 Self::new(self.0.wrapping_add(rhs))
190 }
191}
192
193impl<Meta: VmMeta> AddAssign<usize> for VAddr<Meta> {
194 #[inline]
195 fn add_assign(&mut self, rhs: usize) {
196 self.0 = self.0.wrapping_add(rhs);
197 }
198}
199
200impl<Meta: VmMeta> VAddr<Meta> {
201 const IGNORED_MASK: usize = mask(Meta::V_ADDR_BITS - 1);
202
203 #[inline]
206 pub const fn new(value: usize) -> Self {
207 Self(value & mask(Meta::V_ADDR_BITS), PhantomData)
208 }
209
210 #[inline]
212 pub const fn val(self) -> usize {
213 if self.0 <= Self::IGNORED_MASK {
214 self.0
215 } else {
216 self.0 | !Self::IGNORED_MASK
217 }
218 }
219
220 #[inline]
226 pub const unsafe fn as_ptr<T>(self) -> *const T {
227 self.val() as _
228 }
229
230 #[inline]
236 pub unsafe fn as_mut_ptr<T>(self) -> *mut T {
237 self.val() as _
238 }
239
240 #[inline]
242 pub const fn floor(self) -> VPN<Meta> {
243 VPN::new(self.0 >> Meta::PAGE_BITS)
244 }
245
246 #[inline]
248 pub const fn ceil(self) -> VPN<Meta> {
249 VPN::new((self.0 + mask(Meta::PAGE_BITS)) >> Meta::PAGE_BITS)
250 }
251
252 #[inline]
254 pub const fn offset(self) -> usize {
255 self.0 & mask(Meta::PAGE_BITS)
256 }
257}
258
259impl<Meta: VmMeta> From<usize> for VAddr<Meta> {
260 #[inline]
261 fn from(value: usize) -> Self {
262 Self::new(value)
263 }
264}
265
266impl<Meta: VmMeta, T> From<&T> for VAddr<Meta> {
267 #[inline]
268 fn from(value: &T) -> Self {
269 Self::new(value as *const _ as _)
270 }
271}
272
273impl<Meta: VmMeta> fmt::Debug for VAddr<Meta> {
274 #[inline]
275 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
276 write!(f, "VAddr({:#x})", self.0)
277 }
278}
279
280#[test]
281fn test_index_in() {
282 use crate::test_meta::Sv39;
283
284 for i in 0..=Sv39::MAX_LEVEL {
285 let vpn = VPN::<Sv39>::new(1 << (i * 9));
286 for j in 0..=Sv39::MAX_LEVEL {
287 assert_eq!(vpn.index_in(j), if i == j { 1 } else { 0 });
288 }
289 }
290}
291
292#[test]
293fn test_align_level() {
294 use crate::test_meta::Sv39;
295
296 assert_eq!(VPN::<Sv39>::new(1).align_level(), 0);
297 assert_eq!(VPN::<Sv39>::new(1 << 9).align_level(), 1);
298 assert_eq!(VPN::<Sv39>::new(1 << 18).align_level(), 2);
299 assert_eq!(VPN::<Sv39>::new(0).align_level(), 2);
300}