From 1756b23aea156306518cc2c3c383a81cc11330fb Mon Sep 17 00:00:00 2001 From: Rob Bradford Date: Fri, 18 Mar 2022 17:41:08 +0000 Subject: [PATCH] vmm: device_manager: Check IOMMU placed device hotplug Rather than just printing a message return an error back through the API if the user attempts to hotplug a device that supports being behind an IOMMU where that device isn't placed on an IOMMU segment. Signed-off-by: Rob Bradford --- vmm/src/device_manager.rs | 43 +++++++++++++++++++++++++++++++++++---- 1 file changed, 39 insertions(+), 4 deletions(-) diff --git a/vmm/src/device_manager.rs b/vmm/src/device_manager.rs index c685759a0..a4ce8f64e 100644 --- a/vmm/src/device_manager.rs +++ b/vmm/src/device_manager.rs @@ -474,6 +474,9 @@ pub enum DeviceManagerError { /// Failed to DMA unmap virtio device. VirtioDmaUnmap(std::io::Error), + + /// Cannot hotplug device behind vIOMMU + InvalidIommuHotplug, } pub type DeviceManagerResult = result::Result; @@ -3680,6 +3683,10 @@ impl DeviceManager { &mut self, device_cfg: &mut DeviceConfig, ) -> DeviceManagerResult { + if device_cfg.iommu && !self.is_iommu_segment(device_cfg.pci_segment) { + return Err(DeviceManagerError::InvalidIommuHotplug); + } + let (bdf, device_name) = self.add_passthrough_device(device_cfg)?; // Update the PCIU bitmap @@ -3940,10 +3947,6 @@ impl DeviceManager { &mut self, handle: MetaVirtioDevice, ) -> DeviceManagerResult { - if handle.iommu { - warn!("Placing device behind vIOMMU is not available for hotplugged devices"); - } - // Add the virtio device to the device manager list. This is important // as the list is used to notify virtio devices about memory updates // for instance. @@ -3969,7 +3972,27 @@ impl DeviceManager { Ok(PciDeviceInfo { id: handle.id, bdf }) } + fn is_iommu_segment(&self, pci_segment_id: u16) -> bool { + self.config + .lock() + .as_ref() + .unwrap() + .platform + .as_ref() + .map(|pc| { + pc.iommu_segments + .as_ref() + .map(|v| v.contains(&pci_segment_id)) + .unwrap_or_default() + }) + .unwrap_or_default() + } + pub fn add_disk(&mut self, disk_cfg: &mut DiskConfig) -> DeviceManagerResult { + if disk_cfg.iommu && !self.is_iommu_segment(disk_cfg.pci_segment) { + return Err(DeviceManagerError::InvalidIommuHotplug); + } + let device = self.make_virtio_block_device(disk_cfg)?; self.hotplug_virtio_pci_device(device) } @@ -3980,11 +4003,19 @@ impl DeviceManager { } pub fn add_pmem(&mut self, pmem_cfg: &mut PmemConfig) -> DeviceManagerResult { + if pmem_cfg.iommu && !self.is_iommu_segment(pmem_cfg.pci_segment) { + return Err(DeviceManagerError::InvalidIommuHotplug); + } + let device = self.make_virtio_pmem_device(pmem_cfg)?; self.hotplug_virtio_pci_device(device) } pub fn add_net(&mut self, net_cfg: &mut NetConfig) -> DeviceManagerResult { + if net_cfg.iommu && !self.is_iommu_segment(net_cfg.pci_segment) { + return Err(DeviceManagerError::InvalidIommuHotplug); + } + let device = self.make_virtio_net_device(net_cfg)?; self.hotplug_virtio_pci_device(device) } @@ -3995,6 +4026,10 @@ impl DeviceManager { } pub fn add_vsock(&mut self, vsock_cfg: &mut VsockConfig) -> DeviceManagerResult { + if vsock_cfg.iommu && !self.is_iommu_segment(vsock_cfg.pci_segment) { + return Err(DeviceManagerError::InvalidIommuHotplug); + } + let device = self.make_virtio_vsock_device(vsock_cfg)?; self.hotplug_virtio_pci_device(device) }