1use crate::error::{Result, VirtioError};
7
8pub mod flags {
10 pub const NEXT: u16 = 1;
12 pub const WRITE: u16 = 2;
14 pub const INDIRECT: u16 = 4;
16}
17
18#[derive(Debug, Clone, Copy, Default)]
20#[repr(C)]
21pub struct Descriptor {
22 pub addr: u64,
24 pub len: u32,
26 pub flags: u16,
28 pub next: u16,
30}
31
32impl Descriptor {
33 #[must_use]
35 pub const fn has_next(&self) -> bool {
36 self.flags & flags::NEXT != 0
37 }
38
39 #[must_use]
41 pub const fn is_write_only(&self) -> bool {
42 self.flags & flags::WRITE != 0
43 }
44
45 #[must_use]
47 pub const fn is_indirect(&self) -> bool {
48 self.flags & flags::INDIRECT != 0
49 }
50}
51
52#[derive(Debug)]
54pub struct AvailRing {
55 pub flags: u16,
57 pub idx: u16,
59 pub ring: Vec<u16>,
61 pub used_event: u16,
63}
64
65impl AvailRing {
66 #[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#[derive(Debug, Clone, Copy, Default)]
80#[repr(C)]
81pub struct UsedElement {
82 pub id: u32,
84 pub len: u32,
86}
87
88#[derive(Debug)]
90pub struct UsedRing {
91 pub flags: u16,
93 pub idx: u16,
95 pub ring: Vec<UsedElement>,
97 pub avail_event: u16,
99}
100
101impl UsedRing {
102 #[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#[derive(Debug)]
116pub struct VirtQueue {
117 size: u16,
119 desc_table: Vec<Descriptor>,
121 avail: AvailRing,
123 used: UsedRing,
125 last_avail_idx: u16,
127 ready: bool,
129}
130
131impl VirtQueue {
132 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 #[must_use]
162 pub const fn size(&self) -> u16 {
163 self.size
164 }
165
166 #[must_use]
168 pub const fn is_ready(&self) -> bool {
169 self.ready
170 }
171
172 pub const fn set_ready(&mut self, ready: bool) {
174 self.ready = ready;
175 }
176
177 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 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 #[must_use]
213 pub const fn has_available(&self) -> bool {
214 self.avail.idx != self.last_avail_idx
215 }
216
217 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 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 #[must_use]
250 pub fn get_descriptor(&self, idx: u16) -> Option<&Descriptor> {
251 self.desc_table.get(idx as usize)
252 }
253}
254
255pub 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 #[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; assert_eq!(cloned.addr, 0xDEADBEEF);
349 assert_eq!(copied.addr, 0xDEADBEEF);
350 }
351
352 #[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 #[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 #[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; assert_eq!(cloned.id, 42);
400 assert_eq!(copied.len, 1024);
401 }
402
403 #[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 #[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 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); assert!(result.is_ok());
456
457 }
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 assert!(queue.get_descriptor(0).is_some());
490 assert!(queue.get_descriptor(15).is_some());
491
492 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 for i in 0..10 {
518 queue.push_used(i, i as u32 * 100);
519 }
520
521 assert_eq!(queue.used.idx, 10);
522 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 queue.avail.ring[0] = 0; queue.avail.idx = 1;
534
535 assert!(queue.has_available());
537
538 let (head_idx, _chain) = queue.pop_avail().unwrap();
540 assert_eq!(head_idx, 0);
541
542 assert!(!queue.has_available());
544
545 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 for i in 0..5 {
557 queue.avail.ring[i] = i as u16;
558 }
559 queue.avail.idx = 5;
560
561 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 #[test]
576 fn test_descriptor_chain_single() {
577 let mut queue = VirtQueue::new(16).unwrap();
578
579 queue.desc_table[0] = Descriptor {
581 addr: 0x1000,
582 len: 512,
583 flags: 0, 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 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, 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 queue.desc_table[0] = Descriptor {
641 addr: 0x1000,
642 len: 256,
643 flags: flags::NEXT, next: 1,
645 };
646 queue.desc_table[1] = Descriptor {
647 addr: 0x2000,
648 len: 512,
649 flags: flags::WRITE, 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 #[test]
669 fn test_avail_idx_wrap() {
670 let mut queue = VirtQueue::new(4).unwrap();
671
672 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 queue.avail.ring[(queue.avail.idx % 4) as usize] = 1;
685 queue.avail.idx = 0; 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); 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 queue.desc_table[0] = Descriptor {
727 addr: 0x1000,
728 len: 256,
729 flags: flags::NEXT,
730 next: 100, };
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 assert_eq!(descs.len(), 1);
741 }
742}