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