memory_addresses/arch/
x86_64.rs1use align_address::Align;
4use core::fmt;
5#[cfg(feature = "conv-x86")]
6use x86::bits64::paging::{PAddr as x86_PAddr, VAddr as x86_VAddr};
7
8use crate::impl_address;
9
10use x86_64::structures::paging::page_table::PageTableLevel;
11use x86_64::structures::paging::{PageOffset, PageTableIndex};
12
13#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
24#[repr(transparent)]
25pub struct VirtAddr(u64);
26
27impl_address!(VirtAddr, u64, as_u64);
28
29#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
39#[repr(transparent)]
40pub struct PhysAddr(u64);
41
42impl_address!(PhysAddr, u64, as_u64);
43
44pub struct VirtAddrNotValid(pub u64);
53
54impl core::fmt::Debug for VirtAddrNotValid {
55 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
56 f.debug_tuple("VirtAddrNotValid")
57 .field(&format_args!("{:#x}", self.0))
58 .finish()
59 }
60}
61
62impl VirtAddr {
63 #[inline]
73 pub const fn new(addr: u64) -> VirtAddr {
74 match Self::try_new(addr) {
76 Ok(v) => v,
77 Err(_) => panic!("virtual address must be sign extended in bits 48 to 64"),
78 }
79 }
80
81 #[inline]
88 pub const fn try_new(addr: u64) -> Result<VirtAddr, VirtAddrNotValid> {
89 let v = Self::new_truncate(addr);
90 if v.0 == addr {
91 Ok(v)
92 } else {
93 Err(VirtAddrNotValid(addr))
94 }
95 }
96
97 #[inline]
103 pub const fn new_truncate(addr: u64) -> VirtAddr {
104 VirtAddr(((addr << 16) as i64 >> 16) as u64)
107 }
108
109 #[cfg(target_pointer_width = "64")]
111 #[inline]
112 pub fn from_ptr<T: ?Sized>(ptr: *const T) -> Self {
113 Self::new(ptr as *const () as u64)
114 }
115
116 #[cfg(target_pointer_width = "64")]
118 #[inline]
119 pub const fn as_ptr<T>(self) -> *const T {
120 self.as_u64() as *const T
121 }
122
123 #[cfg(target_pointer_width = "64")]
125 #[inline]
126 pub const fn as_mut_ptr<T>(self) -> *mut T {
127 self.as_ptr::<T>() as *mut T
128 }
129
130 #[cfg(target_pointer_width = "64")]
131 pub const fn as_usize(&self) -> usize {
133 self.0 as usize
134 }
135
136 #[inline]
138 pub fn is_aligned(self, align: u64) -> bool {
139 self.align_down(align).as_u64() == self.as_u64()
140 }
141
142 #[inline]
144 pub const fn page_offset(self) -> PageOffset {
145 PageOffset::new_truncate(self.0 as u16)
146 }
147
148 #[inline]
150 pub const fn p1_index(self) -> PageTableIndex {
151 PageTableIndex::new_truncate((self.0 >> 12) as u16)
152 }
153
154 #[inline]
156 pub const fn p2_index(self) -> PageTableIndex {
157 PageTableIndex::new_truncate((self.0 >> 12 >> 9) as u16)
158 }
159
160 #[inline]
162 pub const fn p3_index(self) -> PageTableIndex {
163 PageTableIndex::new_truncate((self.0 >> 12 >> 9 >> 9) as u16)
164 }
165
166 #[inline]
168 pub const fn p4_index(self) -> PageTableIndex {
169 PageTableIndex::new_truncate((self.0 >> 12 >> 9 >> 9 >> 9) as u16)
170 }
171
172 #[inline]
174 pub const fn page_table_index(self, level: PageTableLevel) -> PageTableIndex {
175 PageTableIndex::new_truncate((self.0 >> 12 >> ((level as u8 - 1) * 9)) as u16)
176 }
177}
178
179impl Align<u64> for VirtAddr {
180 #[inline]
181 fn align_down(self, align: u64) -> Self {
182 Self::new_truncate(self.0.align_down(align))
183 }
184
185 #[inline]
186 fn checked_align_up(self, align: u64) -> Option<Self> {
187 let addr = self.0.checked_align_up(align)?;
188 Some(Self::new_truncate(addr))
189 }
190}
191
192#[cfg(target_pointer_width = "64")]
193impl From<usize> for VirtAddr {
195 fn from(addr: usize) -> VirtAddr {
196 Self::new_truncate(addr as u64)
197 }
198}
199
200#[cfg(target_pointer_width = "64")]
201impl core::ops::Add<usize> for VirtAddr {
203 type Output = Self;
204 #[inline]
205 fn add(self, rhs: usize) -> Self::Output {
206 VirtAddr::new(self.0 + rhs as u64)
207 }
208}
209
210#[cfg(target_pointer_width = "64")]
211impl core::ops::AddAssign<usize> for VirtAddr {
213 #[inline]
214 fn add_assign(&mut self, rhs: usize) {
215 *self = *self + rhs;
216 }
217}
218
219#[cfg(target_pointer_width = "64")]
220impl core::ops::Sub<usize> for VirtAddr {
222 type Output = Self;
223 #[inline]
224 fn sub(self, rhs: usize) -> Self::Output {
225 VirtAddr::new(self.0.checked_sub(rhs as u64).unwrap())
226 }
227}
228
229#[cfg(target_pointer_width = "64")]
230impl core::ops::SubAssign<usize> for VirtAddr {
232 #[inline]
233 fn sub_assign(&mut self, rhs: usize) {
234 *self = *self - rhs;
235 }
236}
237
238#[cfg(feature = "conv-x86_64")]
239impl From<x86_64::VirtAddr> for VirtAddr {
240 fn from(addr: x86_64::VirtAddr) -> Self {
241 Self(addr.as_u64())
242 }
243}
244#[cfg(feature = "conv-x86_64")]
245impl From<&x86_64::VirtAddr> for VirtAddr {
246 fn from(addr: &x86_64::VirtAddr) -> Self {
247 Self(addr.as_u64())
248 }
249}
250
251#[cfg(feature = "conv-x86_64")]
252impl From<VirtAddr> for x86_64::VirtAddr {
253 fn from(addr: VirtAddr) -> x86_64::VirtAddr {
254 x86_64::VirtAddr::new(addr.0)
255 }
256}
257
258#[cfg(feature = "conv-x86_64")]
259impl From<&VirtAddr> for x86_64::VirtAddr {
260 fn from(addr: &VirtAddr) -> x86_64::VirtAddr {
261 x86_64::VirtAddr::new(addr.0)
262 }
263}
264
265#[cfg(feature = "conv-x86")]
266impl From<x86_VAddr> for VirtAddr {
267 fn from(addr: x86_VAddr) -> Self {
268 Self(addr.as_u64())
269 }
270}
271#[cfg(feature = "conv-x86")]
272impl From<&x86_VAddr> for VirtAddr {
273 fn from(addr: &x86_VAddr) -> Self {
274 Self(addr.as_u64())
275 }
276}
277
278#[cfg(feature = "conv-x86")]
279impl From<VirtAddr> for x86_VAddr {
280 fn from(addr: VirtAddr) -> x86_VAddr {
281 x86_VAddr(addr.0)
282 }
283}
284
285#[cfg(feature = "conv-x86")]
286impl From<&VirtAddr> for x86_VAddr {
287 fn from(addr: &VirtAddr) -> x86_VAddr {
288 x86_VAddr(addr.0)
289 }
290}
291
292pub struct PhysAddrNotValid(pub u64);
298
299impl core::fmt::Debug for PhysAddrNotValid {
300 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
301 f.debug_tuple("PhysAddrNotValid")
302 .field(&format_args!("{:#x}", self.0))
303 .finish()
304 }
305}
306
307impl PhysAddr {
308 #[inline]
314 pub const fn new(addr: u64) -> Self {
315 match Self::try_new(addr) {
317 Ok(p) => p,
318 Err(_) => panic!("physical addresses must not have any bits in the range 52 to 64 set"),
319 }
320 }
321
322 #[inline]
324 pub const fn new_truncate(addr: u64) -> PhysAddr {
325 PhysAddr(addr % (1 << 52))
326 }
327
328 #[inline]
332 pub const fn try_new(addr: u64) -> Result<Self, PhysAddrNotValid> {
333 let p = Self::new_truncate(addr);
334 if p.0 == addr {
335 Ok(p)
336 } else {
337 Err(PhysAddrNotValid(addr))
338 }
339 }
340
341 #[cfg(target_pointer_width = "64")]
342 pub const fn as_usize(&self) -> usize {
344 self.0 as usize
345 }
346}
347
348impl Align<u64> for PhysAddr {
349 #[inline]
350 fn align_down(self, align: u64) -> Self {
351 Self::new(self.as_u64().align_down(align))
352 }
353
354 #[inline]
355 fn checked_align_up(self, align: u64) -> Option<Self> {
356 let addr = self.0.checked_align_up(align)?;
357 let this = Self::try_new(addr).ok()?;
358 Some(this)
359 }
360}
361
362#[cfg(target_pointer_width = "64")]
363impl From<usize> for PhysAddr {
365 fn from(addr: usize) -> PhysAddr {
366 Self::new_truncate(addr as u64)
367 }
368}
369
370#[cfg(target_pointer_width = "64")]
371impl core::ops::Add<usize> for PhysAddr {
373 type Output = Self;
374 #[inline]
375 fn add(self, rhs: usize) -> Self::Output {
376 PhysAddr::new(self.0 + rhs as u64)
377 }
378}
379
380#[cfg(target_pointer_width = "64")]
381impl core::ops::AddAssign<usize> for PhysAddr {
383 #[inline]
384 fn add_assign(&mut self, rhs: usize) {
385 *self = *self + rhs;
386 }
387}
388
389#[cfg(target_pointer_width = "64")]
390impl core::ops::Sub<usize> for PhysAddr {
392 type Output = Self;
393 #[inline]
394 fn sub(self, rhs: usize) -> Self::Output {
395 PhysAddr::new(self.0.checked_sub(rhs as u64).unwrap())
396 }
397}
398
399#[cfg(target_pointer_width = "64")]
400impl core::ops::SubAssign<usize> for PhysAddr {
402 #[inline]
403 fn sub_assign(&mut self, rhs: usize) {
404 *self = *self - rhs;
405 }
406}
407
408#[cfg(feature = "conv-x86_64")]
409impl From<x86_64::PhysAddr> for PhysAddr {
410 fn from(addr: x86_64::PhysAddr) -> Self {
411 Self(addr.as_u64())
412 }
413}
414#[cfg(feature = "conv-x86_64")]
415impl From<&x86_64::PhysAddr> for PhysAddr {
416 fn from(addr: &x86_64::PhysAddr) -> Self {
417 Self(addr.as_u64())
418 }
419}
420
421#[cfg(feature = "conv-x86_64")]
422impl From<PhysAddr> for x86_64::PhysAddr {
423 fn from(addr: PhysAddr) -> x86_64::PhysAddr {
424 x86_64::PhysAddr::new(addr.0)
425 }
426}
427
428#[cfg(feature = "conv-x86_64")]
429impl From<&PhysAddr> for x86_64::PhysAddr {
430 fn from(addr: &PhysAddr) -> x86_64::PhysAddr {
431 x86_64::PhysAddr::new(addr.0)
432 }
433}
434
435#[cfg(feature = "conv-x86")]
436impl From<x86_PAddr> for PhysAddr {
437 fn from(addr: x86_PAddr) -> Self {
438 Self(addr.as_u64())
439 }
440}
441#[cfg(feature = "conv-x86")]
442impl From<&x86_PAddr> for PhysAddr {
443 fn from(addr: &x86_PAddr) -> Self {
444 Self(addr.as_u64())
445 }
446}
447
448#[cfg(feature = "conv-x86")]
449impl From<PhysAddr> for x86_PAddr {
450 fn from(addr: PhysAddr) -> x86_PAddr {
451 x86_PAddr(addr.0)
452 }
453}
454
455#[cfg(feature = "conv-x86")]
456impl From<&PhysAddr> for x86_PAddr {
457 fn from(addr: &PhysAddr) -> x86_PAddr {
458 x86_PAddr(addr.0)
459 }
460}
461
462#[cfg(test)]
463mod tests {
464 use super::*;
465
466 #[test]
467 pub fn virtaddr_new_truncate() {
468 assert_eq!(VirtAddr::new_truncate(0), VirtAddr(0));
469 assert_eq!(VirtAddr::new_truncate(1 << 47), VirtAddr(0xfffff << 47));
470 assert_eq!(VirtAddr::new_truncate(123), VirtAddr(123));
471 assert_eq!(VirtAddr::new_truncate(123 << 47), VirtAddr(0xfffff << 47));
472 }
473
474 #[test]
475 fn test_virt_addr_align_up() {
476 assert_eq!(
478 VirtAddr::new(0x7fff_ffff_ffff).align_up(2u64),
479 VirtAddr::new(0xffff_8000_0000_0000)
480 );
481 assert_eq!(
482 VirtAddr::new(0xffff_ffff_ffff_ffff).checked_align_up(2u64),
483 None
484 );
485 }
486
487 #[test]
488 fn test_virt_addr_align_down() {
489 assert_eq!(
491 VirtAddr::new(0xffff_8000_0000_0000).align_down(1u64 << 48),
492 VirtAddr::new(0)
493 );
494 }
495
496 #[test]
497 fn test_phys_addr_align_up() {
498 assert_eq!(
499 PhysAddr::new(0x000f_ffff_ffff_ffff).checked_align_up(2u64),
500 None
501 );
502 }
503
504 #[test]
505 fn test_from_ptr_array() {
506 let slice = &[1, 2, 3, 4, 5];
507 assert_eq!(VirtAddr::from_ptr(slice), VirtAddr::from_ptr(&slice[0]));
509 }
510}