virt/aarch64/gic_v2m.rs
1// Copyright (c) Microsoft Corporation.
2// Licensed under the MIT License.
3
4//! GIC v2m MSI frame support for delivering PCIe MSIs as SPI assertions.
5
6use crate::irqcon::ControlGic;
7use aarch64defs::gic::GicV2mRegister;
8use pci_core::msi::SignalMsi;
9use std::ops::Range;
10use std::sync::Arc;
11use vm_topology::processor::aarch64::GicV2mInfo;
12
13/// A [`SignalMsi`] implementation that decodes GIC v2m-style MSIs and delivers
14/// them as SPI assertions via [`ControlGic`].
15///
16/// When a device fires an MSI it writes the assigned GIC interrupt ID to the
17/// SETSPI_NS register inside the v2m frame (`frame_base + 0x0040`). The host
18/// intercepts that write (or for software devices, synthesises it) and calls
19/// [`signal_msi`](SignalMsi::signal_msi) with `address = frame_base + 0x0040`
20/// and `data = interrupt_id`. This struct validates the address and SPI range
21/// then calls [`ControlGic::set_spi_irq`].
22pub struct GicV2mSignalMsi {
23 /// Address of the v2m SETSPI_NS doorbell, i.e. `frame_base + 0x0040`.
24 setspi_addr: u64,
25 /// The SPI interrupt IDs owned by this v2m frame.
26 spi_range: Range<u32>,
27 irqcon: Arc<dyn ControlGic>,
28}
29
30impl GicV2mSignalMsi {
31 /// Create a new `GicV2mSignalMsi` from v2m frame info and a GIC controller.
32 pub fn new(v2m: &GicV2mInfo, irqcon: Arc<dyn ControlGic>) -> Self {
33 Self {
34 setspi_addr: v2m.frame_base + GicV2mRegister::SETSPI_NS.0 as u64,
35 spi_range: v2m.spi_base..v2m.spi_base + v2m.spi_count,
36 irqcon,
37 }
38 }
39}
40
41impl SignalMsi for GicV2mSignalMsi {
42 fn signal_msi(&self, _rid: u32, address: u64, data: u32) {
43 if address != self.setspi_addr {
44 tracelimit::warn_ratelimited!(
45 address,
46 data,
47 "unexpected MSI address (expected v2m SETSPI_NS)"
48 );
49 return;
50 }
51 if !self.spi_range.contains(&data) {
52 tracelimit::warn_ratelimited!(data, "MSI data (SPI ID) outside v2m SPI range");
53 return;
54 }
55 self.irqcon.set_spi_irq(data, true);
56 }
57}