1use core::convert::TryFrom;
4use core::fmt;
5#[cfg(feature = "step_trait")]
6use core::iter::Step;
7use core::ops::{Add, AddAssign, Sub, SubAssign};
8#[cfg(feature = "memory_encryption")]
9use core::sync::atomic::Ordering;
10
11#[cfg(feature = "memory_encryption")]
12use crate::structures::mem_encrypt::ENC_BIT_MASK;
13use crate::structures::paging::page_table::PageTableLevel;
14use crate::structures::paging::{PageOffset, PageTableIndex};
15
16use bit_field::BitField;
17use dep_const_fn::const_fn;
18
19const ADDRESS_SPACE_SIZE: u64 = 0x1_0000_0000_0000;
20
21#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
32#[repr(transparent)]
33pub struct VirtAddr(u64);
34
35#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
45#[repr(transparent)]
46pub struct PhysAddr(u64);
47
48pub struct VirtAddrNotValid(pub u64);
57
58impl core::fmt::Debug for VirtAddrNotValid {
59 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
60 f.debug_tuple("VirtAddrNotValid")
61 .field(&format_args!("{:#x}", self.0))
62 .finish()
63 }
64}
65
66impl VirtAddr {
67 #[inline]
77 pub const fn new(addr: u64) -> VirtAddr {
78 match Self::try_new(addr) {
80 Ok(v) => v,
81 Err(_) => panic!("virtual address must be sign extended in bits 48 to 64"),
82 }
83 }
84
85 #[inline]
92 pub const fn try_new(addr: u64) -> Result<VirtAddr, VirtAddrNotValid> {
93 let v = Self::new_truncate(addr);
94 if v.0 == addr {
95 Ok(v)
96 } else {
97 Err(VirtAddrNotValid(addr))
98 }
99 }
100
101 #[inline]
107 pub const fn new_truncate(addr: u64) -> VirtAddr {
108 VirtAddr(((addr << 16) as i64 >> 16) as u64)
111 }
112
113 #[inline]
119 pub const unsafe fn new_unsafe(addr: u64) -> VirtAddr {
120 VirtAddr(addr)
121 }
122
123 #[inline]
125 pub const fn zero() -> VirtAddr {
126 VirtAddr(0)
127 }
128
129 #[inline]
131 pub const fn as_u64(self) -> u64 {
132 self.0
133 }
134
135 #[cfg(target_pointer_width = "64")]
137 #[inline]
138 pub fn from_ptr<T: ?Sized>(ptr: *const T) -> Self {
139 Self::new(ptr as *const () as u64)
140 }
141
142 #[cfg(target_pointer_width = "64")]
144 #[inline]
145 pub const fn as_ptr<T>(self) -> *const T {
146 self.as_u64() as *const T
147 }
148
149 #[cfg(target_pointer_width = "64")]
151 #[inline]
152 pub const fn as_mut_ptr<T>(self) -> *mut T {
153 self.as_ptr::<T>() as *mut T
154 }
155
156 #[inline]
158 pub const fn is_null(self) -> bool {
159 self.0 == 0
160 }
161
162 #[inline]
171 pub fn align_up<U>(self, align: U) -> Self
172 where
173 U: Into<u64>,
174 {
175 VirtAddr::new_truncate(align_up(self.0, align.into()))
176 }
177
178 #[inline]
182 pub fn align_down<U>(self, align: U) -> Self
183 where
184 U: Into<u64>,
185 {
186 self.align_down_u64(align.into())
187 }
188
189 #[inline]
193 pub(crate) const fn align_down_u64(self, align: u64) -> Self {
194 VirtAddr::new_truncate(align_down(self.0, align))
195 }
196
197 #[inline]
199 pub fn is_aligned<U>(self, align: U) -> bool
200 where
201 U: Into<u64>,
202 {
203 self.is_aligned_u64(align.into())
204 }
205
206 #[inline]
208 pub(crate) const fn is_aligned_u64(self, align: u64) -> bool {
209 self.align_down_u64(align).as_u64() == self.as_u64()
210 }
211
212 #[inline]
214 pub const fn page_offset(self) -> PageOffset {
215 PageOffset::new_truncate(self.0 as u16)
216 }
217
218 #[inline]
220 pub const fn p1_index(self) -> PageTableIndex {
221 PageTableIndex::new_truncate((self.0 >> 12) as u16)
222 }
223
224 #[inline]
226 pub const fn p2_index(self) -> PageTableIndex {
227 PageTableIndex::new_truncate((self.0 >> 12 >> 9) as u16)
228 }
229
230 #[inline]
232 pub const fn p3_index(self) -> PageTableIndex {
233 PageTableIndex::new_truncate((self.0 >> 12 >> 9 >> 9) as u16)
234 }
235
236 #[inline]
238 pub const fn p4_index(self) -> PageTableIndex {
239 PageTableIndex::new_truncate((self.0 >> 12 >> 9 >> 9 >> 9) as u16)
240 }
241
242 #[inline]
244 pub const fn page_table_index(self, level: PageTableLevel) -> PageTableIndex {
245 PageTableIndex::new_truncate((self.0 >> 12 >> ((level as u8 - 1) * 9)) as u16)
246 }
247
248 #[cfg(feature = "step_trait")]
250 pub(crate) fn steps_between_impl(start: &Self, end: &Self) -> (usize, Option<usize>) {
251 if let Some(steps) = Self::steps_between_u64(start, end) {
252 let steps = usize::try_from(steps).ok();
253 (steps.unwrap_or(usize::MAX), steps)
254 } else {
255 (0, None)
256 }
257 }
258
259 pub(crate) fn steps_between_u64(start: &Self, end: &Self) -> Option<u64> {
263 let mut steps = end.0.checked_sub(start.0)?;
264
265 steps &= 0xffff_ffff_ffff;
267
268 Some(steps)
269 }
270
271 #[inline]
273 pub(crate) fn forward_checked_impl(start: Self, count: usize) -> Option<Self> {
274 Self::forward_checked_u64(start, u64::try_from(count).ok()?)
275 }
276
277 #[inline]
279 pub(crate) fn forward_checked_u64(start: Self, count: u64) -> Option<Self> {
280 if count > ADDRESS_SPACE_SIZE {
281 return None;
282 }
283
284 let mut addr = start.0.checked_add(count)?;
285
286 match addr.get_bits(47..) {
287 0x1 => {
288 addr.set_bits(47.., 0x1ffff);
290 }
291 0x2 => {
292 return None;
294 }
295 _ => {}
296 }
297
298 Some(unsafe { Self::new_unsafe(addr) })
299 }
300
301 #[cfg(feature = "step_trait")]
303 #[inline]
304 pub(crate) fn backward_checked_u64(start: Self, count: u64) -> Option<Self> {
305 if count > ADDRESS_SPACE_SIZE {
306 return None;
307 }
308
309 let mut addr = start.0.checked_sub(count)?;
310
311 match addr.get_bits(47..) {
312 0x1fffe => {
313 addr.set_bits(47.., 0);
315 }
316 0x1fffd => {
317 return None;
319 }
320 _ => {}
321 }
322
323 Some(unsafe { Self::new_unsafe(addr) })
324 }
325}
326
327impl fmt::Debug for VirtAddr {
328 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
329 f.debug_tuple("VirtAddr")
330 .field(&format_args!("{:#x}", self.0))
331 .finish()
332 }
333}
334
335impl fmt::Binary for VirtAddr {
336 #[inline]
337 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
338 fmt::Binary::fmt(&self.0, f)
339 }
340}
341
342impl fmt::LowerHex for VirtAddr {
343 #[inline]
344 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
345 fmt::LowerHex::fmt(&self.0, f)
346 }
347}
348
349impl fmt::Octal for VirtAddr {
350 #[inline]
351 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
352 fmt::Octal::fmt(&self.0, f)
353 }
354}
355
356impl fmt::UpperHex for VirtAddr {
357 #[inline]
358 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
359 fmt::UpperHex::fmt(&self.0, f)
360 }
361}
362
363impl fmt::Pointer for VirtAddr {
364 #[inline]
365 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
366 fmt::Pointer::fmt(&(self.0 as *const ()), f)
367 }
368}
369
370impl Add<u64> for VirtAddr {
371 type Output = Self;
372
373 #[cfg_attr(not(feature = "step_trait"), allow(rustdoc::broken_intra_doc_links))]
374 #[inline]
385 fn add(self, rhs: u64) -> Self::Output {
386 VirtAddr::try_new(
387 self.0
388 .checked_add(rhs)
389 .expect("attempt to add with overflow"),
390 )
391 .expect("attempt to add resulted in non-canonical virtual address")
392 }
393}
394
395impl AddAssign<u64> for VirtAddr {
396 #[cfg_attr(not(feature = "step_trait"), allow(rustdoc::broken_intra_doc_links))]
397 #[inline]
408 fn add_assign(&mut self, rhs: u64) {
409 *self = *self + rhs;
410 }
411}
412
413impl Sub<u64> for VirtAddr {
414 type Output = Self;
415
416 #[cfg_attr(not(feature = "step_trait"), allow(rustdoc::broken_intra_doc_links))]
417 #[inline]
428 fn sub(self, rhs: u64) -> Self::Output {
429 VirtAddr::try_new(
430 self.0
431 .checked_sub(rhs)
432 .expect("attempt to subtract with overflow"),
433 )
434 .expect("attempt to subtract resulted in non-canonical virtual address")
435 }
436}
437
438impl SubAssign<u64> for VirtAddr {
439 #[cfg_attr(not(feature = "step_trait"), allow(rustdoc::broken_intra_doc_links))]
440 #[inline]
451 fn sub_assign(&mut self, rhs: u64) {
452 *self = *self - rhs;
453 }
454}
455
456impl Sub<VirtAddr> for VirtAddr {
457 type Output = u64;
458
459 #[inline]
465 fn sub(self, rhs: VirtAddr) -> Self::Output {
466 self.as_u64()
467 .checked_sub(rhs.as_u64())
468 .expect("attempt to subtract with overflow")
469 }
470}
471
472#[cfg(feature = "step_trait")]
473impl Step for VirtAddr {
474 #[inline]
475 fn steps_between(start: &Self, end: &Self) -> (usize, Option<usize>) {
476 Self::steps_between_impl(start, end)
477 }
478
479 #[inline]
480 fn forward_checked(start: Self, count: usize) -> Option<Self> {
481 Self::forward_checked_impl(start, count)
482 }
483
484 #[inline]
485 fn backward_checked(start: Self, count: usize) -> Option<Self> {
486 Self::backward_checked_u64(start, u64::try_from(count).ok()?)
487 }
488
489 #[cfg(not(kani))]
493 #[inline]
494 fn forward_overflowing(start: Self, count: usize) -> (Self, bool) {
495 match Self::forward_checked(start, count) {
496 Some(next) => (next, false),
497 None => (start, true),
498 }
499 }
500
501 #[cfg(not(kani))]
505 #[inline]
506 fn backward_overflowing(start: Self, count: usize) -> (Self, bool) {
507 match Self::backward_checked(start, count) {
508 Some(next) => (next, false),
509 None => (start, true),
510 }
511 }
512}
513
514#[cfg(kani)]
515impl kani::Arbitrary for VirtAddr {
516 fn any() -> Self {
517 Self::new_truncate(kani::any())
518 }
519}
520
521pub struct PhysAddrNotValid(pub u64);
527
528impl core::fmt::Debug for PhysAddrNotValid {
529 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
530 f.debug_tuple("PhysAddrNotValid")
531 .field(&format_args!("{:#x}", self.0))
532 .finish()
533 }
534}
535
536impl PhysAddr {
537 #[inline]
546 #[const_fn(cfg(not(feature = "memory_encryption")))]
547 pub const fn new(addr: u64) -> Self {
548 match Self::try_new(addr) {
550 Ok(p) => p,
551 Err(_) => panic!("physical addresses must not have any bits in the range 52 to 64 set"),
552 }
553 }
554
555 #[cfg(not(feature = "memory_encryption"))]
557 #[inline]
558 pub const fn new_truncate(addr: u64) -> PhysAddr {
559 PhysAddr(addr % (1 << 52))
560 }
561
562 #[cfg(feature = "memory_encryption")]
564 #[inline]
565 pub fn new_truncate(addr: u64) -> PhysAddr {
566 PhysAddr((addr % (1 << 52)) & !ENC_BIT_MASK.load(Ordering::Relaxed))
567 }
568
569 #[inline]
575 pub const unsafe fn new_unsafe(addr: u64) -> PhysAddr {
576 PhysAddr(addr)
577 }
578
579 #[inline]
585 #[const_fn(cfg(not(feature = "memory_encryption")))]
586 pub const fn try_new(addr: u64) -> Result<Self, PhysAddrNotValid> {
587 let p = Self::new_truncate(addr);
588 if p.0 == addr {
589 Ok(p)
590 } else {
591 Err(PhysAddrNotValid(addr))
592 }
593 }
594
595 #[inline]
597 pub const fn zero() -> PhysAddr {
598 PhysAddr(0)
599 }
600
601 #[inline]
603 pub const fn as_u64(self) -> u64 {
604 self.0
605 }
606
607 #[inline]
609 pub const fn is_null(self) -> bool {
610 self.0 == 0
611 }
612
613 #[inline]
622 pub fn align_up<U>(self, align: U) -> Self
623 where
624 U: Into<u64>,
625 {
626 PhysAddr::new(align_up(self.0, align.into()))
627 }
628
629 #[inline]
633 pub fn align_down<U>(self, align: U) -> Self
634 where
635 U: Into<u64>,
636 {
637 self.align_down_u64(align.into())
638 }
639
640 #[inline]
644 pub(crate) const fn align_down_u64(self, align: u64) -> Self {
645 PhysAddr(align_down(self.0, align))
646 }
647
648 #[inline]
650 pub fn is_aligned<U>(self, align: U) -> bool
651 where
652 U: Into<u64>,
653 {
654 self.is_aligned_u64(align.into())
655 }
656
657 #[inline]
659 pub(crate) const fn is_aligned_u64(self, align: u64) -> bool {
660 self.align_down_u64(align).as_u64() == self.as_u64()
661 }
662}
663
664impl fmt::Debug for PhysAddr {
665 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
666 f.debug_tuple("PhysAddr")
667 .field(&format_args!("{:#x}", self.0))
668 .finish()
669 }
670}
671
672impl fmt::Binary for PhysAddr {
673 #[inline]
674 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
675 fmt::Binary::fmt(&self.0, f)
676 }
677}
678
679impl fmt::LowerHex for PhysAddr {
680 #[inline]
681 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
682 fmt::LowerHex::fmt(&self.0, f)
683 }
684}
685
686impl fmt::Octal for PhysAddr {
687 #[inline]
688 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
689 fmt::Octal::fmt(&self.0, f)
690 }
691}
692
693impl fmt::UpperHex for PhysAddr {
694 #[inline]
695 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
696 fmt::UpperHex::fmt(&self.0, f)
697 }
698}
699
700impl fmt::Pointer for PhysAddr {
701 #[inline]
702 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
703 fmt::Pointer::fmt(&(self.0 as *const ()), f)
704 }
705}
706
707impl Add<u64> for PhysAddr {
708 type Output = Self;
709 #[inline]
710 fn add(self, rhs: u64) -> Self::Output {
711 PhysAddr::new(self.0.checked_add(rhs).unwrap())
712 }
713}
714
715impl AddAssign<u64> for PhysAddr {
716 #[inline]
717 fn add_assign(&mut self, rhs: u64) {
718 *self = *self + rhs;
719 }
720}
721
722impl Sub<u64> for PhysAddr {
723 type Output = Self;
724 #[inline]
725 fn sub(self, rhs: u64) -> Self::Output {
726 PhysAddr::new(self.0.checked_sub(rhs).unwrap())
727 }
728}
729
730impl SubAssign<u64> for PhysAddr {
731 #[inline]
732 fn sub_assign(&mut self, rhs: u64) {
733 *self = *self - rhs;
734 }
735}
736
737impl Sub<PhysAddr> for PhysAddr {
738 type Output = u64;
739 #[inline]
740 fn sub(self, rhs: PhysAddr) -> Self::Output {
741 self.as_u64().checked_sub(rhs.as_u64()).unwrap()
742 }
743}
744
745#[cfg(kani)]
746impl kani::Arbitrary for PhysAddr {
747 fn any() -> Self {
748 Self::new_truncate(kani::any())
749 }
750}
751
752#[inline]
758pub const fn align_down(addr: u64, align: u64) -> u64 {
759 assert!(align.is_power_of_two(), "`align` must be a power of two");
760 addr & !(align - 1)
761}
762
763#[inline]
769pub const fn align_up(addr: u64, align: u64) -> u64 {
770 assert!(align.is_power_of_two(), "`align` must be a power of two");
771 let align_mask = align - 1;
772 if addr & align_mask == 0 {
773 addr } else {
775 if let Some(aligned) = (addr | align_mask).checked_add(1) {
777 aligned
778 } else {
779 panic!("attempt to add with overflow")
780 }
781 }
782}
783
784#[cfg(test)]
785mod tests {
786 use super::*;
787
788 #[test]
789 #[should_panic]
790 pub fn add_overflow_virtaddr() {
791 let _ = VirtAddr::new(0xffff_ffff_ffff_ffff) + 1;
792 }
793
794 #[test]
795 #[should_panic]
796 pub fn add_overflow_physaddr() {
797 let _ = PhysAddr::new(0x000f_ffff_ffff_ffff) + 0xffff_0000_0000_0000;
798 }
799
800 #[test]
801 #[should_panic]
802 pub fn sub_underflow_virtaddr() {
803 let _ = VirtAddr::new(0) - 1;
804 }
805
806 #[test]
807 #[should_panic]
808 pub fn sub_overflow_physaddr() {
809 let _ = PhysAddr::new(0) - 1;
810 }
811
812 #[test]
813 pub fn virtaddr_new_truncate() {
814 assert_eq!(VirtAddr::new_truncate(0), VirtAddr(0));
815 assert_eq!(VirtAddr::new_truncate(1 << 47), VirtAddr(0xfffff << 47));
816 assert_eq!(VirtAddr::new_truncate(123), VirtAddr(123));
817 assert_eq!(VirtAddr::new_truncate(123 << 47), VirtAddr(0xfffff << 47));
818 }
819
820 #[test]
821 #[cfg(feature = "step_trait")]
822 fn virtaddr_step_forward() {
823 assert_eq!(Step::forward(VirtAddr(0), 0), VirtAddr(0));
824 assert_eq!(Step::forward(VirtAddr(0), 1), VirtAddr(1));
825 assert_eq!(
826 Step::forward(VirtAddr(0x7fff_ffff_ffff), 1),
827 VirtAddr(0xffff_8000_0000_0000)
828 );
829 assert_eq!(
830 Step::forward(VirtAddr(0xffff_8000_0000_0000), 1),
831 VirtAddr(0xffff_8000_0000_0001)
832 );
833 assert_eq!(
834 Step::forward_checked(VirtAddr(0xffff_ffff_ffff_ffff), 1),
835 None
836 );
837 #[cfg(target_pointer_width = "64")]
838 assert_eq!(
839 Step::forward(VirtAddr(0x7fff_ffff_ffff), 0x1234_5678_9abd),
840 VirtAddr(0xffff_9234_5678_9abc)
841 );
842 #[cfg(target_pointer_width = "64")]
843 assert_eq!(
844 Step::forward(VirtAddr(0x7fff_ffff_ffff), 0x8000_0000_0000),
845 VirtAddr(0xffff_ffff_ffff_ffff)
846 );
847 #[cfg(target_pointer_width = "64")]
848 assert_eq!(
849 Step::forward(VirtAddr(0x7fff_ffff_ff00), 0x8000_0000_00ff),
850 VirtAddr(0xffff_ffff_ffff_ffff)
851 );
852 #[cfg(target_pointer_width = "64")]
853 assert_eq!(
854 Step::forward_checked(VirtAddr(0x7fff_ffff_ff00), 0x8000_0000_0100),
855 None
856 );
857 #[cfg(target_pointer_width = "64")]
858 assert_eq!(
859 Step::forward_checked(VirtAddr(0x7fff_ffff_ffff), 0x8000_0000_0001),
860 None
861 );
862 }
863
864 #[test]
865 #[cfg(feature = "step_trait")]
866 fn virtaddr_step_backward() {
867 assert_eq!(Step::backward(VirtAddr(0), 0), VirtAddr(0));
868 assert_eq!(Step::backward_checked(VirtAddr(0), 1), None);
869 assert_eq!(Step::backward(VirtAddr(1), 1), VirtAddr(0));
870 assert_eq!(
871 Step::backward(VirtAddr(0xffff_8000_0000_0000), 1),
872 VirtAddr(0x7fff_ffff_ffff)
873 );
874 assert_eq!(
875 Step::backward(VirtAddr(0xffff_8000_0000_0001), 1),
876 VirtAddr(0xffff_8000_0000_0000)
877 );
878 #[cfg(target_pointer_width = "64")]
879 assert_eq!(
880 Step::backward(VirtAddr(0xffff_9234_5678_9abc), 0x1234_5678_9abd),
881 VirtAddr(0x7fff_ffff_ffff)
882 );
883 #[cfg(target_pointer_width = "64")]
884 assert_eq!(
885 Step::backward(VirtAddr(0xffff_8000_0000_0000), 0x8000_0000_0000),
886 VirtAddr(0)
887 );
888 #[cfg(target_pointer_width = "64")]
889 assert_eq!(
890 Step::backward(VirtAddr(0xffff_8000_0000_0000), 0x7fff_ffff_ff01),
891 VirtAddr(0xff)
892 );
893 #[cfg(target_pointer_width = "64")]
894 assert_eq!(
895 Step::backward_checked(VirtAddr(0xffff_8000_0000_0000), 0x8000_0000_0001),
896 None
897 );
898 }
899
900 #[test]
901 #[cfg(feature = "step_trait")]
902 fn virtaddr_steps_between() {
903 assert_eq!(
904 Step::steps_between(&VirtAddr(0), &VirtAddr(0)),
905 (0, Some(0))
906 );
907 assert_eq!(
908 Step::steps_between(&VirtAddr(0), &VirtAddr(1)),
909 (1, Some(1))
910 );
911 assert_eq!(Step::steps_between(&VirtAddr(1), &VirtAddr(0)), (0, None));
912 assert_eq!(
913 Step::steps_between(
914 &VirtAddr(0x7fff_ffff_ffff),
915 &VirtAddr(0xffff_8000_0000_0000)
916 ),
917 (1, Some(1))
918 );
919 assert_eq!(
920 Step::steps_between(
921 &VirtAddr(0xffff_8000_0000_0000),
922 &VirtAddr(0x7fff_ffff_ffff)
923 ),
924 (0, None)
925 );
926 assert_eq!(
927 Step::steps_between(
928 &VirtAddr(0xffff_8000_0000_0000),
929 &VirtAddr(0xffff_8000_0000_0000)
930 ),
931 (0, Some(0))
932 );
933 assert_eq!(
934 Step::steps_between(
935 &VirtAddr(0xffff_8000_0000_0000),
936 &VirtAddr(0xffff_8000_0000_0001)
937 ),
938 (1, Some(1))
939 );
940 assert_eq!(
941 Step::steps_between(
942 &VirtAddr(0xffff_8000_0000_0001),
943 &VirtAddr(0xffff_8000_0000_0000)
944 ),
945 (0, None)
946 );
947 #[cfg(target_pointer_width = "64")]
953 assert_eq!(
954 Step::steps_between(&VirtAddr(0), &VirtAddr(0x1_0000_0000)),
955 (0x1_0000_0000, Some(0x1_0000_0000))
956 );
957 #[cfg(not(target_pointer_width = "64"))]
958 assert_eq!(
959 Step::steps_between(&VirtAddr(0), &VirtAddr(0x1_0000_0000)),
960 (usize::MAX, None)
961 );
962 }
963
964 #[test]
965 #[cfg(feature = "step_trait")]
966 fn virtaddr_step_overflowing() {
967 assert_eq!(
968 Step::forward_overflowing(VirtAddr(0x7fff_ffff_ffff), 1),
969 (VirtAddr(0xffff_8000_0000_0000), false)
970 );
971 assert_eq!(
972 Step::backward_overflowing(VirtAddr(0xffff_8000_0000_0000), 1),
973 (VirtAddr(0x7fff_ffff_ffff), false)
974 );
975 assert_eq!(
976 Step::forward_overflowing(VirtAddr(0), 0),
977 (VirtAddr(0), false)
978 );
979
980 assert!(Step::forward_overflowing(VirtAddr(0xffff_ffff_ffff_ffff), 1).1);
981 assert!(Step::backward_overflowing(VirtAddr(0), 1).1);
982 }
983
984 #[test]
985 pub fn test_align_up() {
986 assert_eq!(align_up(0, 1), 0);
988 assert_eq!(align_up(1234, 1), 1234);
989 assert_eq!(align_up(0xffff_ffff_ffff_ffff, 1), 0xffff_ffff_ffff_ffff);
990 assert_eq!(align_up(0, 2), 0);
992 assert_eq!(align_up(1233, 2), 1234);
993 assert_eq!(align_up(0xffff_ffff_ffff_fffe, 2), 0xffff_ffff_ffff_fffe);
994 assert_eq!(align_up(0, 128), 0);
996 assert_eq!(align_up(0, 1), 0);
997 assert_eq!(align_up(0, 2), 0);
998 assert_eq!(align_up(0, 0x8000_0000_0000_0000), 0);
999 }
1000
1001 #[test]
1002 fn test_virt_addr_align_up() {
1003 assert_eq!(
1005 VirtAddr::new(0x7fff_ffff_ffff).align_up(2u64),
1006 VirtAddr::new(0xffff_8000_0000_0000)
1007 );
1008 }
1009
1010 #[test]
1011 fn test_virt_addr_align_down() {
1012 assert_eq!(
1014 VirtAddr::new(0xffff_8000_0000_0000).align_down(1u64 << 48),
1015 VirtAddr::new(0)
1016 );
1017 }
1018
1019 #[test]
1020 #[should_panic]
1021 fn test_virt_addr_align_up_overflow() {
1022 VirtAddr::new(0xffff_ffff_ffff_ffff).align_up(2u64);
1023 }
1024
1025 #[test]
1026 #[should_panic]
1027 fn test_phys_addr_align_up_overflow() {
1028 PhysAddr::new(0x000f_ffff_ffff_ffff).align_up(2u64);
1029 }
1030
1031 #[test]
1032 #[cfg(target_pointer_width = "64")]
1033 fn test_from_ptr_array() {
1034 let slice = &[1, 2, 3, 4, 5];
1035 assert_eq!(
1037 VirtAddr::from_ptr(slice.as_slice()),
1038 VirtAddr::from_ptr(&slice[0])
1039 );
1040 }
1041}
1042
1043#[cfg(kani)]
1044mod proofs {
1045 use super::*;
1046
1047 #[kani::proof]
1053 fn forward_base_case() {
1054 let start = kani::any::<VirtAddr>();
1055 let start_raw = start.as_u64();
1056
1057 let same = Step::forward(start, 0);
1059 assert!(start == same);
1060
1061 let expected = match start_raw {
1063 0x0000_0000_0000_0000..=0x0000_7fff_ffff_fffe => Some(start_raw + 1),
1066 0x0000_7fff_ffff_ffff => Some(0xffff_8000_0000_0000),
1068 0x0000_8000_0000_0000..=0xffff_7fff_ffff_ffff => unreachable!(),
1070 0xffff_8000_0000_0000..=0xffff_ffff_ffff_fffe => Some(start_raw + 1),
1073 0xffff_ffff_ffff_ffff => None,
1075 };
1076 if let Some(expected) = expected {
1077 assert!(VirtAddr::try_new(expected).is_ok());
1079 }
1080 let next = Step::forward_checked(start, 1);
1082 assert!(next.map(VirtAddr::as_u64) == expected);
1083 }
1084
1085 #[kani::proof]
1088 fn forward_induction_step() {
1089 let start = kani::any::<VirtAddr>();
1090
1091 let count1: usize = kani::any();
1092 let count2: usize = kani::any();
1093 let Some(next1) = Step::forward_checked(start, count1) else {
1095 return;
1096 };
1097 let Some(next2) = Step::forward_checked(next1, count2) else {
1098 return;
1099 };
1100
1101 let count_both = count1 + count2;
1103 let next_both = Step::forward(start, count_both);
1104 assert!(next2 == next_both);
1105 }
1106
1107 #[kani::proof]
1115 fn forward_implies_backward() {
1116 let start = kani::any::<VirtAddr>();
1117 let count: usize = kani::any();
1118
1119 let Some(end) = Step::forward_checked(start, count) else {
1121 return;
1122 };
1123
1124 let start2 = Step::backward(end, count);
1126 assert!(start == start2);
1127 }
1128
1129 #[kani::proof]
1132 fn backward_implies_forward() {
1133 let end = kani::any::<VirtAddr>();
1134 let count: usize = kani::any();
1135
1136 let Some(start) = Step::backward_checked(end, count) else {
1138 return;
1139 };
1140
1141 let end2 = Step::forward(start, count);
1143 assert!(end == end2);
1144 }
1145
1146 #[kani::proof]
1154 fn forward_implies_steps_between() {
1155 let start = kani::any::<VirtAddr>();
1156 let count: usize = kani::any();
1157
1158 let Some(end) = Step::forward_checked(start, count) else {
1160 return;
1161 };
1162
1163 assert!(Step::steps_between(&start, &end) == (count, Some(count)));
1165 }
1166
1167 #[kani::proof]
1170 fn steps_between_implies_forward() {
1171 let start = kani::any::<VirtAddr>();
1172 let end = kani::any::<VirtAddr>();
1173
1174 let Some(count) = Step::steps_between(&start, &end).1 else {
1176 return;
1177 };
1178
1179 assert!(Step::forward(start, count) == end);
1181 }
1182}