virt/aarch64/
gic_software_device.rs

1// Copyright (c) Microsoft Corporation.
2// Licensed under the MIT License.
3
4//! VPCI device implementation for GIC-based VMs.
5
6use crate::irqcon::ControlGic;
7use pci_core::msi::SignalMsi;
8use std::ops::Range;
9use std::sync::Arc;
10use thiserror::Error;
11use vmcore::vpci_msi::MapVpciInterrupt;
12use vmcore::vpci_msi::MsiAddressData;
13use vmcore::vpci_msi::RegisterInterruptError;
14
15pub struct GicSoftwareDevice {
16    irqcon: Arc<dyn ControlGic>,
17}
18
19impl GicSoftwareDevice {
20    pub fn new(irqcon: Arc<dyn ControlGic>) -> Self {
21        Self { irqcon }
22    }
23}
24
25#[derive(Debug, Error)]
26enum GicInterruptError {
27    #[error("invalid vector count {0}")]
28    InvalidVectorCount(u32),
29    #[error("invalid {count} vectors at {start}")]
30    InvalidVector { start: u32, count: u32 },
31}
32
33const SPI_RANGE: Range<u32> = 32..1020;
34
35impl MapVpciInterrupt for GicSoftwareDevice {
36    async fn register_interrupt(
37        &self,
38        vector_count: u32,
39        params: &vmcore::vpci_msi::VpciInterruptParameters<'_>,
40    ) -> Result<MsiAddressData, RegisterInterruptError> {
41        if !vector_count.is_power_of_two() {
42            return Err(RegisterInterruptError::new(
43                GicInterruptError::InvalidVectorCount(vector_count),
44            ));
45        }
46        if params.vector < SPI_RANGE.start
47            || params.vector.saturating_add(vector_count) > SPI_RANGE.end
48        {
49            return Err(RegisterInterruptError::new(
50                GicInterruptError::InvalidVector {
51                    start: params.vector,
52                    count: vector_count,
53                },
54            ));
55        }
56        Ok(MsiAddressData {
57            address: 0,
58            data: params.vector,
59        })
60    }
61
62    async fn unregister_interrupt(&self, address: u64, data: u32) {
63        let _ = (address, data);
64    }
65}
66
67impl SignalMsi for GicSoftwareDevice {
68    fn signal_msi(&self, _rid: u32, _address: u64, data: u32) {
69        if SPI_RANGE.contains(&data) {
70            self.irqcon.set_spi_irq(data, true);
71        }
72    }
73}