@@ -459,6 +459,17 @@ impl kani::Arbitrary for ProofContext {
459
459
}
460
460
}
461
461
462
+ /// Helper function to determine if `point` is in the wrapping range `[start, stop)`.
463
+ fn pred_in_wrapping_range ( start : Wrapping < u16 > , stop : Wrapping < u16 > , point : Wrapping < u16 > ) -> bool {
464
+ // Check if point is in the range [start, stop) in a wrapping manner.
465
+ if start <= stop {
466
+ start <= point && point < stop
467
+ } else {
468
+ // If start > stop, we wrap around the maximum value of u16.
469
+ point >= start || point < stop
470
+ }
471
+ }
472
+
462
473
/// # Specification (VirtIO 1.3, Section 2.7.7.2: "Device Requirements: Used Buffer Notification Suppression")
463
474
///
464
475
/// Section 2.7.7.2 deals with device-to-driver notification suppression. It
@@ -468,46 +479,35 @@ impl kani::Arbitrary for ProofContext {
468
479
/// specific number of descriptors has been processed. This is done by the
469
480
/// driver defining a "used_event" index, which tells the device "please do not
470
481
/// notify me until used.ring[used_event] has been written to by you".
482
+ ///
483
+ /// This proof checks:
484
+ // - If event_idx is not enabled, a notification is always needed.
485
+ // - If event_idx is enabled, a notification is needed if the used_event index
486
+ // is in the wrapping range [next_used - num_added, next_used).
471
487
#[ kani:: proof]
472
488
// There are no loops anywhere, but kani really enjoys getting stuck in
473
489
// std::ptr::drop_in_place. This is a compiler intrinsic that has a "dummy"
474
490
// implementation in stdlib that just recursively calls itself. Kani will
475
491
// generally unwind this recursion infinitely.
476
492
#[ kani:: unwind( 0 ) ]
477
- fn verify_device_notification_suppression ( ) {
478
- let ProofContext {
479
- mut queue,
480
- memory : mem,
481
- } = kani:: any ( ) ;
482
-
483
- let num_added_old = queue. num_added . 0 ;
484
- let needs_notification = queue. needs_notification ( & mem) ;
493
+ fn verify_device_to_driver_notification ( ) {
494
+ let ProofContext { mut queue, memory } = kani:: any ( ) ;
485
495
486
- // event_idx_enabled equivalent to VIRTIO_F_EVENT_IDX negotiated
496
+ // If the event_idx_enabled is false, we always need a notification
487
497
if !queue. event_idx_enabled {
488
- // The specification here says
489
- // After the device writes a descriptor index into the used ring:
490
- // – If flags is 1, the device SHOULD NOT send a notification.
491
- // – If flags is 0, the device MUST send a notification
492
- // flags is the first field in the avail_ring_address, which we completely ignore. We
493
- // always send a notification, and as there only is a SHOULD NOT, that is okay
494
- assert ! ( needs_notification. unwrap( ) ) ;
498
+ assert ! ( queue. needs_notification( & memory) . unwrap( ) ) ;
495
499
} else {
496
- // next_used - 1 is where the previous descriptor was placed
497
- if Wrapping ( queue. used_event ( & mem, Ordering :: Relaxed ) . unwrap ( ) )
498
- == std:: num:: Wrapping ( queue. next_used - Wrapping ( 1 ) )
499
- && num_added_old > 0
500
- {
501
- // If the idx field in the used ring (which determined where that descriptor index
502
- // was placed) was equal to used_event, the device MUST send a
503
- // notification.
504
- assert ! ( needs_notification. unwrap( ) ) ;
505
-
506
- kani:: cover!( ) ;
507
- }
508
-
509
- // The other case is handled by a "SHOULD NOT send a notification" in the spec.
510
- // So we do not care
500
+ // If the event_idx_enabled is true, we only need a notification if
501
+ // the used_event is in the range of [next_used - num_added, next_used)
502
+ let used_event = queue. used_event ( & memory, Ordering :: Relaxed ) . unwrap ( ) ;
503
+ let current_used = queue. next_used ;
504
+ let old = current_used - queue. num_added ;
505
+ let should_notify = pred_in_wrapping_range ( old, current_used, used_event) ;
506
+ assert_eq ! (
507
+ queue. needs_notification( & memory) . unwrap( ) , /* actual */
508
+ should_notify, /* expected */
509
+ ) ;
510
+ assert_eq ! ( queue. num_added. 0 , 0 ) ;
511
511
}
512
512
}
513
513
0 commit comments