vmm: device_manager: Add ability to notify via GED device

Add ability to notify via the GED device that there is some new hotplug
activity. This will be used by the CpuManager (and later DeviceManager
itself) to notify of new hotplug activity.

Currently it has a hardcoded IRQ of 5 as the ACPI tables also need to
refer to this IRQ and the IRQ allocation does not permit the allocation
of specific IRQs.

Signed-off-by: Rob Bradford <robert.bradford@intel.com>
This commit is contained in:
Rob Bradford 2019-11-27 15:28:22 +00:00
parent 623755cc70
commit 791ca3388f
2 changed files with 78 additions and 22 deletions

View File

@ -12,7 +12,7 @@
use crate::config::ConsoleOutputMode;
use crate::vm::VmInfo;
use devices::ioapic;
use devices::{ioapic, HotPlugNotificationType};
use kvm_bindings::kvm_userspace_memory_region;
use kvm_ioctls::*;
use libc::O_TMPFILE;
@ -169,6 +169,9 @@ pub enum DeviceManagerError {
/// Failed to allocate IO port
AllocateIOPort,
// Failed to make hotplug notification
HotPlugNotification(io::Error),
}
pub type DeviceManagerResult<T> = result::Result<T, DeviceManagerError>;
@ -402,6 +405,10 @@ pub struct DeviceManager {
// Virtual IOMMU ID along with the list of device IDs attached to the
// virtual IOMMU. This is useful for filling the ACPI IORT table.
virt_iommu: Option<(u32, Vec<u32>)>,
// ACPI GED notification device
#[cfg(feature = "acpi")]
ged_notification_device: Option<Arc<Mutex<devices::AcpiGEDDevice>>>,
}
impl DeviceManager {
@ -460,10 +467,13 @@ impl DeviceManager {
reset_evt.try_clone().map_err(DeviceManagerError::EventFd)?,
)?;
DeviceManager::add_acpi_device(
#[cfg(feature = "acpi")]
let ged_notification_device = DeviceManager::add_acpi_devices(
vm_info,
&address_manager,
reset_evt.try_clone().map_err(DeviceManagerError::EventFd)?,
_exit_evt.try_clone().map_err(DeviceManagerError::EventFd)?,
&ioapic,
)?;
if cfg!(feature = "pci_support") {
@ -492,6 +502,8 @@ impl DeviceManager {
mmap_regions,
cmdline_additions,
virt_iommu,
#[cfg(feature = "acpi")]
ged_notification_device,
})
}
@ -658,31 +670,58 @@ impl DeviceManager {
}
#[allow(unused_variables)]
fn add_acpi_device(
#[cfg(feature = "acpi")]
fn add_acpi_devices(
vm_info: &VmInfo,
address_manager: &Arc<AddressManager>,
reset_evt: EventFd,
exit_evt: EventFd,
) -> DeviceManagerResult<()> {
#[cfg(feature = "acpi")]
{
let acpi_device = Arc::new(Mutex::new(devices::AcpiShutdownDevice::new(
exit_evt, reset_evt,
)));
ioapic: &Option<Arc<Mutex<ioapic::Ioapic>>>,
) -> DeviceManagerResult<Option<Arc<Mutex<devices::AcpiGEDDevice>>>> {
let acpi_device = Arc::new(Mutex::new(devices::AcpiShutdownDevice::new(
exit_evt, reset_evt,
)));
address_manager
.allocator
.lock()
.unwrap()
.allocate_io_addresses(Some(GuestAddress(0x3c0)), 0x8, None)
.ok_or(DeviceManagerError::AllocateIOPort)?;
address_manager
.allocator
.lock()
.unwrap()
.allocate_io_addresses(Some(GuestAddress(0x3c0)), 0x8, None)
.ok_or(DeviceManagerError::AllocateIOPort)?;
address_manager
.io_bus
.insert(acpi_device.clone(), 0x3c0, 0x4)
.map_err(DeviceManagerError::BusError)?;
}
address_manager
.io_bus
.insert(acpi_device.clone(), 0x3c0, 0x4)
.map_err(DeviceManagerError::BusError)?;
Ok(())
// We need to hardcode this as the ACPI tables need to specify a particular IRQ and it's not possible
// to ask the allocator for a specific one.
let ged_irq = 5;
let interrupt: Box<dyn devices::Interrupt> = if let Some(ioapic) = &ioapic {
Box::new(UserIoapicIrq::new(ioapic.clone(), ged_irq))
} else {
let ged_evt = EventFd::new(EFD_NONBLOCK).map_err(DeviceManagerError::EventFd)?;
vm_info
.vm_fd
.register_irqfd(&ged_evt, ged_irq as u32)
.map_err(DeviceManagerError::Irq)?;
Box::new(KernelIoapicIrq::new(ged_evt))
};
let ged_device = Arc::new(Mutex::new(devices::AcpiGEDDevice::new(interrupt)));
address_manager
.allocator
.lock()
.unwrap()
.allocate_io_addresses(Some(GuestAddress(0xb000)), 0x1, None)
.ok_or(DeviceManagerError::AllocateIOPort)?;
address_manager
.io_bus
.insert(ged_device.clone(), 0xb000, 0x1)
.map_err(DeviceManagerError::BusError)?;
Ok(Some(ged_device))
}
fn add_legacy_devices(
@ -1540,6 +1579,23 @@ impl DeviceManager {
None
}
}
pub fn notify_hotplug(
&self,
_notification_type: HotPlugNotificationType,
) -> DeviceManagerResult<()> {
#[cfg(feature = "acpi")]
return self
.ged_notification_device
.as_ref()
.unwrap()
.lock()
.unwrap()
.notify(_notification_type)
.map_err(DeviceManagerError::HotPlugNotification);
#[cfg(not(feature = "acpi"))]
return Ok(());
}
}
impl Drop for DeviceManager {

View File

@ -54,7 +54,7 @@ use vm_memory::{
use vmm_sys_util::eventfd::EventFd;
use vmm_sys_util::terminal::Terminal;
const X86_64_IRQ_BASE: u32 = 5;
const X86_64_IRQ_BASE: u32 = 6;
// CPUID feature bits
const TSC_DEADLINE_TIMER_ECX_BIT: u8 = 24; // tsc deadline timer ecx bit.