@@ -161,17 +161,26 @@ impl<S: PageSize> Page<S> {
161161 // FIXME: Move this into the `Step` impl, once `Step` is stabilized.
162162 #[ cfg( any( feature = "instructions" , feature = "step_trait" ) ) ]
163163 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+ }
168175 }
169176
170177 // FIXME: Move this into the `Step` impl, once `Step` is stabilized.
171178 #[ cfg( any( feature = "instructions" , feature = "step_trait" ) ) ]
172179 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) ?;
175184 Some ( Self {
176185 start_address,
177186 size : PhantomData ,
@@ -304,8 +313,10 @@ impl<S: PageSize> Step for Page<S> {
304313 }
305314
306315 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) ?;
309320 Some ( Self {
310321 start_address,
311322 size : PhantomData ,
@@ -531,4 +542,106 @@ mod tests {
531542 let range_inclusive = PageRangeInclusive { start, end } ;
532543 assert_eq ! ( range_inclusive. len( ) , 51 ) ;
533544 }
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+ }
534647}
0 commit comments