memory_addresses/arch/
aarch64.rs1use crate::impl_address;
4use core::fmt;
5
6use align_address::Align;
7
8#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
16#[repr(transparent)]
17pub struct VirtAddr(u64);
18
19impl_address!(VirtAddr, u64);
20
21pub struct VirtAddrNotValid(pub u64);
27
28impl core::fmt::Debug for VirtAddrNotValid {
29 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
30 f.debug_tuple("VirtAddrNotValid")
31 .field(&format_args!("{:#x}", self.0))
32 .finish()
33 }
34}
35
36impl VirtAddr {
37 #[inline]
39 pub const fn new(addr: u64) -> VirtAddr {
40 match Self::try_new(addr) {
42 Ok(v) => v,
43 Err(_) => panic!("virtual address must be sign extended in bits 52 to 64"),
44 }
45 }
46
47 #[inline]
49 pub const fn try_new(addr: u64) -> Result<VirtAddr, VirtAddrNotValid> {
50 match addr {
51 0..=0x000f_ffff_ffff_ffff | 0xfff0_0000_0000_0000..=0xffff_ffff_ffff_ffff => {
52 Ok(Self(addr))
53 }
54 _ => Err(VirtAddrNotValid(addr)),
55 }
56 }
57
58 #[inline]
64 pub const fn new_truncate(addr: u64) -> VirtAddr {
65 VirtAddr(((addr << 11) as i64 >> 11) as u64)
68 }
69
70 #[inline]
72 pub fn from_ptr<T: ?Sized>(ptr: *const T) -> Self {
73 Self::new(ptr as *const () as u64)
74 }
75
76 #[inline]
78 pub const fn as_ptr<T>(self) -> *const T {
79 self.0 as *const T
80 }
81
82 #[inline]
84 pub const fn as_mut_ptr<T>(self) -> *mut T {
85 self.as_ptr::<T>() as *mut T
86 }
87
88 #[cfg(target_pointer_width = "64")]
89 pub const fn as_usize(&self) -> usize {
91 self.0 as usize
92 }
93}
94
95impl Align<u64> for VirtAddr {
96 #[inline]
97 fn align_down(self, align: u64) -> Self {
98 Self::new_truncate(self.0.align_down(align))
99 }
100
101 #[inline]
102 fn align_up(self, align: u64) -> Self {
103 Self::new_truncate(self.0.align_up(align))
104 }
105}
106
107#[cfg(target_pointer_width = "64")]
108impl From<usize> for VirtAddr {
110 fn from(addr: usize) -> VirtAddr {
111 Self::new_truncate(addr as u64)
112 }
113}
114
115#[cfg(target_pointer_width = "64")]
116impl core::ops::Add<usize> for VirtAddr {
118 type Output = Self;
119 #[inline]
120 fn add(self, rhs: usize) -> Self::Output {
121 VirtAddr::new(self.0 + rhs as u64)
122 }
123}
124
125#[cfg(target_pointer_width = "64")]
126impl core::ops::AddAssign<usize> for VirtAddr {
128 #[inline]
129 fn add_assign(&mut self, rhs: usize) {
130 *self = *self + rhs;
131 }
132}
133
134#[cfg(target_pointer_width = "64")]
135impl core::ops::Sub<usize> for VirtAddr {
137 type Output = Self;
138 #[inline]
139 fn sub(self, rhs: usize) -> Self::Output {
140 VirtAddr::new(self.0.checked_sub(rhs as u64).unwrap())
141 }
142}
143
144#[cfg(target_pointer_width = "64")]
145impl core::ops::SubAssign<usize> for VirtAddr {
147 #[inline]
148 fn sub_assign(&mut self, rhs: usize) {
149 *self = *self - rhs;
150 }
151}
152
153#[cfg(target_pointer_width = "64")]
154impl From<usize> for PhysAddr {
156 fn from(addr: usize) -> PhysAddr {
157 Self::new_truncate(addr as u64)
158 }
159}
160
161#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
166#[repr(transparent)]
167pub struct PhysAddr(u64);
168
169impl_address!(PhysAddr, u64);
170
171pub struct PhysAddrNotValid(pub u64);
177
178impl core::fmt::Debug for PhysAddrNotValid {
179 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
180 f.debug_tuple("PhysAddrNotValid")
181 .field(&format_args!("{:#x}", self.0))
182 .finish()
183 }
184}
185
186impl PhysAddr {
187 #[inline]
189 pub const fn new(addr: u64) -> Self {
190 match Self::try_new(addr) {
192 Ok(p) => p,
193 Err(_) => panic!("physical addresses must not have any bits in the range 57 to 64 set"),
194 }
195 }
196
197 #[inline]
199 pub const fn new_truncate(addr: u64) -> PhysAddr {
200 PhysAddr(addr % (1 << 56))
201 }
202
203 #[inline]
207 pub const fn try_new(addr: u64) -> Result<Self, PhysAddrNotValid> {
208 let p = Self::new_truncate(addr);
209 if p.0 == addr {
210 Ok(p)
211 } else {
212 Err(PhysAddrNotValid(addr))
213 }
214 }
215
216 #[cfg(target_pointer_width = "64")]
217 pub const fn as_usize(&self) -> usize {
219 self.0 as usize
220 }
221}
222
223#[cfg(target_pointer_width = "64")]
224impl core::ops::Add<usize> for PhysAddr {
226 type Output = Self;
227 #[inline]
228 fn add(self, rhs: usize) -> Self::Output {
229 PhysAddr::new(self.0 + rhs as u64)
230 }
231}
232
233#[cfg(target_pointer_width = "64")]
234impl core::ops::AddAssign<usize> for PhysAddr {
236 #[inline]
237 fn add_assign(&mut self, rhs: usize) {
238 *self = *self + rhs;
239 }
240}
241
242#[cfg(target_pointer_width = "64")]
243impl core::ops::Sub<usize> for PhysAddr {
245 type Output = Self;
246 #[inline]
247 fn sub(self, rhs: usize) -> Self::Output {
248 PhysAddr::new(self.0.checked_sub(rhs as u64).unwrap())
249 }
250}
251
252#[cfg(target_pointer_width = "64")]
253impl core::ops::SubAssign<usize> for PhysAddr {
255 #[inline]
256 fn sub_assign(&mut self, rhs: usize) {
257 *self = *self - rhs;
258 }
259}
260
261impl Align<u64> for PhysAddr {
262 #[inline]
263 fn align_down(self, align: u64) -> Self {
264 Self::new(self.0.align_down(align))
265 }
266
267 #[inline]
268 fn align_up(self, align: u64) -> Self {
269 Self::new(self.0.align_up(align))
270 }
271}
272
273#[cfg(test)]
274mod tests {
275 use super::*;
276
277 #[test]
278 fn test_virt_addr() {
279 let _ = VirtAddr::new(0x0);
280 let _ = VirtAddr::new(0x1);
281 let _ = VirtAddr::new(0x000f_ffff_ffff_ffff);
282 let _ = VirtAddr::new(0xffff_0000_0000_0000);
283 let _ = VirtAddr::new(0xffff_ffff_ffff_ffff);
284 }
285
286 #[test]
287 #[should_panic]
288 fn test_invalid_virt_addr() {
289 let _ = VirtAddr::new(0x0ff0_0000_0000_0000);
290 let _ = VirtAddr::new(0xffe0_0000_0000_0000);
291 let _ = VirtAddr::new(0x0010_0000_0000_0000);
292 }
293
294 #[test]
295 fn test_phys_addr() {
296 let _ = PhysAddr::new(0x0);
297 let _ = PhysAddr::new(0x1);
298 let _ = PhysAddr::new(0x00ff_ffff_ffff_ffff);
299 }
300
301 #[test]
302 #[should_panic]
303 fn test_invalid_phys_addr() {
304 let _ = PhysAddr::new(0x0100_0000_0000_0000);
305 let _ = PhysAddr::new(0xffff_ffff_ffff_ffff);
306 }
307
308 #[test]
309 pub fn virtaddr_new_truncate() {
310 assert_eq!(VirtAddr::new_truncate(0), VirtAddr(0));
311 assert_eq!(VirtAddr::new_truncate(1 << 51), VirtAddr(1 << 51));
312 assert_eq!(VirtAddr::new_truncate(1 << 52), VirtAddr(0xfffff << 52));
313 assert_eq!(VirtAddr::new_truncate(123), VirtAddr(123));
314 assert_eq!(VirtAddr::new_truncate(123 << 51), VirtAddr(0xfffff << 51));
315 assert_eq!(
316 VirtAddr::new_truncate(0xfff0_0000_0000_0000),
317 VirtAddr::new_truncate(0xfff0_0000_0000_0000)
318 );
319 assert_eq!(
320 VirtAddr::new_truncate(0xfff0_0000_0000_1000),
321 VirtAddr::new_truncate(0xfff0_0000_0000_1000)
322 );
323 assert_eq!(
324 VirtAddr::new_truncate(0xffff_ffff_ffff_ffff),
325 VirtAddr::new_truncate(0xffff_ffff_ffff_ffff)
326 );
327 }
328
329 #[test]
330 fn test_virt_addr_align_up() {
331 assert_eq!(
332 VirtAddr::new(0x0000_0000_0000_1234).align_up(0x1000_u64),
333 VirtAddr::new(0x0000_0000_0000_2000)
334 );
335 assert_eq!(
336 VirtAddr::new(0x000f_ffff_ffff_ffff).align_up(2u64),
337 VirtAddr::new(0xfff0_0000_0000_0000)
338 );
339 }
340
341 #[test]
342 fn test_virt_addr_align_down() {
343 assert_eq!(
344 VirtAddr::new(0x0000_0000_0000_1005).align_down(0x1000_u64),
345 VirtAddr::new(0x0000_0000_0000_1000)
346 );
347 assert_eq!(
348 VirtAddr::new(0x0000_0000_0000_1000).align_down(0x1_0000_u64),
349 VirtAddr::new(0x0000_0000_0000_0000)
350 );
351 assert_eq!(
352 VirtAddr::new(0xfff0_0000_0000_0000).align_down(1u64 << 10),
353 VirtAddr::new(0xfff0_0000_0000_0000)
354 );
355 }
356
357 #[test]
358 #[should_panic]
359 fn test_virt_addr_align_up_overflow() {
360 let _ = VirtAddr::new(0xffff_ffff_ffff_ffff).align_up(2u64);
361 }
362
363 #[test]
364 #[should_panic]
365 fn test_phys_addr_align_up_overflow() {
366 PhysAddr::new(0x00ff_ffff_ffff_ffff).align_up(2u64);
367 }
368
369 #[test]
370 fn test_from_ptr_array() {
371 let slice = &[1, 2, 3, 4, 5];
372 assert_eq!(VirtAddr::from_ptr(slice), VirtAddr::from_ptr(&slice[0]));
374 }
375}