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::device_slot::{DeviceSlot, DeviceSlots, Error as DeviceSlotError}; 6 use super::interrupter::{Error as InterrupterError, Interrupter}; 7 use super::ring_buffer_controller::{ 8 Error as RingBufferControllerError, RingBufferController, TransferDescriptorHandler, 9 }; 10 use super::xhci_abi::{ 11 AddressDeviceCommandTrb, AddressedTrb, ConfigureEndpointCommandTrb, DisableSlotCommandTrb, 12 Error as TrbError, EvaluateContextCommandTrb, ResetDeviceCommandTrb, 13 SetTRDequeuePointerCommandTrb, StopEndpointCommandTrb, TransferDescriptor, TrbCast, 14 TrbCompletionCode, TrbType, 15 }; 16 use super::xhci_regs::{valid_slot_id, MAX_SLOTS}; 17 use crate::utils::EventLoop; 18 19 use anyhow::Context; 20 use base::{error, warn, Error as SysError, Event}; 21 use remain::sorted; 22 use std::sync::Arc; 23 use sync::Mutex; 24 use thiserror::Error; 25 use vm_memory::{GuestAddress, GuestMemory}; 26 27 #[sorted] 28 #[derive(Error, Debug)] 29 pub enum Error { 30 #[error("bad slot id: {0}")] 31 BadSlotId(u8), 32 #[error("failed to cast trb: {0}")] 33 CastTrb(TrbError), 34 #[error("failed to config endpoint: {0}")] 35 ConfigEndpoint(DeviceSlotError), 36 #[error("failed to disable slot: {0}")] 37 DisableSlot(DeviceSlotError), 38 #[error("failed to evaluate context: {0}")] 39 EvaluateContext(DeviceSlotError), 40 #[error("failed to reset slot: {0}")] 41 ResetSlot(DeviceSlotError), 42 #[error("failed to send interrupt: {0}")] 43 SendInterrupt(InterrupterError), 44 #[error("failed to set address: {0}")] 45 SetAddress(DeviceSlotError), 46 #[error("failed to set dequeue pointer: {0}")] 47 SetDequeuePointer(DeviceSlotError), 48 #[error("failed to stop endpoint: {0}")] 49 StopEndpoint(DeviceSlotError), 50 #[error("failed to write event: {0}")] 51 WriteEvent(SysError), 52 } 53 54 type Result<T> = std::result::Result<T, Error>; 55 56 pub type CommandRingController = RingBufferController<CommandRingTrbHandler>; 57 pub type CommandRingControllerError = RingBufferControllerError; 58 59 impl CommandRingController { new( mem: GuestMemory, event_loop: Arc<EventLoop>, slots: DeviceSlots, interrupter: Arc<Mutex<Interrupter>>, ) -> std::result::Result<Arc<CommandRingController>, RingBufferControllerError>60 pub fn new( 61 mem: GuestMemory, 62 event_loop: Arc<EventLoop>, 63 slots: DeviceSlots, 64 interrupter: Arc<Mutex<Interrupter>>, 65 ) -> std::result::Result<Arc<CommandRingController>, RingBufferControllerError> { 66 RingBufferController::new_with_handler( 67 String::from("command ring"), 68 mem, 69 event_loop, 70 CommandRingTrbHandler::new(slots, interrupter), 71 ) 72 } 73 } 74 75 pub struct CommandRingTrbHandler { 76 slots: DeviceSlots, 77 interrupter: Arc<Mutex<Interrupter>>, 78 } 79 80 impl CommandRingTrbHandler { new(slots: DeviceSlots, interrupter: Arc<Mutex<Interrupter>>) -> Self81 fn new(slots: DeviceSlots, interrupter: Arc<Mutex<Interrupter>>) -> Self { 82 CommandRingTrbHandler { slots, interrupter } 83 } 84 slot(&self, slot_id: u8) -> Result<Arc<DeviceSlot>>85 fn slot(&self, slot_id: u8) -> Result<Arc<DeviceSlot>> { 86 self.slots.slot(slot_id).ok_or(Error::BadSlotId(slot_id)) 87 } 88 command_completion_callback( interrupter: &Arc<Mutex<Interrupter>>, completion_code: TrbCompletionCode, slot_id: u8, trb_addr: u64, event: &Event, ) -> Result<()>89 fn command_completion_callback( 90 interrupter: &Arc<Mutex<Interrupter>>, 91 completion_code: TrbCompletionCode, 92 slot_id: u8, 93 trb_addr: u64, 94 event: &Event, 95 ) -> Result<()> { 96 interrupter 97 .lock() 98 .send_command_completion_trb(completion_code, slot_id, GuestAddress(trb_addr)) 99 .map_err(Error::SendInterrupt)?; 100 event.write(1).map_err(Error::WriteEvent) 101 } 102 enable_slot(&self, atrb: &AddressedTrb, event: Event) -> Result<()>103 fn enable_slot(&self, atrb: &AddressedTrb, event: Event) -> Result<()> { 104 for slot_id in 1..=MAX_SLOTS { 105 if self.slot(slot_id)?.enable() { 106 return CommandRingTrbHandler::command_completion_callback( 107 &self.interrupter, 108 TrbCompletionCode::Success, 109 slot_id, 110 atrb.gpa, 111 &event, 112 ); 113 } 114 } 115 116 CommandRingTrbHandler::command_completion_callback( 117 &self.interrupter, 118 TrbCompletionCode::NoSlotsAvailableError, 119 0, 120 atrb.gpa, 121 &event, 122 ) 123 } 124 disable_slot(&self, atrb: &AddressedTrb, event: Event) -> Result<()>125 fn disable_slot(&self, atrb: &AddressedTrb, event: Event) -> Result<()> { 126 let trb = atrb 127 .trb 128 .cast::<DisableSlotCommandTrb>() 129 .map_err(Error::CastTrb)?; 130 let slot_id = trb.get_slot_id(); 131 if valid_slot_id(slot_id) { 132 let gpa = atrb.gpa; 133 let interrupter = self.interrupter.clone(); 134 self.slots 135 .disable_slot(slot_id, move |completion_code| { 136 CommandRingTrbHandler::command_completion_callback( 137 &interrupter, 138 completion_code, 139 slot_id, 140 gpa, 141 &event, 142 ) 143 .map_err(|e| { 144 error!("failed to run command completion callback: {}", e); 145 }) 146 }) 147 .map_err(Error::DisableSlot) 148 } else { 149 CommandRingTrbHandler::command_completion_callback( 150 &self.interrupter, 151 TrbCompletionCode::TrbError, 152 slot_id, 153 atrb.gpa, 154 &event, 155 ) 156 } 157 } 158 address_device(&self, atrb: &AddressedTrb, event: Event) -> Result<()>159 fn address_device(&self, atrb: &AddressedTrb, event: Event) -> Result<()> { 160 let trb = atrb 161 .trb 162 .cast::<AddressDeviceCommandTrb>() 163 .map_err(Error::CastTrb)?; 164 let slot_id = trb.get_slot_id(); 165 let completion_code = { 166 if valid_slot_id(slot_id) { 167 self.slot(slot_id)? 168 .set_address(trb) 169 .map_err(Error::SetAddress)? 170 } else { 171 TrbCompletionCode::TrbError 172 } 173 }; 174 CommandRingTrbHandler::command_completion_callback( 175 &self.interrupter, 176 completion_code, 177 slot_id, 178 atrb.gpa, 179 &event, 180 ) 181 } 182 configure_endpoint(&self, atrb: &AddressedTrb, event: Event) -> Result<()>183 fn configure_endpoint(&self, atrb: &AddressedTrb, event: Event) -> Result<()> { 184 let trb = atrb 185 .trb 186 .cast::<ConfigureEndpointCommandTrb>() 187 .map_err(Error::CastTrb)?; 188 let slot_id = trb.get_slot_id(); 189 let completion_code = { 190 if valid_slot_id(slot_id) { 191 self.slot(slot_id)? 192 .configure_endpoint(trb) 193 .map_err(Error::ConfigEndpoint)? 194 } else { 195 TrbCompletionCode::TrbError 196 } 197 }; 198 CommandRingTrbHandler::command_completion_callback( 199 &self.interrupter, 200 completion_code, 201 slot_id, 202 atrb.gpa, 203 &event, 204 ) 205 } 206 evaluate_context(&self, atrb: &AddressedTrb, event: Event) -> Result<()>207 fn evaluate_context(&self, atrb: &AddressedTrb, event: Event) -> Result<()> { 208 let trb = atrb 209 .trb 210 .cast::<EvaluateContextCommandTrb>() 211 .map_err(Error::CastTrb)?; 212 let slot_id = trb.get_slot_id(); 213 let completion_code = { 214 if valid_slot_id(slot_id) { 215 self.slot(slot_id)? 216 .evaluate_context(trb) 217 .map_err(Error::EvaluateContext)? 218 } else { 219 TrbCompletionCode::TrbError 220 } 221 }; 222 CommandRingTrbHandler::command_completion_callback( 223 &self.interrupter, 224 completion_code, 225 slot_id, 226 atrb.gpa, 227 &event, 228 ) 229 } 230 reset_device(&self, atrb: &AddressedTrb, event: Event) -> Result<()>231 fn reset_device(&self, atrb: &AddressedTrb, event: Event) -> Result<()> { 232 let trb = atrb 233 .trb 234 .cast::<ResetDeviceCommandTrb>() 235 .map_err(Error::CastTrb)?; 236 let slot_id = trb.get_slot_id(); 237 if valid_slot_id(slot_id) { 238 let gpa = atrb.gpa; 239 let interrupter = self.interrupter.clone(); 240 self.slots 241 .reset_slot(slot_id, move |completion_code| { 242 CommandRingTrbHandler::command_completion_callback( 243 &interrupter, 244 completion_code, 245 slot_id, 246 gpa, 247 &event, 248 ) 249 .map_err(|e| { 250 error!("command completion callback failed: {}", e); 251 }) 252 }) 253 .map_err(Error::ResetSlot) 254 } else { 255 CommandRingTrbHandler::command_completion_callback( 256 &self.interrupter, 257 TrbCompletionCode::TrbError, 258 slot_id, 259 atrb.gpa, 260 &event, 261 ) 262 } 263 } 264 stop_endpoint(&self, atrb: &AddressedTrb, event: Event) -> Result<()>265 fn stop_endpoint(&self, atrb: &AddressedTrb, event: Event) -> Result<()> { 266 let trb = atrb 267 .trb 268 .cast::<StopEndpointCommandTrb>() 269 .map_err(Error::CastTrb)?; 270 let slot_id = trb.get_slot_id(); 271 let endpoint_id = trb.get_endpoint_id(); 272 if valid_slot_id(slot_id) { 273 let gpa = atrb.gpa; 274 let interrupter = self.interrupter.clone(); 275 self.slots 276 .stop_endpoint(slot_id, endpoint_id, move |completion_code| { 277 CommandRingTrbHandler::command_completion_callback( 278 &interrupter, 279 completion_code, 280 slot_id, 281 gpa, 282 &event, 283 ) 284 .map_err(|e| { 285 error!("command completion callback failed: {}", e); 286 }) 287 }) 288 .map_err(Error::StopEndpoint)?; 289 Ok(()) 290 } else { 291 error!("stop endpoint trb has invalid slot id {}", slot_id); 292 CommandRingTrbHandler::command_completion_callback( 293 &self.interrupter, 294 TrbCompletionCode::TrbError, 295 slot_id, 296 atrb.gpa, 297 &event, 298 ) 299 } 300 } 301 set_tr_dequeue_ptr(&self, atrb: &AddressedTrb, event: Event) -> Result<()>302 fn set_tr_dequeue_ptr(&self, atrb: &AddressedTrb, event: Event) -> Result<()> { 303 let trb = atrb 304 .trb 305 .cast::<SetTRDequeuePointerCommandTrb>() 306 .map_err(Error::CastTrb)?; 307 let slot_id = trb.get_slot_id(); 308 let endpoint_id = trb.get_endpoint_id(); 309 // See Set TR Dequeue Pointer Trb in spec. 310 let dequeue_ptr = trb.get_dequeue_ptr().get_gpa().offset(); 311 let completion_code = { 312 if valid_slot_id(slot_id) { 313 self.slot(slot_id)? 314 .set_tr_dequeue_ptr(endpoint_id, dequeue_ptr) 315 .map_err(Error::SetDequeuePointer)? 316 } else { 317 error!("stop endpoint trb has invalid slot id {}", slot_id); 318 TrbCompletionCode::TrbError 319 } 320 }; 321 CommandRingTrbHandler::command_completion_callback( 322 &self.interrupter, 323 completion_code, 324 slot_id, 325 atrb.gpa, 326 &event, 327 ) 328 } 329 } 330 331 impl TransferDescriptorHandler for CommandRingTrbHandler { handle_transfer_descriptor( &self, descriptor: TransferDescriptor, complete_event: Event, ) -> anyhow::Result<()>332 fn handle_transfer_descriptor( 333 &self, 334 descriptor: TransferDescriptor, 335 complete_event: Event, 336 ) -> anyhow::Result<()> { 337 // Command descriptor always consist of a single TRB. 338 assert_eq!(descriptor.len(), 1); 339 let atrb = &descriptor[0]; 340 let command_result = match atrb.trb.get_trb_type() { 341 Ok(TrbType::EnableSlotCommand) => self.enable_slot(atrb, complete_event), 342 Ok(TrbType::DisableSlotCommand) => self.disable_slot(atrb, complete_event), 343 Ok(TrbType::AddressDeviceCommand) => self.address_device(atrb, complete_event), 344 Ok(TrbType::ConfigureEndpointCommand) => self.configure_endpoint(atrb, complete_event), 345 Ok(TrbType::EvaluateContextCommand) => self.evaluate_context(atrb, complete_event), 346 Ok(TrbType::ResetDeviceCommand) => self.reset_device(atrb, complete_event), 347 Ok(TrbType::NoopCommand) => CommandRingTrbHandler::command_completion_callback( 348 &self.interrupter, 349 TrbCompletionCode::Success, 350 0, 351 atrb.gpa, 352 &complete_event, 353 ), 354 Ok(TrbType::ResetEndpointCommand) => { 355 error!( 356 "Receiving reset endpoint command. \ 357 It should only happen when cmd ring stall" 358 ); 359 CommandRingTrbHandler::command_completion_callback( 360 &self.interrupter, 361 TrbCompletionCode::TrbError, 362 0, 363 atrb.gpa, 364 &complete_event, 365 ) 366 } 367 Ok(TrbType::StopEndpointCommand) => self.stop_endpoint(atrb, complete_event), 368 Ok(TrbType::SetTRDequeuePointerCommand) => { 369 self.set_tr_dequeue_ptr(atrb, complete_event) 370 } 371 _ => { 372 warn!( 373 // We are not handling type 14,15,16. See table 6.4.6. 374 "Unexpected command ring trb type: {}", 375 atrb.trb 376 ); 377 match self.interrupter.lock().send_command_completion_trb( 378 TrbCompletionCode::TrbError, 379 0, 380 GuestAddress(atrb.gpa), 381 ) { 382 Err(e) => Err(Error::SendInterrupt(e)), 383 Ok(_) => complete_event.write(1).map_err(Error::WriteEvent), 384 } 385 } 386 }; 387 command_result.context("command ring TRB failed") 388 } 389 } 390