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