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