• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2019 The Chromium OS Authors. All rights reserved.
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 super::interrupter::{Error as InterrupterError, Interrupter};
6 use super::scatter_gather_buffer::{Error as BufferError, ScatterGatherBuffer};
7 use super::usb_hub::{Error as HubError, UsbPort};
8 use super::xhci_abi::{
9     AddressedTrb, Error as TrbError, EventDataTrb, SetupStageTrb, TransferDescriptor, TrbCast,
10     TrbCompletionCode, TrbType,
11 };
12 use super::xhci_regs::MAX_INTERRUPTER;
13 use base::{error, Error as SysError, Event};
14 use bit_field::Error as BitFieldError;
15 use remain::sorted;
16 use std::cmp::min;
17 use std::fmt::{self, Display};
18 use std::mem;
19 use std::sync::{Arc, Weak};
20 use sync::Mutex;
21 use thiserror::Error;
22 use usb_util::{TransferStatus, UsbRequestSetup};
23 use vm_memory::GuestMemory;
24 
25 #[sorted]
26 #[derive(Error, Debug)]
27 pub enum Error {
28     #[error("unexpected trb type: {0:?}")]
29     BadTrbType(TrbType),
30     #[error("cannot cast trb: {0}")]
31     CastTrb(TrbError),
32     #[error("cannot create transfer buffer: {0}")]
33     CreateBuffer(BufferError),
34     #[error("cannot detach from port: {0}")]
35     DetachPort(HubError),
36     #[error("cannot send interrupt: {0}")]
37     SendInterrupt(InterrupterError),
38     #[error("failed to submit transfer to backend")]
39     SubmitTransfer,
40     #[error("cannot get transfer length: {0}")]
41     TransferLength(TrbError),
42     #[error("cannot get trb type: {0}")]
43     TrbType(BitFieldError),
44     #[error("cannot write completion event: {0}")]
45     WriteCompletionEvent(SysError),
46 }
47 
48 type Result<T> = std::result::Result<T, Error>;
49 
50 /// Type of usb endpoints.
51 #[derive(PartialEq, Clone, Copy, Debug)]
52 pub enum TransferDirection {
53     In,
54     Out,
55     Control,
56 }
57 
58 /// Current state of xhci transfer.
59 pub enum XhciTransferState {
60     Created,
61     /// When transfer is submitted, it will contain a transfer callback, which should be invoked
62     /// when the transfer is cancelled.
63     Submitted {
64         cancel_callback: Box<dyn FnOnce() + Send>,
65     },
66     Cancelling,
67     Cancelled,
68     Completed,
69 }
70 
71 impl XhciTransferState {
72     /// Try to cancel this transfer, if it's possible.
try_cancel(&mut self)73     pub fn try_cancel(&mut self) {
74         match mem::replace(self, XhciTransferState::Created) {
75             XhciTransferState::Submitted { cancel_callback } => {
76                 *self = XhciTransferState::Cancelling;
77                 cancel_callback();
78             }
79             XhciTransferState::Cancelling => {
80                 error!("Another cancellation is already issued.");
81             }
82             _ => {
83                 *self = XhciTransferState::Cancelled;
84             }
85         }
86     }
87 }
88 
89 /// Type of a transfer received handled by transfer ring.
90 pub enum XhciTransferType {
91     // Normal means bulk transfer or interrupt transfer, depending on endpoint type.
92     // See spec 4.11.2.1.
93     Normal(ScatterGatherBuffer),
94     // See usb spec for setup stage, data stage and status stage,
95     // see xHCI spec 4.11.2.2 for corresponding trbs.
96     SetupStage(UsbRequestSetup),
97     DataStage(ScatterGatherBuffer),
98     StatusStage,
99     // See xHCI spec 4.11.2.3.
100     Isochronous(ScatterGatherBuffer),
101     // See xHCI spec 6.4.1.4.
102     Noop,
103 }
104 
105 impl Display for XhciTransferType {
fmt(&self, f: &mut fmt::Formatter) -> fmt::Result106     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
107         use self::XhciTransferType::*;
108 
109         match self {
110             Normal(_) => write!(f, "Normal"),
111             SetupStage(_) => write!(f, "SetupStage"),
112             DataStage(_) => write!(f, "DataStage"),
113             StatusStage => write!(f, "StatusStage"),
114             Isochronous(_) => write!(f, "Isochronous"),
115             Noop => write!(f, "Noop"),
116         }
117     }
118 }
119 
120 impl XhciTransferType {
121     /// Analyze transfer descriptor and return transfer type.
new(mem: GuestMemory, td: TransferDescriptor) -> Result<XhciTransferType>122     pub fn new(mem: GuestMemory, td: TransferDescriptor) -> Result<XhciTransferType> {
123         // We can figure out transfer type from the first trb.
124         // See transfer descriptor description in xhci spec for more details.
125         match td[0].trb.get_trb_type().map_err(Error::TrbType)? {
126             TrbType::Normal => {
127                 let buffer = ScatterGatherBuffer::new(mem, td).map_err(Error::CreateBuffer)?;
128                 Ok(XhciTransferType::Normal(buffer))
129             }
130             TrbType::SetupStage => {
131                 let trb = td[0].trb.cast::<SetupStageTrb>().map_err(Error::CastTrb)?;
132                 Ok(XhciTransferType::SetupStage(UsbRequestSetup::new(
133                     trb.get_request_type(),
134                     trb.get_request(),
135                     trb.get_value(),
136                     trb.get_index(),
137                     trb.get_length(),
138                 )))
139             }
140             TrbType::DataStage => {
141                 let buffer = ScatterGatherBuffer::new(mem, td).map_err(Error::CreateBuffer)?;
142                 Ok(XhciTransferType::DataStage(buffer))
143             }
144             TrbType::StatusStage => Ok(XhciTransferType::StatusStage),
145             TrbType::Isoch => {
146                 let buffer = ScatterGatherBuffer::new(mem, td).map_err(Error::CreateBuffer)?;
147                 Ok(XhciTransferType::Isochronous(buffer))
148             }
149             TrbType::Noop => Ok(XhciTransferType::Noop),
150             t => Err(Error::BadTrbType(t)),
151         }
152     }
153 }
154 
155 /// Xhci Transfer manager holds reference to all ongoing transfers. Can cancel them all if
156 /// needed.
157 #[derive(Clone)]
158 pub struct XhciTransferManager {
159     transfers: Arc<Mutex<Vec<Weak<Mutex<XhciTransferState>>>>>,
160 }
161 
162 impl XhciTransferManager {
163     /// Create a new manager.
new() -> XhciTransferManager164     pub fn new() -> XhciTransferManager {
165         XhciTransferManager {
166             transfers: Arc::new(Mutex::new(Vec::new())),
167         }
168     }
169 
170     /// Build a new XhciTransfer. Endpoint id is the id in xHCI device slot.
create_transfer( &self, mem: GuestMemory, port: Arc<UsbPort>, interrupter: Arc<Mutex<Interrupter>>, slot_id: u8, endpoint_id: u8, transfer_trbs: TransferDescriptor, completion_event: Event, ) -> XhciTransfer171     pub fn create_transfer(
172         &self,
173         mem: GuestMemory,
174         port: Arc<UsbPort>,
175         interrupter: Arc<Mutex<Interrupter>>,
176         slot_id: u8,
177         endpoint_id: u8,
178         transfer_trbs: TransferDescriptor,
179         completion_event: Event,
180     ) -> XhciTransfer {
181         assert!(!transfer_trbs.is_empty());
182         let transfer_dir = {
183             if endpoint_id == 0 {
184                 TransferDirection::Control
185             } else if (endpoint_id % 2) == 0 {
186                 TransferDirection::Out
187             } else {
188                 TransferDirection::In
189             }
190         };
191         let t = XhciTransfer {
192             manager: self.clone(),
193             state: Arc::new(Mutex::new(XhciTransferState::Created)),
194             mem,
195             port,
196             interrupter,
197             transfer_completion_event: completion_event,
198             slot_id,
199             endpoint_id,
200             transfer_dir,
201             transfer_trbs,
202         };
203         self.transfers.lock().push(Arc::downgrade(&t.state));
204         t
205     }
206 
207     /// Cancel all current transfers.
cancel_all(&self)208     pub fn cancel_all(&self) {
209         self.transfers.lock().iter().for_each(|t| {
210             let state = match t.upgrade() {
211                 Some(state) => state,
212                 None => {
213                     error!("transfer is already cancelled or finished");
214                     return;
215                 }
216             };
217             state.lock().try_cancel();
218         });
219     }
220 
remove_transfer(&self, t: &Arc<Mutex<XhciTransferState>>)221     fn remove_transfer(&self, t: &Arc<Mutex<XhciTransferState>>) {
222         let mut transfers = self.transfers.lock();
223         match transfers.iter().position(|wt| match wt.upgrade() {
224             Some(wt) => Arc::ptr_eq(&wt, t),
225             None => false,
226         }) {
227             None => error!("attempted to remove unknow transfer"),
228             Some(i) => {
229                 transfers.swap_remove(i);
230             }
231         }
232     }
233 }
234 
235 /// Xhci transfer denotes a transfer initiated by guest os driver. It will be submitted to a
236 /// XhciBackendDevice.
237 pub struct XhciTransfer {
238     manager: XhciTransferManager,
239     state: Arc<Mutex<XhciTransferState>>,
240     mem: GuestMemory,
241     port: Arc<UsbPort>,
242     interrupter: Arc<Mutex<Interrupter>>,
243     slot_id: u8,
244     // id of endpoint in device slot.
245     endpoint_id: u8,
246     transfer_dir: TransferDirection,
247     transfer_trbs: TransferDescriptor,
248     transfer_completion_event: Event,
249 }
250 
251 impl Drop for XhciTransfer {
drop(&mut self)252     fn drop(&mut self) {
253         self.manager.remove_transfer(&self.state);
254     }
255 }
256 
257 impl fmt::Debug for XhciTransfer {
fmt(&self, f: &mut fmt::Formatter) -> fmt::Result258     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
259         write!(
260             f,
261             "xhci_transfer slot id: {}, endpoint id {}, transfer_dir {:?}, transfer_trbs {:?}",
262             self.slot_id, self.endpoint_id, self.transfer_dir, self.transfer_trbs
263         )
264     }
265 }
266 
267 impl XhciTransfer {
268     /// Get state of this transfer.
state(&self) -> &Arc<Mutex<XhciTransferState>>269     pub fn state(&self) -> &Arc<Mutex<XhciTransferState>> {
270         &self.state
271     }
272 
273     /// Get transfer type.
get_transfer_type(&self) -> Result<XhciTransferType>274     pub fn get_transfer_type(&self) -> Result<XhciTransferType> {
275         XhciTransferType::new(self.mem.clone(), self.transfer_trbs.clone())
276     }
277 
278     /// Get endpoint number.
get_endpoint_number(&self) -> u8279     pub fn get_endpoint_number(&self) -> u8 {
280         // See spec 4.5.1 for dci.
281         self.endpoint_id / 2
282     }
283 
284     /// get transfer direction.
get_transfer_dir(&self) -> TransferDirection285     pub fn get_transfer_dir(&self) -> TransferDirection {
286         self.transfer_dir
287     }
288 
289     /// This functions should be invoked when transfer is completed (or failed).
on_transfer_complete( &self, status: &TransferStatus, bytes_transferred: u32, ) -> Result<()>290     pub fn on_transfer_complete(
291         &self,
292         status: &TransferStatus,
293         bytes_transferred: u32,
294     ) -> Result<()> {
295         match status {
296             TransferStatus::NoDevice => {
297                 usb_debug!("device disconnected, detaching from port");
298                 // If the device is gone, we don't need to send transfer completion event, cause we
299                 // are going to destroy everything related to this device anyway.
300                 return match self.port.detach() {
301                     Ok(()) => Ok(()),
302                     // It's acceptable for the port to be already disconnected
303                     // as asynchronous transfer completions are processed.
304                     Err(HubError::AlreadyDetached(_e)) => Ok(()),
305                     Err(e) => Err(Error::DetachPort(e)),
306                 };
307             }
308             TransferStatus::Cancelled => {
309                 // TODO(jkwang) According to the spec, we should send a stopped event here. But
310                 // kernel driver does not do anything meaningful when it sees a stopped event.
311                 return self
312                     .transfer_completion_event
313                     .write(1)
314                     .map_err(Error::WriteCompletionEvent);
315             }
316             TransferStatus::Completed => {
317                 self.transfer_completion_event
318                     .write(1)
319                     .map_err(Error::WriteCompletionEvent)?;
320             }
321             _ => {
322                 // Transfer failed, we are not handling this correctly yet. Guest kernel might see
323                 // short packets for in transfer and might think control transfer is successful. It
324                 // will eventually find out device is in a wrong state.
325                 self.transfer_completion_event
326                     .write(1)
327                     .map_err(Error::WriteCompletionEvent)?;
328             }
329         }
330 
331         let mut edtla: u32 = 0;
332         // As noted in xHCI spec 4.11.3.1
333         // Transfer Event TRB only occurs under the following conditions:
334         //   1. If the Interrupt On Completion flag is set.
335         //   2. When a short transfer occurs during the execution of a Transfer TRB and the
336         //      Interrupt-on-Short Packet flag is set.
337         //   3. If an error occurs during the execution of a Transfer TRB.
338         // Errors are handled above, so just check for the two flags.
339         for atrb in &self.transfer_trbs {
340             edtla += atrb.trb.transfer_length().map_err(Error::TransferLength)?;
341             if atrb.trb.interrupt_on_completion()
342                 || (atrb.trb.interrupt_on_short_packet() && edtla > bytes_transferred)
343             {
344                 // For details about event data trb and EDTLA, see spec 4.11.5.2.
345                 if atrb.trb.get_trb_type().map_err(Error::TrbType)? == TrbType::EventData {
346                     let tlength = min(edtla, bytes_transferred);
347                     self.interrupter
348                         .lock()
349                         .send_transfer_event_trb(
350                             TrbCompletionCode::Success,
351                             atrb.trb
352                                 .cast::<EventDataTrb>()
353                                 .map_err(Error::CastTrb)?
354                                 .get_event_data(),
355                             tlength,
356                             true,
357                             self.slot_id,
358                             self.endpoint_id,
359                         )
360                         .map_err(Error::SendInterrupt)?;
361                 } else {
362                     // For Short Transfer details, see xHCI spec 4.10.1.1.
363                     if edtla > bytes_transferred {
364                         usb_debug!("on transfer complete short packet");
365                         let residual_transfer_length = edtla - bytes_transferred;
366                         self.interrupter
367                             .lock()
368                             .send_transfer_event_trb(
369                                 TrbCompletionCode::ShortPacket,
370                                 atrb.gpa,
371                                 residual_transfer_length,
372                                 true,
373                                 self.slot_id,
374                                 self.endpoint_id,
375                             )
376                             .map_err(Error::SendInterrupt)?;
377                     } else {
378                         usb_debug!("on transfer complete success");
379                         self.interrupter
380                             .lock()
381                             .send_transfer_event_trb(
382                                 TrbCompletionCode::Success,
383                                 atrb.gpa,
384                                 0, // transfer length
385                                 true,
386                                 self.slot_id,
387                                 self.endpoint_id,
388                             )
389                             .map_err(Error::SendInterrupt)?;
390                     }
391                 }
392             }
393         }
394         Ok(())
395     }
396 
397     /// Send this transfer to backend if it's a valid transfer.
send_to_backend_if_valid(self) -> Result<()>398     pub fn send_to_backend_if_valid(self) -> Result<()> {
399         if self.validate_transfer()? {
400             // Backend should invoke on transfer complete when transfer is completed.
401             let port = self.port.clone();
402             let mut backend = port.get_backend_device();
403             match &mut *backend {
404                 Some(backend) => backend
405                     .submit_transfer(self)
406                     .map_err(|_| Error::SubmitTransfer)?,
407                 None => {
408                     error!("backend is already disconnected");
409                     self.transfer_completion_event
410                         .write(1)
411                         .map_err(Error::WriteCompletionEvent)?;
412                 }
413             }
414         } else {
415             error!("invalid td on transfer ring");
416             self.transfer_completion_event
417                 .write(1)
418                 .map_err(Error::WriteCompletionEvent)?;
419         }
420         Ok(())
421     }
422 
423     // Check each trb in the transfer descriptor for invalid or out of bounds
424     // parameters. Returns true iff the transfer descriptor is valid.
validate_transfer(&self) -> Result<bool>425     fn validate_transfer(&self) -> Result<bool> {
426         let mut valid = true;
427         for atrb in &self.transfer_trbs {
428             if !trb_is_valid(atrb) {
429                 self.interrupter
430                     .lock()
431                     .send_transfer_event_trb(
432                         TrbCompletionCode::TrbError,
433                         atrb.gpa,
434                         0,
435                         false,
436                         self.slot_id,
437                         self.endpoint_id,
438                     )
439                     .map_err(Error::SendInterrupt)?;
440                 valid = false;
441             }
442         }
443         Ok(valid)
444     }
445 }
446 
trb_is_valid(atrb: &AddressedTrb) -> bool447 fn trb_is_valid(atrb: &AddressedTrb) -> bool {
448     let can_be_in_transfer_ring = match atrb.trb.can_be_in_transfer_ring() {
449         Ok(v) => v,
450         Err(e) => {
451             error!("unknown error {:?}", e);
452             return false;
453         }
454     };
455     can_be_in_transfer_ring && (atrb.trb.interrupter_target() < MAX_INTERRUPTER)
456 }
457