// Copyright 2023 The ChromiumOS Authors1// Use of this source code is governed by a BSD-style license that can be2// found in the LICENSE file.34//! Virtqueue descriptor chain abstraction56#![deny(missing_docs)]78use anyhow::bail;9use anyhow::Context;10use anyhow::Result;11use base::trace;12use cros_async::MemRegion;13use smallvec::SmallVec;14use vm_memory::GuestAddress;15use vm_memory::GuestMemory;1617use crate::virtio::descriptor_utils::Reader;18use crate::virtio::descriptor_utils::Writer;1920/// Virtio flag indicating there is a next descriptor in descriptor chain21pub const VIRTQ_DESC_F_NEXT: u16 = 0x1;22/// Virtio flag indicating descriptor is write-only23pub const VIRTQ_DESC_F_WRITE: u16 = 0x2;2425/// Packed virtqueue flags26pub const VIRTQ_DESC_F_AVAIL: u16 = 0x80;27pub const VIRTQ_DESC_F_USED: u16 = 0x8000;2829/// Type of access allowed for a single virtio descriptor within a descriptor chain.30#[derive(Copy, Clone, Debug, PartialEq, Eq)]31pub enum DescriptorAccess {32/// Descriptor is readable by the device (written by the driver before putting the descriptor33/// chain on the available queue).34DeviceRead,35/// Descriptor is writable by the device (read by the driver after the device puts the36/// descriptor chain on the used queue).37DeviceWrite,38}3940/// A virtio descriptor chain.41///42/// This is a low-level representation of the memory regions in a descriptor chain. Most code should43/// use [`virtio::Reader`](crate::virtio::Reader) and [`virtio::Writer`](crate::virtio::Writer)44/// rather than working with `DescriptorChain` memory regions directly.45pub struct DescriptorChain {46mem: GuestMemory,4748/// Index into the descriptor table.49index: u16,5051/// The readable memory regions that make up the descriptor chain.52pub reader: Reader,5354/// The writable memory regions that make up the descriptor chain.55pub writer: Writer,5657/// The descriptor chain id(only if it is a packed virtqueue descriptor chain)58pub id: Option<u16>,5960/// Number of descriptor in descriptor chain61pub count: u16,62}6364impl DescriptorChain {65/// Read all descriptors from `chain` into a new `DescriptorChain` instance.66///67/// This function validates the following properties of the descriptor chain:68/// * The chain contains at least one descriptor.69/// * Each descriptor has a non-zero length.70/// * Each descriptor's memory falls entirely within a contiguous region of `mem`.71/// * The total length of the descriptor chain data is representable in `u32`.72///73/// If these properties do not hold, `Err` will be returned.74///75/// # Arguments76///77/// * `chain` - Iterator that will be walked to retrieve all of the descriptors in the chain.78/// * `mem` - The [`GuestMemory`] backing the descriptor table and descriptor memory regions.79/// * `index` - The index of the first descriptor in the chain.80pub fn new(81mut chain: impl DescriptorChainIter,82mem: &GuestMemory,83index: u16,84) -> Result<DescriptorChain> {85let mut readable_regions = SmallVec::new();86let mut writable_regions = SmallVec::new();8788// If `writable` is true, a writable descriptor has already been encountered.89// Valid descriptor chains must consist of readable descriptors followed by writable90// descriptors.91let mut writable = false;9293while let Some(desc) = chain.next()? {94if desc.len == 0 {95trace!("zero-length descriptor at index {index}");96continue;97}9899let region = MemRegion {100offset: desc.address,101len: desc.len as usize,102};103104match desc.access {105DescriptorAccess::DeviceRead => {106if writable {107bail!("invalid device-readable descriptor following writable descriptors");108}109readable_regions.push(region);110}111DescriptorAccess::DeviceWrite => {112writable = true;113writable_regions.push(region);114}115}116}117118let count = chain.count();119let id = chain.id();120121Self::validate_mem_regions(mem, &readable_regions, &writable_regions)122.context("invalid descriptor chain memory regions")?;123124trace!(125"Descriptor chain created, index:{index}, count:{count}, buffer id:{:?}, readable:{}, writable:{}",126id,127readable_regions.len(),128writable_regions.len()129);130131let reader = Reader::new_from_regions(mem, readable_regions);132let writer = Writer::new_from_regions(mem, writable_regions);133134let desc_chain = DescriptorChain {135mem: mem.clone(),136index,137reader,138writer,139id,140count,141};142143Ok(desc_chain)144}145146fn validate_mem_regions(147mem: &GuestMemory,148readable_regions: &[MemRegion],149writable_regions: &[MemRegion],150) -> Result<()> {151let mut total_len: u32 = 0;152for r in readable_regions.iter().chain(writable_regions.iter()) {153// This cast is safe because the virtio descriptor length field is u32.154let len = r.len as u32;155156// Check that all the regions are totally contained in GuestMemory.157if !mem.is_valid_range(GuestAddress(r.offset), len.into()) {158bail!(159"descriptor address range out of bounds: addr={:#x} len={:#x}",160r.offset,161r.len162);163}164165// Verify that summing the descriptor sizes does not overflow.166// This can happen if a driver tricks a device into reading/writing more data than167// fits in a `u32`.168total_len = total_len169.checked_add(len)170.context("descriptor chain length overflow")?;171}172173if total_len == 0 {174bail!("invalid zero-length descriptor chain");175}176177Ok(())178}179180/// Returns a reference to the [`GuestMemory`] instance.181pub fn mem(&self) -> &GuestMemory {182&self.mem183}184185/// Returns the index of the first descriptor in the chain.186pub fn index(&self) -> u16 {187self.index188}189}190191/// A single descriptor within a [`DescriptorChain`].192pub struct Descriptor {193/// Guest memory address of this descriptor.194/// If IOMMU is enabled, this is an IOVA, which must be translated via the IOMMU to get a195/// guest physical address.196pub address: u64,197198/// Length of the descriptor in bytes.199pub len: u32,200201/// Whether this descriptor should be treated as writable or readable by the device.202pub access: DescriptorAccess,203}204205/// Iterator over the descriptors of a descriptor chain.206pub trait DescriptorChainIter {207/// Return the next descriptor in the chain, or `None` if there are no more descriptors.208fn next(&mut self) -> Result<Option<Descriptor>>;209210/// Return the number of descriptor has been iterated in the chain211fn count(&self) -> u16;212213/// Return Packed descriptor chain buffer id if iterator reaches end, otherwise return None214/// SplitDescriptorChainIter should return None.215fn id(&self) -> Option<u16>;216}217218219