#![deny(missing_docs)]
use std::fmt::{self, Debug, Display};
use std::num::Wrapping;
use std::ops::{Deref, DerefMut};
use std::sync::atomic::Ordering;
use log::error;
use vm_memory::{GuestMemory, GuestMemoryError, VolatileMemoryError};
pub use self::chain::{DescriptorChain, DescriptorChainRwIter};
pub use self::descriptor_utils::{Reader, Writer};
pub use self::queue::{AvailIter, Queue};
pub use self::queue_sync::QueueSync;
pub use self::state::QueueState;
pub mod defs;
pub mod desc;
#[cfg(any(test, feature = "test-utils"))]
pub mod mock;
mod chain;
mod descriptor_utils;
mod queue;
mod queue_sync;
mod state;
#[derive(Debug)]
pub enum Error {
AddressOverflow,
GuestMemory(GuestMemoryError),
InvalidIndirectDescriptor,
InvalidIndirectDescriptorTable,
InvalidChain,
InvalidDescriptorIndex,
InvalidMaxSize,
InvalidSize,
InvalidDescTableAlign,
InvalidAvailRingAlign,
InvalidUsedRingAlign,
InvalidAvailRingIndex,
QueueNotReady,
VolatileMemoryError(VolatileMemoryError),
DescriptorChainOverflow,
FindMemoryRegion,
GuestMemoryError(GuestMemoryError),
SplitOutOfBounds(usize),
}
impl Display for Error {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
use self::Error::*;
match self {
AddressOverflow => write!(f, "address overflow"),
GuestMemory(_) => write!(f, "error accessing guest memory"),
InvalidChain => write!(f, "invalid descriptor chain"),
InvalidIndirectDescriptor => write!(f, "invalid indirect descriptor"),
InvalidIndirectDescriptorTable => write!(f, "invalid indirect descriptor table"),
InvalidDescriptorIndex => write!(f, "invalid descriptor index"),
InvalidMaxSize => write!(f, "invalid queue maximum size"),
InvalidSize => write!(f, "invalid queue size"),
InvalidDescTableAlign => write!(
f,
"virtio queue descriptor table breaks alignment constraints"
),
InvalidAvailRingAlign => write!(
f,
"virtio queue available ring breaks alignment constraints"
),
InvalidUsedRingAlign => {
write!(f, "virtio queue used ring breaks alignment constraints")
}
InvalidAvailRingIndex => write!(
f,
"invalid available ring index (more descriptors to process than queue size)"
),
QueueNotReady => write!(f, "trying to process requests on a queue that's not ready"),
VolatileMemoryError(e) => write!(f, "volatile memory error: {e}"),
DescriptorChainOverflow => write!(
f,
"the combined length of all the buffers in a `DescriptorChain` would overflow"
),
FindMemoryRegion => write!(f, "no memory region for this address range"),
GuestMemoryError(e) => write!(f, "descriptor guest memory error: {e}"),
SplitOutOfBounds(off) => write!(f, "`DescriptorChain` split is out of bounds: {off}"),
}
}
}
impl std::error::Error for Error {}
pub trait QueueGuard<'a> {
type G: DerefMut<Target = Queue>;
}
pub trait QueueT: for<'a> QueueGuard<'a> {
fn new(max_size: u16) -> Result<Self, Error>
where
Self: Sized;
fn is_valid<M: GuestMemory>(&self, mem: &M) -> bool;
fn reset(&mut self);
fn lock(&mut self) -> <Self as QueueGuard<'_>>::G;
fn max_size(&self) -> u16;
fn size(&self) -> u16;
fn set_size(&mut self, size: u16);
fn ready(&self) -> bool;
fn set_ready(&mut self, ready: bool);
fn set_desc_table_address(&mut self, low: Option<u32>, high: Option<u32>);
fn set_avail_ring_address(&mut self, low: Option<u32>, high: Option<u32>);
fn set_used_ring_address(&mut self, low: Option<u32>, high: Option<u32>);
fn set_event_idx(&mut self, enabled: bool);
fn avail_idx<M>(&self, mem: &M, order: Ordering) -> Result<Wrapping<u16>, Error>
where
M: GuestMemory + ?Sized;
fn used_idx<M: GuestMemory>(&self, mem: &M, order: Ordering) -> Result<Wrapping<u16>, Error>;
fn add_used<M: GuestMemory>(&mut self, mem: &M, head_index: u16, len: u32)
-> Result<(), Error>;
fn enable_notification<M: GuestMemory>(&mut self, mem: &M) -> Result<bool, Error>;
fn disable_notification<M: GuestMemory>(&mut self, mem: &M) -> Result<(), Error>;
fn needs_notification<M: GuestMemory>(&mut self, mem: &M) -> Result<bool, Error>;
fn next_avail(&self) -> u16;
fn set_next_avail(&mut self, next_avail: u16);
fn next_used(&self) -> u16;
fn set_next_used(&mut self, next_used: u16);
fn desc_table(&self) -> u64;
fn avail_ring(&self) -> u64;
fn used_ring(&self) -> u64;
fn event_idx_enabled(&self) -> bool;
fn pop_descriptor_chain<M>(&mut self, mem: M) -> Option<DescriptorChain<M>>
where
M: Clone + Deref,
M::Target: GuestMemory;
}
pub trait QueueOwnedT: QueueT {
fn iter<M>(&mut self, mem: M) -> Result<AvailIter<'_, M>, Error>
where
M: Deref,
M::Target: GuestMemory;
fn go_to_previous_position(&mut self);
}