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