mirror of
https://github.com/cloud-hypervisor/cloud-hypervisor.git
synced 2025-01-05 04:15:20 +00:00
devices: Refactor IOAPIC to cover other architectures
IOAPIC, a X86 specific interrupt controller, is referenced by device manager and CPU manager. To work with more architectures, a common type for all architectures is needed. This commit introduces trait InterruptController to provide architecture agnostic functions. Device manager and CPU manager can use it without caring what the underlying device is. Signed-off-by: Michael Zhao <michael.zhao@arm.com>
This commit is contained in:
parent
d588418053
commit
b32d3025f3
58
devices/src/interrupt_controller.rs
Normal file
58
devices/src/interrupt_controller.rs
Normal file
@ -0,0 +1,58 @@
|
|||||||
|
// Copyright 2020, ARM Limited.
|
||||||
|
//
|
||||||
|
// SPDX-License-Identifier: Apache-2.0 AND BSD-3-Clause
|
||||||
|
|
||||||
|
use std::io;
|
||||||
|
use std::result;
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub enum Error {
|
||||||
|
/// Invalid destination mode.
|
||||||
|
InvalidDestinationMode,
|
||||||
|
/// Invalid trigger mode.
|
||||||
|
InvalidTriggerMode,
|
||||||
|
/// Invalid delivery mode.
|
||||||
|
InvalidDeliveryMode,
|
||||||
|
/// Failed creating the interrupt source group.
|
||||||
|
CreateInterruptSourceGroup(io::Error),
|
||||||
|
/// Failed triggering the interrupt.
|
||||||
|
TriggerInterrupt(io::Error),
|
||||||
|
/// Failed masking the interrupt.
|
||||||
|
MaskInterrupt(io::Error),
|
||||||
|
/// Failed unmasking the interrupt.
|
||||||
|
UnmaskInterrupt(io::Error),
|
||||||
|
/// Failed updating the interrupt.
|
||||||
|
UpdateInterrupt(io::Error),
|
||||||
|
/// Failed enabling the interrupt.
|
||||||
|
EnableInterrupt(io::Error),
|
||||||
|
}
|
||||||
|
|
||||||
|
type Result<T> = result::Result<T, Error>;
|
||||||
|
|
||||||
|
pub struct MsiMessage {
|
||||||
|
// Message Address Register
|
||||||
|
// 31-20: Base address. Fixed value (0x0FEE)
|
||||||
|
// 19-12: Destination ID
|
||||||
|
// 11-4: Reserved
|
||||||
|
// 3: Redirection Hint indication
|
||||||
|
// 2: Destination Mode
|
||||||
|
// 1-0: Reserved
|
||||||
|
pub addr: u32,
|
||||||
|
// Message Data Register
|
||||||
|
// 32-16: Reserved
|
||||||
|
// 15: Trigger Mode. 0 = Edge, 1 = Level
|
||||||
|
// 14: Level. 0 = Deassert, 1 = Assert
|
||||||
|
// 13-11: Reserved
|
||||||
|
// 10-8: Delivery Mode
|
||||||
|
// 7-0: Vector
|
||||||
|
pub data: u32,
|
||||||
|
}
|
||||||
|
|
||||||
|
// Introduce trait InterruptController to uniform the interrupt
|
||||||
|
// service provided for devices.
|
||||||
|
// Device manager uses this trait without caring whether it is a
|
||||||
|
// IOAPIC (X86) or GIC (Arm).
|
||||||
|
pub trait InterruptController: Send {
|
||||||
|
fn service_irq(&mut self, irq: usize) -> Result<()>;
|
||||||
|
fn end_of_interrupt(&mut self, vec: u8);
|
||||||
|
}
|
@ -9,10 +9,10 @@
|
|||||||
// Implementation of an intel 82093AA Input/Output Advanced Programmable Interrupt Controller
|
// Implementation of an intel 82093AA Input/Output Advanced Programmable Interrupt Controller
|
||||||
// See https://pdos.csail.mit.edu/6.828/2016/readings/ia32/ioapic.pdf for a specification.
|
// See https://pdos.csail.mit.edu/6.828/2016/readings/ia32/ioapic.pdf for a specification.
|
||||||
|
|
||||||
|
use super::interrupt_controller::{Error, InterruptController};
|
||||||
use crate::BusDevice;
|
use crate::BusDevice;
|
||||||
use anyhow::anyhow;
|
use anyhow::anyhow;
|
||||||
use byteorder::{ByteOrder, LittleEndian};
|
use byteorder::{ByteOrder, LittleEndian};
|
||||||
use std::io;
|
|
||||||
use std::result;
|
use std::result;
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
use vm_device::interrupt::{
|
use vm_device::interrupt::{
|
||||||
@ -29,28 +29,6 @@ use vm_migration::{
|
|||||||
#[serde(remote = "GuestAddress")]
|
#[serde(remote = "GuestAddress")]
|
||||||
pub struct GuestAddressDef(pub u64);
|
pub struct GuestAddressDef(pub u64);
|
||||||
|
|
||||||
#[derive(Debug)]
|
|
||||||
pub enum Error {
|
|
||||||
/// Invalid destination mode.
|
|
||||||
InvalidDestinationMode,
|
|
||||||
/// Invalid trigger mode.
|
|
||||||
InvalidTriggerMode,
|
|
||||||
/// Invalid delivery mode.
|
|
||||||
InvalidDeliveryMode,
|
|
||||||
/// Failed creating the interrupt source group.
|
|
||||||
CreateInterruptSourceGroup(io::Error),
|
|
||||||
/// Failed triggering the interrupt.
|
|
||||||
TriggerInterrupt(io::Error),
|
|
||||||
/// Failed masking the interrupt.
|
|
||||||
MaskInterrupt(io::Error),
|
|
||||||
/// Failed unmasking the interrupt.
|
|
||||||
UnmaskInterrupt(io::Error),
|
|
||||||
/// Failed updating the interrupt.
|
|
||||||
UpdateInterrupt(io::Error),
|
|
||||||
/// Failed enabling the interrupt.
|
|
||||||
EnableInterrupt(io::Error),
|
|
||||||
}
|
|
||||||
|
|
||||||
type Result<T> = result::Result<T, Error>;
|
type Result<T> = result::Result<T, Error>;
|
||||||
|
|
||||||
// I/O REDIRECTION TABLE REGISTER
|
// I/O REDIRECTION TABLE REGISTER
|
||||||
@ -238,35 +216,77 @@ impl Ioapic {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
// The ioapic must be informed about EOIs in order to deassert interrupts
|
fn ioapic_write(&mut self, val: u32) {
|
||||||
// already sent.
|
debug!("IOAPIC_W reg 0x{:x}, val 0x{:x}", self.reg_sel, val);
|
||||||
pub fn end_of_interrupt(&mut self, vec: u8) {
|
|
||||||
for i in 0..NUM_IOAPIC_PINS {
|
match self.reg_sel as u8 {
|
||||||
let entry = &mut self.reg_entries[i];
|
IOAPIC_REG_ID => self.id_reg = (val >> 24) & 0xf,
|
||||||
// Clear Remote IRR bit
|
IOWIN_OFF..=REG_MAX_OFFSET => {
|
||||||
if vector(*entry) == vec && trigger_mode(*entry) == 1 {
|
let (index, is_high_bits) = decode_irq_from_selector(self.reg_sel as u8);
|
||||||
set_remote_irr(entry, 0);
|
if is_high_bits {
|
||||||
|
self.reg_entries[index] &= 0xffff_ffff;
|
||||||
|
self.reg_entries[index] |= u64::from(val) << 32;
|
||||||
|
} else {
|
||||||
|
// Ensure not to override read-only bits:
|
||||||
|
// - Delivery Status (bit 12)
|
||||||
|
// - Remote IRR (bit 14)
|
||||||
|
self.reg_entries[index] &= 0xffff_ffff_0000_5000;
|
||||||
|
self.reg_entries[index] |= u64::from(val) & 0xffff_afff;
|
||||||
|
}
|
||||||
|
// The entry must be updated through the interrupt source
|
||||||
|
// group.
|
||||||
|
if let Err(e) = self.update_entry(index) {
|
||||||
|
error!("Failed updating IOAPIC entry: {:?}", e);
|
||||||
|
}
|
||||||
|
// Store the information this IRQ is now being used.
|
||||||
|
self.used_entries[index] = true;
|
||||||
|
}
|
||||||
|
_ => error!("IOAPIC: invalid write to register offset"),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn ioapic_read(&self) -> u32 {
|
||||||
|
debug!("IOAPIC_R reg 0x{:x}", self.reg_sel);
|
||||||
|
|
||||||
|
match self.reg_sel as u8 {
|
||||||
|
IOAPIC_REG_VERSION => IOAPIC_VERSION_ID,
|
||||||
|
IOAPIC_REG_ID | IOAPIC_REG_ARBITRATION_ID => (self.id_reg & 0xf) << 24,
|
||||||
|
IOWIN_OFF..=REG_MAX_OFFSET => {
|
||||||
|
let (index, is_high_bits) = decode_irq_from_selector(self.reg_sel as u8);
|
||||||
|
if is_high_bits {
|
||||||
|
(self.reg_entries[index] >> 32) as u32
|
||||||
|
} else {
|
||||||
|
(self.reg_entries[index] & 0xffff_ffff) as u32
|
||||||
|
}
|
||||||
|
}
|
||||||
|
_ => {
|
||||||
|
error!("IOAPIC: invalid read from register offset");
|
||||||
|
0
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// This should be called anytime an interrupt needs to be injected into the
|
fn state(&self) -> IoapicState {
|
||||||
// running guest.
|
IoapicState {
|
||||||
pub fn service_irq(&mut self, irq: usize) -> Result<()> {
|
id_reg: self.id_reg,
|
||||||
let entry = &mut self.reg_entries[irq];
|
reg_sel: self.reg_sel,
|
||||||
|
reg_entries: self.reg_entries,
|
||||||
self.interrupt_source_group
|
used_entries: self.used_entries,
|
||||||
.trigger(irq as InterruptIndex)
|
apic_address: self.apic_address,
|
||||||
.map_err(Error::TriggerInterrupt)?;
|
}
|
||||||
debug!("Interrupt successfully delivered");
|
}
|
||||||
|
|
||||||
// If trigger mode is level sensitive, set the Remote IRR bit.
|
fn set_state(&mut self, state: &IoapicState) -> Result<()> {
|
||||||
// It will be cleared when the EOI is received.
|
self.id_reg = state.id_reg;
|
||||||
if trigger_mode(*entry) == 1 {
|
self.reg_sel = state.reg_sel;
|
||||||
set_remote_irr(entry, 1);
|
self.reg_entries = state.reg_entries;
|
||||||
|
self.used_entries = state.used_entries;
|
||||||
|
self.apic_address = state.apic_address;
|
||||||
|
for (irq, entry) in self.used_entries.iter().enumerate() {
|
||||||
|
if *entry {
|
||||||
|
self.update_entry(irq)?;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
// Clear the Delivery Status bit
|
|
||||||
set_delivery_status(entry, 0);
|
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
@ -342,78 +362,38 @@ impl Ioapic {
|
|||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fn ioapic_write(&mut self, val: u32) {
|
impl InterruptController for Ioapic {
|
||||||
debug!("IOAPIC_W reg 0x{:x}, val 0x{:x}", self.reg_sel, val);
|
// The ioapic must be informed about EOIs in order to deassert interrupts
|
||||||
|
// already sent.
|
||||||
match self.reg_sel as u8 {
|
fn end_of_interrupt(&mut self, vec: u8) {
|
||||||
IOAPIC_REG_ID => self.id_reg = (val >> 24) & 0xf,
|
for i in 0..NUM_IOAPIC_PINS {
|
||||||
IOWIN_OFF..=REG_MAX_OFFSET => {
|
let entry = &mut self.reg_entries[i];
|
||||||
let (index, is_high_bits) = decode_irq_from_selector(self.reg_sel as u8);
|
// Clear Remote IRR bit
|
||||||
if is_high_bits {
|
if vector(*entry) == vec && trigger_mode(*entry) == 1 {
|
||||||
self.reg_entries[index] &= 0xffff_ffff;
|
set_remote_irr(entry, 0);
|
||||||
self.reg_entries[index] |= u64::from(val) << 32;
|
|
||||||
} else {
|
|
||||||
// Ensure not to override read-only bits:
|
|
||||||
// - Delivery Status (bit 12)
|
|
||||||
// - Remote IRR (bit 14)
|
|
||||||
self.reg_entries[index] &= 0xffff_ffff_0000_5000;
|
|
||||||
self.reg_entries[index] |= u64::from(val) & 0xffff_afff;
|
|
||||||
}
|
|
||||||
// The entry must be updated through the interrupt source
|
|
||||||
// group.
|
|
||||||
if let Err(e) = self.update_entry(index) {
|
|
||||||
error!("Failed updating IOAPIC entry: {:?}", e);
|
|
||||||
}
|
|
||||||
// Store the information this IRQ is now being used.
|
|
||||||
self.used_entries[index] = true;
|
|
||||||
}
|
|
||||||
_ => error!("IOAPIC: invalid write to register offset"),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn ioapic_read(&self) -> u32 {
|
|
||||||
debug!("IOAPIC_R reg 0x{:x}", self.reg_sel);
|
|
||||||
|
|
||||||
match self.reg_sel as u8 {
|
|
||||||
IOAPIC_REG_VERSION => IOAPIC_VERSION_ID,
|
|
||||||
IOAPIC_REG_ID | IOAPIC_REG_ARBITRATION_ID => (self.id_reg & 0xf) << 24,
|
|
||||||
IOWIN_OFF..=REG_MAX_OFFSET => {
|
|
||||||
let (index, is_high_bits) = decode_irq_from_selector(self.reg_sel as u8);
|
|
||||||
if is_high_bits {
|
|
||||||
(self.reg_entries[index] >> 32) as u32
|
|
||||||
} else {
|
|
||||||
(self.reg_entries[index] & 0xffff_ffff) as u32
|
|
||||||
}
|
|
||||||
}
|
|
||||||
_ => {
|
|
||||||
error!("IOAPIC: invalid read from register offset");
|
|
||||||
0
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn state(&self) -> IoapicState {
|
// This should be called anytime an interrupt needs to be injected into the
|
||||||
IoapicState {
|
// running guest.
|
||||||
id_reg: self.id_reg,
|
fn service_irq(&mut self, irq: usize) -> Result<()> {
|
||||||
reg_sel: self.reg_sel,
|
let entry = &mut self.reg_entries[irq];
|
||||||
reg_entries: self.reg_entries,
|
|
||||||
used_entries: self.used_entries,
|
|
||||||
apic_address: self.apic_address,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn set_state(&mut self, state: &IoapicState) -> Result<()> {
|
self.interrupt_source_group
|
||||||
self.id_reg = state.id_reg;
|
.trigger(irq as InterruptIndex)
|
||||||
self.reg_sel = state.reg_sel;
|
.map_err(Error::TriggerInterrupt)?;
|
||||||
self.reg_entries = state.reg_entries;
|
debug!("Interrupt successfully delivered");
|
||||||
self.used_entries = state.used_entries;
|
|
||||||
self.apic_address = state.apic_address;
|
// If trigger mode is level sensitive, set the Remote IRR bit.
|
||||||
for (irq, entry) in self.used_entries.iter().enumerate() {
|
// It will be cleared when the EOI is received.
|
||||||
if *entry {
|
if trigger_mode(*entry) == 1 {
|
||||||
self.update_entry(irq)?;
|
set_remote_irr(entry, 1);
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
// Clear the Delivery Status bit
|
||||||
|
set_delivery_status(entry, 0);
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
@ -31,6 +31,7 @@ use std::io;
|
|||||||
#[cfg(feature = "acpi")]
|
#[cfg(feature = "acpi")]
|
||||||
mod acpi;
|
mod acpi;
|
||||||
mod bus;
|
mod bus;
|
||||||
|
pub mod interrupt_controller;
|
||||||
pub mod ioapic;
|
pub mod ioapic;
|
||||||
pub mod legacy;
|
pub mod legacy;
|
||||||
|
|
||||||
|
@ -20,7 +20,7 @@ use anyhow::anyhow;
|
|||||||
#[cfg(feature = "acpi")]
|
#[cfg(feature = "acpi")]
|
||||||
use arch::layout;
|
use arch::layout;
|
||||||
use arch::EntryPoint;
|
use arch::EntryPoint;
|
||||||
use devices::{ioapic, BusDevice};
|
use devices::{interrupt_controller::InterruptController, BusDevice};
|
||||||
#[cfg(target_arch = "x86_64")]
|
#[cfg(target_arch = "x86_64")]
|
||||||
use kvm_bindings::{
|
use kvm_bindings::{
|
||||||
kvm_fpu, kvm_lapic_state, kvm_mp_state, kvm_regs, kvm_sregs, kvm_vcpu_events, kvm_xcrs,
|
kvm_fpu, kvm_lapic_state, kvm_mp_state, kvm_regs, kvm_sregs, kvm_vcpu_events, kvm_xcrs,
|
||||||
@ -329,7 +329,7 @@ pub struct Vcpu {
|
|||||||
io_bus: Arc<devices::Bus>,
|
io_bus: Arc<devices::Bus>,
|
||||||
mmio_bus: Arc<devices::Bus>,
|
mmio_bus: Arc<devices::Bus>,
|
||||||
#[cfg_attr(target_arch = "aarch64", allow(dead_code))]
|
#[cfg_attr(target_arch = "aarch64", allow(dead_code))]
|
||||||
ioapic: Option<Arc<Mutex<ioapic::Ioapic>>>,
|
interrupt_controller: Option<Arc<Mutex<dyn InterruptController>>>,
|
||||||
#[cfg_attr(target_arch = "aarch64", allow(dead_code))]
|
#[cfg_attr(target_arch = "aarch64", allow(dead_code))]
|
||||||
vm_ts: std::time::Instant,
|
vm_ts: std::time::Instant,
|
||||||
}
|
}
|
||||||
@ -364,7 +364,7 @@ impl Vcpu {
|
|||||||
fd: &Arc<VmFd>,
|
fd: &Arc<VmFd>,
|
||||||
io_bus: Arc<devices::Bus>,
|
io_bus: Arc<devices::Bus>,
|
||||||
mmio_bus: Arc<devices::Bus>,
|
mmio_bus: Arc<devices::Bus>,
|
||||||
ioapic: Option<Arc<Mutex<ioapic::Ioapic>>>,
|
interrupt_controller: Option<Arc<Mutex<dyn InterruptController>>>,
|
||||||
creation_ts: std::time::Instant,
|
creation_ts: std::time::Instant,
|
||||||
) -> Result<Arc<Mutex<Self>>> {
|
) -> Result<Arc<Mutex<Self>>> {
|
||||||
let kvm_vcpu = fd.create_vcpu(id).map_err(Error::VcpuFd)?;
|
let kvm_vcpu = fd.create_vcpu(id).map_err(Error::VcpuFd)?;
|
||||||
@ -374,7 +374,7 @@ impl Vcpu {
|
|||||||
id,
|
id,
|
||||||
io_bus,
|
io_bus,
|
||||||
mmio_bus,
|
mmio_bus,
|
||||||
ioapic,
|
interrupt_controller,
|
||||||
vm_ts: creation_ts,
|
vm_ts: creation_ts,
|
||||||
})))
|
})))
|
||||||
}
|
}
|
||||||
@ -452,8 +452,11 @@ impl Vcpu {
|
|||||||
}
|
}
|
||||||
#[cfg(target_arch = "x86_64")]
|
#[cfg(target_arch = "x86_64")]
|
||||||
VcpuExit::IoapicEoi(vector) => {
|
VcpuExit::IoapicEoi(vector) => {
|
||||||
if let Some(ioapic) = &self.ioapic {
|
if let Some(interrupt_controller) = &self.interrupt_controller {
|
||||||
ioapic.lock().unwrap().end_of_interrupt(vector);
|
interrupt_controller
|
||||||
|
.lock()
|
||||||
|
.unwrap()
|
||||||
|
.end_of_interrupt(vector);
|
||||||
}
|
}
|
||||||
Ok(true)
|
Ok(true)
|
||||||
}
|
}
|
||||||
@ -618,7 +621,7 @@ pub struct CpuManager {
|
|||||||
#[cfg_attr(target_arch = "aarch64", allow(dead_code))]
|
#[cfg_attr(target_arch = "aarch64", allow(dead_code))]
|
||||||
mmio_bus: Arc<devices::Bus>,
|
mmio_bus: Arc<devices::Bus>,
|
||||||
#[cfg_attr(target_arch = "aarch64", allow(dead_code))]
|
#[cfg_attr(target_arch = "aarch64", allow(dead_code))]
|
||||||
ioapic: Option<Arc<Mutex<ioapic::Ioapic>>>,
|
interrupt_controller: Option<Arc<Mutex<dyn InterruptController>>>,
|
||||||
#[cfg_attr(target_arch = "aarch64", allow(dead_code))]
|
#[cfg_attr(target_arch = "aarch64", allow(dead_code))]
|
||||||
vm_memory: GuestMemoryAtomic<GuestMemoryMmap>,
|
vm_memory: GuestMemoryAtomic<GuestMemoryMmap>,
|
||||||
#[cfg(target_arch = "x86_64")]
|
#[cfg(target_arch = "x86_64")]
|
||||||
@ -769,7 +772,7 @@ impl CpuManager {
|
|||||||
max_vcpus: config.max_vcpus,
|
max_vcpus: config.max_vcpus,
|
||||||
io_bus: device_manager.io_bus().clone(),
|
io_bus: device_manager.io_bus().clone(),
|
||||||
mmio_bus: device_manager.mmio_bus().clone(),
|
mmio_bus: device_manager.mmio_bus().clone(),
|
||||||
ioapic: device_manager.ioapic().clone(),
|
interrupt_controller: device_manager.interrupt_controller().clone(),
|
||||||
vm_memory: guest_memory,
|
vm_memory: guest_memory,
|
||||||
#[cfg(target_arch = "x86_64")]
|
#[cfg(target_arch = "x86_64")]
|
||||||
cpuid,
|
cpuid,
|
||||||
@ -858,8 +861,8 @@ impl CpuManager {
|
|||||||
inserting: bool,
|
inserting: bool,
|
||||||
snapshot: Option<Snapshot>,
|
snapshot: Option<Snapshot>,
|
||||||
) -> Result<()> {
|
) -> Result<()> {
|
||||||
let ioapic = if let Some(ioapic) = &self.ioapic {
|
let interrupt_controller = if let Some(interrupt_controller) = &self.interrupt_controller {
|
||||||
Some(ioapic.clone())
|
Some(interrupt_controller.clone())
|
||||||
} else {
|
} else {
|
||||||
None
|
None
|
||||||
};
|
};
|
||||||
@ -869,7 +872,7 @@ impl CpuManager {
|
|||||||
&self.fd,
|
&self.fd,
|
||||||
self.io_bus.clone(),
|
self.io_bus.clone(),
|
||||||
self.mmio_bus.clone(),
|
self.mmio_bus.clone(),
|
||||||
ioapic,
|
interrupt_controller,
|
||||||
creation_ts,
|
creation_ts,
|
||||||
)?;
|
)?;
|
||||||
|
|
||||||
|
@ -26,7 +26,10 @@ use anyhow::anyhow;
|
|||||||
use arch::layout;
|
use arch::layout;
|
||||||
#[cfg(target_arch = "x86_64")]
|
#[cfg(target_arch = "x86_64")]
|
||||||
use arch::layout::{APIC_START, IOAPIC_SIZE, IOAPIC_START};
|
use arch::layout::{APIC_START, IOAPIC_SIZE, IOAPIC_START};
|
||||||
use devices::{ioapic, BusDevice, HotPlugNotificationFlags};
|
use devices::{
|
||||||
|
interrupt_controller, interrupt_controller::InterruptController, ioapic, BusDevice,
|
||||||
|
HotPlugNotificationFlags,
|
||||||
|
};
|
||||||
use kvm_ioctls::*;
|
use kvm_ioctls::*;
|
||||||
use libc::TIOCGWINSZ;
|
use libc::TIOCGWINSZ;
|
||||||
use libc::{MAP_NORESERVE, MAP_PRIVATE, MAP_SHARED, O_TMPFILE, PROT_READ, PROT_WRITE};
|
use libc::{MAP_NORESERVE, MAP_PRIVATE, MAP_SHARED, O_TMPFILE, PROT_READ, PROT_WRITE};
|
||||||
@ -235,8 +238,8 @@ pub enum DeviceManagerError {
|
|||||||
/// Failed to update interrupt source group.
|
/// Failed to update interrupt source group.
|
||||||
UpdateInterruptGroup(io::Error),
|
UpdateInterruptGroup(io::Error),
|
||||||
|
|
||||||
/// Failed creating IOAPIC.
|
/// Failed creating interrupt controller.
|
||||||
CreateIoapic(ioapic::Error),
|
CreateInterruptController(interrupt_controller::Error),
|
||||||
|
|
||||||
/// Failed creating a new MmapRegion instance.
|
/// Failed creating a new MmapRegion instance.
|
||||||
NewMmapRegion(vm_memory::mmap::MmapRegionError),
|
NewMmapRegion(vm_memory::mmap::MmapRegionError),
|
||||||
@ -626,8 +629,8 @@ pub struct DeviceManager {
|
|||||||
// Console abstraction
|
// Console abstraction
|
||||||
console: Arc<Console>,
|
console: Arc<Console>,
|
||||||
|
|
||||||
// IOAPIC
|
// Interrupt controller
|
||||||
ioapic: Option<Arc<Mutex<ioapic::Ioapic>>>,
|
interrupt_controller: Option<Arc<Mutex<ioapic::Ioapic>>>,
|
||||||
|
|
||||||
// Things to be added to the commandline (i.e. for virtio-mmio)
|
// Things to be added to the commandline (i.e. for virtio-mmio)
|
||||||
cmdline_additions: Vec<String>,
|
cmdline_additions: Vec<String>,
|
||||||
@ -746,7 +749,7 @@ impl DeviceManager {
|
|||||||
let device_manager = DeviceManager {
|
let device_manager = DeviceManager {
|
||||||
address_manager: Arc::clone(&address_manager),
|
address_manager: Arc::clone(&address_manager),
|
||||||
console: Arc::new(Console::default()),
|
console: Arc::new(Console::default()),
|
||||||
ioapic: None,
|
interrupt_controller: None,
|
||||||
cmdline_additions: Vec::new(),
|
cmdline_additions: Vec::new(),
|
||||||
#[cfg(feature = "acpi")]
|
#[cfg(feature = "acpi")]
|
||||||
ged_notification_device: None,
|
ged_notification_device: None,
|
||||||
@ -804,13 +807,15 @@ impl DeviceManager {
|
|||||||
pub fn create_devices(&mut self) -> DeviceManagerResult<()> {
|
pub fn create_devices(&mut self) -> DeviceManagerResult<()> {
|
||||||
let mut virtio_devices: Vec<(VirtioDeviceArc, bool, String)> = Vec::new();
|
let mut virtio_devices: Vec<(VirtioDeviceArc, bool, String)> = Vec::new();
|
||||||
|
|
||||||
let ioapic = self.add_ioapic()?;
|
let interrupt_controller = self.add_interrupt_controller()?;
|
||||||
|
|
||||||
// Now we can create the legacy interrupt manager, which needs the freshly
|
// Now we can create the legacy interrupt manager, which needs the freshly
|
||||||
// formed IOAPIC device.
|
// formed IOAPIC device.
|
||||||
let legacy_interrupt_manager: Arc<
|
let legacy_interrupt_manager: Arc<
|
||||||
dyn InterruptManager<GroupConfig = LegacyIrqGroupConfig>,
|
dyn InterruptManager<GroupConfig = LegacyIrqGroupConfig>,
|
||||||
> = Arc::new(KvmLegacyUserspaceInterruptManager::new(ioapic));
|
> = Arc::new(KvmLegacyUserspaceInterruptManager::new(Arc::clone(
|
||||||
|
&interrupt_controller,
|
||||||
|
)));
|
||||||
|
|
||||||
#[cfg(feature = "acpi")]
|
#[cfg(feature = "acpi")]
|
||||||
self.address_manager
|
self.address_manager
|
||||||
@ -1003,33 +1008,37 @@ impl DeviceManager {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(target_arch = "aarch64")]
|
#[cfg(target_arch = "aarch64")]
|
||||||
fn add_ioapic(&mut self) -> DeviceManagerResult<Arc<Mutex<ioapic::Ioapic>>> {
|
fn add_interrupt_controller(
|
||||||
|
&mut self,
|
||||||
|
) -> DeviceManagerResult<Arc<Mutex<dyn InterruptController>>> {
|
||||||
unimplemented!();
|
unimplemented!();
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(target_arch = "x86_64")]
|
#[cfg(target_arch = "x86_64")]
|
||||||
fn add_ioapic(&mut self) -> DeviceManagerResult<Arc<Mutex<ioapic::Ioapic>>> {
|
fn add_interrupt_controller(
|
||||||
|
&mut self,
|
||||||
|
) -> DeviceManagerResult<Arc<Mutex<dyn InterruptController>>> {
|
||||||
let id = String::from(IOAPIC_DEVICE_NAME);
|
let id = String::from(IOAPIC_DEVICE_NAME);
|
||||||
|
|
||||||
// Create IOAPIC
|
// Create IOAPIC
|
||||||
let ioapic = Arc::new(Mutex::new(
|
let interrupt_controller = Arc::new(Mutex::new(
|
||||||
ioapic::Ioapic::new(
|
ioapic::Ioapic::new(
|
||||||
id.clone(),
|
id.clone(),
|
||||||
APIC_START,
|
APIC_START,
|
||||||
Arc::clone(&self.msi_interrupt_manager),
|
Arc::clone(&self.msi_interrupt_manager),
|
||||||
)
|
)
|
||||||
.map_err(DeviceManagerError::CreateIoapic)?,
|
.map_err(DeviceManagerError::CreateInterruptController)?,
|
||||||
));
|
));
|
||||||
|
|
||||||
self.ioapic = Some(ioapic.clone());
|
self.interrupt_controller = Some(interrupt_controller.clone());
|
||||||
|
|
||||||
self.address_manager
|
self.address_manager
|
||||||
.mmio_bus
|
.mmio_bus
|
||||||
.insert(ioapic.clone(), IOAPIC_START.0, IOAPIC_SIZE)
|
.insert(interrupt_controller.clone(), IOAPIC_START.0, IOAPIC_SIZE)
|
||||||
.map_err(DeviceManagerError::BusError)?;
|
.map_err(DeviceManagerError::BusError)?;
|
||||||
|
|
||||||
self.bus_devices
|
self.bus_devices
|
||||||
.push(Arc::clone(&ioapic) as Arc<Mutex<dyn BusDevice>>);
|
.push(Arc::clone(&interrupt_controller) as Arc<Mutex<dyn BusDevice>>);
|
||||||
|
|
||||||
// Fill the device tree with a new node. In case of restore, we
|
// 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
|
// know there is nothing to do, so we can simply override the
|
||||||
@ -1037,9 +1046,9 @@ impl DeviceManager {
|
|||||||
self.device_tree
|
self.device_tree
|
||||||
.lock()
|
.lock()
|
||||||
.unwrap()
|
.unwrap()
|
||||||
.insert(id.clone(), device_node!(id, ioapic));
|
.insert(id.clone(), device_node!(id, interrupt_controller));
|
||||||
|
|
||||||
Ok(ioapic)
|
Ok(interrupt_controller)
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(feature = "acpi")]
|
#[cfg(feature = "acpi")]
|
||||||
@ -2550,8 +2559,12 @@ impl DeviceManager {
|
|||||||
&self.address_manager.allocator
|
&self.address_manager.allocator
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn ioapic(&self) -> &Option<Arc<Mutex<ioapic::Ioapic>>> {
|
pub fn interrupt_controller(&self) -> Option<Arc<Mutex<dyn InterruptController>>> {
|
||||||
&self.ioapic
|
if let Some(interrupt_controller) = &self.interrupt_controller {
|
||||||
|
Some(interrupt_controller.clone() as Arc<Mutex<dyn InterruptController>>)
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn console(&self) -> &Arc<Console> {
|
pub fn console(&self) -> &Arc<Console> {
|
||||||
|
@ -3,7 +3,7 @@
|
|||||||
// SPDX-License-Identifier: Apache-2.0 AND BSD-3-Clause
|
// SPDX-License-Identifier: Apache-2.0 AND BSD-3-Clause
|
||||||
//
|
//
|
||||||
|
|
||||||
use devices::ioapic;
|
use devices::interrupt_controller::InterruptController;
|
||||||
use kvm_bindings::{kvm_irq_routing, kvm_irq_routing_entry, KVM_IRQ_ROUTING_MSI};
|
use kvm_bindings::{kvm_irq_routing, kvm_irq_routing_entry, KVM_IRQ_ROUTING_MSI};
|
||||||
use kvm_ioctls::VmFd;
|
use kvm_ioctls::VmFd;
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
@ -281,12 +281,12 @@ impl InterruptSourceGroup for MsiInterruptGroup {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub struct LegacyUserspaceInterruptGroup {
|
pub struct LegacyUserspaceInterruptGroup {
|
||||||
ioapic: Arc<Mutex<ioapic::Ioapic>>,
|
ioapic: Arc<Mutex<dyn InterruptController>>,
|
||||||
irq: u32,
|
irq: u32,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl LegacyUserspaceInterruptGroup {
|
impl LegacyUserspaceInterruptGroup {
|
||||||
fn new(ioapic: Arc<Mutex<ioapic::Ioapic>>, irq: u32) -> Self {
|
fn new(ioapic: Arc<Mutex<dyn InterruptController>>, irq: u32) -> Self {
|
||||||
LegacyUserspaceInterruptGroup { ioapic, irq }
|
LegacyUserspaceInterruptGroup { ioapic, irq }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -311,7 +311,7 @@ impl InterruptSourceGroup for LegacyUserspaceInterruptGroup {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub struct KvmLegacyUserspaceInterruptManager {
|
pub struct KvmLegacyUserspaceInterruptManager {
|
||||||
ioapic: Arc<Mutex<ioapic::Ioapic>>,
|
ioapic: Arc<Mutex<dyn InterruptController>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct KvmMsiInterruptManager {
|
pub struct KvmMsiInterruptManager {
|
||||||
@ -321,7 +321,7 @@ pub struct KvmMsiInterruptManager {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl KvmLegacyUserspaceInterruptManager {
|
impl KvmLegacyUserspaceInterruptManager {
|
||||||
pub fn new(ioapic: Arc<Mutex<ioapic::Ioapic>>) -> Self {
|
pub fn new(ioapic: Arc<Mutex<dyn InterruptController>>) -> Self {
|
||||||
KvmLegacyUserspaceInterruptManager { ioapic }
|
KvmLegacyUserspaceInterruptManager { ioapic }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user