From c87ca3921963f40ee748c3b05ccfc3431871fc21 Mon Sep 17 00:00:00 2001 From: Bo Chen Date: Thu, 1 Jan 2026 02:14:58 +0000 Subject: [PATCH] vmm: acpi: Generate IORT table according to spec revision E.b The current IORT table implementation is based on IORT Spec revision E.b [1], as evidenced by: * The PCI root complex node revision being set to `3` * The code being updated in late 2021 [2] when revision E.b was the latest version This patch ensures the IORT table is properly generated according to this specification revision, fixing three issues: 1. The IORT table revision should be `3` rather than `2` (see Table 2 in the spec [1]) 2. The GIC ITS group node revision should be `1` rather than `0` (see Table 12 in the spec [1]) 3. The "Memory access properties" and "ATS Attribute" fields of the PCI root complex node was set incorrectly - specifically the MAF (Memory Access Flags) including CPM and DACS bits (see Tables 14, 15, and 17 in the spec [1]) [1] https://developer.arm.com/documentation/den0049/eb/?lang=en [2] https://github.com/cloud-hypervisor/cloud-hypervisor/pull/3356 Signed-off-by: Bo Chen --- vmm/src/acpi.rs | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/vmm/src/acpi.rs b/vmm/src/acpi.rs index 7fca8435f..5cb96f5d6 100644 --- a/vmm/src/acpi.rs +++ b/vmm/src/acpi.rs @@ -515,6 +515,8 @@ fn create_dbg2_table(base_address: u64) -> Sdt { } #[cfg(target_arch = "aarch64")] +// Generate IORT table based on Spec Revision E.b: +// https://developer.arm.com/documentation/den0049/eb/?lang=en fn create_iort_table(pci_segments: &[PciSegment]) -> Sdt { const ACPI_IORT_NODE_ITS_GROUP: u8 = 0x00; const ACPI_IORT_NODE_PCI_ROOT_COMPLEX: u8 = 0x02; @@ -528,7 +530,7 @@ fn create_iort_table(pci_segments: &[PciSegment]) -> Sdt { let iort_table_size: u32 = (ACPI_IORT_NODE_ROOT_COMPLEX_OFFSET + ACPI_IORT_NODE_ROOT_COMPLEX_SIZE * pci_segments.len()) as u32; - let mut iort = Sdt::new(*b"IORT", iort_table_size, 2, *b"CLOUDH", *b"CHIORT ", 1); + let mut iort = Sdt::new(*b"IORT", iort_table_size, 3, *b"CLOUDH", *b"CHIORT ", 1); iort.write(36, ((1 + pci_segments.len()) as u32).to_le()); iort.write(40, (48u32).to_le()); @@ -536,6 +538,8 @@ fn create_iort_table(pci_segments: &[PciSegment]) -> Sdt { iort.write(48, ACPI_IORT_NODE_ITS_GROUP); // Length of the ITS group node in bytes iort.write(49, (24u16).to_le()); + // Revision + iort.write(51, (1u8).to_le()); // ITS counts iort.write(64, (1u32).to_le()); @@ -560,7 +564,7 @@ fn create_iort_table(pci_segments: &[PciSegment]) -> Sdt { // Fully coherent device iort.write(node_offset + 16, (1u32).to_le()); // CCA = CPM = DCAS = 1 - iort.write(node_offset + 24, 3u8); + iort.write(node_offset + 23, 3u8); // PCI segment number iort.write(node_offset + 28, (segment.id as u32).to_le()); // Memory address size limit