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