mirror of
https://github.com/cloud-hypervisor/cloud-hypervisor.git
synced 2024-12-22 13:45:20 +00:00
vm-virtio: Extend Queue helpers
First, this modifies the existing helpers on how to get indexes for available and used rings from memory. Instead of updating the queue through each helper, they are now used as simple getters. Based on these new getters, we could create a new helper to determine if the queue has some available descriptors already queued from the driver side. This helper is going to be particularly helpful when trying to determine from a virtio thread if a queue is already loaded with some available buffers that can be used to send information to the guest. Signed-off-by: Sebastien Boeuf <sebastien.boeuf@intel.com>
This commit is contained in:
parent
c22fd39170
commit
cf707da1a8
@ -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::<u16>(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<u16, Error> {
|
||||
mem.read_obj::<u16>(
|
||||
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<u16, Error> {
|
||||
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::<u16>(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<u16, Error> {
|
||||
self.index_from_memory(self.used_ring, mem)
|
||||
}
|
||||
|
||||
self.next_used = Wrapping(next_used);
|
||||
pub fn available_descriptors(&self, mem: &GuestMemoryMmap) -> Result<bool, Error> {
|
||||
Ok(self.used_index_from_memory(mem)? < self.avail_index_from_memory(mem)?)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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<AtomicUsize>,
|
||||
interrupt: Arc<Box<dyn InterruptSourceGroup>>,
|
||||
@ -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)?,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user