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…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user