1
1
//! Physical and virtual addresses manipulation
2
2
3
+ #[ cfg( feature = "step_trait" ) ]
4
+ use core:: convert:: TryFrom ;
3
5
use core:: fmt;
6
+ #[ cfg( feature = "step_trait" ) ]
7
+ use core:: iter:: Step ;
4
8
use core:: ops:: { Add , AddAssign , Sub , SubAssign } ;
5
9
6
10
use crate :: structures:: paging:: page_table:: PageTableLevel ;
7
11
use crate :: structures:: paging:: { PageOffset , PageTableIndex } ;
8
12
use bit_field:: BitField ;
9
13
14
+ #[ cfg( feature = "step_trait" ) ]
15
+ const ADDRESS_SPACE_SIZE : u64 = 0x1_0000_0000_0000 ;
16
+
10
17
/// A canonical 64-bit virtual memory address.
11
18
///
12
19
/// This is a wrapper type around an `u64`, so it is always 8 bytes, even when compiled
@@ -40,9 +47,18 @@ pub struct PhysAddr(u64);
40
47
/// a valid sign extension and are not null either. So automatic sign extension would have
41
48
/// overwritten possibly meaningful bits. This likely indicates a bug, for example an invalid
42
49
/// address calculation.
43
- #[ derive( Debug ) ]
50
+ ///
51
+ /// Contains the invalid address.
44
52
pub struct VirtAddrNotValid ( pub u64 ) ;
45
53
54
+ impl 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
+
46
62
impl VirtAddr {
47
63
/// Creates a new canonical virtual address.
48
64
///
@@ -70,7 +86,7 @@ impl VirtAddr {
70
86
match addr. get_bits ( 47 ..64 ) {
71
87
0 | 0x1ffff => Ok ( VirtAddr ( addr) ) , // address is canonical
72
88
1 => Ok ( VirtAddr :: new_truncate ( addr) ) , // address needs sign extension
73
- other => Err ( VirtAddrNotValid ( other ) ) ,
89
+ _ => Err ( VirtAddrNotValid ( addr ) ) ,
74
90
}
75
91
}
76
92
@@ -322,12 +338,81 @@ impl Sub<VirtAddr> for VirtAddr {
322
338
}
323
339
}
324
340
341
+ #[ cfg( feature = "step_trait" ) ]
342
+ impl Step for VirtAddr {
343
+ fn steps_between ( start : & Self , end : & Self ) -> Option < usize > {
344
+ let mut steps = end. 0 . checked_sub ( start. 0 ) ?;
345
+
346
+ // Check if we jumped the gap.
347
+ if end. 0 . get_bit ( 47 ) && !start. 0 . get_bit ( 47 ) {
348
+ steps = steps. checked_sub ( 0xffff_0000_0000_0000 ) . unwrap ( ) ;
349
+ }
350
+
351
+ usize:: try_from ( steps) . ok ( )
352
+ }
353
+
354
+ fn forward_checked ( start : Self , count : usize ) -> Option < Self > {
355
+ let offset = u64:: try_from ( count) . ok ( ) ?;
356
+ if offset > ADDRESS_SPACE_SIZE {
357
+ return None ;
358
+ }
359
+
360
+ let mut addr = start. 0 . checked_add ( offset) ?;
361
+
362
+ match addr. get_bits ( 47 ..) {
363
+ 0x1 => {
364
+ // Jump the gap by sign extending the 47th bit.
365
+ addr. set_bits ( 47 .., 0x1ffff ) ;
366
+ }
367
+ 0x2 => {
368
+ // Address overflow
369
+ return None ;
370
+ }
371
+ _ => { }
372
+ }
373
+
374
+ Some ( Self :: new ( addr) )
375
+ }
376
+
377
+ fn backward_checked ( start : Self , count : usize ) -> Option < Self > {
378
+ let offset = u64:: try_from ( count) . ok ( ) ?;
379
+ if offset > ADDRESS_SPACE_SIZE {
380
+ return None ;
381
+ }
382
+
383
+ let mut addr = start. 0 . checked_sub ( offset) ?;
384
+
385
+ match addr. get_bits ( 47 ..) {
386
+ 0x1fffe => {
387
+ // Jump the gap by sign extending the 47th bit.
388
+ addr. set_bits ( 47 .., 0 ) ;
389
+ }
390
+ 0x1fffd => {
391
+ // Address underflow
392
+ return None ;
393
+ }
394
+ _ => { }
395
+ }
396
+
397
+ Some ( Self :: new ( addr) )
398
+ }
399
+ }
400
+
325
401
/// A passed `u64` was not a valid physical address.
326
402
///
327
403
/// This means that bits 52 to 64 were not all null.
328
- #[ derive( Debug ) ]
404
+ ///
405
+ /// Contains the invalid address.
329
406
pub struct PhysAddrNotValid ( pub u64 ) ;
330
407
408
+ impl core:: fmt:: Debug for PhysAddrNotValid {
409
+ fn fmt ( & self , f : & mut fmt:: Formatter < ' _ > ) -> fmt:: Result {
410
+ f. debug_tuple ( "PhysAddrNotValid" )
411
+ . field ( & format_args ! ( "{:#x}" , self . 0 ) )
412
+ . finish ( )
413
+ }
414
+ }
415
+
331
416
impl PhysAddr {
332
417
/// Creates a new physical address.
333
418
///
@@ -367,7 +452,7 @@ impl PhysAddr {
367
452
pub fn try_new ( addr : u64 ) -> Result < PhysAddr , PhysAddrNotValid > {
368
453
match addr. get_bits ( 52 ..64 ) {
369
454
0 => Ok ( PhysAddr ( addr) ) , // address is valid
370
- other => Err ( PhysAddrNotValid ( other ) ) ,
455
+ _ => Err ( PhysAddrNotValid ( addr ) ) ,
371
456
}
372
457
}
373
458
@@ -540,8 +625,7 @@ impl Sub<PhysAddr> for PhysAddr {
540
625
///
541
626
/// Returns the greatest `x` with alignment `align` so that `x <= addr`.
542
627
///
543
- /// Panics if the alignment is not a power of two. Without the `const_fn`
544
- /// feature, the panic message will be "index out of bounds".
628
+ /// Panics if the alignment is not a power of two.
545
629
#[ inline]
546
630
pub const fn align_down ( addr : u64 , align : u64 ) -> u64 {
547
631
assert ! ( align. is_power_of_two( ) , "`align` must be a power of two" ) ;
@@ -552,8 +636,7 @@ pub const fn align_down(addr: u64, align: u64) -> u64 {
552
636
///
553
637
/// Returns the smallest `x` with alignment `align` so that `x >= addr`.
554
638
///
555
- /// Panics if the alignment is not a power of two. Without the `const_fn`
556
- /// feature, the panic message will be "index out of bounds".
639
+ /// Panics if the alignment is not a power of two.
557
640
#[ inline]
558
641
pub const fn align_up ( addr : u64 , align : u64 ) -> u64 {
559
642
assert ! ( align. is_power_of_two( ) , "`align` must be a power of two" ) ;
@@ -577,6 +660,120 @@ mod tests {
577
660
assert_eq ! ( VirtAddr :: new_truncate( 123 << 47 ) , VirtAddr ( 0xfffff << 47 ) ) ;
578
661
}
579
662
663
+ #[ test]
664
+ #[ cfg( feature = "step_trait" ) ]
665
+ fn virtaddr_step_forward ( ) {
666
+ assert_eq ! ( Step :: forward( VirtAddr ( 0 ) , 0 ) , VirtAddr ( 0 ) ) ;
667
+ assert_eq ! ( Step :: forward( VirtAddr ( 0 ) , 1 ) , VirtAddr ( 1 ) ) ;
668
+ assert_eq ! (
669
+ Step :: forward( VirtAddr ( 0x7fff_ffff_ffff ) , 1 ) ,
670
+ VirtAddr ( 0xffff_8000_0000_0000 )
671
+ ) ;
672
+ assert_eq ! (
673
+ Step :: forward( VirtAddr ( 0xffff_8000_0000_0000 ) , 1 ) ,
674
+ VirtAddr ( 0xffff_8000_0000_0001 )
675
+ ) ;
676
+ assert_eq ! (
677
+ Step :: forward_checked( VirtAddr ( 0xffff_ffff_ffff_ffff ) , 1 ) ,
678
+ None
679
+ ) ;
680
+ assert_eq ! (
681
+ Step :: forward( VirtAddr ( 0x7fff_ffff_ffff ) , 0x1234_5678_9abd ) ,
682
+ VirtAddr ( 0xffff_9234_5678_9abc )
683
+ ) ;
684
+ assert_eq ! (
685
+ Step :: forward( VirtAddr ( 0x7fff_ffff_ffff ) , 0x8000_0000_0000 ) ,
686
+ VirtAddr ( 0xffff_ffff_ffff_ffff )
687
+ ) ;
688
+ assert_eq ! (
689
+ Step :: forward( VirtAddr ( 0x7fff_ffff_ff00 ) , 0x8000_0000_00ff ) ,
690
+ VirtAddr ( 0xffff_ffff_ffff_ffff )
691
+ ) ;
692
+ assert_eq ! (
693
+ Step :: forward_checked( VirtAddr ( 0x7fff_ffff_ff00 ) , 0x8000_0000_0100 ) ,
694
+ None
695
+ ) ;
696
+ assert_eq ! (
697
+ Step :: forward_checked( VirtAddr ( 0x7fff_ffff_ffff ) , 0x8000_0000_0001 ) ,
698
+ None
699
+ ) ;
700
+ }
701
+
702
+ #[ test]
703
+ #[ cfg( feature = "step_trait" ) ]
704
+ fn virtaddr_step_backward ( ) {
705
+ assert_eq ! ( Step :: backward( VirtAddr ( 0 ) , 0 ) , VirtAddr ( 0 ) ) ;
706
+ assert_eq ! ( Step :: backward_checked( VirtAddr ( 0 ) , 1 ) , None ) ;
707
+ assert_eq ! ( Step :: backward( VirtAddr ( 1 ) , 1 ) , VirtAddr ( 0 ) ) ;
708
+ assert_eq ! (
709
+ Step :: backward( VirtAddr ( 0xffff_8000_0000_0000 ) , 1 ) ,
710
+ VirtAddr ( 0x7fff_ffff_ffff )
711
+ ) ;
712
+ assert_eq ! (
713
+ Step :: backward( VirtAddr ( 0xffff_8000_0000_0001 ) , 1 ) ,
714
+ VirtAddr ( 0xffff_8000_0000_0000 )
715
+ ) ;
716
+ assert_eq ! (
717
+ Step :: backward( VirtAddr ( 0xffff_9234_5678_9abc ) , 0x1234_5678_9abd ) ,
718
+ VirtAddr ( 0x7fff_ffff_ffff )
719
+ ) ;
720
+ assert_eq ! (
721
+ Step :: backward( VirtAddr ( 0xffff_8000_0000_0000 ) , 0x8000_0000_0000 ) ,
722
+ VirtAddr ( 0 )
723
+ ) ;
724
+ assert_eq ! (
725
+ Step :: backward( VirtAddr ( 0xffff_8000_0000_0000 ) , 0x7fff_ffff_ff01 ) ,
726
+ VirtAddr ( 0xff )
727
+ ) ;
728
+ assert_eq ! (
729
+ Step :: backward_checked( VirtAddr ( 0xffff_8000_0000_0000 ) , 0x8000_0000_0001 ) ,
730
+ None
731
+ ) ;
732
+ }
733
+
734
+ #[ test]
735
+ #[ cfg( feature = "step_trait" ) ]
736
+ fn virtaddr_steps_between ( ) {
737
+ assert_eq ! ( Step :: steps_between( & VirtAddr ( 0 ) , & VirtAddr ( 0 ) ) , Some ( 0 ) ) ;
738
+ assert_eq ! ( Step :: steps_between( & VirtAddr ( 0 ) , & VirtAddr ( 1 ) ) , Some ( 1 ) ) ;
739
+ assert_eq ! ( Step :: steps_between( & VirtAddr ( 1 ) , & VirtAddr ( 0 ) ) , None ) ;
740
+ assert_eq ! (
741
+ Step :: steps_between(
742
+ & VirtAddr ( 0x7fff_ffff_ffff ) ,
743
+ & VirtAddr ( 0xffff_8000_0000_0000 )
744
+ ) ,
745
+ Some ( 1 )
746
+ ) ;
747
+ assert_eq ! (
748
+ Step :: steps_between(
749
+ & VirtAddr ( 0xffff_8000_0000_0000 ) ,
750
+ & VirtAddr ( 0x7fff_ffff_ffff )
751
+ ) ,
752
+ None
753
+ ) ;
754
+ assert_eq ! (
755
+ Step :: steps_between(
756
+ & VirtAddr ( 0xffff_8000_0000_0000 ) ,
757
+ & VirtAddr ( 0xffff_8000_0000_0000 )
758
+ ) ,
759
+ Some ( 0 )
760
+ ) ;
761
+ assert_eq ! (
762
+ Step :: steps_between(
763
+ & VirtAddr ( 0xffff_8000_0000_0000 ) ,
764
+ & VirtAddr ( 0xffff_8000_0000_0001 )
765
+ ) ,
766
+ Some ( 1 )
767
+ ) ;
768
+ assert_eq ! (
769
+ Step :: steps_between(
770
+ & VirtAddr ( 0xffff_8000_0000_0001 ) ,
771
+ & VirtAddr ( 0xffff_8000_0000_0000 )
772
+ ) ,
773
+ None
774
+ ) ;
775
+ }
776
+
580
777
#[ test]
581
778
pub fn test_align_up ( ) {
582
779
// align 1
0 commit comments