mirror of
https://github.com/cloud-hypervisor/cloud-hypervisor.git
synced 2026-08-05 02:19:16 +00:00
virtio-devices, vmm: Update virtio-iommu to rely on VIOT
Since using the VIRTIO configuration to expose the virtual IOMMU topology has been deprecated, the virtio-iommu implementation must be updated. In order to follow the latest patchset that is about to be merged in the upstream Linux kernel, it must rely on ACPI, and in particular the newly introduced VIOT table to expose the information about the list of PCI devices attached to the virtual IOMMU. Signed-off-by: Sebastien Boeuf <sebastien.boeuf@intel.com>
This commit is contained in:
@@ -109,6 +109,32 @@ impl MemoryAffinity {
|
||||
}
|
||||
}
|
||||
|
||||
#[repr(packed)]
|
||||
#[derive(Default)]
|
||||
struct ViotVirtioPciNode {
|
||||
pub type_: u8,
|
||||
_reserved: u8,
|
||||
pub length: u16,
|
||||
pub pci_segment: u16,
|
||||
pub pci_bdf_number: u16,
|
||||
_reserved2: [u8; 8],
|
||||
}
|
||||
|
||||
#[repr(packed)]
|
||||
#[derive(Default)]
|
||||
struct ViotPciRangeNode {
|
||||
pub type_: u8,
|
||||
_reserved: u8,
|
||||
pub length: u16,
|
||||
pub endpoint_start: u32,
|
||||
pub pci_segment_start: u16,
|
||||
pub pci_segment_end: u16,
|
||||
pub pci_bdf_start: u16,
|
||||
pub pci_bdf_end: u16,
|
||||
pub output_node: u16,
|
||||
_reserved2: [u8; 6],
|
||||
}
|
||||
|
||||
pub fn create_dsdt_table(
|
||||
device_manager: &Arc<Mutex<DeviceManager>>,
|
||||
cpu_manager: &Arc<Mutex<CpuManager>>,
|
||||
@@ -360,6 +386,42 @@ fn create_iort_table() -> Sdt {
|
||||
iort
|
||||
}
|
||||
|
||||
fn create_viot_table(iommu_bdf: u32, devices_bdf: &[u32]) -> Sdt {
|
||||
// VIOT
|
||||
let mut viot = Sdt::new(*b"VIOT", 36, 0, *b"CLOUDH", *b"CHVIOT ", 0);
|
||||
// Node count
|
||||
viot.append((devices_bdf.len() + 1) as u16);
|
||||
// Node offset
|
||||
viot.append(48u16);
|
||||
// VIOT reserved 8 bytes
|
||||
viot.append_slice(&[0u8; 8]);
|
||||
|
||||
// Virtio-iommu based on virtio-pci node
|
||||
viot.append(ViotVirtioPciNode {
|
||||
type_: 3,
|
||||
length: 16,
|
||||
pci_segment: 0,
|
||||
pci_bdf_number: iommu_bdf as u16,
|
||||
..Default::default()
|
||||
});
|
||||
|
||||
for device_bdf in devices_bdf {
|
||||
viot.append(ViotPciRangeNode {
|
||||
type_: 1,
|
||||
length: 24,
|
||||
endpoint_start: *device_bdf,
|
||||
pci_segment_start: 0,
|
||||
pci_segment_end: 0,
|
||||
pci_bdf_start: *device_bdf as u16,
|
||||
pci_bdf_end: *device_bdf as u16,
|
||||
output_node: 48,
|
||||
..Default::default()
|
||||
});
|
||||
}
|
||||
|
||||
viot
|
||||
}
|
||||
|
||||
pub fn create_acpi_tables(
|
||||
guest_mem: &GuestMemoryMmap,
|
||||
device_manager: &Arc<Mutex<DeviceManager>>,
|
||||
@@ -489,6 +551,20 @@ pub fn create_acpi_tables(
|
||||
prev_tbl_off = iort_offset;
|
||||
}
|
||||
|
||||
// VIOT
|
||||
if let Some((iommu_bdf, devices_bdf)) = device_manager.lock().unwrap().iommu_attached_devices()
|
||||
{
|
||||
let viot = create_viot_table(*iommu_bdf, devices_bdf);
|
||||
|
||||
let viot_offset = prev_tbl_off.checked_add(prev_tbl_len).unwrap();
|
||||
guest_mem
|
||||
.write_slice(viot.as_slice(), viot_offset)
|
||||
.expect("Error writing VIOT table");
|
||||
tables.push(viot_offset.0);
|
||||
prev_tbl_len = viot.len() as u64;
|
||||
prev_tbl_off = viot_offset;
|
||||
}
|
||||
|
||||
// XSDT
|
||||
let mut xsdt = Sdt::new(*b"XSDT", 36, 1, *b"CLOUDH", *b"CHXSDT ", 1);
|
||||
for table in tables {
|
||||
|
||||
@@ -869,6 +869,12 @@ pub struct DeviceManager {
|
||||
// Paravirtualized IOMMU
|
||||
iommu_device: Option<Arc<Mutex<virtio_devices::Iommu>>>,
|
||||
|
||||
// PCI information about devices attached to the paravirtualized IOMMU
|
||||
// It contains the virtual IOMMU PCI BDF along with the list of PCI BDF
|
||||
// representing the devices attached to the virtual IOMMU. This is useful
|
||||
// information for filling the ACPI VIOT table.
|
||||
iommu_attached_devices: Option<(u32, Vec<u32>)>,
|
||||
|
||||
// Bitmap of PCI devices to hotplug.
|
||||
pci_devices_up: u32,
|
||||
|
||||
@@ -975,6 +981,7 @@ impl DeviceManager {
|
||||
legacy_interrupt_manager: None,
|
||||
passthrough_device: None,
|
||||
iommu_device: None,
|
||||
iommu_attached_devices: None,
|
||||
pci_devices_up: 0,
|
||||
pci_devices_down: 0,
|
||||
pci_irq_slots: [0; 32],
|
||||
@@ -1196,15 +1203,8 @@ impl DeviceManager {
|
||||
iommu_attached_devices.append(&mut vfio_iommu_device_ids);
|
||||
|
||||
if let Some(iommu_device) = iommu_device {
|
||||
iommu_device
|
||||
.lock()
|
||||
.unwrap()
|
||||
.attach_pci_devices(0, iommu_attached_devices);
|
||||
|
||||
// Because we determined the virtio-iommu b/d/f, we have to
|
||||
// add the device to the PCI topology now. Otherwise, the
|
||||
// b/d/f won't match the virtio-iommu device as expected.
|
||||
self.add_virtio_pci_device(iommu_device, &mut pci_bus, &None, iommu_id)?;
|
||||
let dev_id = self.add_virtio_pci_device(iommu_device, &mut pci_bus, &None, iommu_id)?;
|
||||
self.iommu_attached_devices = Some((dev_id, iommu_attached_devices));
|
||||
}
|
||||
|
||||
let pci_bus = Arc::new(Mutex::new(pci_bus));
|
||||
@@ -3486,6 +3486,10 @@ impl DeviceManager {
|
||||
.trigger_key(3)
|
||||
.map_err(DeviceManagerError::AArch64PowerButtonNotification)
|
||||
}
|
||||
|
||||
pub fn iommu_attached_devices(&self) -> &Option<(u32, Vec<u32>)> {
|
||||
&self.iommu_attached_devices
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "acpi")]
|
||||
|
||||
Reference in New Issue
Block a user