queue.rs 7.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255
  1. use core::mem::size_of;
  2. use core::slice;
  3. use core::sync::atomic::{fence, Ordering};
  4. use super::*;
  5. use crate::header::VirtIOHeader;
  6. use bitflags::*;
  7. use volatile::Volatile;
  8. /// The mechanism for bulk data transport on virtio devices.
  9. ///
  10. /// Each device can have zero or more virtqueues.
  11. #[repr(C)]
  12. pub struct VirtQueue<'a> {
  13. /// DMA guard
  14. dma: DMA,
  15. /// Descriptor table
  16. desc: &'a mut [Descriptor],
  17. /// Available ring
  18. avail: &'a mut AvailRing,
  19. /// Used ring
  20. used: &'a mut UsedRing,
  21. /// Pages of DMA region
  22. pages: usize,
  23. /// The index of queue
  24. queue_idx: u32,
  25. /// The size of queue
  26. queue_size: u16,
  27. /// The number of used queues.
  28. num_used: u16,
  29. /// The head desc index of the free list.
  30. free_head: u16,
  31. avail_idx: u16,
  32. last_used_idx: u16,
  33. }
  34. impl VirtQueue<'_> {
  35. /// Create a new VirtQueue.
  36. pub fn new(header: &mut VirtIOHeader, idx: usize, size: u16) -> Result<Self> {
  37. if header.queue_used(idx as u32) {
  38. return Err(Error::AlreadyUsed);
  39. }
  40. if !size.is_power_of_two() || header.max_queue_size() < size as u32 {
  41. return Err(Error::InvalidParam);
  42. }
  43. let layout = VirtQueueLayout::new(size);
  44. let pages = layout.size / PAGE_SIZE;
  45. // alloc continuous pages
  46. let dma = DMA::new(pages)?;
  47. header.queue_set(idx as u32, size as u32, PAGE_SIZE as u32, dma.pfn());
  48. let desc =
  49. unsafe { slice::from_raw_parts_mut(dma.vaddr() as *mut Descriptor, size as usize) };
  50. let avail = unsafe { &mut *((dma.vaddr() + layout.avail_offset) as *mut AvailRing) };
  51. let used = unsafe { &mut *((dma.vaddr() + layout.used_offset) as *mut UsedRing) };
  52. // link descriptors together
  53. for i in 0..(size - 1) {
  54. desc[i as usize].next.write(i + 1);
  55. }
  56. Ok(VirtQueue {
  57. dma,
  58. desc,
  59. avail,
  60. used,
  61. pages,
  62. queue_size: size,
  63. queue_idx: idx as u32,
  64. num_used: 0,
  65. free_head: 0,
  66. avail_idx: 0,
  67. last_used_idx: 0,
  68. })
  69. }
  70. /// Add buffers to the virtqueue.
  71. ///
  72. /// Ref: linux virtio_ring.c virtqueue_add
  73. pub fn add(&mut self, inputs: &[&[u8]], outputs: &[&mut [u8]]) -> Result {
  74. if inputs.is_empty() && outputs.is_empty() {
  75. return Ok(());
  76. }
  77. if inputs.len() + outputs.len() + self.num_used as usize > self.queue_size as usize {
  78. return Err(Error::BufferTooSmall);
  79. }
  80. // allocate descriptors from free list
  81. let head = self.free_head;
  82. let mut last = self.free_head;
  83. for input in inputs.iter() {
  84. let desc = &mut self.desc[self.free_head as usize];
  85. desc.set_buf(input);
  86. desc.flags.write(DescFlags::NEXT);
  87. last = self.free_head;
  88. self.free_head = desc.next.read();
  89. }
  90. for output in outputs.iter() {
  91. let desc = &mut self.desc[self.free_head as usize];
  92. desc.set_buf(output);
  93. desc.flags.write(DescFlags::NEXT | DescFlags::WRITE);
  94. last = self.free_head;
  95. self.free_head = desc.next.read();
  96. }
  97. // set last_elem.next = NULL
  98. {
  99. let desc = &mut self.desc[last as usize];
  100. let mut flags = desc.flags.read();
  101. flags.remove(DescFlags::NEXT);
  102. desc.flags.write(flags);
  103. }
  104. self.num_used += (inputs.len() + outputs.len()) as u16;
  105. let avail_slot = self.avail_idx & (self.queue_size - 1);
  106. self.avail.ring[avail_slot as usize].write(head);
  107. // write barrier
  108. fence(Ordering::SeqCst);
  109. // increase head of avail ring
  110. self.avail_idx = self.avail_idx.wrapping_add(1);
  111. self.avail.idx.write(self.avail_idx);
  112. Ok(())
  113. }
  114. ///
  115. pub fn can_get(&self) -> bool {
  116. self.last_used_idx != self.used.idx.read()
  117. }
  118. /// Recycle descriptors in the list specified by head.
  119. ///
  120. /// This will push all linked descriptors at the front of the free list.
  121. fn recycle_descriptors(&mut self, mut head: u16) {
  122. let origin_free_head = self.free_head;
  123. self.free_head = head;
  124. loop {
  125. let desc = &mut self.desc[head as usize];
  126. let flags = desc.flags.read();
  127. self.num_used -= 1;
  128. if flags.contains(DescFlags::NEXT) {
  129. head = desc.next.read();
  130. } else {
  131. desc.next.write(origin_free_head);
  132. return;
  133. }
  134. }
  135. }
  136. /// Get device used buffers.
  137. ///
  138. /// Ref: linux virtio_ring.c virtqueue_get_buf_ctx
  139. pub fn get(&mut self) -> Result<usize> {
  140. if !self.can_get() {
  141. return Err(Error::NotReady);
  142. }
  143. // read barrier
  144. fence(Ordering::SeqCst);
  145. let last_used_slot = self.last_used_idx & (self.queue_size - 1);
  146. let index = self.used.ring[last_used_slot as usize].id.read();
  147. let len = self.used.ring[last_used_slot as usize].len.read();
  148. self.recycle_descriptors(index as u16);
  149. self.last_used_idx = self.last_used_idx.wrapping_add(1);
  150. Ok(len as usize)
  151. }
  152. }
  153. /// The inner layout of a VirtQueue.
  154. ///
  155. /// Ref: 2.6.2 Legacy Interfaces: A Note on Virtqueue Layout
  156. struct VirtQueueLayout {
  157. avail_offset: usize,
  158. used_offset: usize,
  159. size: usize,
  160. }
  161. impl VirtQueueLayout {
  162. fn new(queue_size: u16) -> Self {
  163. assert!(
  164. queue_size.is_power_of_two(),
  165. "queue size should be a power of 2"
  166. );
  167. let queue_size = queue_size as usize;
  168. let desc = size_of::<Descriptor>() * queue_size;
  169. let avail = size_of::<u16>() * (3 + queue_size);
  170. let used = size_of::<u16>() * 3 + size_of::<UsedElem>() * queue_size;
  171. VirtQueueLayout {
  172. avail_offset: desc,
  173. used_offset: align_up(desc + avail),
  174. size: align_up(desc + avail) + align_up(used),
  175. }
  176. }
  177. }
  178. #[repr(C, align(16))]
  179. #[derive(Debug)]
  180. struct Descriptor {
  181. addr: Volatile<u64>,
  182. len: Volatile<u32>,
  183. flags: Volatile<DescFlags>,
  184. next: Volatile<u16>,
  185. }
  186. impl Descriptor {
  187. fn set_buf(&mut self, buf: &[u8]) {
  188. self.addr.write(virt_to_phys(buf.as_ptr() as usize) as u64);
  189. self.len.write(buf.len() as u32);
  190. }
  191. }
  192. bitflags! {
  193. /// Descriptor flags
  194. struct DescFlags: u16 {
  195. const NEXT = 1;
  196. const WRITE = 2;
  197. const INDIRECT = 4;
  198. }
  199. }
  200. /// The driver uses the available ring to offer buffers to the device:
  201. /// each ring entry refers to the head of a descriptor chain.
  202. /// It is only written by the driver and read by the device.
  203. #[repr(C)]
  204. #[derive(Debug)]
  205. struct AvailRing {
  206. flags: Volatile<u16>,
  207. /// A driver MUST NOT decrement the idx.
  208. idx: Volatile<u16>,
  209. ring: [Volatile<u16>; 32], // actual size: queue_size
  210. used_event: Volatile<u16>, // unused
  211. }
  212. /// The used ring is where the device returns buffers once it is done with them:
  213. /// it is only written to by the device, and read by the driver.
  214. #[repr(C)]
  215. #[derive(Debug)]
  216. struct UsedRing {
  217. flags: Volatile<u16>,
  218. idx: Volatile<u16>,
  219. ring: [UsedElem; 32], // actual size: queue_size
  220. avail_event: Volatile<u16>, // unused
  221. }
  222. #[repr(C)]
  223. #[derive(Debug)]
  224. struct UsedElem {
  225. id: Volatile<u32>,
  226. len: Volatile<u32>,
  227. }