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::Interrupter;
6 use super::transfer_ring_controller::{TransferRingController, TransferRingControllerError};
7 use super::usb_hub::{self, UsbHub};
8 use super::xhci_abi::{
9 AddressDeviceCommandTrb, ConfigureEndpointCommandTrb, DequeuePtr, DeviceContext,
10 DeviceSlotState, EndpointContext, EndpointState, EvaluateContextCommandTrb,
11 InputControlContext, SlotContext, TrbCompletionCode, DEVICE_CONTEXT_ENTRY_SIZE,
12 };
13 use super::xhci_regs::{valid_slot_id, MAX_PORTS, MAX_SLOTS};
14 use crate::register_space::Register;
15 use crate::usb::host_backend::error::Error as HostBackendProviderError;
16 use crate::usb::xhci::ring_buffer_stop_cb::{fallible_closure, RingBufferStopCallback};
17 use crate::utils::{EventLoop, FailHandle};
18 use base::error;
19 use bit_field::Error as BitFieldError;
20 use remain::sorted;
21 use std::mem::size_of;
22 use std::sync::atomic::{AtomicBool, Ordering};
23 use std::sync::Arc;
24 use sync::Mutex;
25 use thiserror::Error;
26 use vm_memory::{GuestAddress, GuestMemory, GuestMemoryError};
27
28 #[sorted]
29 #[derive(Error, Debug)]
30 pub enum Error {
31 #[error("bad device context: {0}")]
32 BadDeviceContextAddr(GuestAddress),
33 #[error("bad input context address: {0}")]
34 BadInputContextAddr(GuestAddress),
35 #[error("device slot get a bad port id: {0}")]
36 BadPortId(u8),
37 #[error("callback failed")]
38 CallbackFailed,
39 #[error("failed to create transfer controller: {0}")]
40 CreateTransferController(TransferRingControllerError),
41 #[error("failed to get endpoint state: {0}")]
42 GetEndpointState(BitFieldError),
43 #[error("failed to get port: {0}")]
44 GetPort(u8),
45 #[error("failed to get slot context state: {0}")]
46 GetSlotContextState(BitFieldError),
47 #[error("failed to get trc: {0}")]
48 GetTrc(u8),
49 #[error("failed to read guest memory: {0}")]
50 ReadGuestMemory(GuestMemoryError),
51 #[error("failed to reset port: {0}")]
52 ResetPort(HostBackendProviderError),
53 #[error("failed to upgrade weak reference")]
54 WeakReferenceUpgrade,
55 #[error("failed to write guest memory: {0}")]
56 WriteGuestMemory(GuestMemoryError),
57 }
58
59 type Result<T> = std::result::Result<T, Error>;
60
61 /// See spec 4.5.1 for dci.
62 /// index 0: Control endpoint. Device Context Index: 1.
63 /// index 1: Endpoint 1 out. Device Context Index: 2
64 /// index 2: Endpoint 1 in. Device Context Index: 3.
65 /// index 3: Endpoint 2 out. Device Context Index: 4
66 /// ...
67 /// index 30: Endpoint 15 in. Device Context Index: 31
68 pub const TRANSFER_RING_CONTROLLERS_INDEX_END: usize = 31;
69 /// End of device context index.
70 pub const DCI_INDEX_END: u8 = (TRANSFER_RING_CONTROLLERS_INDEX_END + 1) as u8;
71 /// Device context index of first transfer endpoint.
72 pub const FIRST_TRANSFER_ENDPOINT_DCI: u8 = 2;
73
valid_endpoint_id(endpoint_id: u8) -> bool74 fn valid_endpoint_id(endpoint_id: u8) -> bool {
75 endpoint_id < DCI_INDEX_END && endpoint_id > 0
76 }
77
78 #[derive(Clone)]
79 pub struct DeviceSlots {
80 fail_handle: Arc<dyn FailHandle>,
81 hub: Arc<UsbHub>,
82 slots: Vec<Arc<DeviceSlot>>,
83 }
84
85 impl DeviceSlots {
new( fail_handle: Arc<dyn FailHandle>, dcbaap: Register<u64>, hub: Arc<UsbHub>, interrupter: Arc<Mutex<Interrupter>>, event_loop: Arc<EventLoop>, mem: GuestMemory, ) -> DeviceSlots86 pub fn new(
87 fail_handle: Arc<dyn FailHandle>,
88 dcbaap: Register<u64>,
89 hub: Arc<UsbHub>,
90 interrupter: Arc<Mutex<Interrupter>>,
91 event_loop: Arc<EventLoop>,
92 mem: GuestMemory,
93 ) -> DeviceSlots {
94 let mut slots = Vec::new();
95 for slot_id in 1..=MAX_SLOTS {
96 slots.push(Arc::new(DeviceSlot::new(
97 slot_id,
98 dcbaap.clone(),
99 hub.clone(),
100 interrupter.clone(),
101 event_loop.clone(),
102 mem.clone(),
103 )));
104 }
105 DeviceSlots {
106 fail_handle,
107 hub,
108 slots,
109 }
110 }
111
112 /// Note that slot id starts from 1. Slot index start from 0.
slot(&self, slot_id: u8) -> Option<Arc<DeviceSlot>>113 pub fn slot(&self, slot_id: u8) -> Option<Arc<DeviceSlot>> {
114 if valid_slot_id(slot_id) {
115 Some(self.slots[slot_id as usize - 1].clone())
116 } else {
117 error!(
118 "trying to index a wrong slot id {}, max slot = {}",
119 slot_id, MAX_SLOTS
120 );
121 None
122 }
123 }
124
125 /// Reset the device connected to a specific port.
reset_port(&self, port_id: u8) -> Result<()>126 pub fn reset_port(&self, port_id: u8) -> Result<()> {
127 if let Some(port) = self.hub.get_port(port_id) {
128 if let Some(backend_device) = port.get_backend_device().as_mut() {
129 backend_device.reset().map_err(Error::ResetPort)?;
130 }
131 }
132
133 // No device on port, so nothing to reset.
134 Ok(())
135 }
136
137 /// Stop all device slots and reset them.
stop_all_and_reset<C: FnMut() + 'static + Send>(&self, mut callback: C)138 pub fn stop_all_and_reset<C: FnMut() + 'static + Send>(&self, mut callback: C) {
139 usb_debug!("stopping all device slots and resetting host hub");
140 let slots = self.slots.clone();
141 let hub = self.hub.clone();
142 let auto_callback = RingBufferStopCallback::new(fallible_closure(
143 self.fail_handle.clone(),
144 move || -> std::result::Result<(), usb_hub::Error> {
145 for slot in &slots {
146 slot.reset();
147 }
148 hub.reset()?;
149 callback();
150 Ok(())
151 },
152 ));
153 self.stop_all(auto_callback);
154 }
155
156 /// Stop all devices. The auto callback will be executed when all trc is stopped. It could
157 /// happen asynchronously, if there are any pending transfers.
stop_all(&self, auto_callback: RingBufferStopCallback)158 pub fn stop_all(&self, auto_callback: RingBufferStopCallback) {
159 for slot in &self.slots {
160 slot.stop_all_trc(auto_callback.clone());
161 }
162 }
163
164 /// Disable a slot. This might happen asynchronously, if there is any pending transfers. The
165 /// callback will be invoked when slot is actually disabled.
disable_slot< C: FnMut(TrbCompletionCode) -> std::result::Result<(), ()> + 'static + Send, >( &self, slot_id: u8, cb: C, ) -> Result<()>166 pub fn disable_slot<
167 C: FnMut(TrbCompletionCode) -> std::result::Result<(), ()> + 'static + Send,
168 >(
169 &self,
170 slot_id: u8,
171 cb: C,
172 ) -> Result<()> {
173 usb_debug!("device slot {} is being disabled", slot_id);
174 DeviceSlot::disable(
175 self.fail_handle.clone(),
176 &self.slots[slot_id as usize - 1],
177 cb,
178 )
179 }
180
181 /// Reset a slot. This is a shortcut call for DeviceSlot::reset_slot.
reset_slot< C: FnMut(TrbCompletionCode) -> std::result::Result<(), ()> + 'static + Send, >( &self, slot_id: u8, cb: C, ) -> Result<()>182 pub fn reset_slot<
183 C: FnMut(TrbCompletionCode) -> std::result::Result<(), ()> + 'static + Send,
184 >(
185 &self,
186 slot_id: u8,
187 cb: C,
188 ) -> Result<()> {
189 usb_debug!("device slot {} is resetting", slot_id);
190 DeviceSlot::reset_slot(
191 self.fail_handle.clone(),
192 &self.slots[slot_id as usize - 1],
193 cb,
194 )
195 }
196
stop_endpoint< C: FnMut(TrbCompletionCode) -> std::result::Result<(), ()> + 'static + Send, >( &self, slot_id: u8, endpoint_id: u8, cb: C, ) -> Result<()>197 pub fn stop_endpoint<
198 C: FnMut(TrbCompletionCode) -> std::result::Result<(), ()> + 'static + Send,
199 >(
200 &self,
201 slot_id: u8,
202 endpoint_id: u8,
203 cb: C,
204 ) -> Result<()> {
205 self.slots[slot_id as usize - 1].stop_endpoint(self.fail_handle.clone(), endpoint_id, cb)
206 }
207 }
208
209 // Usb port id. Valid ids starts from 1, to MAX_PORTS.
210 struct PortId(Mutex<u8>);
211
212 impl PortId {
new() -> Self213 fn new() -> Self {
214 PortId(Mutex::new(0))
215 }
216
set(&self, value: u8) -> Result<()>217 fn set(&self, value: u8) -> Result<()> {
218 if !(1..=MAX_PORTS).contains(&value) {
219 return Err(Error::BadPortId(value));
220 }
221 *self.0.lock() = value;
222 Ok(())
223 }
224
reset(&self)225 fn reset(&self) {
226 *self.0.lock() = 0;
227 }
228
get(&self) -> Result<u8>229 fn get(&self) -> Result<u8> {
230 let val = *self.0.lock();
231 if val == 0 {
232 return Err(Error::BadPortId(val));
233 }
234 Ok(val)
235 }
236 }
237
238 pub struct DeviceSlot {
239 slot_id: u8,
240 port_id: PortId, // Valid port id starts from 1, to MAX_PORTS.
241 dcbaap: Register<u64>,
242 hub: Arc<UsbHub>,
243 interrupter: Arc<Mutex<Interrupter>>,
244 event_loop: Arc<EventLoop>,
245 mem: GuestMemory,
246 enabled: AtomicBool,
247 transfer_ring_controllers: Mutex<Vec<Option<Arc<TransferRingController>>>>,
248 }
249
250 impl DeviceSlot {
251 /// Create a new device slot.
new( slot_id: u8, dcbaap: Register<u64>, hub: Arc<UsbHub>, interrupter: Arc<Mutex<Interrupter>>, event_loop: Arc<EventLoop>, mem: GuestMemory, ) -> Self252 pub fn new(
253 slot_id: u8,
254 dcbaap: Register<u64>,
255 hub: Arc<UsbHub>,
256 interrupter: Arc<Mutex<Interrupter>>,
257 event_loop: Arc<EventLoop>,
258 mem: GuestMemory,
259 ) -> Self {
260 let transfer_ring_controllers = vec![None; TRANSFER_RING_CONTROLLERS_INDEX_END];
261 DeviceSlot {
262 slot_id,
263 port_id: PortId::new(),
264 dcbaap,
265 hub,
266 interrupter,
267 event_loop,
268 mem,
269 enabled: AtomicBool::new(false),
270 transfer_ring_controllers: Mutex::new(transfer_ring_controllers),
271 }
272 }
273
get_trc(&self, i: usize) -> Option<Arc<TransferRingController>>274 fn get_trc(&self, i: usize) -> Option<Arc<TransferRingController>> {
275 let trcs = self.transfer_ring_controllers.lock();
276 trcs[i].clone()
277 }
278
set_trc(&self, i: usize, trc: Option<Arc<TransferRingController>>)279 fn set_trc(&self, i: usize, trc: Option<Arc<TransferRingController>>) {
280 let mut trcs = self.transfer_ring_controllers.lock();
281 trcs[i] = trc;
282 }
283
trc_len(&self) -> usize284 fn trc_len(&self) -> usize {
285 self.transfer_ring_controllers.lock().len()
286 }
287
288 /// The arguments are identical to the fields in each doorbell register. The
289 /// target value:
290 /// 1: Reserved
291 /// 2: Control endpoint
292 /// 3: Endpoint 1 out
293 /// 4: Endpoint 1 in
294 /// 5: Endpoint 2 out
295 /// ...
296 /// 32: Endpoint 15 in
297 ///
298 /// Steam ID will be useful when host controller support streams.
299 /// The stream ID must be zero for endpoints that do not have streams
300 /// configured.
301 /// This function will return false if it fails to trigger transfer ring start.
ring_doorbell(&self, target: u8, _stream_id: u16) -> Result<bool>302 pub fn ring_doorbell(&self, target: u8, _stream_id: u16) -> Result<bool> {
303 if !valid_endpoint_id(target) {
304 error!(
305 "device slot {}: Invalid target written to doorbell register. target: {}",
306 self.slot_id, target
307 );
308 return Ok(false);
309 }
310 usb_debug!(
311 "device slot {}: ding-dong. who is that? target = {}",
312 self.slot_id,
313 target
314 );
315 // See DCI in spec.
316 let endpoint_index = (target - 1) as usize;
317 let transfer_ring_controller = match self.get_trc(endpoint_index) {
318 Some(tr) => tr,
319 None => {
320 error!("Device endpoint is not inited");
321 return Ok(false);
322 }
323 };
324 let context = self.get_device_context()?;
325 if context.endpoint_context[endpoint_index]
326 .get_endpoint_state()
327 .map_err(Error::GetEndpointState)?
328 == EndpointState::Running
329 {
330 usb_debug!("endpoint is started, start transfer ring");
331 transfer_ring_controller.start();
332 } else {
333 error!("doorbell rung when endpoint is not started");
334 }
335 Ok(true)
336 }
337
338 /// Enable the slot. This function returns false if it's already enabled.
enable(&self) -> bool339 pub fn enable(&self) -> bool {
340 let was_already_enabled = self.enabled.swap(true, Ordering::SeqCst);
341 if was_already_enabled {
342 error!("device slot is already enabled");
343 } else {
344 usb_debug!("device slot {} enabled", self.slot_id);
345 }
346 !was_already_enabled
347 }
348
349 /// Disable this device slot. If the slot is not enabled, callback will be invoked immediately
350 /// with error. Otherwise, callback will be invoked when all trc is stopped.
disable<C: FnMut(TrbCompletionCode) -> std::result::Result<(), ()> + 'static + Send>( fail_handle: Arc<dyn FailHandle>, slot: &Arc<DeviceSlot>, mut callback: C, ) -> Result<()>351 pub fn disable<C: FnMut(TrbCompletionCode) -> std::result::Result<(), ()> + 'static + Send>(
352 fail_handle: Arc<dyn FailHandle>,
353 slot: &Arc<DeviceSlot>,
354 mut callback: C,
355 ) -> Result<()> {
356 if slot.enabled.load(Ordering::SeqCst) {
357 let slot_weak = Arc::downgrade(slot);
358 let auto_callback =
359 RingBufferStopCallback::new(fallible_closure(fail_handle, move || {
360 // Slot should still be alive when the callback is invoked. If it's not, there
361 // must be a bug somewhere.
362 let slot = slot_weak.upgrade().ok_or(Error::WeakReferenceUpgrade)?;
363 let mut device_context = slot.get_device_context()?;
364 device_context
365 .slot_context
366 .set_slot_state(DeviceSlotState::DisabledOrEnabled);
367 slot.set_device_context(device_context)?;
368 slot.reset();
369 usb_debug!(
370 "device slot {}: all trc disabled, sending trb",
371 slot.slot_id
372 );
373 callback(TrbCompletionCode::Success).map_err(|_| Error::CallbackFailed)
374 }));
375 slot.stop_all_trc(auto_callback);
376 Ok(())
377 } else {
378 callback(TrbCompletionCode::SlotNotEnabledError).map_err(|_| Error::CallbackFailed)
379 }
380 }
381
382 // Assigns the device address and initializes slot and endpoint 0 context.
set_address(&self, trb: &AddressDeviceCommandTrb) -> Result<TrbCompletionCode>383 pub fn set_address(&self, trb: &AddressDeviceCommandTrb) -> Result<TrbCompletionCode> {
384 if !self.enabled.load(Ordering::SeqCst) {
385 error!(
386 "trying to set address to a disabled device slot {}",
387 self.slot_id
388 );
389 return Ok(TrbCompletionCode::SlotNotEnabledError);
390 }
391 let device_context = self.get_device_context()?;
392 let state = device_context
393 .slot_context
394 .get_slot_state()
395 .map_err(Error::GetSlotContextState)?;
396 match state {
397 DeviceSlotState::DisabledOrEnabled => {}
398 DeviceSlotState::Default if !trb.get_block_set_address_request() => {}
399 _ => {
400 error!("slot {} has unexpected slot state", self.slot_id);
401 return Ok(TrbCompletionCode::ContextStateError);
402 }
403 }
404
405 // Copy all fields of the slot context and endpoint 0 context from the input context
406 // to the output context.
407 let input_context_ptr = GuestAddress(trb.get_input_context_pointer());
408 // Copy slot context.
409 self.copy_context(input_context_ptr, 0)?;
410 // Copy control endpoint context.
411 self.copy_context(input_context_ptr, 1)?;
412
413 // Read back device context.
414 let mut device_context = self.get_device_context()?;
415 let port_id = device_context.slot_context.get_root_hub_port_number();
416 self.port_id.set(port_id)?;
417 usb_debug!(
418 "port id {} is assigned to slot id {}",
419 port_id,
420 self.slot_id
421 );
422
423 // Initialize the control endpoint. Endpoint id = 1.
424 self.set_trc(
425 0,
426 Some(
427 TransferRingController::new(
428 self.mem.clone(),
429 self.hub.get_port(port_id).ok_or(Error::GetPort(port_id))?,
430 self.event_loop.clone(),
431 self.interrupter.clone(),
432 self.slot_id,
433 1,
434 )
435 .map_err(Error::CreateTransferController)?,
436 ),
437 );
438
439 // Assign slot ID as device address if block_set_address_request is not set.
440 if trb.get_block_set_address_request() {
441 device_context
442 .slot_context
443 .set_slot_state(DeviceSlotState::Default);
444 } else {
445 let port = self.hub.get_port(port_id).ok_or(Error::GetPort(port_id))?;
446 match port.get_backend_device().as_mut() {
447 Some(backend) => {
448 backend.set_address(self.slot_id as u32);
449 }
450 None => {
451 return Ok(TrbCompletionCode::TransactionError);
452 }
453 }
454
455 device_context
456 .slot_context
457 .set_usb_device_address(self.slot_id);
458 device_context
459 .slot_context
460 .set_slot_state(DeviceSlotState::Addressed);
461 }
462
463 // TODO(jkwang) trc should always exists. Fix this.
464 self.get_trc(0)
465 .ok_or(Error::GetTrc(0))?
466 .set_dequeue_pointer(
467 device_context.endpoint_context[0]
468 .get_tr_dequeue_pointer()
469 .get_gpa(),
470 );
471
472 self.get_trc(0)
473 .ok_or(Error::GetTrc(0))?
474 .set_consumer_cycle_state(device_context.endpoint_context[0].get_dequeue_cycle_state());
475
476 usb_debug!("Setting endpoint 0 to running");
477 device_context.endpoint_context[0].set_endpoint_state(EndpointState::Running);
478 self.set_device_context(device_context)?;
479 Ok(TrbCompletionCode::Success)
480 }
481
482 // Adds or drops multiple endpoints in the device slot.
configure_endpoint( &self, trb: &ConfigureEndpointCommandTrb, ) -> Result<TrbCompletionCode>483 pub fn configure_endpoint(
484 &self,
485 trb: &ConfigureEndpointCommandTrb,
486 ) -> Result<TrbCompletionCode> {
487 usb_debug!("configuring endpoint");
488 let input_control_context = if trb.get_deconfigure() {
489 // From section 4.6.6 of the xHCI spec:
490 // Setting the deconfigure (DC) flag to '1' in the Configure Endpoint Command
491 // TRB is equivalent to setting Input Context Drop Context flags 2-31 to '1'
492 // and Add Context 2-31 flags to '0'.
493 let mut c = InputControlContext::new();
494 c.set_add_context_flags(0);
495 c.set_drop_context_flags(0xfffffffc);
496 c
497 } else {
498 self.mem
499 .read_obj_from_addr(GuestAddress(trb.get_input_context_pointer()))
500 .map_err(Error::ReadGuestMemory)?
501 };
502
503 for device_context_index in 1..DCI_INDEX_END {
504 if input_control_context.drop_context_flag(device_context_index) {
505 self.drop_one_endpoint(device_context_index)?;
506 }
507 if input_control_context.add_context_flag(device_context_index) {
508 self.copy_context(
509 GuestAddress(trb.get_input_context_pointer()),
510 device_context_index,
511 )?;
512 self.add_one_endpoint(device_context_index)?;
513 }
514 }
515
516 if trb.get_deconfigure() {
517 self.set_state(DeviceSlotState::Addressed)?;
518 } else {
519 self.set_state(DeviceSlotState::Configured)?;
520 }
521 Ok(TrbCompletionCode::Success)
522 }
523
524 // Evaluates the device context by reading new values for certain fields of
525 // the slot context and/or control endpoint context.
evaluate_context(&self, trb: &EvaluateContextCommandTrb) -> Result<TrbCompletionCode>526 pub fn evaluate_context(&self, trb: &EvaluateContextCommandTrb) -> Result<TrbCompletionCode> {
527 if !self.enabled.load(Ordering::SeqCst) {
528 return Ok(TrbCompletionCode::SlotNotEnabledError);
529 }
530 // TODO(jkwang) verify this
531 // The spec has multiple contradictions about validating context parameters in sections
532 // 4.6.7, 6.2.3.3. To keep things as simple as possible we do no further validation here.
533 let input_control_context: InputControlContext = self
534 .mem
535 .read_obj_from_addr(GuestAddress(trb.get_input_context_pointer()))
536 .map_err(Error::ReadGuestMemory)?;
537
538 let mut device_context = self.get_device_context()?;
539 if input_control_context.add_context_flag(0) {
540 let input_slot_context: SlotContext = self
541 .mem
542 .read_obj_from_addr(GuestAddress(
543 trb.get_input_context_pointer() + DEVICE_CONTEXT_ENTRY_SIZE as u64,
544 ))
545 .map_err(Error::ReadGuestMemory)?;
546 device_context
547 .slot_context
548 .set_interrupter_target(input_slot_context.get_interrupter_target());
549
550 device_context
551 .slot_context
552 .set_max_exit_latency(input_slot_context.get_max_exit_latency());
553 }
554
555 // From 6.2.3.3: "Endpoint Contexts 2 throught 31 shall not be evaluated by the Evaluate
556 // Context Command".
557 if input_control_context.add_context_flag(1) {
558 let ep0_context: EndpointContext = self
559 .mem
560 .read_obj_from_addr(GuestAddress(
561 trb.get_input_context_pointer() + 2 * DEVICE_CONTEXT_ENTRY_SIZE as u64,
562 ))
563 .map_err(Error::ReadGuestMemory)?;
564 device_context.endpoint_context[0]
565 .set_max_packet_size(ep0_context.get_max_packet_size());
566 }
567 self.set_device_context(device_context)?;
568 Ok(TrbCompletionCode::Success)
569 }
570
571 /// Reset the device slot to default state and deconfigures all but the
572 /// control endpoint.
reset_slot< C: FnMut(TrbCompletionCode) -> std::result::Result<(), ()> + 'static + Send, >( fail_handle: Arc<dyn FailHandle>, slot: &Arc<DeviceSlot>, mut callback: C, ) -> Result<()>573 pub fn reset_slot<
574 C: FnMut(TrbCompletionCode) -> std::result::Result<(), ()> + 'static + Send,
575 >(
576 fail_handle: Arc<dyn FailHandle>,
577 slot: &Arc<DeviceSlot>,
578 mut callback: C,
579 ) -> Result<()> {
580 let weak_s = Arc::downgrade(slot);
581 let auto_callback =
582 RingBufferStopCallback::new(fallible_closure(fail_handle, move || -> Result<()> {
583 let s = weak_s.upgrade().ok_or(Error::WeakReferenceUpgrade)?;
584 for i in FIRST_TRANSFER_ENDPOINT_DCI..DCI_INDEX_END {
585 s.drop_one_endpoint(i)?;
586 }
587 let mut ctx = s.get_device_context()?;
588 ctx.slot_context.set_slot_state(DeviceSlotState::Default);
589 ctx.slot_context.set_context_entries(1);
590 ctx.slot_context.set_root_hub_port_number(0);
591 s.set_device_context(ctx)?;
592 callback(TrbCompletionCode::Success).map_err(|_| Error::CallbackFailed)?;
593 Ok(())
594 }));
595 slot.stop_all_trc(auto_callback);
596 Ok(())
597 }
598
599 /// Stop all transfer ring controllers.
stop_all_trc(&self, auto_callback: RingBufferStopCallback)600 pub fn stop_all_trc(&self, auto_callback: RingBufferStopCallback) {
601 for i in 0..self.trc_len() {
602 if let Some(trc) = self.get_trc(i) {
603 trc.stop(auto_callback.clone());
604 }
605 }
606 }
607
608 /// Stop a endpoint.
stop_endpoint< C: FnMut(TrbCompletionCode) -> std::result::Result<(), ()> + 'static + Send, >( &self, fail_handle: Arc<dyn FailHandle>, endpoint_id: u8, mut cb: C, ) -> Result<()>609 pub fn stop_endpoint<
610 C: FnMut(TrbCompletionCode) -> std::result::Result<(), ()> + 'static + Send,
611 >(
612 &self,
613 fail_handle: Arc<dyn FailHandle>,
614 endpoint_id: u8,
615 mut cb: C,
616 ) -> Result<()> {
617 if !valid_endpoint_id(endpoint_id) {
618 error!("trb indexing wrong endpoint id");
619 return cb(TrbCompletionCode::TrbError).map_err(|_| Error::CallbackFailed);
620 }
621 let index = endpoint_id - 1;
622 match self.get_trc(index as usize) {
623 Some(trc) => {
624 usb_debug!("stopping endpoint");
625 let auto_cb = RingBufferStopCallback::new(fallible_closure(
626 fail_handle,
627 move || -> Result<()> {
628 cb(TrbCompletionCode::Success).map_err(|_| Error::CallbackFailed)
629 },
630 ));
631 trc.stop(auto_cb);
632 }
633 None => {
634 error!("endpoint at index {} is not started", index);
635 cb(TrbCompletionCode::ContextStateError).map_err(|_| Error::CallbackFailed)?;
636 }
637 }
638 Ok(())
639 }
640
641 /// Set transfer ring dequeue pointer.
set_tr_dequeue_ptr(&self, endpoint_id: u8, ptr: u64) -> Result<TrbCompletionCode>642 pub fn set_tr_dequeue_ptr(&self, endpoint_id: u8, ptr: u64) -> Result<TrbCompletionCode> {
643 if !valid_endpoint_id(endpoint_id) {
644 error!("trb indexing wrong endpoint id");
645 return Ok(TrbCompletionCode::TrbError);
646 }
647 let index = (endpoint_id - 1) as usize;
648 match self.get_trc(index) {
649 Some(trc) => {
650 trc.set_dequeue_pointer(GuestAddress(ptr));
651 let mut ctx = self.get_device_context()?;
652 ctx.endpoint_context[index]
653 .set_tr_dequeue_pointer(DequeuePtr::new(GuestAddress(ptr)));
654 self.set_device_context(ctx)?;
655 Ok(TrbCompletionCode::Success)
656 }
657 None => {
658 error!("set tr dequeue ptr failed due to no trc started");
659 Ok(TrbCompletionCode::ContextStateError)
660 }
661 }
662 }
663
664 // Reset and reset_slot are different.
665 // Reset_slot handles command ring `reset slot` command. It will reset the slot state.
666 // Reset handles xhci reset. It will destroy everything.
reset(&self)667 fn reset(&self) {
668 for i in 0..self.trc_len() {
669 self.set_trc(i, None);
670 }
671 usb_debug!("reseting device slot {}!", self.slot_id);
672 self.enabled.store(false, Ordering::SeqCst);
673 self.port_id.reset();
674 }
675
add_one_endpoint(&self, device_context_index: u8) -> Result<()>676 fn add_one_endpoint(&self, device_context_index: u8) -> Result<()> {
677 usb_debug!(
678 "adding one endpoint, device context index {}",
679 device_context_index
680 );
681 let mut device_context = self.get_device_context()?;
682 let transfer_ring_index = (device_context_index - 1) as usize;
683 let trc = TransferRingController::new(
684 self.mem.clone(),
685 self.hub
686 .get_port(self.port_id.get()?)
687 .ok_or(Error::GetPort(self.port_id.get()?))?,
688 self.event_loop.clone(),
689 self.interrupter.clone(),
690 self.slot_id,
691 device_context_index,
692 )
693 .map_err(Error::CreateTransferController)?;
694 trc.set_dequeue_pointer(
695 device_context.endpoint_context[transfer_ring_index]
696 .get_tr_dequeue_pointer()
697 .get_gpa(),
698 );
699 trc.set_consumer_cycle_state(
700 device_context.endpoint_context[transfer_ring_index].get_dequeue_cycle_state(),
701 );
702 self.set_trc(transfer_ring_index, Some(trc));
703 device_context.endpoint_context[transfer_ring_index]
704 .set_endpoint_state(EndpointState::Running);
705 self.set_device_context(device_context)
706 }
707
drop_one_endpoint(&self, device_context_index: u8) -> Result<()>708 fn drop_one_endpoint(&self, device_context_index: u8) -> Result<()> {
709 let endpoint_index = (device_context_index - 1) as usize;
710 self.set_trc(endpoint_index, None);
711 let mut ctx = self.get_device_context()?;
712 ctx.endpoint_context[endpoint_index].set_endpoint_state(EndpointState::Disabled);
713 self.set_device_context(ctx)
714 }
715
get_device_context(&self) -> Result<DeviceContext>716 fn get_device_context(&self) -> Result<DeviceContext> {
717 let ctx = self
718 .mem
719 .read_obj_from_addr(self.get_device_context_addr()?)
720 .map_err(Error::ReadGuestMemory)?;
721 usb_debug!("read device ctx: {:?}", ctx);
722 Ok(ctx)
723 }
724
set_device_context(&self, device_context: DeviceContext) -> Result<()>725 fn set_device_context(&self, device_context: DeviceContext) -> Result<()> {
726 self.mem
727 .write_obj_at_addr(device_context, self.get_device_context_addr()?)
728 .map_err(Error::WriteGuestMemory)
729 }
730
copy_context( &self, input_context_ptr: GuestAddress, device_context_index: u8, ) -> Result<()>731 fn copy_context(
732 &self,
733 input_context_ptr: GuestAddress,
734 device_context_index: u8,
735 ) -> Result<()> {
736 // Note that it could be slot context or device context. They have the same size. Won't
737 // make a difference here.
738 let ctx: EndpointContext = self
739 .mem
740 .read_obj_from_addr(
741 input_context_ptr
742 .checked_add(
743 (device_context_index as u64 + 1) * DEVICE_CONTEXT_ENTRY_SIZE as u64,
744 )
745 .ok_or(Error::BadInputContextAddr(input_context_ptr))?,
746 )
747 .map_err(Error::ReadGuestMemory)?;
748 usb_debug!("context being copied {:?}", ctx);
749 let device_context_ptr = self.get_device_context_addr()?;
750 self.mem
751 .write_obj_at_addr(
752 ctx,
753 device_context_ptr
754 .checked_add(device_context_index as u64 * DEVICE_CONTEXT_ENTRY_SIZE as u64)
755 .ok_or(Error::BadDeviceContextAddr(device_context_ptr))?,
756 )
757 .map_err(Error::WriteGuestMemory)
758 }
759
get_device_context_addr(&self) -> Result<GuestAddress>760 fn get_device_context_addr(&self) -> Result<GuestAddress> {
761 let addr: u64 = self
762 .mem
763 .read_obj_from_addr(GuestAddress(
764 self.dcbaap.get_value() + size_of::<u64>() as u64 * self.slot_id as u64,
765 ))
766 .map_err(Error::ReadGuestMemory)?;
767 Ok(GuestAddress(addr))
768 }
769
set_state(&self, state: DeviceSlotState) -> Result<()>770 fn set_state(&self, state: DeviceSlotState) -> Result<()> {
771 let mut ctx = self.get_device_context()?;
772 ctx.slot_context.set_slot_state(state);
773 self.set_device_context(ctx)
774 }
775 }
776