mirror of
https://github.com/cloud-hypervisor/cloud-hypervisor.git
synced 2024-12-22 13:45:20 +00:00
devices: Introduce RISC-V AIA interrupt device
Introduce definitions, implementations and error variants of RISC-V AIA (Advance Interrupt Architecture) interrupt controller. Signed-off-by: Ruoqing He <heruoqing@iscas.ac.cn>
This commit is contained in:
parent
ba78e331c6
commit
e8c330e220
144
devices/src/aia.rs
Normal file
144
devices/src/aia.rs
Normal file
@ -0,0 +1,144 @@
|
|||||||
|
// Copyright © 2024 Institute of Software, CAS. All rights reserved.
|
||||||
|
// Copyright 2020, ARM Limited.
|
||||||
|
//
|
||||||
|
// SPDX-License-Identifier: Apache-2.0 AND BSD-3-Clause
|
||||||
|
|
||||||
|
use super::interrupt_controller::{Error, InterruptController};
|
||||||
|
extern crate arch;
|
||||||
|
use std::result;
|
||||||
|
use std::sync::{Arc, Mutex};
|
||||||
|
|
||||||
|
use arch::layout;
|
||||||
|
use hypervisor::arch::riscv64::aia::{Vaia, VaiaConfig};
|
||||||
|
use hypervisor::{AiaState, CpuState};
|
||||||
|
use vm_device::interrupt::{
|
||||||
|
InterruptIndex, InterruptManager, InterruptSourceConfig, InterruptSourceGroup,
|
||||||
|
LegacyIrqSourceConfig, MsiIrqGroupConfig,
|
||||||
|
};
|
||||||
|
use vm_memory::address::Address;
|
||||||
|
use vm_migration::{Migratable, Pausable, Snapshottable, Transportable};
|
||||||
|
use vmm_sys_util::eventfd::EventFd;
|
||||||
|
|
||||||
|
type Result<T> = result::Result<T, Error>;
|
||||||
|
|
||||||
|
// Reserve 32 IRQs for legacy devices.
|
||||||
|
pub const IRQ_LEGACY_BASE: usize = layout::IRQ_BASE as usize;
|
||||||
|
pub const IRQ_LEGACY_COUNT: usize = 32;
|
||||||
|
// TODO: AIA snapshotting is not yet completed.
|
||||||
|
pub const _AIA_SNAPSHOT_ID: &str = "";
|
||||||
|
|
||||||
|
// Aia (Advance Interrupt Architecture) struct provides all the functionality of a
|
||||||
|
// AIA device. It wraps a hypervisor-emulated AIA device (Vaia) provided by the
|
||||||
|
// `hypervisor` crate.
|
||||||
|
// Aia struct also implements InterruptController to provide interrupt delivery
|
||||||
|
// service.
|
||||||
|
pub struct Aia {
|
||||||
|
interrupt_source_group: Arc<dyn InterruptSourceGroup>,
|
||||||
|
// The hypervisor agnostic virtual AIA
|
||||||
|
vaia: Arc<Mutex<dyn Vaia>>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Aia {
|
||||||
|
pub fn new(
|
||||||
|
vcpu_count: u8,
|
||||||
|
interrupt_manager: Arc<dyn InterruptManager<GroupConfig = MsiIrqGroupConfig>>,
|
||||||
|
vm: Arc<dyn hypervisor::Vm>,
|
||||||
|
) -> Result<Aia> {
|
||||||
|
let interrupt_source_group = interrupt_manager
|
||||||
|
.create_group(MsiIrqGroupConfig {
|
||||||
|
base: IRQ_LEGACY_BASE as InterruptIndex,
|
||||||
|
count: IRQ_LEGACY_COUNT as InterruptIndex,
|
||||||
|
})
|
||||||
|
.map_err(Error::CreateInterruptSourceGroup)?;
|
||||||
|
|
||||||
|
let vaia = vm
|
||||||
|
.create_vaia(Aia::create_default_config(vcpu_count as u64))
|
||||||
|
.map_err(Error::CreateAia)?;
|
||||||
|
|
||||||
|
let aia = Aia {
|
||||||
|
interrupt_source_group,
|
||||||
|
vaia,
|
||||||
|
};
|
||||||
|
aia.enable()?;
|
||||||
|
|
||||||
|
Ok(aia)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn restore_vaia(
|
||||||
|
&mut self,
|
||||||
|
state: Option<AiaState>,
|
||||||
|
_saved_vcpu_states: &[CpuState],
|
||||||
|
) -> Result<()> {
|
||||||
|
self.vaia
|
||||||
|
.clone()
|
||||||
|
.lock()
|
||||||
|
.unwrap()
|
||||||
|
.set_state(&state.unwrap())
|
||||||
|
.map_err(Error::RestoreAia)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn enable(&self) -> Result<()> {
|
||||||
|
// Set irqfd for legacy interrupts
|
||||||
|
self.interrupt_source_group
|
||||||
|
.enable()
|
||||||
|
.map_err(Error::EnableInterrupt)?;
|
||||||
|
|
||||||
|
// Set irq_routing for legacy interrupts.
|
||||||
|
// irqchip: Hardcode to 0 as we support only 1 APLIC
|
||||||
|
// pin: Use irq number as pin
|
||||||
|
for i in IRQ_LEGACY_BASE..(IRQ_LEGACY_BASE + IRQ_LEGACY_COUNT) {
|
||||||
|
let config = LegacyIrqSourceConfig {
|
||||||
|
irqchip: 0,
|
||||||
|
pin: (i - IRQ_LEGACY_BASE) as u32,
|
||||||
|
};
|
||||||
|
self.interrupt_source_group
|
||||||
|
.update(
|
||||||
|
i as InterruptIndex,
|
||||||
|
InterruptSourceConfig::LegacyIrq(config),
|
||||||
|
false,
|
||||||
|
false,
|
||||||
|
)
|
||||||
|
.map_err(Error::EnableInterrupt)?;
|
||||||
|
}
|
||||||
|
|
||||||
|
self.interrupt_source_group
|
||||||
|
.set_gsi()
|
||||||
|
.map_err(Error::EnableInterrupt)?;
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Default config implied by arch::layout
|
||||||
|
pub fn create_default_config(vcpu_count: u64) -> VaiaConfig {
|
||||||
|
VaiaConfig {
|
||||||
|
vcpu_count: vcpu_count as u32,
|
||||||
|
aplic_addr: layout::APLIC_START.raw_value(),
|
||||||
|
imsic_addr: layout::IMSIC_START.raw_value(),
|
||||||
|
nr_irqs: layout::IRQ_NUM,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn get_vaia(&mut self) -> Result<Arc<Mutex<dyn Vaia>>> {
|
||||||
|
Ok(self.vaia.clone())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl InterruptController for Aia {
|
||||||
|
// This should be called anytime an interrupt needs to be injected into the
|
||||||
|
// running guest.
|
||||||
|
fn service_irq(&mut self, irq: usize) -> Result<()> {
|
||||||
|
self.interrupt_source_group
|
||||||
|
.trigger(irq as InterruptIndex)
|
||||||
|
.map_err(Error::TriggerInterrupt)?;
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn notifier(&self, irq: usize) -> Option<EventFd> {
|
||||||
|
self.interrupt_source_group.notifier(irq as InterruptIndex)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Snapshottable for Aia {}
|
||||||
|
impl Pausable for Aia {}
|
||||||
|
impl Transportable for Aia {}
|
||||||
|
impl Migratable for Aia {}
|
@ -1,3 +1,4 @@
|
|||||||
|
// Copyright © 2024 Institute of Software, CAS. All rights reserved.
|
||||||
// Copyright 2020, ARM Limited.
|
// Copyright 2020, ARM Limited.
|
||||||
//
|
//
|
||||||
// SPDX-License-Identifier: Apache-2.0 AND BSD-3-Clause
|
// SPDX-License-Identifier: Apache-2.0 AND BSD-3-Clause
|
||||||
@ -41,6 +42,14 @@ pub enum Error {
|
|||||||
/// Failed restoring GIC device.
|
/// Failed restoring GIC device.
|
||||||
#[error("Failed restoring GIC device: {0}")]
|
#[error("Failed restoring GIC device: {0}")]
|
||||||
RestoreGic(hypervisor::arch::aarch64::gic::Error),
|
RestoreGic(hypervisor::arch::aarch64::gic::Error),
|
||||||
|
#[cfg(target_arch = "riscv64")]
|
||||||
|
/// Failed creating AIA device.
|
||||||
|
#[error("Failed creating AIA device: {0}")]
|
||||||
|
CreateAia(hypervisor::HypervisorVmError),
|
||||||
|
#[cfg(target_arch = "riscv64")]
|
||||||
|
/// Failed restoring AIA device.
|
||||||
|
#[error("Failed restoring AIA device: {0}")]
|
||||||
|
RestoreAia(hypervisor::arch::riscv64::aia::Error),
|
||||||
}
|
}
|
||||||
|
|
||||||
type Result<T> = result::Result<T, Error>;
|
type Result<T> = result::Result<T, Error>;
|
||||||
@ -67,7 +76,7 @@ pub struct MsiMessage {
|
|||||||
// Introduce trait InterruptController to uniform the interrupt
|
// Introduce trait InterruptController to uniform the interrupt
|
||||||
// service provided for devices.
|
// service provided for devices.
|
||||||
// Device manager uses this trait without caring whether it is a
|
// Device manager uses this trait without caring whether it is a
|
||||||
// IOAPIC (X86) or GIC (Arm).
|
// IOAPIC (X86), GIC (Arm) or AIA (RISC-V).
|
||||||
pub trait InterruptController: Send {
|
pub trait InterruptController: Send {
|
||||||
fn service_irq(&mut self, irq: usize) -> Result<()>;
|
fn service_irq(&mut self, irq: usize) -> Result<()>;
|
||||||
#[cfg(target_arch = "x86_64")]
|
#[cfg(target_arch = "x86_64")]
|
||||||
|
@ -15,6 +15,8 @@ extern crate event_monitor;
|
|||||||
extern crate log;
|
extern crate log;
|
||||||
|
|
||||||
pub mod acpi;
|
pub mod acpi;
|
||||||
|
#[cfg(target_arch = "riscv64")]
|
||||||
|
pub mod aia;
|
||||||
#[cfg(target_arch = "x86_64")]
|
#[cfg(target_arch = "x86_64")]
|
||||||
pub mod debug_console;
|
pub mod debug_console;
|
||||||
#[cfg(target_arch = "aarch64")]
|
#[cfg(target_arch = "aarch64")]
|
||||||
|
Loading…
Reference in New Issue
Block a user