1#![allow(clippy::result_large_err)]
6
7use std::sync::Arc;
8
9use anyhow::Context;
10use base::error;
11use base::warn;
12use base::Error as SysError;
13use base::Event;
14use remain::sorted;
15use sync::Mutex;
16use thiserror::Error;
17use vm_memory::GuestAddress;
18use vm_memory::GuestMemory;
19
20use super::device_slot::DeviceSlot;
21use super::device_slot::DeviceSlots;
22use super::device_slot::Error as DeviceSlotError;
23use super::interrupter::Error as InterrupterError;
24use super::interrupter::Interrupter;
25use super::ring_buffer_controller::Error as RingBufferControllerError;
26use super::ring_buffer_controller::RingBufferController;
27use super::ring_buffer_controller::TransferDescriptorHandler;
28use super::xhci_abi::AddressDeviceCommandTrb;
29use super::xhci_abi::AddressedTrb;
30use super::xhci_abi::ConfigureEndpointCommandTrb;
31use super::xhci_abi::DisableSlotCommandTrb;
32use super::xhci_abi::Error as TrbError;
33use super::xhci_abi::EvaluateContextCommandTrb;
34use super::xhci_abi::ResetDeviceCommandTrb;
35use super::xhci_abi::ResetEndpointCommandTrb;
36use super::xhci_abi::SetTRDequeuePointerCommandTrb;
37use super::xhci_abi::StopEndpointCommandTrb;
38use super::xhci_abi::TransferDescriptor;
39use super::xhci_abi::TrbCast;
40use super::xhci_abi::TrbCompletionCode;
41use super::xhci_abi::TrbType;
42use super::xhci_regs::valid_slot_id;
43use super::xhci_regs::MAX_SLOTS;
44use crate::utils::EventLoop;
45
46#[sorted]
47#[derive(Error, Debug)]
48pub 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
73type Result<T> = std::result::Result<T, Error>;
74
75pub type CommandRingController = RingBufferController<CommandRingTrbHandler>;
76pub type CommandRingControllerError = RingBufferControllerError;
77
78impl CommandRingController {
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
94pub struct CommandRingTrbHandler {
95 slots: DeviceSlots,
96 interrupter: Arc<Mutex<Interrupter>>,
97}
98
99impl CommandRingTrbHandler {
100 fn new(slots: DeviceSlots, interrupter: Arc<Mutex<Interrupter>>) -> Self {
101 CommandRingTrbHandler { slots, interrupter }
102 }
103
104 fn slot(&self, slot_id: u8) -> Result<Arc<DeviceSlot>> {
105 self.slots.slot(slot_id).ok_or(Error::BadSlotId(slot_id))
106 }
107
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
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
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
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
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
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
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
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
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
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 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
388impl TransferDescriptorHandler for CommandRingTrbHandler {
389 fn handle_transfer_descriptor(
390 &self,
391 descriptor: TransferDescriptor,
392 complete_event: Event,
393 ) -> anyhow::Result<()> {
394 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 "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}