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 */
 | 
					    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;
 | 
					    int i;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
				
			|||||||
@ -59,7 +59,8 @@
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
#include "qapi/qmp/qint.h"
 | 
					#include "qapi/qmp/qint.h"
 | 
				
			||||||
#include "qom/qom-qobject.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"
 | 
					#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),
 | 
					    build_header(linker, table_data, (void *)(table_data->data + dmar_start),
 | 
				
			||||||
                 "DMAR", table_data->len - dmar_start, 1, NULL, NULL);
 | 
					                 "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 *
 | 
					static GArray *
 | 
				
			||||||
build_rsdp(GArray *rsdp_table, BIOSLinker *linker, unsigned rsdt_tbl_offset)
 | 
					build_rsdp(GArray *rsdp_table, BIOSLinker *linker, unsigned rsdt_tbl_offset)
 | 
				
			||||||
@ -2622,11 +2679,6 @@ static bool acpi_get_mcfg(AcpiMcfgInfo *mcfg)
 | 
				
			|||||||
    return true;
 | 
					    return true;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static bool acpi_has_iommu(void)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
    return !!x86_iommu_get_default();
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
static
 | 
					static
 | 
				
			||||||
void acpi_build(AcpiBuildTables *tables, MachineState *machine)
 | 
					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);
 | 
					        acpi_add_table(table_offsets, tables_blob);
 | 
				
			||||||
        build_mcfg_q35(tables_blob, tables->linker, &mcfg);
 | 
					        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);
 | 
					            acpi_add_table(table_offsets, tables_blob);
 | 
				
			||||||
            build_dmar_q35(tables_blob, tables->linker);
 | 
					            build_dmar_q35(tables_blob, tables->linker);
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
    if (pcms->acpi_nvdimm_state.is_enabled) {
 | 
					    if (pcms->acpi_nvdimm_state.is_enabled) {
 | 
				
			||||||
        nvdimm_build_acpi(table_offsets, tables_blob, tables->linker,
 | 
					        nvdimm_build_acpi(table_offsets, tables_blob, tables->linker,
 | 
				
			||||||
                          pcms->acpi_nvdimm_state.dsm_mem);
 | 
					                          pcms->acpi_nvdimm_state.dsm_mem);
 | 
				
			||||||
 | 
				
			|||||||
@ -1130,11 +1130,13 @@ static void amdvi_reset(DeviceState *dev)
 | 
				
			|||||||
static void amdvi_realize(DeviceState *dev, Error **err)
 | 
					static void amdvi_realize(DeviceState *dev, Error **err)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
    AMDVIState *s = AMD_IOMMU_DEVICE(dev);
 | 
					    AMDVIState *s = AMD_IOMMU_DEVICE(dev);
 | 
				
			||||||
 | 
					    X86IOMMUState *x86_iommu = X86_IOMMU_DEVICE(dev);
 | 
				
			||||||
    PCIBus *bus = PC_MACHINE(qdev_get_machine())->bus;
 | 
					    PCIBus *bus = PC_MACHINE(qdev_get_machine())->bus;
 | 
				
			||||||
    s->iotlb = g_hash_table_new_full(amdvi_uint64_hash,
 | 
					    s->iotlb = g_hash_table_new_full(amdvi_uint64_hash,
 | 
				
			||||||
                                     amdvi_uint64_equal, g_free, g_free);
 | 
					                                     amdvi_uint64_equal, g_free, g_free);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /* This device should take care of IOMMU PCI properties */
 | 
					    /* This device should take care of IOMMU PCI properties */
 | 
				
			||||||
 | 
					    x86_iommu->type = TYPE_AMD;
 | 
				
			||||||
    qdev_set_parent_bus(DEVICE(&s->pci), &bus->qbus);
 | 
					    qdev_set_parent_bus(DEVICE(&s->pci), &bus->qbus);
 | 
				
			||||||
    object_property_set_bool(OBJECT(&s->pci), true, "realized", err);
 | 
					    object_property_set_bool(OBJECT(&s->pci), true, "realized", err);
 | 
				
			||||||
    s->capab_offset = pci_add_capability(&s->pci.dev, AMDVI_CAPAB_ID_SEC, 0,
 | 
					    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);
 | 
					    X86IOMMUState *x86_iommu = X86_IOMMU_DEVICE(dev);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    VTD_DPRINTF(GENERAL, "");
 | 
					    VTD_DPRINTF(GENERAL, "");
 | 
				
			||||||
 | 
					    x86_iommu->type = TYPE_INTEL;
 | 
				
			||||||
    memset(s->vtd_as_by_bus_num, 0, sizeof(s->vtd_as_by_bus_num));
 | 
					    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,
 | 
					    memory_region_init_io(&s->csrmem, OBJECT(s), &vtd_mem_ops, s,
 | 
				
			||||||
                          "intel_iommu", DMAR_REG_SIZE);
 | 
					                          "intel_iommu", DMAR_REG_SIZE);
 | 
				
			||||||
 | 
				
			|||||||
@ -71,6 +71,11 @@ X86IOMMUState *x86_iommu_get_default(void)
 | 
				
			|||||||
    return x86_iommu_default;
 | 
					    return x86_iommu_default;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					IommuType x86_iommu_get_type(void)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    return x86_iommu_default->type;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static void x86_iommu_realize(DeviceState *dev, Error **errp)
 | 
					static void x86_iommu_realize(DeviceState *dev, Error **errp)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
    X86IOMMUState *x86_iommu = X86_IOMMU_DEVICE(dev);
 | 
					    X86IOMMUState *x86_iommu = X86_IOMMU_DEVICE(dev);
 | 
				
			||||||
@ -79,6 +84,7 @@ static void x86_iommu_realize(DeviceState *dev, Error **errp)
 | 
				
			|||||||
    if (x86_class->realize) {
 | 
					    if (x86_class->realize) {
 | 
				
			||||||
        x86_class->realize(dev, errp);
 | 
					        x86_class->realize(dev, errp);
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    x86_iommu_set_default(X86_IOMMU_DEVICE(dev));
 | 
					    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_concatenate(Aml *source1, Aml *source2, Aml *target);
 | 
				
			||||||
Aml *aml_object_type(Aml *object);
 | 
					Aml *aml_object_type(Aml *object);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void build_append_int_noprefix(GArray *table, uint64_t value, int size);
 | 
				
			||||||
void
 | 
					void
 | 
				
			||||||
build_header(BIOSLinker *linker, GArray *table_data,
 | 
					build_header(BIOSLinker *linker, GArray *table_data,
 | 
				
			||||||
             AcpiTableHeader *h, const char *sig, int len, uint8_t rev,
 | 
					             AcpiTableHeader *h, const char *sig, int len, uint8_t rev,
 | 
				
			||||||
 | 
				
			|||||||
@ -37,6 +37,12 @@
 | 
				
			|||||||
typedef struct X86IOMMUState X86IOMMUState;
 | 
					typedef struct X86IOMMUState X86IOMMUState;
 | 
				
			||||||
typedef struct X86IOMMUClass X86IOMMUClass;
 | 
					typedef struct X86IOMMUClass X86IOMMUClass;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					typedef enum IommuType {
 | 
				
			||||||
 | 
					    TYPE_INTEL,
 | 
				
			||||||
 | 
					    TYPE_AMD,
 | 
				
			||||||
 | 
					    TYPE_NONE
 | 
				
			||||||
 | 
					} IommuType;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
struct X86IOMMUClass {
 | 
					struct X86IOMMUClass {
 | 
				
			||||||
    SysBusDeviceClass parent;
 | 
					    SysBusDeviceClass parent;
 | 
				
			||||||
    /* Intel/AMD specific realize() hook */
 | 
					    /* Intel/AMD specific realize() hook */
 | 
				
			||||||
@ -67,6 +73,7 @@ typedef struct IEC_Notifier IEC_Notifier;
 | 
				
			|||||||
struct X86IOMMUState {
 | 
					struct X86IOMMUState {
 | 
				
			||||||
    SysBusDevice busdev;
 | 
					    SysBusDevice busdev;
 | 
				
			||||||
    bool intr_supported;        /* Whether vIOMMU supports IR */
 | 
					    bool intr_supported;        /* Whether vIOMMU supports IR */
 | 
				
			||||||
 | 
					    IommuType type;             /* IOMMU type - AMD/Intel     */
 | 
				
			||||||
    QLIST_HEAD(, IEC_Notifier) iec_notifiers; /* IEC notify list */
 | 
					    QLIST_HEAD(, IEC_Notifier) iec_notifiers; /* IEC notify list */
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -76,6 +83,11 @@ struct X86IOMMUState {
 | 
				
			|||||||
 */
 | 
					 */
 | 
				
			||||||
X86IOMMUState *x86_iommu_get_default(void);
 | 
					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
 | 
					 * x86_iommu_iec_register_notifier - register IEC (Interrupt Entry
 | 
				
			||||||
 *                                   Cache) notifiers
 | 
					 *                                   Cache) notifiers
 | 
				
			||||||
 | 
				
			|||||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user