diff --git a/vmm/src/device_manager.rs b/vmm/src/device_manager.rs index eccacc14d..7f7197893 100644 --- a/vmm/src/device_manager.rs +++ b/vmm/src/device_manager.rs @@ -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 = result::Result; @@ -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)>, + + // ACPI GED notification device + #[cfg(feature = "acpi")] + ged_notification_device: Option>>, } 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, 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>>, + ) -> DeviceManagerResult>>> { + 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 = 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 { diff --git a/vmm/src/vm.rs b/vmm/src/vm.rs index 3bf2ba5c8..a7c782450 100755 --- a/vmm/src/vm.rs +++ b/vmm/src/vm.rs @@ -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.