From bac0d1e689d8d83547a61193d940661c5efc38b2 Mon Sep 17 00:00:00 2001 From: Sebastien Boeuf Date: Tue, 28 Jan 2020 18:58:28 +0100 Subject: [PATCH] iommu: Implement virtio topology configuration Based on the new structures previously introduced, the new topology feature is being fully implemented through this commit. This allows the description of the devices attached to the virtual IOMMU, which is why a new function attach_devices() has been introduced. It gives the virtual IOMMU device the full list of devices which must be attached to it, letting the device share this information through its virtio configuration. Signed-off-by: Sebastien Boeuf --- vm-virtio/src/iommu.rs | 52 +++++++++++++++++++++++++++++++++++++++--- 1 file changed, 49 insertions(+), 3 deletions(-) diff --git a/vm-virtio/src/iommu.rs b/vm-virtio/src/iommu.rs index 07a80e83e..e40ef39b8 100644 --- a/vm-virtio/src/iommu.rs +++ b/vm-virtio/src/iommu.rs @@ -114,9 +114,9 @@ struct VirtioIommuConfig { unsafe impl ByteValued for VirtioIommuConfig {} #[allow(unused)] -const VIRTIO_IOMMU_TOPO_PCI_RANGE: u32 = 1; +const VIRTIO_IOMMU_TOPO_PCI_RANGE: u16 = 1; #[allow(unused)] -const VIRTIO_IOMMU_TOPO_ENDPOINT: u32 = 2; +const VIRTIO_IOMMU_TOPO_ENDPOINT: u16 = 2; #[derive(Copy, Clone, Debug, Default)] #[repr(packed)] @@ -793,6 +793,7 @@ pub struct Iommu { avail_features: u64, acked_features: u64, config: VirtioIommuConfig, + config_topo_pci_ranges: Vec, mapping: Arc, ext_mapping: BTreeMap>, queue_evts: Option>, @@ -823,6 +824,7 @@ impl Iommu { | 1u64 << VIRTIO_IOMMU_F_PROBE, acked_features: 0u64, config, + config_topo_pci_ranges: Vec::new(), mapping: mapping.clone(), ext_mapping: BTreeMap::new(), queue_evts: None, @@ -834,6 +836,44 @@ impl Iommu { )) } + // This function lets the caller specify a list of devices attached to the + // virtual IOMMU. This list is translated into a virtio-iommu configuration + // topology, so that it can be understood by the guest driver. + // + // The topology is overriden everytime this function is being invoked. + // + // This function is dedicated to PCI, which means it will exclusively + // create VIRTIO_IOMMU_TOPO_PCI_RANGE entries. + pub fn attach_pci_devices(&mut self, domain: u16, device_ids: Vec) { + if device_ids.is_empty() { + warn!("No device to attach to virtual IOMMU"); + return; + } + + // If there is at least one device attached to the virtual IOMMU, we + // need the topology feature to be enabled. + self.avail_features |= 1u64 << VIRTIO_IOMMU_F_TOPOLOGY; + + // Update the topology. + let mut topo_pci_ranges = Vec::new(); + for device_id in device_ids.iter() { + let dev_id = *device_id; + topo_pci_ranges.push(VirtioIommuTopoPciRange { + type_: VIRTIO_IOMMU_TOPO_PCI_RANGE, + hierarchy: domain, + requester_start: dev_id as u16, + requester_end: dev_id as u16, + endpoint_start: dev_id, + }); + } + self.config_topo_pci_ranges = topo_pci_ranges; + + // Update the configuration to include the topology. + self.config.topo_config.offset = size_of::() as u32; + self.config.topo_config.num_items = self.config_topo_pci_ranges.len() as u32; + self.config.topo_config.item_length = size_of::() as u32; + } + pub fn add_external_mapping(&mut self, device_id: u32, mapping: Arc) { self.ext_mapping.insert(device_id, mapping); } @@ -892,7 +932,13 @@ impl VirtioDevice for Iommu { } fn read_config(&self, offset: u64, mut data: &mut [u8]) { - let config_slice = self.config.as_slice(); + let mut config: Vec = Vec::new(); + config.extend_from_slice(self.config.as_slice()); + for config_topo_pci_range in self.config_topo_pci_ranges.iter() { + config.extend_from_slice(config_topo_pci_range.as_slice()); + } + + let config_slice = config.as_slice(); let config_len = config_slice.len() as u64; if offset >= config_len { error!("Failed to read config space");