diff --git a/vm-virtio/src/queue.rs b/vm-virtio/src/queue.rs index 845019a13..35aca45fe 100644 --- a/vm-virtio/src/queue.rs +++ b/vm-virtio/src/queue.rs @@ -17,7 +17,8 @@ use std::sync::Arc; use crate::device::VirtioIommuRemapping; use vm_memory::{ - Address, ByteValued, Bytes, GuestAddress, GuestMemory, GuestMemoryMmap, GuestUsize, + Address, ByteValued, Bytes, GuestAddress, GuestMemory, GuestMemoryError, GuestMemoryMmap, + GuestUsize, }; pub(super) const VIRTQ_DESC_F_NEXT: u16 = 0x1; @@ -29,6 +30,8 @@ pub enum Error { GuestMemoryError, InvalidIndirectDescriptor, InvalidChain, + InvalidOffset(u64), + InvalidRingIndexFromMemory(GuestMemoryError), } impl Display for Error { @@ -39,6 +42,8 @@ impl Display for Error { GuestMemoryError => write!(f, "error accessing guest memory"), InvalidChain => write!(f, "invalid descriptor chain"), InvalidIndirectDescriptor => write!(f, "invalid indirect descriptor"), + InvalidOffset(o) => write!(f, "invalid offset {}", o), + InvalidRingIndexFromMemory(e) => write!(f, "invalid ring index from memory: {}", e), } } } @@ -649,44 +654,27 @@ impl Queue { self.next_avail -= Wrapping(1); } - /// Get latest index from available ring. - pub fn update_avail_index_from_memory(&mut self, mem: &GuestMemoryMmap) { - let index_addr = match mem.checked_offset(self.avail_ring, 2) { - Some(ret) => ret, - None => { - error!("Invalid offset 0x{:x}", self.avail_ring.raw_value() + 2); - return; - } - }; - let next_avail: u16 = match mem.read_obj::(index_addr) { - Ok(ret) => ret, - Err(e) => { - error!("Couldn't read `idx` field from memory: {}", e); - return; - } - }; + /// Get ring's index from memory. + fn index_from_memory(&self, ring: GuestAddress, mem: &GuestMemoryMmap) -> Result { + mem.read_obj::( + mem.checked_offset(ring, 2) + .ok_or_else(|| Error::InvalidOffset(ring.raw_value() + 2))?, + ) + .map_err(Error::InvalidRingIndexFromMemory) + } - self.next_avail = Wrapping(next_avail); + /// Get latest index from available ring. + pub fn avail_index_from_memory(&self, mem: &GuestMemoryMmap) -> Result { + self.index_from_memory(self.avail_ring, mem) } /// Get latest index from used ring. - pub fn update_used_index_from_memory(&mut self, mem: &GuestMemoryMmap) { - let index_addr = match mem.checked_offset(self.used_ring, 2) { - Some(ret) => ret, - None => { - error!("Invalid offset 0x{:x}", self.used_ring.raw_value() + 2); - return; - } - }; - let next_used: u16 = match mem.read_obj::(index_addr) { - Ok(ret) => ret, - Err(e) => { - error!("Couldn't read `idx` field from memory: {}", e); - return; - } - }; + pub fn used_index_from_memory(&self, mem: &GuestMemoryMmap) -> Result { + self.index_from_memory(self.used_ring, mem) + } - self.next_used = Wrapping(next_used); + pub fn available_descriptors(&self, mem: &GuestMemoryMmap) -> Result { + Ok(self.used_index_from_memory(mem)? < self.avail_index_from_memory(mem)?) } } diff --git a/vm-virtio/src/transport/mmio.rs b/vm-virtio/src/transport/mmio.rs index 417ac15d3..b8a63ceb7 100644 --- a/vm-virtio/src/transport/mmio.rs +++ b/vm-virtio/src/transport/mmio.rs @@ -12,6 +12,7 @@ use anyhow::anyhow; use byteorder::{ByteOrder, LittleEndian}; use devices::BusDevice; use libc::EFD_NONBLOCK; +use std::num::Wrapping; use std::result; use std::sync::atomic::{AtomicUsize, Ordering}; use std::sync::{Arc, Mutex}; @@ -28,6 +29,12 @@ const VENDOR_ID: u32 = 0; const MMIO_MAGIC_VALUE: u32 = 0x7472_6976; const MMIO_VERSION: u32 = 2; +#[derive(Debug)] +enum Error { + /// Failed to retrieve queue ring's index. + QueueRingIndex(crate::queue::Error), +} + pub struct VirtioInterruptIntx { interrupt_status: Arc, interrupt: Arc>, @@ -152,7 +159,7 @@ impl MmioDevice { } } - fn set_state(&mut self, state: &VirtioMmioDeviceState) -> Result<()> { + fn set_state(&mut self, state: &VirtioMmioDeviceState) -> std::result::Result<(), Error> { self.device_activated = state.device_activated; self.features_select = state.features_select; self.acked_features_select = state.acked_features_select; @@ -166,8 +173,16 @@ impl MmioDevice { if let Some(mem) = self.mem.as_ref() { let mem = mem.memory(); for queue in self.queues.iter_mut() { - queue.update_avail_index_from_memory(&mem); - queue.update_used_index_from_memory(&mem); + queue.next_avail = Wrapping( + queue + .avail_index_from_memory(&mem) + .map_err(Error::QueueRingIndex)?, + ); + queue.next_used = Wrapping( + queue + .used_index_from_memory(&mem) + .map_err(Error::QueueRingIndex)?, + ); } }