Skip to main content

arcbox_virtio/
queue.rs

1//! `VirtIO` queue (virtqueue) implementation.
2//!
3//! This module provides the core virtqueue data structures used for
4//! communication between the guest driver and host device.
5
6use crate::error::{Result, VirtioError};
7
8/// Descriptor flags.
9pub mod flags {
10    /// Descriptor continues via next field.
11    pub const NEXT: u16 = 1;
12    /// Buffer is write-only (for device).
13    pub const WRITE: u16 = 2;
14    /// Buffer contains a list of descriptors.
15    pub const INDIRECT: u16 = 4;
16}
17
18/// A single descriptor in the descriptor table.
19#[derive(Debug, Clone, Copy, Default)]
20#[repr(C)]
21pub struct Descriptor {
22    /// Guest physical address of the buffer.
23    pub addr: u64,
24    /// Length of the buffer.
25    pub len: u32,
26    /// Descriptor flags.
27    pub flags: u16,
28    /// Next descriptor index (if NEXT flag is set).
29    pub next: u16,
30}
31
32impl Descriptor {
33    /// Checks if this descriptor has the NEXT flag.
34    #[must_use]
35    pub const fn has_next(&self) -> bool {
36        self.flags & flags::NEXT != 0
37    }
38
39    /// Checks if this descriptor is write-only.
40    #[must_use]
41    pub const fn is_write_only(&self) -> bool {
42        self.flags & flags::WRITE != 0
43    }
44
45    /// Checks if this descriptor is indirect.
46    #[must_use]
47    pub const fn is_indirect(&self) -> bool {
48        self.flags & flags::INDIRECT != 0
49    }
50}
51
52/// Available ring structure.
53#[derive(Debug)]
54pub struct AvailRing {
55    /// Flags (e.g., no interrupt).
56    pub flags: u16,
57    /// Index of the next entry to add.
58    pub idx: u16,
59    /// Ring of descriptor indices.
60    pub ring: Vec<u16>,
61    /// Used event (for event suppression).
62    pub used_event: u16,
63}
64
65impl AvailRing {
66    /// Creates a new available ring.
67    #[must_use]
68    pub fn new(size: u16) -> Self {
69        Self {
70            flags: 0,
71            idx: 0,
72            ring: vec![0; size as usize],
73            used_event: 0,
74        }
75    }
76}
77
78/// Used ring element.
79#[derive(Debug, Clone, Copy, Default)]
80#[repr(C)]
81pub struct UsedElement {
82    /// Descriptor chain head index.
83    pub id: u32,
84    /// Number of bytes written to the descriptor chain.
85    pub len: u32,
86}
87
88/// Used ring structure.
89#[derive(Debug)]
90pub struct UsedRing {
91    /// Flags (e.g., no notify).
92    pub flags: u16,
93    /// Index of the next entry to add.
94    pub idx: u16,
95    /// Ring of used elements.
96    pub ring: Vec<UsedElement>,
97    /// Avail event (for event suppression).
98    pub avail_event: u16,
99}
100
101impl UsedRing {
102    /// Creates a new used ring.
103    #[must_use]
104    pub fn new(size: u16) -> Self {
105        Self {
106            flags: 0,
107            idx: 0,
108            ring: vec![UsedElement::default(); size as usize],
109            avail_event: 0,
110        }
111    }
112}
113
114/// `VirtIO` queue implementation.
115#[derive(Debug)]
116pub struct VirtQueue {
117    /// Queue size (number of descriptors).
118    size: u16,
119    /// Descriptor table.
120    desc_table: Vec<Descriptor>,
121    /// Available ring.
122    avail: AvailRing,
123    /// Used ring.
124    used: UsedRing,
125    /// Last seen available index.
126    last_avail_idx: u16,
127    /// Whether the queue is ready.
128    ready: bool,
129}
130
131impl VirtQueue {
132    /// Creates a new virtqueue with the given size.
133    ///
134    /// # Errors
135    ///
136    /// Returns an error if the size is not a power of 2 or exceeds limits.
137    pub fn new(size: u16) -> Result<Self> {
138        if size == 0 || !size.is_power_of_two() {
139            return Err(VirtioError::InvalidQueue(
140                "size must be a power of 2".to_string(),
141            ));
142        }
143
144        if size > 32768 {
145            return Err(VirtioError::InvalidQueue(
146                "size must not exceed 32768".to_string(),
147            ));
148        }
149
150        Ok(Self {
151            size,
152            desc_table: vec![Descriptor::default(); size as usize],
153            avail: AvailRing::new(size),
154            used: UsedRing::new(size),
155            last_avail_idx: 0,
156            ready: false,
157        })
158    }
159
160    /// Returns the queue size.
161    #[must_use]
162    pub const fn size(&self) -> u16 {
163        self.size
164    }
165
166    /// Returns whether the queue is ready.
167    #[must_use]
168    pub const fn is_ready(&self) -> bool {
169        self.ready
170    }
171
172    /// Sets the queue ready state.
173    pub const fn set_ready(&mut self, ready: bool) {
174        self.ready = ready;
175    }
176
177    /// Updates a descriptor entry.
178    ///
179    /// # Errors
180    ///
181    /// Returns an error if the index is out of range.
182    pub fn set_descriptor(&mut self, idx: u16, descriptor: Descriptor) -> Result<()> {
183        if idx >= self.size {
184            return Err(VirtioError::InvalidQueue(
185                "descriptor index out of bounds".to_string(),
186            ));
187        }
188
189        self.desc_table[idx as usize] = descriptor;
190        Ok(())
191    }
192
193    /// Adds a descriptor chain head to the available ring.
194    ///
195    /// # Errors
196    ///
197    /// Returns an error if the descriptor index is out of range.
198    pub fn add_avail(&mut self, head_idx: u16) -> Result<()> {
199        if head_idx >= self.size {
200            return Err(VirtioError::InvalidQueue(
201                "available index out of bounds".to_string(),
202            ));
203        }
204
205        let ring_idx = (self.avail.idx % self.size) as usize;
206        self.avail.ring[ring_idx] = head_idx;
207        self.avail.idx = self.avail.idx.wrapping_add(1);
208        Ok(())
209    }
210
211    /// Checks if there are available descriptors.
212    #[must_use]
213    pub const fn has_available(&self) -> bool {
214        self.avail.idx != self.last_avail_idx
215    }
216
217    /// Pops the next available descriptor chain.
218    ///
219    /// Returns the head descriptor index and the descriptor chain.
220    pub fn pop_avail(&mut self) -> Option<(u16, DescriptorChain)> {
221        if !self.has_available() {
222            return None;
223        }
224
225        let avail_idx = self.last_avail_idx;
226        let head_idx = self.avail.ring[(avail_idx % self.size) as usize];
227        self.last_avail_idx = self.last_avail_idx.wrapping_add(1);
228
229        Some((
230            head_idx,
231            DescriptorChain {
232                queue: self,
233                current: Some(head_idx),
234            },
235        ))
236    }
237
238    /// Adds a used descriptor to the used ring.
239    pub fn push_used(&mut self, head_idx: u16, len: u32) {
240        let used_idx = self.used.idx;
241        self.used.ring[(used_idx % self.size) as usize] = UsedElement {
242            id: head_idx as u32,
243            len,
244        };
245        self.used.idx = self.used.idx.wrapping_add(1);
246    }
247
248    /// Returns a reference to a descriptor.
249    #[must_use]
250    pub fn get_descriptor(&self, idx: u16) -> Option<&Descriptor> {
251        self.desc_table.get(idx as usize)
252    }
253}
254
255/// Iterator over a descriptor chain.
256pub struct DescriptorChain<'a> {
257    queue: &'a VirtQueue,
258    current: Option<u16>,
259}
260
261impl<'a> Iterator for DescriptorChain<'a> {
262    type Item = &'a Descriptor;
263
264    fn next(&mut self) -> Option<Self::Item> {
265        let idx = self.current?;
266        let desc = self.queue.get_descriptor(idx)?;
267
268        self.current = if desc.has_next() {
269            Some(desc.next)
270        } else {
271            None
272        };
273
274        Some(desc)
275    }
276}
277
278#[cfg(test)]
279mod tests {
280    use super::*;
281
282    // ==========================================================================
283    // Descriptor Tests
284    // ==========================================================================
285
286    #[test]
287    fn test_descriptor_default() {
288        let desc = Descriptor::default();
289        assert_eq!(desc.addr, 0);
290        assert_eq!(desc.len, 0);
291        assert_eq!(desc.flags, 0);
292        assert_eq!(desc.next, 0);
293    }
294
295    #[test]
296    fn test_descriptor_has_next() {
297        let mut desc = Descriptor::default();
298        assert!(!desc.has_next());
299
300        desc.flags = flags::NEXT;
301        assert!(desc.has_next());
302    }
303
304    #[test]
305    fn test_descriptor_is_write_only() {
306        let mut desc = Descriptor::default();
307        assert!(!desc.is_write_only());
308
309        desc.flags = flags::WRITE;
310        assert!(desc.is_write_only());
311    }
312
313    #[test]
314    fn test_descriptor_is_indirect() {
315        let mut desc = Descriptor::default();
316        assert!(!desc.is_indirect());
317
318        desc.flags = flags::INDIRECT;
319        assert!(desc.is_indirect());
320    }
321
322    #[test]
323    fn test_descriptor_multiple_flags() {
324        let desc = Descriptor {
325            addr: 0x1000,
326            len: 512,
327            flags: flags::NEXT | flags::WRITE,
328            next: 1,
329        };
330
331        assert!(desc.has_next());
332        assert!(desc.is_write_only());
333        assert!(!desc.is_indirect());
334    }
335
336    #[test]
337    fn test_descriptor_clone_copy() {
338        let desc = Descriptor {
339            addr: 0xDEADBEEF,
340            len: 1234,
341            flags: flags::NEXT,
342            next: 42,
343        };
344
345        let cloned = desc.clone();
346        let copied = desc; // Copy
347
348        assert_eq!(cloned.addr, 0xDEADBEEF);
349        assert_eq!(copied.addr, 0xDEADBEEF);
350    }
351
352    // ==========================================================================
353    // Flag Constants Tests
354    // ==========================================================================
355
356    #[test]
357    fn test_flag_constants() {
358        assert_eq!(flags::NEXT, 1);
359        assert_eq!(flags::WRITE, 2);
360        assert_eq!(flags::INDIRECT, 4);
361    }
362
363    // ==========================================================================
364    // AvailRing Tests
365    // ==========================================================================
366
367    #[test]
368    fn test_avail_ring_new() {
369        let ring = AvailRing::new(256);
370        assert_eq!(ring.flags, 0);
371        assert_eq!(ring.idx, 0);
372        assert_eq!(ring.ring.len(), 256);
373        assert_eq!(ring.used_event, 0);
374    }
375
376    #[test]
377    fn test_avail_ring_small() {
378        let ring = AvailRing::new(1);
379        assert_eq!(ring.ring.len(), 1);
380    }
381
382    // ==========================================================================
383    // UsedElement Tests
384    // ==========================================================================
385
386    #[test]
387    fn test_used_element_default() {
388        let elem = UsedElement::default();
389        assert_eq!(elem.id, 0);
390        assert_eq!(elem.len, 0);
391    }
392
393    #[test]
394    fn test_used_element_clone_copy() {
395        let elem = UsedElement { id: 42, len: 1024 };
396        let cloned = elem.clone();
397        let copied = elem; // Copy
398
399        assert_eq!(cloned.id, 42);
400        assert_eq!(copied.len, 1024);
401    }
402
403    // ==========================================================================
404    // UsedRing Tests
405    // ==========================================================================
406
407    #[test]
408    fn test_used_ring_new() {
409        let ring = UsedRing::new(128);
410        assert_eq!(ring.flags, 0);
411        assert_eq!(ring.idx, 0);
412        assert_eq!(ring.ring.len(), 128);
413        assert_eq!(ring.avail_event, 0);
414    }
415
416    // ==========================================================================
417    // VirtQueue Tests
418    // ==========================================================================
419
420    #[test]
421    fn test_virtqueue_new() {
422        let queue = VirtQueue::new(256).unwrap();
423        assert_eq!(queue.size(), 256);
424        assert!(!queue.is_ready());
425    }
426
427    #[test]
428    fn test_virtqueue_new_power_of_two() {
429        // Valid sizes
430        for size in [1, 2, 4, 8, 16, 32, 64, 128, 256, 512, 1024] {
431            assert!(VirtQueue::new(size).is_ok());
432        }
433    }
434
435    #[test]
436    fn test_virtqueue_new_invalid_size_zero() {
437        let result = VirtQueue::new(0);
438        assert!(result.is_err());
439        if let Err(VirtioError::InvalidQueue(msg)) = result {
440            assert!(msg.contains("power of 2"));
441        }
442    }
443
444    #[test]
445    fn test_virtqueue_new_invalid_size_not_power_of_two() {
446        for size in [3, 5, 6, 7, 9, 100, 1000] {
447            let result = VirtQueue::new(size);
448            assert!(result.is_err());
449        }
450    }
451
452    #[test]
453    fn test_virtqueue_new_too_large() {
454        let result = VirtQueue::new(32768); // Max allowed
455        assert!(result.is_ok());
456
457        // This would need 65536 which exceeds u16 anyway
458        // Just test max size works
459    }
460
461    #[test]
462    fn test_virtqueue_ready_state() {
463        let mut queue = VirtQueue::new(16).unwrap();
464
465        assert!(!queue.is_ready());
466        queue.set_ready(true);
467        assert!(queue.is_ready());
468        queue.set_ready(false);
469        assert!(!queue.is_ready());
470    }
471
472    #[test]
473    fn test_virtqueue_has_available_empty() {
474        let queue = VirtQueue::new(16).unwrap();
475        assert!(!queue.has_available());
476    }
477
478    #[test]
479    fn test_virtqueue_pop_avail_empty() {
480        let mut queue = VirtQueue::new(16).unwrap();
481        assert!(queue.pop_avail().is_none());
482    }
483
484    #[test]
485    fn test_virtqueue_get_descriptor() {
486        let queue = VirtQueue::new(16).unwrap();
487
488        // Valid indices
489        assert!(queue.get_descriptor(0).is_some());
490        assert!(queue.get_descriptor(15).is_some());
491
492        // Invalid indices
493        assert!(queue.get_descriptor(16).is_none());
494        assert!(queue.get_descriptor(100).is_none());
495    }
496
497    #[test]
498    fn test_virtqueue_push_used() {
499        let mut queue = VirtQueue::new(16).unwrap();
500
501        queue.push_used(0, 512);
502        assert_eq!(queue.used.idx, 1);
503        assert_eq!(queue.used.ring[0].id, 0);
504        assert_eq!(queue.used.ring[0].len, 512);
505
506        queue.push_used(1, 1024);
507        assert_eq!(queue.used.idx, 2);
508        assert_eq!(queue.used.ring[1].id, 1);
509        assert_eq!(queue.used.ring[1].len, 1024);
510    }
511
512    #[test]
513    fn test_virtqueue_push_used_wrap() {
514        let mut queue = VirtQueue::new(4).unwrap();
515
516        // Push more than queue size to test wrapping
517        for i in 0..10 {
518            queue.push_used(i, i as u32 * 100);
519        }
520
521        assert_eq!(queue.used.idx, 10);
522        // Ring index wraps: 10 % 4 = 2, so last entry is at index 1
523        assert_eq!(queue.used.ring[1].id, 9);
524    }
525
526    #[test]
527    fn test_virtqueue_simulated_transaction() {
528        let mut queue = VirtQueue::new(16).unwrap();
529        queue.set_ready(true);
530
531        // Simulate guest adding a descriptor to available ring
532        queue.avail.ring[0] = 0; // Descriptor index 0
533        queue.avail.idx = 1;
534
535        // Device should see available descriptor
536        assert!(queue.has_available());
537
538        // Pop the descriptor
539        let (head_idx, _chain) = queue.pop_avail().unwrap();
540        assert_eq!(head_idx, 0);
541
542        // No more available
543        assert!(!queue.has_available());
544
545        // Device adds to used ring
546        queue.push_used(head_idx, 256);
547        assert_eq!(queue.used.idx, 1);
548    }
549
550    #[test]
551    fn test_virtqueue_multiple_descriptors() {
552        let mut queue = VirtQueue::new(16).unwrap();
553        queue.set_ready(true);
554
555        // Add multiple descriptors to available ring
556        for i in 0..5 {
557            queue.avail.ring[i] = i as u16;
558        }
559        queue.avail.idx = 5;
560
561        // Pop all
562        for i in 0..5 {
563            assert!(queue.has_available());
564            let (head_idx, _) = queue.pop_avail().unwrap();
565            assert_eq!(head_idx, i as u16);
566        }
567
568        assert!(!queue.has_available());
569    }
570
571    // ==========================================================================
572    // DescriptorChain Tests
573    // ==========================================================================
574
575    #[test]
576    fn test_descriptor_chain_single() {
577        let mut queue = VirtQueue::new(16).unwrap();
578
579        // Set up a single descriptor (no chain)
580        queue.desc_table[0] = Descriptor {
581            addr: 0x1000,
582            len: 512,
583            flags: 0, // No NEXT flag
584            next: 0,
585        };
586
587        queue.avail.ring[0] = 0;
588        queue.avail.idx = 1;
589
590        let (head_idx, chain) = queue.pop_avail().unwrap();
591        assert_eq!(head_idx, 0);
592
593        let descs: Vec<_> = chain.collect();
594        assert_eq!(descs.len(), 1);
595        assert_eq!(descs[0].addr, 0x1000);
596        assert_eq!(descs[0].len, 512);
597    }
598
599    #[test]
600    fn test_descriptor_chain_multiple() {
601        let mut queue = VirtQueue::new(16).unwrap();
602
603        // Set up a chain: 0 -> 1 -> 2
604        queue.desc_table[0] = Descriptor {
605            addr: 0x1000,
606            len: 256,
607            flags: flags::NEXT,
608            next: 1,
609        };
610        queue.desc_table[1] = Descriptor {
611            addr: 0x2000,
612            len: 512,
613            flags: flags::NEXT,
614            next: 2,
615        };
616        queue.desc_table[2] = Descriptor {
617            addr: 0x3000,
618            len: 1024,
619            flags: 0, // End of chain
620            next: 0,
621        };
622
623        queue.avail.ring[0] = 0;
624        queue.avail.idx = 1;
625
626        let (_, chain) = queue.pop_avail().unwrap();
627        let descs: Vec<_> = chain.collect();
628
629        assert_eq!(descs.len(), 3);
630        assert_eq!(descs[0].addr, 0x1000);
631        assert_eq!(descs[1].addr, 0x2000);
632        assert_eq!(descs[2].addr, 0x3000);
633    }
634
635    #[test]
636    fn test_descriptor_chain_with_write_flags() {
637        let mut queue = VirtQueue::new(16).unwrap();
638
639        // Set up: read buffer -> write buffer
640        queue.desc_table[0] = Descriptor {
641            addr: 0x1000,
642            len: 256,
643            flags: flags::NEXT, // Read-only for device
644            next: 1,
645        };
646        queue.desc_table[1] = Descriptor {
647            addr: 0x2000,
648            len: 512,
649            flags: flags::WRITE, // Write-only for device
650            next: 0,
651        };
652
653        queue.avail.ring[0] = 0;
654        queue.avail.idx = 1;
655
656        let (_, chain) = queue.pop_avail().unwrap();
657        let descs: Vec<_> = chain.collect();
658
659        assert_eq!(descs.len(), 2);
660        assert!(!descs[0].is_write_only());
661        assert!(descs[1].is_write_only());
662    }
663
664    // ==========================================================================
665    // Edge Case Tests
666    // ==========================================================================
667
668    #[test]
669    fn test_avail_idx_wrap() {
670        let mut queue = VirtQueue::new(4).unwrap();
671
672        // Simulate wrapping of avail.idx
673        queue.avail.idx = u16::MAX;
674        queue.last_avail_idx = u16::MAX - 1;
675        queue.avail.ring[(queue.last_avail_idx % 4) as usize] = 0;
676
677        assert!(queue.has_available());
678
679        let (head_idx, _) = queue.pop_avail().unwrap();
680        assert_eq!(head_idx, 0);
681        assert_eq!(queue.last_avail_idx, u16::MAX);
682
683        // Add one more
684        queue.avail.ring[(queue.avail.idx % 4) as usize] = 1;
685        queue.avail.idx = 0; // Wraps
686
687        assert!(queue.has_available());
688        let (head_idx, _) = queue.pop_avail().unwrap();
689        assert_eq!(head_idx, 1);
690    }
691
692    #[test]
693    fn test_used_idx_wrap() {
694        let mut queue = VirtQueue::new(4).unwrap();
695        queue.used.idx = u16::MAX;
696
697        queue.push_used(0, 100);
698        assert_eq!(queue.used.idx, 0); // Wrapped
699
700        // Value should be at index (u16::MAX % 4) = 3
701        assert_eq!(queue.used.ring[3].id, 0);
702        assert_eq!(queue.used.ring[3].len, 100);
703    }
704
705    #[test]
706    fn test_queue_min_size() {
707        let queue = VirtQueue::new(1).unwrap();
708        assert_eq!(queue.size(), 1);
709        assert_eq!(queue.desc_table.len(), 1);
710        assert_eq!(queue.avail.ring.len(), 1);
711        assert_eq!(queue.used.ring.len(), 1);
712    }
713
714    #[test]
715    fn test_queue_max_size() {
716        let queue = VirtQueue::new(32768).unwrap();
717        assert_eq!(queue.size(), 32768);
718        assert_eq!(queue.desc_table.len(), 32768);
719    }
720
721    #[test]
722    fn test_descriptor_chain_out_of_bounds() {
723        let mut queue = VirtQueue::new(4).unwrap();
724
725        // Set up descriptor pointing to out-of-bounds next
726        queue.desc_table[0] = Descriptor {
727            addr: 0x1000,
728            len: 256,
729            flags: flags::NEXT,
730            next: 100, // Out of bounds
731        };
732
733        queue.avail.ring[0] = 0;
734        queue.avail.idx = 1;
735
736        let (_, chain) = queue.pop_avail().unwrap();
737        let descs: Vec<_> = chain.collect();
738
739        // Should only get first descriptor, chain stops at invalid next
740        assert_eq!(descs.len(), 1);
741    }
742}