Skip to main content

VirtioQueue

Struct VirtioQueue 

Source
pub struct VirtioQueue<T: GuestMemoryAccessor + Clone> {
    pub index: u16,
    pub size: u16,
    pub desc_table: Option<DescriptorTable>,
    pub max_size: u16,
    pub ready: bool,
    pub desc_table_addr: GuestPhysAddr,
    pub avail_ring_addr: GuestPhysAddr,
    pub used_ring_addr: GuestPhysAddr,
    pub event_idx_enabled: bool,
    /* private fields */
}
Expand description

VirtIO queue implementation

Fields§

§index: u16

Queue index

§size: u16

Queue size

§desc_table: Option<DescriptorTable>

Descriptor table

§max_size: u16

Maximum queue size

§ready: bool

Queue ready flag

§desc_table_addr: GuestPhysAddr

Descriptor table address (guest physical)

§avail_ring_addr: GuestPhysAddr

Available ring address (guest physical)

§used_ring_addr: GuestPhysAddr

Used ring address (guest physical)

§event_idx_enabled: bool

Event index enabled.

Currently always false and intentionally unused: event-index feature negotiation is not implemented yet, and a follow-up will wire this flag. Layout validation deliberately does not depend on it: the ring regions always include the 2-byte event-index footer through the layout_size math, so the check stays negotiation-independent.

Implementations§

Source§

impl<T: GuestMemoryAccessor + Clone> VirtioQueue<T>

Source

pub fn new(index: u16, size: u16, accessor: Arc<T>) -> Self

Create a new VirtIO queue

Source

pub fn set_size(&mut self, size: u16) -> VirtioResult<()>

Set queue size

Rejected once any ring address is programmed or the queue is ready: the ring objects snapshot the size when their address is set, so a later resize would leave layout validation and runtime ring accesses derived from different sizes, letting the queue serve requests outside the validated regions.

Source

pub fn set_desc_table_addr(&mut self, addr: GuestPhysAddr) -> VirtioResult<()>

Set descriptor table address

Source

pub fn set_avail_ring_addr(&mut self, addr: GuestPhysAddr) -> VirtioResult<()>

Set available ring address

Source

pub fn set_used_ring_addr(&mut self, addr: GuestPhysAddr) -> VirtioResult<()>

Set used ring address

Source

pub fn set_ready(&mut self, ready: bool)

Mark queue as ready

Source

pub fn is_configured(&self) -> bool

Whether the three ring addresses have all been programmed.

Address 0 is the “unconfigured” sentinel: a driver that has not finished programming a ring must never be able to make the queue ready.

Source

pub fn accessor(&self) -> &Arc<T>

The guest-memory accessor used by the non-_with_memory operations.

Source

pub fn validate_layout(&self) -> VirtioResult<()>

Validate the three ring layouts against the VirtIO split-ring requirements. This is a pure query and does not change queue state.

Checks, per VirtIO 1.x §2.7:

  • all three ring addresses are non-zero;
  • the descriptor table is 16-byte aligned, the available ring 2-byte and the used ring 4-byte aligned;
  • addr + size * elem_size does not overflow the guest address space for any ring;
  • the three regions do not overlap (overlap would let a used-element write corrupt descriptors the device is about to read).

The available and used regions always include their 2-byte event-index footer (used_event / avail_event), even when VIRTIO_F_RING_EVENT_IDX is not negotiated: a driver that negotiated it writes into those bytes, and the ring types’ own total_size counts them. Always covering the footer is the conservative, negotiation-independent envelope.

The transport is expected to call this from its single “queue becomes usable” enforcement point (MMIO: the QUEUE_READY write; PCI: layout programmed in the queue config registers) and to refuse to mark the queue ready when it fails.

Source

pub fn validate_layout_with_memory( &self, memory: &mut dyn GuestMemory, ) -> VirtioResult<()>

Validates the ring layout like validate_layout and additionally screens the ring regions against memory: the first byte and the last byte (end - 1) of every region must be readable through memory.

memory must be backed by the same accessor the queue uses for its runtime accesses; passing a capability over different memory makes the check vacuous. Only the two boundary bytes per region are probed on purpose: this is a best-effort enable-time screen, and the per-byte runtime accesses are what ultimately verify mid-region mapping.

An accessor that cannot translate any guest address (such as NoGuestMemoryAccessor, whose translate_and_get_limit always returns None) fails every probe and therefore cannot satisfy this check; such layouts are rejected (the first rejection per configuration cycle is warned, later ones only traced), so the MMIO transport requires an accessor backed by real guest memory. Memory-screening failures are reported as VirtioError::InvalidRingLayout, while pure layout errors keep their specific variants (RingMisaligned, RingOverlap); any Err means the layout was rejected, so the caller only needs to distinguish “layout rejected” from “queue ready”.

Source

pub fn is_faulted(&self) -> bool

Whether the queue is in the faulted state and must be reset before further pop/complete calls.

While faulted, the guest-serving data paths (pop/complete, chain walks and data access) reject with VirtioError::QueueFaulted. The configuration setters remain usable so a driver can re-program the queue, and reset is the only operation that clears the fault.

Source

