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