From 03352f45f9d0cdf125aac1b84bfce447969c18e9 Mon Sep 17 00:00:00 2001 From: Sebastien Boeuf Date: Tue, 1 Oct 2019 23:56:37 -0700 Subject: [PATCH] arch: Create ACPI IORT table The virtual IOMMU exposed through virtio-iommu device has a dependency on ACPI. It needs to expose the device ID of the virtio-iommu device, and all the other devices attached to this virtual IOMMU. The IDs are expressed from a PCI bus perspective, based on segment, bus, device and function. The guest relies on the topology description provided by the IORT table to attach devices to the virtio-iommu device. Signed-off-by: Sebastien Boeuf --- arch/src/aarch64/mod.rs | 1 + arch/src/x86_64/acpi.rs | 115 +++++++++++++++++++++++++++++++++++++++- arch/src/x86_64/mod.rs | 7 +++ vmm/src/vm.rs | 2 + 4 files changed, 124 insertions(+), 1 deletion(-) diff --git a/arch/src/aarch64/mod.rs b/arch/src/aarch64/mod.rs index 3a15d2688..fa016278a 100644 --- a/arch/src/aarch64/mod.rs +++ b/arch/src/aarch64/mod.rs @@ -17,6 +17,7 @@ pub fn configure_system( _cmdline_size: usize, _num_cpus: u8, _serial_enabled: bool, + _virt_iommu: Option<(u32, &[u32])>, ) -> super::Result<()> { Ok(()) } diff --git a/arch/src/x86_64/acpi.rs b/arch/src/x86_64/acpi.rs index c9f866a04..6be8102cb 100644 --- a/arch/src/x86_64/acpi.rs +++ b/arch/src/x86_64/acpi.rs @@ -10,6 +10,8 @@ use vm_memory::{GuestAddress, GuestMemoryMmap}; use vm_memory::{Address, ByteValued, Bytes}; +use std::convert::TryInto; + use super::layout; #[repr(packed)] @@ -53,6 +55,57 @@ struct PCIRangeEntry { _reserved: u32, } +#[repr(packed)] +#[derive(Default)] +struct IortParavirtIommuNode { + pub type_: u8, + pub length: u16, + pub revision: u8, + _reserved1: u32, + pub num_id_mappings: u32, + pub ref_id_mappings: u32, + pub device_id: u32, + _reserved2: [u32; 3], + pub model: u32, + pub flags: u32, + _reserved3: [u32; 4], +} + +#[repr(packed)] +#[derive(Default)] +struct IortPciRootComplexNode { + pub type_: u8, + pub length: u16, + pub revision: u8, + _reserved1: u32, + pub num_id_mappings: u32, + pub ref_id_mappings: u32, + pub mem_access_props: IortMemoryAccessProperties, + pub ats_attr: u32, + pub pci_seg_num: u32, + pub mem_addr_size_limit: u8, + _reserved2: [u8; 3], +} + +#[repr(packed)] +#[derive(Default)] +struct IortMemoryAccessProperties { + pub cca: u32, + pub ah: u8, + _reserved: u16, + pub maf: u8, +} + +#[repr(packed)] +#[derive(Default)] +struct IortIdMapping { + pub input_base: u32, + pub num_of_ids: u32, + pub ouput_base: u32, + pub output_ref: u32, + pub flags: u32, +} + pub fn create_dsdt_table( serial_enabled: bool, start_of_device_area: GuestAddress, @@ -247,6 +300,7 @@ pub fn create_acpi_tables( serial_enabled: bool, start_of_device_area: GuestAddress, end_of_device_area: GuestAddress, + virt_iommu: Option<(u32, &[u32])>, ) -> GuestAddress { // RSDP is at the EBDA let rsdp_offset = layout::RSDP_POINTER; @@ -349,6 +403,65 @@ pub fn create_acpi_tables( .expect("Error writing MCFG table"); tables.push(mcfg_offset.0); + let (prev_tbl_len, prev_tbl_off) = if let Some((iommu_id, dev_ids)) = &virt_iommu { + // IORT + let mut iort = SDT::new(*b"IORT", 36, 1, *b"CLOUDH", *b"CHIORT ", 1); + // IORT number of nodes + iort.append(2u32); + // IORT offset to array of IORT nodes + iort.append(48u32); + // IORT reserved 4 bytes + iort.append(0u32); + // IORT paravirtualized IOMMU node + iort.append(IortParavirtIommuNode { + type_: 128, + length: 56, + revision: 0, + num_id_mappings: 0, + ref_id_mappings: 56, + device_id: *iommu_id, + model: 1, + ..Default::default() + }); + + let num_entries = dev_ids.len(); + let length: u16 = (36 + (20 * num_entries)).try_into().unwrap(); + + // IORT PCI root complex node + iort.append(IortPciRootComplexNode { + type_: 2, + length, + revision: 0, + num_id_mappings: num_entries as u32, + ref_id_mappings: 36, + ats_attr: 0, + pci_seg_num: 0, + mem_addr_size_limit: 255, + ..Default::default() + }); + + for dev_id in dev_ids.iter() { + // IORT ID mapping + iort.append(IortIdMapping { + input_base: *dev_id, + num_of_ids: 1, + ouput_base: *dev_id, + output_ref: 48, + flags: 0, + }); + } + + let iort_offset = mcfg_offset.checked_add(mcfg.len() as u64).unwrap(); + guest_mem + .write_slice(iort.as_slice(), iort_offset) + .expect("Error writing IORT table"); + tables.push(iort_offset.0); + + (iort.len(), iort_offset) + } else { + (mcfg.len(), mcfg_offset) + }; + // XSDT let mut xsdt = SDT::new(*b"XSDT", 36, 1, *b"CLOUDH", *b"CHXSDT ", 1); for table in tables { @@ -356,7 +469,7 @@ pub fn create_acpi_tables( } xsdt.update_checksum(); - let xsdt_offset = mcfg_offset.checked_add(mcfg.len() as u64).unwrap(); + let xsdt_offset = prev_tbl_off.checked_add(prev_tbl_len as u64).unwrap(); guest_mem .write_slice(xsdt.as_slice(), xsdt_offset) .expect("Error writing XSDT table"); diff --git a/arch/src/x86_64/mod.rs b/arch/src/x86_64/mod.rs index 28b357b17..fc09b8fc9 100644 --- a/arch/src/x86_64/mod.rs +++ b/arch/src/x86_64/mod.rs @@ -104,6 +104,7 @@ pub fn arch_memory_regions(size: GuestUsize) -> Vec<(GuestAddress, usize, Region /// * `cmdline_addr` - Address in `guest_mem` where the kernel command line was loaded. /// * `cmdline_size` - Size of the kernel command line in bytes including the null terminator. /// * `num_cpus` - Number of virtual CPUs the guest will have. +#[allow(clippy::too_many_arguments)] pub fn configure_system( guest_mem: &GuestMemoryMmap, cmdline_addr: GuestAddress, @@ -112,6 +113,7 @@ pub fn configure_system( setup_hdr: Option, _serial_enabled: bool, _end_of_range: GuestAddress, + _virt_iommu: Option<(u32, &[u32])>, ) -> super::Result<()> { const KERNEL_BOOT_FLAG_MAGIC: u16 = 0xaa55; const KERNEL_HDR_MAGIC: u32 = 0x53726448; @@ -183,6 +185,7 @@ pub fn configure_system( _serial_enabled, start_of_device_area, _end_of_range, + _virt_iommu, ); params.0.acpi_rsdp_addr = rsdp_addr.0; } @@ -251,6 +254,7 @@ mod tests { None, false, GuestAddress((1 << 36) - 1), + None, ); assert!(config_err.is_err()); assert_eq!( @@ -277,6 +281,7 @@ mod tests { None, false, GuestAddress((1 << 36) - 1), + None, ) .unwrap(); @@ -297,6 +302,7 @@ mod tests { None, false, GuestAddress((1 << 36) - 1), + None, ) .unwrap(); @@ -317,6 +323,7 @@ mod tests { None, false, GuestAddress((1 << 36) - 1), + None, ) .unwrap(); } diff --git a/vmm/src/vm.rs b/vmm/src/vm.rs index 8afee7525..ddaea86da 100755 --- a/vmm/src/vm.rs +++ b/vmm/src/vm.rs @@ -745,6 +745,7 @@ impl Vm { Some(hdr), self.config.serial.mode != ConsoleOutputMode::Off, end_of_range, + None, ) .map_err(|_| Error::CmdLine)?; @@ -765,6 +766,7 @@ impl Vm { None, self.config.serial.mode != ConsoleOutputMode::Off, end_of_range, + None, ) .map_err(|_| Error::CmdLine)?;