@@ -161,17 +161,26 @@ impl<S: PageSize> Page<S> {
161
161
// FIXME: Move this into the `Step` impl, once `Step` is stabilized.
162
162
#[ cfg( any( feature = "instructions" , feature = "step_trait" ) ) ]
163
163
pub ( crate ) fn steps_between_impl ( start : & Self , end : & Self ) -> ( usize , Option < usize > ) {
164
- let ( lower, upper) = VirtAddr :: steps_between_impl ( & start. start_address , & end. start_address ) ;
165
- let lower = lower / S :: SIZE as usize ;
166
- let upper = upper. map ( |steps| steps / S :: SIZE as usize ) ;
167
- ( lower, upper)
164
+ use core:: convert:: TryFrom ;
165
+
166
+ if let Some ( steps) =
167
+ VirtAddr :: steps_between_u64 ( & start. start_address ( ) , & end. start_address ( ) )
168
+ {
169
+ let steps = steps / S :: SIZE ;
170
+ let steps = usize:: try_from ( steps) . ok ( ) ;
171
+ ( steps. unwrap_or ( !0 ) , steps)
172
+ } else {
173
+ ( 0 , None )
174
+ }
168
175
}
169
176
170
177
// FIXME: Move this into the `Step` impl, once `Step` is stabilized.
171
178
#[ cfg( any( feature = "instructions" , feature = "step_trait" ) ) ]
172
179
pub ( crate ) fn forward_checked_impl ( start : Self , count : usize ) -> Option < Self > {
173
- let count = count. checked_mul ( S :: SIZE as usize ) ?;
174
- let start_address = VirtAddr :: forward_checked_impl ( start. start_address , count) ?;
180
+ use core:: convert:: TryFrom ;
181
+
182
+ let count = u64:: try_from ( count) . ok ( ) ?. checked_mul ( S :: SIZE ) ?;
183
+ let start_address = VirtAddr :: forward_checked_u64 ( start. start_address , count) ?;
175
184
Some ( Self {
176
185
start_address,
177
186
size : PhantomData ,
@@ -304,8 +313,10 @@ impl<S: PageSize> Step for Page<S> {
304
313
}
305
314
306
315
fn backward_checked ( start : Self , count : usize ) -> Option < Self > {
307
- let count = count. checked_mul ( S :: SIZE as usize ) ?;
308
- let start_address = Step :: backward_checked ( start. start_address , count) ?;
316
+ use core:: convert:: TryFrom ;
317
+
318
+ let count = u64:: try_from ( count) . ok ( ) ?. checked_mul ( S :: SIZE ) ?;
319
+ let start_address = VirtAddr :: backward_checked_u64 ( start. start_address , count) ?;
309
320
Some ( Self {
310
321
start_address,
311
322
size : PhantomData ,
@@ -531,4 +542,106 @@ mod tests {
531
542
let range_inclusive = PageRangeInclusive { start, end } ;
532
543
assert_eq ! ( range_inclusive. len( ) , 51 ) ;
533
544
}
545
+
546
+ #[ test]
547
+ #[ cfg( feature = "step_trait" ) ]
548
+ fn page_step_forward ( ) {
549
+ let test_cases = [
550
+ ( 0 , 0 , Some ( 0 ) ) ,
551
+ ( 0 , 1 , Some ( 0x1000 ) ) ,
552
+ ( 0x1000 , 1 , Some ( 0x2000 ) ) ,
553
+ ( 0x7fff_ffff_f000 , 1 , Some ( 0xffff_8000_0000_0000 ) ) ,
554
+ ( 0xffff_8000_0000_0000 , 1 , Some ( 0xffff_8000_0000_1000 ) ) ,
555
+ ( 0xffff_ffff_ffff_f000 , 1 , None ) ,
556
+ #[ cfg( target_pointer_width = "64" ) ]
557
+ ( 0x7fff_ffff_f000 , 0x1_2345_6789 , Some ( 0xffff_9234_5678_8000 ) ) ,
558
+ #[ cfg( target_pointer_width = "64" ) ]
559
+ ( 0x7fff_ffff_f000 , 0x8_0000_0000 , Some ( 0xffff_ffff_ffff_f000 ) ) ,
560
+ #[ cfg( target_pointer_width = "64" ) ]
561
+ ( 0x7fff_fff0_0000 , 0x8_0000_00ff , Some ( 0xffff_ffff_ffff_f000 ) ) ,
562
+ #[ cfg( target_pointer_width = "64" ) ]
563
+ ( 0x7fff_fff0_0000 , 0x8_0000_0100 , None ) ,
564
+ #[ cfg( target_pointer_width = "64" ) ]
565
+ ( 0x7fff_ffff_f000 , 0x8_0000_0001 , None ) ,
566
+ // Make sure that we handle `steps * PAGE_SIZE > u32::MAX`
567
+ // correctly on 32-bit targets.
568
+ ( 0 , 0x10_0000 , Some ( 0x1_0000_0000 ) ) ,
569
+ ] ;
570
+ for ( start, count, result) in test_cases {
571
+ let start = Page :: < Size4KiB > :: from_start_address ( VirtAddr :: new ( start) ) . unwrap ( ) ;
572
+ let result = result
573
+ . map ( |result| Page :: < Size4KiB > :: from_start_address ( VirtAddr :: new ( result) ) . unwrap ( ) ) ;
574
+ assert_eq ! ( Step :: forward_checked( start, count) , result) ;
575
+ }
576
+ }
577
+
578
+ #[ test]
579
+ #[ cfg( feature = "step_trait" ) ]
580
+ fn page_step_backwards ( ) {
581
+ let test_cases = [
582
+ ( 0 , 0 , Some ( 0 ) ) ,
583
+ ( 0 , 1 , None ) ,
584
+ ( 0x1000 , 1 , Some ( 0 ) ) ,
585
+ ( 0xffff_8000_0000_0000 , 1 , Some ( 0x7fff_ffff_f000 ) ) ,
586
+ ( 0xffff_8000_0000_1000 , 1 , Some ( 0xffff_8000_0000_0000 ) ) ,
587
+ #[ cfg( target_pointer_width = "64" ) ]
588
+ ( 0xffff_9234_5678_8000 , 0x1_2345_6789 , Some ( 0x7fff_ffff_f000 ) ) ,
589
+ #[ cfg( target_pointer_width = "64" ) ]
590
+ ( 0xffff_8000_0000_0000 , 0x8_0000_0000 , Some ( 0 ) ) ,
591
+ #[ cfg( target_pointer_width = "64" ) ]
592
+ ( 0xffff_8000_0000_0000 , 0x7_ffff_ff01 , Some ( 0xff000 ) ) ,
593
+ #[ cfg( target_pointer_width = "64" ) ]
594
+ ( 0xffff_8000_0000_0000 , 0x8_0000_0001 , None ) ,
595
+ // Make sure that we handle `steps * PAGE_SIZE > u32::MAX`
596
+ // correctly on 32-bit targets.
597
+ ( 0x1_0000_0000 , 0x10_0000 , Some ( 0 ) ) ,
598
+ ] ;
599
+ for ( start, count, result) in test_cases {
600
+ let start = Page :: < Size4KiB > :: from_start_address ( VirtAddr :: new ( start) ) . unwrap ( ) ;
601
+ let result = result
602
+ . map ( |result| Page :: < Size4KiB > :: from_start_address ( VirtAddr :: new ( result) ) . unwrap ( ) ) ;
603
+ assert_eq ! ( Step :: backward_checked( start, count) , result) ;
604
+ }
605
+ }
606
+
607
+ #[ test]
608
+ #[ cfg( feature = "step_trait" ) ]
609
+ fn page_steps_between ( ) {
610
+ let test_cases = [
611
+ ( 0 , 0 , 0 , Some ( 0 ) ) ,
612
+ ( 0 , 0x1000 , 1 , Some ( 1 ) ) ,
613
+ ( 0x1000 , 0 , 0 , None ) ,
614
+ ( 0x1000 , 0x1000 , 0 , Some ( 0 ) ) ,
615
+ ( 0x7fff_ffff_f000 , 0xffff_8000_0000_0000 , 1 , Some ( 1 ) ) ,
616
+ ( 0xffff_8000_0000_0000 , 0x7fff_ffff_f000 , 0 , None ) ,
617
+ ( 0xffff_8000_0000_0000 , 0xffff_8000_0000_0000 , 0 , Some ( 0 ) ) ,
618
+ ( 0xffff_8000_0000_0000 , 0xffff_8000_0000_1000 , 1 , Some ( 1 ) ) ,
619
+ ( 0xffff_8000_0000_1000 , 0xffff_8000_0000_0000 , 0 , None ) ,
620
+ ( 0xffff_8000_0000_1000 , 0xffff_8000_0000_1000 , 0 , Some ( 0 ) ) ,
621
+ // Make sure that we handle `steps > u32::MAX` correctly on 32-bit
622
+ // targets.
623
+ (
624
+ 0x0000_0000_0000 ,
625
+ 0x0001_0000_0000 ,
626
+ 0x10_0000 ,
627
+ Some ( 0x10_0000 ) ,
628
+ ) ,
629
+ // The returned bounds are different when `steps` doesn't fit in
630
+ // into `usize`.
631
+ #[ cfg( target_pointer_width = "64" ) ]
632
+ (
633
+ 0x0000_0000_0000 ,
634
+ 0x1000_0000_0000 ,
635
+ 0x1_0000_0000 ,
636
+ Some ( 0x1_0000_0000 ) ,
637
+ ) ,
638
+ #[ cfg( not( target_pointer_width = "64" ) ) ]
639
+ ( 0x0000_0000_0000 , 0x1000_0000_0000 , !0 , None ) ,
640
+ ] ;
641
+ for ( start, end, lower, upper) in test_cases {
642
+ let start = Page :: < Size4KiB > :: from_start_address ( VirtAddr :: new ( start) ) . unwrap ( ) ;
643
+ let end = Page :: from_start_address ( VirtAddr :: new ( end) ) . unwrap ( ) ;
644
+ assert_eq ! ( Step :: steps_between( & start, & end) , ( lower, upper) ) ;
645
+ }
646
+ }
534
647
}
0 commit comments