1use crate::bus_range::AssignedBusRange;
7use pal_event::Event;
8use parking_lot::RwLock;
9use std::sync::Arc;
10use vmcore::irqfd::IrqFd;
11use vmcore::irqfd::IrqFdRoute;
12
13pub trait SignalMsi: Send + Sync {
15 fn signal_msi(&self, devid: Option<u32>, address: u64, data: u32);
22}
23
24pub struct MsiRoute {
31 inner: Box<dyn IrqFdRoute>,
32 default_rid: DefaultRid,
33}
34
35impl MsiRoute {
36 pub fn event(&self) -> &Event {
40 self.inner.event()
41 }
42
43 pub fn enable(&self, address: u64, data: u32) {
49 let Some(resolved) = resolve_default_rid(&self.default_rid) else {
52 self.inner.disable();
53 return;
54 };
55 self.inner.enable(address, data, Some(resolved))
56 }
57
58 pub fn enable_with_rid(&self, rid: u16, address: u64, data: u32) {
70 let bus = (rid >> 8) as u8;
71 if !self.default_rid.bus_range.contains_bus(bus) {
72 let (secondary, subordinate) = self.default_rid.bus_range.bus_range();
73 tracelimit::warn_ratelimited!(
74 rid,
75 secondary,
76 subordinate,
77 "refusing to enable MSI route: rid bus outside assigned bus range"
78 );
79 self.inner.disable();
80 return;
81 }
82 self.inner.enable(address, data, Some(rid.into()))
83 }
84
85 pub fn disable(&self) {
90 self.inner.disable()
91 }
92
93 pub fn consume_pending(&self) -> bool {
96 self.event().try_wait()
97 }
98}
99
100struct DisconnectedMsiTarget;
101
102impl SignalMsi for DisconnectedMsiTarget {
103 fn signal_msi(&self, _devid: Option<u32>, _address: u64, _data: u32) {
104 tracelimit::warn_ratelimited!("dropped MSI interrupt to disconnected target");
105 }
106}
107
108#[derive(Clone, Debug)]
116struct DefaultRid {
117 bus_range: AssignedBusRange,
118 rid_offset: u16,
119}
120
121fn resolve_default_rid(default: &DefaultRid) -> Option<u32> {
130 let (secondary, subordinate) = default.bus_range.bus_range();
131 let rid = ((secondary as u32) << 8) + default.rid_offset as u32;
132 if rid >> 8 > subordinate as u32 {
133 tracelimit::warn_ratelimited!(
134 rid,
135 secondary,
136 subordinate,
137 "dropping MSI: rid bus outside assigned bus range"
138 );
139 return None;
140 }
141 Some(rid)
142}
143
144#[derive(Debug)]
154pub struct MsiConnection {
155 inner: Arc<RwLock<MsiTargetInner>>,
156}
157
158#[derive(Clone)]
160pub struct MsiTarget {
161 inner: Arc<RwLock<MsiTargetInner>>,
162 default_rid: DefaultRid,
163}
164
165impl MsiTarget {
166 pub fn disconnected() -> Self {
170 Self {
171 inner: Arc::new(RwLock::new(MsiTargetInner {
172 signal_msi: Arc::new(DisconnectedMsiTarget),
173 irqfd: None,
174 })),
175 default_rid: DefaultRid {
176 bus_range: AssignedBusRange::new(),
177 rid_offset: 0,
178 },
179 }
180 }
181}
182
183impl std::fmt::Debug for MsiTarget {
184 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
185 f.debug_struct("MsiTarget")
186 .field("default_rid", &self.default_rid)
187 .finish()
188 }
189}
190
191struct MsiTargetInner {
192 signal_msi: Arc<dyn SignalMsi>,
193 irqfd: Option<Arc<dyn IrqFd>>,
194}
195
196impl std::fmt::Debug for MsiTargetInner {
197 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
198 let Self {
199 signal_msi: _,
200 irqfd,
201 } = self;
202 f.debug_struct("MsiTargetInner")
203 .field("has_irqfd", &irqfd.is_some())
204 .finish()
205 }
206}
207
208impl MsiConnection {
209 pub fn new() -> Self {
216 Self {
217 inner: Arc::new(RwLock::new(MsiTargetInner {
218 signal_msi: Arc::new(DisconnectedMsiTarget),
219 irqfd: None,
220 })),
221 }
222 }
223
224 pub fn connect(&self, signal_msi: Arc<dyn SignalMsi>) {
226 let mut inner = self.inner.write();
227 inner.signal_msi = signal_msi;
228 }
229
230 pub fn connect_irqfd(&self, irqfd: Arc<dyn IrqFd>) {
235 let mut inner = self.inner.write();
236 inner.irqfd = Some(irqfd);
237 }
238
239 pub fn msi_target(&self, bus_range: AssignedBusRange, devfn: u8) -> MsiTarget {
242 MsiTarget {
243 inner: self.inner.clone(),
244 default_rid: DefaultRid {
245 bus_range,
246 rid_offset: devfn as u16,
247 },
248 }
249 }
250
251 pub fn target(&self) -> MsiTarget {
256 self.msi_target(AssignedBusRange::new(), 0)
257 }
258}
259
260impl Default for MsiConnection {
261 fn default() -> Self {
262 Self::new()
263 }
264}
265
266impl MsiTarget {
267 pub fn with_devfn(&self, devfn: u8) -> MsiTarget {
274 self.with_rid_offset(devfn as u16)
275 }
276
277 pub fn with_bus_range(&self, bus_range: AssignedBusRange, devfn: u8) -> MsiTarget {
283 MsiTarget {
284 inner: self.inner.clone(),
285 default_rid: DefaultRid {
286 bus_range,
287 rid_offset: devfn as u16,
288 },
289 }
290 }
291
292 pub fn with_rid(&self, rid: u16) -> MsiTarget {
304 let (secondary, _) = self.default_rid.bus_range.bus_range();
305 self.with_rid_offset(rid.wrapping_sub((secondary as u16) << 8))
306 }
307
308 pub fn with_rid_offset(&self, rid_offset: u16) -> MsiTarget {
317 MsiTarget {
318 inner: self.inner.clone(),
319 default_rid: DefaultRid {
320 bus_range: self.default_rid.bus_range.clone(),
321 rid_offset,
322 },
323 }
324 }
325
326 pub fn signal_msi(&self, address: u64, data: u32) {
329 let Some(resolved) = resolve_default_rid(&self.default_rid) else {
330 return;
331 };
332 let inner = self.inner.read();
333 inner.signal_msi.signal_msi(Some(resolved), address, data);
334 }
335
336 pub fn signal_msi_with_rid(&self, rid: u16, address: u64, data: u32) {
348 let bus = (rid >> 8) as u8;
349 if !self.default_rid.bus_range.contains_bus(bus) {
350 let (secondary, subordinate) = self.default_rid.bus_range.bus_range();
351 tracelimit::warn_ratelimited!(
352 rid,
353 secondary,
354 subordinate,
355 "dropping MSI: rid bus outside assigned bus range"
356 );
357 return;
358 }
359 let inner = self.inner.read();
360 inner.signal_msi.signal_msi(Some(rid.into()), address, data);
361 }
362
363 pub fn new_route(&self) -> Option<anyhow::Result<MsiRoute>> {
372 let inner = self.inner.read();
373 inner.irqfd.as_ref().map(|fd| {
374 Ok(MsiRoute {
375 inner: fd.new_irqfd_route()?,
376 default_rid: self.default_rid.clone(),
377 })
378 })
379 }
380
381 pub fn supports_direct_msi(&self) -> bool {
383 let inner = self.inner.read();
384 inner.irqfd.is_some()
385 }
386}
387
388#[cfg(test)]
389mod tests {
390 use super::*;
391 use crate::bus_range::AssignedBusRange;
392 use pal_event::Event;
393 use parking_lot::Mutex;
394 use std::collections::VecDeque;
395
396 struct RecordingSignalMsi {
398 calls: Mutex<VecDeque<(Option<u32>, u64, u32)>>,
399 }
400
401 impl RecordingSignalMsi {
402 fn new() -> Arc<Self> {
403 Arc::new(Self {
404 calls: Mutex::new(VecDeque::new()),
405 })
406 }
407
408 fn pop(&self) -> Option<(Option<u32>, u64, u32)> {
409 self.calls.lock().pop_front()
410 }
411 }
412
413 impl SignalMsi for RecordingSignalMsi {
414 fn signal_msi(&self, devid: Option<u32>, address: u64, data: u32) {
415 self.calls.lock().push_back((devid, address, data));
416 }
417 }
418
419 #[derive(Debug, Clone, PartialEq)]
420 enum RouteCall {
421 Enable {
422 address: u64,
423 data: u32,
424 devid: Option<u32>,
425 },
426 Disable,
427 }
428
429 struct MockIrqFdRoute {
430 event: Event,
431 calls: Arc<Mutex<Vec<RouteCall>>>,
432 }
433
434 impl IrqFdRoute for MockIrqFdRoute {
435 fn event(&self) -> &Event {
436 &self.event
437 }
438
439 fn enable(&self, address: u64, data: u32, devid: Option<u32>) {
440 self.calls.lock().push(RouteCall::Enable {
441 address,
442 data,
443 devid,
444 });
445 }
446
447 fn disable(&self) {
448 self.calls.lock().push(RouteCall::Disable);
449 }
450 }
451
452 fn mock_irqfd(count: usize) -> (Arc<dyn IrqFd>, Vec<Arc<Mutex<Vec<RouteCall>>>>) {
453 let mut call_logs = Vec::new();
454 let route_params = Arc::new(Mutex::new(Vec::new()));
455 for _ in 0..count {
456 let calls = Arc::new(Mutex::new(Vec::new()));
457 call_logs.push(calls.clone());
458 route_params.lock().push(calls);
459 }
460
461 struct MockIrqFd {
462 routes: Mutex<Vec<Arc<Mutex<Vec<RouteCall>>>>>,
463 }
464 impl IrqFd for MockIrqFd {
465 fn new_irqfd_route(&self) -> anyhow::Result<Box<dyn IrqFdRoute>> {
466 let calls = self.routes.lock().remove(0);
467 Ok(Box::new(MockIrqFdRoute {
468 event: Event::new(),
469 calls,
470 }))
471 }
472 }
473
474 (
475 Arc::new(MockIrqFd {
476 routes: Mutex::new(call_logs.clone()),
477 }),
478 call_logs,
479 )
480 }
481
482 #[test]
483 fn signal_msi_resolves_default_rid() {
484 let bus_range = AssignedBusRange::new();
485 bus_range.set_bus_range(5, 10);
486 let msi_conn = MsiConnection::new();
487 let recorder = RecordingSignalMsi::new();
488 msi_conn.connect(recorder.clone());
489
490 msi_conn
491 .msi_target(bus_range, 0x18)
492 .signal_msi(0xFEE0_0000, 42);
493
494 let (devid, addr, data) = recorder.pop().unwrap();
495 assert_eq!(devid, Some((5 << 8) | 0x18));
496 assert_eq!(addr, 0xFEE0_0000);
497 assert_eq!(data, 42);
498 }
499
500 #[test]
501 fn signal_msi_with_rid_accepts_bus_in_range() {
502 let bus_range = AssignedBusRange::new();
503 bus_range.set_bus_range(5, 10);
504 let msi_conn = MsiConnection::new();
505 let recorder = RecordingSignalMsi::new();
506 msi_conn.connect(recorder.clone());
507
508 let rid: u16 = (7 << 8) | 0x0A;
510 msi_conn
511 .msi_target(bus_range, 0)
512 .signal_msi_with_rid(rid, 0xABCD, 99);
513
514 let (devid, addr, data) = recorder.pop().unwrap();
515 assert_eq!(devid, Some(rid as u32));
516 assert_eq!(addr, 0xABCD);
517 assert_eq!(data, 99);
518 }
519
520 #[test]
521 fn signal_msi_with_rid_drops_bus_outside_range() {
522 let bus_range = AssignedBusRange::new();
523 bus_range.set_bus_range(5, 10);
524 let msi_conn = MsiConnection::new();
525 let recorder = RecordingSignalMsi::new();
526 msi_conn.connect(recorder.clone());
527
528 let rid_above: u16 = 11 << 8;
530 msi_conn
531 .msi_target(bus_range.clone(), 0)
532 .signal_msi_with_rid(rid_above, 0xABCD, 1);
533 assert!(recorder.pop().is_none());
534
535 let rid_below: u16 = 4 << 8;
537 msi_conn
538 .msi_target(bus_range, 0)
539 .signal_msi_with_rid(rid_below, 0xABCD, 2);
540 assert!(recorder.pop().is_none());
541 }
542
543 #[test]
544 fn signal_msi_with_rid_accepts_boundary_buses() {
545 let bus_range = AssignedBusRange::new();
546 bus_range.set_bus_range(5, 10);
547 let msi_conn = MsiConnection::new();
548 let recorder = RecordingSignalMsi::new();
549 msi_conn.connect(recorder.clone());
550
551 msi_conn
553 .msi_target(bus_range.clone(), 0)
554 .signal_msi_with_rid(5 << 8, 0x1000, 10);
555 assert!(recorder.pop().is_some());
556
557 msi_conn
559 .msi_target(bus_range, 0)
560 .signal_msi_with_rid(10 << 8, 0x2000, 20);
561 assert!(recorder.pop().is_some());
562 }
563
564 #[test]
565 fn route_enable_resolves_default_rid() {
566 let bus_range = AssignedBusRange::new();
567 bus_range.set_bus_range(3, 8);
568 let (irqfd, calls) = mock_irqfd(1);
569 let msi_conn = MsiConnection::new();
570 msi_conn.connect_irqfd(irqfd);
571
572 let route = msi_conn
573 .msi_target(bus_range, 0x10)
574 .new_route()
575 .unwrap()
576 .unwrap();
577 route.enable(0xFEE0_0000, 55);
578
579 let log = calls[0].lock();
580 assert_eq!(log.len(), 1);
581 assert_eq!(
582 log[0],
583 RouteCall::Enable {
584 address: 0xFEE0_0000,
585 data: 55,
586 devid: Some((3 << 8) | 0x10),
587 }
588 );
589 }
590
591 #[test]
592 fn route_enable_with_rid_accepts_bus_in_range() {
593 let bus_range = AssignedBusRange::new();
594 bus_range.set_bus_range(5, 10);
595 let (irqfd, calls) = mock_irqfd(1);
596 let msi_conn = MsiConnection::new();
597 msi_conn.connect_irqfd(irqfd);
598
599 let route = msi_conn
600 .msi_target(bus_range, 0)
601 .new_route()
602 .unwrap()
603 .unwrap();
604 let rid: u16 = (7 << 8) | 0x0A;
605 route.enable_with_rid(rid, 0xBEEF, 77);
606
607 let log = calls[0].lock();
608 assert_eq!(log.len(), 1);
609 assert_eq!(
610 log[0],
611 RouteCall::Enable {
612 address: 0xBEEF,
613 data: 77,
614 devid: Some(rid as u32),
615 }
616 );
617 }
618
619 #[test]
620 fn route_enable_with_rid_disables_when_bus_outside_range() {
621 let bus_range = AssignedBusRange::new();
622 bus_range.set_bus_range(5, 10);
623 let (irqfd, calls) = mock_irqfd(1);
624 let msi_conn = MsiConnection::new();
625 msi_conn.connect_irqfd(irqfd);
626
627 let route = msi_conn
628 .msi_target(bus_range, 0)
629 .new_route()
630 .unwrap()
631 .unwrap();
632 let rid: u16 = 11 << 8;
634 route.enable_with_rid(rid, 0xBEEF, 77);
635
636 let log = calls[0].lock();
637 assert_eq!(log.len(), 1);
638 assert_eq!(log[0], RouteCall::Disable);
639 }
640
641 #[test]
642 fn with_devfn_derives_target_with_new_devfn() {
643 let bus_range = AssignedBusRange::new();
644 bus_range.set_bus_range(2, 5);
645 let msi_conn = MsiConnection::new();
646 let recorder = RecordingSignalMsi::new();
647 msi_conn.connect(recorder.clone());
648
649 let derived = msi_conn.msi_target(bus_range, 0).with_devfn(0x18); derived.signal_msi(0x1000, 1);
651
652 let (devid, _, _) = recorder.pop().unwrap();
653 assert_eq!(devid, Some((2 << 8) | 0x18));
654 }
655
656 #[test]
657 fn with_bus_range_derives_target_with_new_range() {
658 let parent_range = AssignedBusRange::new();
659 parent_range.set_bus_range(1, 20);
660 let msi_conn = MsiConnection::new();
661 let recorder = RecordingSignalMsi::new();
662 msi_conn.connect(recorder.clone());
663
664 let child_range = AssignedBusRange::new();
665 child_range.set_bus_range(10, 15);
666 let derived = msi_conn
667 .msi_target(parent_range, 0)
668 .with_bus_range(child_range, 0x08);
669 derived.signal_msi(0x2000, 2);
670
671 let (devid, _, _) = recorder.pop().unwrap();
672 assert_eq!(devid, Some((10 << 8) | 0x08));
674
675 derived.signal_msi_with_rid(16 << 8, 0x3000, 3);
677 assert!(recorder.pop().is_none()); }
679
680 #[test]
681 fn with_rid_signal_msi_accepts_bus_in_range() {
682 let bus_range = AssignedBusRange::new();
683 bus_range.set_bus_range(5, 10);
684 let msi_conn = MsiConnection::new();
685 let recorder = RecordingSignalMsi::new();
686 msi_conn.connect(recorder.clone());
687
688 let rid: u16 = (7 << 8) | 0x0A;
690 let derived = msi_conn.msi_target(bus_range, 0).with_rid(rid);
691 derived.signal_msi(0x1000, 7);
692
693 let (devid, addr, data) = recorder.pop().unwrap();
694 assert_eq!(devid, Some(rid as u32));
695 assert_eq!(addr, 0x1000);
696 assert_eq!(data, 7);
697 }
698
699 #[test]
700 fn with_rid_signal_msi_drops_bus_outside_range() {
701 let bus_range = AssignedBusRange::new();
702 bus_range.set_bus_range(5, 10);
703 let msi_conn = MsiConnection::new();
704 let recorder = RecordingSignalMsi::new();
705 msi_conn.connect(recorder.clone());
706
707 let derived_above = msi_conn.msi_target(bus_range.clone(), 0).with_rid(11 << 8);
709 derived_above.signal_msi(0x1000, 1);
710 assert!(recorder.pop().is_none());
711
712 let derived_below = msi_conn.msi_target(bus_range, 0).with_rid(4 << 8);
714 derived_below.signal_msi(0x2000, 2);
715 assert!(recorder.pop().is_none());
716 }
717
718 #[test]
719 fn with_rid_route_enable_disables_when_bus_outside_range() {
720 let bus_range = AssignedBusRange::new();
721 bus_range.set_bus_range(5, 10);
722 let (irqfd, calls) = mock_irqfd(1);
723 let msi_conn = MsiConnection::new();
724 msi_conn.connect_irqfd(irqfd);
725
726 let derived = msi_conn.msi_target(bus_range, 0).with_rid(11 << 8);
729 let route = derived.new_route().unwrap().unwrap();
730 route.enable(0xBEEF, 77);
731
732 let log = calls[0].lock();
733 assert_eq!(log.len(), 1);
734 assert_eq!(log[0], RouteCall::Disable);
735 }
736}