mirror of
https://github.com/cloud-hypervisor/cloud-hypervisor.git
synced 2026-08-05 02:19:16 +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:
+22
-34
@@ -17,7 +17,8 @@ use std::sync::Arc;
|
|||||||
|
|
||||||
use crate::device::VirtioIommuRemapping;
|
use crate::device::VirtioIommuRemapping;
|
||||||
use vm_memory::{
|
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;
|
pub(super) const VIRTQ_DESC_F_NEXT: u16 = 0x1;
|
||||||
@@ -29,6 +30,8 @@ pub enum Error {
|
|||||||
GuestMemoryError,
|
GuestMemoryError,
|
||||||
InvalidIndirectDescriptor,
|
InvalidIndirectDescriptor,
|
||||||
InvalidChain,
|
InvalidChain,
|
||||||
|
InvalidOffset(u64),
|
||||||
|
InvalidRingIndexFromMemory(GuestMemoryError),
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Display for Error {
|
impl Display for Error {
|
||||||
@@ -39,6 +42,8 @@ impl Display for Error {
|
|||||||
GuestMemoryError => write!(f, "error accessing guest memory"),
|
GuestMemoryError => write!(f, "error accessing guest memory"),
|
||||||
InvalidChain => write!(f, "invalid descriptor chain"),
|
InvalidChain => write!(f, "invalid descriptor chain"),
|
||||||
InvalidIndirectDescriptor => write!(f, "invalid indirect descriptor"),
|
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);
|
self.next_avail -= Wrapping(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Get latest index from available ring.
|
/// Get ring's index from memory.
|
||||||
pub fn update_avail_index_from_memory(&mut self, mem: &GuestMemoryMmap) {
|
fn index_from_memory(&self, ring: GuestAddress, mem: &GuestMemoryMmap) -> Result<u16, Error> {
|
||||||
let index_addr = match mem.checked_offset(self.avail_ring, 2) {
|
mem.read_obj::<u16>(
|
||||||
Some(ret) => ret,
|
mem.checked_offset(ring, 2)
|
||||||
None => {
|
.ok_or_else(|| Error::InvalidOffset(ring.raw_value() + 2))?,
|
||||||
error!("Invalid offset 0x{:x}", self.avail_ring.raw_value() + 2);
|
)
|
||||||
return;
|
.map_err(Error::InvalidRingIndexFromMemory)
|
||||||
}
|
}
|
||||||
};
|
|
||||||
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;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
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.
|
/// Get latest index from used ring.
|
||||||
pub fn update_used_index_from_memory(&mut self, mem: &GuestMemoryMmap) {
|
pub fn used_index_from_memory(&self, mem: &GuestMemoryMmap) -> Result<u16, Error> {
|
||||||
let index_addr = match mem.checked_offset(self.used_ring, 2) {
|
self.index_from_memory(self.used_ring, mem)
|
||||||
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;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
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 byteorder::{ByteOrder, LittleEndian};
|
||||||
use devices::BusDevice;
|
use devices::BusDevice;
|
||||||
use libc::EFD_NONBLOCK;
|
use libc::EFD_NONBLOCK;
|
||||||
|
use std::num::Wrapping;
|
||||||
use std::result;
|
use std::result;
|
||||||
use std::sync::atomic::{AtomicUsize, Ordering};
|
use std::sync::atomic::{AtomicUsize, Ordering};
|
||||||
use std::sync::{Arc, Mutex};
|
use std::sync::{Arc, Mutex};
|
||||||
@@ -28,6 +29,12 @@ const VENDOR_ID: u32 = 0;
|
|||||||
const MMIO_MAGIC_VALUE: u32 = 0x7472_6976;
|
const MMIO_MAGIC_VALUE: u32 = 0x7472_6976;
|
||||||
const MMIO_VERSION: u32 = 2;
|
const MMIO_VERSION: u32 = 2;
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
enum Error {
|
||||||
|
/// Failed to retrieve queue ring's index.
|
||||||
|
QueueRingIndex(crate::queue::Error),
|
||||||
|
}
|
||||||
|
|
||||||
pub struct VirtioInterruptIntx {
|
pub struct VirtioInterruptIntx {
|
||||||
interrupt_status: Arc<AtomicUsize>,
|
interrupt_status: Arc<AtomicUsize>,
|
||||||
interrupt: Arc<Box<dyn InterruptSourceGroup>>,
|
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.device_activated = state.device_activated;
|
||||||
self.features_select = state.features_select;
|
self.features_select = state.features_select;
|
||||||
self.acked_features_select = state.acked_features_select;
|
self.acked_features_select = state.acked_features_select;
|
||||||
@@ -166,8 +173,16 @@ impl MmioDevice {
|
|||||||
if let Some(mem) = self.mem.as_ref() {
|
if let Some(mem) = self.mem.as_ref() {
|
||||||
let mem = mem.memory();
|
let mem = mem.memory();
|
||||||
for queue in self.queues.iter_mut() {
|
for queue in self.queues.iter_mut() {
|
||||||
queue.update_avail_index_from_memory(&mem);
|
queue.next_avail = Wrapping(
|
||||||
queue.update_used_index_from_memory(&mem);
|
queue
|
||||||
|
.avail_index_from_memory(&mem)
|
||||||
|
.map_err(Error::QueueRingIndex)?,
|
||||||
|
);
|
||||||
|
queue.next_used = Wrapping(
|
||||||
|
queue
|
||||||
|
.used_index_from_memory(&mem)
|
||||||
|
.map_err(Error::QueueRingIndex)?,
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user