Skip to content

Commit

Permalink
hw/i386: AMD IOMMU IVRS table
Browse files Browse the repository at this point in the history
Add IVRS table for AMD IOMMU. Generate IVRS or DMAR
depending on emulated IOMMU.

Signed-off-by: David Kiarie <davidkiarie4@gmail.com>
Reviewed-by: Michael S. Tsirkin <mst@redhat.com>
Signed-off-by: Michael S. Tsirkin <mst@redhat.com>
  • Loading branch information
3dgie authored and mstsirkin committed Sep 23, 2016
1 parent d29a09c commit fb9f592
Show file tree
Hide file tree
Showing 7 changed files with 90 additions and 10 deletions.
2 changes: 1 addition & 1 deletion hw/acpi/aml-build.c
Expand Up @@ -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;

Expand Down
76 changes: 67 additions & 9 deletions hw/i386/acpi-build.c
Expand Up @@ -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"

Expand Down Expand Up @@ -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)
Expand Down Expand Up @@ -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)
{
Expand Down Expand Up @@ -2706,9 +2758,15 @@ 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()) {
acpi_add_table(table_offsets, tables_blob);
build_dmar_q35(tables_blob, tables->linker);
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,
Expand Down
2 changes: 2 additions & 0 deletions hw/i386/amd_iommu.c
Expand Up @@ -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,
Expand Down
1 change: 1 addition & 0 deletions hw/i386/intel_iommu.c
Expand Up @@ -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);
Expand Down
6 changes: 6 additions & 0 deletions hw/i386/x86-iommu.c
Expand Up @@ -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);
Expand All @@ -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));
}

Expand Down
1 change: 1 addition & 0 deletions include/hw/acpi/aml-build.h
Expand Up @@ -367,6 +367,7 @@ Aml *aml_sizeof(Aml *arg);
Aml *aml_concatenate(Aml *source1, Aml *source2, Aml *target);
Aml *aml_object_type(Aml *object);

void build_append_int_noprefix(GArray *table, uint64_t value, int size);
void
build_header(BIOSLinker *linker, GArray *table_data,
AcpiTableHeader *h, const char *sig, int len, uint8_t rev,
Expand Down
12 changes: 12 additions & 0 deletions include/hw/i386/x86-iommu.h
Expand Up @@ -37,6 +37,12 @@
typedef struct X86IOMMUState X86IOMMUState;
typedef struct X86IOMMUClass X86IOMMUClass;

typedef enum IommuType {
TYPE_INTEL,
TYPE_AMD,
TYPE_NONE
} IommuType;

struct X86IOMMUClass {
SysBusDeviceClass parent;
/* Intel/AMD specific realize() hook */
Expand Down Expand Up @@ -67,6 +73,7 @@ typedef struct IEC_Notifier IEC_Notifier;
struct X86IOMMUState {
SysBusDevice busdev;
bool intr_supported; /* Whether vIOMMU supports IR */
IommuType type; /* IOMMU type - AMD/Intel */
QLIST_HEAD(, IEC_Notifier) iec_notifiers; /* IEC notify list */
};

Expand All @@ -76,6 +83,11 @@ struct X86IOMMUState {
*/
X86IOMMUState *x86_iommu_get_default(void);

/*
* x86_iommu_get_type - get IOMMU type
*/
IommuType x86_iommu_get_type(void);

/**
* x86_iommu_iec_register_notifier - register IEC (Interrupt Entry
* Cache) notifiers
Expand Down

0 comments on commit fb9f592

Please sign in to comment.