Skip to main content

hyperlight_common/virtq/
ring.rs

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