memory_addresses/arch/
riscv64.rs1use crate::impl_address;
4use core::fmt;
5
6use align_address::Align;
7
8pub const BASE_PAGE_SIZE: usize = 4096;
10
11pub const MEGA_PAGE_SIZE: usize = 1024 * 1024 * 2;
13
14pub const GIGA_PAGE_SIZE: usize = 1024 * 1024 * 1024;
16
17pub const TERA_PAGE_SIZE: usize = 1024 * 1024 * 1024 * 512;
19
20#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
25#[repr(transparent)]
26pub struct VirtAddr(u64);
27
28impl_address!(VirtAddr, u64);
29
30pub struct VirtAddrNotValid(pub u64);
32
33impl core::fmt::Debug for VirtAddrNotValid {
34 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
35 f.debug_tuple("VirtAddrNotValid")
36 .field(&format_args!("{:#x}", self.0))
37 .finish()
38 }
39}
40
41impl VirtAddr {
42 #[inline]
44 pub const fn new(addr: u64) -> VirtAddr {
45 match Self::try_new(addr) {
47 Ok(v) => v,
48 Err(_) => panic!("virtual address must be sign extended in bits 48 to 64"),
49 }
50 }
51
52 #[inline]
54 pub const fn try_new(addr: u64) -> Result<VirtAddr, VirtAddrNotValid> {
55 match addr {
56 0..=0xFFFF_FFFF_FFFF | 0xFFFF800000000000..=0xffff_ffff_ffff_ffff => Ok(Self(addr)),
57 _ => Err(VirtAddrNotValid(addr)),
58 }
59 }
60
61 #[inline]
66 pub const fn new_truncate(addr: u64) -> VirtAddr {
67 VirtAddr(((addr << 16) as i64 >> 16) as u64)
70 }
71
72 #[inline]
74 pub fn from_ptr<T: ?Sized>(ptr: *const T) -> Self {
75 Self::new(ptr as *const () as u64)
76 }
77
78 #[inline]
80 pub const fn as_ptr<T>(self) -> *const T {
81 self.0 as *const T
82 }
83
84 #[inline]
86 pub const fn as_mut_ptr<T>(self) -> *mut T {
87 self.as_ptr::<T>() as *mut T
88 }
89
90 #[cfg(target_pointer_width = "64")]
91 pub const fn as_usize(&self) -> usize {
93 self.0 as usize
94 }
95
96 pub fn base_page_offset(self) -> u64 {
98 self.0 & (BASE_PAGE_SIZE as u64 - 1)
99 }
100
101 pub fn large_page_offset(self) -> u64 {
103 self.0 & (MEGA_PAGE_SIZE as u64 - 1)
104 }
105
106 pub fn giga_page_offset(self) -> u64 {
108 self.0 & (GIGA_PAGE_SIZE as u64 - 1)
109 }
110
111 pub fn tera_page_offset(self) -> u64 {
113 self.0 & (TERA_PAGE_SIZE as u64 - 1)
114 }
115}
116
117impl Align<u64> for VirtAddr {
118 #[inline]
119 fn align_down(self, align: u64) -> Self {
120 Self::new_truncate(self.0.align_down(align))
121 }
122
123 #[inline]
124 fn align_up(self, align: u64) -> Self {
125 Self::new_truncate(self.0.align_up(align))
126 }
127}
128
129#[cfg(target_pointer_width = "64")]
130impl From<usize> for VirtAddr {
132 fn from(addr: usize) -> VirtAddr {
133 Self::new_truncate(addr as u64)
134 }
135}
136
137#[cfg(target_pointer_width = "64")]
138impl core::ops::Add<usize> for VirtAddr {
140 type Output = Self;
141 #[inline]
142 fn add(self, rhs: usize) -> Self::Output {
143 VirtAddr::new(self.0 + rhs as u64)
144 }
145}
146#[cfg(target_pointer_width = "64")]
147impl core::ops::AddAssign<usize> for VirtAddr {
149 #[inline]
150 fn add_assign(&mut self, rhs: usize) {
151 *self = *self + rhs;
152 }
153}
154#[cfg(target_pointer_width = "64")]
155impl core::ops::Sub<usize> for VirtAddr {
157 type Output = Self;
158 #[inline]
159 fn sub(self, rhs: usize) -> Self::Output {
160 VirtAddr::new(self.0.checked_sub(rhs as u64).unwrap())
161 }
162}
163#[cfg(target_pointer_width = "64")]
164impl core::ops::SubAssign<usize> for VirtAddr {
166 #[inline]
167 fn sub_assign(&mut self, rhs: usize) {
168 *self = *self - rhs;
169 }
170}
171
172#[cfg(target_pointer_width = "64")]
173impl From<usize> for PhysAddr {
175 fn from(addr: usize) -> PhysAddr {
176 Self::new_truncate(addr as u64)
177 }
178}
179
180#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
184#[repr(transparent)]
185pub struct PhysAddr(u64);
186
187impl_address!(PhysAddr, u64);
188
189pub struct PhysAddrNotValid(pub u64);
195
196impl core::fmt::Debug for PhysAddrNotValid {
197 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
198 f.debug_tuple("PhysAddrNotValid")
199 .field(&format_args!("{:#x}", self.0))
200 .finish()
201 }
202}
203
204impl PhysAddr {
205 #[inline]
207 pub const fn new(addr: u64) -> Self {
208 match Self::try_new(addr) {
210 Ok(p) => p,
211 Err(_) => panic!("physical addresses must not have any bits in the range 57 to 64 set"),
212 }
213 }
214
215 #[inline]
217 pub const fn new_truncate(addr: u64) -> PhysAddr {
218 PhysAddr(addr % (1 << 54))
219 }
220
221 #[inline]
225 pub const fn try_new(addr: u64) -> Result<Self, PhysAddrNotValid> {
226 match addr {
227 0..=0x3FFFFFFFFFFFFF => Ok(Self(addr)),
228 _ => Err(PhysAddrNotValid(addr)),
229 }
230 }
231
232 #[cfg(target_pointer_width = "64")]
233 pub const fn as_usize(&self) -> usize {
235 self.0 as usize
236 }
237}
238
239impl Align<u64> for PhysAddr {
240 #[inline]
241 fn align_down(self, align: u64) -> Self {
242 Self::new(self.0.align_down(align))
243 }
244
245 #[inline]
246 fn align_up(self, align: u64) -> Self {
247 Self::new(self.0.align_up(align))
248 }
249}
250
251#[cfg(target_pointer_width = "64")]
252impl core::ops::Add<usize> for PhysAddr {
254 type Output = Self;
255 #[inline]
256 fn add(self, rhs: usize) -> Self::Output {
257 PhysAddr::new(self.0 + rhs as u64)
258 }
259}
260
261#[cfg(target_pointer_width = "64")]
262impl core::ops::AddAssign<usize> for PhysAddr {
264 #[inline]
265 fn add_assign(&mut self, rhs: usize) {
266 *self = *self + rhs;
267 }
268}
269
270#[cfg(target_pointer_width = "64")]
271impl core::ops::Sub<usize> for PhysAddr {
273 type Output = Self;
274 #[inline]
275 fn sub(self, rhs: usize) -> Self::Output {
276 PhysAddr::new(self.0.checked_sub(rhs as u64).unwrap())
277 }
278}
279
280#[cfg(target_pointer_width = "64")]
281impl core::ops::SubAssign<usize> for PhysAddr {
283 #[inline]
284 fn sub_assign(&mut self, rhs: usize) {
285 *self = *self - rhs;
286 }
287}
288
289#[cfg(test)]
290mod tests {
291 use super::*;
292
293 #[test]
294 fn test_virt_addr() {
295 let _ = VirtAddr::new(0x0);
296 let _ = VirtAddr::new(0x1);
297 let _ = VirtAddr::new(0x0000_ffff_ffff_ffff);
298 let _ = VirtAddr::new(0xffff_8000_0000_0000);
299 let _ = VirtAddr::new(0xffff_ffff_ffff_ffff);
300 }
301
302 #[test]
303 #[should_panic]
304 fn test_invalid_virt_addr() {
305 let _ = VirtAddr::new(0xffff_0000_0000_0000);
306 let _ = VirtAddr::new(0x0ff0_0000_0000_0000);
307 let _ = VirtAddr::new(0xffe0_0000_0000_0000);
308 let _ = VirtAddr::new(0x0010_0000_0000_0000);
309 }
310
311 #[test]
312 fn test_phys_addr() {
313 let _ = PhysAddr::new(0x0);
314 let _ = PhysAddr::new(0x1);
315 let _ = PhysAddr::new(0x003F_FFFF_FFFF_FFFF);
316 }
317
318 #[test]
319 #[should_panic]
320 fn test_invalid_phys_addr() {
321 let _ = PhysAddr::new(0x0040_0000_0000_0000);
322 let _ = PhysAddr::new(0x0100_0000_0000_0000);
323 let _ = PhysAddr::new(0xffff_ffff_ffff_ffff);
324 }
325
326 #[test]
327 pub fn virtaddr_new_truncate() {
328 assert_eq!(VirtAddr::new_truncate(0), VirtAddr(0));
329 assert_eq!(VirtAddr::new_truncate(1 << 46), VirtAddr(1 << 46));
330 assert_eq!(VirtAddr::new_truncate(1 << 47), VirtAddr(0xfffff << 47));
331 assert_eq!(VirtAddr::new_truncate(123), VirtAddr(123));
332 assert_eq!(VirtAddr::new_truncate(123 << 46), VirtAddr(0xfffff << 46));
333 assert_eq!(
334 VirtAddr::new_truncate(0xfff0_0000_0000_0000),
335 VirtAddr::new_truncate(0xfff0_0000_0000_0000)
336 );
337 assert_eq!(
338 VirtAddr::new_truncate(0xfff0_0000_0000_1000),
339 VirtAddr::new_truncate(0xfff0_0000_0000_1000)
340 );
341 assert_eq!(
342 VirtAddr::new_truncate(0xffff_ffff_ffff_ffff),
343 VirtAddr::new_truncate(0xffff_ffff_ffff_ffff)
344 );
345 }
346
347 #[test]
348 fn test_virt_addr_align_up() {
349 assert_eq!(
350 VirtAddr::new(0x0000_0000_0000_1234).align_up(0x1000_u64),
351 VirtAddr::new(0x0000_0000_0000_2000)
352 );
353 assert_eq!(
354 VirtAddr::new(0x0000_7fff_ffff_ffff).align_up(2u64),
355 VirtAddr::new(0xffff_8000_0000_0000)
356 );
357 }
358
359 #[test]
360 fn test_virt_addr_align_down() {
361 assert_eq!(
362 VirtAddr::new(0x0000_0000_0000_1005).align_down(0x1000_u64),
363 VirtAddr::new(0x0000_0000_0000_1000)
364 );
365 assert_eq!(
366 VirtAddr::new(0x0000_0000_0000_1000).align_down(0x1_0000_u64),
367 VirtAddr::new(0x0000_0000_0000_0000)
368 );
369 assert_eq!(
370 VirtAddr::new(0xffff_8000_0000_0000).align_down(1u64 << 10),
371 VirtAddr::new(0xffff_8000_0000_0000)
372 );
373 }
374
375 #[test]
376 #[should_panic]
377 fn test_virt_addr_align_up_overflow() {
378 let _ = VirtAddr::new(0xffff_ffff_ffff_ffff).align_up(2u64);
379 }
380
381 #[test]
382 #[should_panic]
383 fn test_phys_addr_align_up_overflow() {
384 PhysAddr::new(0x00ff_ffff_ffff_ffff).align_up(2u64);
385 }
386
387 #[test]
388 fn test_from_ptr_array() {
389 let slice = &[1, 2, 3, 4, 5];
390 assert_eq!(VirtAddr::from_ptr(slice), VirtAddr::from_ptr(&slice[0]));
392 }
393}