xref: /aosp_15_r20/external/crosvm/devices/src/virtio/descriptor_chain.rs (revision bb4ee6a4ae7042d18b07a98463b9c8b875e44b39)
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 
9 use anyhow::bail;
10 use anyhow::Context;
11 use anyhow::Result;
12 use base::trace;
13 use cros_async::MemRegion;
14 use smallvec::SmallVec;
15 use vm_memory::GuestAddress;
16 use vm_memory::GuestMemory;
17 
18 use crate::virtio::descriptor_utils::Reader;
19 use crate::virtio::descriptor_utils::Writer;
20 
21 /// Virtio flag indicating there is a next descriptor in descriptor chain
22 pub const VIRTQ_DESC_F_NEXT: u16 = 0x1;
23 /// Virtio flag indicating descriptor is write-only
24 pub const VIRTQ_DESC_F_WRITE: u16 = 0x2;
25 
26 /// Packed virtqueue flags
27 pub const VIRTQ_DESC_F_AVAIL: u16 = 0x80;
28 pub 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)]
32 pub 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.
46 pub 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 
65 impl 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.
new( mut chain: impl DescriptorChainIter, mem: &GuestMemory, index: u16, ) -> Result<DescriptorChain>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 
validate_mem_regions( mem: &GuestMemory, readable_regions: &[MemRegion], writable_regions: &[MemRegion], ) -> Result<()>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.
mem(&self) -> &GuestMemory182     pub fn mem(&self) -> &GuestMemory {
183         &self.mem
184     }
185 
186     /// Returns the index of the first descriptor in the chain.
index(&self) -> u16187     pub fn index(&self) -> u16 {
188         self.index
189     }
190 }
191 
192 /// A single descriptor within a [`DescriptorChain`].
193 pub 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.
207 pub trait DescriptorChainIter {
208     /// Return the next descriptor in the chain, or `None` if there are no more descriptors.
next(&mut self) -> Result<Option<Descriptor>>209     fn next(&mut self) -> Result<Option<Descriptor>>;
210 
211     /// Return the number of descriptor has been iterated in the chain
count(&self) -> u16212     fn count(&self) -> u16;
213 
214     /// Return Packed descriptor chain buffer id if iterator reaches end, otherwise return None
215     /// SplitDescriptorChainIter should return None.
id(&self) -> Option<u16>216     fn id(&self) -> Option<u16>;
217 }
218