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