Skip to main content

hyperlight_common/virtq/
ring.rs

1// SPDX-License-Identifier: Apache-2.0
2// Copyright 2026 The Hyperlight Authors.
3
4//! Packed Virtqueue Ring Implementation
5//!
6//! This module implements the packed virtqueue format from the VIRTIO specification.
7//! Packed virtqueues use a single descriptor ring where descriptors cycle through
8//! available and used states, providing better cache locality and simpler memory
9//! layout compared to split virtqueues.
10//!
11//! # Descriptor State Machine
12//!
13//! Each descriptor transitions through states using AVAIL and USED flags:
14//!
15//! ```text
16//!                    Driver publishes
17//!     ┌─────────┐    (AVAIL=wrap)     ┌───────────┐
18//!     │  Free   │ ──────────────────> │ Available │
19//!     └─────────┘                     └───────────┘
20//!          ^                                │
21//!          │                                │ Device consumes
22//!          │ Driver reclaims                │ and marks used
23//!          │ (polls USED=wrap)              │ (USED=wrap)
24//!          │                                v
25//!     ┌─────────┐                     ┌───────────┐
26//!     │Reclaimed│ <────────────────── │   Used    │
27//!     └─────────┘                     └───────────┘
28//! ```
29//!
30//! # Wrap Counter
31//!
32//! The wrap counter solves ring wraparound ambiguity. When cursors wrap around
33//! the ring, the wrap counter toggles, changing how AVAIL/USED flags are interpreted:
34//!
35//! - **wrap=true**: AVAIL=1, USED=0 means "available"; AVAIL=1, USED=1 means "used"
36//! - **wrap=false**: AVAIL=0, USED=1 means "available"; AVAIL=0, USED=0 means "used"
37//!
38//! # Buffer Chains
39//!
40//! Multiple buffers can be chained using the NEXT flag. All descriptors in a chain
41//! share the same ID, and only the head descriptor's AVAIL/USED flags matter for
42//! state transitions:
43//!
44//! ```text
45//! Chain with 3 buffers (ID=5):
46//! ┌──────────────┐    ┌──────────────┐    ┌──────────────┐
47//! │ Desc[0]      │    │ Desc[1]      │    │ Desc[2]      │
48//! │ id=42        │───>│ id=42        │───>│ id=42        │
49//! │ flags=NEXT   │    │ flags=NEXT   │    │ flags=0      │
50//! │ AVAIL/USED   │    │ (ignored)    │    │ (ignored)    │
51//! └──────────────┘    └──────────────┘    └──────────────┘
52//!       HEAD              MIDDLE               TAIL
53//! ```
54//!
55//! # Event Suppression
56//!
57//! Both sides can control when they want to be notified:
58//!
59//! - **ENABLE**: Always notify (default)
60//! - **DISABLE**: Never notify (for polling mode)
61//! - **DESC**: Notify only when a specific descriptor index is reached
62//! ```
63
64use core::fmt;
65use core::marker::PhantomData;
66use core::sync::atomic::{Ordering, fence};
67
68use bytemuck::Zeroable;
69use smallvec::SmallVec;
70use thiserror::Error;
71
72use super::desc::{DescFlags, DescTable, Descriptor};
73use super::event::{EventFlags, EventSuppression};
74use super::{Layout, MemOps};
75
76/// A single buffer element in a scatter-gather list.
77///
78/// Represents one contiguous memory region that the device will read from
79/// or write to. Multiple elements can be chained together to form a
80/// [`BufferChain`].
81#[derive(Debug, Copy, Clone, Zeroable)]
82pub struct BufferElement {
83    /// Physical address of buffer
84    pub addr: u64,
85    /// Length of the buffer in bytes
86    pub len: u32,
87    /// Whether this buffer is writable by the device
88    pub writable: bool,
89}
90
91/// A buffer returned from the ring after being used by the device.
92///
93/// When the device completes processing a buffer chain, it returns this
94/// structure containing the original descriptor ID and the number of bytes
95/// written (for chains with writable buffers).
96#[derive(Debug, Copy, Clone)]
97pub struct UsedBuffer {
98    /// Descriptor ID that was assigned when the buffer was submitted
99    pub id: u16,
100    /// Number of bytes written by the device to writable buffers.
101    /// For read-only chains, this may be 0 or the total readable length.
102    pub len: u32,
103}
104
105/// Result of submitting a buffer to the ring.
106///
107/// Contains the assigned descriptor ID and whether the other side
108/// needs to be notified about the new buffer.
109#[derive(Debug, Copy, Clone)]
110pub struct SubmitResult {
111    /// Descriptor ID assigned to the submitted buffer chain
112    /// Use this ID to correlate completions with submissions.
113    pub id: u16,
114    /// Whether the device should be notified immediately based on the other
115    /// side's event suppression settings.
116    pub notify: bool,
117}
118
119/// Memory operation that failed in the backend.
120#[derive(Debug, Copy, Clone, PartialEq, Eq)]
121pub enum MemOp {
122    /// Reading a descriptor from the descriptor table.
123    ReadDesc,
124    /// Writing a descriptor to the descriptor table.
125    WriteDesc,
126    /// Reading an event suppression structure.
127    ReadEvent,
128    /// Writing an event suppression structure.
129    WriteEvent,
130}
131
132impl fmt::Display for MemOp {
133    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
134        match self {
135            Self::ReadDesc => f.write_str("reading descriptor"),
136            Self::WriteDesc => f.write_str("writing descriptor"),
137            Self::ReadEvent => f.write_str("reading event suppression"),
138            Self::WriteEvent => f.write_str("writing event suppression"),
139        }
140    }
141}
142
143#[derive(Error, Debug)]
144pub enum RingError {
145    #[error("Buffer chain is empty")]
146    EmptyChain,
147    #[error("Buffer chain is malformed")]
148    BadChain,
149    #[error("Operation would block")]
150    WouldBlock,
151    #[error("Out of memory")]
152    OutOfMemory,
153    #[error("Invalid state")]
154    InvalidState,
155    #[error("Invalid memory layout")]
156    InvalidLayout,
157    #[error("Backend memory error while {op} at address 0x{addr:x}, len {len}")]
158    MemError {
159        /// Memory operation that failed.
160        op: MemOp,
161        /// Address passed to the memory backend.
162        addr: u64,
163        /// Number of bytes requested for the operation.
164        len: usize,
165    },
166}
167
168impl RingError {
169    #[inline]
170    fn mem_err(op: MemOp, addr: u64) -> Self {
171        let len = match op {
172            MemOp::ReadDesc | MemOp::WriteDesc => Descriptor::SIZE,
173            MemOp::ReadEvent | MemOp::WriteEvent => EventSuppression::SIZE,
174        };
175
176        Self::MemError { op, addr, len }
177    }
178}
179
180/// Type-state: Can add readable buffers
181pub struct Readable;
182
183/// Type-state: Can add writable buffers (no more readables allowed)
184pub struct Writable;
185
186/// A builder for buffer chains using type-state to enforce readable/writable order.
187///
188/// Upholds invariants: at least one buffer must be present in the chain,
189/// and readable buffers must be added before writable buffers.
190///
191/// The builder stores up to 16 buffer elements inline to avoid allocation for
192/// common small chains. Larger chains are still supported and spill to the heap.
193#[derive(Debug, Default)]
194pub struct BufferChainBuilder<T> {
195    elems: SmallVec<[BufferElement; 16]>,
196    split: usize,
197    marker: PhantomData<T>,
198}
199
200impl BufferChainBuilder<Readable> {
201    /// Create a new builder in the [`Readable`] state.
202    pub fn new() -> Self {
203        Self {
204            elems: Default::default(),
205            split: 0,
206            marker: PhantomData,
207        }
208    }
209
210    /// Add a readable buffer (device reads from this).
211    pub fn readable(mut self, addr: u64, len: u32) -> Self {
212        self.elems.push(BufferElement {
213            addr,
214            len,
215            writable: false,
216        });
217        self.split += 1;
218        self
219    }
220
221    /// Add multiple readable buffers from an iterator.
222    pub fn readables(
223        mut self,
224        elements: impl IntoIterator<Item = impl Into<BufferElement>>,
225    ) -> Self {
226        for elem in elements {
227            let mut elem = elem.into();
228            elem.writable = false;
229            self.elems.push(elem);
230            self.split += 1;
231        }
232
233        self
234    }
235
236    /// Add a writable buffer (device writes to this).
237    ///
238    /// This transitions to Writable state so no more readable buffers can be added.
239    pub fn writable(mut self, addr: u64, len: u32) -> BufferChainBuilder<Writable> {
240        self.elems.push(BufferElement {
241            addr,
242            len,
243            writable: true,
244        });
245
246        BufferChainBuilder {
247            elems: self.elems,
248            split: self.split,
249            marker: PhantomData,
250        }
251    }
252
253    /// Add multiple writable buffers from an iterator.
254    ///
255    /// This transitions to Writable state so no more readable buffers can be added.
256    pub fn writables(
257        mut self,
258        elements: impl IntoIterator<Item = impl Into<BufferElement>>,
259    ) -> BufferChainBuilder<Writable> {
260        for elem in elements {
261            let mut elem = elem.into();
262            elem.writable = true;
263            self.elems.push(elem);
264        }
265
266        BufferChainBuilder {
267            elems: self.elems,
268            split: self.split,
269            marker: PhantomData,
270        }
271    }
272
273    /// Build a buffer chain with only readable buffers.
274    ///
275    /// Chain must have at least one buffer otherwise an error is returned.
276    pub fn build(self) -> Result<BufferChain, RingError> {
277        if self.elems.is_empty() {
278            return Err(RingError::EmptyChain);
279        }
280
281        Ok(BufferChain {
282            elems: self.elems,
283            split: self.split,
284        })
285    }
286}
287
288impl BufferChainBuilder<Writable> {
289    /// Add writable buffer
290    pub fn writable(mut self, addr: u64, len: u32) -> Self {
291        self.elems.push(BufferElement {
292            addr,
293            len,
294            writable: true,
295        });
296        self
297    }
298
299    /// Add multiple writable buffers from an iterator.
300    pub fn writables(
301        mut self,
302        elements: impl IntoIterator<Item = impl Into<BufferElement>>,
303    ) -> Self {
304        for elem in elements {
305            let mut elem = elem.into();
306            elem.writable = true;
307            self.elems.push(elem);
308        }
309        self
310    }
311
312    /// Build the buffer chain.
313    ///
314    /// Chain must have at least one buffer otherwise an error is returned.
315    pub fn build(self) -> Result<BufferChain, RingError> {
316        if self.elems.is_empty() {
317            return Err(RingError::EmptyChain);
318        }
319
320        Ok(BufferChain {
321            elems: self.elems,
322            split: self.split,
323        })
324    }
325}
326
327/// A chain of buffers ready for submission to the virtqueue.
328///
329/// Contains a scatter-gather list of [`BufferElement`]s, divided into
330/// readable (driver->device) and writable (device->driver) sections.
331#[derive(Debug, Clone)]
332pub struct BufferChain {
333    /// All buffer elements (readable followed by writable)
334    elems: SmallVec<[BufferElement; 16]>,
335    /// Split index between readable and writable buffers
336    split: usize,
337}
338
339impl BufferChain {
340    /// Get all buffer elements in the chain.
341    pub fn elems(&self) -> &[BufferElement] {
342        self.elems.as_slice()
343    }
344
345    /// Get readable buffers in chain
346    pub fn readables(&self) -> &[BufferElement] {
347        &self.elems[..self.split]
348    }
349
350    /// Get mutable readable buffers in chain.
351    pub(crate) fn readables_mut(&mut self) -> &mut [BufferElement] {
352        &mut self.elems[..self.split]
353    }
354
355    /// Get writable buffers in chain
356    pub fn writables(&self) -> &[BufferElement] {
357        &self.elems[self.split..]
358    }
359
360    /// Get total number of buffers in chain
361    // Note: buffer chain cannot be empty by construction
362    #[allow(clippy::len_without_is_empty)]
363    pub fn len(&self) -> usize {
364        self.elems.len()
365    }
366}
367
368/// Tracks position in a ring buffer with wrap-around handling.
369///
370/// The cursor maintains both an index into the ring and a wrap counter
371/// that toggles each time the index wraps around.
372#[derive(Debug, Copy, Clone, PartialEq, Eq)]
373pub struct RingCursor {
374    head: u16,
375    size: u16,
376    wrap: bool,
377}
378
379impl RingCursor {
380    pub(crate) fn new(size: usize) -> Self {
381        Self {
382            head: 0,
383            size: size as u16,
384            wrap: true,
385        }
386    }
387
388    /// Advance to next position, wrapping around and toggling wrap counter if needed
389    #[inline]
390    fn advance(&mut self) {
391        debug_assert!(self.head.checked_add(1).is_some());
392        self.head += 1;
393        if self.head >= self.size {
394            self.head = 0;
395            self.wrap = !self.wrap;
396        }
397    }
398
399    /// Advance by n positions using modular arithmetic.
400    #[inline]
401    fn advance_by(&mut self, n: u16) {
402        debug_assert!(self.head.checked_add(n).is_some());
403        let new = self.head + n;
404        let wraps = new / self.size;
405        self.head = new % self.size;
406        if !wraps.is_multiple_of(2) {
407            self.wrap = !self.wrap;
408        }
409    }
410
411    /// Get current head index
412    #[inline]
413    pub fn head(&self) -> u16 {
414        self.head
415    }
416
417    /// Get current wrap counter
418    #[inline]
419    pub fn wrap(&self) -> bool {
420        self.wrap
421    }
422
423    /// Reset cursor to initial state.
424    #[inline]
425    pub fn reset(&mut self) {
426        self.head = 0;
427        self.wrap = true;
428    }
429}
430
431/// Producer (driver) side of a packed virtqueue.
432///
433/// The producer submits buffer chains for the device to process and polls
434/// for completions. This is typically used by the driver/guest side.
435///
436/// # Lifecycle
437///
438/// 1.Submit: Call [`submit_available`](Self::submit_available) or
439///    [`submit_one`](Self::submit_one) to make buffers available to device
440/// 2. Notify: If `SubmitResult::notify` is true, signal the device
441/// 3. Poll: Call [`poll_used`](Self::poll_used) to check for completions
442/// 4. Process: Handle completed buffers and reuse descriptor IDs
443#[derive(Debug)]
444pub struct RingProducer<M> {
445    /// Memory accessor
446    mem: M,
447    /// Next available descriptor position
448    avail_cursor: RingCursor,
449    /// Next used descriptor position
450    used_cursor: RingCursor,
451    /// Free slots in the ring
452    num_free: usize,
453    /// Descriptor table in shared memory
454    desc_table: DescTable,
455    /// Shadow of driver event flags (last written value)
456    event_flags_shadow: EventFlags,
457    // controls when device notifies about used buffers
458    drv_evt_addr: u64,
459    // reads device event to check if device wants notification
460    dev_evt_addr: u64,
461    /// stack of free IDs, allows out-of-order completion
462    id_free: SmallVec<[u16; DescTable::DEFAULT_LEN]>,
463    // chain length per ID, index = ID,
464    id_num: SmallVec<[u16; DescTable::DEFAULT_LEN]>,
465}
466
467impl<M: MemOps> RingProducer<M> {
468    /// Create a new producer from a memory layout and accessor.
469    pub fn new(layout: Layout, mem: M) -> Self {
470        let size = layout.desc_table_len() as usize;
471        let raw = layout.desc_table_addr();
472
473        // SAFETY: Layout fields are private and from_base validates ring geometry.
474        let table = unsafe { DescTable::from_raw_parts(raw, size) };
475        let cursor = RingCursor::new(size);
476
477        const DEFAULT_LEN: usize = DescTable::default_len();
478        let id_free = (0..size as u16).collect::<SmallVec<[_; DEFAULT_LEN]>>();
479        let id_num = SmallVec::<[_; DEFAULT_LEN]>::from_elem(0, size);
480
481        // Notification enabled by default
482        let event_flags_shadow = EventFlags::ENABLE;
483
484        Self {
485            mem,
486            avail_cursor: cursor,
487            used_cursor: cursor,
488            num_free: size,
489            desc_table: table,
490            id_free,
491            id_num,
492            event_flags_shadow,
493            drv_evt_addr: layout.drv_evt_addr(),
494            dev_evt_addr: layout.dev_evt_addr(),
495        }
496    }
497
498    /// Fast path: submit exactly one descriptor
499    ///
500    /// This is more efficient than [`submit_available`](Self::submit_available)
501    /// for single-buffer submissions as it avoids chain iteration overhead.
502    ///
503    /// # Arguments
504    ///
505    /// * `addr` - physical address of the buffer
506    /// * `len` - Length of the buffer in bytes
507    /// * `writable` - If true, device writes to buffer; if false, device reads
508    ///
509    /// # Returns
510    ///
511    /// The descriptor ID assigned to this buffer, for matching with completions.
512    ///
513    /// # Errors
514    ///
515    /// - [`RingError::WouldBlock`] - No free descriptor slots
516    /// - [`RingError::OutOfMemory`] - No free descriptor IDs (internal error)
517    /// - [`RingError::InvalidState`] - ID tracking corrupted (internal error)
518    /// - [`RingError::MemError`] - Backend memory error while publishing the descriptor
519    pub fn submit_one(&mut self, addr: u64, len: u32, writable: bool) -> Result<u16, RingError> {
520        if self.num_free < 1 {
521            return Err(RingError::WouldBlock);
522        }
523
524        // Allocate ID and record chain length
525        let id = self.id_free.pop().ok_or(RingError::OutOfMemory)?;
526
527        // We should never reuse an ID that is still outstanding
528        if self.id_num[id as usize] != 0 {
529            return Err(RingError::InvalidState);
530        }
531
532        // Record chain length for single descriptor
533        self.id_num[id as usize] = 1;
534
535        // Build and publish the head descriptor
536        let head_idx = self.avail_cursor.head();
537        let head_wrap = self.avail_cursor.wrap();
538
539        let mut flags = DescFlags::empty();
540        flags.set(DescFlags::WRITE, writable);
541        let mut desc = Descriptor::new(addr, len, id, flags);
542        desc.mark_avail(head_wrap);
543
544        let addr = self
545            .desc_table
546            .desc_addr(head_idx)
547            .ok_or(RingError::InvalidState)?;
548
549        // Release publish
550        desc.write_release(&self.mem, addr)
551            .map_err(|_| RingError::mem_err(MemOp::WriteDesc, addr))?;
552
553        // Advance state
554        self.avail_cursor.advance();
555        self.num_free -= 1;
556
557        Ok(id)
558    }
559
560    /// Submit a buffer chain to the ring, returning whether to notify the device.
561    pub fn submit_available_with_notify(
562        &mut self,
563        chain: &BufferChain,
564    ) -> Result<SubmitResult, RingError> {
565        let old = self.avail_cursor;
566        let id = self.submit_available(chain)?;
567        let new = self.avail_cursor;
568        let notify = self.should_notify_device(old, new)?;
569
570        Ok(SubmitResult { id, notify })
571    }
572
573    /// Submit a single-buffer descriptor with notification check.
574    pub fn submit_one_with_notify(
575        &mut self,
576        addr: u64,
577        len: u32,
578        writable: bool,
579    ) -> Result<SubmitResult, RingError> {
580        let old = self.avail_cursor;
581        let id = self.submit_one(addr, len, writable)?;
582        let new = self.avail_cursor;
583        let notify = self.should_notify_device(old, new)?;
584        Ok(SubmitResult { id, notify })
585    }
586
587    /// Submit a buffer chain to the ring.
588    ///
589    /// Writes all descriptors in the chain to the ring, linking them with
590    /// NEXT flags. The head descriptor is written last with release semantics
591    /// to ensure atomicity of the chain.
592    ///
593    /// # Arguments
594    ///
595    /// * `chain` - The buffer chain to submit
596    ///
597    /// # Returns
598    ///
599    /// The descriptor ID assigned to this chain. All descriptors in the chain
600    /// share this ID for correlation during completion.
601    ///
602    /// # Errors
603    ///
604    /// - [`RingError::EmptyChain`] - Chain has no buffers
605    /// - [`RingError::WouldBlock`] - Not enough free descriptor slots
606    /// - [`RingError::OutOfMemory`] - No free descriptor IDs (internal error)
607    /// - [`RingError::InvalidState`] - ID tracking or descriptor-table state is corrupted
608    /// - [`RingError::MemError`] - Backend memory error while publishing descriptors
609    pub fn submit_available(&mut self, chain: &BufferChain) -> Result<u16, RingError> {
610        let total_descs = chain.len();
611        if total_descs == 0 {
612            return Err(RingError::EmptyChain);
613        }
614
615        if self.num_free < total_descs {
616            return Err(RingError::WouldBlock);
617        }
618
619        if total_descs == 1 {
620            let elem = chain.elems()[0];
621            return self.submit_one(elem.addr, elem.len, elem.writable);
622        }
623
624        let head_idx = self.avail_cursor.head();
625        let head_wrap = self.avail_cursor.wrap();
626
627        let id = self.id_free.pop().ok_or(RingError::OutOfMemory)?;
628
629        // We should never reuse an ID that is still outstanding
630        if self.id_num[id as usize] != 0 {
631            return Err(RingError::InvalidState);
632        }
633
634        // Record chain length
635        self.id_num[id as usize] = total_descs as u16;
636
637        // Write tail elements first; head last.
638        let mut pos = self.avail_cursor;
639        pos.advance();
640
641        for (i, elem) in chain.elems().iter().enumerate().skip(1) {
642            let is_next = i + 1 < total_descs;
643            let mut flags = DescFlags::empty();
644
645            flags.set(DescFlags::NEXT, is_next);
646            flags.set(DescFlags::WRITE, elem.writable);
647
648            let mut desc = Descriptor::new(elem.addr, elem.len, id, flags);
649            desc.mark_avail(pos.wrap());
650
651            let addr = self
652                .desc_table
653                .desc_addr(pos.head())
654                .ok_or(RingError::InvalidState)?;
655
656            self.mem
657                .write_val(addr, desc)
658                .map_err(|_| RingError::mem_err(MemOp::WriteDesc, addr))?;
659            pos.advance();
660        }
661
662        // Head descriptor
663        let head_elem = chain.elems()[0];
664        // Record chain length
665        let mut head_flags = DescFlags::empty();
666        head_flags.set(DescFlags::NEXT, total_descs > 1);
667        head_flags.set(DescFlags::WRITE, head_elem.writable);
668
669        let mut head_desc = Descriptor::new(head_elem.addr, head_elem.len, id, head_flags);
670        head_desc.mark_avail(head_wrap);
671
672        let head_addr = self
673            .desc_table
674            .desc_addr(head_idx)
675            .ok_or(RingError::InvalidState)?;
676
677        // Release publish
678        head_desc
679            .write_release(&self.mem, head_addr)
680            .map_err(|_| RingError::mem_err(MemOp::WriteDesc, head_addr))?;
681
682        self.num_free -= total_descs;
683        self.avail_cursor = pos;
684
685        Ok(id)
686    }
687
688    /// Poll the ring for a used buffer.
689    ///
690    /// Checks if the device has marked any buffers as used. If so, returns
691    /// the completion information and reclaims the descriptor(s).
692    ///
693    /// # Returns
694    ///
695    /// - `Ok(UsedBuffer)` - A buffer chain was completed
696    /// - `Err(RingError::WouldBlock)` - No completions available
697    pub fn poll_used(&mut self) -> Result<UsedBuffer, RingError> {
698        let idx = self.used_cursor.head();
699        let wrap = self.used_cursor.wrap();
700
701        // Read the descriptor at next_used position with ordering
702        let addr = self
703            .desc_table
704            .desc_addr(idx)
705            .ok_or(RingError::InvalidState)?;
706
707        // Acquire flags then fields (publish point)
708        let flags = Descriptor::read_flags_acquire(&self.mem, addr)
709            .map_err(|_| RingError::mem_err(MemOp::ReadDesc, addr))?;
710
711        if !flags.is_used(wrap) {
712            return Err(RingError::WouldBlock);
713        }
714
715        let desc = Descriptor::read_body(&self.mem, addr, flags)
716            .map_err(|_| RingError::mem_err(MemOp::ReadDesc, addr))?;
717
718        let id = desc.id;
719        let count = *self
720            .id_num
721            .get(id as usize)
722            .ok_or(RingError::InvalidState)?;
723
724        if count == 0 {
725            return Err(RingError::InvalidState);
726        }
727
728        // Advance used cursor by number of reclaimed descriptors
729        self.used_cursor.advance_by(count);
730        // Update number of free descriptors
731        self.num_free += count as usize;
732        // SAFETY: id is valid because we checked above
733        self.id_num[id as usize] = 0;
734        // Return ID to free stack
735        self.id_free.push(id);
736
737        Ok(UsedBuffer { id, len: desc.len })
738    }
739
740    /// Get number of free descriptors in the ring.
741    #[inline]
742    pub fn num_free(&self) -> usize {
743        self.num_free
744    }
745
746    /// Get number of inflight (submitted but not yet used) descriptors.
747    #[inline]
748    pub fn num_inflight(&self) -> usize {
749        self.desc_table.len() - self.num_free
750    }
751
752    /// Check if the ring is full (no free descriptors).
753    #[inline]
754    pub fn is_full(&self) -> bool {
755        self.num_free == 0
756    }
757
758    /// Get descriptor table length
759    #[inline]
760    #[allow(clippy::len_without_is_empty)]
761    pub fn len(&self) -> usize {
762        self.desc_table.len()
763    }
764
765    /// Get memory accessor reference
766    #[inline]
767    pub fn mem(&self) -> &M {
768        &self.mem
769    }
770
771    /// Get descriptor table reference
772    #[inline]
773    pub fn desc_table(&self) -> &DescTable {
774        &self.desc_table
775    }
776
777    /// Get a snapshot of the current available cursor position.
778    ///
779    /// Used for batch operations to track the cursor before submitting
780    /// multiple chains, enabling proper event suppression checks.
781    #[inline]
782    pub fn avail_cursor(&self) -> RingCursor {
783        self.avail_cursor
784    }
785
786    /// Get a snapshot of the current used cursor position.
787    ///
788    /// Used for setting up DESC mode event suppression at specific positions.
789    #[inline]
790    pub fn used_cursor(&self) -> RingCursor {
791        self.used_cursor
792    }
793
794    /// Check if device should be notified given a cursor snapshot from before batch start.
795    ///
796    /// This is used for batching: record cursor before first submit, then after all
797    /// submits call this to determine if notification is needed based on event suppression.
798    ///
799    /// # Arguments
800    /// * `old` - Cursor position snapshot taken before batch started
801    pub fn should_notify_since(&self, old: RingCursor) -> Result<bool, RingError> {
802        self.should_notify_device(old, self.avail_cursor)
803    }
804
805    /// Driver disables used-buffer notifications from device to driver.
806    pub fn disable_used_notifications(&mut self) -> Result<(), RingError> {
807        // Avoid redundant MMIO writes if already disabled
808        if self.event_flags_shadow == EventFlags::DISABLE {
809            return Ok(());
810        }
811
812        let mut evt = self
813            .mem
814            .read_val::<EventSuppression>(self.drv_evt_addr)
815            .map_err(|_| RingError::mem_err(MemOp::ReadEvent, self.drv_evt_addr))?;
816
817        evt.set_flags(EventFlags::DISABLE);
818
819        evt.write_release(&self.mem, self.drv_evt_addr)
820            .map_err(|_| RingError::mem_err(MemOp::WriteEvent, self.drv_evt_addr))?;
821        self.event_flags_shadow = EventFlags::DISABLE;
822        Ok(())
823    }
824
825    /// Driver enables used-buffer notifications from device to driver.
826    pub fn enable_used_notifications(&mut self) -> Result<(), RingError> {
827        if self.event_flags_shadow == EventFlags::ENABLE {
828            return Ok(());
829        }
830
831        let mut evt = self
832            .mem
833            .read_val::<EventSuppression>(self.drv_evt_addr)
834            .map_err(|_| RingError::mem_err(MemOp::ReadEvent, self.drv_evt_addr))?;
835
836        evt.set_flags(EventFlags::ENABLE);
837        evt.write_release(&self.mem, self.drv_evt_addr)
838            .map_err(|_| RingError::mem_err(MemOp::WriteEvent, self.drv_evt_addr))?;
839
840        self.event_flags_shadow = EventFlags::ENABLE;
841        Ok(())
842    }
843
844    /// Driver enables descriptor-specific used notifications (EVENT_IDX / DESC mode).
845    ///
846    /// This tells the device: "Interrupt me when you reach used index (off, wrap)".
847    ///
848    /// This enables batching on the device side - it can complete multiple requests
849    /// before triggering an interrupt.
850    pub fn enable_used_notifications_desc(
851        &mut self,
852        off: u16,
853        wrap: bool,
854    ) -> Result<(), RingError> {
855        let mut evt = self
856            .mem
857            .read_val::<EventSuppression>(self.drv_evt_addr)
858            .map_err(|_| RingError::mem_err(MemOp::ReadEvent, self.drv_evt_addr))?;
859
860        evt.set_desc_event(off, wrap);
861        evt.set_flags(EventFlags::DESC);
862
863        // Now publish flags = DESC with Release semantics.
864        evt.write_release(&self.mem, self.drv_evt_addr)
865            .map_err(|_| RingError::mem_err(MemOp::WriteEvent, self.drv_evt_addr))?;
866        // cache shadow
867        self.event_flags_shadow = EventFlags::DESC;
868        Ok(())
869    }
870
871    /// Convenience: enable DESC mode for "next used cursor" like Linux enable_cb_prepare.
872    pub fn enable_used_notifications_for_next(&mut self) -> Result<(), RingError> {
873        let off = self.used_cursor.head();
874        let wrap = self.used_cursor.wrap();
875
876        self.enable_used_notifications_desc(off, wrap)
877    }
878
879    /// Check whether the device should be notified about new available descriptors.
880    fn should_notify_device(&self, old: RingCursor, new: RingCursor) -> Result<bool, RingError> {
881        // VIRTIO 1.1 "The driver MUST perform a suitable memory barrier before
882        // reading the Device Event Suppression structure".
883        //
884        // After publishing descriptors with store-release on the AVAIL/USED flags,
885        // we need a full barrier before reading event suppression, because
886        // release+acquire across different memory locations does NOT provide
887        // Store/Load ordering on weakly-ordered architectures e.g. aarch64.
888        //
889        // Linux kernel uses virtio_mb() full barrier in virtqueue_kick_prepare_packed.
890        fence(Ordering::SeqCst);
891
892        should_notify_evt(&self.mem, self.dev_evt_addr, self.len() as u16, old, new)
893    }
894
895    /// Reset to initial state matching a freshly zeroed ring.
896    pub fn reset(&mut self) {
897        let size = self.desc_table.len();
898        self.avail_cursor.reset();
899        self.used_cursor.reset();
900        self.num_free = size;
901        self.id_free.clear();
902        self.id_free.extend(0..size as u16);
903        self.id_num.iter_mut().for_each(|n| *n = 0);
904        self.event_flags_shadow = EventFlags::ENABLE;
905    }
906
907    /// Reset the ring to the "N slots submitted, none completed" state.
908    ///
909    /// `ids` contains the descriptor IDs that are in-flight.
910    /// Sets cursors, counters, and `id_num` accordingly. The chain lengths are all set to 1.
911    pub fn reset_prefilled(&mut self, ids: &[u16]) {
912        let size = self.desc_table.len();
913        let count = ids.len();
914        assert!(count <= size);
915
916        let wrapped = count >= size;
917        self.avail_cursor.head = if wrapped { 0 } else { count as u16 };
918        self.avail_cursor.wrap = !wrapped;
919
920        self.used_cursor.head = 0;
921        self.used_cursor.wrap = true;
922
923        self.id_num.iter_mut().for_each(|n| *n = 0);
924        for &id in ids {
925            assert!((id as usize) < size);
926            assert_eq!(self.id_num[id as usize], 0);
927            self.id_num[id as usize] = 1;
928        }
929
930        self.num_free = size - count;
931        self.id_free.clear();
932        self.id_free
933            .extend((0..size as u16).filter(|id| self.id_num[*id as usize] == 0));
934    }
935}
936
937/// Consumer (device) side of a packed virtqueue.
938///
939/// The consumer polls for available buffer chains submitted by the driver,
940/// processes them, and marks them as used. This is typically used by the
941/// device/host side.
942///
943/// # Lifecycle
944///
945/// 1. **Poll**: Call [`poll_available`](Self::poll_available) to get buffers
946/// 2. **Process**: Read from readable buffers, write to writable buffers
947/// 3. **Complete**: Call [`submit_used`](Self::submit_used) to return buffers
948/// 4. **Notify**: If `submit_used_with_notify` returns true, signal the driver
949#[derive(Debug)]
950pub struct RingConsumer<M> {
951    /// Memory accessor
952    mem: M,
953    /// Cursor for reading available (driver-published) descriptors
954    avail_cursor: RingCursor,
955    /// Cursor for writing used descriptors
956    used_cursor: RingCursor,
957    /// Shared descriptor table
958    desc_table: DescTable,
959    /// Per-ID chain length learned when polling (index = ID)
960    id_num: SmallVec<[u16; DescTable::DEFAULT_LEN]>,
961    /// Number of descriptors consumed from avail stream but not yet posted as used.
962    num_inflight: usize,
963    /// Shadow of device event flags (last written value)
964    event_flags_shadow: EventFlags,
965    // reads driver event to control when device should notify
966    drv_evt_addr: u64,
967    // write device_event (checks if device wants notification about available buffers)
968    dev_evt_addr: u64,
969}
970
971impl<M: MemOps> RingConsumer<M> {
972    pub fn new(layout: Layout, mem: M) -> Self {
973        let size = layout.desc_table_len() as usize;
974        let raw = layout.desc_table_addr();
975
976        // SAFETY: Layout fields are private and from_base validates ring geometry.
977        let table = unsafe { DescTable::from_raw_parts(raw, size) };
978        let cursor = RingCursor::new(size);
979        let id_chain_len = SmallVec::<[u16; DescTable::DEFAULT_LEN]>::from_elem(0, size);
980
981        // Notification enabled by default
982        let event_flags_shadow = EventFlags::ENABLE;
983
984        Self {
985            mem,
986            avail_cursor: cursor,
987            used_cursor: cursor,
988            desc_table: table,
989            id_num: id_chain_len,
990            num_inflight: 0,
991            event_flags_shadow,
992            drv_evt_addr: layout.drv_evt_addr(),
993            dev_evt_addr: layout.dev_evt_addr(),
994        }
995    }
996
997    /// Poll for an available buffer chain.
998    ///
999    /// Returns the chain ID and a [`BufferChain`] containing all buffers.
1000    /// The chain ID must be passed to [`submit_used`](Self::submit_used)
1001    /// when processing is complete.
1002    ///
1003    /// # Returns
1004    ///
1005    /// - `Ok((id, chain))` - A buffer chain is available
1006    /// - `Err(RingError::WouldBlock)` - No buffers available
1007    /// - `Err(RingError::BadChain)` - Malformed chain (driver bug)
1008    pub fn poll_available(&mut self) -> Result<(u16, BufferChain), RingError> {
1009        let idx = self.avail_cursor.head();
1010        let wrap = self.avail_cursor.wrap();
1011
1012        let head_addr = self
1013            .desc_table
1014            .desc_addr(idx)
1015            .ok_or(RingError::InvalidState)?;
1016
1017        // Acquire: flags then fields (publish point)
1018        let flags = Descriptor::read_flags_acquire(&self.mem, head_addr)
1019            .map_err(|_| RingError::mem_err(MemOp::ReadDesc, head_addr))?;
1020
1021        // Check if head descriptor is available to consume
1022        if !flags.is_avail(wrap) {
1023            return Err(RingError::WouldBlock);
1024        }
1025
1026        let head_desc = Descriptor::read_body(&self.mem, head_addr, flags)
1027            .map_err(|_| RingError::mem_err(MemOp::ReadDesc, head_addr))?;
1028
1029        if flags.contains(DescFlags::INDIRECT) {
1030            return Err(RingError::BadChain);
1031        }
1032
1033        // Build chain (head + tails), tracking readable/writable split inline.
1034        let mut elements = SmallVec::<[BufferElement; 16]>::new();
1035        let mut pos = self.avail_cursor;
1036        let mut chain_len: u16 = 1;
1037
1038        let mut steps = 1;
1039        let mut has_next = head_desc.is_next();
1040
1041        let max_steps = self.desc_table.len();
1042
1043        let head_elem = BufferElement::from(&head_desc);
1044        let mut seen_writable = head_elem.writable;
1045        let mut writables: usize = if seen_writable { 1 } else { 0 };
1046        elements.push(head_elem);
1047        pos.advance();
1048
1049        while has_next && steps < max_steps {
1050            let addr = self
1051                .desc_table
1052                .desc_addr(pos.head())
1053                .ok_or(RingError::InvalidState)?;
1054
1055            // tail reads does not need ordering because head has been already validated
1056            let desc: Descriptor = self
1057                .mem
1058                .read_val(addr)
1059                .map_err(|_| RingError::mem_err(MemOp::ReadDesc, addr))?;
1060            if desc.flags().contains(DescFlags::INDIRECT) {
1061                return Err(RingError::BadChain);
1062            }
1063
1064            let elem = BufferElement::from(&desc);
1065
1066            if elem.writable {
1067                seen_writable = true;
1068                writables += 1;
1069            } else if seen_writable {
1070                return Err(RingError::BadChain);
1071            }
1072
1073            elements.push(elem);
1074
1075            chain_len += 1;
1076            steps += 1;
1077
1078            has_next = desc.is_next();
1079            pos.advance();
1080        }
1081
1082        // Detect malformed chains, this means we reached max_steps but still have NEXT set.
1083        if steps >= max_steps && has_next {
1084            return Err(RingError::BadChain);
1085        }
1086
1087        // Check if next inflight will exceed ring capacity - this should never happen if driver is
1088        // well-behaved and we correctly track inflight count.
1089        if self.num_inflight + chain_len as usize > self.desc_table.len() {
1090            return Err(RingError::InvalidState);
1091        }
1092
1093        let readables = elements.len() - writables;
1094
1095        // Since driver wrote the same id everywhere, head_desc.id is valid.
1096        let id = head_desc.id;
1097        let id_num = self
1098            .id_num
1099            .get_mut(id as usize)
1100            .ok_or(RingError::InvalidState)?;
1101        if *id_num != 0 {
1102            return Err(RingError::InvalidState);
1103        }
1104
1105        // Record chain length for later used submission
1106        *id_num = chain_len;
1107        // Advance avail cursor to first slot after chain
1108        self.avail_cursor = pos;
1109        // Update inflight count
1110        self.num_inflight += chain_len as usize;
1111
1112        Ok((
1113            id,
1114            BufferChain {
1115                elems: elements,
1116                split: readables,
1117            },
1118        ))
1119    }
1120
1121    /// Publish a single used descriptor for the chain identified by id.
1122    /// written_len is the total bytes produced by the device (for writable part).
1123    ///
1124    /// # Arguments
1125    ///
1126    /// * `id` - The chain ID from `poll_available`
1127    /// * `written_len` - Total bytes written to writable buffers
1128    ///
1129    /// # Errors
1130    ///
1131    /// - [`RingError::InvalidState`] - Unknown ID or already completed
1132    pub fn submit_used(&mut self, id: u16, written_len: u32) -> Result<(), RingError> {
1133        // Lookup chain length
1134        let chain_len = *self
1135            .id_num
1136            .get(id as usize)
1137            .ok_or(RingError::InvalidState)?;
1138
1139        if chain_len == 0 || chain_len > self.desc_table.len() as u16 {
1140            return Err(RingError::InvalidState);
1141        }
1142
1143        let idx = self.used_cursor.head();
1144        let wrap = self.used_cursor.wrap();
1145
1146        // addr is unused for used descriptor according to packed-virtqueue spec
1147        let mut used_desc = Descriptor::new(0, written_len, id, DescFlags::empty());
1148        used_desc.mark_used(wrap);
1149
1150        let addr = self
1151            .desc_table
1152            .desc_addr(idx)
1153            .ok_or(RingError::InvalidState)?;
1154
1155        // Release publish (flags written last inside write_release)
1156        used_desc
1157            .write_release(&self.mem, addr)
1158            .map_err(|_| RingError::mem_err(MemOp::WriteDesc, addr))?;
1159
1160        // Advance used cursor by whole chain length
1161        self.used_cursor.advance_by(chain_len);
1162        self.id_num[id as usize] = 0;
1163
1164        self.num_inflight -= chain_len as usize;
1165        Ok(())
1166    }
1167
1168    /// Try to peek whether the next chain is available without consuming it.
1169    pub fn peek_available(&self) -> Result<bool, RingError> {
1170        let Some(addr) = self.desc_table.desc_addr(self.avail_cursor.head()) else {
1171            return Err(RingError::InvalidState);
1172        };
1173
1174        let flags = Descriptor::read_flags_acquire(&self.mem, addr)
1175            .map_err(|_| RingError::mem_err(MemOp::ReadDesc, addr))?;
1176
1177        Ok(flags.is_avail(self.avail_cursor.wrap()))
1178    }
1179
1180    /// Submit a used descriptor and return whether to notify the driver.
1181    pub fn submit_used_with_notify(
1182        &mut self,
1183        id: u16,
1184        written_len: u32,
1185    ) -> Result<bool, RingError> {
1186        let old = self.used_cursor;
1187        self.submit_used(id, written_len)?;
1188        let new = self.used_cursor;
1189        self.should_notify_driver(old, new)
1190    }
1191
1192    /// Get number of free descriptors in the ring.
1193    pub fn num_free(&self) -> usize {
1194        self.desc_table.len() - self.num_inflight
1195    }
1196
1197    /// Get number of inflight (submitted but not yet used) descriptors.
1198    pub fn num_inflight(&self) -> usize {
1199        self.num_inflight
1200    }
1201
1202    /// Check if the ring is full (no free descriptors).
1203    pub fn is_full(&self) -> bool {
1204        self.num_inflight == self.desc_table.len()
1205    }
1206
1207    /// Get descriptor table length
1208    #[allow(clippy::len_without_is_empty)]
1209    pub fn len(&self) -> usize {
1210        self.desc_table.len()
1211    }
1212
1213    /// Get memory accessor reference
1214    pub fn mem(&self) -> &M {
1215        &self.mem
1216    }
1217
1218    /// Get a snapshot of the current avail cursor position.
1219    #[inline]
1220    pub fn avail_cursor(&self) -> RingCursor {
1221        self.avail_cursor
1222    }
1223
1224    /// Get a snapshot of the current used cursor position.
1225    #[inline]
1226    pub fn used_cursor(&self) -> RingCursor {
1227        self.used_cursor
1228    }
1229
1230    /// Device disables available-buffer notifications from driver to device.
1231    ///
1232    /// This is the device-side mirror of "disable callbacks" but for avail kicks.
1233    pub fn disable_avail_notifications(&mut self) -> Result<(), RingError> {
1234        if self.event_flags_shadow == EventFlags::DISABLE {
1235            return Ok(());
1236        }
1237
1238        let mut evt = self
1239            .mem
1240            .read_val::<EventSuppression>(self.dev_evt_addr)
1241            .map_err(|_| RingError::mem_err(MemOp::ReadEvent, self.dev_evt_addr))?;
1242
1243        evt.set_flags(EventFlags::DISABLE);
1244        evt.write_release(&self.mem, self.dev_evt_addr)
1245            .map_err(|_| RingError::mem_err(MemOp::WriteEvent, self.dev_evt_addr))?;
1246
1247        self.event_flags_shadow = EventFlags::DISABLE;
1248        Ok(())
1249    }
1250
1251    /// Device enables available-buffer notifications from driver to device.
1252    pub fn enable_avail_notifications(&mut self) -> Result<(), RingError> {
1253        if self.event_flags_shadow == EventFlags::ENABLE {
1254            return Ok(());
1255        }
1256
1257        let mut evt = self
1258            .mem
1259            .read_val::<EventSuppression>(self.dev_evt_addr)
1260            .map_err(|_| RingError::mem_err(MemOp::ReadEvent, self.dev_evt_addr))?;
1261
1262        evt.set_flags(EventFlags::ENABLE);
1263        evt.write_release(&self.mem, self.dev_evt_addr)
1264            .map_err(|_| RingError::mem_err(MemOp::WriteEvent, self.dev_evt_addr))?;
1265
1266        self.event_flags_shadow = EventFlags::ENABLE;
1267        Ok(())
1268    }
1269
1270    /// Device enables descriptor-specific available notifications (EVENT_IDX / DESC mode).
1271    ///
1272    /// This tells the driver: "Kick me when you reach avail index (off, wrap)".
1273    pub fn enable_avail_notifications_desc(
1274        &mut self,
1275        off: u16,
1276        wrap: bool,
1277    ) -> Result<(), RingError> {
1278        // Update off_wrap first
1279        let mut evt = self
1280            .mem
1281            .read_val::<EventSuppression>(self.dev_evt_addr)
1282            .map_err(|_| RingError::mem_err(MemOp::ReadEvent, self.dev_evt_addr))?;
1283
1284        evt.set_desc_event(off, wrap);
1285        evt.set_flags(EventFlags::DESC);
1286
1287        // Now publish flags = DESC with Release semantics.
1288        evt.write_release(&self.mem, self.dev_evt_addr)
1289            .map_err(|_| RingError::mem_err(MemOp::WriteEvent, self.dev_evt_addr))?;
1290
1291        self.event_flags_shadow = EventFlags::DESC;
1292        Ok(())
1293    }
1294
1295    /// Convenience: enable DESC mode for "next avail cursor" (device wants a kick when new
1296    /// buffers arrive at the next index it will poll).
1297    pub fn enable_avail_notifications_for_next(&mut self) -> Result<(), RingError> {
1298        let off = self.avail_cursor.head();
1299        let wrap = self.avail_cursor.wrap();
1300        self.enable_avail_notifications_desc(off, wrap)
1301    }
1302
1303    /// Decide whether the device should notify the driver about newly used descriptors.
1304    fn should_notify_driver(&self, old: RingCursor, new: RingCursor) -> Result<bool, RingError> {
1305        // VIRTIO 1.1: Full memory barrier required before reading the
1306        // Driver Event Suppression structure. See also should_notify_device()
1307        fence(Ordering::SeqCst);
1308
1309        should_notify_evt(&self.mem, self.drv_evt_addr, self.len() as u16, old, new)
1310    }
1311
1312    /// Reset to initial state matching a freshly zeroed ring.
1313    /// Does not reallocate internal buffers.
1314    pub fn reset(&mut self) {
1315        self.avail_cursor.reset();
1316        self.used_cursor.reset();
1317        self.id_num.iter_mut().for_each(|n| *n = 0);
1318        self.num_inflight = 0;
1319        self.event_flags_shadow = EventFlags::ENABLE;
1320    }
1321}
1322
1323/// Read an event-suppression structure and decide whether to notify the peer.
1324fn should_notify_evt<M: MemOps>(
1325    mem: &M,
1326    evt_addr: u64,
1327    ring_len: u16,
1328    old: RingCursor,
1329    new: RingCursor,
1330) -> Result<bool, RingError> {
1331    let flags = EventSuppression::read_flags_acquire(mem, evt_addr)
1332        .map_err(|_| RingError::mem_err(MemOp::ReadEvent, evt_addr))?;
1333
1334    let evt = if flags == EventFlags::DESC {
1335        EventSuppression::read_body(mem, evt_addr, flags)
1336            .map_err(|_| RingError::mem_err(MemOp::ReadEvent, evt_addr))?
1337    } else {
1338        EventSuppression::new(0, flags)
1339    };
1340
1341    Ok(should_notify(evt, ring_len, old, new))
1342}
1343
1344/// Common packed-ring notification decision:
1345/// - `old` and `new` are the ring indices (head) before/after publishing a batch
1346/// - `new.wrap()` is the wrap counter corresponding to `new.head()`
1347/// - `evt.desc_event_wrap()` is compared against `new.wrap()`
1348///
1349/// This is compatible with Linux `virtqueue_kick_prepare_packed` logic
1350#[inline]
1351fn should_notify(evt: EventSuppression, ring_len: u16, old: RingCursor, new: RingCursor) -> bool {
1352    match evt.flags() {
1353        EventFlags::DISABLE => false,
1354        EventFlags::ENABLE => true,
1355        EventFlags::DESC => {
1356            let mut off = evt.desc_event_off();
1357            if off >= ring_len {
1358                return false;
1359            }
1360
1361            let wrap = evt.desc_event_wrap();
1362
1363            if wrap != new.wrap() {
1364                off = off.wrapping_sub(ring_len);
1365            }
1366
1367            ring_need_event(off, new.head(), old.head())
1368        }
1369        // treat as disabled if invalid
1370        _ => false,
1371    }
1372}
1373
1374#[inline(always)]
1375fn ring_need_event(event_idx: u16, new: u16, old: u16) -> bool {
1376    new.wrapping_sub(event_idx).wrapping_sub(1) < new.wrapping_sub(old)
1377}
1378
1379impl From<&Descriptor> for BufferElement {
1380    fn from(desc: &Descriptor) -> Self {
1381        BufferElement {
1382            addr: desc.addr,
1383            len: desc.len,
1384            writable: desc.is_writable(),
1385        }
1386    }
1387}
1388
1389#[cfg(test)]
1390pub(crate) mod tests {
1391    use alloc::sync::Arc;
1392    use core::cell::UnsafeCell;
1393    use core::num::NonZeroU16;
1394    use core::ptr;
1395    use core::sync::atomic::{AtomicU16, Ordering};
1396
1397    use bytemuck::{Pod, Zeroable};
1398
1399    use super::super::align_up;
1400    use super::*;
1401    use crate::virtq::event::EventSuppression;
1402
1403    /// Test MemOps implementation that maintains pointer provenance.
1404    ///
1405    /// Wraps shared storage behind Arc for cheap cloning. This allows
1406    /// producer and consumer to share the same backing memory without
1407    /// Arc appearing in the type signatures.
1408    #[derive(Clone)]
1409    pub struct TestMem {
1410        inner: Arc<TestMemInner>,
1411    }
1412
1413    struct TestMemInner {
1414        /// The backing storage - UnsafeCell for interior mutability
1415        storage: UnsafeCell<Vec<u8>>,
1416        /// Base address (the address we tell the ring about)
1417        base_addr: u64,
1418    }
1419
1420    // Safety: TestMemInner's UnsafeCell is only accessed from test code
1421    // with no real concurrency in unit tests (loom tests use LoomMem).
1422    unsafe impl Send for TestMemInner {}
1423    unsafe impl Sync for TestMemInner {}
1424
1425    impl TestMem {
1426        pub fn new(size: usize) -> Self {
1427            let storage = vec![0u8; size];
1428            let base_addr = storage.as_ptr() as u64;
1429            Self {
1430                inner: Arc::new(TestMemInner {
1431                    storage: UnsafeCell::new(storage),
1432                    base_addr,
1433                }),
1434            }
1435        }
1436
1437        /// Get a pointer with proper provenance for the given address
1438        fn ptr_for_addr(&self, addr: u64) -> *mut u8 {
1439            let storage = unsafe { &mut *self.inner.storage.get() };
1440            let base_ptr = storage.as_mut_ptr();
1441            let offset = (addr - self.inner.base_addr) as usize;
1442            // Use wrapping_add to maintain provenance from base_ptr
1443            base_ptr.wrapping_add(offset)
1444        }
1445
1446        pub fn base_addr(&self) -> u64 {
1447            self.inner.base_addr
1448        }
1449    }
1450
1451    // SAFETY: TestMem translates addresses into its owned backing storage. Unit
1452    // tests construct layouts within that storage and avoid concurrent access.
1453    unsafe impl MemOps for TestMem {
1454        type Error = core::convert::Infallible;
1455
1456        fn read(&self, addr: u64, dst: &mut [u8]) -> Result<(), Self::Error> {
1457            let src = self.ptr_for_addr(addr);
1458            unsafe {
1459                ptr::copy_nonoverlapping(src, dst.as_mut_ptr(), dst.len());
1460            }
1461            Ok(())
1462        }
1463
1464        fn write(&self, addr: u64, src: &[u8]) -> Result<(), Self::Error> {
1465            let dst = self.ptr_for_addr(addr);
1466            unsafe {
1467                ptr::copy_nonoverlapping(src.as_ptr(), dst, src.len());
1468            }
1469            Ok(())
1470        }
1471
1472        fn read_val<T: Pod>(&self, addr: u64) -> Result<T, Self::Error> {
1473            let ptr = self.ptr_for_addr(addr).cast::<T>();
1474            Ok(unsafe { ptr::read_volatile(ptr) })
1475        }
1476
1477        fn write_val<T: Pod>(&self, addr: u64, val: T) -> Result<(), Self::Error> {
1478            let ptr = self.ptr_for_addr(addr).cast::<T>();
1479            unsafe { ptr::write_volatile(ptr, val) };
1480            Ok(())
1481        }
1482
1483        fn load_acquire(&self, addr: u64) -> Result<u16, Self::Error> {
1484            let ptr = self.ptr_for_addr(addr).cast::<AtomicU16>();
1485            Ok(unsafe { (*ptr).load(Ordering::Acquire) })
1486        }
1487
1488        fn store_release(&self, addr: u64, val: u16) -> Result<(), Self::Error> {
1489            let ptr = self.ptr_for_addr(addr).cast::<AtomicU16>();
1490            unsafe { (*ptr).store(val, Ordering::Release) };
1491            Ok(())
1492        }
1493
1494        unsafe fn as_slice(&self, addr: u64, len: usize) -> Result<&[u8], Self::Error> {
1495            let ptr = self.ptr_for_addr(addr);
1496            Ok(unsafe { core::slice::from_raw_parts(ptr, len) })
1497        }
1498
1499        unsafe fn as_mut_slice(&self, addr: u64, len: usize) -> Result<&mut [u8], Self::Error> {
1500            let ptr = self.ptr_for_addr(addr);
1501            Ok(unsafe { core::slice::from_raw_parts_mut(ptr, len) })
1502        }
1503    }
1504
1505    /// Owns the descriptor table and event suppression structures
1506    pub struct OwnedRing {
1507        mem: TestMem,
1508        layout: Layout,
1509    }
1510
1511    impl OwnedRing {
1512        pub fn new(size: usize) -> Self {
1513            let num_descs = NonZeroU16::new(size as u16).unwrap();
1514            let needed = Layout::query_size(size);
1515
1516            // Add padding for alignment, plus extra space for pool buffers
1517            // used by high-level API tests (pool offset = ring_end + 0x100,
1518            // pool size = 0x8000).
1519            let padding = Descriptor::ALIGN;
1520            let pool_headroom = 0x100 + 0x8000;
1521            let mem = TestMem::new(needed + padding + pool_headroom);
1522
1523            // Align the base address
1524            let aligned_base = align_up(mem.base_addr() as usize, Descriptor::ALIGN) as u64;
1525            let layout = unsafe { Layout::from_base(aligned_base, num_descs).unwrap() };
1526
1527            Self { mem, layout }
1528        }
1529
1530        pub fn layout(&self) -> Layout {
1531            self.layout
1532        }
1533
1534        pub fn mem(&self) -> TestMem {
1535            self.mem.clone()
1536        }
1537
1538        /// Get address of descriptor at index
1539        pub fn desc_addr(&self, idx: u16) -> u64 {
1540            self.layout.desc_table_addr() + (idx as u64 * Descriptor::SIZE as u64)
1541        }
1542
1543        /// Read descriptor directly (for test verification)
1544        pub fn read_desc(&self, idx: u16) -> Descriptor {
1545            self.mem.read_val(self.desc_addr(idx)).unwrap()
1546        }
1547
1548        /// Write descriptor directly (for test manipulation)
1549        pub fn write_desc(&self, idx: u16, desc: Descriptor) {
1550            self.mem.write_val(self.desc_addr(idx), desc).unwrap()
1551        }
1552
1553        /// Read driver event directly
1554        pub fn read_driver_event(&self) -> EventSuppression {
1555            self.mem.read_val(self.layout.drv_evt_addr()).unwrap()
1556        }
1557
1558        /// Read device event directly
1559        pub fn read_device_event(&self) -> EventSuppression {
1560            self.mem.read_val(self.layout.dev_evt_addr()).unwrap()
1561        }
1562
1563        pub fn len(&self) -> usize {
1564            self.layout.desc_table_len() as usize
1565        }
1566    }
1567
1568    // Share the TestMem between producer and consumer via reference
1569    pub(crate) fn make_ring(size: usize) -> OwnedRing {
1570        OwnedRing::new(size)
1571    }
1572
1573    pub(crate) fn make_producer(ring: &OwnedRing) -> RingProducer<TestMem> {
1574        RingProducer::new(ring.layout(), ring.mem())
1575    }
1576
1577    pub(crate) fn make_consumer(ring: &OwnedRing) -> RingConsumer<TestMem> {
1578        RingConsumer::new(ring.layout(), ring.mem())
1579    }
1580
1581    fn assert_invariants(ring: &OwnedRing, prod: &RingProducer<TestMem>) {
1582        let outstanding: u16 = prod.id_num.iter().copied().sum();
1583        assert_eq!(outstanding as usize + prod.num_free, ring.len());
1584
1585        for id in prod.id_free.iter() {
1586            assert_eq!(prod.id_num[*id as usize], 0);
1587        }
1588
1589        for (id, &n) in prod.id_num.iter().enumerate() {
1590            if n > 0 {
1591                assert!(!prod.id_free.contains(&(id as u16)));
1592            }
1593        }
1594    }
1595
1596    #[test]
1597    fn test_initialization() {
1598        let ring = make_ring(8);
1599        let producer = make_producer(&ring);
1600
1601        // All descriptors should be zeroed
1602        for i in 0..8u16 {
1603            let desc = ring.read_desc(i);
1604            assert_eq!(desc, Descriptor::zeroed());
1605            assert_eq!(desc.flags, 0);
1606            assert_eq!(desc.addr, 0);
1607            assert_eq!(desc.len, 0);
1608            assert_eq!(desc.id, 0);
1609        }
1610
1611        // Cursors start at head=0, wrap=true
1612        assert_eq!(producer.avail_cursor.head(), 0);
1613        assert!(producer.avail_cursor.wrap());
1614        assert_eq!(producer.used_cursor.head(), 0);
1615        assert!(producer.used_cursor.wrap());
1616
1617        // All IDs free, id_num zeroed, num_free == size
1618        assert_eq!(producer.id_free.len(), 8);
1619        assert_eq!(producer.num_free, 8);
1620        for i in 0..8 {
1621            assert_eq!(producer.id_num[i], 0);
1622        }
1623    }
1624
1625    #[test]
1626    fn test_buffer_chain_builder_normalizes_element_direction() {
1627        let readable_as_writable = BufferElement {
1628            addr: 0x1000,
1629            len: 16,
1630            writable: true,
1631        };
1632        let writable_as_readable = BufferElement {
1633            addr: 0x2000,
1634            len: 32,
1635            writable: false,
1636        };
1637        let second_writable_as_readable = BufferElement {
1638            addr: 0x3000,
1639            len: 64,
1640            writable: false,
1641        };
1642
1643        let chain = BufferChainBuilder::new()
1644            .readables([readable_as_writable])
1645            .writables([writable_as_readable])
1646            .writables([second_writable_as_readable])
1647            .build()
1648            .unwrap();
1649
1650        assert!(!chain.readables()[0].writable);
1651        assert!(chain.writables().iter().all(|elem| elem.writable));
1652    }
1653
1654    #[test]
1655    fn test_submit_one_descriptor() {
1656        let ring = make_ring(8);
1657        let mut producer = make_producer(&ring);
1658
1659        let addr = 0x1000;
1660        let len = 512;
1661        let writable = false;
1662
1663        let id = producer.submit_one(addr, len, writable).unwrap();
1664
1665        // Check descriptor was written correctly
1666        let desc = ring.read_desc(0);
1667
1668        assert_eq!(desc.addr, addr);
1669        assert_eq!(desc.len, len);
1670        assert_eq!(desc.id, id);
1671
1672        // AVAIL should match wrap (true), USED should be inverse (false)
1673        let flags = desc.flags();
1674        assert!(flags.contains(DescFlags::AVAIL));
1675        assert!(!flags.contains(DescFlags::USED));
1676        assert!(!flags.contains(DescFlags::WRITE));
1677        assert!(!flags.contains(DescFlags::NEXT));
1678
1679        // num_free should be decremented
1680        assert_eq!(producer.num_free, 7);
1681
1682        // Cursor advanced
1683        assert_eq!(producer.avail_cursor.head(), 1);
1684        assert!(producer.avail_cursor.wrap());
1685
1686        // ID allocated and chain length recorded
1687        assert_eq!(producer.id_num[id as usize], 1);
1688        assert_eq!(producer.id_free.len(), 7);
1689    }
1690
1691    #[test]
1692    fn test_single_descriptor_wrap_toggle() {
1693        let ring = make_ring(4);
1694        let mut producer = make_producer(&ring);
1695
1696        // Advance to last slot
1697        producer.avail_cursor.head = 3;
1698        producer.avail_cursor.wrap = true;
1699        producer.num_free = 1;
1700        producer.id_free.clear();
1701        producer.id_free.push(0);
1702
1703        let _id = producer.submit_one(0x1000, 512, false).unwrap();
1704
1705        // After submission, cursor should wrap
1706        assert_eq!(producer.avail_cursor.head(), 0);
1707        assert!(!producer.avail_cursor.wrap());
1708
1709        // Descriptor should have old wrap bits
1710        let desc = ring.read_desc(3);
1711        let flags = desc.flags();
1712        assert!(flags.contains(DescFlags::AVAIL));
1713        assert!(!flags.contains(DescFlags::USED));
1714    }
1715
1716    #[test]
1717    fn test_multi_descriptor_no_wrap() {
1718        let ring = make_ring(8);
1719        let mut producer = make_producer(&ring);
1720
1721        let chain = BufferChainBuilder::new()
1722            .readable(0x1000, 256)
1723            .readable(0x2000, 256)
1724            .writable(0x3000, 512)
1725            .build()
1726            .unwrap();
1727
1728        let id = producer.submit_available(&chain).unwrap();
1729
1730        // Check head descriptor
1731        let head_desc = ring.read_desc(0);
1732        assert_eq!(head_desc.addr, 0x1000);
1733        assert_eq!(head_desc.len, 256);
1734        assert_eq!(head_desc.id, id);
1735
1736        let head_flags = head_desc.flags();
1737        assert!(head_flags.contains(DescFlags::NEXT));
1738        assert!(!head_flags.contains(DescFlags::WRITE));
1739        assert!(head_flags.contains(DescFlags::AVAIL));
1740        assert!(!head_flags.contains(DescFlags::USED));
1741
1742        // Check middle descriptor
1743        let mid_desc = ring.read_desc(1);
1744        assert_eq!(mid_desc.addr, 0x2000);
1745        assert_eq!(mid_desc.len, 256);
1746        assert_eq!(mid_desc.id, id);
1747
1748        let mid_flags = mid_desc.flags();
1749        assert!(mid_flags.contains(DescFlags::NEXT));
1750        assert!(!mid_flags.contains(DescFlags::WRITE));
1751
1752        // Check tail descriptor
1753        let tail_desc = ring.read_desc(2);
1754        assert_eq!(tail_desc.addr, 0x3000);
1755        assert_eq!(tail_desc.len, 512);
1756        assert_eq!(tail_desc.id, id);
1757
1758        let tail_flags = tail_desc.flags();
1759        assert!(!tail_flags.contains(DescFlags::NEXT));
1760        assert!(tail_flags.contains(DescFlags::WRITE));
1761
1762        // All descriptors have same ID
1763        assert_eq!(head_desc.id, mid_desc.id);
1764        assert_eq!(mid_desc.id, tail_desc.id);
1765
1766        // Check state updates
1767        assert_eq!(producer.num_free, 5);
1768        assert_eq!(producer.avail_cursor.head(), 3);
1769        assert_eq!(producer.id_num[id as usize], 3);
1770    }
1771
1772    #[test]
1773    fn test_multi_descriptor_with_wrap() {
1774        let ring = make_ring(4);
1775        let mut producer = make_producer(&ring);
1776
1777        // Position head near end
1778        producer.avail_cursor.head = 2;
1779        producer.avail_cursor.wrap = true;
1780
1781        let chain = BufferChainBuilder::new()
1782            .readable(0x1000, 256)
1783            .readable(0x2000, 256)
1784            .readable(0x3000, 256)
1785            .build()
1786            .unwrap();
1787
1788        let _id = producer.submit_available(&chain).unwrap();
1789
1790        // Head at index 2 with wrap=true
1791        let head_desc = ring.read_desc(2);
1792        let head_flags = head_desc.flags();
1793        assert!(head_flags.contains(DescFlags::AVAIL));
1794        assert!(!head_flags.contains(DescFlags::USED));
1795
1796        // Middle at index 3 with wrap=true (before boundary)
1797        let mid_desc = ring.read_desc(3);
1798        let mid_flags = mid_desc.flags();
1799        assert!(mid_flags.contains(DescFlags::AVAIL));
1800        assert!(!mid_flags.contains(DescFlags::USED));
1801
1802        // Tail at index 0 with wrap=false (after boundary)
1803        let tail_desc = ring.read_desc(0);
1804        let tail_flags = tail_desc.flags();
1805        assert!(!tail_flags.contains(DescFlags::AVAIL));
1806        assert!(tail_flags.contains(DescFlags::USED));
1807
1808        // Cursor should have wrapped
1809        assert_eq!(producer.avail_cursor.head(), 1);
1810        assert!(!producer.avail_cursor.wrap());
1811    }
1812
1813    #[test]
1814    fn test_ring_full() {
1815        let ring = make_ring(4);
1816        let mut producer = make_producer(&ring);
1817
1818        // Fill ring completely
1819        for _ in 0..4 {
1820            producer.submit_one(0x1000, 256, false).unwrap();
1821        }
1822
1823        assert_eq!(producer.num_free, 0);
1824
1825        // Next submit should fail
1826        let result = producer.submit_one(0x5000, 256, false);
1827        assert!(matches!(result, Err(RingError::WouldBlock)));
1828    }
1829
1830    #[test]
1831    fn test_poll_and_reclaim() {
1832        let ring = make_ring(8);
1833        let mut producer = make_producer(&ring);
1834
1835        let id = producer.submit_one(0x1000, 512, false).unwrap();
1836
1837        // Manually mark as used (simulate device)
1838        let mut desc = ring.read_desc(0);
1839        desc.mark_used(true);
1840        desc.len = 256;
1841        ring.write_desc(0, desc);
1842
1843        // Poll should return the used buffer
1844        let used = producer.poll_used().unwrap();
1845        assert_eq!(used.id, id);
1846        assert_eq!(used.len, 256);
1847
1848        // State should be updated
1849        assert_eq!(producer.num_free, 8);
1850        assert_eq!(producer.used_cursor.head(), 1);
1851        assert_eq!(producer.id_num[id as usize], 0);
1852        assert!(producer.id_free.contains(&id));
1853    }
1854
1855    #[test]
1856    fn test_poll_multi_descriptor_chain() {
1857        let ring = make_ring(8);
1858        let mut producer = make_producer(&ring);
1859
1860        let chain = BufferChainBuilder::new()
1861            .readable(0x1000, 256)
1862            .readable(0x2000, 256)
1863            .writable(0x3000, 512)
1864            .build()
1865            .unwrap();
1866
1867        let id = producer.submit_available(&chain).unwrap();
1868
1869        // Mark only head as used
1870        let mut head_desc = ring.read_desc(0);
1871        head_desc.mark_used(true);
1872        head_desc.len = 512;
1873        ring.write_desc(0, head_desc);
1874
1875        // Poll should reclaim all 3 descriptors
1876        let used = producer.poll_used().unwrap();
1877        assert_eq!(used.id, id);
1878        assert_eq!(used.len, 512);
1879
1880        // Should have skipped 3 descriptors
1881        assert_eq!(producer.used_cursor.head(), 3);
1882        assert_eq!(producer.num_free, 8);
1883    }
1884
1885    #[test]
1886    fn test_id_reuse() {
1887        let ring = make_ring(4);
1888        let mut producer = make_producer(&ring);
1889
1890        // Submit and complete first buffer
1891        let id1 = producer.submit_one(0x1000, 256, false).unwrap();
1892
1893        let mut desc = ring.read_desc(0);
1894        desc.mark_used(true);
1895        ring.write_desc(0, desc);
1896
1897        producer.poll_used().unwrap();
1898
1899        // Submit another buffer - should reuse ID
1900        let id2 = producer.submit_one(0x2000, 256, false).unwrap();
1901
1902        // ID should be reused (LIFO from stack)
1903        assert_eq!(id2, id1);
1904        assert_eq!(producer.id_num[id2 as usize], 1);
1905    }
1906
1907    #[test]
1908    fn test_available_descriptor_flags() {
1909        let ring = make_ring(4);
1910        let mut producer = make_producer(&ring);
1911
1912        producer.submit_one(0x1000, 256, false).unwrap();
1913
1914        let desc = ring.read_desc(0);
1915
1916        // Available descriptor: AVAIL != USED
1917        let flags = desc.flags();
1918        assert_ne!(
1919            flags.contains(DescFlags::AVAIL),
1920            flags.contains(DescFlags::USED)
1921        );
1922
1923        // ... and AVAIL=true, USED=false for wrap=true
1924        assert!(flags.contains(DescFlags::AVAIL));
1925        assert!(!flags.contains(DescFlags::USED));
1926    }
1927
1928    #[test]
1929    fn test_used_descriptor_flags() {
1930        let ring = make_ring(4);
1931        let mut producer = make_producer(&ring);
1932
1933        producer.submit_one(0x1000, 256, false).unwrap();
1934
1935        let mut desc = ring.read_desc(0);
1936        desc.mark_used(true);
1937        ring.write_desc(0, desc);
1938
1939        let desc = ring.read_desc(0);
1940        let flags = desc.flags();
1941
1942        // Used descriptor: AVAIL == USED
1943        assert_eq!(
1944            flags.contains(DescFlags::AVAIL),
1945            flags.contains(DescFlags::USED)
1946        );
1947    }
1948
1949    #[test]
1950    fn test_poll_empty_ring() {
1951        let ring = make_ring(4);
1952        let mut producer = make_producer(&ring);
1953
1954        // Poll without any submitted buffers
1955        assert!(matches!(producer.poll_used(), Err(RingError::WouldBlock)));
1956    }
1957
1958    #[test]
1959    fn test_submit_when_full() {
1960        let ring = make_ring(2);
1961        let mut producer = make_producer(&ring);
1962
1963        producer.submit_one(0x1000, 256, false).unwrap();
1964        producer.submit_one(0x2000, 256, false).unwrap();
1965
1966        // Ring is full
1967        assert!(matches!(
1968            producer.submit_one(0x3000, 256, false),
1969            Err(RingError::WouldBlock)
1970        ));
1971    }
1972
1973    #[test]
1974    fn test_wrap_stress() {
1975        let ring = make_ring(4);
1976        let mut producer = make_producer(&ring);
1977        let mut consumer = make_consumer(&ring);
1978
1979        // Do multiple full laps
1980        for lap in 0..3 {
1981            let expected_wrap = lap % 2 == 0;
1982
1983            for _ in 0..4 {
1984                let id = producer.submit_one(0x1000, 256, false).unwrap();
1985
1986                let (dev_id, _) = consumer.poll_available().unwrap();
1987                assert_eq!(dev_id, id);
1988
1989                consumer.submit_used(dev_id, 256).unwrap();
1990
1991                producer.poll_used().unwrap();
1992            }
1993
1994            // After full lap, wrap should toggle
1995            assert_eq!(producer.avail_cursor.wrap(), !expected_wrap);
1996        }
1997        assert_invariants(&ring, &producer);
1998    }
1999
2000    #[test]
2001    fn test_next_flag_termination() {
2002        let ring = make_ring(8);
2003        let mut producer = make_producer(&ring);
2004
2005        let chain = BufferChainBuilder::new()
2006            .readable(0x1000, 256)
2007            .readable(0x2000, 256)
2008            .readable(0x3000, 256)
2009            .build()
2010            .unwrap();
2011
2012        producer.submit_available(&chain).unwrap();
2013
2014        // First two should have NEXT
2015        for i in 0..2 {
2016            let desc = ring.read_desc(i);
2017            assert!(desc.flags().contains(DescFlags::NEXT));
2018        }
2019
2020        // Last should not have NEXT
2021        let tail_desc = ring.read_desc(2);
2022        assert!(!tail_desc.flags().contains(DescFlags::NEXT));
2023    }
2024
2025    #[test]
2026    fn test_consumer_initialization() {
2027        let ring = make_ring(8);
2028        let consumer = make_consumer(&ring);
2029
2030        assert_eq!(consumer.avail_cursor.head(), 0);
2031        assert!(consumer.avail_cursor.wrap());
2032        assert_eq!(consumer.used_cursor.head(), 0);
2033        assert!(consumer.used_cursor.wrap());
2034
2035        for i in 0..8 {
2036            assert_eq!(consumer.id_num[i], 0);
2037        }
2038    }
2039
2040    #[test]
2041    fn test_consumer_poll_available_single() {
2042        let ring = make_ring(8);
2043        let mut producer = make_producer(&ring);
2044        let mut consumer = make_consumer(&ring);
2045
2046        let id = producer.submit_one(0x1000, 512, false).unwrap();
2047
2048        let (polled_id, chain) = consumer.poll_available().unwrap();
2049
2050        assert_eq!(polled_id, id);
2051        assert_eq!(chain.len(), 1);
2052        assert_eq!(chain.elems()[0].addr, 0x1000);
2053        assert_eq!(chain.elems()[0].len, 512);
2054        assert!(!chain.elems()[0].writable);
2055
2056        // Chain length recorded
2057        assert_eq!(consumer.id_num[id as usize], 1);
2058        assert_eq!(consumer.avail_cursor.head(), 1);
2059    }
2060
2061    #[test]
2062    fn test_consumer_poll_available_chain() {
2063        let ring = make_ring(8);
2064        let mut producer = make_producer(&ring);
2065        let mut consumer = make_consumer(&ring);
2066
2067        let chain = BufferChainBuilder::new()
2068            .readable(0x1000, 256)
2069            .readable(0x2000, 256)
2070            .writable(0x3000, 512)
2071            .build()
2072            .unwrap();
2073
2074        let id = producer.submit_available(&chain).unwrap();
2075
2076        let (polled_id, polled_chain) = consumer.poll_available().unwrap();
2077
2078        assert_eq!(polled_id, id);
2079        assert_eq!(polled_chain.len(), 3);
2080
2081        assert_eq!(polled_chain.elems()[0].addr, 0x1000);
2082        assert!(!polled_chain.elems()[0].writable);
2083
2084        assert_eq!(polled_chain.elems()[1].addr, 0x2000);
2085        assert!(!polled_chain.elems()[1].writable);
2086
2087        assert_eq!(polled_chain.elems()[2].addr, 0x3000);
2088        assert!(polled_chain.elems()[2].writable);
2089
2090        assert_eq!(consumer.id_num[id as usize], 3);
2091    }
2092
2093    #[test]
2094    fn test_consumer_rejects_duplicate_inflight_id() {
2095        let ring = make_ring(8);
2096        let mut producer = make_producer(&ring);
2097        let mut consumer = make_consumer(&ring);
2098
2099        let id = producer.submit_one(0x1000, 512, false).unwrap();
2100        let (polled_id, _) = consumer.poll_available().unwrap();
2101        assert_eq!(polled_id, id);
2102
2103        let mut desc = Descriptor::new(0x2000, 256, id, DescFlags::empty());
2104        desc.mark_avail(consumer.avail_cursor.wrap());
2105        ring.write_desc(consumer.avail_cursor.head(), desc);
2106
2107        assert!(matches!(
2108            consumer.poll_available(),
2109            Err(RingError::InvalidState)
2110        ));
2111    }
2112
2113    #[test]
2114    fn test_consumer_submit_used() {
2115        let ring = make_ring(8);
2116        let mut producer = make_producer(&ring);
2117        let mut consumer = make_consumer(&ring);
2118
2119        let id = producer.submit_one(0x1000, 512, true).unwrap();
2120
2121        let (polled_id, _) = consumer.poll_available().unwrap();
2122
2123        // Submit as used
2124        consumer.submit_used(polled_id, 256).unwrap();
2125
2126        // Check descriptor marked used
2127        let desc = ring.read_desc(0);
2128
2129        assert_eq!(desc.id, id);
2130        assert_eq!(desc.len, 256);
2131        assert!(desc.is_used(true));
2132
2133        // Cursor advanced, chain length cleared
2134        assert_eq!(consumer.used_cursor.head(), 1);
2135        assert_eq!(consumer.id_num[id as usize], 0);
2136    }
2137
2138    #[test]
2139    fn test_consumer_submit_used_multi_descriptor() {
2140        let ring = make_ring(8);
2141        let mut producer = make_producer(&ring);
2142        let mut consumer = make_consumer(&ring);
2143
2144        let chain = BufferChainBuilder::new()
2145            .readable(0x1000, 256)
2146            .writable(0x2000, 512)
2147            .writable(0x3000, 512)
2148            .build()
2149            .unwrap();
2150
2151        producer.submit_available(&chain).unwrap();
2152
2153        let (id, _) = consumer.poll_available().unwrap();
2154
2155        consumer.submit_used(id, 1024).unwrap();
2156
2157        // Only head marked used
2158        let head_desc = ring.read_desc(0);
2159        assert!(head_desc.is_used(true));
2160        assert_eq!(head_desc.len, 1024);
2161
2162        // Cursor skipped entire chain
2163        assert_eq!(consumer.used_cursor.head(), 3);
2164        assert_eq!(consumer.id_num[id as usize], 0);
2165    }
2166
2167    #[test]
2168    fn test_consumer_poll_empty() {
2169        let ring = make_ring(4);
2170        let mut consumer = make_consumer(&ring);
2171
2172        assert!(matches!(
2173            consumer.poll_available(),
2174            Err(RingError::WouldBlock)
2175        ));
2176    }
2177
2178    #[test]
2179    fn test_consumer_peek() {
2180        let ring = make_ring(8);
2181        let mut producer = make_producer(&ring);
2182        let consumer = make_consumer(&ring);
2183
2184        producer.submit_one(0x1000, 512, false).unwrap();
2185        assert!(consumer.peek_available().unwrap());
2186
2187        let empty_ring = make_ring(4);
2188        let empty_consumer = make_consumer(&empty_ring);
2189        assert!(!empty_consumer.peek_available().unwrap());
2190    }
2191
2192    #[test]
2193    fn test_full_roundtrip() {
2194        let ring = make_ring(8);
2195        let mut producer = make_producer(&ring);
2196        let mut consumer = make_consumer(&ring);
2197
2198        let chain = BufferChainBuilder::new()
2199            .readable(0x1000, 256)
2200            .writable(0x2000, 512)
2201            .build()
2202            .unwrap();
2203
2204        let id = producer.submit_available(&chain).unwrap();
2205
2206        let (consumer_id, consumer_chain) = consumer.poll_available().unwrap();
2207
2208        assert_eq!(consumer_id, id);
2209        assert_eq!(consumer_chain.len(), 2);
2210
2211        consumer.submit_used(consumer_id, 512).unwrap();
2212
2213        let used = producer.poll_used().unwrap();
2214        assert_eq!(used.id, id);
2215        assert_eq!(used.len, 512);
2216    }
2217
2218    #[test]
2219    fn ring_initial_poll_used_blocks() {
2220        let ring = make_ring(8);
2221        let mut producer = make_producer(&ring);
2222        // No submissions yet: all descriptors zero.
2223        for _ in 0..8 {
2224            assert!(matches!(producer.poll_used(), Err(RingError::WouldBlock)));
2225        }
2226        // Invariants: num_free == ring size
2227        assert_eq!(producer.num_free, ring.len());
2228    }
2229
2230    #[test]
2231    fn ring_consumer_blocks_until_submit() {
2232        let ring = make_ring(8);
2233        let mut producer = make_producer(&ring);
2234        let mut consumer = make_consumer(&ring);
2235
2236        assert!(matches!(
2237            consumer.poll_available(),
2238            Err(RingError::WouldBlock)
2239        ));
2240
2241        let chain = BufferChainBuilder::new()
2242            .readable(0x1000, 32)
2243            .readable(0x2000, 16)
2244            .build()
2245            .unwrap();
2246
2247        let id = producer.submit_available(&chain).unwrap();
2248
2249        let (cid, polled) = consumer.poll_available().unwrap();
2250        assert_eq!(cid, id);
2251        assert_eq!(polled.len(), chain.len());
2252    }
2253
2254    #[test]
2255    fn test_out_of_order_completion_stream() {
2256        let ring = make_ring(8);
2257        let mut producer = make_producer(&ring);
2258        let mut consumer = make_consumer(&ring);
2259
2260        // Driver submits two single-descriptor chains A then B
2261        let id_a = producer.submit_one(0x1000, 256, true).unwrap();
2262        let id_b = producer.submit_one(0x2000, 256, true).unwrap();
2263
2264        // Device polls them in ring order (A then B)
2265        let (dev_id_a, chain_a) = consumer.poll_available().unwrap();
2266        assert_eq!(dev_id_a, id_a);
2267        assert_eq!(chain_a.len(), 1);
2268
2269        let (dev_id_b, chain_b) = consumer.poll_available().unwrap();
2270        assert_eq!(dev_id_b, id_b);
2271        assert_eq!(chain_b.len(), 1);
2272
2273        // Device completes B first, then A
2274        consumer.submit_used(dev_id_b, 128).unwrap();
2275        consumer.submit_used(dev_id_a, 256).unwrap();
2276
2277        // Driver polls used stream: should see B (first completion)
2278        let used_b = producer.poll_used().unwrap();
2279        assert_eq!(used_b.id, id_b);
2280        assert_eq!(used_b.len, 128);
2281
2282        // Then sees A
2283        let used_a = producer.poll_used().unwrap();
2284        assert_eq!(used_a.id, id_a);
2285        assert_eq!(used_a.len, 256);
2286
2287        // IDs recycled
2288        assert!(producer.id_free.contains(&id_a));
2289        assert!(producer.id_free.contains(&id_b));
2290    }
2291
2292    #[test]
2293    fn test_mixed_chain_sizes_out_of_order_completion() {
2294        let ring = make_ring(16);
2295        let mut producer = make_producer(&ring);
2296        let mut consumer = make_consumer(&ring);
2297
2298        let chains = vec![
2299            BufferChainBuilder::new()
2300                .readable(0x1000, 10)
2301                .writable(0x2000, 5)
2302                .build()
2303                .unwrap(),
2304            BufferChainBuilder::new()
2305                .readable(0x3000, 8)
2306                .readable(0x3010, 8)
2307                .writable(0x3020, 16)
2308                .build()
2309                .unwrap(),
2310            BufferChainBuilder::new()
2311                .readable(0x4000, 4)
2312                .build()
2313                .unwrap(),
2314            BufferChainBuilder::new()
2315                .readable(0x5000, 4)
2316                .readable(0x5010, 4)
2317                .readable(0x5020, 4)
2318                .writable(0x5030, 4)
2319                .build()
2320                .unwrap(),
2321        ];
2322
2323        for c in &chains {
2324            producer.submit_available(c).unwrap();
2325        }
2326
2327        let mut dev_chain_lens = Vec::new();
2328        for _ in &chains {
2329            let (id, chain) = consumer.poll_available().unwrap();
2330            dev_chain_lens.push((id, chain.len() as u32));
2331        }
2332
2333        let order = [1, 3, 0, 2];
2334        let mut completion = Vec::new();
2335
2336        for &idx in &order {
2337            let (id, len) = dev_chain_lens[idx];
2338            consumer.submit_used(id, len).unwrap();
2339            completion.push((id, len));
2340        }
2341
2342        for (expected_id, expected_len) in &completion {
2343            let used = producer.poll_used().unwrap();
2344            assert_eq!(used.id, *expected_id);
2345            assert_eq!(used.len, *expected_len);
2346            assert_eq!(producer.id_num[*expected_id as usize], 0);
2347            assert!(producer.id_free.contains(expected_id));
2348        }
2349
2350        assert_invariants(&ring, &producer);
2351    }
2352
2353    // Used stream wrap crossing
2354    #[test]
2355    fn test_used_stream_wrap_crossing() {
2356        let ring = make_ring(8);
2357        let mut producer = make_producer(&ring);
2358        let mut consumer = make_consumer(&ring);
2359
2360        // Submit enough single descriptors to make used writes wrap
2361        let mut ids = Vec::new();
2362        for i in 0..8 {
2363            ids.push(producer.submit_one(0x1000 + i as u64, 1, false).unwrap());
2364        }
2365
2366        // Device polls all
2367        for _ in 0..8 {
2368            consumer.poll_available().unwrap();
2369        }
2370
2371        // Complete all in order except we simulate out-of-order by reversing
2372        for &id in ids.iter().rev() {
2373            consumer.submit_used(id, 1).unwrap();
2374        }
2375
2376        // Producer polls used; after consuming size descriptors used_cursor should wrap
2377        for _ in 0..8 {
2378            producer.poll_used().unwrap();
2379        }
2380        assert_eq!(producer.used_cursor.head(), 0);
2381        assert!(!producer.used_cursor.wrap()); // flipped once
2382        assert_invariants(&ring, &producer);
2383    }
2384
2385    // Interleaved availability and completion
2386    #[test]
2387    fn test_interleaved_submit_completion() {
2388        let ring = make_ring(8);
2389        let mut producer = make_producer(&ring);
2390        let mut consumer = make_consumer(&ring);
2391
2392        // Submit chain A (len 2)
2393        let chain_a = BufferChainBuilder::new()
2394            .readable(0x1000, 8)
2395            .writable(0x2000, 8)
2396            .build()
2397            .unwrap();
2398        let id_a = producer.submit_available(&chain_a).unwrap();
2399
2400        // Device polls A
2401        let (dev_id_a, _) = consumer.poll_available().unwrap();
2402        assert_eq!(dev_id_a, id_a);
2403
2404        // Device completes A
2405        consumer.submit_used(dev_id_a, 8).unwrap();
2406
2407        // Submit chain B (len 3) before driver reclaims A
2408        let chain_b = BufferChainBuilder::new()
2409            .readable(0x3000, 4)
2410            .readable(0x3010, 4)
2411            .writable(0x3020, 4)
2412            .build()
2413            .unwrap();
2414        let id_b = producer.submit_available(&chain_b).unwrap();
2415
2416        // Device polls B
2417        let (dev_id_b, _) = consumer.poll_available().unwrap();
2418        assert_eq!(dev_id_b, id_b);
2419
2420        // Driver reclaims A
2421        let used_a = producer.poll_used().unwrap();
2422        assert_eq!(used_a.id, id_a);
2423
2424        // Device completes B
2425        consumer.submit_used(dev_id_b, 12).unwrap();
2426
2427        // Driver reclaims B
2428        let used_b = producer.poll_used().unwrap();
2429        assert_eq!(used_b.id, id_b);
2430
2431        assert_invariants(&ring, &producer);
2432    }
2433
2434    // Partial publish safety (head not published yet)
2435    #[test]
2436    fn test_partial_publish_safety() {
2437        let ring = make_ring(8);
2438        let mut consumer = make_consumer(&ring);
2439        let mut producer = make_producer(&ring);
2440
2441        // Build chain manually: write tails only
2442        let chain = BufferChainBuilder::new()
2443            .readable(0x1000, 4)
2444            .readable(0x2000, 4)
2445            .writable(0x3000, 4)
2446            .build()
2447            .unwrap();
2448
2449        // Simulate manual tail writes without head publish
2450        let id = producer.id_free.pop().unwrap();
2451        producer.id_num[id as usize] = chain.len() as u16;
2452
2453        // Emulate internal position logic
2454        let head_idx = producer.avail_cursor.head();
2455        let wrap_start = producer.avail_cursor.wrap();
2456        let mut pos = producer.avail_cursor;
2457        pos.advance();
2458
2459        for (i, elem) in chain.elems().iter().enumerate().skip(1) {
2460            let is_next = i + 1 < chain.len();
2461            let mut flags = DescFlags::empty();
2462            flags.set(DescFlags::NEXT, is_next);
2463            flags.set(DescFlags::WRITE, elem.writable);
2464            let mut d = Descriptor::new(elem.addr, elem.len, id, flags);
2465            d.mark_avail(pos.wrap());
2466            ring.write_desc(pos.head(), d);
2467            pos.advance();
2468        }
2469
2470        // Head not published yet: consumer must not see chain
2471        assert!(matches!(
2472            consumer.poll_available(),
2473            Err(RingError::WouldBlock)
2474        ));
2475
2476        // Now publish head
2477        let head_elem = chain.elems()[0];
2478        let mut head_flags = DescFlags::empty();
2479        head_flags.set(DescFlags::NEXT, true);
2480        head_flags.set(DescFlags::WRITE, head_elem.writable);
2481        let mut head_desc = Descriptor::new(head_elem.addr, head_elem.len, id, head_flags);
2482        head_desc.mark_avail(wrap_start);
2483        ring.write_desc(head_idx, head_desc);
2484        producer.avail_cursor = pos;
2485        producer.num_free -= chain.len();
2486
2487        // Consumer can now see the chain
2488        let (dev_id, dev_chain) = consumer.poll_available().unwrap();
2489        assert_eq!(dev_id, id);
2490        assert_eq!(dev_chain.len(), chain.len());
2491        assert_invariants(&ring, &producer);
2492    }
2493
2494    // Tail misuse negative test
2495    #[test]
2496    fn test_tail_marked_used_ignored() {
2497        let ring = make_ring(8);
2498        let mut producer = make_producer(&ring);
2499
2500        let chain = BufferChainBuilder::new()
2501            .readable(0x1000, 4)
2502            .readable(0x2000, 4)
2503            .build()
2504            .unwrap();
2505        let id = producer.submit_available(&chain).unwrap();
2506
2507        // Incorrectly mark tail (index 1) used
2508        let mut tail_desc = ring.read_desc(1);
2509        tail_desc.mark_used(producer.used_cursor.wrap());
2510        ring.write_desc(1, tail_desc);
2511
2512        // Poll should return WouldBlock (head not used yet)
2513        assert!(matches!(producer.poll_used(), Err(RingError::WouldBlock)));
2514
2515        // Mark head used properly
2516        let mut head_desc = ring.read_desc(0);
2517        head_desc.mark_used(producer.used_cursor.wrap());
2518        ring.write_desc(0, head_desc);
2519
2520        // Now poll succeeds
2521        let used = producer.poll_used().unwrap();
2522        assert_eq!(used.id, id);
2523        assert_invariants(&ring, &producer);
2524    }
2525
2526    // Max chain length boundary
2527    #[test]
2528    fn test_max_chain_len_rejected() {
2529        let ring = make_ring(8);
2530        let mut producer = make_producer(&ring);
2531
2532        // Try chain longer than ring size
2533        let elems = (0..9).map(|i| BufferElement {
2534            addr: 0x1000 + i as u64,
2535            len: 42,
2536            writable: false,
2537        });
2538
2539        let chain = BufferChainBuilder::new().readables(elems).build().unwrap();
2540
2541        // Submit_available should reject when num_free < total_descs
2542        assert!(matches!(
2543            producer.submit_available(&chain),
2544            Err(RingError::WouldBlock)
2545        ));
2546    }
2547
2548    // Descriptor state monotonicity after many cycles
2549    #[test]
2550    fn test_descriptor_state_monotonicity() {
2551        let ring = make_ring(8);
2552        let mut producer = make_producer(&ring);
2553        let mut consumer = make_consumer(&ring);
2554
2555        // Track states: 0=zero/init, 1=available, 2=used, 3=reclaimed
2556        let mut states = vec![0u8; 8];
2557
2558        for _ in 0..5 {
2559            for state in states.iter_mut() {
2560                let id = producer.submit_one(0x1000, 4, false).unwrap();
2561                // mark available
2562                *state = (*state).max(1);
2563
2564                // device polls and completes
2565                let (dev_id, _) = consumer.poll_available().unwrap();
2566                consumer.submit_used(dev_id, 4).unwrap();
2567                *state = (*state).max(2);
2568
2569                let used = producer.poll_used().unwrap();
2570                assert_eq!(used.id, id);
2571                *state = (*state).max(3);
2572            }
2573
2574            assert_invariants(&ring, &producer);
2575        }
2576
2577        // Ensure monotonic progression (never decrease)
2578        for s in states {
2579            assert!(s >= 3);
2580        }
2581    }
2582
2583    // Large multi-lap random submission/completion
2584    #[test]
2585    fn test_random_stress_small() {
2586        use rand::RngExt;
2587        use rand::seq::SliceRandom;
2588
2589        let ring = make_ring(16);
2590        let mut producer = make_producer(&ring);
2591        let mut consumer = make_consumer(&ring);
2592        let mut rng = rand::rng();
2593
2594        // Submit initial set
2595        let mut active_ids = Vec::new();
2596        for _ in 0..8 {
2597            let len = rng.random_range(1..=4);
2598            let mut b = BufferChainBuilder::new().readable(0x1000, 4);
2599            for i in 1..len {
2600                b = b.readable(0x1000 + i as u64 * 0x10, 4);
2601            }
2602            let chain = b.build().unwrap();
2603            if let Ok(id) = producer.submit_available(&chain) {
2604                active_ids.push(id);
2605            }
2606        }
2607
2608        let mut dev_ids = Vec::new();
2609        while let Ok((id, _)) = consumer.poll_available() {
2610            dev_ids.push(id);
2611        }
2612
2613        // Randomly complete
2614        dev_ids.shuffle(&mut rng);
2615        for id in &dev_ids {
2616            let chain_len = consumer.id_num[*id as usize];
2617            consumer.submit_used(*id, chain_len as u32 * 4).unwrap();
2618        }
2619        // Driver reclaim
2620        for _ in &dev_ids {
2621            if producer.poll_used().is_ok() {}
2622        }
2623
2624        assert_invariants(&ring, &producer);
2625    }
2626
2627    // Out-of-order multi-length explicit
2628    #[test]
2629    fn test_out_of_order_multi_length() {
2630        let ring = make_ring(16);
2631        let mut producer = make_producer(&ring);
2632        let mut consumer = make_consumer(&ring);
2633
2634        let chain_a = BufferChainBuilder::new()
2635            .readable(0x1000, 4)
2636            .writable(0x2000, 4)
2637            .build()
2638            .unwrap();
2639        let chain_b = BufferChainBuilder::new()
2640            .readable(0x3000, 4)
2641            .readable(0x3010, 4)
2642            .writable(0x3020, 4)
2643            .build()
2644            .unwrap();
2645        let chain_c = BufferChainBuilder::new()
2646            .readable(0x4000, 4)
2647            .build()
2648            .unwrap();
2649
2650        let id_a = producer.submit_available(&chain_a).unwrap();
2651        let id_b = producer.submit_available(&chain_b).unwrap();
2652        let id_c = producer.submit_available(&chain_c).unwrap();
2653
2654        let (d_a, _) = consumer.poll_available().unwrap();
2655        let (d_b, _) = consumer.poll_available().unwrap();
2656        let (d_c, _) = consumer.poll_available().unwrap();
2657        assert_eq!(d_a, id_a);
2658        assert_eq!(d_b, id_b);
2659        assert_eq!(d_c, id_c);
2660
2661        // Complete B, then C, then A
2662        consumer.submit_used(d_b, 12).unwrap();
2663        consumer.submit_used(d_c, 4).unwrap();
2664        consumer.submit_used(d_a, 8).unwrap();
2665
2666        let u_b = producer.poll_used().unwrap();
2667        assert_eq!(u_b.id, id_b);
2668        let u_c = producer.poll_used().unwrap();
2669        assert_eq!(u_c.id, id_c);
2670        let u_a = producer.poll_used().unwrap();
2671        assert_eq!(u_a.id, id_a);
2672
2673        assert_invariants(&ring, &producer);
2674    }
2675
2676    #[test]
2677    fn interleave_submit_and_completion() {
2678        let ring = make_ring(16);
2679        let mut producer = make_producer(&ring);
2680        let mut consumer = make_consumer(&ring);
2681
2682        // Submit A (len 2)
2683        let chain_a = BufferChainBuilder::new()
2684            .readable(0x1000, 4)
2685            .writable(0x2000, 4)
2686            .build()
2687            .unwrap();
2688        let id_a = producer.submit_available(&chain_a).unwrap();
2689
2690        // Device polls A
2691        let (d_a, _) = consumer.poll_available().unwrap();
2692        assert_eq!(d_a, id_a);
2693
2694        // Immediately complete A
2695        consumer.submit_used(d_a, 8).unwrap();
2696
2697        // Submit B (len 3)
2698        let chain_b = BufferChainBuilder::new()
2699            .readable(0x3000, 4)
2700            .readable(0x3010, 4)
2701            .writable(0x3020, 4)
2702            .build()
2703            .unwrap();
2704        let id_b = producer.submit_available(&chain_b).unwrap();
2705
2706        // Driver polls used: gets A
2707        let u_a = producer.poll_used().unwrap();
2708        assert_eq!(u_a.id, id_a);
2709        assert_eq!(u_a.len, 8);
2710
2711        // Device polls B and submits used for it
2712        let (d_b, _) = consumer.poll_available().unwrap();
2713        assert_eq!(d_b, id_b);
2714        consumer.submit_used(d_b, 12).unwrap();
2715
2716        // Submit C (len 1)
2717        let id_c = producer.submit_one(0x4000, 4, false).unwrap();
2718
2719        // Device polls C and completes it
2720        let (d_c, _) = consumer.poll_available().unwrap();
2721        assert_eq!(d_c, id_c);
2722        consumer.submit_used(d_c, 4).unwrap();
2723
2724        // Driver polls used: gets B then C
2725        let u_b = producer.poll_used().unwrap();
2726        assert_eq!(u_b.id, id_b);
2727        assert_eq!(u_b.len, 12);
2728
2729        let u_c = producer.poll_used().unwrap();
2730        assert_eq!(u_c.id, id_c);
2731        assert_eq!(u_c.len, 4);
2732
2733        assert_invariants(&ring, &producer);
2734    }
2735
2736    // Event suppression tests
2737    #[test]
2738    fn producer_disable_used_notifications_writes_driver_disable() {
2739        let ring = make_ring(8);
2740        let mut producer = make_producer(&ring);
2741
2742        assert_eq!(ring.read_driver_event().flags(), EventFlags::ENABLE);
2743        producer.disable_used_notifications().unwrap();
2744        assert_eq!(ring.read_driver_event().flags(), EventFlags::DISABLE);
2745    }
2746
2747    #[test]
2748    fn producer_enable_used_notifications_writes_driver_enable() {
2749        let ring = make_ring(8);
2750        let mut producer = make_producer(&ring);
2751
2752        producer.disable_used_notifications().unwrap();
2753        assert_eq!(ring.read_driver_event().flags(), EventFlags::DISABLE);
2754
2755        producer.enable_used_notifications().unwrap();
2756        assert_eq!(ring.read_driver_event().flags(), EventFlags::ENABLE);
2757    }
2758
2759    #[test]
2760    fn producer_enable_used_notifications_desc_sets_off_wrap_and_flags() {
2761        let ring = make_ring(8);
2762        let mut producer = make_producer(&ring);
2763
2764        producer.enable_used_notifications_desc(5, true).unwrap();
2765
2766        let evt = ring.read_driver_event();
2767        assert_eq!(evt.flags(), EventFlags::DESC);
2768        assert_eq!(evt.desc_event_off(), 5);
2769        assert!(evt.desc_event_wrap());
2770    }
2771
2772    #[test]
2773    fn producer_enable_used_notifications_for_next_programs_used_cursor() {
2774        let ring = make_ring(8);
2775        let mut producer = make_producer(&ring);
2776
2777        // initial used cursor: head=0, wrap=true
2778        producer.enable_used_notifications_for_next().unwrap();
2779
2780        let evt = ring.read_driver_event();
2781        assert_eq!(evt.flags(), EventFlags::DESC);
2782        assert_eq!(evt.desc_event_off(), 0);
2783        assert!(evt.desc_event_wrap());
2784    }
2785
2786    #[test]
2787    fn consumer_disable_avail_notifications_writes_device_disable() {
2788        let ring = make_ring(8);
2789        let mut consumer = make_consumer(&ring);
2790
2791        assert_eq!(ring.read_device_event().flags(), EventFlags::ENABLE);
2792        consumer.disable_avail_notifications().unwrap();
2793        assert_eq!(ring.read_device_event().flags(), EventFlags::DISABLE);
2794    }
2795
2796    #[test]
2797    fn consumer_enable_avail_notifications_writes_device_enable() {
2798        let ring = make_ring(8);
2799        let mut consumer = make_consumer(&ring);
2800
2801        consumer.disable_avail_notifications().unwrap();
2802        assert_eq!(ring.read_device_event().flags(), EventFlags::DISABLE);
2803
2804        consumer.enable_avail_notifications().unwrap();
2805        assert_eq!(ring.read_device_event().flags(), EventFlags::ENABLE);
2806    }
2807
2808    #[test]
2809    fn consumer_enable_avail_notifications_desc_sets_off_wrap_and_flags() {
2810        let ring = make_ring(8);
2811        let mut consumer = make_consumer(&ring);
2812
2813        consumer.enable_avail_notifications_desc(7, false).unwrap();
2814
2815        let evt = ring.read_device_event();
2816        assert_eq!(evt.flags(), EventFlags::DESC);
2817        assert_eq!(evt.desc_event_off(), 7);
2818        assert!(!evt.desc_event_wrap());
2819    }
2820
2821    #[test]
2822    fn consumer_enable_avail_notifications_for_next_programs_avail_cursor() {
2823        let ring = make_ring(8);
2824        let mut consumer = make_consumer(&ring);
2825
2826        // initial avail cursor: head=0, wrap=true
2827        consumer.enable_avail_notifications_for_next().unwrap();
2828
2829        let evt = ring.read_device_event();
2830        assert_eq!(evt.flags(), EventFlags::DESC);
2831        assert_eq!(evt.desc_event_off(), 0);
2832        assert!(evt.desc_event_wrap());
2833    }
2834
2835    #[test]
2836    fn producer_does_not_write_device_event_when_toggling_used_notifications() {
2837        let ring = make_ring(8);
2838        let mut producer = make_producer(&ring);
2839
2840        let dev_before = ring.read_device_event();
2841        producer.disable_used_notifications().unwrap();
2842        let dev_after = ring.read_device_event();
2843
2844        assert_eq!(dev_after, dev_before);
2845    }
2846
2847    #[test]
2848    fn consumer_does_not_write_driver_event_when_toggling_avail_notifications() {
2849        let ring = make_ring(8);
2850        let mut consumer = make_consumer(&ring);
2851
2852        let drv_before = ring.read_driver_event();
2853        consumer.disable_avail_notifications().unwrap();
2854        let drv_after = ring.read_driver_event();
2855
2856        assert_eq!(drv_after, drv_before);
2857    }
2858
2859    #[test]
2860    fn should_notify_flags_enable_disable() {
2861        let ring_len = 8;
2862
2863        let old = RingCursor {
2864            head: 0,
2865            size: ring_len,
2866            wrap: true,
2867        };
2868        let new = RingCursor {
2869            head: 1,
2870            size: ring_len,
2871            wrap: true,
2872        };
2873
2874        // DISABLE -> never notify
2875        let evt = EventSuppression::new(0, EventFlags::DISABLE);
2876        assert!(!should_notify(evt, ring_len, old, new));
2877
2878        // ENABLE -> always notify
2879        let evt = EventSuppression::new(0, EventFlags::ENABLE);
2880        assert!(should_notify(evt, ring_len, old, new));
2881    }
2882
2883    #[test]
2884    fn should_notify_desc_no_crossing() {
2885        let ring_len = 8;
2886
2887        let old = RingCursor {
2888            head: 2,
2889            size: ring_len,
2890            wrap: true,
2891        };
2892        let new = RingCursor {
2893            head: 3,
2894            size: ring_len,
2895            wrap: true,
2896        };
2897
2898        // event at 6, we did not cross it
2899        let mut evt = EventSuppression::zeroed();
2900        evt.set_desc_event(6, true);
2901        evt.set_flags(EventFlags::DESC);
2902
2903        assert!(!should_notify(evt, ring_len, old, new));
2904    }
2905
2906    #[test]
2907    fn should_notify_desc_wrap_mismatch_adjusts_event_idx() {
2908        let ring_len = 8;
2909
2910        let old = RingCursor {
2911            head: 7,
2912            size: ring_len,
2913            wrap: true,
2914        };
2915        let new = RingCursor {
2916            head: 1,
2917            size: ring_len,
2918            wrap: false,
2919        };
2920
2921        let mut evt = EventSuppression::zeroed();
2922        evt.set_desc_event(7, true);
2923        evt.set_flags(EventFlags::DESC);
2924
2925        assert!(should_notify(evt, ring_len, old, new));
2926    }
2927
2928    #[test]
2929    fn ring_need_event_basic_cases() {
2930        // If event_idx == new-1, should be true
2931        assert!(ring_need_event(4, 5, 2));
2932        // If no progress, should be false
2933        assert!(!ring_need_event(4, 5, 5));
2934
2935        // Wrapping arithmetic sanity: old near u16::MAX
2936        let old = 0xFFFE;
2937        let new = 1;
2938        // event at 0xFFFF is considered "just before wrap"
2939        assert!(ring_need_event(0xFFFF, new, old));
2940    }
2941
2942    // Bad device/driver tests
2943    #[test]
2944    fn bad_device_marks_tail_used() {
2945        let ring = make_ring(8);
2946        let mut producer = make_producer(&ring);
2947
2948        let chain = BufferChainBuilder::new()
2949            .readable(0x1000, 4)
2950            .readable(0x2000, 4)
2951            .build()
2952            .unwrap();
2953        let id = producer.submit_available(&chain).unwrap();
2954
2955        // Bad device: mark index 1 (tail) used
2956        let mut tail = ring.read_desc(1);
2957        tail.mark_used(producer.used_cursor.wrap());
2958        ring.write_desc(1, tail);
2959
2960        // Driver must not consume it
2961        assert!(matches!(producer.poll_used(), Err(RingError::WouldBlock)));
2962
2963        // Now mark head properly, driver must consume
2964        let mut head = ring.read_desc(0);
2965        head.mark_used(producer.used_cursor.wrap());
2966        ring.write_desc(0, head);
2967
2968        let used = producer.poll_used().unwrap();
2969        assert_eq!(used.id, id);
2970    }
2971
2972    #[test]
2973    fn bad_device_wrong_used_bits() {
2974        let ring = make_ring(4);
2975        let mut producer = make_producer(&ring);
2976
2977        let id = producer.submit_one(0x1000, 8, true).unwrap();
2978
2979        // Malformed: set AVAIL but clear USED (should be equal for used)
2980        let mut d = ring.read_desc(0);
2981        // Force flags to look like "available" despite intent
2982        d.mark_avail(producer.used_cursor.wrap());
2983        d.len = 8;
2984        ring.write_desc(0, d);
2985
2986        assert!(matches!(producer.poll_used(), Err(RingError::WouldBlock)));
2987
2988        let mut d2 = ring.read_desc(0);
2989        d2.mark_used(producer.used_cursor.wrap());
2990        ring.write_desc(0, d2);
2991
2992        let u = producer.poll_used().unwrap();
2993        assert_eq!(u.id, id);
2994    }
2995
2996    #[test]
2997    fn bad_driver_next_never_clears() {
2998        let ring = make_ring(8);
2999        let mut consumer = make_consumer(&ring);
3000        let mut producer = make_producer(&ring);
3001
3002        // Allocate an ID and pretend one huge chain
3003        let id = producer.id_free.pop().unwrap();
3004        producer.id_num[id as usize] = 8;
3005
3006        let mut pos = producer.avail_cursor;
3007        let wrap_start = pos.wrap();
3008
3009        // Write every descriptor with NEXT set and same id
3010        for _ in 0..8 {
3011            let idx = pos.head();
3012            let mut flags = DescFlags::empty();
3013            flags.set(DescFlags::NEXT, true); // incorrect: last should NOT have NEXT
3014            let mut desc = Descriptor::new(0x1000 + idx as u64 * 0x10, 4, id, flags);
3015            desc.mark_avail(pos.wrap());
3016            ring.write_desc(idx, desc);
3017            pos.advance();
3018        }
3019
3020        // Publish head last (simulate driver behavior)
3021        let head_idx = producer.avail_cursor.head();
3022        let mut head_flags = DescFlags::empty();
3023        head_flags.set(DescFlags::NEXT, true);
3024        let mut head_desc = Descriptor::new(0x42, 4, id, head_flags);
3025        head_desc.mark_avail(wrap_start);
3026        ring.write_desc(head_idx, head_desc);
3027
3028        // Consumer should detect invalid chain via step guard
3029        assert!(matches!(
3030            consumer.poll_available(),
3031            Err(RingError::BadChain)
3032        ));
3033    }
3034
3035    #[test]
3036    fn bad_driver_interleaved_readables_and_writables() {
3037        let ring = make_ring(8);
3038        let mut consumer = make_consumer(&ring);
3039        let mut producer = make_producer(&ring);
3040
3041        let chain = BufferChainBuilder::new()
3042            .readable(0x1000, 4)
3043            .readable(0x2000, 4)
3044            .writable(0x2000, 4)
3045            .build()
3046            .unwrap();
3047
3048        let _id = producer.submit_available(&chain).unwrap();
3049
3050        // now change first descriptor to writable (bad driver)
3051        let mut first = ring.read_desc(0);
3052        first.flags |= DescFlags::WRITE.bits();
3053        ring.write_desc(0, first);
3054
3055        assert!(matches!(
3056            consumer.poll_available(),
3057            Err(RingError::BadChain)
3058        ));
3059    }
3060
3061    #[test]
3062    fn bad_device_marks_multiple_used_in_chain() {
3063        let ring = make_ring(8);
3064        let mut producer = make_producer(&ring);
3065
3066        let chain = BufferChainBuilder::new()
3067            .readable(0x1000, 4)
3068            .readable(0x2000, 4)
3069            .build()
3070            .unwrap();
3071        let id = producer.submit_available(&chain).unwrap();
3072
3073        // Bad device: mark head and tail used
3074        let mut head = ring.read_desc(0);
3075        head.mark_used(producer.used_cursor.wrap());
3076        ring.write_desc(0, head);
3077
3078        let mut tail = ring.read_desc(1);
3079        tail.mark_used(producer.used_cursor.wrap());
3080        ring.write_desc(1, tail);
3081
3082        // Driver consumes once
3083        let u = producer.poll_used().unwrap();
3084        assert_eq!(u.id, id);
3085
3086        // Next poll should block; no duplicate consumption
3087        assert!(matches!(producer.poll_used(), Err(RingError::WouldBlock)));
3088    }
3089
3090    #[test]
3091    fn bad_device_writes_used_at_wrong_slot() {
3092        let ring = make_ring(8);
3093        let mut producer = make_producer(&ring);
3094
3095        let _id = producer.submit_one(0x1000, 4, true).unwrap();
3096
3097        // Wrong slot: mark index 3 used while next_used is 0
3098        let mut d = ring.read_desc(3);
3099        d.mark_used(producer.used_cursor.wrap());
3100        ring.write_desc(3, d);
3101
3102        // Driver should still block (polls only slot 0)
3103        assert!(matches!(producer.poll_used(), Err(RingError::WouldBlock)));
3104
3105        // Now mark slot 0 correctly, driver can consume
3106        let mut d0 = ring.read_desc(0);
3107        d0.mark_used(producer.used_cursor.wrap());
3108        ring.write_desc(0, d0);
3109        let _u = producer.poll_used().unwrap();
3110    }
3111
3112    #[test]
3113    fn bad_driver_reuses_id_while_outstanding() {
3114        let ring = make_ring(8);
3115        let mut producer = make_producer(&ring);
3116
3117        // Submit first buffer: allocate ID
3118        let id = producer.submit_one(0x1000, 4, false).unwrap();
3119        assert_eq!(producer.id_num[id as usize], 1);
3120
3121        // push the same ID back into free list while it's still outstanding.
3122        producer.id_free.push(id);
3123
3124        // Next submit should fail because ID is still outstanding.
3125        let res = producer.submit_one(0x2000, 4, false);
3126        assert!(matches!(res, Err(RingError::InvalidState)));
3127    }
3128
3129    #[test]
3130    fn test_avail_cursor_accessor() {
3131        let ring = make_ring(8);
3132        let mut producer = make_producer(&ring);
3133
3134        // Initial cursor
3135        let cursor = producer.avail_cursor();
3136        assert_eq!(cursor.head(), 0);
3137        assert!(cursor.wrap());
3138
3139        // After submit
3140        producer.submit_one(0x1000, 512, false).unwrap();
3141        let cursor = producer.avail_cursor();
3142        assert_eq!(cursor.head(), 1);
3143        assert!(cursor.wrap());
3144    }
3145
3146    #[test]
3147    fn test_should_notify_since() {
3148        let ring = make_ring(8);
3149        let mut producer = make_producer(&ring);
3150
3151        let before = producer.avail_cursor();
3152        producer.submit_one(0x1000, 512, false).unwrap();
3153
3154        // Default is ENABLE mode, so should notify
3155        let should_notify = producer.should_notify_since(before).unwrap();
3156        assert!(should_notify);
3157    }
3158
3159    #[test]
3160    fn test_batch_notification_single_check() {
3161        let ring = make_ring(8);
3162        let mut producer = make_producer(&ring);
3163        let mut consumer = make_consumer(&ring);
3164
3165        let before = producer.avail_cursor();
3166
3167        // Submit multiple descriptors
3168        producer.submit_one(0x1000, 512, false).unwrap();
3169        producer.submit_one(0x2000, 512, false).unwrap();
3170        producer.submit_one(0x3000, 512, false).unwrap();
3171
3172        // Single notification check for the entire batch
3173        let should_notify = producer.should_notify_since(before).unwrap();
3174        assert!(should_notify);
3175
3176        // Consumer sees all 3 descriptors
3177        for _ in 0..3 {
3178            let (_, _) = consumer.poll_available().unwrap();
3179        }
3180    }
3181
3182    #[test]
3183    fn test_ring_cursor_reset() {
3184        let mut cursor = RingCursor::new(16);
3185        cursor.advance_by(5);
3186        assert_eq!(cursor.head(), 5);
3187
3188        cursor.reset();
3189        assert_eq!(cursor, RingCursor::new(16));
3190        assert_eq!(cursor.head(), 0);
3191        assert!(cursor.wrap());
3192    }
3193
3194    #[test]
3195    fn test_ring_cursor_reset_after_wrap() {
3196        let mut cursor = RingCursor::new(4);
3197        // Advance past the wrap point
3198        cursor.advance_by(5);
3199        assert_eq!(cursor.head(), 1);
3200        assert!(!cursor.wrap());
3201
3202        cursor.reset();
3203        assert_eq!(cursor.head(), 0);
3204        assert!(cursor.wrap());
3205    }
3206
3207    #[test]
3208    fn test_ring_producer_reset_matches_new() {
3209        let ring = make_ring(8);
3210        let fresh = make_producer(&ring);
3211
3212        let mut used = make_producer(&ring);
3213        // Mutate state
3214        used.submit_one(0x1000, 64, false).unwrap();
3215        used.submit_one(0x2000, 128, true).unwrap();
3216
3217        used.reset();
3218
3219        assert_eq!(used.avail_cursor, fresh.avail_cursor);
3220        assert_eq!(used.used_cursor, fresh.used_cursor);
3221        assert_eq!(used.num_free, fresh.num_free);
3222        assert_eq!(used.id_free.len(), fresh.id_free.len());
3223        assert_eq!(used.id_num.as_slice(), fresh.id_num.as_slice());
3224        assert_eq!(used.event_flags_shadow, fresh.event_flags_shadow);
3225    }
3226
3227    #[test]
3228    fn test_ring_producer_reset_id_free_complete() {
3229        let ring = make_ring(8);
3230        let mut producer = make_producer(&ring);
3231
3232        // Submit and consume several descriptors
3233        for i in 0..4u64 {
3234            producer.submit_one(0x1000 + i * 0x100, 64, false).unwrap();
3235        }
3236        assert_eq!(producer.num_free, 4);
3237
3238        producer.reset();
3239
3240        assert_eq!(producer.num_free, 8);
3241        assert_eq!(producer.id_free.len(), 8);
3242        // All IDs 0..8 should be present
3243        for id in 0..8u16 {
3244            assert!(producer.id_free.contains(&id));
3245        }
3246    }
3247
3248    #[test]
3249    fn test_ring_consumer_reset_matches_new() {
3250        let ring = make_ring(8);
3251        let fresh = make_consumer(&ring);
3252
3253        let mut used = make_consumer(&ring);
3254
3255        // Submit from producer side so consumer has something to poll
3256        let mut producer = make_producer(&ring);
3257        producer.submit_one(0x1000, 64, false).unwrap();
3258
3259        // Consumer polls the available descriptor
3260        let (id, _chain) = used.poll_available().unwrap();
3261        used.submit_used(id, 64).unwrap();
3262
3263        used.reset();
3264
3265        assert_eq!(used.avail_cursor, fresh.avail_cursor);
3266        assert_eq!(used.used_cursor, fresh.used_cursor);
3267        assert_eq!(used.id_num.as_slice(), fresh.id_num.as_slice());
3268        assert_eq!(used.num_inflight, fresh.num_inflight);
3269        assert_eq!(used.event_flags_shadow, fresh.event_flags_shadow);
3270    }
3271
3272    #[test]
3273    fn test_ring_consumer_reset_clears_inflight() {
3274        let ring = make_ring(8);
3275        let mut producer = make_producer(&ring);
3276        let mut consumer = make_consumer(&ring);
3277
3278        // Submit and poll two items (consume but do not complete)
3279        producer.submit_one(0x1000, 64, false).unwrap();
3280        producer.submit_one(0x2000, 64, false).unwrap();
3281        let _ = consumer.poll_available().unwrap();
3282        let _ = consumer.poll_available().unwrap();
3283        assert_eq!(consumer.num_inflight, 2);
3284
3285        consumer.reset();
3286        assert_eq!(consumer.num_inflight, 0);
3287    }
3288
3289    #[test]
3290    fn test_reset_prefilled_sets_cursors() {
3291        let ring = make_ring(8);
3292        let mut producer = make_producer(&ring);
3293        let ids: Vec<u16> = (0..8).collect();
3294        producer.reset_prefilled(&ids);
3295
3296        // avail wrapped once (all 8 slots submitted)
3297        assert_eq!(producer.avail_cursor.head(), 0);
3298        assert!(!producer.avail_cursor.wrap());
3299        // used cursor at initial position
3300        assert_eq!(producer.used_cursor.head(), 0);
3301        assert!(producer.used_cursor.wrap());
3302    }
3303
3304    #[test]
3305    fn test_reset_prefilled_all_ids_inflight() {
3306        let ring = make_ring(8);
3307        let mut producer = make_producer(&ring);
3308        let ids: Vec<u16> = (0..8).collect();
3309        producer.reset_prefilled(&ids);
3310
3311        assert_eq!(producer.num_free, 0);
3312        assert!(producer.id_free.is_empty());
3313        assert!(producer.id_num.iter().all(|&n| n == 1));
3314    }
3315
3316    #[test]
3317    fn test_reset_prefilled_partial() {
3318        let ring = make_ring(8);
3319        let mut producer = make_producer(&ring);
3320        producer.reset_prefilled(&[5, 6, 7, 3]);
3321
3322        // avail cursor at position 4, no wrap
3323        assert_eq!(producer.avail_cursor.head(), 4);
3324        assert!(producer.avail_cursor.wrap());
3325        // used cursor at initial position
3326        assert_eq!(producer.used_cursor.head(), 0);
3327        assert!(producer.used_cursor.wrap());
3328
3329        assert_eq!(producer.num_free, 4);
3330        assert_eq!(producer.id_free.len(), 4);
3331        for &id in &[0, 1, 2, 4] {
3332            assert!(producer.id_free.contains(&id));
3333        }
3334        // Only the specified IDs are in-flight
3335        for &id in &[5, 6, 7, 3] {
3336            assert_eq!(producer.id_num[id as usize], 1);
3337        }
3338        for &id in &[0, 1, 2, 4] {
3339            assert_eq!(producer.id_num[id as usize], 0);
3340        }
3341    }
3342
3343    #[test]
3344    fn test_reset_prefilled_partial_then_submit() {
3345        let ring = make_ring(8);
3346        let mut producer = make_producer(&ring);
3347        producer.reset_prefilled(&[4, 5, 6, 7]);
3348
3349        let id = producer.submit_one(0x8000, 128, false).unwrap();
3350
3351        assert!([0, 1, 2, 3].contains(&id));
3352        assert_eq!(producer.num_free, 3);
3353        assert_eq!(producer.id_num[id as usize], 1);
3354    }
3355
3356    #[test]
3357    fn test_reset_prefilled_then_poll_used() {
3358        let ring = make_ring(4);
3359        let mut producer = make_producer(&ring);
3360
3361        // Simulate host prefill: LIFO assigns IDs 3, 2, 1, 0
3362        for i in 0..4u64 {
3363            producer.submit_one(0x1000 + i * 4096, 4096, true).unwrap();
3364        }
3365
3366        // Consumer marks one as used
3367        let mut consumer = make_consumer(&ring);
3368        let (id, _chain) = consumer.poll_available().unwrap();
3369        consumer.submit_used(id, 64).unwrap();
3370
3371        // Fresh producer restores via reset_prefilled with all IDs
3372        let mut restored = make_producer(&ring);
3373        restored.reset_prefilled(&[0, 1, 2, 3]);
3374
3375        // poll_used should discover the consumed descriptor
3376        let used = restored.poll_used().unwrap();
3377        assert_eq!(used.id, id);
3378    }
3379
3380    #[test]
3381    fn test_desc_table_read_after_submit() {
3382        let ring = make_ring(8);
3383        let mut writer = make_producer(&ring);
3384        writer.submit_one(0x1000, 4096, true).unwrap();
3385
3386        let reader = make_producer(&ring);
3387        let addr = reader.desc_table().desc_addr(0).unwrap();
3388        let flags = Descriptor::read_flags_acquire(reader.mem(), addr).unwrap();
3389        let desc = Descriptor::read_body(reader.mem(), addr, flags).unwrap();
3390        assert_eq!(desc.addr, 0x1000);
3391        assert_eq!(desc.len, 4096);
3392        assert!(desc.is_writable());
3393        assert!(desc.is_avail(true));
3394        assert!(!desc.is_used(true));
3395    }
3396
3397    #[test]
3398    fn test_desc_table_out_of_bounds() {
3399        let ring = make_ring(8);
3400        let reader = make_producer(&ring);
3401        assert!(reader.desc_table().desc_addr(8).is_none());
3402    }
3403
3404    #[test]
3405    fn test_desc_table_read_used_descriptor() {
3406        let ring = make_ring(8);
3407        let mut writer = make_producer(&ring);
3408        writer.submit_one(0x1000, 4096, true).unwrap();
3409
3410        let mut consumer = make_consumer(&ring);
3411        let (id, _chain) = consumer.poll_available().unwrap();
3412        consumer.submit_used(id, 128).unwrap();
3413
3414        let reader = make_producer(&ring);
3415        let addr = reader.desc_table().desc_addr(0).unwrap();
3416        let flags = Descriptor::read_flags_acquire(reader.mem(), addr).unwrap();
3417        let desc = Descriptor::read_body(reader.mem(), addr, flags).unwrap();
3418        assert!(desc.is_used(true));
3419        assert!(!desc.is_avail(true));
3420    }
3421}
3422
3423// Adopted from https://github.com/weltling/virtio-villain/tree/main/tests/packed
3424#[cfg(test)]
3425mod virtio_villain {
3426    use super::tests::{OwnedRing, make_consumer, make_producer, make_ring};
3427    use super::*;
3428
3429    fn raw_desc(id: u16, len: u32, flags: DescFlags) -> Descriptor {
3430        Descriptor::new(0x1000 + u64::from(id) * 0x10, len, id, flags)
3431    }
3432
3433    fn avail_desc(id: u16, len: u32, flags: DescFlags) -> Descriptor {
3434        let mut desc = raw_desc(id, len, flags);
3435        desc.mark_avail(true);
3436        desc
3437    }
3438
3439    fn write_avail(ring: &OwnedRing, idx: u16, id: u16, flags: DescFlags) {
3440        write_avail_len(ring, idx, id, 16, flags);
3441    }
3442
3443    fn write_avail_len(ring: &OwnedRing, idx: u16, id: u16, len: u32, flags: DescFlags) {
3444        ring.write_desc(idx, avail_desc(id, len, flags));
3445    }
3446
3447    fn write_driver_event(ring: &OwnedRing, off_wrap: u16, flags: u16) {
3448        write_event(ring, ring.layout().drv_evt_addr(), off_wrap, flags);
3449    }
3450
3451    fn write_device_event(ring: &OwnedRing, off_wrap: u16, flags: u16) {
3452        write_event(ring, ring.layout().dev_evt_addr(), off_wrap, flags);
3453    }
3454
3455    fn write_event(ring: &OwnedRing, addr: u64, off_wrap: u16, flags: u16) {
3456        ring.mem()
3457            .write(
3458                addr,
3459                &[
3460                    (off_wrap & 0xff) as u8,
3461                    (off_wrap >> 8) as u8,
3462                    (flags & 0xff) as u8,
3463                    (flags >> 8) as u8,
3464                ],
3465            )
3466            .unwrap();
3467    }
3468
3469    #[test]
3470    fn p0003_chain_with_next_past_ring_is_rejected() {
3471        let ring = make_ring(4);
3472        let mut consumer = make_consumer(&ring);
3473
3474        for idx in 0..ring.len() as u16 {
3475            write_avail(&ring, idx, 0, DescFlags::NEXT);
3476        }
3477
3478        assert!(matches!(
3479            consumer.poll_available(),
3480            Err(RingError::BadChain)
3481        ));
3482    }
3483
3484    #[test]
3485    fn p0005_indirect_without_feature_is_rejected() {
3486        let ring = make_ring(8);
3487        let mut consumer = make_consumer(&ring);
3488
3489        write_avail(&ring, 0, 0, DescFlags::INDIRECT);
3490
3491        assert!(matches!(
3492            consumer.poll_available(),
3493            Err(RingError::BadChain)
3494        ));
3495    }
3496
3497    #[test]
3498    fn p0006_indirect_with_bad_flags_is_rejected() {
3499        let ring = make_ring(8);
3500        let mut consumer = make_consumer(&ring);
3501
3502        write_avail(&ring, 0, 0, DescFlags::INDIRECT | DescFlags::WRITE);
3503
3504        assert!(matches!(
3505            consumer.poll_available(),
3506            Err(RingError::BadChain)
3507        ));
3508    }
3509
3510    #[test]
3511    fn p0007_indirect_tail_in_mixed_chain_is_rejected() {
3512        let ring = make_ring(8);
3513        let mut consumer = make_consumer(&ring);
3514
3515        write_avail(&ring, 0, 0, DescFlags::NEXT);
3516        write_avail(&ring, 1, 0, DescFlags::INDIRECT | DescFlags::WRITE);
3517
3518        assert!(matches!(
3519            consumer.poll_available(),
3520            Err(RingError::BadChain)
3521        ));
3522    }
3523
3524    #[test]
3525    fn p0008_long_chain_is_consumable_at_ring_layer() {
3526        let ring = make_ring(16);
3527        let mut consumer = make_consumer(&ring);
3528
3529        for idx in 0..12u16 {
3530            let flags = if idx == 11 {
3531                DescFlags::WRITE
3532            } else {
3533                DescFlags::NEXT | DescFlags::WRITE
3534            };
3535            write_avail(&ring, idx, 0, flags);
3536        }
3537
3538        let (id, chain) = consumer.poll_available().unwrap();
3539        assert_eq!(id, 0);
3540        assert_eq!(chain.len(), 12);
3541    }
3542
3543    #[test]
3544    fn p0009_unaligned_descriptor_address_is_preserved() {
3545        let ring = make_ring(8);
3546        let mut consumer = make_consumer(&ring);
3547
3548        let mut desc = Descriptor::new(0x1003, 16, 0, DescFlags::empty());
3549        desc.mark_avail(true);
3550        ring.write_desc(0, desc);
3551
3552        let (_, chain) = consumer.poll_available().unwrap();
3553        assert_eq!(chain.elems()[0].addr, 0x1003);
3554    }
3555
3556    #[test]
3557    fn p0010_writable_before_readable_is_rejected() {
3558        let ring = make_ring(8);
3559        let mut consumer = make_consumer(&ring);
3560
3561        write_avail(&ring, 0, 0, DescFlags::NEXT);
3562        write_avail(&ring, 1, 0, DescFlags::NEXT | DescFlags::WRITE);
3563        write_avail(&ring, 2, 0, DescFlags::NEXT);
3564        write_avail(&ring, 3, 0, DescFlags::WRITE);
3565
3566        assert!(matches!(
3567            consumer.poll_available(),
3568            Err(RingError::BadChain)
3569        ));
3570    }
3571
3572    #[test]
3573    fn p0011_stale_wrap_descriptor_is_ignored() {
3574        let ring = make_ring(8);
3575        let mut consumer = make_consumer(&ring);
3576
3577        let mut desc = raw_desc(0, 16, DescFlags::empty());
3578        desc.mark_avail(false);
3579        ring.write_desc(0, desc);
3580
3581        assert!(matches!(
3582            consumer.poll_available(),
3583            Err(RingError::WouldBlock)
3584        ));
3585    }
3586
3587    #[test]
3588    fn p0012_multidescriptor_oob_id_is_rejected() {
3589        let ring = make_ring(8);
3590        let mut consumer = make_consumer(&ring);
3591        let bad_id = ring.len() as u16;
3592
3593        write_avail(&ring, 0, bad_id, DescFlags::NEXT);
3594        write_avail(&ring, 1, bad_id, DescFlags::WRITE);
3595
3596        assert!(matches!(
3597            consumer.poll_available(),
3598            Err(RingError::InvalidState)
3599        ));
3600    }
3601
3602    #[test]
3603    fn p0013_duplicate_inflight_buffer_id_is_rejected() {
3604        let ring = make_ring(8);
3605        let mut consumer = make_consumer(&ring);
3606
3607        write_avail(&ring, 0, 0, DescFlags::NEXT);
3608        write_avail(&ring, 1, 0, DescFlags::WRITE);
3609        write_avail(&ring, 2, 0, DescFlags::NEXT);
3610        write_avail(&ring, 3, 0, DescFlags::WRITE);
3611
3612        let (first_id, first_chain) = consumer.poll_available().unwrap();
3613        assert_eq!(first_id, 0);
3614        assert_eq!(first_chain.len(), 2);
3615
3616        assert!(matches!(
3617            consumer.poll_available(),
3618            Err(RingError::InvalidState)
3619        ));
3620    }
3621
3622    #[test]
3623    fn p0014_reserved_driver_event_flags_do_not_block_processing() {
3624        let ring = make_ring(8);
3625        let mut consumer = make_consumer(&ring);
3626
3627        write_driver_event(&ring, 0, 3);
3628        write_avail(&ring, 0, 0, DescFlags::empty());
3629
3630        let (id, chain) = consumer.poll_available().unwrap();
3631        assert_eq!(id, 0);
3632        assert_eq!(chain.len(), 1);
3633    }
3634
3635    #[test]
3636    fn p0015_wrap_at_zero_is_consumed_correctly() {
3637        let ring = make_ring(2);
3638        let mut producer = make_producer(&ring);
3639        let mut consumer = make_consumer(&ring);
3640
3641        producer.submit_one(0x1000, 16, false).unwrap();
3642        producer.submit_one(0x2000, 16, false).unwrap();
3643
3644        assert_eq!(producer.avail_cursor().head(), 0);
3645        assert!(!producer.avail_cursor().wrap());
3646
3647        assert_eq!(consumer.poll_available().unwrap().1.elems()[0].addr, 0x1000);
3648        assert_eq!(consumer.poll_available().unwrap().1.elems()[0].addr, 0x2000);
3649        assert_eq!(consumer.avail_cursor().head(), 0);
3650        assert!(!consumer.avail_cursor().wrap());
3651    }
3652
3653    #[test]
3654    fn p0016_queue_size_one_next_chain_is_rejected() {
3655        let ring = make_ring(1);
3656        let mut consumer = make_consumer(&ring);
3657
3658        write_avail(&ring, 0, 0, DescFlags::NEXT);
3659
3660        assert!(matches!(
3661            consumer.poll_available(),
3662            Err(RingError::BadChain)
3663        ));
3664    }
3665
3666    #[test]
3667    fn p0017_stale_driver_event_wrap_suppresses_notification() {
3668        let ring = make_ring(8);
3669        let mut consumer = make_consumer(&ring);
3670
3671        write_driver_event(&ring, 0, EventFlags::DESC.bits());
3672        write_avail(&ring, 0, 0, DescFlags::empty());
3673
3674        let (id, _) = consumer.poll_available().unwrap();
3675
3676        assert!(!consumer.submit_used_with_notify(id, 0).unwrap());
3677    }
3678
3679    #[test]
3680    fn p0018_pre_used_descriptor_is_ignored() {
3681        let ring = make_ring(8);
3682        let mut consumer = make_consumer(&ring);
3683
3684        let mut desc = raw_desc(0, 16, DescFlags::empty());
3685        desc.mark_used(true);
3686        ring.write_desc(0, desc);
3687
3688        assert!(matches!(
3689            consumer.poll_available(),
3690            Err(RingError::WouldBlock)
3691        ));
3692    }
3693
3694    #[test]
3695    fn p0019_driver_event_wrap_mismatch_suppresses_notification() {
3696        let ring = make_ring(8);
3697        let mut consumer = make_consumer(&ring);
3698
3699        write_driver_event(&ring, 1, EventFlags::DESC.bits());
3700        write_avail(&ring, 0, 0, DescFlags::empty());
3701
3702        let (id, _) = consumer.poll_available().unwrap();
3703
3704        assert!(!consumer.submit_used_with_notify(id, 0).unwrap());
3705    }
3706
3707    #[test]
3708    fn p0020_ring_full_reports_backpressure() {
3709        let ring = make_ring(4);
3710        let mut producer = make_producer(&ring);
3711
3712        for idx in 0..4 {
3713            producer.submit_one(0x1000 + idx * 0x10, 16, false).unwrap();
3714        }
3715
3716        assert!(matches!(
3717            producer.submit_one(0x2000, 16, false),
3718            Err(RingError::WouldBlock)
3719        ));
3720    }
3721
3722    #[test]
3723    fn p0022_indirect_reused_id_is_rejected_before_id_reuse() {
3724        let ring = make_ring(8);
3725        let mut consumer = make_consumer(&ring);
3726
3727        write_avail(&ring, 0, 0, DescFlags::INDIRECT);
3728        write_avail(&ring, 1, 0, DescFlags::empty());
3729
3730        assert!(matches!(
3731            consumer.poll_available(),
3732            Err(RingError::BadChain)
3733        ));
3734    }
3735
3736    #[test]
3737    fn p0023_desc_event_mode_suppresses_before_later_slot() {
3738        let ring = make_ring(8);
3739        let mut consumer = make_consumer(&ring);
3740
3741        write_driver_event(&ring, 0x8001, EventFlags::DESC.bits());
3742        write_avail(&ring, 0, 0, DescFlags::empty());
3743
3744        let (id, _) = consumer.poll_available().unwrap();
3745
3746        assert!(!consumer.submit_used_with_notify(id, 0).unwrap());
3747    }
3748
3749    #[test]
3750    fn p0024_single_slot_indirect_is_rejected() {
3751        let ring = make_ring(1);
3752        let mut consumer = make_consumer(&ring);
3753
3754        write_avail(&ring, 0, 0, DescFlags::INDIRECT);
3755
3756        assert!(matches!(
3757            consumer.poll_available(),
3758            Err(RingError::BadChain)
3759        ));
3760    }
3761
3762    #[test]
3763    fn p0025_used_completions_can_arrive_out_of_order() {
3764        let ring = make_ring(8);
3765        let mut producer = make_producer(&ring);
3766        let mut consumer = make_consumer(&ring);
3767
3768        let id0 = producer.submit_one(0x1000, 16, true).unwrap();
3769        let id1 = producer.submit_one(0x2000, 16, true).unwrap();
3770        let id2 = producer.submit_one(0x3000, 16, true).unwrap();
3771
3772        let (dev0, _) = consumer.poll_available().unwrap();
3773        let (dev1, _) = consumer.poll_available().unwrap();
3774        let (dev2, _) = consumer.poll_available().unwrap();
3775
3776        consumer.submit_used(dev2, 32).unwrap();
3777        consumer.submit_used(dev0, 16).unwrap();
3778        consumer.submit_used(dev1, 24).unwrap();
3779
3780        assert_eq!(producer.poll_used().unwrap().id, id2);
3781        assert_eq!(producer.poll_used().unwrap().id, id0);
3782        assert_eq!(producer.poll_used().unwrap().id, id1);
3783    }
3784
3785    #[test]
3786    fn p0026_all_descriptor_flags_set_is_not_available() {
3787        let ring = make_ring(8);
3788        let mut consumer = make_consumer(&ring);
3789
3790        ring.write_desc(0, raw_desc(0, 16, DescFlags::from_bits_truncate(u16::MAX)));
3791
3792        assert!(matches!(
3793            consumer.poll_available(),
3794            Err(RingError::WouldBlock)
3795        ));
3796    }
3797
3798    #[test]
3799    fn p0028_multi_wrap_round_trip_remains_ordered() {
3800        let ring = make_ring(2);
3801        let mut producer = make_producer(&ring);
3802        let mut consumer = make_consumer(&ring);
3803
3804        for idx in 0..8u64 {
3805            let id = producer.submit_one(0x1000 + idx * 0x10, 16, false).unwrap();
3806            let (dev_id, _) = consumer.poll_available().unwrap();
3807            assert_eq!(dev_id, id);
3808            consumer.submit_used(dev_id, idx as u32).unwrap();
3809            assert_eq!(producer.poll_used().unwrap().id, id);
3810        }
3811    }
3812
3813    #[test]
3814    fn p0029_desc_event_idx_zero_notifies() {
3815        let ring = make_ring(8);
3816        let mut consumer = make_consumer(&ring);
3817
3818        write_driver_event(&ring, 0x8000, EventFlags::DESC.bits());
3819        write_avail(&ring, 0, 0, DescFlags::empty());
3820
3821        let (id, _) = consumer.poll_available().unwrap();
3822
3823        assert!(consumer.submit_used_with_notify(id, 0).unwrap());
3824    }
3825
3826    #[test]
3827    fn p0031_reserved_driver_event_flags_suppress_notification() {
3828        let ring = make_ring(8);
3829        let mut consumer = make_consumer(&ring);
3830
3831        write_driver_event(&ring, 0, 3);
3832        write_avail(&ring, 0, 0, DescFlags::empty());
3833
3834        let (id, _) = consumer.poll_available().unwrap();
3835
3836        assert!(!consumer.submit_used_with_notify(id, 0).unwrap());
3837    }
3838
3839    #[test]
3840    fn p0032_unaligned_indirect_descriptor_is_rejected() {
3841        let ring = make_ring(8);
3842        let mut consumer = make_consumer(&ring);
3843
3844        let mut desc = Descriptor::new(0x1003, 16, 0, DescFlags::INDIRECT);
3845        desc.mark_avail(true);
3846        ring.write_desc(0, desc);
3847
3848        assert!(matches!(
3849            consumer.poll_available(),
3850            Err(RingError::BadChain)
3851        ));
3852    }
3853
3854    #[test]
3855    fn p0033_scatter_gather_chain_is_preserved() {
3856        let ring = make_ring(16);
3857        let mut consumer = make_consumer(&ring);
3858
3859        for idx in 0..8u16 {
3860            let flags = if idx == 7 {
3861                DescFlags::WRITE
3862            } else {
3863                DescFlags::NEXT
3864            };
3865            write_avail(&ring, idx, 0, flags);
3866        }
3867
3868        let (_, chain) = consumer.poll_available().unwrap();
3869        assert_eq!(chain.len(), 8);
3870        assert_eq!(chain.readables().len(), 7);
3871        assert_eq!(chain.writables().len(), 1);
3872    }
3873
3874    #[test]
3875    fn p0034_page_boundary_indirect_descriptor_is_rejected() {
3876        let ring = make_ring(8);
3877        let mut consumer = make_consumer(&ring);
3878
3879        let mut desc = Descriptor::new(0x1ff0, 16, 0, DescFlags::INDIRECT);
3880        desc.mark_avail(true);
3881        ring.write_desc(0, desc);
3882
3883        assert!(matches!(
3884            consumer.poll_available(),
3885            Err(RingError::BadChain)
3886        ));
3887    }
3888
3889    #[test]
3890    fn p0035_both_avail_and_used_clear_is_ignored() {
3891        let ring = make_ring(8);
3892        let mut consumer = make_consumer(&ring);
3893
3894        ring.write_desc(0, raw_desc(0, 16, DescFlags::empty()));
3895
3896        assert!(matches!(
3897            consumer.poll_available(),
3898            Err(RingError::WouldBlock)
3899        ));
3900    }
3901
3902    #[test]
3903    fn p0037_event_flags_can_cycle_between_batches() {
3904        let ring = make_ring(8);
3905        let mut consumer = make_consumer(&ring);
3906
3907        for (idx, (flags, expect_notify)) in [
3908            (EventFlags::ENABLE.bits(), true),
3909            (EventFlags::DISABLE.bits(), false),
3910            (EventFlags::ENABLE.bits(), true),
3911        ]
3912        .into_iter()
3913        .enumerate()
3914        {
3915            write_driver_event(&ring, 0, flags);
3916            write_avail(&ring, idx as u16, idx as u16, DescFlags::empty());
3917            let (id, _) = consumer.poll_available().unwrap();
3918            assert_eq!(
3919                consumer.submit_used_with_notify(id, 0).unwrap(),
3920                expect_notify
3921            );
3922        }
3923    }
3924
3925    #[test]
3926    fn p0038_many_wraps_on_minimum_queue_size() {
3927        let ring = make_ring(1);
3928        let mut producer = make_producer(&ring);
3929        let mut consumer = make_consumer(&ring);
3930
3931        for idx in 0..8u64 {
3932            let id = producer.submit_one(0x1000 + idx * 0x10, 16, false).unwrap();
3933            let (dev_id, _) = consumer.poll_available().unwrap();
3934            assert_eq!(dev_id, id);
3935            consumer.submit_used(dev_id, 0).unwrap();
3936            assert_eq!(producer.poll_used().unwrap().id, id);
3937        }
3938    }
3939
3940    #[test]
3941    fn p0039_reserved_device_event_flags_suppress_avail_notification() {
3942        let ring = make_ring(8);
3943        let mut producer = make_producer(&ring);
3944
3945        write_device_event(&ring, 0, 3);
3946
3947        assert!(
3948            !producer
3949                .submit_one_with_notify(0x1000, 16, false)
3950                .unwrap()
3951                .notify
3952        );
3953    }
3954
3955    #[test]
3956    fn p0040_indirect_with_next_is_rejected() {
3957        let ring = make_ring(8);
3958        let mut consumer = make_consumer(&ring);
3959
3960        write_avail(&ring, 0, 0, DescFlags::INDIRECT | DescFlags::NEXT);
3961
3962        assert!(matches!(
3963            consumer.poll_available(),
3964            Err(RingError::BadChain)
3965        ));
3966    }
3967
3968    #[test]
3969    fn p0041_driver_event_offset_at_queue_size_suppresses_notification() {
3970        let ring = make_ring(8);
3971        let mut consumer = make_consumer(&ring);
3972
3973        write_driver_event(&ring, ring.len() as u16, EventFlags::DESC.bits());
3974        write_avail(&ring, 0, 0, DescFlags::empty());
3975
3976        let (id, _) = consumer.poll_available().unwrap();
3977
3978        assert!(!consumer.submit_used_with_notify(id, 0).unwrap());
3979    }
3980
3981    #[test]
3982    fn p0042_empty_ring_has_no_available_work() {
3983        let ring = make_ring(8);
3984        let mut consumer = make_consumer(&ring);
3985
3986        assert!(matches!(
3987            consumer.poll_available(),
3988            Err(RingError::WouldBlock)
3989        ));
3990    }
3991
3992    #[test]
3993    fn p0043_id_equal_to_queue_size_is_rejected() {
3994        let ring = make_ring(8);
3995        let mut consumer = make_consumer(&ring);
3996
3997        write_avail(&ring, 0, ring.len() as u16, DescFlags::empty());
3998
3999        assert!(matches!(
4000            consumer.poll_available(),
4001            Err(RingError::InvalidState)
4002        ));
4003    }
4004
4005    #[test]
4006    fn p0044_avail_and_used_set_is_not_available() {
4007        let ring = make_ring(8);
4008        let mut consumer = make_consumer(&ring);
4009
4010        ring.write_desc(0, raw_desc(0, 16, DescFlags::AVAIL | DescFlags::USED));
4011
4012        assert!(!consumer.peek_available().unwrap());
4013        assert!(matches!(
4014            consumer.poll_available(),
4015            Err(RingError::WouldBlock)
4016        ));
4017    }
4018
4019    #[test]
4020    fn p0045_zero_length_descriptor_is_consumable() {
4021        let ring = make_ring(8);
4022        let mut consumer = make_consumer(&ring);
4023
4024        write_avail_len(&ring, 0, 0, 0, DescFlags::WRITE);
4025
4026        let (id, chain) = consumer.poll_available().unwrap();
4027        assert_eq!(id, 0);
4028        assert_eq!(chain.writables()[0].len, 0);
4029    }
4030
4031    #[test]
4032    fn p0046_max_length_descriptor_is_consumable_at_ring_layer() {
4033        let ring = make_ring(8);
4034        let mut consumer = make_consumer(&ring);
4035
4036        write_avail_len(&ring, 0, 0, u32::MAX, DescFlags::WRITE);
4037
4038        let (id, chain) = consumer.poll_available().unwrap();
4039        assert_eq!(id, 0);
4040        assert_eq!(chain.writables()[0].len, u32::MAX);
4041    }
4042
4043    #[test]
4044    fn p0047_zero_descriptor_address_is_preserved_at_ring_layer() {
4045        let ring = make_ring(8);
4046        let mut consumer = make_consumer(&ring);
4047
4048        let mut desc = Descriptor::new(0, 16, 0, DescFlags::WRITE);
4049        desc.mark_avail(true);
4050        ring.write_desc(0, desc);
4051
4052        let (id, chain) = consumer.poll_available().unwrap();
4053        assert_eq!(id, 0);
4054        assert_eq!(chain.writables()[0].addr, 0);
4055    }
4056
4057    #[test]
4058    fn p0049_indirect_entry_with_phase_bits_is_rejected() {
4059        let ring = make_ring(8);
4060        let mut consumer = make_consumer(&ring);
4061
4062        ring.write_desc(
4063            0,
4064            raw_desc(
4065                0,
4066                16,
4067                DescFlags::INDIRECT | DescFlags::AVAIL | DescFlags::USED,
4068            ),
4069        );
4070
4071        assert!(matches!(
4072            consumer.poll_available(),
4073            Err(RingError::WouldBlock)
4074        ));
4075    }
4076
4077    #[test]
4078    fn p0050_nested_indirect_is_rejected_at_head() {
4079        let ring = make_ring(8);
4080        let mut consumer = make_consumer(&ring);
4081
4082        write_avail(&ring, 0, 0, DescFlags::INDIRECT);
4083
4084        assert!(matches!(
4085            consumer.poll_available(),
4086            Err(RingError::BadChain)
4087        ));
4088    }
4089
4090    #[test]
4091    fn p0051_write_flag_controls_readable_writable_split() {
4092        let ring = make_ring(8);
4093        let mut consumer = make_consumer(&ring);
4094
4095        write_avail(&ring, 0, 0, DescFlags::NEXT);
4096        write_avail(&ring, 1, 0, DescFlags::WRITE);
4097
4098        let (_, chain) = consumer.poll_available().unwrap();
4099        assert_eq!(chain.readables().len(), 1);
4100        assert_eq!(chain.writables().len(), 1);
4101    }
4102
4103    #[test]
4104    fn p0052_batch_completion_signals_each_chain_head() {
4105        let ring = make_ring(8);
4106        let mut producer = make_producer(&ring);
4107        let mut consumer = make_consumer(&ring);
4108
4109        let id0 = producer.submit_one(0x1000, 16, true).unwrap();
4110        let id1 = producer.submit_one(0x2000, 16, true).unwrap();
4111
4112        let (dev0, _) = consumer.poll_available().unwrap();
4113        let (dev1, _) = consumer.poll_available().unwrap();
4114        consumer.submit_used(dev0, 16).unwrap();
4115        consumer.submit_used(dev1, 32).unwrap();
4116
4117        assert_eq!(producer.poll_used().unwrap().id, id0);
4118        assert_eq!(producer.poll_used().unwrap().id, id1);
4119    }
4120
4121    #[test]
4122    fn p0053_descriptor_without_avail_bit_is_ignored() {
4123        let ring = make_ring(8);
4124        let mut consumer = make_consumer(&ring);
4125
4126        ring.write_desc(0, raw_desc(0, 16, DescFlags::WRITE));
4127
4128        assert!(!consumer.peek_available().unwrap());
4129        assert!(matches!(
4130            consumer.poll_available(),
4131            Err(RingError::WouldBlock)
4132        ));
4133    }
4134
4135    #[test]
4136    fn p0054_event_suppression_struct_layout_matches_packed_ring() {
4137        assert_eq!(EventSuppression::SIZE, 4);
4138        assert_eq!(EventSuppression::WRAP_OFFSET, 0);
4139        assert_eq!(EventSuppression::FLAGS_OFFSET, 2);
4140    }
4141
4142    #[test]
4143    fn p0055_descriptor_after_chain_tail_is_ignored() {
4144        let ring = make_ring(8);
4145        let mut consumer = make_consumer(&ring);
4146
4147        write_avail(&ring, 0, 0, DescFlags::empty());
4148        write_avail(&ring, 1, 1, DescFlags::WRITE);
4149
4150        let (id, chain) = consumer.poll_available().unwrap();
4151        assert_eq!(id, 0);
4152        assert_eq!(chain.len(), 1);
4153    }
4154
4155    #[test]
4156    fn p0056_next_chain_order_is_preserved() {
4157        let ring = make_ring(8);
4158        let mut consumer = make_consumer(&ring);
4159
4160        for idx in 0..3u16 {
4161            let mut desc = Descriptor::new(
4162                0x1000 + u64::from(idx) * 0x100,
4163                16,
4164                0,
4165                if idx == 2 {
4166                    DescFlags::WRITE
4167                } else {
4168                    DescFlags::NEXT
4169                },
4170            );
4171            desc.mark_avail(true);
4172            ring.write_desc(idx, desc);
4173        }
4174
4175        let (_, chain) = consumer.poll_available().unwrap();
4176        assert_eq!(chain.elems()[0].addr, 0x1000);
4177        assert_eq!(chain.elems()[1].addr, 0x1100);
4178        assert_eq!(chain.elems()[2].addr, 0x1200);
4179    }
4180
4181    #[test]
4182    fn p0057_device_event_enable_requests_avail_notification() {
4183        let ring = make_ring(8);
4184        let mut producer = make_producer(&ring);
4185
4186        write_device_event(&ring, 0, EventFlags::ENABLE.bits());
4187
4188        assert!(
4189            producer
4190                .submit_one_with_notify(0x1000, 16, false)
4191                .unwrap()
4192                .notify
4193        );
4194    }
4195
4196    #[test]
4197    fn p0058_used_descriptor_carries_id_and_len() {
4198        let ring = make_ring(8);
4199        let mut producer = make_producer(&ring);
4200        let mut consumer = make_consumer(&ring);
4201
4202        let id = producer.submit_one(0x1000, 16, true).unwrap();
4203        let (dev_id, _) = consumer.poll_available().unwrap();
4204        consumer.submit_used(dev_id, 42).unwrap();
4205
4206        let used = producer.poll_used().unwrap();
4207        assert_eq!(used.id, id);
4208        assert_eq!(used.len, 42);
4209    }
4210}
4211
4212#[cfg(test)]
4213mod fuzz {
4214    use quickcheck::{Arbitrary, Gen, QuickCheck};
4215
4216    use super::tests::{OwnedRing, make_consumer, make_producer};
4217    use super::*;
4218
4219    const MAX_RING: usize = 64;
4220    const MAX_OPS: usize = 128;
4221    const MAX_CHAIN_LEN: usize = 8;
4222
4223    #[allow(clippy::large_enum_variant)]
4224    #[derive(Clone, Debug)]
4225    enum Op {
4226        /// submit one chain
4227        Submit(BufferChain),
4228        /// poll up to N chains
4229        PollAvail(u8),
4230        /// driver reclaims up to N completions
4231        PollUsed(u8),
4232        /// complete one previously polled chain
4233        CompleteOne,
4234    }
4235
4236    impl Arbitrary for Op {
4237        fn arbitrary(g: &mut Gen) -> Self {
4238            let choice = u8::arbitrary(g) % 4;
4239            match choice {
4240                0 => Op::Submit(BufferChain::arbitrary(g)),
4241                1 => Op::PollAvail(u8::arbitrary(g) % 8 + 1),
4242                2 => Op::PollUsed(u8::arbitrary(g) % 8 + 1),
4243                3 => Op::CompleteOne,
4244                _ => unreachable!(),
4245            }
4246        }
4247    }
4248
4249    #[derive(Clone, Debug)]
4250    struct Scenario {
4251        table_size: usize,
4252        ops: Vec<Op>,
4253    }
4254
4255    impl Arbitrary for Scenario {
4256        fn arbitrary(g: &mut Gen) -> Self {
4257            let table_size = (usize::arbitrary(g) % MAX_RING + 1).next_power_of_two();
4258            let num_ops = usize::arbitrary(g) % MAX_OPS + 1;
4259
4260            let ops = (0..num_ops).map(|_| Op::arbitrary(g)).collect();
4261            Scenario { table_size, ops }
4262        }
4263    }
4264
4265    impl Arbitrary for BufferElement {
4266        fn arbitrary(g: &mut Gen) -> Self {
4267            let addr = u64::arbitrary(g);
4268            let len = u32::arbitrary(g);
4269            let writable = bool::arbitrary(g);
4270
4271            BufferElement {
4272                addr,
4273                len,
4274                writable,
4275            }
4276        }
4277    }
4278
4279    impl Arbitrary for BufferChain {
4280        fn arbitrary(g: &mut Gen) -> Self {
4281            let chain_len = usize::arbitrary(g) % MAX_CHAIN_LEN + 1;
4282
4283            let mut elems = vec![BufferElement::zeroed(); chain_len];
4284            let mut readables = 0;
4285            let mut writables = 0;
4286
4287            for _ in 0..chain_len {
4288                let elem = BufferElement::arbitrary(g);
4289                if elem.writable {
4290                    elems[chain_len - 1 - writables] = elem;
4291                    writables += 1;
4292                } else {
4293                    elems[readables] = elem;
4294                    readables += 1;
4295                }
4296            }
4297
4298            BufferChain {
4299                elems: elems.into(),
4300                split: readables,
4301            }
4302        }
4303    }
4304
4305    fn run_scenario(s: Scenario) -> bool {
4306        let ring = OwnedRing::new(s.table_size);
4307        let mut producer = make_producer(&ring);
4308        let mut consumer = make_consumer(&ring);
4309
4310        // Order logs
4311        let mut dev_order: Vec<u16> = Vec::new();
4312        let mut drv_order: Vec<u16> = Vec::new();
4313
4314        // Device-tracked polled-but-not-completed IDs
4315        let mut dev_ready: Vec<(u16, u32)> = Vec::new();
4316
4317        for op in &s.ops {
4318            match op {
4319                Op::Submit(chain) => {
4320                    // Submit only if space; otherwise skip
4321                    let _ = producer.submit_available(chain);
4322                }
4323                Op::PollAvail(n) => {
4324                    for _ in 0..*n {
4325                        if let Ok((id, chain)) = consumer.poll_available() {
4326                            dev_ready.push((id, chain.len() as u32));
4327                        } else {
4328                            break;
4329                        }
4330                    }
4331                }
4332                Op::PollUsed(n) => {
4333                    for _ in 0..*n {
4334                        match producer.poll_used() {
4335                            Ok(u) => {
4336                                drv_order.push(u.id);
4337                                if producer.id_num[u.id as usize] != 0 {
4338                                    return false;
4339                                }
4340                                if !producer.id_free.contains(&u.id) {
4341                                    return false;
4342                                }
4343                            }
4344                            Err(RingError::WouldBlock) => break,
4345                            Err(_) => return false,
4346                        }
4347                    }
4348                }
4349                Op::CompleteOne => {
4350                    if let Some((id, len)) = dev_ready.pop() {
4351                        if consumer.submit_used(id, len).is_err() {
4352                            return false;
4353                        }
4354
4355                        dev_order.push(id);
4356                    }
4357                }
4358            }
4359
4360            // assert invariants after each op
4361            let outstanding: u16 = producer.id_num.iter().copied().sum();
4362            if outstanding as usize + producer.num_free != ring.len() {
4363                return false;
4364            }
4365
4366            for id in producer.id_free.iter() {
4367                if producer.id_num[*id as usize] != 0 {
4368                    return false;
4369                }
4370            }
4371        }
4372
4373        // Drain remaining completions and reclaims
4374        while let Some((id, len)) = dev_ready.pop() {
4375            if consumer.submit_used(id, len).is_err() {
4376                return false;
4377            }
4378        }
4379
4380        loop {
4381            match producer.poll_used() {
4382                Ok(u) => drv_order.push(u.id),
4383                Err(RingError::WouldBlock) => break,
4384                Err(_) => return false,
4385            }
4386        }
4387
4388        true
4389    }
4390
4391    #[test]
4392    fn prop_interleaved_with_order_verification() {
4393        #[cfg(miri)]
4394        let tests = 1;
4395        #[cfg(not(miri))]
4396        let tests = 100;
4397
4398        QuickCheck::new()
4399            .tests(tests)
4400            .quickcheck(run_scenario as fn(Scenario) -> bool);
4401    }
4402}