mirror of
https://github.com/cloud-hypervisor/cloud-hypervisor.git
synced 2025-02-21 19:02:30 +00:00
devices: Implement InterruptController on AArch64
This commit only implements the InterruptController crate on AArch64. The device specific part for GIC is to be added. Signed-off-by: Michael Zhao <michael.zhao@arm.com>
This commit is contained in:
parent
b32d3025f3
commit
8f1f9d9e6b
85
devices/src/gic.rs
Normal file
85
devices/src/gic.rs
Normal file
@ -0,0 +1,85 @@
|
||||
// Copyright 2020, ARM Limited.
|
||||
//
|
||||
// SPDX-License-Identifier: Apache-2.0 AND BSD-3-Clause
|
||||
|
||||
use super::interrupt_controller::{Error, InterruptController};
|
||||
use std::result;
|
||||
use std::sync::Arc;
|
||||
use vm_device::interrupt::{
|
||||
InterruptIndex, InterruptManager, InterruptSourceGroup, MsiIrqGroupConfig,
|
||||
};
|
||||
use vm_migration::{Migratable, MigratableError, Pausable, Snapshot, Snapshottable, Transportable};
|
||||
|
||||
type Result<T> = result::Result<T, Error>;
|
||||
|
||||
// Reserve 32 IRQs (GSI 32 ~ 64) for legacy device.
|
||||
// GsiAllocator should allocate beyond this: from 64 on
|
||||
pub const IRQ_LEGACY_COUNT: usize = 32;
|
||||
pub const IRQ_SPI_OFFSET: usize = 32;
|
||||
|
||||
// This Gic struct implements InterruptController to provide interrupt delivery service.
|
||||
// The Gic source files in arch/ folder maintain the Aarch64 specific Gic device.
|
||||
// The 2 Gic instances could be merged together.
|
||||
// Leave this refactoring to future. Two options may be considered:
|
||||
// 1. Move Gic*.rs from arch/ folder here.
|
||||
// 2. Move this file and ioapic.rs to arch/, as they are architecture specific.
|
||||
pub struct Gic {
|
||||
interrupt_source_group: Arc<Box<dyn InterruptSourceGroup>>,
|
||||
}
|
||||
|
||||
impl Gic {
|
||||
pub fn new(
|
||||
_vcpu_count: u8,
|
||||
interrupt_manager: Arc<dyn InterruptManager<GroupConfig = MsiIrqGroupConfig>>,
|
||||
) -> Result<Gic> {
|
||||
let interrupt_source_group = interrupt_manager
|
||||
.create_group(MsiIrqGroupConfig {
|
||||
base: IRQ_SPI_OFFSET as InterruptIndex,
|
||||
count: IRQ_LEGACY_COUNT as InterruptIndex,
|
||||
})
|
||||
.map_err(Error::CreateInterruptSourceGroup)?;
|
||||
|
||||
Ok(Gic {
|
||||
interrupt_source_group,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl InterruptController for Gic {
|
||||
fn enable(&self) -> Result<()> {
|
||||
&self
|
||||
.interrupt_source_group
|
||||
.enable()
|
||||
.map_err(Error::EnableInterrupt)?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
// 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(())
|
||||
}
|
||||
}
|
||||
|
||||
const GIC_SNAPSHOT_ID: &str = "gic";
|
||||
impl Snapshottable for Gic {
|
||||
fn id(&self) -> String {
|
||||
GIC_SNAPSHOT_ID.to_string()
|
||||
}
|
||||
|
||||
fn snapshot(&self) -> std::result::Result<Snapshot, MigratableError> {
|
||||
unimplemented!();
|
||||
}
|
||||
|
||||
fn restore(&mut self, _snapshot: Snapshot) -> std::result::Result<(), MigratableError> {
|
||||
unimplemented!();
|
||||
}
|
||||
}
|
||||
|
||||
impl Pausable for Gic {}
|
||||
impl Transportable for Gic {}
|
||||
impl Migratable for Gic {}
|
@ -54,5 +54,8 @@ pub struct MsiMessage {
|
||||
// IOAPIC (X86) or GIC (Arm).
|
||||
pub trait InterruptController: Send {
|
||||
fn service_irq(&mut self, irq: usize) -> Result<()>;
|
||||
#[cfg(target_arch = "aarch64")]
|
||||
fn enable(&self) -> Result<()>;
|
||||
#[cfg(target_arch = "x86_64")]
|
||||
fn end_of_interrupt(&mut self, vec: u8);
|
||||
}
|
||||
|
@ -31,7 +31,10 @@ use std::io;
|
||||
#[cfg(feature = "acpi")]
|
||||
mod acpi;
|
||||
mod bus;
|
||||
#[cfg(target_arch = "aarch64")]
|
||||
pub mod gic;
|
||||
pub mod interrupt_controller;
|
||||
#[cfg(target_arch = "x86_64")]
|
||||
pub mod ioapic;
|
||||
pub mod legacy;
|
||||
|
||||
|
@ -26,8 +26,12 @@ use anyhow::anyhow;
|
||||
use arch::layout;
|
||||
#[cfg(target_arch = "x86_64")]
|
||||
use arch::layout::{APIC_START, IOAPIC_SIZE, IOAPIC_START};
|
||||
#[cfg(target_arch = "aarch64")]
|
||||
use devices::gic;
|
||||
#[cfg(target_arch = "x86_64")]
|
||||
use devices::ioapic;
|
||||
use devices::{
|
||||
interrupt_controller, interrupt_controller::InterruptController, ioapic, BusDevice,
|
||||
interrupt_controller, interrupt_controller::InterruptController, BusDevice,
|
||||
HotPlugNotificationFlags,
|
||||
};
|
||||
use kvm_ioctls::*;
|
||||
@ -81,6 +85,9 @@ const VFIO_DEVICE_NAME_PREFIX: &str = "_vfio";
|
||||
|
||||
#[cfg(target_arch = "x86_64")]
|
||||
const IOAPIC_DEVICE_NAME: &str = "_ioapic";
|
||||
#[cfg(target_arch = "aarch64")]
|
||||
const GIC_DEVICE_NAME: &str = "_gic";
|
||||
|
||||
const SERIAL_DEVICE_NAME_PREFIX: &str = "_serial";
|
||||
|
||||
const CONSOLE_DEVICE_NAME: &str = "_console";
|
||||
@ -630,7 +637,10 @@ pub struct DeviceManager {
|
||||
console: Arc<Console>,
|
||||
|
||||
// Interrupt controller
|
||||
#[cfg(target_arch = "x86_64")]
|
||||
interrupt_controller: Option<Arc<Mutex<ioapic::Ioapic>>>,
|
||||
#[cfg(target_arch = "aarch64")]
|
||||
interrupt_controller: Option<Arc<Mutex<gic::Gic>>>,
|
||||
|
||||
// Things to be added to the commandline (i.e. for virtio-mmio)
|
||||
cmdline_additions: Vec<String>,
|
||||
@ -1011,7 +1021,27 @@ impl DeviceManager {
|
||||
fn add_interrupt_controller(
|
||||
&mut self,
|
||||
) -> DeviceManagerResult<Arc<Mutex<dyn InterruptController>>> {
|
||||
unimplemented!();
|
||||
let id = String::from(GIC_DEVICE_NAME);
|
||||
|
||||
let interrupt_controller: Arc<Mutex<gic::Gic>> = Arc::new(Mutex::new(
|
||||
gic::Gic::new(
|
||||
self.config.lock().unwrap().cpus.boot_vcpus,
|
||||
Arc::clone(&self.msi_interrupt_manager),
|
||||
)
|
||||
.map_err(DeviceManagerError::CreateInterruptController)?,
|
||||
));
|
||||
|
||||
self.interrupt_controller = Some(interrupt_controller.clone());
|
||||
|
||||
// Fill the device tree with a new node. In case of restore, we
|
||||
// know there is nothing to do, so we can simply override the
|
||||
// existing entry.
|
||||
self.device_tree
|
||||
.lock()
|
||||
.unwrap()
|
||||
.insert(id.clone(), device_node!(id, interrupt_controller));
|
||||
|
||||
Ok(interrupt_controller)
|
||||
}
|
||||
|
||||
#[cfg(target_arch = "x86_64")]
|
||||
|
Loading…
x
Reference in New Issue
Block a user