Commit fb9f5926 authored by David Kiarie's avatar David Kiarie Committed by Michael S. Tsirkin
Browse files

hw/i386: AMD IOMMU IVRS table



Add IVRS table for AMD IOMMU. Generate IVRS or DMAR
depending on emulated IOMMU.

Signed-off-by: default avatarDavid Kiarie <davidkiarie4@gmail.com>
Reviewed-by: default avatarMichael S. Tsirkin <mst@redhat.com>
Signed-off-by: default avatarMichael S. Tsirkin <mst@redhat.com>
parent d29a09ca
Loading
Loading
Loading
Loading
+1 −1
Original line number Diff line number Diff line
@@ -226,7 +226,7 @@ static void build_extop_package(GArray *package, uint8_t op)
    build_prepend_byte(package, 0x5B); /* ExtOpPrefix */
}

static void build_append_int_noprefix(GArray *table, uint64_t value, int size)
void build_append_int_noprefix(GArray *table, uint64_t value, int size)
{
    int i;

+67 −9
Original line number Diff line number Diff line
@@ -59,7 +59,8 @@

#include "qapi/qmp/qint.h"
#include "qom/qom-qobject.h"
#include "hw/i386/x86-iommu.h"
#include "hw/i386/amd_iommu.h"
#include "hw/i386/intel_iommu.h"

#include "hw/acpi/ipmi.h"

@@ -2562,6 +2563,62 @@ build_dmar_q35(GArray *table_data, BIOSLinker *linker)
    build_header(linker, table_data, (void *)(table_data->data + dmar_start),
                 "DMAR", table_data->len - dmar_start, 1, NULL, NULL);
}
/*
 *   IVRS table as specified in AMD IOMMU Specification v2.62, Section 5.2
 *   accessible here http://support.amd.com/TechDocs/48882_IOMMU.pdf
 */
static void
build_amd_iommu(GArray *table_data, BIOSLinker *linker)
{
    int iommu_start = table_data->len;
    AMDVIState *s = AMD_IOMMU_DEVICE(x86_iommu_get_default());

    /* IVRS header */
    acpi_data_push(table_data, sizeof(AcpiTableHeader));
    /* IVinfo - IO virtualization information common to all
     * IOMMU units in a system
     */
    build_append_int_noprefix(table_data, 40UL << 8/* PASize */, 4);
    /* reserved */
    build_append_int_noprefix(table_data, 0, 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, 0x24, 2);
    /* DeviceID */
    build_append_int_noprefix(table_data, s->devid, 2);
    /* Capability offset */
    build_append_int_noprefix(table_data, s->capab_offset, 2);
    /* IOMMU base address */
    build_append_int_noprefix(table_data, s->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 */
    build_append_int_noprefix(table_data,
                             (48UL << 30) | /* HATS   */
                             (48UL << 28) | /* GATS   */
                             (1UL << 2),    /* GTSup  */
                             4);
    /*
     *   Type 1 device entry reporting all devices
     *   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(table_data, 0x0000001, 4);

    build_header(linker, table_data, (void *)(table_data->data + iommu_start),
                 "IVRS", table_data->len - iommu_start, 1, NULL, NULL);
}

static GArray *
build_rsdp(GArray *rsdp_table, BIOSLinker *linker, unsigned rsdt_tbl_offset)
@@ -2622,11 +2679,6 @@ static bool acpi_get_mcfg(AcpiMcfgInfo *mcfg)
    return true;
}

static bool acpi_has_iommu(void)
{
    return !!x86_iommu_get_default();
}

static
void acpi_build(AcpiBuildTables *tables, MachineState *machine)
{
@@ -2706,10 +2758,16 @@ void acpi_build(AcpiBuildTables *tables, MachineState *machine)
        acpi_add_table(table_offsets, tables_blob);
        build_mcfg_q35(tables_blob, tables->linker, &mcfg);
    }
    if (acpi_has_iommu()) {
    if (x86_iommu_get_default()) {
        IommuType IOMMUType = x86_iommu_get_type();
        if (IOMMUType == TYPE_AMD) {
            acpi_add_table(table_offsets, tables_blob);
            build_amd_iommu(tables_blob, tables->linker);
        } else if (IOMMUType == TYPE_INTEL) {
            acpi_add_table(table_offsets, tables_blob);
            build_dmar_q35(tables_blob, tables->linker);
        }
    }
    if (pcms->acpi_nvdimm_state.is_enabled) {
        nvdimm_build_acpi(table_offsets, tables_blob, tables->linker,
                          pcms->acpi_nvdimm_state.dsm_mem);
+2 −0
Original line number Diff line number Diff line
@@ -1130,11 +1130,13 @@ static void amdvi_reset(DeviceState *dev)
static void amdvi_realize(DeviceState *dev, Error **err)
{
    AMDVIState *s = AMD_IOMMU_DEVICE(dev);
    X86IOMMUState *x86_iommu = X86_IOMMU_DEVICE(dev);
    PCIBus *bus = PC_MACHINE(qdev_get_machine())->bus;
    s->iotlb = g_hash_table_new_full(amdvi_uint64_hash,
                                     amdvi_uint64_equal, g_free, g_free);

    /* This device should take care of IOMMU PCI properties */
    x86_iommu->type = TYPE_AMD;
    qdev_set_parent_bus(DEVICE(&s->pci), &bus->qbus);
    object_property_set_bool(OBJECT(&s->pci), true, "realized", err);
    s->capab_offset = pci_add_capability(&s->pci.dev, AMDVI_CAPAB_ID_SEC, 0,
+1 −0
Original line number Diff line number Diff line
@@ -2453,6 +2453,7 @@ static void vtd_realize(DeviceState *dev, Error **errp)
    X86IOMMUState *x86_iommu = X86_IOMMU_DEVICE(dev);

    VTD_DPRINTF(GENERAL, "");
    x86_iommu->type = TYPE_INTEL;
    memset(s->vtd_as_by_bus_num, 0, sizeof(s->vtd_as_by_bus_num));
    memory_region_init_io(&s->csrmem, OBJECT(s), &vtd_mem_ops, s,
                          "intel_iommu", DMAR_REG_SIZE);
+6 −0
Original line number Diff line number Diff line
@@ -71,6 +71,11 @@ X86IOMMUState *x86_iommu_get_default(void)
    return x86_iommu_default;
}

IommuType x86_iommu_get_type(void)
{
    return x86_iommu_default->type;
}

static void x86_iommu_realize(DeviceState *dev, Error **errp)
{
    X86IOMMUState *x86_iommu = X86_IOMMU_DEVICE(dev);
@@ -79,6 +84,7 @@ static void x86_iommu_realize(DeviceState *dev, Error **errp)
    if (x86_class->realize) {
        x86_class->realize(dev, errp);
    }

    x86_iommu_set_default(X86_IOMMU_DEVICE(dev));
}

Loading