axvirtio_common/queue/
available.rs1use alloc::sync::Arc;
2
3use axaddrspace::GuestMemoryAccessor;
4use axvm_types::GuestPhysAddr;
5
6use crate::{
7 constants::*,
8 error::{VirtioError, VirtioResult},
9 memory::GuestMemory,
10};
11
12#[repr(C)]
26#[derive(Debug, Clone, Copy, Default)]
27pub struct VirtQueueAvail {
28 pub flags: u16,
30 pub idx: u16,
32}
33
34impl VirtQueueAvail {
35 pub fn new() -> Self {
37 Self { flags: 0, idx: 0 }
38 }
39
40 pub fn no_interrupt(&self) -> bool {
42 (self.flags & VIRTQ_AVAIL_F_NO_INTERRUPT) != 0
43 }
44
45 pub fn set_no_interrupt(&mut self, no_interrupt: bool) {
47 if no_interrupt {
48 self.flags |= VIRTQ_AVAIL_F_NO_INTERRUPT;
49 } else {
50 self.flags &= !VIRTQ_AVAIL_F_NO_INTERRUPT;
51 }
52 }
53}
54
55#[derive(Debug, Clone)]
83pub struct AvailableRing<T: GuestMemoryAccessor + Clone> {
84 pub base_addr: GuestPhysAddr,
86 pub size: u16,
88 pub last_avail_idx: u16,
90 accessor: Arc<T>,
92}
93
94impl<T: GuestMemoryAccessor + Clone> AvailableRing<T> {
95 pub fn new(base_addr: GuestPhysAddr, size: u16, accessor: Arc<T>) -> Self {
97 Self {
98 base_addr,
99 size,
100 last_avail_idx: 0,
101 accessor,
102 }
103 }
104
105 pub fn header_addr(&self) -> GuestPhysAddr {
107 self.base_addr
108 }
109
110 pub fn ring_addr(&self) -> GuestPhysAddr {
112 self.base_addr + core::mem::size_of::<VirtQueueAvail>()
113 }
114
115 pub fn ring_entry_addr(&self, index: u16) -> Option<GuestPhysAddr> {
117 if index >= self.size {
118 return None;
119 }
120
121 let offset = core::mem::size_of::<VirtQueueAvail>() + (index as usize * 2);
122 Some(self.base_addr + offset)
123 }
124
125 pub fn used_event_addr(&self) -> GuestPhysAddr {
127 self.base_addr + Self::layout_size(self.size) - 2
131 }
132
133 pub(crate) const fn layout_size(size: u16) -> usize {
140 core::mem::size_of::<VirtQueueAvail>() + (size as usize) * 2 + 2
141 }
142
143 pub fn total_size(&self) -> usize {
147 Self::layout_size(self.size)
148 }
149
150 pub fn is_valid(&self) -> bool {
152 self.base_addr.as_usize() != 0 && self.size > 0
153 }
154
155 pub fn has_new_avail(&self, current_idx: u16) -> bool {
157 current_idx != self.last_avail_idx
158 }
159
160 pub fn update_last_avail_idx(&mut self, idx: u16) {
162 self.last_avail_idx = idx;
163 }
164
165 pub fn read_avail_header(&self) -> VirtioResult<VirtQueueAvail> {
167 if !self.is_valid() {
168 return Err(VirtioError::QueueNotReady);
169 }
170
171 self.accessor
172 .read_obj(self.base_addr)
173 .map_err(|_| VirtioError::InvalidAddress)
174 }
175
176 pub fn write_avail_header(&self, header: &VirtQueueAvail) -> VirtioResult<()> {
178 if !self.is_valid() {
179 return Err(VirtioError::QueueNotReady);
180 }
181
182 self.accessor
183 .write_obj(self.base_addr, header)
184 .map_err(|_| VirtioError::InvalidAddress)
185 }
186
187 pub fn read_avail_idx(&self) -> VirtioResult<u16> {
189 let mut memory = crate::AddressSpaceMemory::new(&*self.accessor);
190 self.read_avail_idx_with_memory(&mut memory)
191 }
192
193 pub fn read_avail_idx_with_memory(&self, memory: &mut dyn GuestMemory) -> VirtioResult<u16> {
195 if !self.is_valid() {
196 return Err(VirtioError::QueueNotReady);
197 }
198
199 let idx_addr = self.base_addr + 2;
201 let mut bytes = [0u8; 2];
202 memory.read(idx_addr, &mut bytes)?;
203 Ok(u16::from_le_bytes(bytes))
204 }
205
206 pub fn get_avail_idx(&self) -> VirtioResult<u16> {
208 self.read_avail_idx()
209 }
210
211 pub fn read_avail_ring_entry(&self, ring_index: u16) -> VirtioResult<u16> {
213 let mut memory = crate::AddressSpaceMemory::new(&*self.accessor);
214 self.read_avail_ring_entry_with_memory(ring_index, &mut memory)
215 }
216
217 pub fn read_avail_ring_entry_with_memory(
219 &self,
220 ring_index: u16,
221 memory: &mut dyn GuestMemory,
222 ) -> VirtioResult<u16> {
223 if !self.is_valid() {
224 return Err(VirtioError::QueueNotReady);
225 }
226
227 let entry_addr = self
228 .ring_entry_addr(ring_index % self.size)
229 .ok_or(VirtioError::InvalidQueue)?;
230
231 let mut bytes = [0u8; 2];
232 memory.read(entry_addr, &mut bytes)?;
233 Ok(u16::from_le_bytes(bytes))
234 }
235
236 pub fn write_avail_ring_entry(&self, ring_index: u16, desc_index: u16) -> VirtioResult<()> {
238 if !self.is_valid() {
239 return Err(VirtioError::QueueNotReady);
240 }
241
242 let entry_addr = self
243 .ring_entry_addr(ring_index % self.size)
244 .ok_or(VirtioError::InvalidQueue)?;
245
246 self.accessor
247 .write_obj(entry_addr, desc_index)
248 .map_err(|_| VirtioError::InvalidAddress)?;
249
250 Ok(())
251 }
252
253 pub fn get_available_count(&self) -> VirtioResult<u16> {
255 let current_idx = self.read_avail_idx()?;
256 Ok(current_idx.wrapping_sub(self.last_avail_idx))
257 }
258
259 pub fn interrupts_suppressed(&self) -> VirtioResult<bool> {
261 let header = self.read_avail_header()?;
262 Ok(header.no_interrupt())
263 }
264
265 pub fn interrupts_suppressed_with_memory(
267 &self,
268 memory: &mut dyn GuestMemory,
269 ) -> VirtioResult<bool> {
270 if !self.is_valid() {
271 return Err(VirtioError::QueueNotReady);
272 }
273 let mut bytes = [0u8; 2];
274 memory.read(self.base_addr, &mut bytes)?;
275 Ok(u16::from_le_bytes(bytes) & VIRTQ_AVAIL_F_NO_INTERRUPT != 0)
276 }
277
278 pub fn set_interrupt_suppression(&self, suppress: bool) -> VirtioResult<()> {
280 let mut header = self.read_avail_header()?;
281 header.set_no_interrupt(suppress);
282 self.write_avail_header(&header)?;
283 Ok(())
284 }
285
286 pub fn read_used_event(&self) -> VirtioResult<u16> {
288 if !self.is_valid() {
289 return Err(VirtioError::QueueNotReady);
290 }
291
292 let event_addr = self.used_event_addr();
293 self.accessor
294 .read_obj(event_addr)
295 .map_err(|_| VirtioError::InvalidAddress)
296 }
297
298 pub fn write_used_event(&self, event: u16) -> VirtioResult<()> {
300 if !self.is_valid() {
301 return Err(VirtioError::QueueNotReady);
302 }
303
304 let event_addr = self.used_event_addr();
305 self.accessor
306 .write_obj(event_addr, event)
307 .map_err(|_| VirtioError::InvalidAddress)
308 }
309}
310
311#[cfg(test)]
312mod tests {
313 use super::*;
314 use crate::NoGuestMemoryAccessor;
315
316 #[test]
317 fn layout_size_counts_header_entries_and_footer() {
318 assert_eq!(AvailableRing::<NoGuestMemoryAccessor>::layout_size(4), 14);
320 assert_eq!(
322 AvailableRing::<NoGuestMemoryAccessor>::layout_size(256),
323 4 + 256 * 2 + 2
324 );
325 }
326}