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 <bchen@crusoe.ai>
This commit is contained in:
Bo Chen 2026-01-01 02:14:58 +00:00
parent 079d94ecae
commit c87ca39219

View file

@ -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