Re: [PATCH 7/8] acpi_build: Cleanup AMD IOMMU IVRS building

"Michael S. Tsirkin" <[email protected]> Mon, 3 Aug 2026 17:56:24 -0400
Newsgroups gmane.comp.emulators.qemu
Message-ID <[email protected]>
On Mon, May 11, 2026 at 06:09:36PM +0530, Sairaj Kodilkar wrote:
> Use structs and macros to improve the readability and maintainability of
> the the code. 
> 
> Signed-off-by: Sairaj Kodilkar <[email protected]>
> ---
>  hw/i386/acpi-build.c | 149 +++++++++++++++++--------------------------
>  1 file changed, 59 insertions(+), 90 deletions(-)
> 
> diff --git a/hw/i386/acpi-build.c b/hw/i386/acpi-build.c
> index 82208e06e155..e18c9be801a2 100644
> --- a/hw/i386/acpi-build.c
> +++ b/hw/i386/acpi-build.c
> @@ -1663,11 +1663,13 @@ static void
>  insert_ivhd(PCIBus *bus, PCIDevice *dev, void *opaque)
>  {
>      GArray *table_data = opaque;
> -    uint32_t entry;
> +    AmdIvhdDeviceEntry entry = {};
>  
>      /* "Select" IVHD entry, type 0x2 */
> -    entry = PCI_BUILD_BDF(pci_bus_num(bus), dev->devfn) << 8 | 0x2;
> -    build_append_int_noprefix(table_data, entry, 4);
> +    entry.type = AMD_IVHD_DEVICE_ENTRY_TYPE_SELECT;
> +    entry.devid = PCI_BUILD_BDF(pci_bus_num(bus), dev->devfn);
> +
> +    g_array_append_vals(table_data, &entry, sizeof(entry));
>  
>      if (object_dynamic_cast(OBJECT(dev), TYPE_PCI_BRIDGE)) {
>          PCIBus *sec_bus = pci_bridge_get_sec_bus(PCI_BRIDGE(dev));
> @@ -1691,11 +1693,14 @@ insert_ivhd(PCIBus *bus, PCIDevice *dev, void *opaque)
>               */
>              if (sec == sub) { /* leaf bus */
>                  /* "Start of Range" IVHD entry, type 0x3 */
> -                entry = PCI_BUILD_BDF(sec, PCI_DEVFN(0, 0)) << 8 | 0x3;
> -                build_append_int_noprefix(table_data, entry, 4);
> +                entry.type = AMD_IVHD_DEVICE_ENTRY_TYPE_START_RANGE;
> +                entry.devid = PCI_BUILD_BDF(sec, PCI_DEVFN(0, 0));
> +                g_array_append_vals(table_data, &entry, sizeof(entry));
> +
>                  /* "End of Range" IVHD entry, type 0x4 */
> -                entry = PCI_BUILD_BDF(sub, PCI_DEVFN(31, 7)) << 8 | 0x4;
> -                build_append_int_noprefix(table_data, entry, 4);
> +                entry.type = AMD_IVHD_DEVICE_ENTRY_TYPE_END_RANGE;
> +                entry.devid = PCI_BUILD_BDF(sub, PCI_DEVFN_MAX - 1);
> +                g_array_append_vals(table_data, &entry, sizeof(entry));
>              } else {
>                  pci_for_each_device(sec_bus, sec, insert_ivhd, table_data);
>              }
> @@ -1708,24 +1713,26 @@ insert_ivhd(PCIBus *bus, PCIDevice *dev, void *opaque)
>               * express bridges, just as in pci_device_iommu_address_space().
>               * DeviceIDa vs DeviceIDb as per the AMD IOMMU spec.
>               */
> -            uint16_t dev_id_a, dev_id_b;
> +            AmdIvhdDeviceEntryExt entry_ext = {};
>  
> -            dev_id_a = PCI_BUILD_BDF(sec, PCI_DEVFN(0, 0));
> +            entry_ext.type = AMD_IVHD_DEVICE_ENTRY_TYPE_ALIAS_START_RANGE;
> +            entry_ext.devid_a = PCI_BUILD_BDF(sec, PCI_DEVFN(0, 0));
>  
>              if (pci_is_express(dev) &&
>                  pcie_cap_get_type(dev) == PCI_EXP_TYPE_PCI_BRIDGE) {
> -                dev_id_b = dev_id_a;
> +                entry_ext.devid_b = entry_ext.devid_a;
>              } else {
> -                dev_id_b = PCI_BUILD_BDF(pci_bus_num(bus), dev->devfn);
> +                entry_ext.devid_b = PCI_BUILD_BDF(pci_bus_num(bus),
> +                                                  dev->devfn);
>              }
>  
>              /* "Alias Start of Range" IVHD entry, type 0x43, 8 bytes */
> -            build_append_int_noprefix(table_data, dev_id_a << 8 | 0x43, 4);
> -            build_append_int_noprefix(table_data, dev_id_b << 8 | 0x0, 4);
> +            g_array_append_vals(table_data, &entry_ext, sizeof(entry_ext));
>  
>              /* "End of Range" IVHD entry, type 0x4 */
> -            entry = PCI_BUILD_BDF(sub, PCI_DEVFN(31, 7)) << 8 | 0x4;
> -            build_append_int_noprefix(table_data, entry, 4);
> +            entry.type = AMD_IVHD_DEVICE_ENTRY_TYPE_END_RANGE;
> +            entry.devid = PCI_BUILD_BDF(sub, PCI_DEVFN_MAX - 1);
> +            g_array_append_vals(table_data, &entry, sizeof(entry));
>          }
>      }
>  }
> @@ -1786,20 +1793,20 @@ build_amd_iommu(GArray *table_data, BIOSLinker *linker, const char *oem_id,
>      GArray *ivhd_blob = g_array_new(false, true, 1);
>      AcpiTable table = { .sig = "IVRS", .rev = 1, .oem_id = oem_id,
>                          .oem_table_id = oem_table_id };
> -    uint64_t feature_report;
>      int iommu_bus = pci_bus_num(pci_get_bus(iommu_dev));
>      uint16_t iommu_devid = PCI_BUILD_BDF(iommu_bus, iommu_dev->devfn);
> +    AmdIvrsVendorHdr ivrs_hdr = {};
> +    AmdIvhdHdr10 ivhd10 = {};
> +    AmdIvhdHdr11 ivhd11 = {};
>  
>      acpi_table_begin(&table, table_data);
>      /* IVinfo - IO virtualization information common to all
>       * IOMMU units in a system
>       */
> -    build_append_int_noprefix(table_data,
> -                             (1UL << 0) | /* EFRSup */
> -                             AMDVI_PA_SIZE_52,
> -                             4);
> -    /* reserved */
> -    build_append_int_noprefix(table_data, 0, 8);
> +    ivrs_hdr.ivinfo = AMD_IVINFO_EFR_SUP | AMDVI_GVA_SIZE_48 |
> +                      AMDVI_PA_SIZE_52 | AMDVI_VA_SIZE_64;
> +
> +    g_array_append_vals(table_data, &ivrs_hdr, sizeof(ivrs_hdr));


This has broken endian-ness.



Please do not use packed structs.


ACPI has infrastructure to build up structs such as
build_append_int_noprefix.

Just use that.


>  
>      /*
>       * A PCI bus walk, for each PCI host bridge, is necessary to create a
> @@ -1817,7 +1824,8 @@ build_amd_iommu(GArray *table_data, BIOSLinker *linker, const char *oem_id,
>           *   These are 4-byte device entries currently reporting the range of
>           *   Refer to Spec - Table 95:IVHD Device Entry Type Codes(4-byte)
>           */
> -        build_append_int_noprefix(ivhd_blob, 0x0000001, 4);
> +        AmdIvhdDeviceEntry entry = { .type = AMD_IVHD_DEVICE_ENTRY_TYPE_ALL };
> +        g_array_append_vals(ivhd_blob, &entry, sizeof(entry));
>      }
>  
>      /*
> @@ -1829,76 +1837,37 @@ build_amd_iommu(GArray *table_data, BIOSLinker *linker, const char *oem_id,
>       * See Linux kernel commit 'c2ff5cf5294bcbd7fa50f7d860e90a66db7e5059'
>       */
>      if (x86_iommu_ir_supported(x86_iommu_get_default())) {
> -        build_append_int_noprefix(ivhd_blob,
> -                                 (0x1ull << 56) |           /* type IOAPIC */
> -                                 (IOAPIC_SB_DEVID << 40) |  /* IOAPIC devid */
> -                                 0x48,                      /* special device */
> -                                 8);
> -    }
> -
> -    /* IVHD definition - type 10h */
> -    build_append_int_noprefix(table_data, 0x10, 1);
> -    /* virtualization flags */
> -    build_append_int_noprefix(table_data,
> -                             (1UL << 0) | /* HtTunEn      */
> -                             (1UL << 4) | /* iotblSup     */
> -                             (1UL << 6) | /* PrefSup      */
> -                             (1UL << 7),  /* PPRSup       */
> -                             1);
> -
> -    /* IVHD length */
> -    build_append_int_noprefix(table_data, ivhd_blob->len + 24, 2);
> -    /* DeviceID */
> -    build_append_int_noprefix(table_data, iommu_devid, 2);
> -    /* Capability offset */
> -    build_append_int_noprefix(table_data, s->pci->capab_offset, 2);
> -    /* IOMMU base address */
> -    build_append_int_noprefix(table_data, s->mr_mmio.addr, 8);
> -    /* PCI Segment Group */
> -    build_append_int_noprefix(table_data, 0, 2);
> -    /* IOMMU info */
> -    build_append_int_noprefix(table_data, 0, 2);
> -    /* IOMMU Feature Reporting */
> -    feature_report = get_amd_ivhd_feature_report(s);
> -    build_append_int_noprefix(table_data, feature_report, 4);
> -
> +        AmdIvhdDeviceEntryExt entry_ext = {
> +                    .type = AMD_IVHD_DEVICE_ENTRY_TYPE_SPECIAL_DEVICE,
> +                    .devid_b = IOAPIC_SB_DEVID,
> +                    .variety = IVHD_VARIETY_IOAPIC
> +                };
> +
> +        g_array_append_vals(ivhd_blob, &entry_ext, sizeof(entry_ext));
> +    }
> +
> +    ivhd10.type = 0x10;
> +    ivhd10.flags = AMD_IVHD_FLAG_HT_TUN_EN | AMD_IVHD_FLAG_IOTLB_SUP |
> +                   AMD_IVHD_FLAG_PREF_SUP  | AMD_IVHD_FLAG_PPR_SUP;
> +    ivhd10.length = ivhd_blob->len + sizeof(ivhd10);
> +    ivhd10.devid = iommu_devid;
> +    ivhd10.capab_offset = s->pci->capab_offset;
> +    ivhd10.base_addr = s->mr_mmio.addr;
> +    ivhd10.iommu_feature_report = get_amd_ivhd_feature_report(s);
> +    g_array_append_vals(table_data, &ivhd10, sizeof(ivhd10));
>      /* IVHD entries as found above */
>      g_array_append_vals(table_data, ivhd_blob->data, ivhd_blob->len);
>  
> -   /* IVHD definition - type 11h */
> -    build_append_int_noprefix(table_data, 0x11, 1);
> -    /* virtualization flags */
> -    build_append_int_noprefix(table_data,
> -                             (1UL << 0) | /* HtTunEn      */
> -                             (1UL << 4),  /* iotblSup     */
> -                             1);
> -
> -    /* IVHD length */
> -    build_append_int_noprefix(table_data, ivhd_blob->len + 40, 2);
> -
> -    /* DeviceID */
> -    build_append_int_noprefix(table_data, iommu_devid, 2);
> -    /* Capability offset */
> -    build_append_int_noprefix(table_data, s->pci->capab_offset, 2);
> -    /* IOMMU base address */
> -    build_append_int_noprefix(table_data, s->mr_mmio.addr, 8);
> -    /* PCI Segment Group */
> -    build_append_int_noprefix(table_data, 0, 2);
> -    /* IOMMU info */
> -    build_append_int_noprefix(table_data, 0, 2);
> -    /* IOMMU Attributes */
> -    if (!s->iommu.dma_translation) {
> -        build_append_int_noprefix(table_data, (1UL << 0) /* HATDis */, 4);
> -    } else {
> -        build_append_int_noprefix(table_data, 0, 4);
> -    }
> -    /* EFR Register Image */
> -    build_append_int_noprefix(table_data,
> -                              amdvi_extended_feature_register(s),
> -                              8);
> -    /* EFR Register Image 2 */
> -    build_append_int_noprefix(table_data, 0, 8);
> -
> +    ivhd11.type = 0x11;
> +    ivhd11.flags = AMD_IVHD_FLAG_HT_TUN_EN | AMD_IVHD_FLAG_IOTLB_SUP;
> +    ivhd11.length = ivhd_blob->len + sizeof(ivhd11);
> +    ivhd11.devid = iommu_devid;
> +    ivhd11.capab_offset = s->pci->capab_offset;
> +    ivhd11.base_addr = s->mr_mmio.addr;
> +    ivhd11.iommu_attributes = !s->iommu.dma_translation <<
> +                              AMD_IVHD_ATTRIBUTES_HATDIS_SHIFT;
> +    ivhd11.efr = amdvi_extended_feature_register(s);
> +    g_array_append_vals(table_data, &ivhd11, sizeof(ivhd11));
>      /* IVHD entries as found above */
>      g_array_append_vals(table_data, ivhd_blob->data, ivhd_blob->len);
>  
> -- 
> 2.34.1