From d39f91de025928bdcfa0d5f41f5f4a5b2cc931d9 Mon Sep 17 00:00:00 2001 From: Sebastien Boeuf Date: Tue, 28 Apr 2020 19:57:28 +0200 Subject: [PATCH] vmm: Reorganize DeviceManager creation This commit performs the split of the DeviceManager's creation into two separate functions by moving anything related to device's creation after the DeviceManager structure has been initialized. Signed-off-by: Sebastien Boeuf --- vmm/src/device_manager.rs | 174 ++++++++++++++++++++------------------ vmm/src/vm.rs | 6 ++ 2 files changed, 98 insertions(+), 82 deletions(-) diff --git a/vmm/src/device_manager.rs b/vmm/src/device_manager.rs index da91435f2..53acc7df1 100644 --- a/vmm/src/device_manager.rs +++ b/vmm/src/device_manager.rs @@ -609,7 +609,6 @@ pub struct DeviceManager { pci_bus: Option>>, // MSI Interrupt Manager - #[cfg(feature = "pci_support")] msi_interrupt_manager: Arc>, // VFIO KVM device @@ -639,10 +638,15 @@ pub struct DeviceManager { // Tree of devices, representing the dependencies between devices. // Useful for introspection, snapshot and restore. device_tree: HashMap, + + // Exit event + #[cfg(feature = "acpi")] + exit_evt: EventFd, + // Reset event + reset_evt: EventFd, } impl DeviceManager { - #[allow(clippy::too_many_arguments)] pub fn new( vm_fd: Arc, config: Arc>, @@ -651,13 +655,6 @@ impl DeviceManager { reset_evt: &EventFd, vmm_path: PathBuf, ) -> DeviceManagerResult>> { - let mut virtio_devices: Vec<(VirtioDeviceArc, bool, String)> = Vec::new(); - let mut bus_devices: Vec>> = Vec::new(); - let mut device_tree = HashMap::new(); - - #[allow(unused_mut)] - let mut cmdline_additions = Vec::new(); - let address_manager = Arc::new(AddressManager { allocator: memory_manager.lock().unwrap().allocator(), io_bus: Arc::new(devices::Bus::new()), @@ -685,53 +682,24 @@ impl DeviceManager { Arc::clone(&kvm_gsi_msi_routes), )); - let ioapic = DeviceManager::add_ioapic( - &address_manager, - Arc::clone(&msi_interrupt_manager), - &mut device_tree, - )?; - let ioapic_migratable = Arc::clone(&ioapic) as Arc>; - bus_devices.push(Arc::clone(&ioapic) as Arc>); - - // Now we can create the legacy interrupt manager, which needs the freshly - // formed IOAPIC device. - let legacy_interrupt_manager: Arc< - dyn InterruptManager, - > = Arc::new(KvmLegacyUserspaceInterruptManager::new(ioapic.clone())); - - #[cfg(feature = "acpi")] - address_manager - .allocator - .lock() - .unwrap() - .allocate_io_addresses(Some(GuestAddress(0x0a00)), 0x18, None) - .ok_or(DeviceManagerError::AllocateIOPort)?; - - #[cfg(feature = "acpi")] - address_manager - .io_bus - .insert(memory_manager.clone(), 0xa00, 0x18) - .map_err(DeviceManagerError::BusError)?; - - let mut device_manager = DeviceManager { + let device_manager = DeviceManager { address_manager: Arc::clone(&address_manager), console: Arc::new(Console::default()), - ioapic: Some(ioapic), - cmdline_additions, + ioapic: None, + cmdline_additions: Vec::new(), #[cfg(feature = "acpi")] ged_notification_device: None, config, migratable_devices: HashMap::new(), memory_manager, virtio_devices: Vec::new(), - bus_devices, + bus_devices: Vec::new(), vmm_path, vhost_user_backends: Vec::new(), device_id_cnt: Wrapping(0), #[cfg(feature = "pci_support")] pci_bus: None, - #[cfg(feature = "pci_support")] - msi_interrupt_manager: Arc::clone(&msi_interrupt_manager), + msi_interrupt_manager, #[cfg(feature = "pci_support")] kvm_device_fd: None, #[cfg(feature = "pci_support")] @@ -744,39 +712,12 @@ impl DeviceManager { pci_id_list: HashMap::new(), #[cfg(feature = "pci_support")] pci_devices: HashMap::new(), - device_tree, + device_tree: HashMap::new(), + #[cfg(feature = "acpi")] + exit_evt: _exit_evt.try_clone().map_err(DeviceManagerError::EventFd)?, + reset_evt: reset_evt.try_clone().map_err(DeviceManagerError::EventFd)?, }; - device_manager - .add_legacy_devices(reset_evt.try_clone().map_err(DeviceManagerError::EventFd)?)?; - - device_manager.add_migratable_device(ioapic_migratable); - - #[cfg(feature = "acpi")] - { - device_manager.ged_notification_device = device_manager.add_acpi_devices( - &legacy_interrupt_manager, - reset_evt.try_clone().map_err(DeviceManagerError::EventFd)?, - _exit_evt.try_clone().map_err(DeviceManagerError::EventFd)?, - )?; - } - - device_manager.console = - device_manager.add_console_device(&legacy_interrupt_manager, &mut virtio_devices)?; - - #[cfg(any(feature = "pci_support", feature = "mmio_support"))] - virtio_devices.append(&mut device_manager.make_virtio_devices()?); - - if cfg!(feature = "pci_support") { - device_manager.add_pci_devices(virtio_devices.clone())?; - } else if cfg!(feature = "mmio_support") { - device_manager.add_mmio_devices(virtio_devices.clone(), &legacy_interrupt_manager)?; - } - - device_manager.virtio_devices = virtio_devices; - - let device_manager = Arc::new(Mutex::new(device_manager)); - #[cfg(feature = "acpi")] address_manager .allocator @@ -785,6 +726,8 @@ impl DeviceManager { .allocate_io_addresses(Some(GuestAddress(0xae00)), 0x10, None) .ok_or(DeviceManagerError::AllocateIOPort)?; + let device_manager = Arc::new(Mutex::new(device_manager)); + #[cfg(feature = "acpi")] address_manager .io_bus @@ -798,6 +741,70 @@ impl DeviceManager { Ok(device_manager) } + pub fn create_devices(&mut self) -> DeviceManagerResult<()> { + let mut virtio_devices: Vec<(VirtioDeviceArc, bool, String)> = Vec::new(); + + let ioapic = self.add_ioapic()?; + + // Now we can create the legacy interrupt manager, which needs the freshly + // formed IOAPIC device. + let legacy_interrupt_manager: Arc< + dyn InterruptManager, + > = Arc::new(KvmLegacyUserspaceInterruptManager::new(ioapic)); + + #[cfg(feature = "acpi")] + self.address_manager + .allocator + .lock() + .unwrap() + .allocate_io_addresses(Some(GuestAddress(0x0a00)), 0x18, None) + .ok_or(DeviceManagerError::AllocateIOPort)?; + + #[cfg(feature = "acpi")] + self.address_manager + .io_bus + .insert( + Arc::clone(&self.memory_manager) as Arc>, + 0xa00, + 0x18, + ) + .map_err(DeviceManagerError::BusError)?; + + self.add_legacy_devices( + self.reset_evt + .try_clone() + .map_err(DeviceManagerError::EventFd)?, + )?; + + #[cfg(feature = "acpi")] + { + self.ged_notification_device = self.add_acpi_devices( + &legacy_interrupt_manager, + self.reset_evt + .try_clone() + .map_err(DeviceManagerError::EventFd)?, + self.exit_evt + .try_clone() + .map_err(DeviceManagerError::EventFd)?, + )?; + } + + self.console = self.add_console_device(&legacy_interrupt_manager, &mut virtio_devices)?; + + #[cfg(any(feature = "pci_support", feature = "mmio_support"))] + virtio_devices.append(&mut self.make_virtio_devices()?); + + if cfg!(feature = "pci_support") { + self.add_pci_devices(virtio_devices.clone())?; + } else if cfg!(feature = "mmio_support") { + self.add_mmio_devices(virtio_devices.clone(), &legacy_interrupt_manager)?; + } + + self.virtio_devices = virtio_devices; + + Ok(()) + } + fn state(&self) -> DeviceManagerState { DeviceManagerState { device_tree: self.device_tree.clone(), @@ -943,26 +950,29 @@ impl DeviceManager { Ok(()) } - fn add_ioapic( - address_manager: &Arc, - interrupt_manager: Arc>, - device_tree: &mut HashMap, - ) -> DeviceManagerResult>> { + fn add_ioapic(&mut self) -> DeviceManagerResult>> { let id = String::from(IOAPIC_DEVICE_NAME); - device_tree.insert(id.clone(), Node::default()); + self.device_tree.insert(id.clone(), Node::default()); // Create IOAPIC let ioapic = Arc::new(Mutex::new( - ioapic::Ioapic::new(id, APIC_START, interrupt_manager) + ioapic::Ioapic::new(id, APIC_START, Arc::clone(&self.msi_interrupt_manager)) .map_err(DeviceManagerError::CreateIoapic)?, )); - address_manager + self.ioapic = Some(ioapic.clone()); + + self.address_manager .mmio_bus .insert(ioapic.clone(), IOAPIC_START.0, IOAPIC_SIZE) .map_err(DeviceManagerError::BusError)?; + self.bus_devices + .push(Arc::clone(&ioapic) as Arc>); + + self.add_migratable_device(Arc::clone(&ioapic) as Arc>); + Ok(ioapic) } diff --git a/vmm/src/vm.rs b/vmm/src/vm.rs index a4d2f898f..6e1ce9e13 100755 --- a/vmm/src/vm.rs +++ b/vmm/src/vm.rs @@ -334,6 +334,12 @@ impl Vm { ) .map_err(Error::DeviceManager)?; + device_manager + .lock() + .unwrap() + .create_devices() + .map_err(Error::DeviceManager)?; + let cpu_manager = cpu::CpuManager::new( &config.lock().unwrap().cpus.clone(), &device_manager,