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: u16Queue index
size: u16Queue size
desc_table: Option<DescriptorTable>Descriptor table
max_size: u16Maximum queue size
ready: boolQueue ready flag
desc_table_addr: GuestPhysAddrDescriptor table address (guest physical)
avail_ring_addr: GuestPhysAddrAvailable ring address (guest physical)
used_ring_addr: GuestPhysAddrUsed ring address (guest physical)
event_idx_enabled: boolEvent 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>
impl<T: GuestMemoryAccessor + Clone> VirtioQueue<T>
Sourcepub fn set_size(&mut self, size: u16) -> VirtioResult<()>
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.
Sourcepub fn set_desc_table_addr(&mut self, addr: GuestPhysAddr) -> VirtioResult<()>
pub fn set_desc_table_addr(&mut self, addr: GuestPhysAddr) -> VirtioResult<()>
Set descriptor table address
Sourcepub fn set_avail_ring_addr(&mut self, addr: GuestPhysAddr) -> VirtioResult<()>
pub fn set_avail_ring_addr(&mut self, addr: GuestPhysAddr) -> VirtioResult<()>
Set available ring address
Sourcepub fn set_used_ring_addr(&mut self, addr: GuestPhysAddr) -> VirtioResult<()>
pub fn set_used_ring_addr(&mut self, addr: GuestPhysAddr) -> VirtioResult<()>
Set used ring address
Sourcepub fn is_configured(&self) -> bool
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.
Sourcepub fn accessor(&self) -> &Arc<T> ⓘ
pub fn accessor(&self) -> &Arc<T> ⓘ
The guest-memory accessor used by the non-_with_memory operations.
Sourcepub fn validate_layout(&self) -> VirtioResult<()>
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_sizedoes 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.
Sourcepub fn validate_layout_with_memory(
&self,
memory: &mut dyn GuestMemory,
) -> VirtioResult<()>
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”.
Sourcepub fn is_faulted(&self) -> bool
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.
Sourcepub fn reset(&mut self)
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.
Sourcepub fn read_avail_idx(&self) -> VirtioResult<u16>
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.
Sourcepub fn read_avail_idx_with_memory(
&self,
memory: &mut dyn GuestMemory,
) -> VirtioResult<u16>
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.
Sourcepub fn add_used(&mut self, desc_index: u16, len: u32) -> VirtioResult<()>
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.
Sourcepub fn pop_available_head(&mut self) -> VirtioResult<Option<u16>>
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.
Sourcepub fn pop_available_head_with_memory(
&mut self,
memory: &mut dyn GuestMemory,
) -> VirtioResult<Option<u16>>
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.
Sourcepub fn pop_available(&mut self) -> VirtioResult<Option<DescriptorChain>>
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.
Sourcepub fn descriptor_chain(&self, head: u16) -> VirtioResult<DescriptorChain>
pub fn descriptor_chain(&self, head: u16) -> VirtioResult<DescriptorChain>
Build a validated DescriptorChain for an already-consumed head index.
Sourcepub fn descriptor_chain_with_memory(
&self,
head: u16,
memory: &mut dyn GuestMemory,
) -> VirtioResult<DescriptorChain>
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.
Sourcepub fn complete(&mut self, head: u16, written_len: u32) -> VirtioResult<bool>
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).
Sourcepub fn complete_with_memory(
&mut self,
head: u16,
written_len: u32,
memory: &mut dyn GuestMemory,
) -> VirtioResult<bool>
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.
Sourcepub fn get_used_ring(&self) -> Option<&UsedRing<T>>
pub fn get_used_ring(&self) -> Option<&UsedRing<T>>
Get the used ring reference
Sourcepub fn get_used_ring_mut(&mut self) -> Option<&mut UsedRing<T>>
pub fn get_used_ring_mut(&mut self) -> Option<&mut UsedRing<T>>
Get the used ring mutable reference
Sourcepub fn get_avail_ring(&self) -> Option<&AvailableRing<T>>
pub fn get_avail_ring(&self) -> Option<&AvailableRing<T>>
Get the available ring reference
Sourcepub fn get_desc_table(&self) -> Option<&DescriptorTable>
pub fn get_desc_table(&self) -> Option<&DescriptorTable>
Get the descriptor table reference
Sourcepub fn read_avail_entry(&self, ring_index: u16) -> VirtioResult<u16>
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.
Sourcepub fn read_avail_entry_with_memory(
&self,
ring_index: u16,
memory: &mut dyn GuestMemory,
) -> VirtioResult<u16>
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.
Sourcepub fn update_last_avail_idx(&mut self, idx: u16)
pub fn update_last_avail_idx(&mut self, idx: u16)
Update last available index
Sourcepub fn get_last_avail_idx(&self) -> u16
pub fn get_last_avail_idx(&self) -> u16
Get last available index
Sourcepub fn validate_virtio_block_chain(
&self,
head_index: u16,
min_length: usize,
) -> VirtioResult<bool>
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.
Sourcepub fn get_data_buffers(
&self,
head_index: u16,
device_type: VirtioDeviceID,
) -> VirtioResult<Vec<(GuestPhysAddr, usize, bool)>>
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.
Sourcepub fn get_status_addr(&self, head_index: u16) -> VirtioResult<GuestPhysAddr>
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.
Sourcepub fn should_notify(&self) -> VirtioResult<bool>
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.
Sourcepub fn write_status_byte(&self, head_index: u16, status: u8) -> VirtioResult<()>
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>
impl<T: GuestMemoryAccessor + Clone> Clone for VirtioQueue<T>
Source§fn clone(&self) -> Self
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)
fn clone_from(&mut self, source: &Self)
source. Read more