pub fn is_valid(&self) -> bool

Check if queue is valid and ready

Source

pub fn reset(&mut self)

Reset the queue: clears the ready flag, the faulted state and the layout-warning latch, and discards the programmed ring addresses, indices and ring objects, so the driver must re-program the queue before it can be used again.

While faulted, the guest-serving data paths reject with VirtioError::QueueFaulted but the configuration setters remain usable; reset is the only operation that clears the fault.

Source

pub fn read_avail_idx(&self) -> VirtioResult<u16>

Read available ring index through the queue’s own accessor.

Returns VirtioError::QueueFaulted when the queue is faulted and VirtioError::QueueNotReady when the available ring is not configured (not a runtime failure, so the queue is not faulted). A read failure of a configured ring is a runtime failure and latches the fault, matching the other avail-ring pre-read paths.

Source

pub fn read_avail_idx_with_memory( &self, memory: &mut dyn GuestMemory, ) -> VirtioResult<u16>

Reads the available index with a scoped memory capability.

Returns VirtioError::QueueFaulted when the queue is faulted and VirtioError::QueueNotReady when the available ring is not configured (not a runtime failure, so the queue is not faulted). A read failure of a configured ring is a runtime failure and latches the fault, matching the other avail-ring pre-read paths.

Source

pub fn add_used(&mut self, desc_index: u16, len: u32) -> VirtioResult<()>

Add a used buffer to the used ring.

Returns VirtioError::QueueNotReady when the queue is not ready or the used ring is not configured: a missing used ring is never silently accepted as a success (the historical fallback did exactly that). Being unconfigured is not a runtime failure, so the queue is not faulted; a guest-memory write failure on a configured ring does latch the fault.

Source

pub fn pop_available_head(&mut self) -> VirtioResult<Option<u16>>

Consume one available-ring head index, or None if the queue is empty.

Advances last_avail_idx by one (wrapping at u16::MAX). Returns VirtioError::InvalidQueue when the guest’s avail.idx is ahead by more than size, which indicates a corrupted available ring.

Source

pub fn pop_available_head_with_memory( &mut self, memory: &mut dyn GuestMemory, ) -> VirtioResult<Option<u16>>

Consumes one available head with a scoped memory capability.

Source

pub fn pop_available(&mut self) -> VirtioResult<Option<DescriptorChain>>

Consume one available head and return a validated DescriptorChain.

Returns Ok(None) when the queue is empty. The head is consumed before the chain is validated; on a validation error the head is already advanced (so the queue is not stalled) and the caller should complete that head with length 0. To recover the head on error, use pop_available_head plus descriptor_chain directly.

Source

pub fn descriptor_chain(&self, head: u16) -> VirtioResult<DescriptorChain>

Build a validated DescriptorChain for an already-consumed head index.

Source

pub fn descriptor_chain_with_memory( &self, head: u16, memory: &mut dyn GuestMemory, ) -> VirtioResult<DescriptorChain>

Builds a validated descriptor chain using a scoped memory capability.

Returns VirtioError::QueueNotReady when the descriptor table is not configured (not a runtime failure, so the queue is not faulted) and VirtioError::QueueFaulted when the queue is already faulted.

Source

pub fn complete(&mut self, head: u16, written_len: u32) -> VirtioResult<bool>

Complete a descriptor chain: append a used element for head with the given written length, then report whether the driver should be notified.

written_len is the number of bytes the device wrote into guest-writable buffers (RX bytes, or 0 for TX / discarded / error completions).

Source

pub fn complete_with_memory( &mut self, head: u16, written_len: u32, memory: &mut dyn GuestMemory, ) -> VirtioResult<bool>

Completes a chain with a scoped memory capability.

Returns VirtioError::QueueNotReady when a ring is not configured (not a runtime failure, so the queue is not faulted) and VirtioError::QueueFaulted when the queue is already faulted. Any failure while writing the used ring or reading the available flags is treated as a runtime failure and latches the fault.

Source

pub fn get_used_ring(&self) -> Option<&UsedRing<T>>

Get the used ring reference

Source

pub fn get_used_ring_mut(&mut self) -> Option<&mut UsedRing<T>>

Get the used ring mutable reference

Source

pub fn get_avail_ring(&self) -> Option<&AvailableRing<T>>

Get the available ring reference

Source

pub fn get_desc_table(&self) -> Option<&DescriptorTable>

Get the descriptor table reference

Source

pub fn read_avail_entry(&self, ring_index: u16) -> VirtioResult<u16>

Read available ring entry through the queue’s own accessor.

Returns VirtioError::QueueFaulted when the queue is faulted and VirtioError::QueueNotReady when the available ring is not configured (not a runtime failure, so the queue is not faulted). A read failure of a configured ring is a runtime failure and latches the fault, matching the other avail-ring pre-read paths.

Source

pub fn read_avail_entry_with_memory( &self, ring_index: u16, memory: &mut dyn GuestMemory, ) -> VirtioResult<u16>

Reads an available-ring entry with a scoped memory capability.

