devices/virtio/
descriptor_chain.rs

1// Copyright 2023 The ChromiumOS Authors
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5//! Virtqueue descriptor chain abstraction
6
7#![deny(missing_docs)]
8
9use anyhow::bail;
10use anyhow::Context;
11use anyhow::Result;
12use base::trace;
13use cros_async::MemRegion;
14use smallvec::SmallVec;
15use vm_memory::GuestAddress;
16use vm_memory::GuestMemory;
17
18use crate::virtio::descriptor_utils::Reader;
19use crate::virtio::descriptor_utils::Writer;
20
21/// Virtio flag indicating there is a next descriptor in descriptor chain
22pub const VIRTQ_DESC_F_NEXT: u16 = 0x1;
23/// Virtio flag indicating descriptor is write-only
24pub const VIRTQ_DESC_F_WRITE: u16 = 0x2;
25
26/// Packed virtqueue flags
27pub const VIRTQ_DESC_F_AVAIL: u16 = 0x80;
28pub const VIRTQ_DESC_F_USED: u16 = 0x8000;
29
30/// Type of access allowed for a single virtio descriptor within a descriptor chain.
31#[derive(Copy, Clone, Debug, PartialEq, Eq)]
32pub enum DescriptorAccess {
33    /// Descriptor is readable by the device (written by the driver before putting the descriptor
34    /// chain on the available queue).
35    DeviceRead,
36    /// Descriptor is writable by the device (read by the driver after the device puts the
37    /// descriptor chain on the used queue).
38    DeviceWrite,
39}
40
41/// A virtio descriptor chain.
42///
43/// This is a low-level representation of the memory regions in a descriptor chain. Most code should
44/// use [`virtio::Reader`](crate::virtio::Reader) and [`virtio::Writer`](crate::virtio::Writer)
45/// rather than working with `DescriptorChain` memory regions directly.
46pub struct DescriptorChain {
47    mem: GuestMemory,
48
49    /// Index into the descriptor table.
50    index: u16,
51
52    /// The readable memory regions that make up the descriptor chain.
53    pub reader: Reader,
54
55    /// The writable memory regions that make up the descriptor chain.
56    pub writer: Writer,
57
58    /// The descriptor chain id(only if it is a packed virtqueue descriptor chain)
59    pub id: Option<u16>,
60
61    ///  Number of descriptor in descriptor chain
62    pub count: u16,
63}
64
65impl DescriptorChain {
66    /// Read all descriptors from `chain` into a new `DescriptorChain` instance.
67    ///
68    /// This function validates the following properties of the descriptor chain:
69    /// * The chain contains at least one descriptor.
70    /// * Each descriptor has a non-zero length.
71    /// * Each descriptor's memory falls entirely within a contiguous region of `mem`.
72    /// * The total length of the descriptor chain data is representable in `u32`.
73    ///
74    /// If these properties do not hold, `Err` will be returned.
75    ///
76    /// # Arguments
77    ///
78    /// * `chain` - Iterator that will be walked to retrieve all of the descriptors in the chain.
79    /// * `mem` - The [`GuestMemory`] backing the descriptor table and descriptor memory regions.
80    /// * `index` - The index of the first descriptor in the chain.
81    pub fn new(
82        mut chain: impl DescriptorChainIter,
83        mem: &GuestMemory,
84        index: u16,
85    ) -> Result<DescriptorChain> {
86        let mut readable_regions = SmallVec::new();
87        let mut writable_regions = SmallVec::new();
88
89        // If `writable` is true, a writable descriptor has already been encountered.
90        // Valid descriptor chains must consist of readable descriptors followed by writable
91        // descriptors.
92        let mut writable = false;
93
94        while let Some(desc) = chain.next()? {
95            if desc.len == 0 {
96                trace!("zero-length descriptor at index {index}");
97                continue;
98            }
99
100            let region = MemRegion {
101                offset: desc.address,
102                len: desc.len as usize,
103            };
104
105            match desc.access {
106                DescriptorAccess::DeviceRead => {
107                    if writable {
108                        bail!("invalid device-readable descriptor following writable descriptors");
109                    }
110                    readable_regions.push(region);
111                }
112                DescriptorAccess::DeviceWrite => {
113                    writable = true;
114                    writable_regions.push(region);
115                }
116            }
117        }
118
119        let count = chain.count();
120        let id = chain.id();
121
122        Self::validate_mem_regions(mem, &readable_regions, &writable_regions)
123            .context("invalid descriptor chain memory regions")?;
124
125        trace!(
126            "Descriptor chain created, index:{index}, count:{count}, buffer id:{:?}, readable:{}, writable:{}",
127            id,
128            readable_regions.len(),
129            writable_regions.len()
130        );
131
132        let reader = Reader::new_from_regions(mem, readable_regions);
133        let writer = Writer::new_from_regions(mem, writable_regions);
134
135        let desc_chain = DescriptorChain {
136            mem: mem.clone(),
137            index,
138            reader,
139            writer,
140            id,
141            count,
142        };
143
144        Ok(desc_chain)
145    }
146
147    fn validate_mem_regions(
148        mem: &GuestMemory,
149        readable_regions: &[MemRegion],
150        writable_regions: &[MemRegion],
151    ) -> Result<()> {
152        let mut total_len: u32 = 0;
153        for r in readable_regions.iter().chain(writable_regions.iter()) {
154            // This cast is safe because the virtio descriptor length field is u32.
155            let len = r.len as u32;
156
157            // Check that all the regions are totally contained in GuestMemory.
158            if !mem.is_valid_range(GuestAddress(r.offset), len.into()) {
159                bail!(
160                    "descriptor address range out of bounds: addr={:#x} len={:#x}",
161                    r.offset,
162                    r.len
163                );
164            }
165
166            // Verify that summing the descriptor sizes does not overflow.
167            // This can happen if a driver tricks a device into reading/writing more data than
168            // fits in a `u32`.
169            total_len = total_len
170                .checked_add(len)
171                .context("descriptor chain length overflow")?;
172        }
173
174        if total_len == 0 {
175            bail!("invalid zero-length descriptor chain");
176        }
177
178        Ok(())
179    }
180
181    /// Returns a reference to the [`GuestMemory`] instance.
182    pub fn mem(&self) -> &GuestMemory {
183        &self.mem
184    }
185
186    /// Returns the index of the first descriptor in the chain.
187    pub fn index(&self) -> u16 {
188        self.index
189    }
190}
191
192/// A single descriptor within a [`DescriptorChain`].
193pub struct Descriptor {
194    /// Guest memory address of this descriptor.
195    /// If IOMMU is enabled, this is an IOVA, which must be translated via the IOMMU to get a
196    /// guest physical address.
197    pub address: u64,
198
199    /// Length of the descriptor in bytes.
200    pub len: u32,
201
202    /// Whether this descriptor should be treated as writable or readable by the device.
203    pub access: DescriptorAccess,
204}
205
206/// Iterator over the descriptors of a descriptor chain.
207pub trait DescriptorChainIter {
208    /// Return the next descriptor in the chain, or `None` if there are no more descriptors.
209    fn next(&mut self) -> Result<Option<Descriptor>>;
210
211    /// Return the number of descriptor has been iterated in the chain
212    fn count(&self) -> u16;
213
214    /// Return Packed descriptor chain buffer id if iterator reaches end, otherwise return None
215    /// SplitDescriptorChainIter should return None.
216    fn id(&self) -> Option<u16>;
217}