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