pub struct UserQueue {
size: Wrapping<u16>,
mem: QueueMemory,
mem_layout: MemLayout,
avail_idx: Wrapping<u16>,
used_count: Wrapping<u16>,
free_count: Wrapping<u16>,
device_writable: bool,
}Expand description
Represents a virtqueue that is allocated in the guest userspace and manipulated from a VFIO driver.
This struct is similar to devices::virtio::Queue which is designed for the virtio devices, but
this struct is defined for the virtio drivers.
Memory Layout
mem is the memory allocated in the guest userspace for the virtqueue, which is mapped into
the vvu device via VFIO. The GuestAddresses of mem are the IOVAs that should be used when
communicating with the vvu device. All accesses to the shared memory from the device backend
must be done through the GuestMemory read/write functions.
The layout mem is defined in the following table and stored in mem_layout.
| | Alignment | Size | |—————————————————————–| | Descriptor Table | 16 | 16 ∗ (Queue Size) | | Available Ring | 2 | 6 + 2 ∗ (Queue Size) | | Used Ring | 4 | 6 + 8 ∗ (Queue Size) | | Buffers | (Buffer Size) | (Buffer Size) * (Queue Size) |
TODO(b/207364742): Once we support VIRTIO_F_EVENT_IDX, the additional 2 bytes for the
used_event field will be added.
TODO(b/215153367): Use crate::virtio::Queue as an underlying data structure so that we can use
descriptor_utils::{Reader, Writer} instead of having our own read/write methods.
One of the biggest blockers is that virtio::Queue is designed for device-side’s virtqueue,
where readable/writable areas are inverted from our use case.
Fields§
§size: Wrapping<u16>The queue size.
mem: QueueMemoryThe underlying memory.
mem_layout: MemLayoutVirtqueue layout on mem.
avail_idx: Wrapping<u16>§used_count: Wrapping<u16>§free_count: Wrapping<u16>§device_writable: boolWhether buffers are device-writable or readable.
If true, every descriptor has the VIRTQ_DESC_F_WRITE flag.
TODO(b/215153358, b/215153367): Since VIRTQ_DESC_F_WRITE is a per-descriptor flag, this
design is specific to the current vvu specification draft, where a device-writable queue
and a device-readable queue are separated.
Ideally, we should update the vvu spec to use both device-{readable, writable} buffers in
one virtqueue. Also, it’s better to use crate::virtio::DescriptorChain for descirptors as
a part of b/215153367.
Implementations§
source§impl UserQueue
impl UserQueue
sourcepub fn new<I>(
queue_size: u16,
device_writable: bool,
tag: u8,
iova_alloc: &I
) -> Result<Self>where
I: IovaAllocator,
pub fn new<I>(
queue_size: u16,
device_writable: bool,
tag: u8,
iova_alloc: &I
) -> Result<Self>where
I: IovaAllocator,
Creats a UserQueue instance.
sourcefn init_memory<I>(
max_queue_size: u16,
tag: u8,
iova_alloc: &I
) -> Result<(QueueMemory, u16, MemLayout)>where
I: IovaAllocator,
fn init_memory<I>(
max_queue_size: u16,
tag: u8,
iova_alloc: &I
) -> Result<(QueueMemory, u16, MemLayout)>where
I: IovaAllocator,
Allocates memory region and returns addresses on the regions for (desc_table, avail_ring, used_ring, `buffer``).
sourcefn init_descriptor_table(&mut self) -> Result<()>
fn init_descriptor_table(&mut self) -> Result<()>
Initialize the descriptor table.
pub fn desc_table_addrs(&self) -> Result<DescTableAddrs>
sourcefn buffer_address(&self, index: Wrapping<u16>) -> Result<IOVA>
fn buffer_address(&self, index: Wrapping<u16>) -> Result<IOVA>
Returns the IOVA of the buffer for the given index.
sourcefn write_desc_entry(&self, index: Wrapping<u16>, desc: Desc) -> Result<()>
fn write_desc_entry(&self, index: Wrapping<u16>, desc: Desc) -> Result<()>
Writes the given descriptor table entry.
sourcefn update_avail_index(&self) -> Result<()>
fn update_avail_index(&self) -> Result<()>
Puts an index into the avail ring for use by the host.
sourcefn read_used_idx(&self) -> Result<Wrapping<u16>>
fn read_used_idx(&self) -> Result<Wrapping<u16>>
Reads the Used ring’s index.
sourcefn read_used_elem(&self, idx: Wrapping<u16>) -> Result<UsedElem>
fn read_used_elem(&self, idx: Wrapping<u16>) -> Result<UsedElem>
Reads the Used ring’s element for the given index.
sourcepub fn read_data(&mut self) -> Result<Option<VolatileSlice<'_>>>
pub fn read_data(&mut self) -> Result<Option<VolatileSlice<'_>>>
Reads data in the virtqueue.
Returns Ok(None) if no data are available.
TODO: Use descriptor_utils::Reader.
Auto Trait Implementations§
impl RefUnwindSafe for UserQueue
impl Send for UserQueue
impl Sync for UserQueue
impl Unpin for UserQueue
impl UnwindSafe for UserQueue
Blanket Implementations§
§impl<T> Downcast for Twhere
T: Any,
impl<T> Downcast for Twhere
T: Any,
§fn into_any(self: Box<T, Global>) -> Box<dyn Any + 'static, Global>
fn into_any(self: Box<T, Global>) -> Box<dyn Any + 'static, Global>
Box<dyn Trait> (where Trait: Downcast) to Box<dyn Any>. Box<dyn Any> can
then be further downcast into Box<ConcreteType> where ConcreteType implements Trait.§fn into_any_rc(self: Rc<T>) -> Rc<dyn Any + 'static>
fn into_any_rc(self: Rc<T>) -> Rc<dyn Any + 'static>
Rc<Trait> (where Trait: Downcast) to Rc<Any>. Rc<Any> can then be
further downcast into Rc<ConcreteType> where ConcreteType implements Trait.§fn as_any(&self) -> &(dyn Any + 'static)
fn as_any(&self) -> &(dyn Any + 'static)
&Trait (where Trait: Downcast) to &Any. This is needed since Rust cannot
generate &Any’s vtable from &Trait’s.§fn as_any_mut(&mut self) -> &mut (dyn Any + 'static)
fn as_any_mut(&mut self) -> &mut (dyn Any + 'static)
&mut Trait (where Trait: Downcast) to &Any. This is needed since Rust cannot
generate &mut Any’s vtable from &mut Trait’s.