mirror of
https://github.com/cloud-hypervisor/cloud-hypervisor.git
synced 2025-03-20 07:58:55 +00:00
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 <sebastien.boeuf@intel.com>
This commit is contained in:
parent
f40adff2a1
commit
03352f45f9
@ -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(())
|
||||
}
|
||||
|
@ -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");
|
||||
|
@ -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<setup_header>,
|
||||
_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();
|
||||
}
|
||||
|
@ -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)?;
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user