xref: /cloud-hypervisor/devices/src/aia.rs (revision eeae63b4595fbf0cc69f62b6e9d9a79c543c4ac7)
1 // Copyright © 2024 Institute of Software, CAS. All rights reserved.
2 // Copyright 2020, ARM Limited.
3 //
4 // SPDX-License-Identifier: Apache-2.0 AND BSD-3-Clause
5 
6 use super::interrupt_controller::{Error, InterruptController};
7 extern crate arch;
8 use std::result;
9 use std::sync::{Arc, Mutex};
10 
11 use arch::layout;
12 use hypervisor::arch::riscv64::aia::{Vaia, VaiaConfig};
13 use hypervisor::{AiaState, CpuState};
14 use vm_device::interrupt::{
15     InterruptIndex, InterruptManager, InterruptSourceConfig, InterruptSourceGroup,
16     LegacyIrqSourceConfig, MsiIrqGroupConfig,
17 };
18 use vm_memory::address::Address;
19 use vm_migration::{Migratable, Pausable, Snapshottable, Transportable};
20 use vmm_sys_util::eventfd::EventFd;
21 
22 type Result<T> = result::Result<T, Error>;
23 
24 // Reserve 32 IRQs for legacy devices.
25 pub const IRQ_LEGACY_BASE: usize = layout::IRQ_BASE as usize;
26 pub const IRQ_LEGACY_COUNT: usize = 32;
27 // TODO: AIA snapshotting is not yet completed.
28 pub const _AIA_SNAPSHOT_ID: &str = "";
29 
30 // Aia (Advance Interrupt Architecture) struct provides all the functionality of a
31 // AIA device. It wraps a hypervisor-emulated AIA device (Vaia) provided by the
32 // `hypervisor` crate.
33 // Aia struct also implements InterruptController to provide interrupt delivery
34 // service.
35 pub struct Aia {
36     interrupt_source_group: Arc<dyn InterruptSourceGroup>,
37     // The hypervisor agnostic virtual AIA
38     vaia: Arc<Mutex<dyn Vaia>>,
39 }
40 
41 impl Aia {
42     pub fn new(
43         vcpu_count: u8,
44         interrupt_manager: Arc<dyn InterruptManager<GroupConfig = MsiIrqGroupConfig>>,
45         vm: Arc<dyn hypervisor::Vm>,
46     ) -> Result<Aia> {
47         let interrupt_source_group = interrupt_manager
48             .create_group(MsiIrqGroupConfig {
49                 base: IRQ_LEGACY_BASE as InterruptIndex,
50                 count: IRQ_LEGACY_COUNT as InterruptIndex,
51             })
52             .map_err(Error::CreateInterruptSourceGroup)?;
53 
54         let vaia = vm
55             .create_vaia(Aia::create_default_config(vcpu_count as u64))
56             .map_err(Error::CreateAia)?;
57 
58         let aia = Aia {
59             interrupt_source_group,
60             vaia,
61         };
62         aia.enable()?;
63 
64         Ok(aia)
65     }
66 
67     pub fn restore_vaia(
68         &mut self,
69         state: Option<AiaState>,
70         _saved_vcpu_states: &[CpuState],
71     ) -> Result<()> {
72         self.vaia
73             .clone()
74             .lock()
75             .unwrap()
76             .set_state(&state.unwrap())
77             .map_err(Error::RestoreAia)
78     }
79 
80     fn enable(&self) -> Result<()> {
81         // Set irqfd for legacy interrupts
82         self.interrupt_source_group
83             .enable()
84             .map_err(Error::EnableInterrupt)?;
85 
86         // Set irq_routing for legacy interrupts.
87         //   irqchip: Hardcode to 0 as we support only 1 APLIC
88         //   pin: Use irq number as pin
89         for i in IRQ_LEGACY_BASE..(IRQ_LEGACY_BASE + IRQ_LEGACY_COUNT) {
90             let config = LegacyIrqSourceConfig {
91                 irqchip: 0,
92                 pin: (i - IRQ_LEGACY_BASE) as u32,
93             };
94             self.interrupt_source_group
95                 .update(
96                     i as InterruptIndex,
97                     InterruptSourceConfig::LegacyIrq(config),
98                     false,
99                     false,
100                 )
101                 .map_err(Error::EnableInterrupt)?;
102         }
103 
104         self.interrupt_source_group
105             .set_gsi()
106             .map_err(Error::EnableInterrupt)?;
107         Ok(())
108     }
109 
110     /// Default config implied by arch::layout
111     pub fn create_default_config(vcpu_count: u64) -> VaiaConfig {
112         VaiaConfig {
113             vcpu_count: vcpu_count as u32,
114             aplic_addr: layout::APLIC_START.raw_value(),
115             imsic_addr: layout::IMSIC_START.raw_value(),
116             nr_irqs: layout::IRQ_NUM,
117         }
118     }
119 
120     pub fn get_vaia(&mut self) -> Result<Arc<Mutex<dyn Vaia>>> {
121         Ok(self.vaia.clone())
122     }
123 }
124 
125 impl InterruptController for Aia {
126     // This should be called anytime an interrupt needs to be injected into the
127     // running guest.
128     fn service_irq(&mut self, irq: usize) -> Result<()> {
129         self.interrupt_source_group
130             .trigger(irq as InterruptIndex)
131             .map_err(Error::TriggerInterrupt)?;
132 
133         Ok(())
134     }
135 
136     fn notifier(&self, irq: usize) -> Option<EventFd> {
137         self.interrupt_source_group.notifier(irq as InterruptIndex)
138     }
139 }
140 
141 impl Snapshottable for Aia {}
142 impl Pausable for Aia {}
143 impl Transportable for Aia {}
144 impl Migratable for Aia {}
145