2020-05-25 08:59:09 +00:00
|
|
|
// Copyright 2020, ARM Limited.
|
|
|
|
//
|
|
|
|
// SPDX-License-Identifier: Apache-2.0 AND BSD-3-Clause
|
|
|
|
|
|
|
|
use super::interrupt_controller::{Error, InterruptController};
|
2021-03-23 11:41:36 +00:00
|
|
|
extern crate arch;
|
2022-06-01 05:24:12 +00:00
|
|
|
use anyhow::anyhow;
|
|
|
|
use arch::layout;
|
2022-08-30 00:48:08 +00:00
|
|
|
use hypervisor::{
|
|
|
|
arch::aarch64::gic::{Vgic, VgicConfig},
|
2022-11-29 12:35:35 +00:00
|
|
|
CpuState, GicState,
|
2022-08-30 00:48:08 +00:00
|
|
|
};
|
2020-05-25 08:59:09 +00:00
|
|
|
use std::result;
|
2021-06-01 12:03:05 +00:00
|
|
|
use std::sync::{Arc, Mutex};
|
2020-05-25 08:59:09 +00:00
|
|
|
use vm_device::interrupt::{
|
2021-03-14 06:35:43 +00:00
|
|
|
InterruptIndex, InterruptManager, InterruptSourceConfig, InterruptSourceGroup,
|
|
|
|
LegacyIrqSourceConfig, MsiIrqGroupConfig,
|
2020-05-25 08:59:09 +00:00
|
|
|
};
|
2022-08-30 00:48:08 +00:00
|
|
|
use vm_memory::address::Address;
|
2022-06-01 05:24:12 +00:00
|
|
|
use vm_migration::{Migratable, MigratableError, Pausable, Snapshot, Snapshottable, Transportable};
|
2021-02-09 07:28:24 +00:00
|
|
|
use vmm_sys_util::eventfd::EventFd;
|
2020-05-25 08:59:09 +00:00
|
|
|
|
|
|
|
type Result<T> = result::Result<T, Error>;
|
|
|
|
|
2022-06-01 05:24:12 +00:00
|
|
|
// Reserve 32 IRQs for legacy devices.
|
|
|
|
pub const IRQ_LEGACY_BASE: usize = layout::IRQ_BASE as usize;
|
2020-05-25 08:59:09 +00:00
|
|
|
pub const IRQ_LEGACY_COUNT: usize = 32;
|
2022-11-29 12:35:35 +00:00
|
|
|
pub const GIC_SNAPSHOT_ID: &str = "gic-v3-its";
|
2020-05-25 08:59:09 +00:00
|
|
|
|
2023-08-31 13:00:19 +00:00
|
|
|
// Gic (Generic Interrupt Controller) struct provides all the functionality of a
|
2022-06-01 05:24:12 +00:00
|
|
|
// GIC device. It wraps a hypervisor-emulated GIC device (Vgic) provided by the
|
|
|
|
// `hypervisor` crate.
|
|
|
|
// Gic struct also implements InterruptController to provide interrupt delivery
|
|
|
|
// service.
|
2020-05-25 08:59:09 +00:00
|
|
|
pub struct Gic {
|
2021-07-29 09:15:10 +00:00
|
|
|
interrupt_source_group: Arc<dyn InterruptSourceGroup>,
|
2022-06-01 05:24:12 +00:00
|
|
|
// The hypervisor agnostic virtual GIC
|
|
|
|
vgic: Option<Arc<Mutex<dyn Vgic>>>,
|
2020-05-25 08:59:09 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
impl Gic {
|
|
|
|
pub fn new(
|
2022-11-06 10:51:12 +00:00
|
|
|
vcpu_count: u8,
|
2020-05-25 08:59:09 +00:00
|
|
|
interrupt_manager: Arc<dyn InterruptManager<GroupConfig = MsiIrqGroupConfig>>,
|
2022-11-06 10:51:12 +00:00
|
|
|
vm: Arc<dyn hypervisor::Vm>,
|
2020-05-25 08:59:09 +00:00
|
|
|
) -> Result<Gic> {
|
|
|
|
let interrupt_source_group = interrupt_manager
|
|
|
|
.create_group(MsiIrqGroupConfig {
|
2021-03-14 06:35:43 +00:00
|
|
|
base: IRQ_LEGACY_BASE as InterruptIndex,
|
2020-05-25 08:59:09 +00:00
|
|
|
count: IRQ_LEGACY_COUNT as InterruptIndex,
|
|
|
|
})
|
|
|
|
.map_err(Error::CreateInterruptSourceGroup)?;
|
|
|
|
|
2022-11-06 10:51:12 +00:00
|
|
|
let vgic = vm
|
|
|
|
.create_vgic(Gic::create_default_config(vcpu_count as u64))
|
|
|
|
.map_err(Error::CreateGic)?;
|
2021-06-01 12:03:05 +00:00
|
|
|
|
2022-11-06 10:51:12 +00:00
|
|
|
let gic = Gic {
|
|
|
|
interrupt_source_group,
|
|
|
|
vgic: Some(vgic),
|
|
|
|
};
|
|
|
|
gic.enable()?;
|
2021-06-01 12:03:05 +00:00
|
|
|
|
2022-11-06 10:51:12 +00:00
|
|
|
Ok(gic)
|
2021-06-01 12:03:05 +00:00
|
|
|
}
|
2020-05-25 08:59:09 +00:00
|
|
|
|
2022-11-29 12:35:35 +00:00
|
|
|
pub fn restore_vgic(
|
|
|
|
&mut self,
|
|
|
|
state: Option<GicState>,
|
2022-12-01 17:22:07 +00:00
|
|
|
saved_vcpu_states: &[CpuState],
|
2022-11-29 12:35:35 +00:00
|
|
|
) -> Result<()> {
|
|
|
|
self.set_gicr_typers(saved_vcpu_states);
|
|
|
|
self.vgic
|
|
|
|
.clone()
|
|
|
|
.unwrap()
|
|
|
|
.lock()
|
|
|
|
.unwrap()
|
|
|
|
.set_state(&state.unwrap())
|
|
|
|
.map_err(Error::RestoreGic)
|
|
|
|
}
|
|
|
|
|
2020-05-25 08:59:09 +00:00
|
|
|
fn enable(&self) -> Result<()> {
|
2021-03-14 06:35:43 +00:00
|
|
|
// Set irqfd for legacy interrupts
|
2020-08-23 07:45:44 +00:00
|
|
|
self.interrupt_source_group
|
2020-05-25 08:59:09 +00:00
|
|
|
.enable()
|
|
|
|
.map_err(Error::EnableInterrupt)?;
|
2021-03-14 06:35:43 +00:00
|
|
|
|
|
|
|
// Set irq_routing for legacy interrupts.
|
|
|
|
// irqchip: Hardcode to 0 as we support only 1 GIC
|
|
|
|
// pin: Use irq number as pin
|
|
|
|
for i in IRQ_LEGACY_BASE..(IRQ_LEGACY_BASE + IRQ_LEGACY_COUNT) {
|
|
|
|
let config = LegacyIrqSourceConfig {
|
|
|
|
irqchip: 0,
|
2021-03-23 11:41:36 +00:00
|
|
|
pin: (i - IRQ_LEGACY_BASE) as u32,
|
2021-03-14 06:35:43 +00:00
|
|
|
};
|
|
|
|
self.interrupt_source_group
|
|
|
|
.update(
|
|
|
|
i as InterruptIndex,
|
|
|
|
InterruptSourceConfig::LegacyIrq(config),
|
2022-04-11 15:21:20 +00:00
|
|
|
false,
|
2023-08-01 06:41:23 +00:00
|
|
|
false,
|
2021-03-14 06:35:43 +00:00
|
|
|
)
|
|
|
|
.map_err(Error::EnableInterrupt)?;
|
|
|
|
}
|
2023-08-01 06:41:23 +00:00
|
|
|
|
|
|
|
self.interrupt_source_group
|
|
|
|
.set_gsi()
|
|
|
|
.map_err(Error::EnableInterrupt)?;
|
2020-05-25 08:59:09 +00:00
|
|
|
Ok(())
|
|
|
|
}
|
|
|
|
|
2022-11-06 10:51:12 +00:00
|
|
|
/// Default config implied by arch::layout
|
|
|
|
pub fn create_default_config(vcpu_count: u64) -> VgicConfig {
|
|
|
|
let redists_size = layout::GIC_V3_REDIST_SIZE * vcpu_count;
|
|
|
|
let redists_addr = layout::GIC_V3_DIST_START.raw_value() - redists_size;
|
|
|
|
VgicConfig {
|
|
|
|
vcpu_count,
|
|
|
|
dist_addr: layout::GIC_V3_DIST_START.raw_value(),
|
|
|
|
dist_size: layout::GIC_V3_DIST_SIZE,
|
|
|
|
redists_addr,
|
|
|
|
redists_size,
|
|
|
|
msi_addr: redists_addr - layout::GIC_V3_ITS_SIZE,
|
|
|
|
msi_size: layout::GIC_V3_ITS_SIZE,
|
|
|
|
nr_irqs: layout::IRQ_NUM,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
pub fn get_vgic(&mut self) -> Result<Arc<Mutex<dyn Vgic>>> {
|
|
|
|
Ok(self.vgic.clone().unwrap())
|
|
|
|
}
|
|
|
|
|
|
|
|
pub fn set_gicr_typers(&mut self, vcpu_states: &[CpuState]) {
|
|
|
|
let vgic = self.vgic.as_ref().unwrap().clone();
|
|
|
|
vgic.lock().unwrap().set_gicr_typers(vcpu_states);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl InterruptController for Gic {
|
2020-05-25 08:59:09 +00:00
|
|
|
// 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(())
|
|
|
|
}
|
2021-02-09 07:28:24 +00:00
|
|
|
|
|
|
|
fn notifier(&self, irq: usize) -> Option<EventFd> {
|
|
|
|
self.interrupt_source_group.notifier(irq as InterruptIndex)
|
|
|
|
}
|
2020-05-25 08:59:09 +00:00
|
|
|
}
|
2022-06-01 05:24:12 +00:00
|
|
|
|
|
|
|
impl Snapshottable for Gic {
|
|
|
|
fn id(&self) -> String {
|
2022-11-29 12:35:35 +00:00
|
|
|
GIC_SNAPSHOT_ID.to_string()
|
2022-06-01 05:24:12 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
fn snapshot(&mut self) -> std::result::Result<Snapshot, MigratableError> {
|
|
|
|
let vgic = self.vgic.as_ref().unwrap().clone();
|
|
|
|
let state = vgic.lock().unwrap().state().unwrap();
|
2022-12-02 14:31:53 +00:00
|
|
|
Snapshot::new_from_state(&state)
|
2022-06-01 05:24:12 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl Pausable for Gic {
|
|
|
|
fn pause(&mut self) -> std::result::Result<(), MigratableError> {
|
|
|
|
// Flush tables to guest RAM
|
|
|
|
let vgic = self.vgic.as_ref().unwrap().clone();
|
|
|
|
vgic.lock().unwrap().save_data_tables().map_err(|e| {
|
|
|
|
MigratableError::Pause(anyhow!(
|
|
|
|
"Could not save GICv3ITS GIC pending tables {:?}",
|
|
|
|
e
|
|
|
|
))
|
|
|
|
})?;
|
|
|
|
Ok(())
|
|
|
|
}
|
|
|
|
}
|
|
|
|
impl Transportable for Gic {}
|
|
|
|
impl Migratable for Gic {}
|