xref: /aosp_15_r20/external/crosvm/devices/src/usb/xhci/scatter_gather_buffer.rs (revision bb4ee6a4ae7042d18b07a98463b9c8b875e44b39)
1 // Copyright 2019 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 use bit_field::Error as BitFieldError;
6 use remain::sorted;
7 use thiserror::Error;
8 use vm_memory::GuestAddress;
9 use vm_memory::GuestMemory;
10 use vm_memory::GuestMemoryError;
11 
12 use super::xhci_abi::AddressedTrb;
13 use super::xhci_abi::Error as TrbError;
14 use super::xhci_abi::NormalTrb;
15 use super::xhci_abi::TransferDescriptor;
16 use super::xhci_abi::TrbCast;
17 use super::xhci_abi::TrbType;
18 
19 #[sorted]
20 #[derive(Error, Debug)]
21 pub enum Error {
22     #[error("should not build buffer from trb type: {0:?}")]
23     BadTrbType(TrbType),
24     #[error("cannot cast trb: {0}")]
25     CastTrb(TrbError),
26     #[error("immediate data longer than allowed: {0}")]
27     ImmediateDataTooLong(usize),
28     #[error("cannot read guest memory: {0}")]
29     ReadGuestMemory(GuestMemoryError),
30     #[error("unknown trb type: {0}")]
31     UnknownTrbType(BitFieldError),
32     #[error("cannot write guest memory: {0}")]
33     WriteGuestMemory(GuestMemoryError),
34 }
35 
36 type Result<T> = std::result::Result<T, Error>;
37 
38 /// See xHCI spec 3.2.8 for scatter/gather transfer. It's used in bulk/interrupt transfers. See
39 /// 3.2.10 for details.
40 pub struct ScatterGatherBuffer {
41     mem: GuestMemory,
42     td: TransferDescriptor,
43 }
44 
45 impl ScatterGatherBuffer {
46     /// Create a new buffer from transfer descriptor.
new(mem: GuestMemory, td: TransferDescriptor) -> Result<ScatterGatherBuffer>47     pub fn new(mem: GuestMemory, td: TransferDescriptor) -> Result<ScatterGatherBuffer> {
48         for atrb in &td {
49             let trb_type = atrb.trb.get_trb_type().map_err(Error::UnknownTrbType)?;
50             if trb_type != TrbType::Normal
51                 && trb_type != TrbType::DataStage
52                 && trb_type != TrbType::Isoch
53             {
54                 return Err(Error::BadTrbType(trb_type));
55             }
56         }
57         Ok(ScatterGatherBuffer { mem, td })
58     }
59 
60     /// Total len of this buffer.
len(&self) -> Result<usize>61     pub fn len(&self) -> Result<usize> {
62         let mut total_len = 0usize;
63         for atrb in &self.td {
64             total_len += atrb
65                 .trb
66                 .cast::<NormalTrb>()
67                 .map_err(Error::CastTrb)?
68                 .get_trb_transfer_length() as usize;
69         }
70         Ok(total_len)
71     }
72 
is_empty(&self) -> Result<bool>73     pub fn is_empty(&self) -> Result<bool> {
74         Ok(self.len()? == 0)
75     }
76 
77     /// Get the guest address and length of the TRB's data buffer.
78     /// This is usually a separate buffer pointed to by the TRB,
79     /// but it can also be within the TRB itself in the case of immediate data.
get_trb_data(&self, atrb: &AddressedTrb) -> Result<(GuestAddress, usize)>80     fn get_trb_data(&self, atrb: &AddressedTrb) -> Result<(GuestAddress, usize)> {
81         let normal_trb = atrb.trb.cast::<NormalTrb>().map_err(Error::CastTrb)?;
82         let len = normal_trb.get_trb_transfer_length() as usize;
83         let addr = if normal_trb.get_immediate_data() == 1 {
84             // If the Immediate Data flag is set, the first <= 8 bytes of the TRB hold the data.
85             if len > 8 {
86                 return Err(Error::ImmediateDataTooLong(len));
87             }
88             atrb.gpa
89         } else {
90             normal_trb.get_data_buffer()
91         };
92         Ok((GuestAddress(addr), len))
93     }
94 
95     /// Read content to buffer, return number of bytes read.
read(&self, buffer: &mut [u8]) -> Result<usize>96     pub fn read(&self, buffer: &mut [u8]) -> Result<usize> {
97         let mut total_size = 0usize;
98         let mut offset = 0;
99         for atrb in &self.td {
100             let (guest_address, len) = self.get_trb_data(atrb)?;
101             let buffer_len = {
102                 if offset == buffer.len() {
103                     return Ok(total_size);
104                 }
105                 if buffer.len() > offset + len {
106                     len
107                 } else {
108                     buffer.len() - offset
109                 }
110             };
111             let buffer_end = offset + buffer_len;
112             let cur_buffer = &mut buffer[offset..buffer_end];
113             offset = buffer_end;
114             total_size += self
115                 .mem
116                 .read_at_addr(cur_buffer, guest_address)
117                 .map_err(Error::ReadGuestMemory)?;
118         }
119         Ok(total_size)
120     }
121 
122     /// Write content from buffer, return number of bytes written.
write(&self, buffer: &[u8]) -> Result<usize>123     pub fn write(&self, buffer: &[u8]) -> Result<usize> {
124         let mut total_size = 0usize;
125         let mut offset = 0;
126         for atrb in &self.td {
127             let (guest_address, len) = self.get_trb_data(atrb)?;
128             let buffer_len = {
129                 if offset == buffer.len() {
130                     return Ok(total_size);
131                 }
132                 if buffer.len() > offset + len {
133                     len
134                 } else {
135                     buffer.len() - offset
136                 }
137             };
138             let buffer_end = offset + buffer_len;
139             let cur_buffer = &buffer[offset..buffer_end];
140             offset = buffer_end;
141             total_size += self
142                 .mem
143                 .write_at_addr(cur_buffer, guest_address)
144                 .map_err(Error::WriteGuestMemory)?;
145         }
146         Ok(total_size)
147     }
148 }
149 
150 #[cfg(test)]
151 mod test {
152     use base::pagesize;
153 
154     use super::*;
155     use crate::usb::xhci::xhci_abi::AddressedTrb;
156     use crate::usb::xhci::xhci_abi::Trb;
157 
158     #[test]
scatter_gather_buffer_test()159     fn scatter_gather_buffer_test() {
160         let gm = GuestMemory::new(&[(GuestAddress(0), pagesize() as u64)]).unwrap();
161         let mut td = TransferDescriptor::new();
162 
163         // In this td, we are going to have scatter buffer at 0x100, length 4, 0x200 length 2 and
164         // 0x300 length 1.
165 
166         let mut trb = Trb::new();
167         let ntrb = trb.cast_mut::<NormalTrb>().unwrap();
168         ntrb.set_trb_type(TrbType::Normal);
169         ntrb.set_data_buffer(0x100);
170         ntrb.set_trb_transfer_length(4);
171         td.push(AddressedTrb { trb, gpa: 0 });
172 
173         let mut trb = Trb::new();
174         let ntrb = trb.cast_mut::<NormalTrb>().unwrap();
175         ntrb.set_trb_type(TrbType::Normal);
176         ntrb.set_data_buffer(0x200);
177         ntrb.set_trb_transfer_length(2);
178         td.push(AddressedTrb { trb, gpa: 0 });
179 
180         let mut trb = Trb::new();
181         let ntrb = trb.cast_mut::<NormalTrb>().unwrap();
182         ntrb.set_trb_type(TrbType::Normal);
183         ntrb.set_data_buffer(0x300);
184         ntrb.set_trb_transfer_length(1);
185         td.push(AddressedTrb { trb, gpa: 0 });
186 
187         let buffer = ScatterGatherBuffer::new(gm.clone(), td).unwrap();
188 
189         assert_eq!(buffer.len().unwrap(), 7);
190         let data_to_write: [u8; 7] = [7, 6, 5, 4, 3, 2, 1];
191         buffer.write(&data_to_write).unwrap();
192 
193         let mut d = [0; 4];
194         gm.read_exact_at_addr(&mut d, GuestAddress(0x100)).unwrap();
195         assert_eq!(d, [7, 6, 5, 4]);
196         gm.read_exact_at_addr(&mut d, GuestAddress(0x200)).unwrap();
197         assert_eq!(d, [3, 2, 0, 0]);
198         gm.read_exact_at_addr(&mut d, GuestAddress(0x300)).unwrap();
199         assert_eq!(d, [1, 0, 0, 0]);
200 
201         let mut data_read = [0; 7];
202         buffer.read(&mut data_read).unwrap();
203         assert_eq!(data_to_write, data_read);
204     }
205 
206     #[test]
immediate_data_test()207     fn immediate_data_test() {
208         let gm = GuestMemory::new(&[(GuestAddress(0), pagesize() as u64)]).unwrap();
209         let mut td = TransferDescriptor::new();
210 
211         let expected_immediate_data: [u8; 8] = [0xDE, 0xAD, 0xBE, 0xEF, 0xF0, 0x0D, 0xCA, 0xFE];
212 
213         let mut trb = Trb::new();
214         let ntrb = trb.cast_mut::<NormalTrb>().unwrap();
215         ntrb.set_trb_type(TrbType::Normal);
216         ntrb.set_data_buffer(u64::from_le_bytes(expected_immediate_data));
217         ntrb.set_trb_transfer_length(8);
218         ntrb.set_immediate_data(1);
219         td.push(AddressedTrb { trb, gpa: 0xC00 });
220 
221         gm.write_obj_at_addr(trb, GuestAddress(0xc00)).unwrap();
222 
223         let buffer = ScatterGatherBuffer::new(gm, td).unwrap();
224 
225         let mut data_read = [0; 8];
226         buffer.read(&mut data_read).unwrap();
227         assert_eq!(data_read, expected_immediate_data);
228     }
229 }
230