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