hw/i386: AMD IOMMU IVRS table
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>
This commit is contained in:
parent
d29a09ca68
commit
fb9f592623
@ -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;
|
||||
|
||||
|
@ -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,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,
|
||||
|
@ -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,
|
||||
|
@ -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);
|
||||
|
@ -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));
|
||||
}
|
||||
|
||||
|
@ -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,
|
||||
|
@ -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 */
|
||||
@ -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 */
|
||||
};
|
||||
|
||||
@ -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
|
||||
|
Loading…
Reference in New Issue
Block a user