1use std::mem::size_of;
6use std::sync::atomic::fence;
7use std::sync::atomic::Ordering;
8
9use remain::sorted;
10use thiserror::Error;
11use vm_memory::GuestAddress;
12use vm_memory::GuestMemory;
13use vm_memory::GuestMemoryError;
14use zerocopy::IntoBytes;
15
16use super::xhci_abi::EventRingSegmentTableEntry;
17use super::xhci_abi::Trb;
18
19#[sorted]
20#[derive(Error, Debug)]
21pub enum Error {
22 #[error("event ring has a bad enqueue pointer: {0}")]
23 BadEnqueuePointer(GuestAddress),
24 #[error("event ring has a bad seg table addr: {0}")]
25 BadSegTableAddress(GuestAddress),
26 #[error("event ring has a bad seg table index: {0}")]
27 BadSegTableIndex(u16),
28 #[error("event ring is full")]
29 EventRingFull,
30 #[error("event ring cannot read from guest memory: {0}")]
31 MemoryRead(GuestMemoryError),
32 #[error("event ring cannot write to guest memory: {0}")]
33 MemoryWrite(GuestMemoryError),
34 #[error("event ring is uninitialized")]
35 Uninitialized,
36}
37
38type Result<T> = std::result::Result<T, Error>;
39
40pub struct EventRing {
46 mem: GuestMemory,
47 segment_table_size: u16,
48 segment_table_base_address: GuestAddress,
49 current_segment_index: u16,
50 trb_count: u16,
51 enqueue_pointer: GuestAddress,
52 dequeue_pointer: GuestAddress,
53 producer_cycle_state: bool,
54}
55
56impl EventRing {
57 pub fn new(mem: GuestMemory) -> Self {
59 EventRing {
60 mem,
61 segment_table_size: 0,
62 segment_table_base_address: GuestAddress(0),
63 current_segment_index: 0,
64 enqueue_pointer: GuestAddress(0),
65 dequeue_pointer: GuestAddress(0),
66 trb_count: 0,
67 producer_cycle_state: true,
69 }
70 }
71
72 pub fn add_event(&mut self, mut trb: Trb) -> Result<()> {
74 self.check_inited()?;
75 if self.is_full()? {
76 return Err(Error::EventRingFull);
77 }
78 trb.set_cycle(!self.producer_cycle_state);
81 self.mem
82 .write_obj_at_addr(trb, self.enqueue_pointer)
83 .map_err(Error::MemoryWrite)?;
84
85 fence(Ordering::SeqCst);
87
88 trb.set_cycle(self.producer_cycle_state);
89
90 const CYCLE_STATE_OFFSET: usize = 12usize;
92 let data = trb.as_bytes();
93 let cycle_bit_dword = &data[CYCLE_STATE_OFFSET..];
95 let address = self.enqueue_pointer;
96 let address = address
97 .checked_add(CYCLE_STATE_OFFSET as u64)
98 .ok_or(Error::BadEnqueuePointer(self.enqueue_pointer))?;
99 self.mem
100 .write_all_at_addr(cycle_bit_dword, address)
101 .map_err(Error::MemoryWrite)?;
102
103 xhci_trace!(
104 "event write to pointer {:#x}, trb_count {}, {}",
105 self.enqueue_pointer.0,
106 self.trb_count,
107 trb
108 );
109 self.enqueue_pointer = match self.enqueue_pointer.checked_add(size_of::<Trb>() as u64) {
110 Some(addr) => addr,
111 None => return Err(Error::BadEnqueuePointer(self.enqueue_pointer)),
112 };
113 self.trb_count -= 1;
114 if self.trb_count == 0 {
115 self.current_segment_index += 1;
116 if self.current_segment_index == self.segment_table_size {
117 self.producer_cycle_state ^= true;
118 self.current_segment_index = 0;
119 }
120 self.load_current_seg_table_entry()?;
121 }
122 Ok(())
123 }
124
125 pub fn set_seg_table_size(&mut self, size: u16) -> Result<()> {
127 xhci_trace!("set_seg_table_size({:#x})", size);
128 self.segment_table_size = size;
129 self.try_reconfigure_event_ring()
130 }
131
132 pub fn set_seg_table_base_addr(&mut self, addr: GuestAddress) -> Result<()> {
134 xhci_trace!("set_seg_table_base_addr({:#x})", addr.0);
135 self.segment_table_base_address = addr;
136 self.try_reconfigure_event_ring()
137 }
138
139 pub fn set_dequeue_pointer(&mut self, addr: GuestAddress) {
141 xhci_trace!("set_dequeue_pointer({:#x})", addr.0);
142 self.dequeue_pointer = addr;
143 }
144
145 pub fn is_empty(&self) -> bool {
147 self.enqueue_pointer == self.dequeue_pointer
148 }
149
150 pub fn is_full(&self) -> Result<bool> {
155 if self.trb_count == 1 {
156 let next_erst_idx =
157 Self::next_seg_table_index(self.current_segment_index, self.segment_table_size)?;
158 let erst_entry = self.read_seg_table_entry(next_erst_idx)?;
159 Ok(self.dequeue_pointer.0 == erst_entry.get_ring_segment_base_address())
160 } else {
161 Self::is_non_boundary_full(self.enqueue_pointer, self.dequeue_pointer)
162 }
163 }
164
165 fn next_seg_table_index(current_segment_index: u16, segment_table_size: u16) -> Result<u16> {
166 if segment_table_size == 0 {
167 return Err(Error::Uninitialized);
168 }
169 Ok(((current_segment_index as u32 + 1) % (segment_table_size as u32)) as u16)
170 }
171
172 fn is_non_boundary_full(
173 enqueue_pointer: GuestAddress,
174 dequeue_pointer: GuestAddress,
175 ) -> Result<bool> {
176 let next_enq = enqueue_pointer
177 .checked_add(size_of::<Trb>() as u64)
178 .ok_or(Error::BadEnqueuePointer(enqueue_pointer))?;
179 Ok(dequeue_pointer == next_enq)
180 }
181
182 fn try_reconfigure_event_ring(&mut self) -> Result<()> {
184 if self.segment_table_size == 0 || self.segment_table_base_address.0 == 0 {
185 return Ok(());
186 }
187 if self.current_segment_index >= self.segment_table_size {
188 self.current_segment_index = 0;
189 }
190 self.load_current_seg_table_entry()
191 }
192
193 fn check_inited(&self) -> Result<()> {
195 Self::check_inited_params(
196 self.segment_table_size,
197 self.segment_table_base_address,
198 self.enqueue_pointer,
199 self.trb_count,
200 )
201 }
202
203 fn check_inited_params(
204 segment_table_size: u16,
205 segment_table_base_address: GuestAddress,
206 enqueue_pointer: GuestAddress,
207 trb_count: u16,
208 ) -> Result<()> {
209 if segment_table_size == 0
210 || segment_table_base_address == GuestAddress(0)
211 || enqueue_pointer == GuestAddress(0)
212 || trb_count == 0
213 {
214 return Err(Error::Uninitialized);
215 }
216 Ok(())
217 }
218
219 fn load_current_seg_table_entry(&mut self) -> Result<()> {
221 let entry = self.read_seg_table_entry(self.current_segment_index)?;
222 self.enqueue_pointer = GuestAddress(entry.get_ring_segment_base_address());
223 self.trb_count = entry.get_ring_segment_size();
224 Ok(())
225 }
226
227 fn read_seg_table_entry(&self, index: u16) -> Result<EventRingSegmentTableEntry> {
229 let seg_table_addr = self.get_seg_table_addr(index)?;
230 self.mem
232 .read_obj_from_addr(seg_table_addr)
233 .map_err(Error::MemoryRead)
234 }
235
236 fn get_seg_table_addr(&self, index: u16) -> Result<GuestAddress> {
238 Self::calc_seg_table_addr(
239 self.segment_table_base_address,
240 self.segment_table_size,
241 index,
242 )
243 }
244
245 fn calc_seg_table_addr(
246 base_address: GuestAddress,
247 segment_table_size: u16,
248 index: u16,
249 ) -> Result<GuestAddress> {
250 if index >= segment_table_size {
251 return Err(Error::BadSegTableIndex(index));
252 }
253 base_address
254 .checked_add((size_of::<EventRingSegmentTableEntry>() as u64) * (index as u64))
255 .ok_or(Error::BadSegTableAddress(base_address))
256 }
257}
258
259#[cfg(test)]
260mod test {
261 use std::mem::size_of;
262
263 use base::pagesize;
264
265 use super::*;
266
267 #[test]
268 fn test_uninited() {
269 let gm = GuestMemory::new(&[(GuestAddress(0), pagesize() as u64)]).unwrap();
270 let mut er = EventRing::new(gm);
271 let trb = Trb::new();
272 match er.add_event(trb).err().unwrap() {
273 Error::Uninitialized => {}
274 _ => panic!("unexpected error"),
275 }
276 assert_eq!(er.is_empty(), true);
277 assert_eq!(er.is_full().unwrap(), false);
278 }
279
280 #[test]
281 fn test_event_ring() {
282 let trb_size = size_of::<Trb>() as u64;
283 let gm = GuestMemory::new(&[(GuestAddress(0), pagesize() as u64)]).unwrap();
284 let mut er = EventRing::new(gm.clone());
285 let mut st_entries = [EventRingSegmentTableEntry::new(); 3];
286 st_entries[0].set_ring_segment_base_address(0x100);
287 st_entries[0].set_ring_segment_size(3);
288 st_entries[1].set_ring_segment_base_address(0x200);
289 st_entries[1].set_ring_segment_size(3);
290 st_entries[2].set_ring_segment_base_address(0x300);
291 st_entries[2].set_ring_segment_size(3);
292 gm.write_obj_at_addr(st_entries[0], GuestAddress(0x8))
293 .unwrap();
294 gm.write_obj_at_addr(
295 st_entries[1],
296 GuestAddress(0x8 + size_of::<EventRingSegmentTableEntry>() as u64),
297 )
298 .unwrap();
299 gm.write_obj_at_addr(
300 st_entries[2],
301 GuestAddress(0x8 + 2 * size_of::<EventRingSegmentTableEntry>() as u64),
302 )
303 .unwrap();
304 er.set_seg_table_size(3).unwrap();
306 er.set_seg_table_base_addr(GuestAddress(0x8)).unwrap();
307 er.set_dequeue_pointer(GuestAddress(0x100));
308
309 let mut trb = Trb::new();
310
311 trb.set_control(1);
313 assert_eq!(er.is_empty(), true);
314 assert_eq!(er.is_full().unwrap(), false);
315 assert!(er.add_event(trb).is_ok());
316 assert_eq!(er.is_full().unwrap(), false);
317 assert_eq!(er.is_empty(), false);
318 let t: Trb = gm.read_obj_from_addr(GuestAddress(0x100)).unwrap();
319 assert_eq!(t.get_control(), 1);
320 assert_eq!(t.get_cycle(), true);
321
322 trb.set_control(2);
323 assert!(er.add_event(trb).is_ok());
324 assert_eq!(er.is_full().unwrap(), false);
325 assert_eq!(er.is_empty(), false);
326 let t: Trb = gm
327 .read_obj_from_addr(GuestAddress(0x100 + trb_size))
328 .unwrap();
329 assert_eq!(t.get_control(), 2);
330 assert_eq!(t.get_cycle(), true);
331
332 trb.set_control(3);
333 assert!(er.add_event(trb).is_ok());
334 assert_eq!(er.is_full().unwrap(), false);
335 assert_eq!(er.is_empty(), false);
336 let t: Trb = gm
337 .read_obj_from_addr(GuestAddress(0x100 + 2 * trb_size))
338 .unwrap();
339 assert_eq!(t.get_control(), 3);
340 assert_eq!(t.get_cycle(), true);
341
342 trb.set_control(4);
344 assert!(er.add_event(trb).is_ok());
345 assert_eq!(er.is_full().unwrap(), false);
346 assert_eq!(er.is_empty(), false);
347 let t: Trb = gm.read_obj_from_addr(GuestAddress(0x200)).unwrap();
348 assert_eq!(t.get_control(), 4);
349 assert_eq!(t.get_cycle(), true);
350
351 trb.set_control(5);
352 assert!(er.add_event(trb).is_ok());
353 assert_eq!(er.is_full().unwrap(), false);
354 assert_eq!(er.is_empty(), false);
355 let t: Trb = gm
356 .read_obj_from_addr(GuestAddress(0x200 + trb_size))
357 .unwrap();
358 assert_eq!(t.get_control(), 5);
359 assert_eq!(t.get_cycle(), true);
360
361 trb.set_control(6);
362 assert!(er.add_event(trb).is_ok());
363 assert_eq!(er.is_full().unwrap(), false);
364 assert_eq!(er.is_empty(), false);
365 let t: Trb = gm
366 .read_obj_from_addr(GuestAddress(0x200 + 2 * trb_size))
367 .unwrap();
368 assert_eq!(t.get_control(), 6);
369 assert_eq!(t.get_cycle(), true);
370
371 trb.set_control(7);
373 assert!(er.add_event(trb).is_ok());
374 assert_eq!(er.is_full().unwrap(), false);
375 assert_eq!(er.is_empty(), false);
376 let t: Trb = gm.read_obj_from_addr(GuestAddress(0x300)).unwrap();
377 assert_eq!(t.get_control(), 7);
378 assert_eq!(t.get_cycle(), true);
379
380 trb.set_control(8);
381 assert!(er.add_event(trb).is_ok());
382 assert_eq!(er.is_full().unwrap(), true);
384 assert_eq!(er.is_empty(), false);
385 let t: Trb = gm
386 .read_obj_from_addr(GuestAddress(0x300 + trb_size))
387 .unwrap();
388 assert_eq!(t.get_control(), 8);
389 assert_eq!(t.get_cycle(), true);
390
391 match er.add_event(trb) {
393 Err(Error::EventRingFull) => {}
394 _ => panic!("er should be full"),
395 };
396
397 er.set_dequeue_pointer(GuestAddress(0x100 + trb_size));
399 assert_eq!(er.is_full().unwrap(), false);
400 assert_eq!(er.is_empty(), false);
401
402 trb.set_control(9);
404 assert!(er.add_event(trb).is_ok());
405 assert_eq!(er.is_full().unwrap(), true);
407 assert_eq!(er.is_empty(), false);
408 let t: Trb = gm
409 .read_obj_from_addr(GuestAddress(0x300 + trb_size))
410 .unwrap();
411 assert_eq!(t.get_control(), 8);
412 assert_eq!(t.get_cycle(), true);
413
414 match er.add_event(trb) {
416 Err(Error::EventRingFull) => {}
417 _ => panic!("er should be full"),
418 };
419
420 er.set_dequeue_pointer(GuestAddress(0x100));
422 assert_eq!(er.is_full().unwrap(), false);
423 assert_eq!(er.is_empty(), true);
424
425 trb.set_control(10);
427 assert!(er.add_event(trb).is_ok());
428 assert_eq!(er.is_full().unwrap(), false);
429 assert_eq!(er.is_empty(), false);
430 let t: Trb = gm.read_obj_from_addr(GuestAddress(0x100)).unwrap();
431 assert_eq!(t.get_control(), 10);
432 assert_eq!(t.get_cycle(), false);
434
435 trb.set_control(11);
436 assert!(er.add_event(trb).is_ok());
437 assert_eq!(er.is_full().unwrap(), false);
438 assert_eq!(er.is_empty(), false);
439 let t: Trb = gm
440 .read_obj_from_addr(GuestAddress(0x100 + trb_size))
441 .unwrap();
442 assert_eq!(t.get_control(), 11);
443 assert_eq!(t.get_cycle(), false);
444
445 trb.set_control(12);
446 assert!(er.add_event(trb).is_ok());
447 assert_eq!(er.is_full().unwrap(), false);
448 assert_eq!(er.is_empty(), false);
449 let t: Trb = gm
450 .read_obj_from_addr(GuestAddress(0x100 + 2 * trb_size))
451 .unwrap();
452 assert_eq!(t.get_control(), 12);
453 assert_eq!(t.get_cycle(), false);
454 }
455}
456
457#[cfg(kani)]
458mod kani_proofs {
459 use super::*;
460
461 #[kani::proof]
462 fn proof_event_ring_seg_table_and_state() {
463 let seg_table_size: u16 = kani::any();
464 let base_addr: u64 = kani::any();
465 let cur_idx: u16 = kani::any();
466 let trb_count: u16 = kani::any();
467 let enq_addr: u64 = kani::any();
468 let deq_addr: u64 = kani::any();
469 let lookup_idx: u16 = kani::any();
470
471 let addr_res =
474 EventRing::calc_seg_table_addr(GuestAddress(base_addr), seg_table_size, lookup_idx);
475 if lookup_idx >= seg_table_size {
476 assert!(matches!(addr_res, Err(Error::BadSegTableIndex(_))));
477 } else {
478 let expected_offset =
479 (size_of::<EventRingSegmentTableEntry>() as u64) * (lookup_idx as u64);
480 match base_addr.checked_add(expected_offset) {
481 Some(expected_addr) => {
482 assert!(matches!(addr_res, Ok(addr) if addr.0 == expected_addr));
483 }
484 None => {
485 assert!(matches!(addr_res, Err(Error::BadSegTableAddress(_))));
486 }
487 }
488 }
489
490 let inited = EventRing::check_inited_params(
492 seg_table_size,
493 GuestAddress(base_addr),
494 GuestAddress(enq_addr),
495 trb_count,
496 );
497 if seg_table_size == 0 || base_addr == 0 || enq_addr == 0 || trb_count == 0 {
498 assert!(matches!(inited, Err(Error::Uninitialized)));
499 } else {
500 assert!(inited.is_ok());
501 }
502
503 let next_idx_res = EventRing::next_seg_table_index(cur_idx, seg_table_size);
505 if seg_table_size == 0 {
506 assert!(matches!(next_idx_res, Err(Error::Uninitialized)));
507 } else {
508 let Ok(next_idx) = next_idx_res else {
509 unreachable!();
510 };
511 assert!(next_idx < seg_table_size);
512 if cur_idx < seg_table_size {
513 let expected = if cur_idx + 1 == seg_table_size {
514 0
515 } else {
516 cur_idx + 1
517 };
518 assert!(next_idx == expected);
519 }
520 }
521
522 let full_res =
523 EventRing::is_non_boundary_full(GuestAddress(enq_addr), GuestAddress(deq_addr));
524 match enq_addr.checked_add(size_of::<Trb>() as u64) {
525 Some(next_enq) => {
526 assert!(matches!(full_res, Ok(full) if full == (deq_addr == next_enq)));
527 }
528 None => {
529 assert!(matches!(full_res, Err(Error::BadEnqueuePointer(_))));
530 }
531 }
532 }
533}