Returns VirtioError::QueueFaulted when the queue is faulted and VirtioError::QueueNotReady when the available ring is not configured (not a runtime failure, so the queue is not faulted). A read failure of a configured ring is a runtime failure and latches the fault, matching the other avail-ring pre-read paths.

Source

pub fn update_last_avail_idx(&mut self, idx: u16)

Update last available index

Source

pub fn get_last_avail_idx(&self) -> u16

Get last available index

Source

pub fn validate_virtio_block_chain( &self, head_index: u16, min_length: usize, ) -> VirtioResult<bool>

Validate VirtIO block chain

Returns VirtioError::QueueNotReady when the descriptor table is not configured and VirtioError::QueueFaulted when the queue is faulted. Any validation or guest-memory failure on a configured queue latches the fault, matching the other descriptor-chain walk entry points.

Source

pub fn get_data_buffers( &self, head_index: u16, device_type: VirtioDeviceID, ) -> VirtioResult<Vec<(GuestPhysAddr, usize, bool)>>

Get data buffers from descriptor chain

Returns VirtioError::QueueNotReady when the descriptor table is not configured and VirtioError::QueueFaulted when the queue is faulted. Any guest-memory failure on a configured queue latches the fault.

Source

pub fn get_status_addr(&self, head_index: u16) -> VirtioResult<GuestPhysAddr>

Get status address from descriptor chain

Returns VirtioError::QueueNotReady when the descriptor table is not configured and VirtioError::QueueFaulted when the queue is faulted. Any guest-memory failure on a configured queue latches the fault.

Source

pub fn should_notify(&self) -> VirtioResult<bool>

Whether the device should interrupt the driver after updating the used ring.

Per the VirtIO specification the device honors the available ring’s VIRTQ_AVAIL_F_NO_INTERRUPT flag. The used ring’s VIRTQ_USED_F_NO_NOTIFY flag is the opposite direction (the driver reads it to decide whether to kick the device), so it must not gate device-to-driver interrupts.

Returns VirtioError::QueueFaulted when the queue is faulted, VirtioError::QueueNotReady when the available ring is not configured (not a runtime failure, so the queue is not faulted), and latches the fault on a read failure of a configured ring.

Source

pub fn write_status_byte(&self, head_index: u16, status: u8) -> VirtioResult<()>

Write status byte to the status buffer of a descriptor chain

This method writes the status byte to the last descriptor in the chain, which should be a write-only descriptor according to VirtIO specification.

Returns VirtioError::QueueNotReady when the descriptor table is not configured and VirtioError::QueueFaulted when the queue is faulted; a faulted queue never writes guest memory.

Trait Implementations§

Source§

impl<T: GuestMemoryAccessor + Clone> Clone for VirtioQueue<T>

Source§

fn clone(&self) -> Self

Clones the queue configuration, snapshotting the current faulted and layout-warning latch states into fresh atomics (the clone does not share the original’s latches).

1.0.0 (const: unstable) · Source§

fn clone_from(&mut self, source: &Self)

Performs copy-assignment from source. Read more
Source§

impl<T: Debug + GuestMemoryAccessor + Clone> Debug for VirtioQueue<T>

Source§

fn fmt(&self, f: &mut Formatter<'_>) -> Result

Formats the value using the given formatter. Read more

Auto Trait Implementations§

§

impl<T> !Freeze for VirtioQueue<T>

§

impl<T> RefUnwindSafe for VirtioQueue<T>
where T: RefUnwindSafe,

§

impl<T> Send for VirtioQueue<T>
where T: Sync + Send,

§

impl<T> Sync for VirtioQueue<T>
where T: Sync + Send,

§

impl<T> Unpin for VirtioQueue<T>

§

impl<T> UnsafeUnpin for VirtioQueue<T>

§

impl<T> UnwindSafe for VirtioQueue<T>
where T: RefUnwindSafe,

Blanket Implementations§

Source§

impl<T> Any for T
where T: 'static + ?Sized,

Source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
Source§

impl<T> Borrow<T> for T
where T: ?Sized,

Source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
Source§

impl<T> BorrowMut<T> for T
where T: ?Sized,

Source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
Source§

impl<T> CloneToUninit for T
where T: Clone,

Source§

unsafe fn clone_to_uninit(&self, dest: *mut u8)

🔬This is a nightly-only experimental API. (clone_to_uninit)
Performs copy-assignment from self to dest. Read more
Source§

impl<T> From<T> for T

Source§

fn from(t: T) -> T

Returns the argument unchanged.

Source§

impl<T, U> Into<U> for T
where U: From<T>,

Source§

fn into(self) -> U

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

Source§

impl<T> ToOwned for T
where T: Clone,

Source§

type Owned = T

The resulting type after obtaining ownership.
Source§

fn to_owned(&self) -> T

Creates owned data from borrowed data, usually by cloning. Read more
Source§

fn clone_into(&self, target: &mut T)

Uses borrowed data to replace owned data, usually by cloning. Read more
Source§

impl<T, U> TryFrom<U> for T
where U: Into<T>,

Source§

type Error = Infallible

The type returned in the event of a conversion error.
Source§

fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>

Performs the conversion.
Source§

impl<T, U> TryInto<U> for T
where U: TryFrom<T>,

Source§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
Source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.