[Qemu-devel] [PATCH 2/4] hw/pci-host: Add AMD IOMMU to PIIX and Q35 pcs
From: David Emulate AMD IOMMU on PIIX and Q35 controlled by a command line switch Signed-off-by: David Kiarie --- hw/pci-host/piix.c | 10 ++ hw/pci-host/q35.c | 10 ++ 2 files changed, 20 insertions(+) diff --git a/hw/pci-host/piix.c b/hw/pci-host/piix.c index 1fb71c8..a4b07d2 100644 --- a/hw/pci-host/piix.c +++ b/hw/pci-host/piix.c @@ -31,6 +31,7 @@ #include "qemu/range.h" #include "hw/xen/xen.h" #include "hw/pci-host/pam.h" +#include "hw/i386/amd_iommu.h" #include "sysemu/sysemu.h" #include "hw/i386/ioapic.h" #include "qapi/visitor.h" @@ -290,12 +291,21 @@ static void i440fx_pcihost_realize(DeviceState *dev, Error **errp) { PCIHostState *s = PCI_HOST_BRIDGE(dev); SysBusDevice *sbd = SYS_BUS_DEVICE(dev); +AMDIOMMUState *iommu_state; +PCIDevice *iommu; sysbus_add_io(sbd, 0xcf8, &s->conf_mem); sysbus_init_ioports(sbd, 0xcf8, 4); sysbus_add_io(sbd, 0xcfc, &s->data_mem); sysbus_init_ioports(sbd, 0xcfc, 4); + +/* AMD IOMMU (AMD-Vi) */ +if(machine_amd_iommu(current_machine)){ +iommu = pci_create_simple(s->bus, 0x20, TYPE_AMD_IOMMU_DEVICE); +iommu_state = AMD_IOMMU_DEVICE(iommu); +pci_setup_iommu(s->bus, bridge_host_amd_iommu, iommu_state); +} } static void i440fx_realize(PCIDevice *dev, Error **errp) diff --git a/hw/pci-host/q35.c b/hw/pci-host/q35.c index bd74094..cef84ff 100644 --- a/hw/pci-host/q35.c +++ b/hw/pci-host/q35.c @@ -30,6 +30,7 @@ #include "hw/hw.h" #include "hw/pci-host/q35.h" #include "qapi/visitor.h" +#include "hw/i386/amd_iommu.h" / * Q35 host @@ -470,6 +471,8 @@ static void mch_realize(PCIDevice *d, Error **errp) { int i; MCHPCIState *mch = MCH_PCI_DEVICE(d); +AMDIOMMUState *iommu_state; +PCIDevice *iommu; /* setup pci memory mapping */ pc_pci_as_mapping_init(OBJECT(mch), mch->system_memory, @@ -528,6 +531,13 @@ static void mch_realize(PCIDevice *d, Error **errp) if (machine_iommu(current_machine)) { mch_init_dmar(mch); } +/* AMD IOMMU (AMD-Vi) */ +if (machine_amd_iommu(current_machine)){ +PCIBus *bus = PCI_BUS(qdev_get_parent_bus(DEVICE(mch))); +iommu = pci_create_simple(bus, 0x20, TYPE_AMD_IOMMU_DEVICE); +iommu_state = AMD_IOMMU_DEVICE(iommu); +pci_setup_iommu(bus, bridge_host_amd_iommu, iommu_state); +} } uint64_t mch_mcfg_base(void) -- 2.1.4
[Qemu-devel] [PATCH 4/4] hw/acpi: ACPI table for AMD IOMMU
From: David Add AMD IOMMU IVRS table to ACPI tables Signed-off-by: David Kiarie --- hw/i386/acpi-build.c| 85 + include/hw/acpi/acpi-defs.h | 55 + 2 files changed, 140 insertions(+) diff --git a/hw/i386/acpi-build.c b/hw/i386/acpi-build.c index 95e0c65..1016ed9 100644 --- a/hw/i386/acpi-build.c +++ b/hw/i386/acpi-build.c @@ -50,6 +50,7 @@ #include "hw/pci/pci_bus.h" #include "hw/pci-host/q35.h" #include "hw/i386/intel_iommu.h" +#include "hw/i386/amd_iommu.h" #include "hw/i386/q35-acpi-dsdt.hex" #include "hw/i386/acpi-dsdt.hex" @@ -1576,10 +1577,80 @@ build_dmar_q35(GArray *table_data, GArray *linker) } static void +amd_iommu_acpi_set_flag(uint8_t *value, uint64_t flag) +{ +uint64_t newvalue = *value | flag; +*(uint64_t*)value = newvalue; +} + +static void +amd_iommu_acpi_set_feature(uint64_t *value, uint64_t feature) +{ +uint64_t newvalue = *value | feature; +*value = newvalue; +} + +static void +build_amd_iommu(GArray *table_data, GArray *linker) +{ +int iommu_start = table_data->len; +bool iommu_ambig; +uint64_t host_width = (AMD_IOMMU_HOST_ADDRESS_WIDTH << 8); + +AcpiAMDIOMMUIVRS *ivrs; +AcpiAMDIOMMUHardwareUnit *iommu; + +/* IVRS definition */ +ivrs = acpi_data_push(table_data, sizeof(*ivrs)); +ivrs->revision = ACPI_IOMMU_IVRS_TYPE; +ivrs->length = (sizeof(*ivrs) + sizeof(*iommu)); +ivrs->v_common_info = host_width; + +AMDIOMMUState *s = (AMDIOMMUState*)object_resolve_path_type("", TYPE_AMD_IOMMU_DEVICE, &iommu_ambig); + +/* IVDB definition */ +iommu = acpi_data_push(table_data, sizeof(*iommu)); +if(!iommu_ambig){ +iommu->type = 0x10; +/* IVHD flags */ +amd_iommu_acpi_set_flag(&iommu->flags, IVHD_HT_TUNEN); +amd_iommu_acpi_set_flag(&iommu->flags, IVHD_PPRSUP); +amd_iommu_acpi_set_flag(&iommu->flags, IVHD_IOTLBSUP); +amd_iommu_acpi_set_flag(&iommu->flags, IVHD_ISOC); +amd_iommu_acpi_set_flag(&iommu->flags, IVHD_PREFSUP); + +iommu->length = sizeof(*iommu); +iommu->device_id = PCI_DEVICE_ID_RD890_IOMMU; +iommu->capability_offset = s->capab_offset; +iommu->mmio_base = s->mmio.addr; +iommu->pci_segment = cpu_to_le16(0); +iommu->interrupt_info = cpu_to_le16(0); + +/* EFR features */ +amd_iommu_acpi_set_feature(&iommu->efr_register, IVHD_EFR_GTSUP); +amd_iommu_acpi_set_feature(&iommu->efr_register, IVHD_EFR_HATS); +amd_iommu_acpi_set_feature(&iommu->efr_register, IVHD_EFR_GATS); + +/* device entries */ +memset(iommu->dev_entries, 0, 20); + +/* Add device flags here */ +iommu->dev_entries[12] = 3; +iommu->dev_entries[16] = 4; +iommu->dev_entries[17] = 0xff; +iommu->dev_entries[18] = 0xff; +} + +build_header(linker, table_data, (void*)(table_data->data + iommu_start), + "IVRS", table_data->len - iommu_start, 1); +} + +static void build_dsdt(GArray *table_data, GArray *linker, AcpiMiscInfo *misc) { AcpiTableHeader *dsdt; + assert(misc->dsdt_code && misc->dsdt_size); dsdt = acpi_data_push(table_data, misc->dsdt_size); @@ -1658,6 +1729,16 @@ static bool acpi_has_iommu(void) return intel_iommu && !ambiguous; } +static bool acpi_has_amd_iommu(void) +{ +bool ambiguous; +Object *amd_iommu; + +amd_iommu = object_resolve_path_type("", TYPE_AMD_IOMMU_DEVICE, + &ambiguous); +return amd_iommu && !ambiguous; +} + static void acpi_build(PcGuestInfo *guest_info, AcpiBuildTables *tables) { @@ -1741,6 +1822,10 @@ void acpi_build(PcGuestInfo *guest_info, AcpiBuildTables *tables) acpi_add_table(table_offsets, tables_blob); build_dmar_q35(tables_blob, tables->linker); } +if(acpi_has_amd_iommu() && !acpi_has_iommu()){ +acpi_add_table(table_offsets, tables_blob); +build_amd_iommu(tables_blob, tables->linker); +} /* Add tables supplied by user (if any) */ for (u = acpi_table_first(); u; u = acpi_table_next(u)) { diff --git a/include/hw/acpi/acpi-defs.h b/include/hw/acpi/acpi-defs.h index 2b431e6..4fc1f79 100644 --- a/include/hw/acpi/acpi-defs.h +++ b/include/hw/acpi/acpi-defs.h @@ -561,4 +561,59 @@ typedef struct AcpiDmarHardwareUnit AcpiDmarHardwareUnit; /* Masks for Flags field above */ #define ACPI_DMAR_INCLUDE_PCI_ALL 1 +/* IVRS constants */ +#define ACPI_IOMMU_HARDWAREUNIT_TYPE 0x10 +#define ACPI_IOMMU_IVRS_TYPE 0x1 +#define AMD_IOMMU_HOST_ADDRESS_WIDTH 39UL + +/* AMD IOMMU IVRS table */ +struct AcpiAMDIOMMUIVRS{ +ACPI_TABLE_HEADER
[Qemu-devel] [PATCH 1/4] hw/core: Add iommu to machine properties
From: David Add iommu to machine properties in preparation of introducing AMD IOMMU Signed-off-by: David Kiarie --- hw/core/machine.c | 25 + include/hw/boards.h | 2 ++ 2 files changed, 27 insertions(+) diff --git a/hw/core/machine.c b/hw/core/machine.c index 51ed6b2..8cc7461 100644 --- a/hw/core/machine.c +++ b/hw/core/machine.c @@ -269,6 +269,20 @@ static void machine_set_iommu(Object *obj, bool value, Error **errp) ms->iommu = value; } +static bool machine_get_amd_iommu(Object *obj, Error **errp) +{ +MachineState *ms = MACHINE(obj); + +return ms->amd_iommu; +} + +static void machine_set_amd_iommu(Object *obj, bool value, Error **errp) +{ +MachineState *ms = MACHINE(obj); + +ms->amd_iommu = value; +} + static void machine_set_suppress_vmdesc(Object *obj, bool value, Error **errp) { MachineState *ms = MACHINE(obj); @@ -420,6 +434,12 @@ static void machine_initfn(Object *obj) object_property_set_description(obj, "iommu", "Set on/off to enable/disable Intel IOMMU (VT-d)", NULL); +object_property_add_bool(obj, "amd-iommu", + machine_get_amd_iommu, + machine_set_amd_iommu, NULL); +object_property_set_description(obj, "amd-iommu", +"Set on/off to enable/disable AMD-Vi", +NULL); object_property_add_bool(obj, "suppress-vmdesc", machine_get_suppress_vmdesc, machine_set_suppress_vmdesc, NULL); @@ -456,6 +476,11 @@ bool machine_iommu(MachineState *machine) return machine->iommu; } +bool machine_amd_iommu(MachineState *machine) +{ +return machine->amd_iommu; +} + bool machine_kernel_irqchip_allowed(MachineState *machine) { return machine->kernel_irqchip_allowed; diff --git a/include/hw/boards.h b/include/hw/boards.h index 566a5ca..c8424f7 100644 --- a/include/hw/boards.h +++ b/include/hw/boards.h @@ -54,6 +54,7 @@ extern MachineState *current_machine; bool machine_usb(MachineState *machine); bool machine_iommu(MachineState *machine); +bool machine_amd_iommu(MachineState *machine); bool machine_kernel_irqchip_allowed(MachineState *machine); bool machine_kernel_irqchip_required(MachineState *machine); int machine_kvm_shadow_mem(MachineState *machine); @@ -140,6 +141,7 @@ struct MachineState { bool igd_gfx_passthru; char *firmware; bool iommu; +bool amd_iommu; bool suppress_vmdesc; ram_addr_t ram_size; -- 2.1.4
[Qemu-devel] [PATCH 3/4] hw/i386: Introduce AMD IOMMU
From: David Introduce basic AMD IOMMU emulation in Qemu. IOMMU implements event logging and host translation which should allow nested PCI passthrough.It also implemented a very basic IOTLB implementation Signed-off-by: David Kiarie --- hw/i386/Makefile.objs |1 + hw/i386/amd_iommu.c | 1266 + hw/i386/amd_iommu.h | 363 ++ 3 files changed, 1630 insertions(+) create mode 100644 hw/i386/amd_iommu.c create mode 100644 hw/i386/amd_iommu.h diff --git a/hw/i386/Makefile.objs b/hw/i386/Makefile.objs index c250deb..85fa90f 100644 --- a/hw/i386/Makefile.objs +++ b/hw/i386/Makefile.objs @@ -3,6 +3,7 @@ obj-y += multiboot.o obj-y += pc.o pc_piix.o pc_q35.o obj-y += pc_sysfw.o obj-y += intel_iommu.o +obj-y += amd_iommu.o obj-$(CONFIG_XEN) += ../xenpv/ xen/ obj-y += kvmvapic.o diff --git a/hw/i386/amd_iommu.c b/hw/i386/amd_iommu.c new file mode 100644 index 000..092f64e --- /dev/null +++ b/hw/i386/amd_iommu.c @@ -0,0 +1,1266 @@ +/* + * QEMU emulation of AMD IOMMU (AMD-Vi) + * + * Copyright (C) 2011 Eduard - Gabriel Munteanu + * Copyright (C) 2015 David Kiarie, + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License along + * with this program; if not, see <http://www.gnu.org/licenses/>. + * + * Cache implementation inspired by hw/i386/intel_iommu.c + * + */ +#include "hw/i386/amd_iommu.h" + +#define DEBUG_AMD_IOMMU +#ifdef DEBUG_AMD_IOMMU +enum { +DEBUG_GENERAL, DEBUG_CAPAB, DEBUG_MMIO, DEBUG_ELOG, +DEBUG_CACHE, DEBUG_COMMAND, DEBUG_MMU +}; + +#define IOMMU_DBGBIT(x) (1 << DEBUG_##x) +static int iommu_dbgflags = IOMMU_DBGBIT(GENERAL) | IOMMU_DBGBIT(MMU) | IOMMU_DBGBIT(MMIO); +//| IOMMU_DBGBIT(CAPAB) | IOMMU_DBGBIT(ELOG) | IOMMU_DBGBIT(CACHE) | IOMMU_DBGBIT(COMMAND); + +#define IOMMU_DPRINTF(what, fmt, ...) do { \ +if (iommu_dbgflags & IOMMU_DBGBIT(what)) { \ +fprintf(stderr, "(amd-iommu)%s: " fmt "\n", __func__, \ +## __VA_ARGS__); } \ +} while (0) +#else +#define IOMMU_DPRINTF(what, fmt, ...) do {} while (0) +#endif + +/* helper functions - FIXME - provide for reading one byte */ +static uint16_t amd_iommu_readw(AMDIOMMUState *s, hwaddr addr) +{ +return lduw_le_p(&s->mmior[addr]); +} + +static uint32_t amd_iommu_readl(AMDIOMMUState *s, hwaddr addr) +{ +return ldl_le_p(&s->mmior[addr]); +} + +static uint64_t amd_iommu_readq(AMDIOMMUState *s, hwaddr addr) +{ +return ldq_le_p(&s->mmior[addr]); +} + +static void amd_iommu_writew(AMDIOMMUState *s, hwaddr addr, uint16_t val) +{ +stw_le_p(&s->mmior[addr], val); +} + +static void amd_iommu_writel(AMDIOMMUState *s, hwaddr addr, uint32_t val) +{ +stl_le_p(&s->mmior[addr], val); +} + +static void amd_iommu_writeq(AMDIOMMUState *s, hwaddr addr, uint64_t val) +{ +stq_le_p(&s->mmior[addr], val); +} + +static void amd_iommu_log_event(AMDIOMMUState *s, uint16_t *evt) +{ +/* event logging not enabled */ +if(!s->evtlog_enabled || *(uint64_t*)&s->mmior[MMIO_STATUS] + | MMIO_STATUS_EVTLOG_OF){ +return; +} + +/* event log buffer full */ +if(s->evtlog_tail >= s->evtlog_len) { +*(uint64_t*)&s->mmior[MMIO_STATUS] |= MMIO_STATUS_EVTLOG_OF; +/* generate interrupt */ +} + +if(dma_memory_write(&address_space_memory, s->evtlog_len + s->evtlog_tail, + &evt, EVENT_LEN)){ +IOMMU_DPRINTF(ELOG, "error: fail to write at address 0x%"PRIx64 + " + offset 0x%"PRIx32, s->evtlog, s->evtlog_tail); +} + + s->evtlog_tail += EVENT_LEN; + *(uint64_t*)&s->mmior[MMIO_STATUS] |= MMIO_STATUS_EVTLOG_INTR; +} + +/* log an error encountered page-walking + * + * @addr: virtual address in translation request + */ +static void amd_iommu_page_fault(AMDIOMMUState *s, uint16_t devid, + dma_addr_t addr, uint8_t info) +{ +IOMMU_DPRINTF(ELOG, ""); + +uint16_t evt[8]; +uint8_t status; + +info |= EVENT_IOPF_I; + +/* encode information */ +*(uint16_t*)&evt[0] = devid; +*(uint16_t*)&evt[3] = info; +*(uint64_t*)&evt[4] = cpu_to_be64(addr); + +/* log a page fault */ +amd_iommu_log_event(s, evt); + +/* Abort the translation */ +status = pci_get_word(s->dev.config + PCI_STATUS); +pci_set_
[Qemu-devel] [PATCH 0/4] AMD IOMMU v1
David (4): hw/core: Add iommu to machine properties hw/pci-host: Add AMD IOMMU to PIIX and Q35 pcs hw/i386: Introduce AMD IOMMU hw/acpi: ACPI table for AMD IOMMU hw/core/machine.c | 25 + hw/i386/Makefile.objs |1 + hw/i386/acpi-build.c| 85 +++ hw/i386/amd_iommu.c | 1266 +++ hw/i386/amd_iommu.h | 363 + hw/pci-host/piix.c | 10 + hw/pci-host/q35.c | 10 + include/hw/acpi/acpi-defs.h | 55 ++ include/hw/boards.h |2 + 9 files changed, 1817 insertions(+) create mode 100644 hw/i386/amd_iommu.c create mode 100644 hw/i386/amd_iommu.h AMD IOMMU v1 Changes since RFC -code cleanup around MMIO code -compacted startup code - some of the 'init' and 'reset' code is similar and can be reused -Implemented basic IOTLB - it's just a hashtable of already requested virtual address translations whereby if a device requests translation of the same address we don't have to do a page walk, again. -Implemented event logging - this version logs about all possible SW/HW errors but most of them are very unlikely to occur. -Changed GVA and HVA to go by the physical host bus implementations - 48 bits virtual and 40 bits physical address space. TODO -Implement MMIO reserving code -Implement r/wc MMIO registers -Implement interrupts related to r/wc registers IOMMU won't be able to implement PPR logging with the current Qemu infrastructure - Qemu doesn't implement anything that's related to PASID. Similary, guest translation won't be possible. Note: I have not tested this code and it might have a few bugs (silly bugs) of course but the RFC version works so, if present, it's just minor bugs. -- 2.1.4
Re: [Qemu-devel] [PATCH 0/4] AMD IOMMU v1
On Fri, Oct 9, 2015 at 10:17 AM, Valentine Sinitsyn wrote: > Hi David, > > Thanks for your efforts. > > > On 09.10.2015 07:53, David Kiarie wrote: >> >> David (4): >>hw/core: Add iommu to machine properties >>hw/pci-host: Add AMD IOMMU to PIIX and Q35 pcs >>hw/i386: Introduce AMD IOMMU >>hw/acpi: ACPI table for AMD IOMMU >> >> hw/core/machine.c | 25 + >> hw/i386/Makefile.objs |1 + >> hw/i386/acpi-build.c| 85 +++ >> hw/i386/amd_iommu.c | 1266 >> +++ >> hw/i386/amd_iommu.h | 363 + >> hw/pci-host/piix.c | 10 + >> hw/pci-host/q35.c | 10 + >> include/hw/acpi/acpi-defs.h | 55 ++ >> include/hw/boards.h |2 + >> 9 files changed, 1817 insertions(+) >> create mode 100644 hw/i386/amd_iommu.c >> create mode 100644 hw/i386/amd_iommu.h >> >> >> AMD IOMMU v1 >> >> Changes since RFC >> -code cleanup around MMIO code >> -compacted startup code - some of the 'init' and 'reset' code is >> similar and can be reused >> -Implemented basic IOTLB - it's just a hashtable of already requested >> virtual address translations whereby if a device requests translation of the >> same address we don't have to do a page walk, again. >> -Implemented event logging - this version logs about all possible >> SW/HW errors but most of them are very unlikely to occur. >> -Changed GVA and HVA to go by the physical host bus implementations - >> 48 bits virtual and 40 bits physical address space. > > I haven't looked into this closely yet, but shouldn't you support a whole 63 > bits wide addresses (and 6-level page tables), as per specification? > Am not sure too. When I tested this, linux was using 3-level pages. I went with 48 bits as AFAIK that's what current hardware works. This code should work with 6-levels though I just used 48 to be 'safe'. >> >> TODO >> -Implement MMIO reserving code >> -Implement r/wc MMIO registers >> -Implement interrupts related to r/wc registers >> >> IOMMU won't be able to implement PPR logging with the current Qemu >> infrastructure - Qemu doesn't implement anything that's related to PASID. >> Similary, guest translation won't be possible. >> >> Note: I have not tested this code and it might have a few bugs (silly >> bugs) of course but the RFC version works so, if present, it's just minor >> bugs. > > > Regards, > Valentine Sinitsyn
Re: [Qemu-devel] [PATCH 0/4] AMD IOMMU v1
On Fri, Oct 9, 2015 at 3:24 PM, Valentine Sinitsyn wrote: > On 09.10.2015 17:22, David kiarie wrote: >> >> On Fri, Oct 9, 2015 at 10:17 AM, Valentine Sinitsyn >> wrote: >>> >>> Hi David, >>> >>> Thanks for your efforts. >>> >>> >>> On 09.10.2015 07:53, David Kiarie wrote: >>>> >>>> >>>> David (4): >>>> hw/core: Add iommu to machine properties >>>> hw/pci-host: Add AMD IOMMU to PIIX and Q35 pcs >>>> hw/i386: Introduce AMD IOMMU >>>> hw/acpi: ACPI table for AMD IOMMU >>>> >>>>hw/core/machine.c | 25 + >>>>hw/i386/Makefile.objs |1 + >>>>hw/i386/acpi-build.c| 85 +++ >>>>hw/i386/amd_iommu.c | 1266 >>>> +++ >>>>hw/i386/amd_iommu.h | 363 + >>>>hw/pci-host/piix.c | 10 + >>>>hw/pci-host/q35.c | 10 + >>>>include/hw/acpi/acpi-defs.h | 55 ++ >>>>include/hw/boards.h |2 + >>>>9 files changed, 1817 insertions(+) >>>>create mode 100644 hw/i386/amd_iommu.c >>>>create mode 100644 hw/i386/amd_iommu.h >>>> >>>> >>>> AMD IOMMU v1 >>>> >>>> Changes since RFC >>>> -code cleanup around MMIO code >>>> -compacted startup code - some of the 'init' and 'reset' code is >>>> similar and can be reused >>>> -Implemented basic IOTLB - it's just a hashtable of already >>>> requested >>>> virtual address translations whereby if a device requests translation of >>>> the >>>> same address we don't have to do a page walk, again. >>>> -Implemented event logging - this version logs about all possible >>>> SW/HW errors but most of them are very unlikely to occur. >>>> -Changed GVA and HVA to go by the physical host bus >>>> implementations - >>>> 48 bits virtual and 40 bits physical address space. >>> >>> >>> I haven't looked into this closely yet, but shouldn't you support a whole >>> 63 >>> bits wide addresses (and 6-level page tables), as per specification? >>> >> Am not sure too. >> >> When I tested this, linux was using 3-level pages. > > Nobody uses whole 6 page table levels, to the best of my knowledge. > Supporting (emulating) them, however, is part of the spec. Besides, it will > be needed if one decides to share page tables between IOMMU and CPU > Should I use 6 levels/64 bit virtual address space ? >> >> I went with 48 bits as AFAIK that's what current hardware works. This >> code should work with 6-levels though I just used 48 to be 'safe'. >> >>>> >>>> TODO >>>> -Implement MMIO reserving code >>>> -Implement r/wc MMIO registers >>>> -Implement interrupts related to r/wc registers >>>> >>>> IOMMU won't be able to implement PPR logging with the current Qemu >>>> infrastructure - Qemu doesn't implement anything that's related to >>>> PASID. >>>> Similary, guest translation won't be possible. >>>> >>>> Note: I have not tested this code and it might have a few bugs (silly >>>> bugs) of course but the RFC version works so, if present, it's just >>>> minor >>>> bugs. >>> >>> >>> >>> Regards, >>> Valentine Sinitsyn > > > Regards, > Valentine Sinitsyn
Re: [Qemu-devel] [PATCH 3/4] hw/i386: Introduce AMD IOMMU
On Thu, Oct 8, 2015 at 9:24 PM, Marcel Apfelbaum wrote: > On 10/09/2015 05:53 AM, David Kiarie wrote: >> >> From: David >> >> Introduce basic AMD IOMMU emulation in Qemu. IOMMU implements event >> logging and >> host translation which should allow nested PCI passthrough.It also >> implemented >> a very basic IOTLB implementation >> >> Signed-off-by: David Kiarie >> --- >> hw/i386/Makefile.objs |1 + >> hw/i386/amd_iommu.c | 1266 >> + >> hw/i386/amd_iommu.h | 363 ++ >> 3 files changed, 1630 insertions(+) >> create mode 100644 hw/i386/amd_iommu.c >> create mode 100644 hw/i386/amd_iommu.h >> >> diff --git a/hw/i386/Makefile.objs b/hw/i386/Makefile.objs >> index c250deb..85fa90f 100644 >> --- a/hw/i386/Makefile.objs >> +++ b/hw/i386/Makefile.objs >> @@ -3,6 +3,7 @@ obj-y += multiboot.o >> obj-y += pc.o pc_piix.o pc_q35.o >> obj-y += pc_sysfw.o >> obj-y += intel_iommu.o >> +obj-y += amd_iommu.o >> obj-$(CONFIG_XEN) += ../xenpv/ xen/ >> >> obj-y += kvmvapic.o >> diff --git a/hw/i386/amd_iommu.c b/hw/i386/amd_iommu.c >> new file mode 100644 >> index 000..092f64e >> --- /dev/null >> +++ b/hw/i386/amd_iommu.c >> @@ -0,0 +1,1266 @@ >> +/* >> + * QEMU emulation of AMD IOMMU (AMD-Vi) >> + * >> + * Copyright (C) 2011 Eduard - Gabriel Munteanu >> + * Copyright (C) 2015 David Kiarie, >> + * >> + * This program is free software; you can redistribute it and/or modify >> + * it under the terms of the GNU General Public License as published by >> + * the Free Software Foundation; either version 2 of the License, or >> + * (at your option) any later version. >> + >> + * This program is distributed in the hope that it will be useful, >> + * but WITHOUT ANY WARRANTY; without even the implied warranty of >> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the >> + * GNU General Public License for more details. >> + >> + * You should have received a copy of the GNU General Public License >> along >> + * with this program; if not, see <http://www.gnu.org/licenses/>. >> + * >> + * Cache implementation inspired by hw/i386/intel_iommu.c >> + * >> + */ >> +#include "hw/i386/amd_iommu.h" >> + >> +#define DEBUG_AMD_IOMMU >> +#ifdef DEBUG_AMD_IOMMU >> +enum { >> +DEBUG_GENERAL, DEBUG_CAPAB, DEBUG_MMIO, DEBUG_ELOG, >> +DEBUG_CACHE, DEBUG_COMMAND, DEBUG_MMU >> +}; >> + >> +#define IOMMU_DBGBIT(x) (1 << DEBUG_##x) >> +static int iommu_dbgflags = IOMMU_DBGBIT(GENERAL) | IOMMU_DBGBIT(MMU) | >> IOMMU_DBGBIT(MMIO); >> +//| IOMMU_DBGBIT(CAPAB) | IOMMU_DBGBIT(ELOG) | IOMMU_DBGBIT(CACHE) | >> IOMMU_DBGBIT(COMMAND); >> + >> +#define IOMMU_DPRINTF(what, fmt, ...) do { \ >> +if (iommu_dbgflags & IOMMU_DBGBIT(what)) { \ >> +fprintf(stderr, "(amd-iommu)%s: " fmt "\n", __func__, \ >> +## __VA_ARGS__); } \ >> +} while (0) >> +#else >> +#define IOMMU_DPRINTF(what, fmt, ...) do {} while (0) >> +#endif >> + >> +/* helper functions - FIXME - provide for reading one byte */ >> +static uint16_t amd_iommu_readw(AMDIOMMUState *s, hwaddr addr) >> +{ >> +return lduw_le_p(&s->mmior[addr]); >> +} >> + >> +static uint32_t amd_iommu_readl(AMDIOMMUState *s, hwaddr addr) >> +{ >> +return ldl_le_p(&s->mmior[addr]); >> +} >> + >> +static uint64_t amd_iommu_readq(AMDIOMMUState *s, hwaddr addr) >> +{ >> +return ldq_le_p(&s->mmior[addr]); >> +} >> + >> +static void amd_iommu_writew(AMDIOMMUState *s, hwaddr addr, uint16_t val) >> +{ >> +stw_le_p(&s->mmior[addr], val); >> +} >> + >> +static void amd_iommu_writel(AMDIOMMUState *s, hwaddr addr, uint32_t val) >> +{ >> +stl_le_p(&s->mmior[addr], val); >> +} >> + >> +static void amd_iommu_writeq(AMDIOMMUState *s, hwaddr addr, uint64_t val) >> +{ >> +stq_le_p(&s->mmior[addr], val); >> +} >> + >> +static void amd_iommu_log_event(AMDIOMMUState *s, uint16_t *evt) >> +{ >> +/* event logging not enabled */ >> +if(!s->evtlog_enabled || *(uint64_t*)&s->mmior[MMIO_STATUS] >> + | MMIO_STATUS_EVTLOG_OF){ >> +return; >> +} >> + >> +/* event log buffer full */ >> +if(s->evtlog_tail >= s->ev
Re: [Qemu-devel] [PATCH 1/4] hw/core: Add iommu to machine properties
On Thu, Oct 8, 2015 at 9:10 PM, Marcel Apfelbaum wrote: > On 10/09/2015 05:53 AM, David Kiarie wrote: >> >> From: David >> >> Add iommu to machine properties in preparation of introducing >> AMD IOMMU >> >> Signed-off-by: David Kiarie >> --- >> hw/core/machine.c | 25 + >> include/hw/boards.h | 2 ++ >> 2 files changed, 27 insertions(+) >> >> diff --git a/hw/core/machine.c b/hw/core/machine.c >> index 51ed6b2..8cc7461 100644 >> --- a/hw/core/machine.c >> +++ b/hw/core/machine.c >> @@ -269,6 +269,20 @@ static void machine_set_iommu(Object *obj, bool >> value, Error **errp) >> ms->iommu = value; >> } >> >> +static bool machine_get_amd_iommu(Object *obj, Error **errp) >> +{ >> +MachineState *ms = MACHINE(obj); >> + >> +return ms->amd_iommu; >> +} >> + >> +static void machine_set_amd_iommu(Object *obj, bool value, Error **errp) >> +{ >> +MachineState *ms = MACHINE(obj); >> + >> +ms->amd_iommu = value; >> +} >> + >> static void machine_set_suppress_vmdesc(Object *obj, bool value, Error >> **errp) >> { >> MachineState *ms = MACHINE(obj); >> @@ -420,6 +434,12 @@ static void machine_initfn(Object *obj) >> object_property_set_description(obj, "iommu", >> "Set on/off to enable/disable Intel >> IOMMU (VT-d)", >> NULL); >> +object_property_add_bool(obj, "amd-iommu", >> + machine_get_amd_iommu, >> + machine_set_amd_iommu, NULL); >> +object_property_set_description(obj, "amd-iommu", >> +"Set on/off to enable/disable >> AMD-Vi", >> +NULL); >> object_property_add_bool(obj, "suppress-vmdesc", >>machine_get_suppress_vmdesc, >>machine_set_suppress_vmdesc, NULL); >> @@ -456,6 +476,11 @@ bool machine_iommu(MachineState *machine) >> return machine->iommu; >> } >> >> +bool machine_amd_iommu(MachineState *machine) >> +{ >> +return machine->amd_iommu; >> +} >> + >> bool machine_kernel_irqchip_allowed(MachineState *machine) >> { >> return machine->kernel_irqchip_allowed; >> diff --git a/include/hw/boards.h b/include/hw/boards.h >> index 566a5ca..c8424f7 100644 >> --- a/include/hw/boards.h >> +++ b/include/hw/boards.h >> @@ -54,6 +54,7 @@ extern MachineState *current_machine; >> >> bool machine_usb(MachineState *machine); >> bool machine_iommu(MachineState *machine); >> +bool machine_amd_iommu(MachineState *machine); >> bool machine_kernel_irqchip_allowed(MachineState *machine); >> bool machine_kernel_irqchip_required(MachineState *machine); >> int machine_kvm_shadow_mem(MachineState *machine); >> @@ -140,6 +141,7 @@ struct MachineState { >> bool igd_gfx_passthru; >> char *firmware; >> bool iommu; >> +bool amd_iommu; >> bool suppress_vmdesc; >> >> ram_addr_t ram_size; >> > > Hi, > > I think we should add the property to PC_MACHINE class because it make sense > only > for PC and Q35 machines (right?). Right. > MACHINE is the base class for all the architectures. > > On the same note, "iommu" refers to intel_iommu and maybe we should > move it also to the PC_MACHINE. > I understand that it is not in the scope of your series, we can add a patch > later. > > Another possibility would be to keep the same "iommu" property, but change > it from boolean > to off|intel|amd|... . This will break backward compatibility, on the other > hand having > iommu referring to Intel only when we have multiple iommu implementations > is ugly IMHO. > Okay. I think I could look into the last option. > Thanks, > Marcel > >
Re: [Qemu-devel] [V4 1/4] hw/i386: Introduce AMD IO MMU
On Thu, Feb 4, 2016 at 6:03 PM, Michael S. Tsirkin wrote: > On Mon, Jan 18, 2016 at 06:25:42PM +0300, David Kiarie wrote: >> Add AMD IO MMU emulation to Qemu in addition to Intel IO MMU. >> The IO MMU does basic translation, error checking and has a >> minimal IOTLB implementation. >> >> Signed-off-by: David Kiarie >> --- >> hw/i386/Makefile.objs |1 + >> hw/i386/amd_iommu.c | 1409 >> + >> hw/i386/amd_iommu.h | 399 ++ >> include/hw/pci/pci.h |2 + >> 4 files changed, 1811 insertions(+) >> create mode 100644 hw/i386/amd_iommu.c >> create mode 100644 hw/i386/amd_iommu.h >> >> diff --git a/hw/i386/Makefile.objs b/hw/i386/Makefile.objs >> index b52d5b8..2f1a265 100644 >> --- a/hw/i386/Makefile.objs >> +++ b/hw/i386/Makefile.objs >> @@ -3,6 +3,7 @@ obj-y += multiboot.o >> obj-y += pc.o pc_piix.o pc_q35.o >> obj-y += pc_sysfw.o >> obj-y += intel_iommu.o >> +obj-y += amd_iommu.o >> obj-$(CONFIG_XEN) += ../xenpv/ xen/ >> >> obj-y += kvmvapic.o >> diff --git a/hw/i386/amd_iommu.c b/hw/i386/amd_iommu.c >> new file mode 100644 >> index 000..20111fe >> --- /dev/null >> +++ b/hw/i386/amd_iommu.c >> @@ -0,0 +1,1409 @@ >> +/* >> + * QEMU emulation of AMD IOMMU (AMD-Vi) >> + * >> + * Copyright (C) 2011 Eduard - Gabriel Munteanu >> + * Copyright (C) 2015 David Kiarie, >> + * >> + * This program is free software; you can redistribute it and/or modify >> + * it under the terms of the GNU General Public License as published by >> + * the Free Software Foundation; either version 2 of the License, or >> + * (at your option) any later version. >> + >> + * This program is distributed in the hope that it will be useful, >> + * but WITHOUT ANY WARRANTY; without even the implied warranty of >> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the >> + * GNU General Public License for more details. >> + >> + * You should have received a copy of the GNU General Public License along >> + * with this program; if not, see <http://www.gnu.org/licenses/>. >> + * >> + * Cache implementation inspired by hw/i386/intel_iommu.c > > Link to hardware spec? > >> + * >> + */ >> +#include "hw/i386/amd_iommu.h" >> + >> +//#define DEBUG_AMD_IOMMU >> +#ifdef DEBUG_AMD_IOMMU >> +enum { >> +DEBUG_GENERAL, DEBUG_CAPAB, DEBUG_MMIO, DEBUG_ELOG, >> +DEBUG_CACHE, DEBUG_COMMAND, DEBUG_MMU >> +}; >> + >> +#define IOMMU_DBGBIT(x) (1 << DEBUG_##x) >> +static int iommu_dbgflags = IOMMU_DBGBIT(MMIO); >> + >> +#define IOMMU_DPRINTF(what, fmt, ...) do { \ >> +if (iommu_dbgflags & IOMMU_DBGBIT(what)) { \ >> +fprintf(stderr, "(amd-iommu)%s: " fmt "\n", __func__, \ >> +## __VA_ARGS__); } \ >> +} while (0) >> +#else >> +#define IOMMU_DPRINTF(what, fmt, ...) do {} while (0) >> +#endif >> + >> +/* configure MMIO registers at startup/reset */ >> +static void amd_iommu_set_quad(AMDIOMMUState *s, hwaddr addr, uint64_t val, >> + uint64_t romask, uint64_t w1cmask) >> +{ >> +stq_le_p(&s->mmior[addr], val); >> +stq_le_p(&s->romask[addr], romask); >> +stq_le_p(&s->w1cmask[addr], w1cmask); >> +} >> + >> +static uint16_t amd_iommu_readw(AMDIOMMUState *s, hwaddr addr) >> +{ >> +return lduw_le_p(&s->mmior[addr]); >> +} >> + >> +static uint32_t amd_iommu_readl(AMDIOMMUState *s, hwaddr addr) >> +{ >> +return ldl_le_p(&s->mmior[addr]); >> +} >> + >> +static uint64_t amd_iommu_readq(AMDIOMMUState *s, hwaddr addr) >> +{ >> +return ldq_le_p(&s->mmior[addr]); >> +} >> + >> +/* internal write */ >> +static void amd_iommu_writeq_raw(AMDIOMMUState *s, uint64_t val, hwaddr >> addr) >> +{ >> +stq_le_p(&s->mmior[addr], val); >> +} >> + >> +/* external write */ >> +static void amd_iommu_writew(AMDIOMMUState *s, hwaddr addr, uint16_t val) >> +{ >> +uint16_t romask = lduw_le_p(&s->romask[addr]); >> +uint16_t w1cmask = lduw_le_p(&s->w1cmask[addr]); >> +uint16_t oldval = lduw_le_p(&s->mmior[addr]); >> +stw_le_p(&s->mmior[addr], (val & ~(val & w1cmask)) | (romask & oldval)); >> +} >> + >> +static void amd_iommu_writel(AMDIOMMUState *s, hwaddr addr, uint
Re: [Qemu-devel] [V4 4/4] hw/pci-host: Emulate AMD IO MMU
On Sun, Feb 14, 2016 at 4:02 PM, Marcel Apfelbaum wrote: > On 01/18/2016 05:25 PM, David Kiarie wrote: >> >> Support AMD IO MMU emulation in q35 and piix chipsets >> >> Signed-off-by: David Kiarie >> --- >> hw/pci-host/piix.c | 11 +++ >> hw/pci-host/q35.c | 14 -- >> 2 files changed, 23 insertions(+), 2 deletions(-) >> >> diff --git a/hw/pci-host/piix.c b/hw/pci-host/piix.c >> index b0d7e31..3ba245d 100644 >> --- a/hw/pci-host/piix.c >> +++ b/hw/pci-host/piix.c >> @@ -35,6 +35,7 @@ >> #include "hw/i386/ioapic.h" >> #include "qapi/visitor.h" >> #include "qemu/error-report.h" >> +#include "hw/i386/amd_iommu.h" >> >> /* >>* I440FX chipset data sheet. >> @@ -297,6 +298,16 @@ static void i440fx_pcihost_realize(DeviceState *dev, >> Error **errp) >> >> sysbus_add_io(sbd, 0xcfc, &s->data_mem); >> sysbus_init_ioports(sbd, 0xcfc, 4); >> + >> +/* AMD IOMMU (AMD-Vi) */ >> +if (g_strcmp0(object_property_get_str(qdev_get_machine(), "iommu", >> NULL), >> + "amd") == 0) { > > > Hi, > > Minor comments, here you can use the same qdev_get_machine())->iommu as used > below > and the same AMD_IOMMU_STR instead of "amd". > > Do I understand correctly that we can have an AMD IOMMU working on an i440fx > machine (non PCI Express)? Well, we could say, it worked - then because I didn't have any interrupts yet but I wont work anymore since am going to add an interrupt with event logging. Will resend, as soon as possible. > > Thanks, > Marcel > > >> +AMDIOMMUState *iommu_state; >> +PCIDevice *iommu; >> +iommu = pci_create_simple(s->bus, 0x20, TYPE_AMD_IOMMU_DEVICE); >> +iommu_state = AMD_IOMMU_DEVICE(iommu); >> +pci_setup_iommu(s->bus, bridge_host_amd_iommu, iommu_state); >> +} >> } >> >> static void i440fx_realize(PCIDevice *dev, Error **errp) >> diff --git a/hw/pci-host/q35.c b/hw/pci-host/q35.c >> index 1fb4707..0c60e3c 100644 >> --- a/hw/pci-host/q35.c >> +++ b/hw/pci-host/q35.c >> @@ -30,6 +30,7 @@ >> #include "hw/hw.h" >> #include "hw/pci-host/q35.h" >> #include "qapi/visitor.h" >> +#include "hw/i386/amd_iommu.h" >> >> >> / >>* Q35 host >> @@ -505,9 +506,18 @@ static void mch_realize(PCIDevice *d, Error **errp) >>mch->pci_address_space, &mch->pam_regions[i+1], >>PAM_EXPAN_BASE + i * PAM_EXPAN_SIZE, PAM_EXPAN_SIZE); >> } >> -/* Intel IOMMU (VT-d) */ >> -if (object_property_get_bool(qdev_get_machine(), "iommu", NULL)) { >> + >> +if (g_strcmp0(MACHINE(qdev_get_machine())->iommu, INTEL_IOMMU_STR) == >> 0) { >> +/* Intel IOMMU (VT-d) */ >> mch_init_dmar(mch); >> +} else if (g_strcmp0(MACHINE(qdev_get_machine())->iommu, >> AMD_IOMMU_STR) >> + == 0) { >> +AMDIOMMUState *iommu_state; >> +PCIDevice *iommu; >> +PCIBus *bus = PCI_BUS(qdev_get_parent_bus(DEVICE(mch))); >> +iommu = pci_create_simple(bus, 0x20, TYPE_AMD_IOMMU_DEVICE); >> +iommu_state = AMD_IOMMU_DEVICE(iommu); >> +pci_setup_iommu(bus, bridge_host_amd_iommu, iommu_state); >> } >> } >> >> >
Re: [Qemu-devel] [V4 3/4] hw/i386: ACPI table for AMD IO MMU
On Sun, Feb 14, 2016 at 4:07 PM, Michael S. Tsirkin wrote: > On Sun, Feb 14, 2016 at 02:54:36PM +0200, Marcel Apfelbaum wrote: >> On 01/18/2016 05:25 PM, David Kiarie wrote: >> >Add IVRS table for AMD IO MMU. >> > >> >Signed-off-by: David Kiarie >> >--- >> > hw/i386/acpi-build.c| 70 >> > + >> > include/hw/acpi/acpi-defs.h | 55 +++ >> > 2 files changed, 125 insertions(+) >> > >> >diff --git a/hw/i386/acpi-build.c b/hw/i386/acpi-build.c >> >index 78758e2..5c0d6b7 100644 >> >--- a/hw/i386/acpi-build.c >> >+++ b/hw/i386/acpi-build.c >> >@@ -52,6 +52,7 @@ >> > #include "hw/pci/pci_bus.h" >> > #include "hw/pci-host/q35.h" >> > #include "hw/i386/intel_iommu.h" >> >+#include "hw/i386/amd_iommu.h" >> > #include "hw/timer/hpet.h" >> > >> > #include "hw/acpi/aml-build.h" >> >@@ -2424,6 +2425,70 @@ build_dmar_q35(GArray *table_data, GArray *linker) >> > } >> > >> > static void >> >+build_amd_iommu(GArray *table_data, GArray *linker) >> >+{ >> >+int iommu_start = table_data->len; >> >+bool iommu_ambig; >> >+ >> >+AcpiAMDIOMMUIVRS *ivrs; >> >+AcpiAMDIOMMUHardwareUnit *iommu; >> >+ >> >+/* IVRS definition */ >> >+ivrs = acpi_data_push(table_data, sizeof(*ivrs)); >> >+ivrs->revision = cpu_to_le16(ACPI_IOMMU_IVRS_TYPE); >> >+ivrs->length = cpu_to_le16((sizeof(*ivrs) + sizeof(*iommu))); >> >+ivrs->v_common_info = cpu_to_le64(AMD_IOMMU_HOST_ADDRESS_WIDTH << 8); >> >+ >> >+AMDIOMMUState *s = (AMDIOMMUState *)object_resolve_path_type("", >> >+TYPE_AMD_IOMMU_DEVICE, &iommu_ambig); >> >+ >> >+/* IVDB definition */ >> >+iommu = acpi_data_push(table_data, sizeof(*iommu)); >> >+if (!iommu_ambig) { >> >> Hi, >> >> If the reference to AMD IOMMU is ambiguous and the table is not added to ACPI >> I think we should report the error to user, something like error_report. >> >> >+iommu->type = cpu_to_le16(0x10); >> >+/* IVHD flags */ >> >+iommu->flags = cpu_to_le16(iommu->flags); >> >+iommu->flags = cpu_to_le16(IVHD_HT_TUNEN | IVHD_PPRSUP | >> >IVHD_IOTLBSUP >> >+ | IVHD_PREFSUP); >> >+iommu->length = cpu_to_le16(sizeof(*iommu)); >> >+iommu->device_id = cpu_to_le16(PCI_DEVICE_ID_RD890_IOMMU); >> >+iommu->capability_offset = cpu_to_le16(s->capab_offset); >> >+iommu->mmio_base = cpu_to_le64(s->mmio.addr); >> >+iommu->pci_segment = 0; >> >+iommu->interrupt_info = 0; >> >+/* EFR features */ >> >+iommu->efr_register = cpu_to_le64(IVHD_EFR_GTSUP | IVHD_EFR_HATS >> >+ | IVHD_EFR_GATS); >> >+iommu->efr_register = cpu_to_le64(iommu->efr_register); >> >+/* device entries */ >> >+memset(iommu->dev_entries, 0, 20); >> >+/* Add device flags here >> >+ * create entries for devices to be treated specially by IO MMU, >> >+ * currently we report all devices to IO MMU with no special flags >> >+ * DTE settings made here apply to all devices >> >+ * Refer to AMD IOMMU spec Table 97 >> >+ */ >> >+iommu->dev_entries[12] = 3; >> >+iommu->dev_entries[16] = 4; >> >+iommu->dev_entries[17] = 0xff; >> >+iommu->dev_entries[18] = 0xff; >> >+} >> >+ >> >+build_header(linker, table_data, (void *)(table_data->data + >> >iommu_start), >> >+ "IVRS", table_data->len - iommu_start, 1, NULL); >> >+} >> >+ >> >+static bool acpi_has_amd_iommu(void) >> >+{ >> >+bool ambiguous; >> >+Object *amd_iommu; >> >+ >> >+amd_iommu = object_resolve_path_type("", TYPE_AMD_IOMMU_DEVICE, >> >+ &ambiguous); >> >+return amd_iommu && !ambiguous; >> >+} >> >+ >> >+static void >> > build_dsdt(GArray *table_data, GArray *linker, >> >
Re: [Qemu-devel] [V4 1/4] hw/i386: Introduce AMD IO MMU
On Thu, Feb 4, 2016 at 6:03 PM, Michael S. Tsirkin wrote: > On Mon, Jan 18, 2016 at 06:25:42PM +0300, David Kiarie wrote: >> Add AMD IO MMU emulation to Qemu in addition to Intel IO MMU. >> The IO MMU does basic translation, error checking and has a >> minimal IOTLB implementation. >> >> Signed-off-by: David Kiarie >> --- >> hw/i386/Makefile.objs |1 + >> hw/i386/amd_iommu.c | 1409 >> + >> hw/i386/amd_iommu.h | 399 ++ >> include/hw/pci/pci.h |2 + >> 4 files changed, 1811 insertions(+) >> create mode 100644 hw/i386/amd_iommu.c >> create mode 100644 hw/i386/amd_iommu.h >> >> diff --git a/hw/i386/Makefile.objs b/hw/i386/Makefile.objs >> index b52d5b8..2f1a265 100644 >> --- a/hw/i386/Makefile.objs >> +++ b/hw/i386/Makefile.objs >> @@ -3,6 +3,7 @@ obj-y += multiboot.o >> obj-y += pc.o pc_piix.o pc_q35.o >> obj-y += pc_sysfw.o >> obj-y += intel_iommu.o >> +obj-y += amd_iommu.o >> obj-$(CONFIG_XEN) += ../xenpv/ xen/ >> >> obj-y += kvmvapic.o >> diff --git a/hw/i386/amd_iommu.c b/hw/i386/amd_iommu.c >> new file mode 100644 >> index 000..20111fe >> --- /dev/null >> +++ b/hw/i386/amd_iommu.c >> @@ -0,0 +1,1409 @@ >> +/* >> + * QEMU emulation of AMD IOMMU (AMD-Vi) >> + * >> + * Copyright (C) 2011 Eduard - Gabriel Munteanu >> + * Copyright (C) 2015 David Kiarie, >> + * >> + * This program is free software; you can redistribute it and/or modify >> + * it under the terms of the GNU General Public License as published by >> + * the Free Software Foundation; either version 2 of the License, or >> + * (at your option) any later version. >> + >> + * This program is distributed in the hope that it will be useful, >> + * but WITHOUT ANY WARRANTY; without even the implied warranty of >> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the >> + * GNU General Public License for more details. >> + >> + * You should have received a copy of the GNU General Public License along >> + * with this program; if not, see <http://www.gnu.org/licenses/>. >> + * >> + * Cache implementation inspired by hw/i386/intel_iommu.c > > Link to hardware spec? > >> + * >> + */ >> +#include "hw/i386/amd_iommu.h" >> + >> +//#define DEBUG_AMD_IOMMU >> +#ifdef DEBUG_AMD_IOMMU >> +enum { >> +DEBUG_GENERAL, DEBUG_CAPAB, DEBUG_MMIO, DEBUG_ELOG, >> +DEBUG_CACHE, DEBUG_COMMAND, DEBUG_MMU >> +}; >> + >> +#define IOMMU_DBGBIT(x) (1 << DEBUG_##x) >> +static int iommu_dbgflags = IOMMU_DBGBIT(MMIO); >> + >> +#define IOMMU_DPRINTF(what, fmt, ...) do { \ >> +if (iommu_dbgflags & IOMMU_DBGBIT(what)) { \ >> +fprintf(stderr, "(amd-iommu)%s: " fmt "\n", __func__, \ >> +## __VA_ARGS__); } \ >> +} while (0) >> +#else >> +#define IOMMU_DPRINTF(what, fmt, ...) do {} while (0) >> +#endif >> + >> +/* configure MMIO registers at startup/reset */ >> +static void amd_iommu_set_quad(AMDIOMMUState *s, hwaddr addr, uint64_t val, >> + uint64_t romask, uint64_t w1cmask) >> +{ >> +stq_le_p(&s->mmior[addr], val); >> +stq_le_p(&s->romask[addr], romask); >> +stq_le_p(&s->w1cmask[addr], w1cmask); >> +} >> + >> +static uint16_t amd_iommu_readw(AMDIOMMUState *s, hwaddr addr) >> +{ >> +return lduw_le_p(&s->mmior[addr]); >> +} >> + >> +static uint32_t amd_iommu_readl(AMDIOMMUState *s, hwaddr addr) >> +{ >> +return ldl_le_p(&s->mmior[addr]); >> +} >> + >> +static uint64_t amd_iommu_readq(AMDIOMMUState *s, hwaddr addr) >> +{ >> +return ldq_le_p(&s->mmior[addr]); >> +} >> + >> +/* internal write */ >> +static void amd_iommu_writeq_raw(AMDIOMMUState *s, uint64_t val, hwaddr >> addr) >> +{ >> +stq_le_p(&s->mmior[addr], val); >> +} >> + >> +/* external write */ >> +static void amd_iommu_writew(AMDIOMMUState *s, hwaddr addr, uint16_t val) >> +{ >> +uint16_t romask = lduw_le_p(&s->romask[addr]); >> +uint16_t w1cmask = lduw_le_p(&s->w1cmask[addr]); >> +uint16_t oldval = lduw_le_p(&s->mmior[addr]); >> +stw_le_p(&s->mmior[addr], (val & ~(val & w1cmask)) | (romask & oldval)); >> +} >> + >> +static void amd_iommu_writel(AMDIOMMUState *s, hwaddr addr, uint
Re: [Qemu-devel] [V4 1/4] hw/i386: Introduce AMD IO MMU
On Mon, Feb 15, 2016 at 6:41 AM, David kiarie wrote: > On Thu, Feb 4, 2016 at 6:03 PM, Michael S. Tsirkin wrote: >> On Mon, Jan 18, 2016 at 06:25:42PM +0300, David Kiarie wrote: >>> Add AMD IO MMU emulation to Qemu in addition to Intel IO MMU. >>> The IO MMU does basic translation, error checking and has a >>> minimal IOTLB implementation. >>> >>> Signed-off-by: David Kiarie >>> --- >>> hw/i386/Makefile.objs |1 + >>> hw/i386/amd_iommu.c | 1409 >>> + >>> hw/i386/amd_iommu.h | 399 ++ >>> include/hw/pci/pci.h |2 + >>> 4 files changed, 1811 insertions(+) >>> create mode 100644 hw/i386/amd_iommu.c >>> create mode 100644 hw/i386/amd_iommu.h >>> >>> diff --git a/hw/i386/Makefile.objs b/hw/i386/Makefile.objs >>> index b52d5b8..2f1a265 100644 >>> --- a/hw/i386/Makefile.objs >>> +++ b/hw/i386/Makefile.objs >>> @@ -3,6 +3,7 @@ obj-y += multiboot.o >>> obj-y += pc.o pc_piix.o pc_q35.o >>> obj-y += pc_sysfw.o >>> obj-y += intel_iommu.o >>> +obj-y += amd_iommu.o >>> obj-$(CONFIG_XEN) += ../xenpv/ xen/ >>> >>> obj-y += kvmvapic.o >>> diff --git a/hw/i386/amd_iommu.c b/hw/i386/amd_iommu.c >>> new file mode 100644 >>> index 000..20111fe >>> --- /dev/null >>> +++ b/hw/i386/amd_iommu.c >>> @@ -0,0 +1,1409 @@ >>> +/* >>> + * QEMU emulation of AMD IOMMU (AMD-Vi) >>> + * >>> + * Copyright (C) 2011 Eduard - Gabriel Munteanu >>> + * Copyright (C) 2015 David Kiarie, >>> + * >>> + * This program is free software; you can redistribute it and/or modify >>> + * it under the terms of the GNU General Public License as published by >>> + * the Free Software Foundation; either version 2 of the License, or >>> + * (at your option) any later version. >>> + >>> + * This program is distributed in the hope that it will be useful, >>> + * but WITHOUT ANY WARRANTY; without even the implied warranty of >>> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the >>> + * GNU General Public License for more details. >>> + >>> + * You should have received a copy of the GNU General Public License along >>> + * with this program; if not, see <http://www.gnu.org/licenses/>. >>> + * >>> + * Cache implementation inspired by hw/i386/intel_iommu.c >> >> Link to hardware spec? >> >>> + * >>> + */ >>> +#include "hw/i386/amd_iommu.h" >>> + >>> +//#define DEBUG_AMD_IOMMU >>> +#ifdef DEBUG_AMD_IOMMU >>> +enum { >>> +DEBUG_GENERAL, DEBUG_CAPAB, DEBUG_MMIO, DEBUG_ELOG, >>> +DEBUG_CACHE, DEBUG_COMMAND, DEBUG_MMU >>> +}; >>> + >>> +#define IOMMU_DBGBIT(x) (1 << DEBUG_##x) >>> +static int iommu_dbgflags = IOMMU_DBGBIT(MMIO); >>> + >>> +#define IOMMU_DPRINTF(what, fmt, ...) do { \ >>> +if (iommu_dbgflags & IOMMU_DBGBIT(what)) { \ >>> +fprintf(stderr, "(amd-iommu)%s: " fmt "\n", __func__, \ >>> +## __VA_ARGS__); } \ >>> +} while (0) >>> +#else >>> +#define IOMMU_DPRINTF(what, fmt, ...) do {} while (0) >>> +#endif >>> + >>> +/* configure MMIO registers at startup/reset */ >>> +static void amd_iommu_set_quad(AMDIOMMUState *s, hwaddr addr, uint64_t val, >>> + uint64_t romask, uint64_t w1cmask) >>> +{ >>> +stq_le_p(&s->mmior[addr], val); >>> +stq_le_p(&s->romask[addr], romask); >>> +stq_le_p(&s->w1cmask[addr], w1cmask); >>> +} >>> + >>> +static uint16_t amd_iommu_readw(AMDIOMMUState *s, hwaddr addr) >>> +{ >>> +return lduw_le_p(&s->mmior[addr]); >>> +} >>> + >>> +static uint32_t amd_iommu_readl(AMDIOMMUState *s, hwaddr addr) >>> +{ >>> +return ldl_le_p(&s->mmior[addr]); >>> +} >>> + >>> +static uint64_t amd_iommu_readq(AMDIOMMUState *s, hwaddr addr) >>> +{ >>> +return ldq_le_p(&s->mmior[addr]); >>> +} >>> + >>> +/* internal write */ >>> +static void amd_iommu_writeq_raw(AMDIOMMUState *s, uint64_t val, hwaddr >>> addr) >>> +{ >>> +stq_le_p(&s->mmior[addr], val); >>> +} >>> + >>> +/*
[Qemu-devel] [V4 2/4] hw/core: Add AMD IO MMU to machine properties
Add IO MMU as a string to machine properties which is used to control whether and they type of IO MMU to emulate Signed-off-by: David Kiarie --- hw/core/machine.c | 28 include/hw/boards.h | 3 ++- qemu-options.hx | 6 +++--- util/qemu-config.c | 4 ++-- 4 files changed, 27 insertions(+), 14 deletions(-) diff --git a/hw/core/machine.c b/hw/core/machine.c index 1261368..6379f24 100644 --- a/hw/core/machine.c +++ b/hw/core/machine.c @@ -14,6 +14,8 @@ #include "hw/boards.h" #include "qapi-visit.h" #include "qapi/visitor.h" +#include "hw/i386/amd_iommu.h" +#include "hw/i386/intel_iommu.h" #include "hw/sysbus.h" #include "sysemu/sysemu.h" #include "qemu/error-report.h" @@ -284,18 +286,28 @@ static void machine_set_firmware(Object *obj, const char *value, Error **errp) ms->firmware = g_strdup(value); } -static bool machine_get_iommu(Object *obj, Error **errp) +static char *machine_get_iommu(Object *obj, Error **errp) { MachineState *ms = MACHINE(obj); -return ms->iommu; +return g_strdup(ms->iommu); } -static void machine_set_iommu(Object *obj, bool value, Error **errp) +static void machine_set_iommu(Object *obj, const char *value, Error **errp) { MachineState *ms = MACHINE(obj); +Error *err = NULL; + +g_free(ms->iommu); + +if (g_strcmp0(value, AMD_IOMMU_STR) && +g_strcmp0(value, INTEL_IOMMU_STR)) { +error_setg(errp, "Invalid IO MMU type %s", value); +error_propagate(errp, err); +return; +} -ms->iommu = value; +ms->iommu = g_strdup(value); } static void machine_set_suppress_vmdesc(Object *obj, bool value, Error **errp) @@ -455,11 +467,10 @@ static void machine_initfn(Object *obj) object_property_set_description(obj, "firmware", "Firmware image", NULL); -object_property_add_bool(obj, "iommu", - machine_get_iommu, - machine_set_iommu, NULL); +object_property_add_str(obj, "iommu", +machine_get_iommu, machine_set_iommu, NULL); object_property_set_description(obj, "iommu", -"Set on/off to enable/disable Intel IOMMU (VT-d)", +"IOMMU list", NULL); object_property_add_bool(obj, "suppress-vmdesc", machine_get_suppress_vmdesc, @@ -485,6 +496,7 @@ static void machine_finalize(Object *obj) g_free(ms->dumpdtb); g_free(ms->dt_compatible); g_free(ms->firmware); +g_free(ms->iommu); } bool machine_usb(MachineState *machine) diff --git a/include/hw/boards.h b/include/hw/boards.h index 0f30959..b119245 100644 --- a/include/hw/boards.h +++ b/include/hw/boards.h @@ -36,6 +36,7 @@ bool machine_usb(MachineState *machine); bool machine_kernel_irqchip_allowed(MachineState *machine); bool machine_kernel_irqchip_required(MachineState *machine); bool machine_kernel_irqchip_split(MachineState *machine); +bool machine_amd_iommu(MachineState *machine); int machine_kvm_shadow_mem(MachineState *machine); int machine_phandle_start(MachineState *machine); bool machine_dump_guest_core(MachineState *machine); @@ -126,7 +127,7 @@ struct MachineState { bool usb_disabled; bool igd_gfx_passthru; char *firmware; -bool iommu; +char *iommu; bool suppress_vmdesc; ram_addr_t ram_size; diff --git a/qemu-options.hx b/qemu-options.hx index 733a194..9ac92c1 100644 --- a/qemu-options.hx +++ b/qemu-options.hx @@ -38,7 +38,7 @@ DEF("machine", HAS_ARG, QEMU_OPTION_machine, \ "kvm_shadow_mem=size of KVM shadow MMU\n" "dump-guest-core=on|off include guest memory in a core dump (default=on)\n" "mem-merge=on|off controls memory merge support (default: on)\n" -"iommu=on|off controls emulated Intel IOMMU (VT-d) support (default=off)\n" +"iommu=amd|intel enables and selects the emulated IO MMU (default: off)\n" "igd-passthru=on|off controls IGD GFX passthrough support (default=off)\n" "aes-key-wrap=on|off controls support for AES key wrapping (default=on)\n" "dea-key-wrap=on|off controls support for DEA key wrapping (default=on)\n" @@ -72,8 +72,8 @@ Include guest memory in a core dump. The default is on. Enables or disables memory merge support. This feature, when supported by the host, de-duplicates identical memory pages among VMs instances (enabled by default). -@item iomm
[Qemu-devel] [V4 0/4] AMD IOMMU
Hello there, This is v5 of AMD IOMMU patches that fixes the issues mentioned in v4 except I fail to see the endian-ness issues Michael mentioned. I also stripped PIIX AMD IOMMU support since I added an MSI interrupt. One of the patches has a conflict with current master but it this is mergable I could quickly send a clean patch. Thanks! David Kiarie (4): hw/i386: Introduce AMD IO MMU hw/core: Add AMD IO MMU to machine properties hw/i386: ACPI table for AMD IO MMU hw/pci-host: Emulate AMD IO MMU hw/core/machine.c | 28 +- hw/i386/Makefile.objs |1 + hw/i386/acpi-build.c | 98 ++- hw/i386/amd_iommu.c | 1430 + hw/i386/amd_iommu.h | 395 hw/pci-host/piix.c|1 + hw/pci-host/q35.c | 14 +- include/hw/acpi/acpi-defs.h | 55 ++ include/hw/boards.h |3 +- include/hw/i386/intel_iommu.h |1 + include/hw/pci/pci.h |2 + qemu-options.hx |6 +- util/qemu-config.c|4 +- 13 files changed, 2011 insertions(+), 27 deletions(-) create mode 100644 hw/i386/amd_iommu.c create mode 100644 hw/i386/amd_iommu.h -- 2.1.4
[Qemu-devel] [V4 1/4] hw/i386: Introduce AMD IO MMU
Add AMD IO MMU emulation to Qemu in addition to Intel IO MMU. The IO MMU does basic translation, error checking and has a minimal IOTLB implementation. Signed-off-by: David Kiarie --- hw/i386/Makefile.objs |1 + hw/i386/amd_iommu.c | 1430 + hw/i386/amd_iommu.h | 395 ++ include/hw/pci/pci.h |2 + 4 files changed, 1828 insertions(+) create mode 100644 hw/i386/amd_iommu.c create mode 100644 hw/i386/amd_iommu.h diff --git a/hw/i386/Makefile.objs b/hw/i386/Makefile.objs index b52d5b8..2f1a265 100644 --- a/hw/i386/Makefile.objs +++ b/hw/i386/Makefile.objs @@ -3,6 +3,7 @@ obj-y += multiboot.o obj-y += pc.o pc_piix.o pc_q35.o obj-y += pc_sysfw.o obj-y += intel_iommu.o +obj-y += amd_iommu.o obj-$(CONFIG_XEN) += ../xenpv/ xen/ obj-y += kvmvapic.o diff --git a/hw/i386/amd_iommu.c b/hw/i386/amd_iommu.c new file mode 100644 index 000..b3b977f --- /dev/null +++ b/hw/i386/amd_iommu.c @@ -0,0 +1,1430 @@ +/* + * QEMU emulation of AMD IOMMU (AMD-Vi) + * + * Copyright (C) 2011 Eduard - Gabriel Munteanu + * Copyright (C) 2015 David Kiarie, + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License along + * with this program; if not, see <http://www.gnu.org/licenses/>. + * + * Cache implementation inspired by hw/i386/intel_iommu.c + * + */ +#include "hw/i386/amd_iommu.h" + +/*#define DEBUG_AMD_IOMMU*/ +#ifdef DEBUG_AMD_IOMMU +enum { +DEBUG_GENERAL, DEBUG_CAPAB, DEBUG_MMIO, DEBUG_ELOG, +DEBUG_CACHE, DEBUG_COMMAND, DEBUG_MMU +}; + +#define IOMMU_DBGBIT(x) (1 << DEBUG_##x) +static int iommu_dbgflags = IOMMU_DBGBIT(MMIO); + +#define IOMMU_DPRINTF(what, fmt, ...) do { \ +if (iommu_dbgflags & IOMMU_DBGBIT(what)) { \ +fprintf(stderr, "(amd-iommu)%s: " fmt "\n", __func__, \ +## __VA_ARGS__); } \ +} while (0) +#else +#define IOMMU_DPRINTF(what, fmt, ...) do {} while (0) +#endif + +typedef struct AMDIOMMUAddressSpace { +uint8_t bus_num;/* bus number */ +uint8_t devfn; /* device function */ +AMDIOMMUState *iommu_state; /* IOMMU - one per machine */ +MemoryRegion iommu; /* Device's iommu region*/ +AddressSpace as;/* device's corresponding address space */ +} AMDIOMMUAddressSpace; + +/* IOMMU cache entry */ +typedef struct IOMMUIOTLBEntry { +uint64_t gfn; +uint16_t domid; +uint64_t devid; +uint64_t perms; +uint64_t translated_addr; +} IOMMUIOTLBEntry; + +/* configure MMIO registers at startup/reset */ +static void amd_iommu_set_quad(AMDIOMMUState *s, hwaddr addr, uint64_t val, + uint64_t romask, uint64_t w1cmask) +{ +stq_le_p(&s->mmior[addr], val); +stq_le_p(&s->romask[addr], romask); +stq_le_p(&s->w1cmask[addr], w1cmask); +} + +static uint16_t amd_iommu_readw(AMDIOMMUState *s, hwaddr addr) +{ +return lduw_le_p(&s->mmior[addr]); +} + +static uint32_t amd_iommu_readl(AMDIOMMUState *s, hwaddr addr) +{ +return ldl_le_p(&s->mmior[addr]); +} + +static uint64_t amd_iommu_readq(AMDIOMMUState *s, hwaddr addr) +{ +return ldq_le_p(&s->mmior[addr]); +} + +/* internal write */ +static void amd_iommu_writeq_raw(AMDIOMMUState *s, uint64_t val, hwaddr addr) +{ +stq_le_p(&s->mmior[addr], val); +} + +/* external write */ +static void amd_iommu_writew(AMDIOMMUState *s, hwaddr addr, uint16_t val) +{ +uint16_t romask = lduw_le_p(&s->romask[addr]); +uint16_t w1cmask = lduw_le_p(&s->w1cmask[addr]); +uint16_t oldval = lduw_le_p(&s->mmior[addr]); +stw_le_p(&s->mmior[addr], (val & ~(val & w1cmask)) | (romask & oldval)); +} + +static void amd_iommu_writel(AMDIOMMUState *s, hwaddr addr, uint32_t val) +{ +uint32_t romask = ldl_le_p(&s->romask[addr]); +uint32_t w1cmask = ldl_le_p(&s->w1cmask[addr]); +uint32_t oldval = ldl_le_p(&s->mmior[addr]); +stl_le_p(&s->mmior[addr], (val & ~(val & w1cmask)) | (romask & oldval)); +} + +static void amd_iommu_writeq(AMDIOMMUState *s, hwaddr addr, uint64_t val) +{ +uint64_t romask = ldq_le_p(&s->romask[addr]); +uint64_t w1cmask = ldq_le_p(&s->w1cmask[addr]); +uint32_t oldval = ldq_le_p(&s->mmior[addr]); +stq_l
[Qemu-devel] [V4 4/4] hw/pci-host: Emulate AMD IO MMU
Add AMD IO MMU emulation support to q35 chipset Signed-off-by: David Kiarie --- hw/pci-host/piix.c| 1 + hw/pci-host/q35.c | 14 -- include/hw/i386/intel_iommu.h | 1 + 3 files changed, 14 insertions(+), 2 deletions(-) diff --git a/hw/pci-host/piix.c b/hw/pci-host/piix.c index 3832ed6..6aad34c 100644 --- a/hw/pci-host/piix.c +++ b/hw/pci-host/piix.c @@ -36,6 +36,7 @@ #include "hw/i386/ioapic.h" #include "qapi/visitor.h" #include "qemu/error-report.h" +#include "hw/i386/amd_iommu.h" /* * I440FX chipset data sheet. diff --git a/hw/pci-host/q35.c b/hw/pci-host/q35.c index 42b421e..7284bdd 100644 --- a/hw/pci-host/q35.c +++ b/hw/pci-host/q35.c @@ -31,6 +31,7 @@ #include "hw/hw.h" #include "hw/pci-host/q35.h" #include "qapi/visitor.h" +#include "hw/i386/amd_iommu.h" / * Q35 host @@ -506,9 +507,18 @@ static void mch_realize(PCIDevice *d, Error **errp) mch->pci_address_space, &mch->pam_regions[i+1], PAM_EXPAN_BASE + i * PAM_EXPAN_SIZE, PAM_EXPAN_SIZE); } -/* Intel IOMMU (VT-d) */ -if (object_property_get_bool(qdev_get_machine(), "iommu", NULL)) { + +if (g_strcmp0(MACHINE(qdev_get_machine())->iommu, INTEL_IOMMU_STR) == 0) { +/* Intel IOMMU (VT-d) */ mch_init_dmar(mch); +} else if (g_strcmp0(MACHINE(qdev_get_machine())->iommu, AMD_IOMMU_STR) + == 0) { +AMDIOMMUState *iommu_state; +PCIDevice *iommu; +PCIBus *bus = PCI_BUS(qdev_get_parent_bus(DEVICE(mch))); +iommu = pci_create_simple(bus, 0x20, TYPE_AMD_IOMMU_DEVICE); +iommu_state = AMD_IOMMU_DEVICE(iommu); +pci_setup_iommu(bus, bridge_host_amd_iommu, iommu_state); } } diff --git a/include/hw/i386/intel_iommu.h b/include/hw/i386/intel_iommu.h index 5dbadb7..0b32bd6 100644 --- a/include/hw/i386/intel_iommu.h +++ b/include/hw/i386/intel_iommu.h @@ -27,6 +27,7 @@ #define TYPE_INTEL_IOMMU_DEVICE "intel-iommu" #define INTEL_IOMMU_DEVICE(obj) \ OBJECT_CHECK(IntelIOMMUState, (obj), TYPE_INTEL_IOMMU_DEVICE) +#define INTEL_IOMMU_STR "intel" /* DMAR Hardware Unit Definition address (IOMMU unit) */ #define Q35_HOST_BRIDGE_IOMMU_ADDR 0xfed9ULL -- 2.1.4
[Qemu-devel] [V4 3/4] hw/i386: ACPI table for AMD IO MMU
Add IVRS table for AMD IO MMU. Also reverve MMIO region for IO MMU via ACPI Signed-off-by: David Kiarie --- hw/i386/acpi-build.c| 98 - include/hw/acpi/acpi-defs.h | 55 + 2 files changed, 142 insertions(+), 11 deletions(-) diff --git a/hw/i386/acpi-build.c b/hw/i386/acpi-build.c index 739cfa3..b8cd091 100644 --- a/hw/i386/acpi-build.c +++ b/hw/i386/acpi-build.c @@ -51,6 +51,7 @@ #include "hw/pci/pci_bus.h" #include "hw/pci-host/q35.h" #include "hw/i386/intel_iommu.h" +#include "hw/i386/amd_iommu.h" #include "hw/timer/hpet.h" #include "hw/acpi/aml-build.h" @@ -121,6 +122,12 @@ typedef struct AcpiBuildPciBusHotplugState { bool pcihp_bridge_en; } AcpiBuildPciBusHotplugState; +typedef enum iommu_type { +TYPE_AMD, +TYPE_INTEL, +TYPE_NONE +} iommu_type; + static int acpi_add_cpu_info(Object *o, void *opaque) { @@ -2423,6 +2430,78 @@ build_dmar_q35(GArray *table_data, GArray *linker) } static void +build_amd_iommu(GArray *table_data, GArray *linker) +{ +int iommu_start = table_data->len; +bool iommu_ambig; + +AcpiAMDIOMMUIVRS *ivrs; +AcpiAMDIOMMUHardwareUnit *iommu; + +/* IVRS definition */ +ivrs = acpi_data_push(table_data, sizeof(*ivrs)); +ivrs->revision = cpu_to_le16(ACPI_IOMMU_IVRS_TYPE); +ivrs->length = cpu_to_le16((sizeof(*ivrs) + sizeof(*iommu))); +ivrs->v_common_info = cpu_to_le64(AMD_IOMMU_HOST_ADDRESS_WIDTH << 8); + +AMDIOMMUState *s = (AMDIOMMUState *)object_resolve_path_type("", +TYPE_AMD_IOMMU_DEVICE, &iommu_ambig); + +/* IVDB definition - type 10h */ +iommu = acpi_data_push(table_data, sizeof(*iommu)); +if (!iommu_ambig) { +iommu->type = cpu_to_le16(0x10); +/* IVHD flags */ +iommu->flags = cpu_to_le16(iommu->flags); +iommu->flags = cpu_to_le16(IVHD_HT_TUNEN | IVHD_PPRSUP | IVHD_IOTLBSUP + | IVHD_PREFSUP); +iommu->length = cpu_to_le16(sizeof(*iommu)); +iommu->device_id = cpu_to_le16(PCI_DEVICE_ID_RD890_IOMMU); +iommu->capability_offset = cpu_to_le16(s->capab_offset); +iommu->mmio_base = cpu_to_le64(s->mmio.addr); +iommu->pci_segment = 0; +iommu->interrupt_info = 0; +/* EFR features */ +iommu->efr_register = cpu_to_le64(IVHD_EFR_GTSUP | IVHD_EFR_HATS + | IVHD_EFR_GATS); +iommu->efr_register = cpu_to_le64(iommu->efr_register); +/* device entries */ +memset(iommu->dev_entries, 0, 20); +/* Add device flags here + * This is are 4-byte device entries currently reporting the range of + * devices 00h - h; all devices + * + * Device setting affecting all devices should be made here + * + * Refer to + * (http://developer.amd.com/wordpress/media/2012/10/488821.pdf) + * 5.2.2.1 + */ +iommu->dev_entries[12] = 3; +iommu->dev_entries[16] = 4; +iommu->dev_entries[17] = 0xff; +iommu->dev_entries[18] = 0xff; +} + +build_header(linker, table_data, (void *)(table_data->data + iommu_start), + "IVRS", table_data->len - iommu_start, 1, NULL); +} + +static iommu_type has_iommu(void) +{ +bool ambiguous; + +if (object_resolve_path_type("", TYPE_AMD_IOMMU_DEVICE, &ambiguous) +&& !ambiguous) +return TYPE_AMD; +else if (object_resolve_path_type("", TYPE_INTEL_IOMMU_DEVICE, &ambiguous) +&& !ambiguous) +return TYPE_INTEL; +else +return TYPE_NONE; +} + +static void build_dsdt(GArray *table_data, GArray *linker, AcpiPmInfo *pm, AcpiMiscInfo *misc) { @@ -2590,16 +2669,6 @@ static bool acpi_get_mcfg(AcpiMcfgInfo *mcfg) return true; } -static bool acpi_has_iommu(void) -{ -bool ambiguous; -Object *intel_iommu; - -intel_iommu = object_resolve_path_type("", TYPE_INTEL_IOMMU_DEVICE, - &ambiguous); -return intel_iommu && !ambiguous; -} - static bool acpi_has_nvdimm(void) { PCMachineState *pcms = PC_MACHINE(qdev_get_machine()); @@ -2618,6 +2687,7 @@ void acpi_build(PcGuestInfo *guest_info, AcpiBuildTables *tables) AcpiMcfgInfo mcfg; PcPciInfo pci; uint8_t *u; +iommu_type type = has_iommu(); size_t aml_len = 0; GArray *tables_blob = tables->table_data; @@ -2685,7 +2755,13 @@ void acpi_build(PcGuestInfo *guest_info, AcpiBuildTables *tables) acpi_add_table(table_offsets, tables_blob); build_mcfg_q35(tables_blob, tables->linker, &mcfg); } -if (acpi_has_iommu()) { + +if (type == TYPE_AMD) {
[Qemu-devel] [V3 0/4] AMD IOMMU
David Kiarie (4): hw/core: Add AMD IO MMU to machine properties hw/i386: ACPI table for AMD IO MMU hw/pci-host: Emulate AMD IO MMU hw/core/machine.c | 17 +- hw/i386/Makefile.objs |1 + hw/i386/acpi-build.c| 96 +++ hw/i386/amd_iommu.c | 1420 +++ hw/i386/amd_iommu.h | 399 hw/pci-host/piix.c | 11 + hw/pci-host/q35.c | 16 +- include/hw/acpi/acpi-defs.h | 55 ++ include/hw/boards.h |3 +- include/hw/pci/pci.h|2 + qemu-options.hx |6 +- util/qemu-config.c |4 +- 12 files changed, 2014 insertions(+), 16 deletions(-) create mode 100644 hw/i386/amd_iommu.c create mode 100644 hw/i386/amd_iommu.h Hello, This series introduces AMD IO MMU emulation to qemu. It's the third version. Changes since v2. -Coding style; fixed all errors reported by scripts/checkpatch.pl as suggested by Micheal -Implemented read/only and write 1/clear registers to IO MMU MMIO -Cleaned up dead code -Introduced a switch that controls IO MMU emulation and what type is emulated i.e q35,iommu=amd|intel as suggested by Marcel -Tested with audio device passthrough (ac97 with sound driver alsa) -Reserved memory for IO MMU MMIO via ACPI (I need someone to check this) I was supposed to implement interrupts related to w1/c registers but I decided to reserve everything to do with interrupts for later Testing procedure outlined here http://www.linux-kvm.org/page/How_to_assign_devices_with_VT-d_in_KVM -- 2.1.4
[Qemu-devel] [V3 3/4] hw/i386: ACPI table for AMD IO MMU
Add IVRS table for AMD IO MMU. Also reverve MMIO region for IO MMU via ACPI Signed-off-by: David Kiarie --- hw/i386/acpi-build.c| 96 + include/hw/acpi/acpi-defs.h | 55 ++ 2 files changed, 151 insertions(+) diff --git a/hw/i386/acpi-build.c b/hw/i386/acpi-build.c index 78758e2..5a5d594 100644 --- a/hw/i386/acpi-build.c +++ b/hw/i386/acpi-build.c @@ -52,6 +52,7 @@ #include "hw/pci/pci_bus.h" #include "hw/pci-host/q35.h" #include "hw/i386/intel_iommu.h" +#include "hw/i386/amd_iommu.h" #include "hw/timer/hpet.h" #include "hw/acpi/aml-build.h" @@ -2424,6 +2425,88 @@ build_dmar_q35(GArray *table_data, GArray *linker) } static void +amd_iommu_acpi_set_flag(uint8_t *value, uint64_t flag) +{ +uint64_t newvalue = *value | flag; +*(uint64_t *)value = newvalue; +} + +static void +amd_iommu_acpi_set_feature(uint64_t *value, uint64_t feature) +{ +uint64_t newvalue = *value | feature; +*value = newvalue; +} + +static void +build_amd_iommu(GArray *table_data, GArray *linker) +{ +int iommu_start = table_data->len; +bool iommu_ambig; +uint64_t host_width = (AMD_IOMMU_HOST_ADDRESS_WIDTH << 8); + +AcpiAMDIOMMUIVRS *ivrs; +AcpiAMDIOMMUHardwareUnit *iommu; + +/* IVRS definition */ +ivrs = acpi_data_push(table_data, sizeof(*ivrs)); +ivrs->revision = ACPI_IOMMU_IVRS_TYPE; +ivrs->length = (sizeof(*ivrs) + sizeof(*iommu)); +ivrs->v_common_info = host_width; + +AMDIOMMUState *s = (AMDIOMMUState *)object_resolve_path_type("", +TYPE_AMD_IOMMU_DEVICE, &iommu_ambig); + +/* IVDB definition */ +iommu = acpi_data_push(table_data, sizeof(*iommu)); +if (!iommu_ambig) { +iommu->type = 0x10; +/* IVHD flags */ +amd_iommu_acpi_set_flag(&iommu->flags, IVHD_HT_TUNEN); +amd_iommu_acpi_set_flag(&iommu->flags, IVHD_PPRSUP); +amd_iommu_acpi_set_flag(&iommu->flags, IVHD_IOTLBSUP); +amd_iommu_acpi_set_flag(&iommu->flags, IVHD_ISOC); +amd_iommu_acpi_set_flag(&iommu->flags, IVHD_PREFSUP); + +iommu->length = sizeof(*iommu); +iommu->device_id = PCI_DEVICE_ID_RD890_IOMMU; +iommu->capability_offset = s->capab_offset; +iommu->mmio_base = s->mmio.addr; +fprintf(stderr, "MMIO addr acpi %lx", s->mmio.addr); + +iommu->pci_segment = cpu_to_le16(0); +iommu->interrupt_info = cpu_to_le16(0); + +/* EFR features */ +amd_iommu_acpi_set_feature(&iommu->efr_register, IVHD_EFR_GTSUP); +amd_iommu_acpi_set_feature(&iommu->efr_register, IVHD_EFR_HATS); +amd_iommu_acpi_set_feature(&iommu->efr_register, IVHD_EFR_GATS); + +/* device entries */ +memset(iommu->dev_entries, 0, 20); + +/* Add device flags here */ +iommu->dev_entries[12] = 3; +iommu->dev_entries[16] = 4; +iommu->dev_entries[17] = 0xff; +iommu->dev_entries[18] = 0xff; +} + +build_header(linker, table_data, (void *)(table_data->data + iommu_start), + "IVRS", table_data->len - iommu_start, 1, NULL); +} + +static bool acpi_has_amd_iommu(void) +{ +bool ambiguous; +Object *amd_iommu; + +amd_iommu = object_resolve_path_type("", TYPE_AMD_IOMMU_DEVICE, + &ambiguous); +return amd_iommu && !ambiguous; +} + +static void build_dsdt(GArray *table_data, GArray *linker, AcpiPmInfo *pm, AcpiMiscInfo *misc) { @@ -2481,6 +2564,14 @@ build_dsdt(GArray *table_data, GArray *linker, build_q35_pci0_int(dsdt); } +/* AMD IOMMU */ +if (acpi_has_amd_iommu()) { +sb_scope = aml_scope("_SB"); +aml_append(sb_scope, +aml_operation_region("AMDV", AML_SYSTEM_MEMORY, IOMMU_BASE_ADDR, + 16*1024)); +} + build_cpu_hotplug_aml(dsdt); build_memory_hotplug_aml(dsdt, nr_mem, pm->mem_hp_io_base, pm->mem_hp_io_len); @@ -2691,6 +2782,11 @@ void acpi_build(PcGuestInfo *guest_info, AcpiBuildTables *tables) build_dmar_q35(tables_blob, tables->linker); } +if (acpi_has_amd_iommu() && !acpi_has_iommu()) { +acpi_add_table(table_offsets, tables_blob); +build_amd_iommu(tables_blob, tables->linker); +} + if (acpi_has_nvdimm()) { nvdimm_build_acpi(table_offsets, tables_blob, tables->linker); } diff --git a/include/hw/acpi/acpi-defs.h b/include/hw/acpi/acpi-defs.h index c7a03d4..a161358 100644 --- a/include/hw/acpi/acpi-defs.h +++ b/include/hw/acpi/acpi-defs.h @@ -570,4 +570,59 @@ typedef struct AcpiDmarHardwareUnit AcpiDmarHa
[Qemu-devel] [V3 2/4] hw/core: Add AMD IO MMU to machine properties
Add IO MMU as a string to machine properties which is used to control whether and they type of IO MMU to emulate Signed-off-by: David Kiarie --- hw/core/machine.c | 17 + include/hw/boards.h | 3 ++- qemu-options.hx | 6 +++--- util/qemu-config.c | 4 ++-- 4 files changed, 16 insertions(+), 14 deletions(-) diff --git a/hw/core/machine.c b/hw/core/machine.c index c46ddc7..cb309aa 100644 --- a/hw/core/machine.c +++ b/hw/core/machine.c @@ -283,18 +283,19 @@ static void machine_set_firmware(Object *obj, const char *value, Error **errp) ms->firmware = g_strdup(value); } -static bool machine_get_iommu(Object *obj, Error **errp) +static char *machine_get_iommu(Object *obj, Error **errp) { MachineState *ms = MACHINE(obj); -return ms->iommu; +return g_strdup(ms->iommu); } -static void machine_set_iommu(Object *obj, bool value, Error **errp) +static void machine_set_iommu(Object *obj, const char *value, Error **errp) { MachineState *ms = MACHINE(obj); -ms->iommu = value; +g_free(ms->iommu); +ms->iommu = g_strdup(value); } static void machine_set_suppress_vmdesc(Object *obj, bool value, Error **errp) @@ -454,11 +455,10 @@ static void machine_initfn(Object *obj) object_property_set_description(obj, "firmware", "Firmware image", NULL); -object_property_add_bool(obj, "iommu", - machine_get_iommu, - machine_set_iommu, NULL); +object_property_add_str(obj, "iommu", +machine_get_iommu, machine_set_iommu, NULL); object_property_set_description(obj, "iommu", -"Set on/off to enable/disable Intel IOMMU (VT-d)", +"IOMMU list", NULL); object_property_add_bool(obj, "suppress-vmdesc", machine_get_suppress_vmdesc, @@ -484,6 +484,7 @@ static void machine_finalize(Object *obj) g_free(ms->dumpdtb); g_free(ms->dt_compatible); g_free(ms->firmware); +g_free(ms->iommu); } bool machine_usb(MachineState *machine) diff --git a/include/hw/boards.h b/include/hw/boards.h index 0f30959..b119245 100644 --- a/include/hw/boards.h +++ b/include/hw/boards.h @@ -36,6 +36,7 @@ bool machine_usb(MachineState *machine); bool machine_kernel_irqchip_allowed(MachineState *machine); bool machine_kernel_irqchip_required(MachineState *machine); bool machine_kernel_irqchip_split(MachineState *machine); +bool machine_amd_iommu(MachineState *machine); int machine_kvm_shadow_mem(MachineState *machine); int machine_phandle_start(MachineState *machine); bool machine_dump_guest_core(MachineState *machine); @@ -126,7 +127,7 @@ struct MachineState { bool usb_disabled; bool igd_gfx_passthru; char *firmware; -bool iommu; +char *iommu; bool suppress_vmdesc; ram_addr_t ram_size; diff --git a/qemu-options.hx b/qemu-options.hx index 215d00d..ac327c8 100644 --- a/qemu-options.hx +++ b/qemu-options.hx @@ -38,7 +38,7 @@ DEF("machine", HAS_ARG, QEMU_OPTION_machine, \ "kvm_shadow_mem=size of KVM shadow MMU\n" "dump-guest-core=on|off include guest memory in a core dump (default=on)\n" "mem-merge=on|off controls memory merge support (default: on)\n" -"iommu=on|off controls emulated Intel IOMMU (VT-d) support (default=off)\n" +"iommu=amd|intel enables and selects the emulated IO MMU (default: off)\n" "igd-passthru=on|off controls IGD GFX passthrough support (default=off)\n" "aes-key-wrap=on|off controls support for AES key wrapping (default=on)\n" "dea-key-wrap=on|off controls support for DEA key wrapping (default=on)\n" @@ -72,8 +72,8 @@ Include guest memory in a core dump. The default is on. Enables or disables memory merge support. This feature, when supported by the host, de-duplicates identical memory pages among VMs instances (enabled by default). -@item iommu=on|off -Enables or disables emulated Intel IOMMU (VT-d) support. The default is off. +@item iommu=intel|amd +Enables and selects the emulated IO MMU. The default is off. @item aes-key-wrap=on|off Enables or disables AES key wrapping support on s390-ccw hosts. This feature controls whether AES wrapping keys will be created to allow diff --git a/util/qemu-config.c b/util/qemu-config.c index 687fd34..f79b98c 100644 --- a/util/qemu-config.c +++ b/util/qemu-config.c @@ -213,8 +213,8 @@ static QemuOptsList machine_opts = { .help = "firmware image", },{
[Qemu-devel] [V3 4/4] hw/pci-host: Emulate AMD IO MMU
Support AMD IO MMU emulation in q35 and piix chipsets Signed-off-by: David Kiarie --- hw/pci-host/piix.c | 11 +++ hw/pci-host/q35.c | 16 ++-- 2 files changed, 25 insertions(+), 2 deletions(-) diff --git a/hw/pci-host/piix.c b/hw/pci-host/piix.c index 924f0fa..19e2930 100644 --- a/hw/pci-host/piix.c +++ b/hw/pci-host/piix.c @@ -35,6 +35,7 @@ #include "hw/i386/ioapic.h" #include "qapi/visitor.h" #include "qemu/error-report.h" +#include "hw/i386/amd_iommu.h" /* * I440FX chipset data sheet. @@ -297,6 +298,16 @@ static void i440fx_pcihost_realize(DeviceState *dev, Error **errp) sysbus_add_io(sbd, 0xcfc, &s->data_mem); sysbus_init_ioports(sbd, 0xcfc, 4); + +/* AMD IOMMU (AMD-Vi) */ +if (g_strcmp0(object_property_get_str(qdev_get_machine(), "iommu", NULL), + "amd") == 0) { +AMDIOMMUState *iommu_state; +PCIDevice *iommu; +iommu = pci_create_simple(s->bus, 0x20, TYPE_AMD_IOMMU_DEVICE); +iommu_state = AMD_IOMMU_DEVICE(iommu); +pci_setup_iommu(s->bus, bridge_host_amd_iommu, iommu_state); +} } static void i440fx_realize(PCIDevice *dev, Error **errp) diff --git a/hw/pci-host/q35.c b/hw/pci-host/q35.c index 1fb4707..dd4c822 100644 --- a/hw/pci-host/q35.c +++ b/hw/pci-host/q35.c @@ -30,6 +30,7 @@ #include "hw/hw.h" #include "hw/pci-host/q35.h" #include "qapi/visitor.h" +#include "hw/i386/amd_iommu.h" / * Q35 host @@ -505,10 +506,21 @@ static void mch_realize(PCIDevice *d, Error **errp) mch->pci_address_space, &mch->pam_regions[i+1], PAM_EXPAN_BASE + i * PAM_EXPAN_SIZE, PAM_EXPAN_SIZE); } -/* Intel IOMMU (VT-d) */ -if (object_property_get_bool(qdev_get_machine(), "iommu", NULL)) { + +char *iommu = object_property_get_str(qdev_get_machine(), "iommu", NULL); + +if (g_strcmp0(iommu, "intel") == 0) { +/* Intel IOMMU (VT-d) */ mch_init_dmar(mch); +} else if (g_strcmp0(iommu, "amd") == 0) { +AMDIOMMUState *iommu_state; +PCIDevice *iommu; +PCIBus *bus = PCI_BUS(qdev_get_parent_bus(DEVICE(mch))); +iommu = pci_create_simple(bus, 0x20, TYPE_AMD_IOMMU_DEVICE); +iommu_state = AMD_IOMMU_DEVICE(iommu); +pci_setup_iommu(bus, bridge_host_amd_iommu, iommu_state); } +g_free(iommu); } uint64_t mch_mcfg_base(void) -- 2.1.4
[Qemu-devel] [V3 1/4] hw/i386: Introduce AMD IO MMU
From: David Add AMD IO MMU emulation to Qemu in addition to Intel IO MMU. The IO MMU does basic translation, error checking and has a minimal IOTLB implementation. Signed-off-by: David Kiarie --- hw/i386/Makefile.objs |1 + hw/i386/amd_iommu.c | 1420 + hw/i386/amd_iommu.h | 399 ++ include/hw/pci/pci.h |2 + 4 files changed, 1822 insertions(+) create mode 100644 hw/i386/amd_iommu.c create mode 100644 hw/i386/amd_iommu.h diff --git a/hw/i386/Makefile.objs b/hw/i386/Makefile.objs index b52d5b8..2f1a265 100644 --- a/hw/i386/Makefile.objs +++ b/hw/i386/Makefile.objs @@ -3,6 +3,7 @@ obj-y += multiboot.o obj-y += pc.o pc_piix.o pc_q35.o obj-y += pc_sysfw.o obj-y += intel_iommu.o +obj-y += amd_iommu.o obj-$(CONFIG_XEN) += ../xenpv/ xen/ obj-y += kvmvapic.o diff --git a/hw/i386/amd_iommu.c b/hw/i386/amd_iommu.c new file mode 100644 index 000..4226abc --- /dev/null +++ b/hw/i386/amd_iommu.c @@ -0,0 +1,1420 @@ +/* + * QEMU emulation of AMD IOMMU (AMD-Vi) + * + * Copyright (C) 2011 Eduard - Gabriel Munteanu + * Copyright (C) 2015 David Kiarie, + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License along + * with this program; if not, see <http://www.gnu.org/licenses/>. + * + * Cache implementation inspired by hw/i386/intel_iommu.c + * + */ +#include "qemu/typedefs.h" +#include "hw/i386/amd_iommu.h" + +#define DEBUG_AMD_IOMMU +#ifdef DEBUG_AMD_IOMMU +enum { +DEBUG_GENERAL, DEBUG_CAPAB, DEBUG_MMIO, DEBUG_ELOG, +DEBUG_CACHE, DEBUG_COMMAND, DEBUG_MMU +}; + +#define IOMMU_DBGBIT(x) (1 << DEBUG_##x) +static int iommu_dbgflags = IOMMU_DBGBIT(MMIO); + +#define IOMMU_DPRINTF(what, fmt, ...) do { \ +if (iommu_dbgflags & IOMMU_DBGBIT(what)) { \ +fprintf(stderr, "(amd-iommu)%s: " fmt "\n", __func__, \ +## __VA_ARGS__); } \ +} while (0) +#else +#define IOMMU_DPRINTF(what, fmt, ...) do {} while (0) +#endif + +/* configure MMIO registers at startup/reset */ +static void amd_iommu_set_quad(AMDIOMMUState *s, hwaddr addr, uint64_t val, + uint64_t romask, uint64_t w1cmask) +{ +stq_le_p(&s->mmior[addr], val); +stq_le_p(&s->romask[addr], romask); +stq_le_p(&s->w1cmask[addr], w1cmask); +} + +static uint16_t amd_iommu_readw(AMDIOMMUState *s, hwaddr addr) +{ +return lduw_le_p(&s->mmior[addr]); +} + +static uint32_t amd_iommu_readl(AMDIOMMUState *s, hwaddr addr) +{ +return ldl_le_p(&s->mmior[addr]); +} + +static uint64_t amd_iommu_readq(AMDIOMMUState *s, hwaddr addr) +{ +return ldq_le_p(&s->mmior[addr]); +} + +/* internal write */ +static void amd_iommu_writeq_raw(AMDIOMMUState *s, uint64_t val, hwaddr addr) +{ +stq_le_p(&s->mmior[addr], val); +} + +/* external write */ +static void amd_iommu_writew(AMDIOMMUState *s, hwaddr addr, uint16_t val) +{ +uint16_t romask = lduw_le_p(&s->romask[addr]); +uint16_t w1cmask = lduw_le_p(&s->w1cmask[addr]); +uint16_t oldval = lduw_le_p(&s->mmior[addr]); +stw_le_p(&s->mmior[addr], (val & ~(val & w1cmask)) | (romask & oldval)); +} + +static void amd_iommu_writel(AMDIOMMUState *s, hwaddr addr, uint32_t val) +{ +uint32_t romask = ldl_le_p(&s->romask[addr]); +uint32_t w1cmask = ldl_le_p(&s->w1cmask[addr]); +uint32_t oldval = ldl_le_p(&s->mmior[addr]); +stl_le_p(&s->mmior[addr], (val & ~(val & w1cmask)) | (romask & oldval)); +} + +static void amd_iommu_writeq(AMDIOMMUState *s, hwaddr addr, uint64_t val) +{ +uint64_t romask = ldq_le_p(&s->romask[addr]); +uint64_t w1cmask = ldq_le_p(&s->w1cmask[addr]); +uint32_t oldval = ldq_le_p(&s->mmior[addr]); +stq_le_p(&s->mmior[addr], (val & ~(val & w1cmask)) | (romask & oldval)); +} + +static void amd_iommu_log_event(AMDIOMMUState *s, uint16_t *evt) +{ +/* event logging not enabled */ +if (!s->evtlog_enabled || *(uint64_t *)&s->mmior[MMIO_STATUS] + | MMIO_STATUS_EVT_OVF) { +return; +} + +/* event log buffer full */ +if (s->evtlog_tail >= s->evtlog_len) { +*(uint64_t *)&s->mmior[MMIO_STATUS] |= MMIO_STATUS_EVT_OVF; +/* generate interrupt */ +} + +if (dma_memory_write(&address_space_memory, s->evtlog_len
Re: [Qemu-devel] [V3 3/4] hw/i386: ACPI table for AMD IO MMU
On Thu, Jan 14, 2016 at 1:09 PM, Michael S. Tsirkin wrote: > On Thu, Jan 14, 2016 at 11:04:27AM +0300, David Kiarie wrote: >> Add IVRS table for AMD IO MMU. Also reverve MMIO > > reserve? Yeah, typo. > >> region for IO MMU via ACPI > > > It does not look like you reserve anything. > > Pls add a link to hardware spec (in > the device implementation) so we can check > what does real hardware do. > > If this is it: > http://developer.amd.com/wordpress/media/2012/10/488821.pdf > > then the way that works seems to be by guest > programming the MMIO base. > We should do the same: patch seabios and EFI to do this. Yes, that's the spec. We thought this could be possible via ACPI (without patching BIOS ), no ? > >> Signed-off-by: David Kiarie >> --- >> hw/i386/acpi-build.c| 96 >> + >> include/hw/acpi/acpi-defs.h | 55 ++ >> 2 files changed, 151 insertions(+) >> >> diff --git a/hw/i386/acpi-build.c b/hw/i386/acpi-build.c >> index 78758e2..5a5d594 100644 >> --- a/hw/i386/acpi-build.c >> +++ b/hw/i386/acpi-build.c >> @@ -52,6 +52,7 @@ >> #include "hw/pci/pci_bus.h" >> #include "hw/pci-host/q35.h" >> #include "hw/i386/intel_iommu.h" >> +#include "hw/i386/amd_iommu.h" >> #include "hw/timer/hpet.h" >> >> #include "hw/acpi/aml-build.h" >> @@ -2424,6 +2425,88 @@ build_dmar_q35(GArray *table_data, GArray *linker) >> } >> >> static void >> +amd_iommu_acpi_set_flag(uint8_t *value, uint64_t flag) >> +{ >> +uint64_t newvalue = *value | flag; >> +*(uint64_t *)value = newvalue; >> +} >> + >> +static void >> +amd_iommu_acpi_set_feature(uint64_t *value, uint64_t feature) >> +{ >> +uint64_t newvalue = *value | feature; >> +*value = newvalue; >> +} >> + > > These wrappers aren't very useful I think. > >> +static void >> +build_amd_iommu(GArray *table_data, GArray *linker) >> +{ >> +int iommu_start = table_data->len; >> +bool iommu_ambig; >> +uint64_t host_width = (AMD_IOMMU_HOST_ADDRESS_WIDTH << 8); >> + >> +AcpiAMDIOMMUIVRS *ivrs; >> +AcpiAMDIOMMUHardwareUnit *iommu; >> + >> +/* IVRS definition */ >> +ivrs = acpi_data_push(table_data, sizeof(*ivrs)); >> +ivrs->revision = ACPI_IOMMU_IVRS_TYPE; >> +ivrs->length = (sizeof(*ivrs) + sizeof(*iommu)); >> +ivrs->v_common_info = host_width; >> + >> +AMDIOMMUState *s = (AMDIOMMUState *)object_resolve_path_type("", >> +TYPE_AMD_IOMMU_DEVICE, &iommu_ambig); >> + >> +/* IVDB definition */ >> +iommu = acpi_data_push(table_data, sizeof(*iommu)); >> +if (!iommu_ambig) { >> +iommu->type = 0x10; >> +/* IVHD flags */ >> +amd_iommu_acpi_set_flag(&iommu->flags, IVHD_HT_TUNEN); >> +amd_iommu_acpi_set_flag(&iommu->flags, IVHD_PPRSUP); >> +amd_iommu_acpi_set_flag(&iommu->flags, IVHD_IOTLBSUP); >> +amd_iommu_acpi_set_flag(&iommu->flags, IVHD_ISOC); >> +amd_iommu_acpi_set_flag(&iommu->flags, IVHD_PREFSUP); >> + >> +iommu->length = sizeof(*iommu); >> +iommu->device_id = PCI_DEVICE_ID_RD890_IOMMU; >> +iommu->capability_offset = s->capab_offset; >> +iommu->mmio_base = s->mmio.addr; >> +fprintf(stderr, "MMIO addr acpi %lx", s->mmio.addr); >> + >> +iommu->pci_segment = cpu_to_le16(0); >> +iommu->interrupt_info = cpu_to_le16(0); >> + >> +/* EFR features */ >> +amd_iommu_acpi_set_feature(&iommu->efr_register, IVHD_EFR_GTSUP); >> +amd_iommu_acpi_set_feature(&iommu->efr_register, IVHD_EFR_HATS); >> +amd_iommu_acpi_set_feature(&iommu->efr_register, IVHD_EFR_GATS); >> + >> +/* device entries */ >> +memset(iommu->dev_entries, 0, 20); >> + >> +/* Add device flags here */ >> +iommu->dev_entries[12] = 3; >> +iommu->dev_entries[16] = 4; >> +iommu->dev_entries[17] = 0xff; >> +iommu->dev_entries[18] = 0xff; >> +} >> + >> +build_header(linker, table_data, (void *)(table_data->data + >> iommu_start), >> + "IVRS", table_data->len - iommu_start, 1,
Re: [Qemu-devel] [V3 3/4] hw/i386: ACPI table for AMD IO MMU
On Thu, Jan 14, 2016 at 1:09 PM, Michael S. Tsirkin wrote: > On Thu, Jan 14, 2016 at 11:04:27AM +0300, David Kiarie wrote: >> Add IVRS table for AMD IO MMU. Also reverve MMIO > > reserve? > >> region for IO MMU via ACPI > > > It does not look like you reserve anything. > > Pls add a link to hardware spec (in > the device implementation) so we can check > what does real hardware do. > > If this is it: > http://developer.amd.com/wordpress/media/2012/10/488821.pdf > > then the way that works seems to be by guest > programming the MMIO base. > We should do the same: patch seabios and EFI to do this. > >> Signed-off-by: David Kiarie >> --- >> hw/i386/acpi-build.c| 96 >> + >> include/hw/acpi/acpi-defs.h | 55 ++ >> 2 files changed, 151 insertions(+) >> >> diff --git a/hw/i386/acpi-build.c b/hw/i386/acpi-build.c >> index 78758e2..5a5d594 100644 >> --- a/hw/i386/acpi-build.c >> +++ b/hw/i386/acpi-build.c >> @@ -52,6 +52,7 @@ >> #include "hw/pci/pci_bus.h" >> #include "hw/pci-host/q35.h" >> #include "hw/i386/intel_iommu.h" >> +#include "hw/i386/amd_iommu.h" >> #include "hw/timer/hpet.h" >> >> #include "hw/acpi/aml-build.h" >> @@ -2424,6 +2425,88 @@ build_dmar_q35(GArray *table_data, GArray *linker) >> } >> >> static void >> +amd_iommu_acpi_set_flag(uint8_t *value, uint64_t flag) >> +{ >> +uint64_t newvalue = *value | flag; >> +*(uint64_t *)value = newvalue; >> +} >> + >> +static void >> +amd_iommu_acpi_set_feature(uint64_t *value, uint64_t feature) >> +{ >> +uint64_t newvalue = *value | feature; >> +*value = newvalue; >> +} >> + > > These wrappers aren't very useful I think. > >> +static void >> +build_amd_iommu(GArray *table_data, GArray *linker) >> +{ >> +int iommu_start = table_data->len; >> +bool iommu_ambig; >> +uint64_t host_width = (AMD_IOMMU_HOST_ADDRESS_WIDTH << 8); >> + >> +AcpiAMDIOMMUIVRS *ivrs; >> +AcpiAMDIOMMUHardwareUnit *iommu; >> + >> +/* IVRS definition */ >> +ivrs = acpi_data_push(table_data, sizeof(*ivrs)); >> +ivrs->revision = ACPI_IOMMU_IVRS_TYPE; >> +ivrs->length = (sizeof(*ivrs) + sizeof(*iommu)); >> +ivrs->v_common_info = host_width; >> + >> +AMDIOMMUState *s = (AMDIOMMUState *)object_resolve_path_type("", >> +TYPE_AMD_IOMMU_DEVICE, &iommu_ambig); >> + >> +/* IVDB definition */ >> +iommu = acpi_data_push(table_data, sizeof(*iommu)); >> +if (!iommu_ambig) { >> +iommu->type = 0x10; >> +/* IVHD flags */ >> +amd_iommu_acpi_set_flag(&iommu->flags, IVHD_HT_TUNEN); >> +amd_iommu_acpi_set_flag(&iommu->flags, IVHD_PPRSUP); >> +amd_iommu_acpi_set_flag(&iommu->flags, IVHD_IOTLBSUP); >> +amd_iommu_acpi_set_flag(&iommu->flags, IVHD_ISOC); >> +amd_iommu_acpi_set_flag(&iommu->flags, IVHD_PREFSUP); >> + >> +iommu->length = sizeof(*iommu); >> +iommu->device_id = PCI_DEVICE_ID_RD890_IOMMU; >> +iommu->capability_offset = s->capab_offset; >> +iommu->mmio_base = s->mmio.addr; >> +fprintf(stderr, "MMIO addr acpi %lx", s->mmio.addr); >> + >> +iommu->pci_segment = cpu_to_le16(0); >> +iommu->interrupt_info = cpu_to_le16(0); >> + >> +/* EFR features */ >> +amd_iommu_acpi_set_feature(&iommu->efr_register, IVHD_EFR_GTSUP); >> +amd_iommu_acpi_set_feature(&iommu->efr_register, IVHD_EFR_HATS); >> +amd_iommu_acpi_set_feature(&iommu->efr_register, IVHD_EFR_GATS); >> + >> +/* device entries */ >> +memset(iommu->dev_entries, 0, 20); >> + >> +/* Add device flags here */ >> +iommu->dev_entries[12] = 3; >> +iommu->dev_entries[16] = 4; >> +iommu->dev_entries[17] = 0xff; >> +iommu->dev_entries[18] = 0xff; >> +} >> + >> +build_header(linker, table_data, (void *)(table_data->data + >> iommu_start), >> + "IVRS", table_data->len - iommu_start, 1, NULL); >> +} >> + >> +static bool acpi_has_amd_iommu(void) >> +{ >> +bool ambiguous; >> +Object
Re: [Qemu-devel] [V3 3/4] hw/i386: ACPI table for AMD IO MMU
On Thu, Jan 14, 2016 at 6:42 PM, Jan Kiszka wrote: > On 2016-01-14 16:39, Michael S. Tsirkin wrote: >> On Thu, Jan 14, 2016 at 03:15:38PM +0300, David kiarie wrote: >>> On Thu, Jan 14, 2016 at 1:09 PM, Michael S. Tsirkin wrote: >>>> On Thu, Jan 14, 2016 at 11:04:27AM +0300, David Kiarie wrote: >>>>> Add IVRS table for AMD IO MMU. Also reverve MMIO >>>> >>>> reserve? >>> >>> Yeah, typo. >>> >>>> >>>>> region for IO MMU via ACPI >>>> >>>> >>>> It does not look like you reserve anything. >>>> >>>> Pls add a link to hardware spec (in >>>> the device implementation) so we can check >>>> what does real hardware do. >>>> >>>> If this is it: >>>> http://developer.amd.com/wordpress/media/2012/10/488821.pdf >>>> >>>> then the way that works seems to be by guest >>>> programming the MMIO base. >>>> We should do the same: patch seabios and EFI to do this. >>> >>> Yes, that's the spec. >>> >>> We thought this could be possible via ACPI (without patching BIOS ), no ? >> >> I don't see how. We should do it the way it happens on real hardware. >> > > Doesn't Seabios retrieve certain ACPI fragments from QEMU via a > pv-interface by now? > > Anyway, the question remains where this address comes from: The BIOS, > which then writes it into some hw config register and reports it in > addition via ACPI or the hardware (hard-wired). Will look at patching BIOS. > > Jan > >
Re: [Qemu-devel] [V3 3/4] hw/i386: ACPI table for AMD IO MMU
On Thu, Jan 14, 2016 at 7:19 PM, Jan Kiszka wrote: > On 2016-01-14 17:09, David kiarie wrote: >> On Thu, Jan 14, 2016 at 6:42 PM, Jan Kiszka wrote: >>> On 2016-01-14 16:39, Michael S. Tsirkin wrote: >>>> On Thu, Jan 14, 2016 at 03:15:38PM +0300, David kiarie wrote: >>>>> On Thu, Jan 14, 2016 at 1:09 PM, Michael S. Tsirkin >>>>> wrote: >>>>>> On Thu, Jan 14, 2016 at 11:04:27AM +0300, David Kiarie wrote: >>>>>>> Add IVRS table for AMD IO MMU. Also reverve MMIO >>>>>> >>>>>> reserve? >>>>> >>>>> Yeah, typo. >>>>> >>>>>> >>>>>>> region for IO MMU via ACPI >>>>>> >>>>>> >>>>>> It does not look like you reserve anything. >>>>>> >>>>>> Pls add a link to hardware spec (in >>>>>> the device implementation) so we can check >>>>>> what does real hardware do. >>>>>> >>>>>> If this is it: >>>>>> http://developer.amd.com/wordpress/media/2012/10/488821.pdf >>>>>> >>>>>> then the way that works seems to be by guest >>>>>> programming the MMIO base. >>>>>> We should do the same: patch seabios and EFI to do this. >>>>> >>>>> Yes, that's the spec. >>>>> >>>>> We thought this could be possible via ACPI (without patching BIOS ), no ? >>>> >>>> I don't see how. We should do it the way it happens on real hardware. >>>> >>> >>> Doesn't Seabios retrieve certain ACPI fragments from QEMU via a >>> pv-interface by now? >>> >>> Anyway, the question remains where this address comes from: The BIOS, >>> which then writes it into some hw config register and reports it in >>> addition via ACPI or the hardware (hard-wired). >> >> Will look at patching BIOS. > > Scanning through the spec again: As the address is not hard-wired but > configured via registers in the extended capabilities of the > corresponding PCI functions of an IOMMU (and also enabled that way!), > it's up to the BIOS to allocate an appropriate address for a system. Is there a way to modify IVRS/ACPI table from seabios because the same address is supposed to be the IVRS table otherwise I'd have to hard-code it :/ Anyway, will check. > > Jan > >
Re: [Qemu-devel] [V3 3/4] hw/i386: ACPI table for AMD IO MMU
Hi all, I think, from coreboot code, the MMIO reservation is done through an MCFG table. I can't see one in Qemu but I don't have a clue how to extend it. There's literally nothing about MCFG online neither do I have an org that's a member of pcisig. Could someone have the docs describing MCFG ? On Thu, Jan 14, 2016 at 7:54 PM, Valentine Sinitsyn wrote: > Hi all, > > I recall I saw IVRS filling code in the coreboot for one of the boards > supported. David, you may want to have a look there. > > Valentine > (from the phone) > > On Jan 14, 2016 9:29 PM, "Kevin O'Connor" wrote: >> >> On Thu, Jan 14, 2016 at 12:09:46PM +0200, Michael S. Tsirkin wrote: >> > On Thu, Jan 14, 2016 at 11:04:27AM +0300, David Kiarie wrote: >> > > Add IVRS table for AMD IO MMU. Also reverve MMIO >> > >> > reserve? >> > >> > > region for IO MMU via ACPI >> > >> > >> > It does not look like you reserve anything. >> > >> > Pls add a link to hardware spec (in >> > the device implementation) so we can check >> > what does real hardware do. >> > >> > If this is it: >> > http://developer.amd.com/wordpress/media/2012/10/488821.pdf >> > >> > then the way that works seems to be by guest >> > programming the MMIO base. >> > We should do the same: patch seabios and EFI to do this. >> >> A similar question - how does a typical factory BIOS select which >> address to set as the MMIO base? Is it generally hard-coded or is it >> allocated from a range in some way? >> >> -Kevin
[Qemu-devel] [V4 0/4] AMD IO MMU
David Kiarie (4): hw/i386: Introduce AMD IO MMU hw/core: Add AMD IO MMU to machine properties hw/i386: ACPI table for AMD IO MMU hw/pci-host: Emulate AMD IO MMU hw/core/machine.c | 17 +- hw/i386/Makefile.objs |1 + hw/i386/acpi-build.c | 70 ++ hw/i386/amd_iommu.c | 1409 + hw/i386/amd_iommu.h | 399 hw/pci-host/piix.c| 11 + hw/pci-host/q35.c | 14 +- include/hw/acpi/acpi-defs.h | 55 ++ include/hw/boards.h |3 +- include/hw/i386/intel_iommu.h |1 + include/hw/pci/pci.h |2 + qemu-options.hx |6 +- util/qemu-config.c|4 +- vl.c |8 + 14 files changed, 1984 insertions(+), 16 deletions(-) create mode 100644 hw/i386/amd_iommu.c create mode 100644 hw/i386/amd_iommu.h Hi all, V4 of IO MMU patches. Changes since V3 -Fixed Marcel's comments -byte swapping in ACPI code fixed As for IO MMU MMIO region: This is the code that sets up the IO MMU base address in coreboot. It seems to be reading something from the BUS config region which as per the comment should have a value written by BIOS. case CB_AmdSetMidPostConfig: nbConfigPtr->pNbConfig->IoApicBaseAddress = IO_APIC_ADDR; #ifndef IOMMU_SUPPORT_DISABLE //TODO enable iommu /* SBIOS must alloc 16K memory for IOMMU MMIO */ UINT32 MmcfgBarAddress; //using default IOmmuBaseAddress LibNbPciRead(nbConfigPtr->NbPciAddress.AddressValue | 0x1C, AccessWidth32, &MmcfgBarAddress, nbConfigPtr); MmcfgBarAddress &= ~0xf; if (MmcfgBarAddress != 0) { nbConfigPtr->IommuBaseAddress = MmcfgBarAddress; } nbConfigPtr->IommuBaseAddress = 0; //disable iommu #endif I have a feeling that this is getting overly and unnecessary complex - AMD have their own BIOS which they, only know what it does and we have ours( which of course, we know how it behaves). If we choose a static address and assign that to IO MMU mmio we could hypothetically have two problems. -SeaBIOS allocating BAR from the same region. -Someone selecting the region for other devices such as HPET. The first problem can be solved as we know from what addresses seaBIOS allocats BARs while as for the second they should know better. I have therefore selected an unused IO region just next IOAPIC and HPET region and mapped 16K for IO MMU mmio. David. -- 2.1.4
[Qemu-devel] [V4 2/4] hw/core: Add AMD IO MMU to machine properties
Add IO MMU as a string to machine properties which is used to control whether and the type of IO MMU to emulate Signed-off-by: David Kiarie --- hw/core/machine.c | 17 + include/hw/boards.h | 3 ++- include/hw/i386/intel_iommu.h | 1 + qemu-options.hx | 6 +++--- util/qemu-config.c| 4 ++-- vl.c | 8 6 files changed, 25 insertions(+), 14 deletions(-) diff --git a/hw/core/machine.c b/hw/core/machine.c index c46ddc7..cb309aa 100644 --- a/hw/core/machine.c +++ b/hw/core/machine.c @@ -283,18 +283,19 @@ static void machine_set_firmware(Object *obj, const char *value, Error **errp) ms->firmware = g_strdup(value); } -static bool machine_get_iommu(Object *obj, Error **errp) +static char *machine_get_iommu(Object *obj, Error **errp) { MachineState *ms = MACHINE(obj); -return ms->iommu; +return g_strdup(ms->iommu); } -static void machine_set_iommu(Object *obj, bool value, Error **errp) +static void machine_set_iommu(Object *obj, const char *value, Error **errp) { MachineState *ms = MACHINE(obj); -ms->iommu = value; +g_free(ms->iommu); +ms->iommu = g_strdup(value); } static void machine_set_suppress_vmdesc(Object *obj, bool value, Error **errp) @@ -454,11 +455,10 @@ static void machine_initfn(Object *obj) object_property_set_description(obj, "firmware", "Firmware image", NULL); -object_property_add_bool(obj, "iommu", - machine_get_iommu, - machine_set_iommu, NULL); +object_property_add_str(obj, "iommu", +machine_get_iommu, machine_set_iommu, NULL); object_property_set_description(obj, "iommu", -"Set on/off to enable/disable Intel IOMMU (VT-d)", +"IOMMU list", NULL); object_property_add_bool(obj, "suppress-vmdesc", machine_get_suppress_vmdesc, @@ -484,6 +484,7 @@ static void machine_finalize(Object *obj) g_free(ms->dumpdtb); g_free(ms->dt_compatible); g_free(ms->firmware); +g_free(ms->iommu); } bool machine_usb(MachineState *machine) diff --git a/include/hw/boards.h b/include/hw/boards.h index 0f30959..b119245 100644 --- a/include/hw/boards.h +++ b/include/hw/boards.h @@ -36,6 +36,7 @@ bool machine_usb(MachineState *machine); bool machine_kernel_irqchip_allowed(MachineState *machine); bool machine_kernel_irqchip_required(MachineState *machine); bool machine_kernel_irqchip_split(MachineState *machine); +bool machine_amd_iommu(MachineState *machine); int machine_kvm_shadow_mem(MachineState *machine); int machine_phandle_start(MachineState *machine); bool machine_dump_guest_core(MachineState *machine); @@ -126,7 +127,7 @@ struct MachineState { bool usb_disabled; bool igd_gfx_passthru; char *firmware; -bool iommu; +char *iommu; bool suppress_vmdesc; ram_addr_t ram_size; diff --git a/include/hw/i386/intel_iommu.h b/include/hw/i386/intel_iommu.h index 5dbadb7..0b32bd6 100644 --- a/include/hw/i386/intel_iommu.h +++ b/include/hw/i386/intel_iommu.h @@ -27,6 +27,7 @@ #define TYPE_INTEL_IOMMU_DEVICE "intel-iommu" #define INTEL_IOMMU_DEVICE(obj) \ OBJECT_CHECK(IntelIOMMUState, (obj), TYPE_INTEL_IOMMU_DEVICE) +#define INTEL_IOMMU_STR "intel" /* DMAR Hardware Unit Definition address (IOMMU unit) */ #define Q35_HOST_BRIDGE_IOMMU_ADDR 0xfed9ULL diff --git a/qemu-options.hx b/qemu-options.hx index 215d00d..ac327c8 100644 --- a/qemu-options.hx +++ b/qemu-options.hx @@ -38,7 +38,7 @@ DEF("machine", HAS_ARG, QEMU_OPTION_machine, \ "kvm_shadow_mem=size of KVM shadow MMU\n" "dump-guest-core=on|off include guest memory in a core dump (default=on)\n" "mem-merge=on|off controls memory merge support (default: on)\n" -"iommu=on|off controls emulated Intel IOMMU (VT-d) support (default=off)\n" +"iommu=amd|intel enables and selects the emulated IO MMU (default: off)\n" "igd-passthru=on|off controls IGD GFX passthrough support (default=off)\n" "aes-key-wrap=on|off controls support for AES key wrapping (default=on)\n" "dea-key-wrap=on|off controls support for DEA key wrapping (default=on)\n" @@ -72,8 +72,8 @@ Include guest memory in a core dump. The default is on. Enables or disables memory merge support. This feature, when supported by the host, de-duplicates identical memory pages among VMs instances (ena
[Qemu-devel] [V4 3/4] hw/i386: ACPI table for AMD IO MMU
Add IVRS table for AMD IO MMU. Signed-off-by: David Kiarie --- hw/i386/acpi-build.c| 70 + include/hw/acpi/acpi-defs.h | 55 +++ 2 files changed, 125 insertions(+) diff --git a/hw/i386/acpi-build.c b/hw/i386/acpi-build.c index 78758e2..5c0d6b7 100644 --- a/hw/i386/acpi-build.c +++ b/hw/i386/acpi-build.c @@ -52,6 +52,7 @@ #include "hw/pci/pci_bus.h" #include "hw/pci-host/q35.h" #include "hw/i386/intel_iommu.h" +#include "hw/i386/amd_iommu.h" #include "hw/timer/hpet.h" #include "hw/acpi/aml-build.h" @@ -2424,6 +2425,70 @@ build_dmar_q35(GArray *table_data, GArray *linker) } static void +build_amd_iommu(GArray *table_data, GArray *linker) +{ +int iommu_start = table_data->len; +bool iommu_ambig; + +AcpiAMDIOMMUIVRS *ivrs; +AcpiAMDIOMMUHardwareUnit *iommu; + +/* IVRS definition */ +ivrs = acpi_data_push(table_data, sizeof(*ivrs)); +ivrs->revision = cpu_to_le16(ACPI_IOMMU_IVRS_TYPE); +ivrs->length = cpu_to_le16((sizeof(*ivrs) + sizeof(*iommu))); +ivrs->v_common_info = cpu_to_le64(AMD_IOMMU_HOST_ADDRESS_WIDTH << 8); + +AMDIOMMUState *s = (AMDIOMMUState *)object_resolve_path_type("", +TYPE_AMD_IOMMU_DEVICE, &iommu_ambig); + +/* IVDB definition */ +iommu = acpi_data_push(table_data, sizeof(*iommu)); +if (!iommu_ambig) { +iommu->type = cpu_to_le16(0x10); +/* IVHD flags */ +iommu->flags = cpu_to_le16(iommu->flags); +iommu->flags = cpu_to_le16(IVHD_HT_TUNEN | IVHD_PPRSUP | IVHD_IOTLBSUP + | IVHD_PREFSUP); +iommu->length = cpu_to_le16(sizeof(*iommu)); +iommu->device_id = cpu_to_le16(PCI_DEVICE_ID_RD890_IOMMU); +iommu->capability_offset = cpu_to_le16(s->capab_offset); +iommu->mmio_base = cpu_to_le64(s->mmio.addr); +iommu->pci_segment = 0; +iommu->interrupt_info = 0; +/* EFR features */ +iommu->efr_register = cpu_to_le64(IVHD_EFR_GTSUP | IVHD_EFR_HATS + | IVHD_EFR_GATS); +iommu->efr_register = cpu_to_le64(iommu->efr_register); +/* device entries */ +memset(iommu->dev_entries, 0, 20); +/* Add device flags here + * create entries for devices to be treated specially by IO MMU, + * currently we report all devices to IO MMU with no special flags + * DTE settings made here apply to all devices + * Refer to AMD IOMMU spec Table 97 + */ +iommu->dev_entries[12] = 3; +iommu->dev_entries[16] = 4; +iommu->dev_entries[17] = 0xff; +iommu->dev_entries[18] = 0xff; +} + +build_header(linker, table_data, (void *)(table_data->data + iommu_start), + "IVRS", table_data->len - iommu_start, 1, NULL); +} + +static bool acpi_has_amd_iommu(void) +{ +bool ambiguous; +Object *amd_iommu; + +amd_iommu = object_resolve_path_type("", TYPE_AMD_IOMMU_DEVICE, + &ambiguous); +return amd_iommu && !ambiguous; +} + +static void build_dsdt(GArray *table_data, GArray *linker, AcpiPmInfo *pm, AcpiMiscInfo *misc) { @@ -2691,6 +2756,11 @@ void acpi_build(PcGuestInfo *guest_info, AcpiBuildTables *tables) build_dmar_q35(tables_blob, tables->linker); } +if (acpi_has_amd_iommu() && !acpi_has_iommu()) { +acpi_add_table(table_offsets, tables_blob); +build_amd_iommu(tables_blob, tables->linker); +} + if (acpi_has_nvdimm()) { nvdimm_build_acpi(table_offsets, tables_blob, tables->linker); } diff --git a/include/hw/acpi/acpi-defs.h b/include/hw/acpi/acpi-defs.h index c7a03d4..a161358 100644 --- a/include/hw/acpi/acpi-defs.h +++ b/include/hw/acpi/acpi-defs.h @@ -570,4 +570,59 @@ typedef struct AcpiDmarHardwareUnit AcpiDmarHardwareUnit; /* Masks for Flags field above */ #define ACPI_DMAR_INCLUDE_PCI_ALL 1 +/* IVRS constants */ +#define ACPI_IOMMU_HARDWAREUNIT_TYPE 0x10 +#define ACPI_IOMMU_IVRS_TYPE 0x1 +#define AMD_IOMMU_HOST_ADDRESS_WIDTH 39UL + +/* AMD IOMMU IVRS table */ +struct AcpiAMDIOMMUIVRS { +ACPI_TABLE_HEADER_DEF +uint32_t v_common_info; /* common virtualization information */ +uint64_t reserved; /* reserved */ +} QEMU_PACKED; +typedef struct AcpiAMDIOMMUIVRS AcpiAMDIOMMUIVRS; + +/* flags in the IVHD headers */ +#define IVHD_HT_TUNEN(1UL << 0) +#define IVHD_PASS_PW (1UL << 1) +#define IVHD_RESPASS_PW (1UL << 2) +#define IVHD_ISOC(1UL << 3) +#define IVHD_IOTLBSUP(1UL << 4) +#define IVHD_COHERENT(1UL << 5) +#define IVHD_PREFSUP (1UL << 6) +#define IVHD_PPRSUP (1UL
[Qemu-devel] [V4 1/4] hw/i386: Introduce AMD IO MMU
Add AMD IO MMU emulation to Qemu in addition to Intel IO MMU. The IO MMU does basic translation, error checking and has a minimal IOTLB implementation. Signed-off-by: David Kiarie --- hw/i386/Makefile.objs |1 + hw/i386/amd_iommu.c | 1409 + hw/i386/amd_iommu.h | 399 ++ include/hw/pci/pci.h |2 + 4 files changed, 1811 insertions(+) create mode 100644 hw/i386/amd_iommu.c create mode 100644 hw/i386/amd_iommu.h diff --git a/hw/i386/Makefile.objs b/hw/i386/Makefile.objs index b52d5b8..2f1a265 100644 --- a/hw/i386/Makefile.objs +++ b/hw/i386/Makefile.objs @@ -3,6 +3,7 @@ obj-y += multiboot.o obj-y += pc.o pc_piix.o pc_q35.o obj-y += pc_sysfw.o obj-y += intel_iommu.o +obj-y += amd_iommu.o obj-$(CONFIG_XEN) += ../xenpv/ xen/ obj-y += kvmvapic.o diff --git a/hw/i386/amd_iommu.c b/hw/i386/amd_iommu.c new file mode 100644 index 000..20111fe --- /dev/null +++ b/hw/i386/amd_iommu.c @@ -0,0 +1,1409 @@ +/* + * QEMU emulation of AMD IOMMU (AMD-Vi) + * + * Copyright (C) 2011 Eduard - Gabriel Munteanu + * Copyright (C) 2015 David Kiarie, + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License along + * with this program; if not, see <http://www.gnu.org/licenses/>. + * + * Cache implementation inspired by hw/i386/intel_iommu.c + * + */ +#include "hw/i386/amd_iommu.h" + +//#define DEBUG_AMD_IOMMU +#ifdef DEBUG_AMD_IOMMU +enum { +DEBUG_GENERAL, DEBUG_CAPAB, DEBUG_MMIO, DEBUG_ELOG, +DEBUG_CACHE, DEBUG_COMMAND, DEBUG_MMU +}; + +#define IOMMU_DBGBIT(x) (1 << DEBUG_##x) +static int iommu_dbgflags = IOMMU_DBGBIT(MMIO); + +#define IOMMU_DPRINTF(what, fmt, ...) do { \ +if (iommu_dbgflags & IOMMU_DBGBIT(what)) { \ +fprintf(stderr, "(amd-iommu)%s: " fmt "\n", __func__, \ +## __VA_ARGS__); } \ +} while (0) +#else +#define IOMMU_DPRINTF(what, fmt, ...) do {} while (0) +#endif + +/* configure MMIO registers at startup/reset */ +static void amd_iommu_set_quad(AMDIOMMUState *s, hwaddr addr, uint64_t val, + uint64_t romask, uint64_t w1cmask) +{ +stq_le_p(&s->mmior[addr], val); +stq_le_p(&s->romask[addr], romask); +stq_le_p(&s->w1cmask[addr], w1cmask); +} + +static uint16_t amd_iommu_readw(AMDIOMMUState *s, hwaddr addr) +{ +return lduw_le_p(&s->mmior[addr]); +} + +static uint32_t amd_iommu_readl(AMDIOMMUState *s, hwaddr addr) +{ +return ldl_le_p(&s->mmior[addr]); +} + +static uint64_t amd_iommu_readq(AMDIOMMUState *s, hwaddr addr) +{ +return ldq_le_p(&s->mmior[addr]); +} + +/* internal write */ +static void amd_iommu_writeq_raw(AMDIOMMUState *s, uint64_t val, hwaddr addr) +{ +stq_le_p(&s->mmior[addr], val); +} + +/* external write */ +static void amd_iommu_writew(AMDIOMMUState *s, hwaddr addr, uint16_t val) +{ +uint16_t romask = lduw_le_p(&s->romask[addr]); +uint16_t w1cmask = lduw_le_p(&s->w1cmask[addr]); +uint16_t oldval = lduw_le_p(&s->mmior[addr]); +stw_le_p(&s->mmior[addr], (val & ~(val & w1cmask)) | (romask & oldval)); +} + +static void amd_iommu_writel(AMDIOMMUState *s, hwaddr addr, uint32_t val) +{ +uint32_t romask = ldl_le_p(&s->romask[addr]); +uint32_t w1cmask = ldl_le_p(&s->w1cmask[addr]); +uint32_t oldval = ldl_le_p(&s->mmior[addr]); +stl_le_p(&s->mmior[addr], (val & ~(val & w1cmask)) | (romask & oldval)); +} + +static void amd_iommu_writeq(AMDIOMMUState *s, hwaddr addr, uint64_t val) +{ +uint64_t romask = ldq_le_p(&s->romask[addr]); +uint64_t w1cmask = ldq_le_p(&s->w1cmask[addr]); +uint32_t oldval = ldq_le_p(&s->mmior[addr]); +stq_le_p(&s->mmior[addr], (val & ~(val & w1cmask)) | (romask & oldval)); +} + +static void amd_iommu_log_event(AMDIOMMUState *s, uint16_t *evt) +{ +/* event logging not enabled */ +if (!s->evtlog_enabled || *(uint64_t *)&s->mmior[MMIO_STATUS] + | MMIO_STATUS_EVT_OVF) { +return; +} + +/* event log buffer full */ +if (s->evtlog_tail >= s->evtlog_len) { +*(uint64_t *)&s->mmior[MMIO_STATUS] |= MMIO_STATUS_EVT_OVF; +/* generate interrupt */ +} + +if (dma_memory_write(&address_space_memory, s->evtlog_len + s->evtlog_tail, +
[Qemu-devel] [V4 4/4] hw/pci-host: Emulate AMD IO MMU
Support AMD IO MMU emulation in q35 and piix chipsets Signed-off-by: David Kiarie --- hw/pci-host/piix.c | 11 +++ hw/pci-host/q35.c | 14 -- 2 files changed, 23 insertions(+), 2 deletions(-) diff --git a/hw/pci-host/piix.c b/hw/pci-host/piix.c index b0d7e31..3ba245d 100644 --- a/hw/pci-host/piix.c +++ b/hw/pci-host/piix.c @@ -35,6 +35,7 @@ #include "hw/i386/ioapic.h" #include "qapi/visitor.h" #include "qemu/error-report.h" +#include "hw/i386/amd_iommu.h" /* * I440FX chipset data sheet. @@ -297,6 +298,16 @@ static void i440fx_pcihost_realize(DeviceState *dev, Error **errp) sysbus_add_io(sbd, 0xcfc, &s->data_mem); sysbus_init_ioports(sbd, 0xcfc, 4); + +/* AMD IOMMU (AMD-Vi) */ +if (g_strcmp0(object_property_get_str(qdev_get_machine(), "iommu", NULL), + "amd") == 0) { +AMDIOMMUState *iommu_state; +PCIDevice *iommu; +iommu = pci_create_simple(s->bus, 0x20, TYPE_AMD_IOMMU_DEVICE); +iommu_state = AMD_IOMMU_DEVICE(iommu); +pci_setup_iommu(s->bus, bridge_host_amd_iommu, iommu_state); +} } static void i440fx_realize(PCIDevice *dev, Error **errp) diff --git a/hw/pci-host/q35.c b/hw/pci-host/q35.c index 1fb4707..0c60e3c 100644 --- a/hw/pci-host/q35.c +++ b/hw/pci-host/q35.c @@ -30,6 +30,7 @@ #include "hw/hw.h" #include "hw/pci-host/q35.h" #include "qapi/visitor.h" +#include "hw/i386/amd_iommu.h" / * Q35 host @@ -505,9 +506,18 @@ static void mch_realize(PCIDevice *d, Error **errp) mch->pci_address_space, &mch->pam_regions[i+1], PAM_EXPAN_BASE + i * PAM_EXPAN_SIZE, PAM_EXPAN_SIZE); } -/* Intel IOMMU (VT-d) */ -if (object_property_get_bool(qdev_get_machine(), "iommu", NULL)) { + +if (g_strcmp0(MACHINE(qdev_get_machine())->iommu, INTEL_IOMMU_STR) == 0) { +/* Intel IOMMU (VT-d) */ mch_init_dmar(mch); +} else if (g_strcmp0(MACHINE(qdev_get_machine())->iommu, AMD_IOMMU_STR) + == 0) { +AMDIOMMUState *iommu_state; +PCIDevice *iommu; +PCIBus *bus = PCI_BUS(qdev_get_parent_bus(DEVICE(mch))); +iommu = pci_create_simple(bus, 0x20, TYPE_AMD_IOMMU_DEVICE); +iommu_state = AMD_IOMMU_DEVICE(iommu); +pci_setup_iommu(bus, bridge_host_amd_iommu, iommu_state); } } -- 2.1.4
Re: [Qemu-devel] [V3 4/4] hw/pci-host: Emulate AMD IO MMU
On 1/17/2016 4:57 PM, Marcel Apfelbaum wrote: On 01/14/2016 10:04 AM, David Kiarie wrote: Support AMD IO MMU emulation in q35 and piix chipsets Signed-off-by: David Kiarie --- hw/pci-host/piix.c | 11 +++ hw/pci-host/q35.c | 16 ++-- 2 files changed, 25 insertions(+), 2 deletions(-) diff --git a/hw/pci-host/piix.c b/hw/pci-host/piix.c index 924f0fa..19e2930 100644 --- a/hw/pci-host/piix.c +++ b/hw/pci-host/piix.c @@ -35,6 +35,7 @@ #include "hw/i386/ioapic.h" #include "qapi/visitor.h" #include "qemu/error-report.h" +#include "hw/i386/amd_iommu.h" /* * I440FX chipset data sheet. @@ -297,6 +298,16 @@ static void i440fx_pcihost_realize(DeviceState *dev, Error **errp) sysbus_add_io(sbd, 0xcfc, &s->data_mem); sysbus_init_ioports(sbd, 0xcfc, 4); + +/* AMD IOMMU (AMD-Vi) */ +if (g_strcmp0(object_property_get_str(qdev_get_machine(), "iommu", NULL), + "amd") == 0) { You can use the Machine wrapper and it will look slightly better (at least you get rid of the literal): MACHINE(qdev_get_machine())->iommu <=> object_property_get_str(qdev_get_machine(), "iommu", NULL) By the way, does i440fx host work with AMD iommu? Forgot,... Yeah, I checked this to confirm it works though looking at it, it seems like i440fx doesn't support PCIE(MSI) so interrupt related things might not work here but we're not yet there. +AMDIOMMUState *iommu_state; +PCIDevice *iommu; +iommu = pci_create_simple(s->bus, 0x20, TYPE_AMD_IOMMU_DEVICE); +iommu_state = AMD_IOMMU_DEVICE(iommu); +pci_setup_iommu(s->bus, bridge_host_amd_iommu, iommu_state); +} } static void i440fx_realize(PCIDevice *dev, Error **errp) diff --git a/hw/pci-host/q35.c b/hw/pci-host/q35.c index 1fb4707..dd4c822 100644 --- a/hw/pci-host/q35.c +++ b/hw/pci-host/q35.c @@ -30,6 +30,7 @@ #include "hw/hw.h" #include "hw/pci-host/q35.h" #include "qapi/visitor.h" +#include "hw/i386/amd_iommu.h" / * Q35 host @@ -505,10 +506,21 @@ static void mch_realize(PCIDevice *d, Error **errp) mch->pci_address_space, &mch->pam_regions[i+1], PAM_EXPAN_BASE + i * PAM_EXPAN_SIZE, PAM_EXPAN_SIZE); } -/* Intel IOMMU (VT-d) */ -if (object_property_get_bool(qdev_get_machine(), "iommu", NULL)) { + +char *iommu = object_property_get_str(qdev_get_machine(), "iommu", NULL); + +if (g_strcmp0(iommu, "intel") == 0) { +/* Intel IOMMU (VT-d) */ mch_init_dmar(mch); +} else if (g_strcmp0(iommu, "amd") == 0) { Last thing, maybe you can define "intel" and "amd" literals in one please, then use it them as you see fit. Thanks, Marcel +AMDIOMMUState *iommu_state; +PCIDevice *iommu; +PCIBus *bus = PCI_BUS(qdev_get_parent_bus(DEVICE(mch))); +iommu = pci_create_simple(bus, 0x20, TYPE_AMD_IOMMU_DEVICE); +iommu_state = AMD_IOMMU_DEVICE(iommu); +pci_setup_iommu(bus, bridge_host_amd_iommu, iommu_state); } +g_free(iommu); } uint64_t mch_mcfg_base(void)
Re: [Qemu-devel] [V4 2/4] hw/core: Add AMD IO MMU to machine properties
On 1/18/2016 7:21 PM, Marcel Apfelbaum wrote: On 01/18/2016 05:25 PM, David Kiarie wrote: Add IO MMU as a string to machine properties which is used to control whether and the type of IO MMU to emulate Signed-off-by: David Kiarie --- hw/core/machine.c | 17 + include/hw/boards.h | 3 ++- include/hw/i386/intel_iommu.h | 1 + qemu-options.hx | 6 +++--- util/qemu-config.c| 4 ++-- vl.c | 8 6 files changed, 25 insertions(+), 14 deletions(-) diff --git a/hw/core/machine.c b/hw/core/machine.c index c46ddc7..cb309aa 100644 --- a/hw/core/machine.c +++ b/hw/core/machine.c @@ -283,18 +283,19 @@ static void machine_set_firmware(Object *obj, const char *value, Error **errp) ms->firmware = g_strdup(value); } -static bool machine_get_iommu(Object *obj, Error **errp) +static char *machine_get_iommu(Object *obj, Error **errp) { MachineState *ms = MACHINE(obj); -return ms->iommu; +return g_strdup(ms->iommu); } -static void machine_set_iommu(Object *obj, bool value, Error **errp) +static void machine_set_iommu(Object *obj, const char *value, Error **errp) { MachineState *ms = MACHINE(obj); -ms->iommu = value; +g_free(ms->iommu); +ms->iommu = g_strdup(value); } static void machine_set_suppress_vmdesc(Object *obj, bool value, Error **errp) @@ -454,11 +455,10 @@ static void machine_initfn(Object *obj) object_property_set_description(obj, "firmware", "Firmware image", NULL); -object_property_add_bool(obj, "iommu", - machine_get_iommu, - machine_set_iommu, NULL); +object_property_add_str(obj, "iommu", +machine_get_iommu, machine_set_iommu, NULL); object_property_set_description(obj, "iommu", -"Set on/off to enable/disable Intel IOMMU (VT-d)", +"IOMMU list", NULL); object_property_add_bool(obj, "suppress-vmdesc", machine_get_suppress_vmdesc, @@ -484,6 +484,7 @@ static void machine_finalize(Object *obj) g_free(ms->dumpdtb); g_free(ms->dt_compatible); g_free(ms->firmware); +g_free(ms->iommu); } bool machine_usb(MachineState *machine) diff --git a/include/hw/boards.h b/include/hw/boards.h index 0f30959..b119245 100644 --- a/include/hw/boards.h +++ b/include/hw/boards.h @@ -36,6 +36,7 @@ bool machine_usb(MachineState *machine); bool machine_kernel_irqchip_allowed(MachineState *machine); bool machine_kernel_irqchip_required(MachineState *machine); bool machine_kernel_irqchip_split(MachineState *machine); +bool machine_amd_iommu(MachineState *machine); int machine_kvm_shadow_mem(MachineState *machine); int machine_phandle_start(MachineState *machine); bool machine_dump_guest_core(MachineState *machine); @@ -126,7 +127,7 @@ struct MachineState { bool usb_disabled; bool igd_gfx_passthru; char *firmware; -bool iommu; +char *iommu; bool suppress_vmdesc; ram_addr_t ram_size; diff --git a/include/hw/i386/intel_iommu.h b/include/hw/i386/intel_iommu.h index 5dbadb7..0b32bd6 100644 --- a/include/hw/i386/intel_iommu.h +++ b/include/hw/i386/intel_iommu.h @@ -27,6 +27,7 @@ #define TYPE_INTEL_IOMMU_DEVICE "intel-iommu" #define INTEL_IOMMU_DEVICE(obj) \ OBJECT_CHECK(IntelIOMMUState, (obj), TYPE_INTEL_IOMMU_DEVICE) +#define INTEL_IOMMU_STR "intel" /* DMAR Hardware Unit Definition address (IOMMU unit) */ #define Q35_HOST_BRIDGE_IOMMU_ADDR 0xfed9ULL diff --git a/qemu-options.hx b/qemu-options.hx index 215d00d..ac327c8 100644 --- a/qemu-options.hx +++ b/qemu-options.hx @@ -38,7 +38,7 @@ DEF("machine", HAS_ARG, QEMU_OPTION_machine, \ "kvm_shadow_mem=size of KVM shadow MMU\n" "dump-guest-core=on|off include guest memory in a core dump (default=on)\n" "mem-merge=on|off controls memory merge support (default: on)\n" -"iommu=on|off controls emulated Intel IOMMU (VT-d) support (default=off)\n" +"iommu=amd|intel enables and selects the emulated IO MMU (default: off)\n" "igd-passthru=on|off controls IGD GFX passthrough support (default=off)\n" "aes-key-wrap=on|off controls support for AES key wrapping (default=on)\n" "dea-key-wrap=on|off controls support for DEA key wrapping (default=on)\n" @@ -72,8 +72,8 @@ Include guest memory in a core dump. The default is on.
Re: [Qemu-devel] [V4 2/4] hw/core: Add AMD IO MMU to machine properties
On 1/18/2016 8:27 PM, Marcel Apfelbaum wrote: On 01/18/2016 06:48 PM, David Kiarie wrote: On 1/18/2016 7:21 PM, Marcel Apfelbaum wrote: On 01/18/2016 05:25 PM, David Kiarie wrote: Add IO MMU as a string to machine properties which is used to control whether and the type of IO MMU to emulate Signed-off-by: David Kiarie --- hw/core/machine.c | 17 + include/hw/boards.h | 3 ++- include/hw/i386/intel_iommu.h | 1 + qemu-options.hx | 6 +++--- util/qemu-config.c| 4 ++-- vl.c | 8 6 files changed, 25 insertions(+), 14 deletions(-) diff --git a/hw/core/machine.c b/hw/core/machine.c index c46ddc7..cb309aa 100644 --- a/hw/core/machine.c +++ b/hw/core/machine.c @@ -283,18 +283,19 @@ static void machine_set_firmware(Object *obj, const char *value, Error **errp) ms->firmware = g_strdup(value); } -static bool machine_get_iommu(Object *obj, Error **errp) +static char *machine_get_iommu(Object *obj, Error **errp) { MachineState *ms = MACHINE(obj); -return ms->iommu; +return g_strdup(ms->iommu); } -static void machine_set_iommu(Object *obj, bool value, Error **errp) +static void machine_set_iommu(Object *obj, const char *value, Error **errp) { MachineState *ms = MACHINE(obj); -ms->iommu = value; +g_free(ms->iommu); +ms->iommu = g_strdup(value); } static void machine_set_suppress_vmdesc(Object *obj, bool value, Error **errp) @@ -454,11 +455,10 @@ static void machine_initfn(Object *obj) object_property_set_description(obj, "firmware", "Firmware image", NULL); -object_property_add_bool(obj, "iommu", - machine_get_iommu, - machine_set_iommu, NULL); +object_property_add_str(obj, "iommu", +machine_get_iommu, machine_set_iommu, NULL); object_property_set_description(obj, "iommu", -"Set on/off to enable/disable Intel IOMMU (VT-d)", +"IOMMU list", NULL); object_property_add_bool(obj, "suppress-vmdesc", machine_get_suppress_vmdesc, @@ -484,6 +484,7 @@ static void machine_finalize(Object *obj) g_free(ms->dumpdtb); g_free(ms->dt_compatible); g_free(ms->firmware); +g_free(ms->iommu); } bool machine_usb(MachineState *machine) diff --git a/include/hw/boards.h b/include/hw/boards.h index 0f30959..b119245 100644 --- a/include/hw/boards.h +++ b/include/hw/boards.h @@ -36,6 +36,7 @@ bool machine_usb(MachineState *machine); bool machine_kernel_irqchip_allowed(MachineState *machine); bool machine_kernel_irqchip_required(MachineState *machine); bool machine_kernel_irqchip_split(MachineState *machine); +bool machine_amd_iommu(MachineState *machine); int machine_kvm_shadow_mem(MachineState *machine); int machine_phandle_start(MachineState *machine); bool machine_dump_guest_core(MachineState *machine); @@ -126,7 +127,7 @@ struct MachineState { bool usb_disabled; bool igd_gfx_passthru; char *firmware; -bool iommu; +char *iommu; bool suppress_vmdesc; ram_addr_t ram_size; diff --git a/include/hw/i386/intel_iommu.h b/include/hw/i386/intel_iommu.h index 5dbadb7..0b32bd6 100644 --- a/include/hw/i386/intel_iommu.h +++ b/include/hw/i386/intel_iommu.h @@ -27,6 +27,7 @@ #define TYPE_INTEL_IOMMU_DEVICE "intel-iommu" #define INTEL_IOMMU_DEVICE(obj) \ OBJECT_CHECK(IntelIOMMUState, (obj), TYPE_INTEL_IOMMU_DEVICE) +#define INTEL_IOMMU_STR "intel" /* DMAR Hardware Unit Definition address (IOMMU unit) */ #define Q35_HOST_BRIDGE_IOMMU_ADDR 0xfed9ULL diff --git a/qemu-options.hx b/qemu-options.hx index 215d00d..ac327c8 100644 --- a/qemu-options.hx +++ b/qemu-options.hx @@ -38,7 +38,7 @@ DEF("machine", HAS_ARG, QEMU_OPTION_machine, \ "kvm_shadow_mem=size of KVM shadow MMU\n" "dump-guest-core=on|off include guest memory in a core dump (default=on)\n" "mem-merge=on|off controls memory merge support (default: on)\n" -"iommu=on|off controls emulated Intel IOMMU (VT-d) support (default=off)\n" +"iommu=amd|intel enables and selects the emulated IO MMU (default: off)\n" "igd-passthru=on|off controls IGD GFX passthrough support (default=off)\n" "aes-key-wrap=on|off controls support for AES key wrapping (default=on)\n" "dea-key-wrap=on|off controls support for DEA key wrapping (d
[Qemu-devel] [V6 0/4] AMD IOMMU
Hello there, Repost, AMD IOMMU patches version 6. Changes since version 5 -Fixed macro formating issues -changed occurences of IO MMU to IOMMU for consistency -Fixed capability registers duplication -Rebased to current master David Kiarie (4): hw/i386: Introduce AMD IOMMU hw/core: Add AMD IOMMU to machine properties hw/i386: ACPI table for AMD IOMMU hw/pci-host: Emulate AMD IOMMU hw/core/machine.c | 28 +- hw/i386/Makefile.objs |1 + hw/i386/acpi-build.c | 208 +- hw/i386/amd_iommu.c | 1432 + hw/i386/amd_iommu.h | 395 hw/pci-host/piix.c|1 + hw/pci-host/q35.c | 14 +- include/hw/acpi/acpi-defs.h | 55 ++ include/hw/boards.h |3 +- include/hw/i386/intel_iommu.h |1 + include/hw/pci/pci.h |2 + qemu-options.hx |6 +- util/qemu-config.c|4 +- 13 files changed, 2123 insertions(+), 27 deletions(-) create mode 100644 hw/i386/amd_iommu.c create mode 100644 hw/i386/amd_iommu.h -- 2.1.4
[Qemu-devel] [V6 2/4] hw/core: Add AMD IOMMU to machine properties
Add IOMMU as a string to machine properties which is used to control whether and the type of IOMMU to emulate Signed-off-by: David Kiarie --- hw/core/machine.c | 28 include/hw/boards.h | 3 ++- qemu-options.hx | 6 +++--- util/qemu-config.c | 4 ++-- 4 files changed, 27 insertions(+), 14 deletions(-) diff --git a/hw/core/machine.c b/hw/core/machine.c index 6d1a0d8..001ace9 100644 --- a/hw/core/machine.c +++ b/hw/core/machine.c @@ -14,6 +14,8 @@ #include "hw/boards.h" #include "qapi-visit.h" #include "qapi/visitor.h" +#include "hw/i386/amd_iommu.h" +#include "hw/i386/intel_iommu.h" #include "hw/sysbus.h" #include "sysemu/sysemu.h" #include "qemu/error-report.h" @@ -284,18 +286,28 @@ static void machine_set_firmware(Object *obj, const char *value, Error **errp) ms->firmware = g_strdup(value); } -static bool machine_get_iommu(Object *obj, Error **errp) +static char *machine_get_iommu(Object *obj, Error **errp) { MachineState *ms = MACHINE(obj); -return ms->iommu; +return g_strdup(ms->iommu); } -static void machine_set_iommu(Object *obj, bool value, Error **errp) +static void machine_set_iommu(Object *obj, const char *value, Error **errp) { MachineState *ms = MACHINE(obj); +Error *err = NULL; + +g_free(ms->iommu); + +if (g_strcmp0(value, AMD_IOMMU_STR) && +g_strcmp0(value, INTEL_IOMMU_STR)) { +error_setg(errp, "Invalid IOMMU type %s", value); +error_propagate(errp, err); +return; +} -ms->iommu = value; +ms->iommu = g_strdup(value); } static void machine_set_suppress_vmdesc(Object *obj, bool value, Error **errp) @@ -455,11 +467,10 @@ static void machine_initfn(Object *obj) object_property_set_description(obj, "firmware", "Firmware image", NULL); -object_property_add_bool(obj, "iommu", - machine_get_iommu, - machine_set_iommu, NULL); +object_property_add_str(obj, "iommu", +machine_get_iommu, machine_set_iommu, NULL); object_property_set_description(obj, "iommu", -"Set on/off to enable/disable Intel IOMMU (VT-d)", +"IOMMU list", NULL); object_property_add_bool(obj, "suppress-vmdesc", machine_get_suppress_vmdesc, @@ -485,6 +496,7 @@ static void machine_finalize(Object *obj) g_free(ms->dumpdtb); g_free(ms->dt_compatible); g_free(ms->firmware); +g_free(ms->iommu); } bool machine_usb(MachineState *machine) diff --git a/include/hw/boards.h b/include/hw/boards.h index 0f30959..b119245 100644 --- a/include/hw/boards.h +++ b/include/hw/boards.h @@ -36,6 +36,7 @@ bool machine_usb(MachineState *machine); bool machine_kernel_irqchip_allowed(MachineState *machine); bool machine_kernel_irqchip_required(MachineState *machine); bool machine_kernel_irqchip_split(MachineState *machine); +bool machine_amd_iommu(MachineState *machine); int machine_kvm_shadow_mem(MachineState *machine); int machine_phandle_start(MachineState *machine); bool machine_dump_guest_core(MachineState *machine); @@ -126,7 +127,7 @@ struct MachineState { bool usb_disabled; bool igd_gfx_passthru; char *firmware; -bool iommu; +char *iommu; bool suppress_vmdesc; ram_addr_t ram_size; diff --git a/qemu-options.hx b/qemu-options.hx index 2f0465e..dad160f 100644 --- a/qemu-options.hx +++ b/qemu-options.hx @@ -38,7 +38,7 @@ DEF("machine", HAS_ARG, QEMU_OPTION_machine, \ "kvm_shadow_mem=size of KVM shadow MMU\n" "dump-guest-core=on|off include guest memory in a core dump (default=on)\n" "mem-merge=on|off controls memory merge support (default: on)\n" -"iommu=on|off controls emulated Intel IOMMU (VT-d) support (default=off)\n" +"iommu=amd|intel enables and selects the emulated IOMMU (default: off)\n" "igd-passthru=on|off controls IGD GFX passthrough support (default=off)\n" "aes-key-wrap=on|off controls support for AES key wrapping (default=on)\n" "dea-key-wrap=on|off controls support for DEA key wrapping (default=on)\n" @@ -72,8 +72,8 @@ Include guest memory in a core dump. The default is on. Enables or disables memory merge support. This feature, when supported by the host, de-duplicates identical memory pages among VMs instances (enabled by default). -@item iommu=on|off -Ena
[Qemu-devel] [V6 3/4] hw/i386: ACPI table for AMD IOMMU
Add IVRS table for AMD IOMMU. Generate IVRS or DMAR depending on emulated IOMMU Signed-off-by: David Kiarie --- hw/i386/acpi-build.c| 208 +--- include/hw/acpi/acpi-defs.h | 55 2 files changed, 252 insertions(+), 11 deletions(-) diff --git a/hw/i386/acpi-build.c b/hw/i386/acpi-build.c index 4554eb8..fa1310f 100644 --- a/hw/i386/acpi-build.c +++ b/hw/i386/acpi-build.c @@ -51,6 +51,7 @@ #include "hw/pci/pci_bus.h" #include "hw/pci-host/q35.h" #include "hw/i386/intel_iommu.h" +#include "hw/i386/amd_iommu.h" #include "hw/timer/hpet.h" #include "hw/acpi/aml-build.h" @@ -121,6 +122,12 @@ typedef struct AcpiBuildPciBusHotplugState { bool pcihp_bridge_en; } AcpiBuildPciBusHotplugState; +typedef enum iommu_type { +TYPE_AMD, +TYPE_INTEL, +TYPE_NONE +} iommu_type; + static int acpi_add_cpu_info(Object *o, void *opaque) { @@ -2513,6 +2520,188 @@ build_dmar_q35(GArray *table_data, GArray *linker) "DMAR", table_data->len - dmar_start, 1, NULL, NULL); } +static void +build_amd_iommu(GArray *table_data, GArray *linker) +{ +int iommu_start = table_data->len; +bool iommu_ambig; + +AcpiAMDIOMMUIVRS *ivrs; +AcpiAMDIOMMUHardwareUnit *iommu; + +/* IVRS definition */ +ivrs = acpi_data_push(table_data, sizeof(*ivrs)); +ivrs->revision = cpu_to_le16(ACPI_IOMMU_IVRS_TYPE); +ivrs->length = cpu_to_le16((sizeof(*ivrs) + sizeof(*iommu))); +ivrs->v_common_info = cpu_to_le64(AMD_IOMMU_HOST_ADDRESS_WIDTH << 8); + +AMDIOMMUState *s = (AMDIOMMUState *)object_resolve_path_type("", +TYPE_AMD_IOMMU_DEVICE, &iommu_ambig); + +/* IVDB definition - type 10h */ +iommu = acpi_data_push(table_data, sizeof(*iommu)); +if (!iommu_ambig) { +iommu->type = cpu_to_le16(0x10); +/* IVHD flags */ +iommu->flags = cpu_to_le16(iommu->flags); +iommu->flags = cpu_to_le16(IVHD_HT_TUNEN | IVHD_PPRSUP | IVHD_IOTLBSUP + | IVHD_PREFSUP); +iommu->length = cpu_to_le16(sizeof(*iommu)); +iommu->device_id = cpu_to_le16(PCI_DEVICE_ID_RD890_IOMMU); +iommu->capability_offset = cpu_to_le16(s->capab_offset); +iommu->mmio_base = cpu_to_le64(s->mmio.addr); +iommu->pci_segment = 0; +iommu->interrupt_info = 0; +/* EFR features */ +iommu->efr_register = cpu_to_le64(IVHD_EFR_GTSUP | IVHD_EFR_HATS + | IVHD_EFR_GATS); +iommu->efr_register = cpu_to_le64(iommu->efr_register); +/* device entries */ +memset(iommu->dev_entries, 0, 20); +/* Add device flags here + * This is are 4-byte device entries currently reporting the range of + * devices 00h - h; all devices + * + * Device setting affecting all devices should be made here + * + * Refer to + * (http://developer.amd.com/wordpress/media/2012/10/488821.pdf) + * 5.2.2.1 + */ +iommu->dev_entries[12] = 3; +iommu->dev_entries[16] = 4; +iommu->dev_entries[17] = 0xff; +iommu->dev_entries[18] = 0xff; +} + +build_header(linker, table_data, (void *)(table_data->data + iommu_start), + "IVRS", table_data->len - iommu_start, 1, NULL); +} + +static iommu_type has_iommu(void) +{ +bool ambiguous; + +if (object_resolve_path_type("", TYPE_AMD_IOMMU_DEVICE, &ambiguous) +&& !ambiguous) +return TYPE_AMD; +else if (object_resolve_path_type("", TYPE_INTEL_IOMMU_DEVICE, &ambiguous) +&& !ambiguous) +return TYPE_INTEL; +else +return TYPE_NONE; +} + +static void +build_dsdt(GArray *table_data, GArray *linker, + AcpiPmInfo *pm, AcpiMiscInfo *misc) +{ +Aml *dsdt, *sb_scope, *scope, *dev, *method, *field; +MachineState *machine = MACHINE(qdev_get_machine()); +uint32_t nr_mem = machine->ram_slots; + +dsdt = init_aml_allocator(); + +/* Reserve space for header */ +acpi_data_push(dsdt->buf, sizeof(AcpiTableHeader)); + +build_dbg_aml(dsdt); +if (misc->is_piix4) { +sb_scope = aml_scope("_SB"); +dev = aml_device("PCI0"); +aml_append(dev, aml_name_decl("_HID", aml_eisaid("PNP0A03"))); +aml_append(dev, aml_name_decl("_ADR", aml_int(0))); +aml_append(dev, aml_name_decl("_UID", aml_int(1))); +aml_append(sb_scope, dev); +aml_append(dsdt, sb_scope); + +build_hpet_aml(dsdt); +build_piix4_pm(dsdt); +build_piix4_isa_bridge(dsdt); +build_isa_devices_aml(dsdt); +build_piix4_pci_hotplug(dsdt
[Qemu-devel] [V6 1/4] hw/i386: Introduce AMD IOMMU
Add AMD IOMMU emulaton to Qemu in addition to Intel IOMMU The IOMMU does basic translation, error checking and has a mininal IOTLB implementation Signed-off-by: David Kiarie --- hw/i386/Makefile.objs |1 + hw/i386/amd_iommu.c | 1432 + hw/i386/amd_iommu.h | 395 ++ include/hw/pci/pci.h |2 + 4 files changed, 1830 insertions(+) create mode 100644 hw/i386/amd_iommu.c create mode 100644 hw/i386/amd_iommu.h diff --git a/hw/i386/Makefile.objs b/hw/i386/Makefile.objs index b52d5b8..2f1a265 100644 --- a/hw/i386/Makefile.objs +++ b/hw/i386/Makefile.objs @@ -3,6 +3,7 @@ obj-y += multiboot.o obj-y += pc.o pc_piix.o pc_q35.o obj-y += pc_sysfw.o obj-y += intel_iommu.o +obj-y += amd_iommu.o obj-$(CONFIG_XEN) += ../xenpv/ xen/ obj-y += kvmvapic.o diff --git a/hw/i386/amd_iommu.c b/hw/i386/amd_iommu.c new file mode 100644 index 000..3dac043 --- /dev/null +++ b/hw/i386/amd_iommu.c @@ -0,0 +1,1432 @@ +/* + * QEMU emulation of AMD IOMMU (AMD-Vi) + * + * Copyright (C) 2011 Eduard - Gabriel Munteanu + * Copyright (C) 2015 David Kiarie, + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License along + * with this program; if not, see <http://www.gnu.org/licenses/>. + * + * Cache implementation inspired by hw/i386/intel_iommu.c + * + */ +#include "hw/i386/amd_iommu.h" + +/*#define DEBUG_AMD_IOMMU*/ +#ifdef DEBUG_AMD_IOMMU +enum { +DEBUG_GENERAL, DEBUG_CAPAB, DEBUG_MMIO, DEBUG_ELOG, +DEBUG_CACHE, DEBUG_COMMAND, DEBUG_MMU +}; + +#define IOMMU_DBGBIT(x) (1 << DEBUG_##x) +static int iommu_dbgflags = IOMMU_DBGBIT(MMIO); + +#define IOMMU_DPRINTF(what, fmt, ...) do { \ +if (iommu_dbgflags & IOMMU_DBGBIT(what)) { \ +fprintf(stderr, "(amd-iommu)%s: " fmt "\n", __func__, \ +## __VA_ARGS__); } \ +} while (0) +#else +#define IOMMU_DPRINTF(what, fmt, ...) do {} while (0) +#endif + +typedef struct AMDIOMMUAddressSpace { +uint8_t bus_num;/* bus number */ +uint8_t devfn; /* device function */ +AMDIOMMUState *iommu_state; /* IOMMU - one per machine */ +MemoryRegion iommu; /* Device's iommu region*/ +AddressSpace as;/* device's corresponding address space */ +} AMDIOMMUAddressSpace; + +/* IOMMU cache entry */ +typedef struct IOMMUIOTLBEntry { +uint64_t gfn; +uint16_t domid; +uint64_t devid; +uint64_t perms; +uint64_t translated_addr; +} IOMMUIOTLBEntry; + +/* configure MMIO registers at startup/reset */ +static void amd_iommu_set_quad(AMDIOMMUState *s, hwaddr addr, uint64_t val, + uint64_t romask, uint64_t w1cmask) +{ +stq_le_p(&s->mmior[addr], val); +stq_le_p(&s->romask[addr], romask); +stq_le_p(&s->w1cmask[addr], w1cmask); +} + +static uint16_t amd_iommu_readw(AMDIOMMUState *s, hwaddr addr) +{ +return lduw_le_p(&s->mmior[addr]); +} + +static uint32_t amd_iommu_readl(AMDIOMMUState *s, hwaddr addr) +{ +return ldl_le_p(&s->mmior[addr]); +} + +static uint64_t amd_iommu_readq(AMDIOMMUState *s, hwaddr addr) +{ +return ldq_le_p(&s->mmior[addr]); +} + +/* internal write */ +static void amd_iommu_writeq_raw(AMDIOMMUState *s, uint64_t val, hwaddr addr) +{ +stq_le_p(&s->mmior[addr], val); +} + +/* external write */ +static void amd_iommu_writew(AMDIOMMUState *s, hwaddr addr, uint16_t val) +{ +uint16_t romask = lduw_le_p(&s->romask[addr]); +uint16_t w1cmask = lduw_le_p(&s->w1cmask[addr]); +uint16_t oldval = lduw_le_p(&s->mmior[addr]); +stw_le_p(&s->mmior[addr], (val & ~(val & w1cmask)) | (romask & oldval)); +} + +static void amd_iommu_writel(AMDIOMMUState *s, hwaddr addr, uint32_t val) +{ +uint32_t romask = ldl_le_p(&s->romask[addr]); +uint32_t w1cmask = ldl_le_p(&s->w1cmask[addr]); +uint32_t oldval = ldl_le_p(&s->mmior[addr]); +stl_le_p(&s->mmior[addr], (val & ~(val & w1cmask)) | (romask & oldval)); +} + +static void amd_iommu_writeq(AMDIOMMUState *s, hwaddr addr, uint64_t val) +{ +uint64_t romask = ldq_le_p(&s->romask[addr]); +uint64_t w1cmask = ldq_le_p(&s->w1cmask[addr]); +uint32_t oldval = ldq_le_p(&s->mmior[addr]); +stq_le_p(&s->
[Qemu-devel] [V6 4/4] hw/pci-host: Emulate AMD IOMMU
Add AMD IOMMU emulation support to q35 chipset Signed-off-by: David Kiarie --- hw/pci-host/piix.c| 1 + hw/pci-host/q35.c | 14 -- include/hw/i386/intel_iommu.h | 1 + 3 files changed, 14 insertions(+), 2 deletions(-) diff --git a/hw/pci-host/piix.c b/hw/pci-host/piix.c index 41aa66f..ab2e24a 100644 --- a/hw/pci-host/piix.c +++ b/hw/pci-host/piix.c @@ -36,6 +36,7 @@ #include "hw/i386/ioapic.h" #include "qapi/visitor.h" #include "qemu/error-report.h" +#include "hw/i386/amd_iommu.h" /* * I440FX chipset data sheet. diff --git a/hw/pci-host/q35.c b/hw/pci-host/q35.c index 115fb8c..355fb32 100644 --- a/hw/pci-host/q35.c +++ b/hw/pci-host/q35.c @@ -31,6 +31,7 @@ #include "hw/hw.h" #include "hw/pci-host/q35.h" #include "qapi/visitor.h" +#include "hw/i386/amd_iommu.h" / * Q35 host @@ -505,9 +506,18 @@ static void mch_realize(PCIDevice *d, Error **errp) mch->pci_address_space, &mch->pam_regions[i+1], PAM_EXPAN_BASE + i * PAM_EXPAN_SIZE, PAM_EXPAN_SIZE); } -/* Intel IOMMU (VT-d) */ -if (object_property_get_bool(qdev_get_machine(), "iommu", NULL)) { + +if (g_strcmp0(MACHINE(qdev_get_machine())->iommu, INTEL_IOMMU_STR) == 0) { +/* Intel IOMMU (VT-d) */ mch_init_dmar(mch); +} else if (g_strcmp0(MACHINE(qdev_get_machine())->iommu, AMD_IOMMU_STR) + == 0) { +AMDIOMMUState *iommu_state; +PCIDevice *iommu; +PCIBus *bus = PCI_BUS(qdev_get_parent_bus(DEVICE(mch))); +iommu = pci_create_simple(bus, 0x20, TYPE_AMD_IOMMU_DEVICE); +iommu_state = AMD_IOMMU_DEVICE(iommu); +pci_setup_iommu(bus, bridge_host_amd_iommu, iommu_state); } } diff --git a/include/hw/i386/intel_iommu.h b/include/hw/i386/intel_iommu.h index b024ffa..539530c 100644 --- a/include/hw/i386/intel_iommu.h +++ b/include/hw/i386/intel_iommu.h @@ -27,6 +27,7 @@ #define TYPE_INTEL_IOMMU_DEVICE "intel-iommu" #define INTEL_IOMMU_DEVICE(obj) \ OBJECT_CHECK(IntelIOMMUState, (obj), TYPE_INTEL_IOMMU_DEVICE) +#define INTEL_IOMMU_STR "intel" /* DMAR Hardware Unit Definition address (IOMMU unit) */ #define Q35_HOST_BRIDGE_IOMMU_ADDR 0xfed9ULL -- 2.1.4
Re: [Qemu-devel] [V6 3/4] hw/i386: ACPI table for AMD IOMMU
On Sun, Feb 21, 2016 at 9:20 PM, Jan Kiszka wrote: > On 2016-02-21 19:10, David Kiarie wrote: >> Add IVRS table for AMD IOMMU. Generate IVRS or DMAR >> depending on emulated IOMMU >> >> Signed-off-by: David Kiarie >> --- >> hw/i386/acpi-build.c| 208 >> +--- >> include/hw/acpi/acpi-defs.h | 55 >> 2 files changed, 252 insertions(+), 11 deletions(-) >> >> diff --git a/hw/i386/acpi-build.c b/hw/i386/acpi-build.c >> index 4554eb8..fa1310f 100644 >> --- a/hw/i386/acpi-build.c >> +++ b/hw/i386/acpi-build.c >> @@ -51,6 +51,7 @@ >> #include "hw/pci/pci_bus.h" >> #include "hw/pci-host/q35.h" >> #include "hw/i386/intel_iommu.h" >> +#include "hw/i386/amd_iommu.h" >> #include "hw/timer/hpet.h" >> >> #include "hw/acpi/aml-build.h" >> @@ -121,6 +122,12 @@ typedef struct AcpiBuildPciBusHotplugState { >> bool pcihp_bridge_en; >> } AcpiBuildPciBusHotplugState; >> >> +typedef enum iommu_type { >> +TYPE_AMD, >> +TYPE_INTEL, >> +TYPE_NONE >> +} iommu_type; >> + >> static >> int acpi_add_cpu_info(Object *o, void *opaque) >> { >> @@ -2513,6 +2520,188 @@ build_dmar_q35(GArray *table_data, GArray *linker) >> "DMAR", table_data->len - dmar_start, 1, NULL, NULL); >> } >> >> +static void >> +build_amd_iommu(GArray *table_data, GArray *linker) >> +{ >> +int iommu_start = table_data->len; >> +bool iommu_ambig; >> + >> +AcpiAMDIOMMUIVRS *ivrs; >> +AcpiAMDIOMMUHardwareUnit *iommu; >> + >> +/* IVRS definition */ >> +ivrs = acpi_data_push(table_data, sizeof(*ivrs)); >> +ivrs->revision = cpu_to_le16(ACPI_IOMMU_IVRS_TYPE); >> +ivrs->length = cpu_to_le16((sizeof(*ivrs) + sizeof(*iommu))); >> +ivrs->v_common_info = cpu_to_le64(AMD_IOMMU_HOST_ADDRESS_WIDTH << 8); >> + >> +AMDIOMMUState *s = (AMDIOMMUState *)object_resolve_path_type("", >> +TYPE_AMD_IOMMU_DEVICE, &iommu_ambig); >> + >> +/* IVDB definition - type 10h */ >> +iommu = acpi_data_push(table_data, sizeof(*iommu)); >> +if (!iommu_ambig) { >> +iommu->type = cpu_to_le16(0x10); >> +/* IVHD flags */ >> +iommu->flags = cpu_to_le16(iommu->flags); >> +iommu->flags = cpu_to_le16(IVHD_HT_TUNEN | IVHD_PPRSUP | >> IVHD_IOTLBSUP >> + | IVHD_PREFSUP); >> +iommu->length = cpu_to_le16(sizeof(*iommu)); >> +iommu->device_id = cpu_to_le16(PCI_DEVICE_ID_RD890_IOMMU); >> +iommu->capability_offset = cpu_to_le16(s->capab_offset); >> +iommu->mmio_base = cpu_to_le64(s->mmio.addr); >> +iommu->pci_segment = 0; >> +iommu->interrupt_info = 0; >> +/* EFR features */ >> +iommu->efr_register = cpu_to_le64(IVHD_EFR_GTSUP | IVHD_EFR_HATS >> + | IVHD_EFR_GATS); >> +iommu->efr_register = cpu_to_le64(iommu->efr_register); >> +/* device entries */ >> +memset(iommu->dev_entries, 0, 20); >> +/* Add device flags here >> + * This is are 4-byte device entries currently reporting the range >> of >> + * devices 00h - h; all devices >> + * >> + * Device setting affecting all devices should be made here >> + * >> + * Refer to >> + * (http://developer.amd.com/wordpress/media/2012/10/488821.pdf) >> + * 5.2.2.1 >> + */ >> +iommu->dev_entries[12] = 3; >> +iommu->dev_entries[16] = 4; >> +iommu->dev_entries[17] = 0xff; >> +iommu->dev_entries[18] = 0xff; >> +} >> + >> +build_header(linker, table_data, (void *)(table_data->data + >> iommu_start), >> + "IVRS", table_data->len - iommu_start, 1, NULL); >> +} >> + >> +static iommu_type has_iommu(void) >> +{ >> +bool ambiguous; >> + >> +if (object_resolve_path_type("", TYPE_AMD_IOMMU_DEVICE, &ambiguous) >> +&& !ambiguous) >> +return TYPE_AMD; >> +else if (object_resolve_path_type("", TYPE_INTEL_IOMMU_DEVICE, >> &ambiguous) >> +&& !ambiguous) >> +
[Qemu-devel] [PATCH 3/4] hw/i386: ACPI table for AMD IOMMU
Add IVRS table for AMD IOMMU. Generate IVRS or DMAR depending on emulated IOMMU Signed-off-by: David Kiarie --- hw/i386/acpi-build.c| 98 - include/hw/acpi/acpi-defs.h | 55 + 2 files changed, 142 insertions(+), 11 deletions(-) diff --git a/hw/i386/acpi-build.c b/hw/i386/acpi-build.c index 4554eb8..76ef75f 100644 --- a/hw/i386/acpi-build.c +++ b/hw/i386/acpi-build.c @@ -51,6 +51,7 @@ #include "hw/pci/pci_bus.h" #include "hw/pci-host/q35.h" #include "hw/i386/intel_iommu.h" +#include "hw/i386/amd_iommu.h" #include "hw/timer/hpet.h" #include "hw/acpi/aml-build.h" @@ -121,6 +122,12 @@ typedef struct AcpiBuildPciBusHotplugState { bool pcihp_bridge_en; } AcpiBuildPciBusHotplugState; +typedef enum iommu_type { +TYPE_AMD, +TYPE_INTEL, +TYPE_NONE +} iommu_type; + static int acpi_add_cpu_info(Object *o, void *opaque) { @@ -2513,6 +2520,78 @@ build_dmar_q35(GArray *table_data, GArray *linker) "DMAR", table_data->len - dmar_start, 1, NULL, NULL); } +static void +build_amd_iommu(GArray *table_data, GArray *linker) +{ +int iommu_start = table_data->len; +bool iommu_ambig; + +AcpiAMDIOMMUIVRS *ivrs; +AcpiAMDIOMMUHardwareUnit *iommu; + +/* IVRS definition */ +ivrs = acpi_data_push(table_data, sizeof(*ivrs)); +ivrs->revision = cpu_to_le16(ACPI_IOMMU_IVRS_TYPE); +ivrs->length = cpu_to_le16((sizeof(*ivrs) + sizeof(*iommu))); +ivrs->v_common_info = cpu_to_le64(AMD_IOMMU_HOST_ADDRESS_WIDTH << 8); + +AMDIOMMUState *s = (AMDIOMMUState *)object_resolve_path_type("", +TYPE_AMD_IOMMU_DEVICE, &iommu_ambig); + +/* IVDB definition - type 10h */ +iommu = acpi_data_push(table_data, sizeof(*iommu)); +if (!iommu_ambig) { +iommu->type = cpu_to_le16(0x10); +/* IVHD flags */ +iommu->flags = cpu_to_le16(iommu->flags); +iommu->flags = cpu_to_le16(IVHD_HT_TUNEN | IVHD_PPRSUP | IVHD_IOTLBSUP + | IVHD_PREFSUP); +iommu->length = cpu_to_le16(sizeof(*iommu)); +iommu->device_id = cpu_to_le16(PCI_DEVICE_ID_RD890_IOMMU); +iommu->capability_offset = cpu_to_le16(s->capab_offset); +iommu->mmio_base = cpu_to_le64(s->mmio.addr); +iommu->pci_segment = 0; +iommu->interrupt_info = 0; +/* EFR features */ +iommu->efr_register = cpu_to_le64(IVHD_EFR_GTSUP | IVHD_EFR_HATS + | IVHD_EFR_GATS); +iommu->efr_register = cpu_to_le64(iommu->efr_register); +/* device entries */ +memset(iommu->dev_entries, 0, 20); +/* Add device flags here + * This is are 4-byte device entries currently reporting the range of + * devices 00h - h; all devices + * + * Device setting affecting all devices should be made here + * + * Refer to + * (http://developer.amd.com/wordpress/media/2012/10/488821.pdf) + * 5.2.2.1 + */ +iommu->dev_entries[12] = 3; +iommu->dev_entries[16] = 4; +iommu->dev_entries[17] = 0xff; +iommu->dev_entries[18] = 0xff; +} + +build_header(linker, table_data, (void *)(table_data->data + iommu_start), + "IVRS", table_data->len - iommu_start, 1, NULL, NULL); +} + +static iommu_type has_iommu(void) +{ +bool ambiguous; + +if (object_resolve_path_type("", TYPE_AMD_IOMMU_DEVICE, &ambiguous) +&& !ambiguous) +return TYPE_AMD; +else if (object_resolve_path_type("", TYPE_INTEL_IOMMU_DEVICE, &ambiguous) +&& !ambiguous) +return TYPE_INTEL; +else +return TYPE_NONE; +} + static GArray * build_rsdp(GArray *rsdp_table, GArray *linker, unsigned rsdt) { @@ -2570,16 +2649,6 @@ static bool acpi_get_mcfg(AcpiMcfgInfo *mcfg) return true; } -static bool acpi_has_iommu(void) -{ -bool ambiguous; -Object *intel_iommu; - -intel_iommu = object_resolve_path_type("", TYPE_INTEL_IOMMU_DEVICE, - &ambiguous); -return intel_iommu && !ambiguous; -} - static bool acpi_has_nvdimm(void) { PCMachineState *pcms = PC_MACHINE(qdev_get_machine()); @@ -2600,6 +2669,7 @@ void acpi_build(AcpiBuildTables *tables) AcpiMcfgInfo mcfg; PcPciInfo pci; uint8_t *u; +iommu_type type = has_iommu(); size_t aml_len = 0; GArray *tables_blob = tables->table_data; AcpiSlicOem slic_oem = { .id = NULL, .table_id = NULL }; @@ -2666,7 +2736,13 @@ void acpi_build(AcpiBuildTables *tables) acpi_add_table(table_offsets, tables_blob); build_mcfg_q35(tables_blob, tables->linker, &mc
Re: [Qemu-devel] [V6 0/4] AMD IOMMU
On Sun, Feb 21, 2016 at 11:20 PM, Jan Kiszka wrote: > On 2016-02-21 19:10, David Kiarie wrote: >> Hello there, >> >> Repost, AMD IOMMU patches version 6. >> >> Changes since version 5 >> -Fixed macro formating issues >> -changed occurences of IO MMU to IOMMU for consistency >> -Fixed capability registers duplication >> -Rebased to current master > > I suspect this still has some subtle bugs: I'm running the patches over > master with standard Linux distro as guest, full desktop, and I'm > getting sporadic segfaults of arbitrary programs. These disappear once I > disable the IOMMU or switch to the Intel version. Is this L1 guest or L2 guest ? - haven't got any such so far. > > How did you test so far? I mainly test by logging. I've tested L1 without any iommu-related command line parameters and with L1 with 'iommu=1 iommu=pt'. L2 guest; passed-through a device checked it's working correctly, that all. These guests barely have any load though. > > Jan > >
Re: [Qemu-devel] [V6 0/4] AMD IOMMU
On Mon, Feb 22, 2016 at 10:29 AM, Jan Kiszka wrote: > On 2016-02-22 06:57, David Kiarie wrote: >> On Sun, Feb 21, 2016 at 11:20 PM, Jan Kiszka wrote: >>> On 2016-02-21 19:10, David Kiarie wrote: >>>> Hello there, >>>> >>>> Repost, AMD IOMMU patches version 6. >>>> >>>> Changes since version 5 >>>> -Fixed macro formating issues >>>> -changed occurences of IO MMU to IOMMU for consistency >>>> -Fixed capability registers duplication >>>> -Rebased to current master >>> >>> I suspect this still has some subtle bugs: I'm running the patches over >>> master with standard Linux distro as guest, full desktop, and I'm >>> getting sporadic segfaults of arbitrary programs. These disappear once I >>> disable the IOMMU or switch to the Intel version. >> >> Is this L1 guest or L2 guest ? - haven't got any such so far. > > It's L1 only. > >> >>> >>> How did you test so far? >> >> I mainly test by logging. I've tested L1 without any iommu-related >> command line parameters and with L1 with 'iommu=1 iommu=pt'. L2 guest; >> passed-through a device checked it's working correctly, that all. >> These guests barely have any load though. > > I quickly reproduced the issue by starting some "heavier" applications, > a browser or an office suite. Something is apparently always corrupted > then, data or code, thus the crashes. Can't reproduce this issue with my ubuntu/debian VMs. Are you using any iommu-related command line parameters ? > > Jan > >
Re: [Qemu-devel] [V6 1/4] hw/i386: Introduce AMD IOMMU
On Thu, Feb 25, 2016 at 6:43 PM, Marcel Apfelbaum wrote: > On 02/21/2016 08:10 PM, David Kiarie wrote: >> >> Add AMD IOMMU emulaton to Qemu in addition to Intel IOMMU >> The IOMMU does basic translation, error checking and has a >> mininal IOTLB implementation > > > Hi, > >> >> Signed-off-by: David Kiarie >> --- >> hw/i386/Makefile.objs |1 + >> hw/i386/amd_iommu.c | 1432 >> + >> hw/i386/amd_iommu.h | 395 ++ >> include/hw/pci/pci.h |2 + >> 4 files changed, 1830 insertions(+) >> create mode 100644 hw/i386/amd_iommu.c >> create mode 100644 hw/i386/amd_iommu.h >> >> diff --git a/hw/i386/Makefile.objs b/hw/i386/Makefile.objs >> index b52d5b8..2f1a265 100644 >> --- a/hw/i386/Makefile.objs >> +++ b/hw/i386/Makefile.objs >> @@ -3,6 +3,7 @@ obj-y += multiboot.o >> obj-y += pc.o pc_piix.o pc_q35.o >> obj-y += pc_sysfw.o >> obj-y += intel_iommu.o >> +obj-y += amd_iommu.o >> obj-$(CONFIG_XEN) += ../xenpv/ xen/ >> >> obj-y += kvmvapic.o >> diff --git a/hw/i386/amd_iommu.c b/hw/i386/amd_iommu.c >> new file mode 100644 >> index 000..3dac043 >> --- /dev/null >> +++ b/hw/i386/amd_iommu.c >> @@ -0,0 +1,1432 @@ >> +/* >> + * QEMU emulation of AMD IOMMU (AMD-Vi) >> + * >> + * Copyright (C) 2011 Eduard - Gabriel Munteanu >> + * Copyright (C) 2015 David Kiarie, >> + * >> + * This program is free software; you can redistribute it and/or modify >> + * it under the terms of the GNU General Public License as published by >> + * the Free Software Foundation; either version 2 of the License, or >> + * (at your option) any later version. >> + >> + * This program is distributed in the hope that it will be useful, >> + * but WITHOUT ANY WARRANTY; without even the implied warranty of >> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the >> + * GNU General Public License for more details. >> + >> + * You should have received a copy of the GNU General Public License >> along >> + * with this program; if not, see <http://www.gnu.org/licenses/>. >> + * >> + * Cache implementation inspired by hw/i386/intel_iommu.c >> + * >> + */ >> +#include "hw/i386/amd_iommu.h" >> + >> +/*#define DEBUG_AMD_IOMMU*/ >> +#ifdef DEBUG_AMD_IOMMU >> +enum { >> +DEBUG_GENERAL, DEBUG_CAPAB, DEBUG_MMIO, DEBUG_ELOG, >> +DEBUG_CACHE, DEBUG_COMMAND, DEBUG_MMU >> +}; >> + >> +#define IOMMU_DBGBIT(x) (1 << DEBUG_##x) >> +static int iommu_dbgflags = IOMMU_DBGBIT(MMIO); >> + >> +#define IOMMU_DPRINTF(what, fmt, ...) do { \ >> +if (iommu_dbgflags & IOMMU_DBGBIT(what)) { \ >> +fprintf(stderr, "(amd-iommu)%s: " fmt "\n", __func__, \ >> +## __VA_ARGS__); } \ >> +} while (0) >> +#else >> +#define IOMMU_DPRINTF(what, fmt, ...) do {} while (0) >> +#endif >> + >> +typedef struct AMDIOMMUAddressSpace { >> +uint8_t bus_num;/* bus number >> */ >> +uint8_t devfn; /* device function >> */ >> +AMDIOMMUState *iommu_state; /* IOMMU - one per machine >> */ >> +MemoryRegion iommu; /* Device's iommu region >> */ >> +AddressSpace as;/* device's corresponding address space >> */ >> +} AMDIOMMUAddressSpace; >> + >> +/* IOMMU cache entry */ >> +typedef struct IOMMUIOTLBEntry { >> +uint64_t gfn; >> +uint16_t domid; >> +uint64_t devid; >> +uint64_t perms; >> +uint64_t translated_addr; >> +} IOMMUIOTLBEntry; >> + >> +/* configure MMIO registers at startup/reset */ >> +static void amd_iommu_set_quad(AMDIOMMUState *s, hwaddr addr, uint64_t >> val, >> + uint64_t romask, uint64_t w1cmask) >> +{ >> +stq_le_p(&s->mmior[addr], val); >> +stq_le_p(&s->romask[addr], romask); >> +stq_le_p(&s->w1cmask[addr], w1cmask); >> +} >> + >> +static uint16_t amd_iommu_readw(AMDIOMMUState *s, hwaddr addr) >> +{ >> +return lduw_le_p(&s->mmior[addr]); >> +} >> + >> +static uint32_t amd_iommu_readl(AMDIOMMUState *s, hwaddr addr) >> +{ >> +return ldl_le_p(&s->mmior[addr]); >> +} >> + >> +static uint64_t amd_iommu_readq(AMDIOMMUState *s, hwaddr addr) >> +{ >> +return ldq_le_p(&s->mmior[addr]);
[Qemu-devel] Allocate PCI MMIO without BAR requests.
Hi all, Some efforts to emulate AMD IOMMU have being going over the past few months. In real hardware AMD IOMMU is implemented as a PCI function. When emulating it in Qemu we want to allocate it MMIO space but real AMD IOMMU manage to reserve memory without making a BAR request, probably through a static address that's written by the device.(This is something similar to what non-PCI bus devices do).Trying to reserve memory via a BAR request results in address conflicts(in Linux) and all other PCI devices reserve platform resources via BAR requests. I would like to hear suggestions on how to reserve a memory region for the device without making a BAR request. Cheers, David.
Re: [Qemu-devel] Aspirant for AMD IOMMU emulation project for Outreachy
On Wed, Sep 9, 2015 at 12:35 AM, Jan Kiszka wrote: > [thanks for forwarding, Peter] > > Hi Rita, > > On 2015-09-08 10:11, Peter Maydell wrote: >> On 7 September 2015 at 22:31, Rita Sinha wrote: >>> Hi Jan, >>> >>> I am interested in participating in next round of Outreachy program >>> with AMD IOMMU emulation project. >>> >>> >>> I have worked on BIOS projects which includes coreboot SeaBios etc and >>> bootloaders like u-boot and grub. I have experience of working with >>> qemu and feel that this project is the right match for my skillset. >>> Kindly guide me how to go ahead with this. > > The particular AMD IOMMU project moved on since we listed it. I'm CC'ing > David, who is currently working on it and just recently posted related > patches, and Valentine who probably oversees the status better than I > (due to my lacking involvement recently). David, maybe you can briefly > comment on status and plans of your work. Hi all, Most recent work is here http://lists.nongnu.org/archive/html/qemu-devel/2015-08/msg02759.html . Most the code is Qemu device boilerplate(so there are a ton of things to add but I wanted to have the existing work merged first). The IOMMU just offers basic translation. From Valentine's previous comments, I only have a few minor issues to fix in the code. I obviously do other things alongside :-D this project but given some time I could get the code merged and continue to add other features. > > For the Outreachy program, just like for GSoC, we need to find a good > topic that is sufficiently clear defined on program start and not worked > on in parallel during the runtime. There are still a number of open > topics in this area, e.g. around the older Intel IOMMU model (error > handling and reporting, interrupt remapping), or maybe we find something > different - depends on your interests and experiences. Do you have any > public references to your previous work? > > Then I'd suggest to schedule an irc meeting to discuss your interests > and background a bit further and consider available options. > > Jan >
Re: [Qemu-devel] Aspirant for AMD IOMMU emulation project for Outreachy
On Wed, Sep 9, 2015 at 8:01 AM, Rita Sinha wrote: > Hi David, > > Please find my response inline. > > >> >> Hi all, >> >> Most recent work is here >> http://lists.nongnu.org/archive/html/qemu-devel/2015-08/msg02759.html >> . Most the code is Qemu device boilerplate(so there are a ton of >> things to add but I wanted to have the existing work merged first). >> The IOMMU just offers basic translation. From Valentine's previous >> comments, I only have a few minor issues to fix in the code. >> >> I obviously do other things alongside :-D this project but given some >> time I could get the code merged and continue to add other features. >> > > Let me know if I can help in this effort which will help me get > started on this project. Hi Rita, Most likely than not you'll work on the Intel IOMMU and I would suggest, if you wish to get your feet dirty, just start right away with the Intel IOMMU (In which case Jan could direct you better) instead of the AMD one. > > Regards, > Rita Sinha
Re: [Qemu-devel] Aspirant for AMD IOMMU emulation project for Outreachy
On Wed, Sep 9, 2015 at 9:47 AM, Valentine Sinitsyn wrote: > Hi all, > > > On 09.09.2015 09:23, David kiarie wrote: >> >> On Wed, Sep 9, 2015 at 12:35 AM, Jan Kiszka wrote: >>> >>> [thanks for forwarding, Peter] >>> >>> Hi Rita, >>> >>> On 2015-09-08 10:11, Peter Maydell wrote: >>>> >>>> On 7 September 2015 at 22:31, Rita Sinha wrote: >>>>> >>>>> Hi Jan, >>>>> >>>>> I am interested in participating in next round of Outreachy program >>>>> with AMD IOMMU emulation project. >>>>> >>>>> >>>>> I have worked on BIOS projects which includes coreboot SeaBios etc and >>>>> bootloaders like u-boot and grub. I have experience of working with >>>>> qemu and feel that this project is the right match for my skillset. >>>>> Kindly guide me how to go ahead with this. >>> >>> >>> The particular AMD IOMMU project moved on since we listed it. I'm CC'ing >>> David, who is currently working on it and just recently posted related >>> patches, and Valentine who probably oversees the status better than I >>> (due to my lacking involvement recently). David, maybe you can briefly >>> comment on status and plans of your work. >> >> >> Hi all, >> >> Most recent work is here >> http://lists.nongnu.org/archive/html/qemu-devel/2015-08/msg02759.html >> . Most the code is Qemu device boilerplate(so there are a ton of >> things to add but I wanted to have the existing work merged first). >> The IOMMU just offers basic translation. From Valentine's previous >> comments, I only have a few minor issues to fix in the code. > > This is a bit of off-topic here, but I'd argue they are minor. There are > some inaccuracies in emulation, and IOMMU itself is rather feature-limited, > just as you said. I doubt I'd be able to run current Jailhouse > implementation on it, for instance, albeit I haven't tried. So, your patches > are good start, but I feel there's a somewhat long way before they actually > get merged. Yep, that is possible. For instance, you were insisting on 'cache' implemention ;) which IMHO, is optional but could be a good project start. > > So, in short: there are still tasks to be done in AMD IOMMU emulation > project. I also feel it's possible to parallelize them so David and Rita can > continue without stepping at each other toe, if the program permits it. > >> I obviously do other things alongside :-D this project but given some >> time I could get the code merged and continue to add other features. >> >>> >>> For the Outreachy program, just like for GSoC, we need to find a good >>> topic that is sufficiently clear defined on program start and not worked >>> on in parallel during the runtime. There are still a number of open >>> topics in this area, e.g. around the older Intel IOMMU model (error >>> handling and reporting, interrupt remapping), or maybe we find something >>> different - depends on your interests and experiences. Do you have any >>> public references to your previous work? >>> >>> Then I'd suggest to schedule an irc meeting to discuss your interests >>> and background a bit further and consider available options. >>> >>> Jan >>> > > Regards, > Valentine
Re: [Qemu-devel] [RFC 2/4] hw/i386: Introduce AMD IOMMU
On Mon, Sep 7, 2015 at 3:46 PM, Valentine Sinitsyn wrote: > Hi David, > > Sorry for the long silence. I've skimmed through your patch, below are some > thoughts. Please remember I'm looking for IOMMU implementation details, not > how it is integrated with QEMU. > > On 25.08.2015 04:19, David Kiarie wrote: >> >> From: David >> >> Add AMD IOMMU emulation to Qemu. This is a very basic AMD IOMMU >> emulation that only does translation and some basic Event logging. >> Guest translation enables nested PCI passthrough >> >> Signed-off-by: David Kiarie >> --- >> hw/i386/Makefile.objs | 1 + >> hw/i386/amd_iommu.c | 993 >> ++ >> hw/i386/amd_iommu.h | 298 +++ >> 3 files changed, 1292 insertions(+) >> create mode 100644 hw/i386/amd_iommu.c >> create mode 100644 hw/i386/amd_iommu.h >> >> diff --git a/hw/i386/Makefile.objs b/hw/i386/Makefile.objs >> index ebd1015..2bae11c 100644 >> --- a/hw/i386/Makefile.objs >> +++ b/hw/i386/Makefile.objs >> @@ -3,6 +3,7 @@ obj-y += multiboot.o >> obj-y += pc.o pc_piix.o pc_q35.o >> obj-y += pc_sysfw.o >> obj-y += intel_iommu.o >> +obj-y += amd_iommu.o >> obj-$(CONFIG_XEN) += ../xenpv/ xen/ >> >> obj-y += kvmvapic.o >> diff --git a/hw/i386/amd_iommu.c b/hw/i386/amd_iommu.c >> new file mode 100644 >> index 000..a3a0b20 >> --- /dev/null >> +++ b/hw/i386/amd_iommu.c >> @@ -0,0 +1,993 @@ >> +/* >> + * QEMU emulation of an AMD IOMMU (AMD-Vi) >> + * >> + * Copyright (C) 2011 Eduard - Gabriel Munteanu >> + * Copyright (C) 2015 David Kiarie, >> + * >> + * This program is free software; you can redistribute it and/or modify >> + * it under the terms of the GNU General Public License as published by >> + * the Free Software Foundation; either version 2 of the License, or >> + * (at your option) any later version. >> + >> + * This program is distributed in the hope that it will be useful, >> + * but WITHOUT ANY WARRANTY; without even the implied warranty of >> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the >> + * GNU General Public License for more details. >> + >> + * You should have received a copy of the GNU General Public License >> along >> + * with this program; if not, see <http://www.gnu.org/licenses/>. >> + * >> + */ >> +#include "hw/i386/amd_iommu.h" >> + >> +#define PCI_EXT_CAP_ID_PASID 0x1B >> +#define PCI_EXT_CAP_ID_PRI 0x13 > > Do you really need those? They don't seem to be used. >> >> + >> +#define PCI_SLOT(devfn) (((devfn) >> 3) & 0x1f) >> +#define PCI_FUNC(devfn) ((devfn) & 0x07) >> + >> +#define MAX_VA_ADDR (64UL << 5) >> +#define MAX_PH_ADDR (48UL << 8) >> +#define MAX_GVA_ADDR (64UL << 15) >> + >> +//#define DEBUG_AMD_IOMMU > > It's generally advisable to avoid commented-out lines. Use #ifdefs, or > remove them altogether. > > >> +#ifdef DEBUG_AMD_IOMMU >> +enum { >> +DEBUG_GENERAL, DEBUG_CAPAB, DEBUG_MMIO, DEBUG_ELOG, >> +DEBUG_CACHE, DEBUG_COMMAND, DEBUG_MMU >> +}; >> + >> +#define IOMMU_DBGBIT(x) (1 << DEBUG_##x) >> +static int iommu_dbgflags = IOMMU_DBGBIT(GENERAL) | IOMMU_DBGBIT(MMU) | >> IOMMU_DBGBIT(MMIO); >> +//| IOMMU_DBGBIT(CAPAB) | IOMMU_DBGBIT(ELOG) | IOMMU_DBGBIT(CACHE) | >> IOMMU_DBGBIT(COMMAND); >> + >> +#define IOMMU_DPRINTF(what, fmt, ...) do { \ >> +if (iommu_dbgflags & IOMMU_DBGBIT(what)) { \ >> +fprintf(stderr, "(amd-iommu)%s: " fmt "\n", __func__, \ >> +## __VA_ARGS__); } \ >> +} while (0) >> +#else >> +#define IOMMU_DPRINTF(what, fmt, ...) do {} while (0) >> +#endif >> + >> +/* helper functions - FIXME - provide for reading one byte */ >> +static uint16_t amd_iommu_readw(AMDIOMMUState *s, hwaddr addr) >> +{ >> +return lduw_le_p(&s->mmior[addr]); >> +} >> + >> +static uint32_t amd_iommu_readl(AMDIOMMUState *s, hwaddr addr) >> +{ >> +return ldl_le_p(&s->mmior[addr]); >> +} >> + >> +static uint64_t amd_iommu_readq(AMDIOMMUState *s, hwaddr addr) >> +{ >> +return ldq_le_p(&s->mmior[addr]); >> +} >> + >> +static void amd_iommu_writew(AMDIOMMUState *s, hwaddr addr, uint16_t val) >> +{ >> +stw_le_p(&s->mmior[addr], val); >> +} >&g
Re: [Qemu-devel] [RFC 2/4] hw/i386: Introduce AMD IOMMU
On Wed, Sep 9, 2015 at 10:45 AM, Valentine Sinitsyn wrote: > On 09.09.2015 12:30, David kiarie wrote: > ...snip... > > >>>> +static void amd_iommu_cmdbuf_exec(AMDIOMMUState *s) >>>> +{ >>>> +unsigned type; >>>> +uint8_t cmd[IOMMU_COMMAND_SIZE]; >>>> + >>>> +IOMMU_DPRINTF(COMMAND, ""); >>>> +memset(cmd, 0, IOMMU_COMMAND_SIZE); >>>> + >>>> +if(dma_memory_read(&address_space_memory, s->cmdbuf + >>>> s->cmdbuf_head, >>>> cmd, IOMMU_COMMAND_SIZE)){ >>>> +IOMMU_DPRINTF(COMMAND, "error: fail to access memory at >>>> 0x%"PRIx64 >>>> + " + %"PRIu8, s->cmdbuf, s->cmdbuf_head); >>>> +} >>>> + >>>> +type = cmd[CMDBUF_ID_BYTE] >> CMDBUF_ID_RSHIFT; >>>> + >>>> +switch(type){ >>>> +case CMD_COMPLETION_WAIT: >>>> +/* pretend to wait for command execution to complete */ >>>> +IOMMU_DPRINTF(COMMAND, "completion wait requested"); >>>> +amd_iommu_completion_wait(s, cmd); >>>> +break; >>>> +case CMD_INVAL_DEVTAB_ENTRY: >>>> +/* Not implemented yet - should just clear device table >>>> contents */ >>>> +IOMMU_DPRINTF(COMMAND, "device table entries invalidated"); >>> >>> >>> Better make it clear that these commands are not implemented yet. An >>> IOMMU >>> is hardly usable without invalidators. >> >> >> I think the "debug prinft" here is misleading. AFAIK, the commands >> listed here(there are others which I haven't listed) relate to 'cache' >> which means this commands do nothing in the absence of cache. >> >> The reason why I advertise 'cache' is because the linux driver checks >> for cache and other optional features to determine the IOMMU version >> whereby versions 2 of IOMMU are assummed to support this features. > > Did you check how address translation is emulated in QEMU. I didn't :) But > you return IOMMTLBEntry from your translation routine, and I'd rather ensure > it is not cached in some other layer. Am expected to cache the IOMMUTLBEntries myself, probably through a hashtable. Also, that's what emulated VT-d in Qemu does. > > Besides, omitting invalidation commands will be a problem on real hardware. > As IOMMU emulation is mainly useful for debugging, I'd reproduce this > behaviour in the emulator. I mean, if I forget to do CMD_INVAL_DEVTAB_ENTRY > in my guest code, things shouldn't work properly. Yes, 'cache' is important for debugging. I or someone else could work on cache, now or later. > > You can just copy all data structures to AMDIOMMUState and use this "cahced" > copies, updated when you run invalidation commands. But this isn't a #1 > priority, you are right. > > Can you share some tests results for this code? Do you mean the whole IOMMU?It works, as far as am concerned. I got was able to 'passthrough' a sound device but that's the only device I tested. > >> >>> >>>> +break; >>>> +case CMD_INVAL_IOMMU_PAGES: >>>> +/* invalidate IOMMU cache for a particular domain */ >>>> +IOMMU_DPRINTF(COMMAND, "IOMMU pages invalidated"); >>>> +break; >>>> +case CMD_INVAL_IOTLB_PAGES: >>>> +/* Only present if remote IOTLB present */ >>>> +IOMMU_DPRINTF(COMMAND, "IOTLB pages invalidated"); >>>> +break; >>>> +case CMD_INVAL_INTR_TABLE: >>>> +/* no support for interrupt remapping yet */ >>>> +IOMMU_DPRINTF(COMMAND, "interrupt table invalidated"); >>>> +break; >>>> +default: >>>> +IOMMU_DPRINTF(COMMAND, "unhandled command %d", type); >>>> +break; >>>> +} >>>> + >>>> +} >>>> + >>>> +static void amd_iommu_cmdbuf_run(AMDIOMMUState *s) >>>> +{ >>>> +IOMMU_DPRINTF(COMMAND, ""); >>>> + >>>> +uint64_t *mmio_cmdbuf_head = (uint64_t*)s->mmior + >>>> MMIO_COMMAND_HEAD; >>>> + >>>> +if(!s->cmdbuf_enabled){ >>>> +IOM
Re: [Qemu-devel] [RFC 2/4] hw/i386: Introduce AMD IOMMU
I wrote something basic on the cover letter http://lists.nongnu.org/archive/html/qemu-devel/2015-08/msg02759.html On Wed, Sep 9, 2015 at 11:07 AM, Valentine Sinitsyn wrote: > On 09.09.2015 12:59, David kiarie wrote: >> >> On Wed, Sep 9, 2015 at 10:45 AM, Valentine Sinitsyn >> wrote: >>> >>> On 09.09.2015 12:30, David kiarie wrote: >>> ...snip... >>> >>> >>>>>> +static void amd_iommu_cmdbuf_exec(AMDIOMMUState *s) >>>>>> +{ >>>>>> +unsigned type; >>>>>> +uint8_t cmd[IOMMU_COMMAND_SIZE]; >>>>>> + >>>>>> +IOMMU_DPRINTF(COMMAND, ""); >>>>>> +memset(cmd, 0, IOMMU_COMMAND_SIZE); >>>>>> + >>>>>> +if(dma_memory_read(&address_space_memory, s->cmdbuf + >>>>>> s->cmdbuf_head, >>>>>> cmd, IOMMU_COMMAND_SIZE)){ >>>>>> +IOMMU_DPRINTF(COMMAND, "error: fail to access memory at >>>>>> 0x%"PRIx64 >>>>>> + " + %"PRIu8, s->cmdbuf, s->cmdbuf_head); >>>>>> +} >>>>>> + >>>>>> +type = cmd[CMDBUF_ID_BYTE] >> CMDBUF_ID_RSHIFT; >>>>>> + >>>>>> +switch(type){ >>>>>> +case CMD_COMPLETION_WAIT: >>>>>> +/* pretend to wait for command execution to complete */ >>>>>> +IOMMU_DPRINTF(COMMAND, "completion wait requested"); >>>>>> +amd_iommu_completion_wait(s, cmd); >>>>>> +break; >>>>>> +case CMD_INVAL_DEVTAB_ENTRY: >>>>>> +/* Not implemented yet - should just clear device table >>>>>> contents */ >>>>>> +IOMMU_DPRINTF(COMMAND, "device table entries >>>>>> invalidated"); >>>>> >>>>> >>>>> >>>>> Better make it clear that these commands are not implemented yet. An >>>>> IOMMU >>>>> is hardly usable without invalidators. >>>> >>>> >>>> >>>> I think the "debug prinft" here is misleading. AFAIK, the commands >>>> listed here(there are others which I haven't listed) relate to 'cache' >>>> which means this commands do nothing in the absence of cache. >>>> >>>> The reason why I advertise 'cache' is because the linux driver checks >>>> for cache and other optional features to determine the IOMMU version >>>> whereby versions 2 of IOMMU are assummed to support this features. >>> >>> >>> Did you check how address translation is emulated in QEMU. I didn't :) >>> But >>> you return IOMMTLBEntry from your translation routine, and I'd rather >>> ensure >>> it is not cached in some other layer. >> >> >> Am expected to cache the IOMMUTLBEntries myself, probably through a >> hashtable. Also, that's what emulated VT-d in Qemu does. >> >>> >>> Besides, omitting invalidation commands will be a problem on real >>> hardware. >>> As IOMMU emulation is mainly useful for debugging, I'd reproduce this >>> behaviour in the emulator. I mean, if I forget to do >>> CMD_INVAL_DEVTAB_ENTRY >>> in my guest code, things shouldn't work properly. >> >> >> Yes, 'cache' is important for debugging. I or someone else could work >> on cache, now or later. >> >>> >>> You can just copy all data structures to AMDIOMMUState and use this >>> "cahced" >>> copies, updated when you run invalidation commands. But this isn't a #1 >>> priority, you are right. >>> >>> Can you share some tests results for this code? >> >> >> Do you mean the whole IOMMU?It works, as far as am concerned. I got >> was able to 'passthrough' a sound device but that's the only device I >> tested. > > That's great. Could you describe your tests setup, please? Maybe in README > or in the cover letter, so anyone interested could reproduce it just > following your steps. > > Valentine > > >> >>> >>>> >>>>> >>>>>> +break; >>>>>> +case CMD_INVAL_IOMMU_PAGES: >>>>>> +/*
Re: [Qemu-devel] [RFC 2/4] hw/i386: Introduce AMD IOMMU
On Wed, Sep 9, 2015 at 11:14 AM, Valentine Sinitsyn wrote: > Oops, that was a long ago. Sorry & thanks. No problem. Will fix all other comments. > > Valentine > > > On 09.09.2015 13:12, David kiarie wrote: >> >> I wrote something basic on the cover letter >> http://lists.nongnu.org/archive/html/qemu-devel/2015-08/msg02759.html >> >> On Wed, Sep 9, 2015 at 11:07 AM, Valentine Sinitsyn >> wrote: >>> >>> On 09.09.2015 12:59, David kiarie wrote: >>>> >>>> >>>> On Wed, Sep 9, 2015 at 10:45 AM, Valentine Sinitsyn >>>> wrote: >>>>> >>>>> >>>>> On 09.09.2015 12:30, David kiarie wrote: >>>>> ...snip... >>>>> >>>>> >>>>>>>> +static void amd_iommu_cmdbuf_exec(AMDIOMMUState *s) >>>>>>>> +{ >>>>>>>> +unsigned type; >>>>>>>> +uint8_t cmd[IOMMU_COMMAND_SIZE]; >>>>>>>> + >>>>>>>> +IOMMU_DPRINTF(COMMAND, ""); >>>>>>>> +memset(cmd, 0, IOMMU_COMMAND_SIZE); >>>>>>>> + >>>>>>>> +if(dma_memory_read(&address_space_memory, s->cmdbuf + >>>>>>>> s->cmdbuf_head, >>>>>>>> cmd, IOMMU_COMMAND_SIZE)){ >>>>>>>> +IOMMU_DPRINTF(COMMAND, "error: fail to access memory at >>>>>>>> 0x%"PRIx64 >>>>>>>> + " + %"PRIu8, s->cmdbuf, s->cmdbuf_head); >>>>>>>> +} >>>>>>>> + >>>>>>>> +type = cmd[CMDBUF_ID_BYTE] >> CMDBUF_ID_RSHIFT; >>>>>>>> + >>>>>>>> +switch(type){ >>>>>>>> +case CMD_COMPLETION_WAIT: >>>>>>>> +/* pretend to wait for command execution to complete */ >>>>>>>> +IOMMU_DPRINTF(COMMAND, "completion wait requested"); >>>>>>>> +amd_iommu_completion_wait(s, cmd); >>>>>>>> +break; >>>>>>>> +case CMD_INVAL_DEVTAB_ENTRY: >>>>>>>> +/* Not implemented yet - should just clear device table >>>>>>>> contents */ >>>>>>>> +IOMMU_DPRINTF(COMMAND, "device table entries >>>>>>>> invalidated"); >>>>>>> >>>>>>> >>>>>>> >>>>>>> >>>>>>> Better make it clear that these commands are not implemented yet. An >>>>>>> IOMMU >>>>>>> is hardly usable without invalidators. >>>>>> >>>>>> >>>>>> >>>>>> >>>>>> I think the "debug prinft" here is misleading. AFAIK, the commands >>>>>> listed here(there are others which I haven't listed) relate to 'cache' >>>>>> which means this commands do nothing in the absence of cache. >>>>>> >>>>>> The reason why I advertise 'cache' is because the linux driver checks >>>>>> for cache and other optional features to determine the IOMMU version >>>>>> whereby versions 2 of IOMMU are assummed to support this features. >>>>> >>>>> >>>>> >>>>> Did you check how address translation is emulated in QEMU. I didn't :) >>>>> But >>>>> you return IOMMTLBEntry from your translation routine, and I'd rather >>>>> ensure >>>>> it is not cached in some other layer. >>>> >>>> >>>> >>>> Am expected to cache the IOMMUTLBEntries myself, probably through a >>>> hashtable. Also, that's what emulated VT-d in Qemu does. >>>> >>>>> >>>>> Besides, omitting invalidation commands will be a problem on real >>>>> hardware. >>>>> As IOMMU emulation is mainly useful for debugging, I'd reproduce this >>>>> behaviour in the emulator. I mean, if I forget to do >>>>> CMD_INVAL_DEVTAB_ENTRY >>>>> in my guest code, things shouldn't work properly. >>>> >>>> >>>> >>>> Yes, 'cache' is i
[Qemu-devel] [RFC 1/4] hw/core: Prepare for introducing AMD IOMMU
From: David Add AMD IOMMU as one of the devices that can possibly be emulated by Qemu. Also, add some helper functions for manipulating presence/absence of IOMMU Signed-off-by: David Kiarie --- hw/core/machine.c | 25 + include/hw/boards.h | 2 ++ 2 files changed, 27 insertions(+) diff --git a/hw/core/machine.c b/hw/core/machine.c index ac4654e..b326a80 100644 --- a/hw/core/machine.c +++ b/hw/core/machine.c @@ -255,6 +255,20 @@ static void machine_set_iommu(Object *obj, bool value, Error **errp) ms->iommu = value; } +static bool machine_get_amd_iommu(Object *obj, Error **errp) +{ +MachineState *ms = MACHINE(obj); + +return ms->amd_iommu; +} + +static void machine_set_amd_iommu(Object *obj, bool value, Error **errp) +{ +MachineState *ms = MACHINE(obj); + +ms->amd_iommu = value; +} + static void machine_set_suppress_vmdesc(Object *obj, bool value, Error **errp) { MachineState *ms = MACHINE(obj); @@ -400,6 +414,12 @@ static void machine_initfn(Object *obj) object_property_set_description(obj, "iommu", "Set on/off to enable/disable Intel IOMMU (VT-d)", NULL); +object_property_add_bool(obj, "amd-iommu", + machine_get_amd_iommu, + machine_set_amd_iommu, NULL); +object_property_set_description(obj, "amd-iommu", +"Set on/off to enable/disable AMD-Vi", +NULL); object_property_add_bool(obj, "suppress-vmdesc", machine_get_suppress_vmdesc, machine_set_suppress_vmdesc, NULL); @@ -436,6 +456,11 @@ bool machine_iommu(MachineState *machine) return machine->iommu; } +bool machine_amd_iommu(MachineState *machine) +{ +return machine->amd_iommu; +} + bool machine_kernel_irqchip_allowed(MachineState *machine) { return machine->kernel_irqchip_allowed; diff --git a/include/hw/boards.h b/include/hw/boards.h index 3f84afd..88324b2 100644 --- a/include/hw/boards.h +++ b/include/hw/boards.h @@ -54,6 +54,7 @@ extern MachineState *current_machine; bool machine_usb(MachineState *machine); bool machine_iommu(MachineState *machine); +bool machine_amd_iommu(MachineState *machine); bool machine_kernel_irqchip_allowed(MachineState *machine); bool machine_kernel_irqchip_required(MachineState *machine); int machine_kvm_shadow_mem(MachineState *machine); @@ -139,6 +140,7 @@ struct MachineState { bool usb_disabled; char *firmware; bool iommu; +bool amd_iommu; bool suppress_vmdesc; ram_addr_t ram_size; -- 2.1.4
[Qemu-devel] [RFC 0/4] AMD IOMMU
This series implements basic AMD IOMMU emulation to Qemu AMD IOMMU emulation. -This series emulates AMD IOMMU on qemu. It implements the following features -Translation - 4K pages -Event logging - particulary fault logging. -AMD IOMMU, being a convectional PCI device doesn't rely on any other technology from AMD and hence you can test this patch on l2 guest emulated on an Intel PC. -These patches have been tested using the 'ac97' sound device with QEMU_AUDIO_DRV=alsa and proven to work. Testing - pretty basic stuff... On host #kvm_amd is loaded with nested support by default by anyways :) -$modprobe -r kvm_amd $modprobe kvm_amd nested=1 $command to start guest with 'iommu=1' kernel arguments On the guest $dmesg | AMD-Vi AMD-Vi: Enabling IOMMU at :00:00.2 cap 0x40 AMD-Vi: Lazy IO/TLB flushing enabled $modprobe kvm_amd $modprobe pci_stub $lspci -n 01:00.0 0200: 8086:10b9 (rev 06) $echo "8086 10b9" > /sys/bus/pci/drivers/pci-stub/new_id $echo :01:00.0 > /sys/bus/pci/devices/:01:00.0/driver/unbind $echo :01:00.0 > /sys/bus/pci/drivers/pci-stub/bind Assign the device $/usr/local/bin/qemu-system-x86_64 -m 512 -boot c -net none -hda /root/ia32e_rhel5u1.img -device pci-assign,host=01:00.0 I guess that's all there is to say. Please test! asla. David (4): hw/core: Prepare for introducing AMD IOMMU hw/i386: Introduce AMD IOMMU hw/i386: Introduce IVRS for AMD IOMMU hw/pci-host: Add AMD IOMMU emulation to q35 and PIIX hw/core/machine.c | 25 ++ hw/i386/Makefile.objs | 1 + hw/i386/acpi-build.c| 85 hw/i386/amd_iommu.c | 993 hw/i386/amd_iommu.h | 298 + hw/pci-host/piix.c | 11 + hw/pci-host/q35.c | 11 + include/hw/acpi/acpi-defs.h | 55 +++ include/hw/boards.h | 2 + 9 files changed, 1481 insertions(+) create mode 100644 hw/i386/amd_iommu.c create mode 100644 hw/i386/amd_iommu.h -- 2.1.4
[Qemu-devel] [RFC 2/4] hw/i386: Introduce AMD IOMMU
From: David Add AMD IOMMU emulation to Qemu. This is a very basic AMD IOMMU emulation that only does translation and some basic Event logging. Guest translation enables nested PCI passthrough Signed-off-by: David Kiarie --- hw/i386/Makefile.objs | 1 + hw/i386/amd_iommu.c | 993 ++ hw/i386/amd_iommu.h | 298 +++ 3 files changed, 1292 insertions(+) create mode 100644 hw/i386/amd_iommu.c create mode 100644 hw/i386/amd_iommu.h diff --git a/hw/i386/Makefile.objs b/hw/i386/Makefile.objs index ebd1015..2bae11c 100644 --- a/hw/i386/Makefile.objs +++ b/hw/i386/Makefile.objs @@ -3,6 +3,7 @@ obj-y += multiboot.o obj-y += pc.o pc_piix.o pc_q35.o obj-y += pc_sysfw.o obj-y += intel_iommu.o +obj-y += amd_iommu.o obj-$(CONFIG_XEN) += ../xenpv/ xen/ obj-y += kvmvapic.o diff --git a/hw/i386/amd_iommu.c b/hw/i386/amd_iommu.c new file mode 100644 index 000..a3a0b20 --- /dev/null +++ b/hw/i386/amd_iommu.c @@ -0,0 +1,993 @@ +/* + * QEMU emulation of an AMD IOMMU (AMD-Vi) + * + * Copyright (C) 2011 Eduard - Gabriel Munteanu + * Copyright (C) 2015 David Kiarie, + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License along + * with this program; if not, see <http://www.gnu.org/licenses/>. + * + */ +#include "hw/i386/amd_iommu.h" + +#define PCI_EXT_CAP_ID_PASID 0x1B +#define PCI_EXT_CAP_ID_PRI 0x13 + +#define PCI_SLOT(devfn) (((devfn) >> 3) & 0x1f) +#define PCI_FUNC(devfn) ((devfn) & 0x07) + +#define MAX_VA_ADDR (64UL << 5) +#define MAX_PH_ADDR (48UL << 8) +#define MAX_GVA_ADDR (64UL << 15) + +//#define DEBUG_AMD_IOMMU +#ifdef DEBUG_AMD_IOMMU +enum { +DEBUG_GENERAL, DEBUG_CAPAB, DEBUG_MMIO, DEBUG_ELOG, +DEBUG_CACHE, DEBUG_COMMAND, DEBUG_MMU +}; + +#define IOMMU_DBGBIT(x) (1 << DEBUG_##x) +static int iommu_dbgflags = IOMMU_DBGBIT(GENERAL) | IOMMU_DBGBIT(MMU) | IOMMU_DBGBIT(MMIO); +//| IOMMU_DBGBIT(CAPAB) | IOMMU_DBGBIT(ELOG) | IOMMU_DBGBIT(CACHE) | IOMMU_DBGBIT(COMMAND); + +#define IOMMU_DPRINTF(what, fmt, ...) do { \ +if (iommu_dbgflags & IOMMU_DBGBIT(what)) { \ +fprintf(stderr, "(amd-iommu)%s: " fmt "\n", __func__, \ +## __VA_ARGS__); } \ +} while (0) +#else +#define IOMMU_DPRINTF(what, fmt, ...) do {} while (0) +#endif + +/* helper functions - FIXME - provide for reading one byte */ +static uint16_t amd_iommu_readw(AMDIOMMUState *s, hwaddr addr) +{ +return lduw_le_p(&s->mmior[addr]); +} + +static uint32_t amd_iommu_readl(AMDIOMMUState *s, hwaddr addr) +{ +return ldl_le_p(&s->mmior[addr]); +} + +static uint64_t amd_iommu_readq(AMDIOMMUState *s, hwaddr addr) +{ +return ldq_le_p(&s->mmior[addr]); +} + +static void amd_iommu_writew(AMDIOMMUState *s, hwaddr addr, uint16_t val) +{ +stw_le_p(&s->mmior[addr], val); +} + +static void amd_iommu_writel(AMDIOMMUState *s, hwaddr addr, uint32_t val) +{ +stl_le_p(&s->mmior[addr], val); +} + +static void amd_iommu_writeq(AMDIOMMUState *s, hwaddr addr, uint64_t val) +{ +stq_le_p(&s->mmior[addr], val); +} + +/* execute a completion wait command */ +static void amd_iommu_completion_wait(AMDIOMMUState *s, uint8_t *cmd) +{ +unsigned int addr; + +/* completion store */ +if(cmd[0] & COM_COMPLETION_STORE_MASK){ +addr = le64_to_cpu(*(uint64_t*)cmd) & COM_STORE_ADDRESS_MASK; +if(dma_memory_write(&address_space_memory, addr, cmd + 8, 8)){ +IOMMU_DPRINTF(ELOG, "error: fail to write at address 0%x"PRIx64, addr); +} + +} + +/* set completion interrupt */ +if (cmd[0] & COM_COMPLETION_INTR){ +s->mmior[MMIO_STATUS] |= MMIO_STATUS_COMWAIT_INTR; +} +} + +static void amd_iommu_cmdbuf_exec(AMDIOMMUState *s) +{ +unsigned type; +uint8_t cmd[IOMMU_COMMAND_SIZE]; + +IOMMU_DPRINTF(COMMAND, ""); +memset(cmd, 0, IOMMU_COMMAND_SIZE); + +if(dma_memory_read(&address_space_memory, s->cmdbuf + s->cmdbuf_head, cmd, IOMMU_COMMAND_SIZE)){ +IOMMU_DPRINTF(COMMAND, "error: fail to access memory at 0x%"PRIx64 + " + %"PRIu8, s->cmdbuf, s->cmdbuf_head); +} + +type = cmd[CMDBUF_ID_BYTE] >> CMDBUF_ID_RSHIFT; + +switch(type){ +case CMD_COMPLETION_WAIT: +/* pretend to wait for co
[Qemu-devel] [RFC 4/4] hw/pci-host: Add AMD IOMMU emulation to q35 and PIIX
From: David Add AMD IOMMU emulation to q35 and PIIX chipsets. Signed-off-by: David Kiarie --- hw/pci-host/piix.c | 11 +++ hw/pci-host/q35.c | 11 +++ 2 files changed, 22 insertions(+) diff --git a/hw/pci-host/piix.c b/hw/pci-host/piix.c index 1cb25f3..348cff0 100644 --- a/hw/pci-host/piix.c +++ b/hw/pci-host/piix.c @@ -31,6 +31,7 @@ #include "qemu/range.h" #include "hw/xen/xen.h" #include "hw/pci-host/pam.h" +#include "hw/i386/amd_iommu.h" #include "sysemu/sysemu.h" #include "hw/i386/ioapic.h" #include "qapi/visitor.h" @@ -292,12 +293,21 @@ static void i440fx_pcihost_realize(DeviceState *dev, Error **errp) { PCIHostState *s = PCI_HOST_BRIDGE(dev); SysBusDevice *sbd = SYS_BUS_DEVICE(dev); +AMDIOMMUState *iommu_state; +PCIDevice *iommu; sysbus_add_io(sbd, 0xcf8, &s->conf_mem); sysbus_init_ioports(sbd, 0xcf8, 4); sysbus_add_io(sbd, 0xcfc, &s->data_mem); sysbus_init_ioports(sbd, 0xcfc, 4); + +/* AMD IOMMU (AMD-Vi) */ +if(machine_amd_iommu(current_machine)){ +iommu = pci_create_simple(s->bus, 0x20, TYPE_AMD_IOMMU_DEVICE); +iommu_state = AMD_IOMMU_DEVICE(iommu); +pci_setup_iommu(s->bus, bridge_host_amd_iommu, iommu_state); +} } static void i440fx_realize(PCIDevice *dev, Error **errp) @@ -333,6 +343,7 @@ PCIBus *i440fx_init(PCII440FXState **pi440fx_state, object_property_add_child(qdev_get_machine(), "i440fx", OBJECT(dev), NULL); qdev_init_nofail(dev); + d = pci_create_simple(b, 0, TYPE_I440FX_PCI_DEVICE); *pi440fx_state = I440FX_PCI_DEVICE(d); f = *pi440fx_state; diff --git a/hw/pci-host/q35.c b/hw/pci-host/q35.c index bd74094..4bb7e3f 100644 --- a/hw/pci-host/q35.c +++ b/hw/pci-host/q35.c @@ -30,6 +30,7 @@ #include "hw/hw.h" #include "hw/pci-host/q35.h" #include "qapi/visitor.h" +#include "hw/i386/amd_iommu.h" / * Q35 host @@ -470,6 +471,8 @@ static void mch_realize(PCIDevice *d, Error **errp) { int i; MCHPCIState *mch = MCH_PCI_DEVICE(d); +AMDIOMMUState *iommu_state; +PCIDevice *iommu; /* setup pci memory mapping */ pc_pci_as_mapping_init(OBJECT(mch), mch->system_memory, @@ -528,6 +531,14 @@ static void mch_realize(PCIDevice *d, Error **errp) if (machine_iommu(current_machine)) { mch_init_dmar(mch); } + +/* AMD IOMMU (AMD-Vi) */ +if (machine_amd_iommu(current_machine)){ +PCIBus *bus = PCI_BUS(qdev_get_parent_bus(DEVICE(mch))); +iommu = pci_create_simple(bus, 0x20, TYPE_AMD_IOMMU_DEVICE); +iommu_state = AMD_IOMMU_DEVICE(iommu); +pci_setup_iommu(bus, bridge_host_amd_iommu, iommu_state); +} } uint64_t mch_mcfg_base(void) -- 2.1.4
[Qemu-devel] [RFC 3/4] hw/i386: Introduce IVRS for AMD IOMMU
From: David Add IVRS table for AMD IOMMU. Table indicates that all devices will be translated by the IOMMU, features common to all IOMMUs and IVDB for the IOMMU to be emulated Signed-off-by: David Kiarie --- hw/i386/acpi-build.c| 85 + include/hw/acpi/acpi-defs.h | 55 + 2 files changed, 140 insertions(+) diff --git a/hw/i386/acpi-build.c b/hw/i386/acpi-build.c index 95e0c65..1016ed9 100644 --- a/hw/i386/acpi-build.c +++ b/hw/i386/acpi-build.c @@ -50,6 +50,7 @@ #include "hw/pci/pci_bus.h" #include "hw/pci-host/q35.h" #include "hw/i386/intel_iommu.h" +#include "hw/i386/amd_iommu.h" #include "hw/i386/q35-acpi-dsdt.hex" #include "hw/i386/acpi-dsdt.hex" @@ -1576,10 +1577,80 @@ build_dmar_q35(GArray *table_data, GArray *linker) } static void +amd_iommu_acpi_set_flag(uint8_t *value, uint64_t flag) +{ +uint64_t newvalue = *value | flag; +*(uint64_t*)value = newvalue; +} + +static void +amd_iommu_acpi_set_feature(uint64_t *value, uint64_t feature) +{ +uint64_t newvalue = *value | feature; +*value = newvalue; +} + +static void +build_amd_iommu(GArray *table_data, GArray *linker) +{ +int iommu_start = table_data->len; +bool iommu_ambig; +uint64_t host_width = (AMD_IOMMU_HOST_ADDRESS_WIDTH << 8); + +AcpiAMDIOMMUIVRS *ivrs; +AcpiAMDIOMMUHardwareUnit *iommu; + +/* IVRS definition */ +ivrs = acpi_data_push(table_data, sizeof(*ivrs)); +ivrs->revision = ACPI_IOMMU_IVRS_TYPE; +ivrs->length = (sizeof(*ivrs) + sizeof(*iommu)); +ivrs->v_common_info = host_width; + +AMDIOMMUState *s = (AMDIOMMUState*)object_resolve_path_type("", TYPE_AMD_IOMMU_DEVICE, &iommu_ambig); + +/* IVDB definition */ +iommu = acpi_data_push(table_data, sizeof(*iommu)); +if(!iommu_ambig){ +iommu->type = 0x10; +/* IVHD flags */ +amd_iommu_acpi_set_flag(&iommu->flags, IVHD_HT_TUNEN); +amd_iommu_acpi_set_flag(&iommu->flags, IVHD_PPRSUP); +amd_iommu_acpi_set_flag(&iommu->flags, IVHD_IOTLBSUP); +amd_iommu_acpi_set_flag(&iommu->flags, IVHD_ISOC); +amd_iommu_acpi_set_flag(&iommu->flags, IVHD_PREFSUP); + +iommu->length = sizeof(*iommu); +iommu->device_id = PCI_DEVICE_ID_RD890_IOMMU; +iommu->capability_offset = s->capab_offset; +iommu->mmio_base = s->mmio.addr; +iommu->pci_segment = cpu_to_le16(0); +iommu->interrupt_info = cpu_to_le16(0); + +/* EFR features */ +amd_iommu_acpi_set_feature(&iommu->efr_register, IVHD_EFR_GTSUP); +amd_iommu_acpi_set_feature(&iommu->efr_register, IVHD_EFR_HATS); +amd_iommu_acpi_set_feature(&iommu->efr_register, IVHD_EFR_GATS); + +/* device entries */ +memset(iommu->dev_entries, 0, 20); + +/* Add device flags here */ +iommu->dev_entries[12] = 3; +iommu->dev_entries[16] = 4; +iommu->dev_entries[17] = 0xff; +iommu->dev_entries[18] = 0xff; +} + +build_header(linker, table_data, (void*)(table_data->data + iommu_start), + "IVRS", table_data->len - iommu_start, 1); +} + +static void build_dsdt(GArray *table_data, GArray *linker, AcpiMiscInfo *misc) { AcpiTableHeader *dsdt; + assert(misc->dsdt_code && misc->dsdt_size); dsdt = acpi_data_push(table_data, misc->dsdt_size); @@ -1658,6 +1729,16 @@ static bool acpi_has_iommu(void) return intel_iommu && !ambiguous; } +static bool acpi_has_amd_iommu(void) +{ +bool ambiguous; +Object *amd_iommu; + +amd_iommu = object_resolve_path_type("", TYPE_AMD_IOMMU_DEVICE, + &ambiguous); +return amd_iommu && !ambiguous; +} + static void acpi_build(PcGuestInfo *guest_info, AcpiBuildTables *tables) { @@ -1741,6 +1822,10 @@ void acpi_build(PcGuestInfo *guest_info, AcpiBuildTables *tables) acpi_add_table(table_offsets, tables_blob); build_dmar_q35(tables_blob, tables->linker); } +if(acpi_has_amd_iommu() && !acpi_has_iommu()){ +acpi_add_table(table_offsets, tables_blob); +build_amd_iommu(tables_blob, tables->linker); +} /* Add tables supplied by user (if any) */ for (u = acpi_table_first(); u; u = acpi_table_next(u)) { diff --git a/include/hw/acpi/acpi-defs.h b/include/hw/acpi/acpi-defs.h index 2b431e6..4fc1f79 100644 --- a/include/hw/acpi/acpi-defs.h +++ b/include/hw/acpi/acpi-defs.h @@ -561,4 +561,59 @@ typedef struct AcpiDmarHardwareUnit AcpiDmarHardwareUnit; /* Masks for Flags field above */ #define ACPI_DMAR_INCLUDE_PCI_ALL 1 +/* IVRS constants */ +#define ACPI_IOMMU_HARDWAREUNIT_TYPE 0x10 +#
Re: [Qemu-devel] [RFC 2/4] hw/i386: Introduce AMD IOMMU
On Tue, Aug 25, 2015 at 9:39 AM, Valentine Sinitsyn wrote: > Hi, > > > On 25.08.2015 04:19, David Kiarie wrote: >> >> From: David >> >> Add AMD IOMMU emulation to Qemu. This is a very basic AMD IOMMU >> emulation that only does translation and some basic Event logging. >> Guest translation enables nested PCI passthrough >> >> Signed-off-by: David Kiarie >> --- >> hw/i386/Makefile.objs | 1 + >> hw/i386/amd_iommu.c | 993 >> ++ >> hw/i386/amd_iommu.h | 298 +++ >> 3 files changed, 1292 insertions(+) >> create mode 100644 hw/i386/amd_iommu.c >> create mode 100644 hw/i386/amd_iommu.h >> >> diff --git a/hw/i386/Makefile.objs b/hw/i386/Makefile.objs >> index ebd1015..2bae11c 100644 >> --- a/hw/i386/Makefile.objs >> +++ b/hw/i386/Makefile.objs >> @@ -3,6 +3,7 @@ obj-y += multiboot.o >> obj-y += pc.o pc_piix.o pc_q35.o >> obj-y += pc_sysfw.o >> obj-y += intel_iommu.o >> +obj-y += amd_iommu.o >> obj-$(CONFIG_XEN) += ../xenpv/ xen/ >> >> obj-y += kvmvapic.o >> diff --git a/hw/i386/amd_iommu.c b/hw/i386/amd_iommu.c >> new file mode 100644 >> index 000..a3a0b20 >> --- /dev/null >> +++ b/hw/i386/amd_iommu.c >> @@ -0,0 +1,993 @@ >> +/* >> + * QEMU emulation of an AMD IOMMU (AMD-Vi) >> + * >> + * Copyright (C) 2011 Eduard - Gabriel Munteanu >> + * Copyright (C) 2015 David Kiarie, >> + * >> + * This program is free software; you can redistribute it and/or modify >> + * it under the terms of the GNU General Public License as published by >> + * the Free Software Foundation; either version 2 of the License, or >> + * (at your option) any later version. >> + >> + * This program is distributed in the hope that it will be useful, >> + * but WITHOUT ANY WARRANTY; without even the implied warranty of >> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the >> + * GNU General Public License for more details. >> + >> + * You should have received a copy of the GNU General Public License >> along >> + * with this program; if not, see <http://www.gnu.org/licenses/>. >> + * >> + */ >> +#include "hw/i386/amd_iommu.h" >> + >> +#define PCI_EXT_CAP_ID_PASID 0x1B >> +#define PCI_EXT_CAP_ID_PRI 0x13 >> + >> +#define PCI_SLOT(devfn) (((devfn) >> 3) & 0x1f) >> +#define PCI_FUNC(devfn) ((devfn) & 0x07) >> + >> +#define MAX_VA_ADDR (64UL << 5) >> +#define MAX_PH_ADDR (48UL << 8) >> +#define MAX_GVA_ADDR (64UL << 15) >> + >> +//#define DEBUG_AMD_IOMMU >> +#ifdef DEBUG_AMD_IOMMU >> +enum { >> +DEBUG_GENERAL, DEBUG_CAPAB, DEBUG_MMIO, DEBUG_ELOG, >> +DEBUG_CACHE, DEBUG_COMMAND, DEBUG_MMU >> +}; >> + >> +#define IOMMU_DBGBIT(x) (1 << DEBUG_##x) >> +static int iommu_dbgflags = IOMMU_DBGBIT(GENERAL) | IOMMU_DBGBIT(MMU) | >> IOMMU_DBGBIT(MMIO); >> +//| IOMMU_DBGBIT(CAPAB) | IOMMU_DBGBIT(ELOG) | IOMMU_DBGBIT(CACHE) | >> IOMMU_DBGBIT(COMMAND); >> + >> +#define IOMMU_DPRINTF(what, fmt, ...) do { \ >> +if (iommu_dbgflags & IOMMU_DBGBIT(what)) { \ >> +fprintf(stderr, "(amd-iommu)%s: " fmt "\n", __func__, \ >> +## __VA_ARGS__); } \ >> +} while (0) >> +#else >> +#define IOMMU_DPRINTF(what, fmt, ...) do {} while (0) >> +#endif >> + >> +/* helper functions - FIXME - provide for reading one byte */ >> +static uint16_t amd_iommu_readw(AMDIOMMUState *s, hwaddr addr) >> +{ >> +return lduw_le_p(&s->mmior[addr]); >> +} >> + >> +static uint32_t amd_iommu_readl(AMDIOMMUState *s, hwaddr addr) >> +{ >> +return ldl_le_p(&s->mmior[addr]); >> +} >> + >> +static uint64_t amd_iommu_readq(AMDIOMMUState *s, hwaddr addr) >> +{ >> +return ldq_le_p(&s->mmior[addr]); >> +} >> + >> +static void amd_iommu_writew(AMDIOMMUState *s, hwaddr addr, uint16_t val) >> +{ >> +stw_le_p(&s->mmior[addr], val); >> +} >> + >> +static void amd_iommu_writel(AMDIOMMUState *s, hwaddr addr, uint32_t val) >> +{ >> +stl_le_p(&s->mmior[addr], val); >> +} >> + >> +static void amd_iommu_writeq(AMDIOMMUState *s, hwaddr addr, uint64_t val) >> +{ >> +stq_le_p(&s->mmior[addr], val); >> +} >> + >> +/* execute a completion wait command */ >> +static voi
Re: [Qemu-devel] [RFC 2/4] hw/i386: Introduce AMD IOMMU
On Tue, Aug 25, 2015 at 10:31 AM, Valentine Sinitsyn wrote: > > > On 25.08.2015 12:25, David kiarie wrote: >> >> On Tue, Aug 25, 2015 at 9:39 AM, Valentine Sinitsyn >> wrote: >>> >>> Hi, >>> >>> >>> On 25.08.2015 04:19, David Kiarie wrote: >>>> >>>> >>>> From: David >>>> >>>> Add AMD IOMMU emulation to Qemu. This is a very basic AMD IOMMU >>>> emulation that only does translation and some basic Event logging. >>>> Guest translation enables nested PCI passthrough >>>> >>>> Signed-off-by: David Kiarie >>>> --- >>>>hw/i386/Makefile.objs | 1 + >>>>hw/i386/amd_iommu.c | 993 >>>> ++ >>>>hw/i386/amd_iommu.h | 298 +++ >>>>3 files changed, 1292 insertions(+) >>>>create mode 100644 hw/i386/amd_iommu.c >>>>create mode 100644 hw/i386/amd_iommu.h >>>> >>>> diff --git a/hw/i386/Makefile.objs b/hw/i386/Makefile.objs >>>> index ebd1015..2bae11c 100644 >>>> --- a/hw/i386/Makefile.objs >>>> +++ b/hw/i386/Makefile.objs >>>> @@ -3,6 +3,7 @@ obj-y += multiboot.o >>>>obj-y += pc.o pc_piix.o pc_q35.o >>>>obj-y += pc_sysfw.o >>>>obj-y += intel_iommu.o >>>> +obj-y += amd_iommu.o >>>> obj-$(CONFIG_XEN) += ../xenpv/ xen/ >>>> >>>>obj-y += kvmvapic.o >>>> diff --git a/hw/i386/amd_iommu.c b/hw/i386/amd_iommu.c >>>> new file mode 100644 >>>> index 000..a3a0b20 >>>> --- /dev/null >>>> +++ b/hw/i386/amd_iommu.c >>>> @@ -0,0 +1,993 @@ >>>> +/* >>>> + * QEMU emulation of an AMD IOMMU (AMD-Vi) >>>> + * >>>> + * Copyright (C) 2011 Eduard - Gabriel Munteanu >>>> + * Copyright (C) 2015 David Kiarie, >>>> + * >>>> + * This program is free software; you can redistribute it and/or modify >>>> + * it under the terms of the GNU General Public License as published by >>>> + * the Free Software Foundation; either version 2 of the License, or >>>> + * (at your option) any later version. >>>> + >>>> + * This program is distributed in the hope that it will be useful, >>>> + * but WITHOUT ANY WARRANTY; without even the implied warranty of >>>> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the >>>> + * GNU General Public License for more details. >>>> + >>>> + * You should have received a copy of the GNU General Public License >>>> along >>>> + * with this program; if not, see <http://www.gnu.org/licenses/>. >>>> + * >>>> + */ >>>> +#include "hw/i386/amd_iommu.h" >>>> + >>>> +#define PCI_EXT_CAP_ID_PASID 0x1B >>>> +#define PCI_EXT_CAP_ID_PRI 0x13 >>>> + >>>> +#define PCI_SLOT(devfn) (((devfn) >> 3) & 0x1f) >>>> +#define PCI_FUNC(devfn) ((devfn) & 0x07) >>>> + >>>> +#define MAX_VA_ADDR (64UL << 5) >>>> +#define MAX_PH_ADDR (48UL << 8) >>>> +#define MAX_GVA_ADDR (64UL << 15) >>>> + >>>> +//#define DEBUG_AMD_IOMMU >>>> +#ifdef DEBUG_AMD_IOMMU >>>> +enum { >>>> +DEBUG_GENERAL, DEBUG_CAPAB, DEBUG_MMIO, DEBUG_ELOG, >>>> +DEBUG_CACHE, DEBUG_COMMAND, DEBUG_MMU >>>> +}; >>>> + >>>> +#define IOMMU_DBGBIT(x) (1 << DEBUG_##x) >>>> +static int iommu_dbgflags = IOMMU_DBGBIT(GENERAL) | IOMMU_DBGBIT(MMU) | >>>> IOMMU_DBGBIT(MMIO); >>>> +//| IOMMU_DBGBIT(CAPAB) | IOMMU_DBGBIT(ELOG) | IOMMU_DBGBIT(CACHE) | >>>> IOMMU_DBGBIT(COMMAND); >>>> + >>>> +#define IOMMU_DPRINTF(what, fmt, ...) do { \ >>>> +if (iommu_dbgflags & IOMMU_DBGBIT(what)) { \ >>>> +fprintf(stderr, "(amd-iommu)%s: " fmt "\n", __func__, \ >>>> +## __VA_ARGS__); } \ >>>> +} while (0) >>>> +#else >>>> +#define IOMMU_DPRINTF(what, fmt, ...) do {} while (0) >>>> +#endif >>>> + >>>> +/* helper functions - FIXME - provide for reading one byte */ >>>> +static uint16_t amd_iommu_readw(AMDIOMMUState *s, hwaddr addr) >>>> +
Re: [Qemu-devel] [RFC 2/4] hw/i386: Introduce AMD IOMMU
Also, am not sure what HATS, GATS and sizes of virtual addresses(for both guest and host) I should be using. On Tue, Aug 25, 2015 at 10:41 AM, David kiarie wrote: > On Tue, Aug 25, 2015 at 10:31 AM, Valentine Sinitsyn > wrote: >> >> >> On 25.08.2015 12:25, David kiarie wrote: >>> >>> On Tue, Aug 25, 2015 at 9:39 AM, Valentine Sinitsyn >>> wrote: >>>> >>>> Hi, >>>> >>>> >>>> On 25.08.2015 04:19, David Kiarie wrote: >>>>> >>>>> >>>>> From: David >>>>> >>>>> Add AMD IOMMU emulation to Qemu. This is a very basic AMD IOMMU >>>>> emulation that only does translation and some basic Event logging. >>>>> Guest translation enables nested PCI passthrough >>>>> >>>>> Signed-off-by: David Kiarie >>>>> --- >>>>>hw/i386/Makefile.objs | 1 + >>>>>hw/i386/amd_iommu.c | 993 >>>>> ++ >>>>>hw/i386/amd_iommu.h | 298 +++ >>>>>3 files changed, 1292 insertions(+) >>>>>create mode 100644 hw/i386/amd_iommu.c >>>>>create mode 100644 hw/i386/amd_iommu.h >>>>> >>>>> diff --git a/hw/i386/Makefile.objs b/hw/i386/Makefile.objs >>>>> index ebd1015..2bae11c 100644 >>>>> --- a/hw/i386/Makefile.objs >>>>> +++ b/hw/i386/Makefile.objs >>>>> @@ -3,6 +3,7 @@ obj-y += multiboot.o >>>>>obj-y += pc.o pc_piix.o pc_q35.o >>>>>obj-y += pc_sysfw.o >>>>>obj-y += intel_iommu.o >>>>> +obj-y += amd_iommu.o >>>>>obj-$(CONFIG_XEN) += ../xenpv/ xen/ >>>>> >>>>>obj-y += kvmvapic.o >>>>> diff --git a/hw/i386/amd_iommu.c b/hw/i386/amd_iommu.c >>>>> new file mode 100644 >>>>> index 000..a3a0b20 >>>>> --- /dev/null >>>>> +++ b/hw/i386/amd_iommu.c >>>>> @@ -0,0 +1,993 @@ >>>>> +/* >>>>> + * QEMU emulation of an AMD IOMMU (AMD-Vi) >>>>> + * >>>>> + * Copyright (C) 2011 Eduard - Gabriel Munteanu >>>>> + * Copyright (C) 2015 David Kiarie, >>>>> + * >>>>> + * This program is free software; you can redistribute it and/or modify >>>>> + * it under the terms of the GNU General Public License as published by >>>>> + * the Free Software Foundation; either version 2 of the License, or >>>>> + * (at your option) any later version. >>>>> + >>>>> + * This program is distributed in the hope that it will be useful, >>>>> + * but WITHOUT ANY WARRANTY; without even the implied warranty of >>>>> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the >>>>> + * GNU General Public License for more details. >>>>> + >>>>> + * You should have received a copy of the GNU General Public License >>>>> along >>>>> + * with this program; if not, see <http://www.gnu.org/licenses/>. >>>>> + * >>>>> + */ >>>>> +#include "hw/i386/amd_iommu.h" >>>>> + >>>>> +#define PCI_EXT_CAP_ID_PASID 0x1B >>>>> +#define PCI_EXT_CAP_ID_PRI 0x13 >>>>> + >>>>> +#define PCI_SLOT(devfn) (((devfn) >> 3) & 0x1f) >>>>> +#define PCI_FUNC(devfn) ((devfn) & 0x07) >>>>> + >>>>> +#define MAX_VA_ADDR (64UL << 5) >>>>> +#define MAX_PH_ADDR (48UL << 8) >>>>> +#define MAX_GVA_ADDR (64UL << 15) >>>>> + >>>>> +//#define DEBUG_AMD_IOMMU >>>>> +#ifdef DEBUG_AMD_IOMMU >>>>> +enum { >>>>> +DEBUG_GENERAL, DEBUG_CAPAB, DEBUG_MMIO, DEBUG_ELOG, >>>>> +DEBUG_CACHE, DEBUG_COMMAND, DEBUG_MMU >>>>> +}; >>>>> + >>>>> +#define IOMMU_DBGBIT(x) (1 << DEBUG_##x) >>>>> +static int iommu_dbgflags = IOMMU_DBGBIT(GENERAL) | IOMMU_DBGBIT(MMU) | >>>>> IOMMU_DBGBIT(MMIO); >>>>> +//| IOMMU_DBGBIT(CAPAB) | IOMMU_DBGBIT(ELOG) | IOMMU_DBGBIT(CACHE) | >>>>> IOMMU_DBGBIT(COMMAND); >>>>> + >>>>> +#define IOMMU_DPRINTF(what, fmt, ...) do { \ >>>>> +if (iommu_dbgflags & IOMMU_DBGBIT
Re: [Qemu-devel] [V6 1/4] hw/i386: Introduce AMD IOMMU
On Fri, Feb 26, 2016 at 9:23 AM, David Kiarie wrote: > On Thu, Feb 25, 2016 at 6:43 PM, Marcel Apfelbaum wrote: >> On 02/21/2016 08:10 PM, David Kiarie wrote: >>> >>> Add AMD IOMMU emulaton to Qemu in addition to Intel IOMMU >>> The IOMMU does basic translation, error checking and has a >>> mininal IOTLB implementation >> >> >> Hi, >> >>> >>> Signed-off-by: David Kiarie >>> --- >>> hw/i386/Makefile.objs |1 + >>> hw/i386/amd_iommu.c | 1432 >>> + >>> hw/i386/amd_iommu.h | 395 ++ >>> include/hw/pci/pci.h |2 + >>> 4 files changed, 1830 insertions(+) >>> create mode 100644 hw/i386/amd_iommu.c >>> create mode 100644 hw/i386/amd_iommu.h >>> >>> diff --git a/hw/i386/Makefile.objs b/hw/i386/Makefile.objs >>> index b52d5b8..2f1a265 100644 >>> --- a/hw/i386/Makefile.objs >>> +++ b/hw/i386/Makefile.objs >>> @@ -3,6 +3,7 @@ obj-y += multiboot.o >>> obj-y += pc.o pc_piix.o pc_q35.o >>> obj-y += pc_sysfw.o >>> obj-y += intel_iommu.o >>> +obj-y += amd_iommu.o >>> obj-$(CONFIG_XEN) += ../xenpv/ xen/ >>> >>> obj-y += kvmvapic.o >>> diff --git a/hw/i386/amd_iommu.c b/hw/i386/amd_iommu.c >>> new file mode 100644 >>> index 000..3dac043 >>> --- /dev/null >>> +++ b/hw/i386/amd_iommu.c >>> @@ -0,0 +1,1432 @@ >>> +/* >>> + * QEMU emulation of AMD IOMMU (AMD-Vi) >>> + * >>> + * Copyright (C) 2011 Eduard - Gabriel Munteanu >>> + * Copyright (C) 2015 David Kiarie, >>> + * >>> + * This program is free software; you can redistribute it and/or modify >>> + * it under the terms of the GNU General Public License as published by >>> + * the Free Software Foundation; either version 2 of the License, or >>> + * (at your option) any later version. >>> + >>> + * This program is distributed in the hope that it will be useful, >>> + * but WITHOUT ANY WARRANTY; without even the implied warranty of >>> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the >>> + * GNU General Public License for more details. >>> + >>> + * You should have received a copy of the GNU General Public License >>> along >>> + * with this program; if not, see <http://www.gnu.org/licenses/>. >>> + * >>> + * Cache implementation inspired by hw/i386/intel_iommu.c >>> + * >>> + */ >>> +#include "hw/i386/amd_iommu.h" >>> + >>> +/*#define DEBUG_AMD_IOMMU*/ >>> +#ifdef DEBUG_AMD_IOMMU >>> +enum { >>> +DEBUG_GENERAL, DEBUG_CAPAB, DEBUG_MMIO, DEBUG_ELOG, >>> +DEBUG_CACHE, DEBUG_COMMAND, DEBUG_MMU >>> +}; >>> + >>> +#define IOMMU_DBGBIT(x) (1 << DEBUG_##x) >>> +static int iommu_dbgflags = IOMMU_DBGBIT(MMIO); >>> + >>> +#define IOMMU_DPRINTF(what, fmt, ...) do { \ >>> +if (iommu_dbgflags & IOMMU_DBGBIT(what)) { \ >>> +fprintf(stderr, "(amd-iommu)%s: " fmt "\n", __func__, \ >>> +## __VA_ARGS__); } \ >>> +} while (0) >>> +#else >>> +#define IOMMU_DPRINTF(what, fmt, ...) do {} while (0) >>> +#endif >>> + >>> +typedef struct AMDIOMMUAddressSpace { >>> +uint8_t bus_num;/* bus number >>> */ >>> +uint8_t devfn; /* device function >>> */ >>> +AMDIOMMUState *iommu_state; /* IOMMU - one per machine >>> */ >>> +MemoryRegion iommu; /* Device's iommu region >>> */ >>> +AddressSpace as;/* device's corresponding address space >>> */ >>> +} AMDIOMMUAddressSpace; >>> + >>> +/* IOMMU cache entry */ >>> +typedef struct IOMMUIOTLBEntry { >>> +uint64_t gfn; >>> +uint16_t domid; >>> +uint64_t devid; >>> +uint64_t perms; >>> +uint64_t translated_addr; >>> +} IOMMUIOTLBEntry; >>> + >>> +/* configure MMIO registers at startup/reset */ >>> +static void amd_iommu_set_quad(AMDIOMMUState *s, hwaddr addr, uint64_t >>> val, >>> + uint64_t romask, uint64_t w1cmask) >>> +{ >>> +stq_le_p(&s->mmior[addr], val); >>> +stq_le_p(&s->romask[addr], romask); >>> +s
Re: [Qemu-devel] [V6 1/4] hw/i386: Introduce AMD IOMMU
On Wed, Mar 2, 2016 at 7:00 AM, David Kiarie wrote: > On Fri, Feb 26, 2016 at 9:23 AM, David Kiarie wrote: >> On Thu, Feb 25, 2016 at 6:43 PM, Marcel Apfelbaum wrote: >>> On 02/21/2016 08:10 PM, David Kiarie wrote: >>>> >>>> Add AMD IOMMU emulaton to Qemu in addition to Intel IOMMU >>>> The IOMMU does basic translation, error checking and has a >>>> mininal IOTLB implementation >>> >>> >>> Hi, >>> >>>> >>>> Signed-off-by: David Kiarie >>>> --- >>>> hw/i386/Makefile.objs |1 + >>>> hw/i386/amd_iommu.c | 1432 >>>> + >>>> hw/i386/amd_iommu.h | 395 ++ >>>> include/hw/pci/pci.h |2 + >>>> 4 files changed, 1830 insertions(+) >>>> create mode 100644 hw/i386/amd_iommu.c >>>> create mode 100644 hw/i386/amd_iommu.h >>>> >>>> diff --git a/hw/i386/Makefile.objs b/hw/i386/Makefile.objs >>>> index b52d5b8..2f1a265 100644 >>>> --- a/hw/i386/Makefile.objs >>>> +++ b/hw/i386/Makefile.objs >>>> @@ -3,6 +3,7 @@ obj-y += multiboot.o >>>> obj-y += pc.o pc_piix.o pc_q35.o >>>> obj-y += pc_sysfw.o >>>> obj-y += intel_iommu.o >>>> +obj-y += amd_iommu.o >>>> obj-$(CONFIG_XEN) += ../xenpv/ xen/ >>>> >>>> obj-y += kvmvapic.o >>>> diff --git a/hw/i386/amd_iommu.c b/hw/i386/amd_iommu.c >>>> new file mode 100644 >>>> index 000..3dac043 >>>> --- /dev/null >>>> +++ b/hw/i386/amd_iommu.c >>>> @@ -0,0 +1,1432 @@ >>>> +/* >>>> + * QEMU emulation of AMD IOMMU (AMD-Vi) >>>> + * >>>> + * Copyright (C) 2011 Eduard - Gabriel Munteanu >>>> + * Copyright (C) 2015 David Kiarie, >>>> + * >>>> + * This program is free software; you can redistribute it and/or modify >>>> + * it under the terms of the GNU General Public License as published by >>>> + * the Free Software Foundation; either version 2 of the License, or >>>> + * (at your option) any later version. >>>> + >>>> + * This program is distributed in the hope that it will be useful, >>>> + * but WITHOUT ANY WARRANTY; without even the implied warranty of >>>> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the >>>> + * GNU General Public License for more details. >>>> + >>>> + * You should have received a copy of the GNU General Public License >>>> along >>>> + * with this program; if not, see <http://www.gnu.org/licenses/>. >>>> + * >>>> + * Cache implementation inspired by hw/i386/intel_iommu.c >>>> + * >>>> + */ >>>> +#include "hw/i386/amd_iommu.h" >>>> + >>>> +/*#define DEBUG_AMD_IOMMU*/ >>>> +#ifdef DEBUG_AMD_IOMMU >>>> +enum { >>>> +DEBUG_GENERAL, DEBUG_CAPAB, DEBUG_MMIO, DEBUG_ELOG, >>>> +DEBUG_CACHE, DEBUG_COMMAND, DEBUG_MMU >>>> +}; >>>> + >>>> +#define IOMMU_DBGBIT(x) (1 << DEBUG_##x) >>>> +static int iommu_dbgflags = IOMMU_DBGBIT(MMIO); >>>> + >>>> +#define IOMMU_DPRINTF(what, fmt, ...) do { \ >>>> +if (iommu_dbgflags & IOMMU_DBGBIT(what)) { \ >>>> +fprintf(stderr, "(amd-iommu)%s: " fmt "\n", __func__, \ >>>> +## __VA_ARGS__); } \ >>>> +} while (0) >>>> +#else >>>> +#define IOMMU_DPRINTF(what, fmt, ...) do {} while (0) >>>> +#endif >>>> + >>>> +typedef struct AMDIOMMUAddressSpace { >>>> +uint8_t bus_num;/* bus number >>>> */ >>>> +uint8_t devfn; /* device function >>>> */ >>>> +AMDIOMMUState *iommu_state; /* IOMMU - one per machine >>>> */ >>>> +MemoryRegion iommu; /* Device's iommu region >>>> */ >>>> +AddressSpace as;/* device's corresponding address space >>>> */ >>>> +} AMDIOMMUAddressSpace; >>>> + >>>> +/* IOMMU cache entry */ >>>> +typedef struct IOMMUIOTLBEntry { >>>> +uint64_t gfn; >>>> +uint16_t domid; >>>> +uint64_t devid; >>>> +uint64_t perms; >>>> +uint64_t translat
Re: [Qemu-devel] [V6 1/4] hw/i386: Introduce AMD IOMMU
On 25/02/16 18:43, Marcel Apfelbaum wrote: On 02/21/2016 08:10 PM, David Kiarie wrote: Add AMD IOMMU emulaton to Qemu in addition to Intel IOMMU The IOMMU does basic translation, error checking and has a mininal IOTLB implementation Hi, Signed-off-by: David Kiarie --- hw/i386/Makefile.objs |1 + hw/i386/amd_iommu.c | 1432 + hw/i386/amd_iommu.h | 395 ++ include/hw/pci/pci.h |2 + 4 files changed, 1830 insertions(+) create mode 100644 hw/i386/amd_iommu.c create mode 100644 hw/i386/amd_iommu.h diff --git a/hw/i386/Makefile.objs b/hw/i386/Makefile.objs index b52d5b8..2f1a265 100644 --- a/hw/i386/Makefile.objs +++ b/hw/i386/Makefile.objs @@ -3,6 +3,7 @@ obj-y += multiboot.o obj-y += pc.o pc_piix.o pc_q35.o obj-y += pc_sysfw.o obj-y += intel_iommu.o +obj-y += amd_iommu.o obj-$(CONFIG_XEN) += ../xenpv/ xen/ obj-y += kvmvapic.o diff --git a/hw/i386/amd_iommu.c b/hw/i386/amd_iommu.c new file mode 100644 index 000..3dac043 --- /dev/null +++ b/hw/i386/amd_iommu.c @@ -0,0 +1,1432 @@ +/* + * QEMU emulation of AMD IOMMU (AMD-Vi) + * + * Copyright (C) 2011 Eduard - Gabriel Munteanu + * Copyright (C) 2015 David Kiarie, + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License along + * with this program; if not, see <http://www.gnu.org/licenses/>. + * + * Cache implementation inspired by hw/i386/intel_iommu.c + * + */ +#include "hw/i386/amd_iommu.h" + +/*#define DEBUG_AMD_IOMMU*/ +#ifdef DEBUG_AMD_IOMMU +enum { +DEBUG_GENERAL, DEBUG_CAPAB, DEBUG_MMIO, DEBUG_ELOG, +DEBUG_CACHE, DEBUG_COMMAND, DEBUG_MMU +}; + +#define IOMMU_DBGBIT(x) (1 << DEBUG_##x) +static int iommu_dbgflags = IOMMU_DBGBIT(MMIO); + +#define IOMMU_DPRINTF(what, fmt, ...) do { \ +if (iommu_dbgflags & IOMMU_DBGBIT(what)) { \ +fprintf(stderr, "(amd-iommu)%s: " fmt "\n", __func__, \ +## __VA_ARGS__); } \ +} while (0) +#else +#define IOMMU_DPRINTF(what, fmt, ...) do {} while (0) +#endif + +typedef struct AMDIOMMUAddressSpace { +uint8_t bus_num;/* bus number */ +uint8_t devfn; /* device function */ +AMDIOMMUState *iommu_state; /* IOMMU - one per machine */ +MemoryRegion iommu; /* Device's iommu region*/ +AddressSpace as;/* device's corresponding address space */ +} AMDIOMMUAddressSpace; + +/* IOMMU cache entry */ +typedef struct IOMMUIOTLBEntry { +uint64_t gfn; +uint16_t domid; +uint64_t devid; +uint64_t perms; +uint64_t translated_addr; +} IOMMUIOTLBEntry; + +/* configure MMIO registers at startup/reset */ +static void amd_iommu_set_quad(AMDIOMMUState *s, hwaddr addr, uint64_t val, + uint64_t romask, uint64_t w1cmask) +{ +stq_le_p(&s->mmior[addr], val); +stq_le_p(&s->romask[addr], romask); +stq_le_p(&s->w1cmask[addr], w1cmask); +} + +static uint16_t amd_iommu_readw(AMDIOMMUState *s, hwaddr addr) +{ +return lduw_le_p(&s->mmior[addr]); +} + +static uint32_t amd_iommu_readl(AMDIOMMUState *s, hwaddr addr) +{ +return ldl_le_p(&s->mmior[addr]); +} + +static uint64_t amd_iommu_readq(AMDIOMMUState *s, hwaddr addr) +{ +return ldq_le_p(&s->mmior[addr]); +} + +/* internal write */ +static void amd_iommu_writeq_raw(AMDIOMMUState *s, uint64_t val, hwaddr addr) +{ +stq_le_p(&s->mmior[addr], val); +} + +/* external write */ +static void amd_iommu_writew(AMDIOMMUState *s, hwaddr addr, uint16_t val) +{ +uint16_t romask = lduw_le_p(&s->romask[addr]); +uint16_t w1cmask = lduw_le_p(&s->w1cmask[addr]); +uint16_t oldval = lduw_le_p(&s->mmior[addr]); +stw_le_p(&s->mmior[addr], (val & ~(val & w1cmask)) | (romask & oldval)); +} + +static void amd_iommu_writel(AMDIOMMUState *s, hwaddr addr, uint32_t val) +{ +uint32_t romask = ldl_le_p(&s->romask[addr]); +uint32_t w1cmask = ldl_le_p(&s->w1cmask[addr]); +uint32_t oldval = ldl_le_p(&s->mmior[addr]); +stl_le_p(&s->mmior[addr], (val & ~(val & w1cmask)) | (romask & oldval)); +} + +static void amd_iommu_writeq(AMDIOMMUState *s, hwaddr addr, uint64_t val) +{ +uint64_t romask = ldq_le_p(&s->romask[addr]); +uin
Re: [Qemu-devel] [V6 2/4] hw/core: Add AMD IOMMU to machine properties
On 21/02/16 23:09, Jan Kiszka wrote: On 2016-02-21 19:10, David Kiarie wrote: diff --git a/qemu-options.hx b/qemu-options.hx index 2f0465e..dad160f 100644 --- a/qemu-options.hx +++ b/qemu-options.hx @@ -38,7 +38,7 @@ DEF("machine", HAS_ARG, QEMU_OPTION_machine, \ "kvm_shadow_mem=size of KVM shadow MMU\n" "dump-guest-core=on|off include guest memory in a core dump (default=on)\n" "mem-merge=on|off controls memory merge support (default: on)\n" -"iommu=on|off controls emulated Intel IOMMU (VT-d) support (default=off)\n" +"iommu=amd|intel enables and selects the emulated IOMMU (default: off)\n" We should also support "iommu=off" or "none" to explicitly disable it. That is consistent with other switches, and maybe there will once be a machine type (chipset) with IOMMU enabled by default. We could have such but this will not be referenced anywhere in the code as the IOMMU is 'off' by default. Most of the other such switches relate to properties that are 'on' by default. Jan
Re: [Qemu-devel] [V6 0/4] AMD IOMMU
On 01/03/16 16:48, Jan Kiszka wrote: On 2016-03-01 14:07, Michael S. Tsirkin wrote: On Sun, Feb 21, 2016 at 09:10:56PM +0300, David Kiarie wrote: Hello there, Repost, AMD IOMMU patches version 6. Changes since version 5 -Fixed macro formating issues -changed occurences of IO MMU to IOMMU for consistency -Fixed capability registers duplication -Rebased to current master David Kiarie (4): hw/i386: Introduce AMD IOMMU hw/core: Add AMD IOMMU to machine properties hw/i386: ACPI table for AMD IOMMU hw/pci-host: Emulate AMD IOMMU I went over AMD IOMMU spec. I'm concerned that it appears that there's no chance for it to work correctly if host caches invalid PTE entries. The spec vaguely discusses write-protecting such PTEs but that would be very complex if it can be made to work at all. This means that this can't work with e.g. VFIO. It can only work with emulated devices. You mean it can't work if we program a real IOMMU (for VFIO) with translated data from the emulated one but cannot track any updates of the related page tables because the guest is not required to issue traceable flush requests? Hmm, too bad. OTOH VTD can easily support PTE shadowing by setting a flag. Do you mean RWBF=1 in the CAP register? Given that "Newer hardware implementations are expected to NOT require explicit software flushing of write buffers and report RWBF=0 in the Capability register", we may eventually run into guests that no longer check that flag if we expose something that looks like a "newer" implementation. However, this flag is not set right now in our VT-d model. I'd like us to find some way to avoid possibility of user error creating a configuration mixing e.g. vfio with the amd iommu. I'm not sure how to do this. Any idea? There is likely no way around write-protecting the IOMMU page tables (in KVM mode) once we evaluated and cached them somewhere. For now, I would simply deny vfio while an IOMMU is active on x86. Should I implement this, in the meantime ? Jan
Re: [Qemu-devel] [V6 4/4] hw/pci-host: Emulate AMD IOMMU
On Thu, Mar 3, 2016 at 12:17 AM, Michael S. Tsirkin wrote: > On Thu, Mar 03, 2016 at 12:09:28AM +0300, David Kiarie wrote: >> >> >> On 22/02/16 14:22, Marcel Apfelbaum wrote: >> >On 02/21/2016 08:11 PM, David Kiarie wrote: >> >>Add AMD IOMMU emulation support to q35 chipset >> >> >> >>Signed-off-by: David Kiarie >> >>--- >> >> hw/pci-host/piix.c| 1 + >> >> hw/pci-host/q35.c | 14 -- >> >> include/hw/i386/intel_iommu.h | 1 + >> >> 3 files changed, 14 insertions(+), 2 deletions(-) >> >> >> >>diff --git a/hw/pci-host/piix.c b/hw/pci-host/piix.c >> >>index 41aa66f..ab2e24a 100644 >> >>--- a/hw/pci-host/piix.c >> >>+++ b/hw/pci-host/piix.c >> >>@@ -36,6 +36,7 @@ >> >> #include "hw/i386/ioapic.h" >> >> #include "qapi/visitor.h" >> >> #include "qemu/error-report.h" >> >>+#include "hw/i386/amd_iommu.h" >> > >> >Hi, >> > >> >I think you don't need this include anymore. >> > >> >> >> >> /* >> >> * I440FX chipset data sheet. >> >>diff --git a/hw/pci-host/q35.c b/hw/pci-host/q35.c >> >>index 115fb8c..355fb32 100644 >> >>--- a/hw/pci-host/q35.c >> >>+++ b/hw/pci-host/q35.c >> >>@@ -31,6 +31,7 @@ >> >> #include "hw/hw.h" >> >> #include "hw/pci-host/q35.h" >> >> #include "qapi/visitor.h" >> >>+#include "hw/i386/amd_iommu.h" >> >> >> >>/ >> >> * Q35 host >> >>@@ -505,9 +506,18 @@ static void mch_realize(PCIDevice *d, Error **errp) >> >> mch->pci_address_space, &mch->pam_regions[i+1], >> >> PAM_EXPAN_BASE + i * PAM_EXPAN_SIZE, PAM_EXPAN_SIZE); >> >> } >> >>-/* Intel IOMMU (VT-d) */ >> >>-if (object_property_get_bool(qdev_get_machine(), "iommu", NULL)) { >> >>+ >> >>+if (g_strcmp0(MACHINE(qdev_get_machine())->iommu, INTEL_IOMMU_STR) >> >>== 0) { >> >>+/* Intel IOMMU (VT-d) */ >> >> mch_init_dmar(mch); >> >>+} else if (g_strcmp0(MACHINE(qdev_get_machine())->iommu, >> >>AMD_IOMMU_STR) >> >>+ == 0) { >> >>+AMDIOMMUState *iommu_state; >> >>+PCIDevice *iommu; >> >>+PCIBus *bus = PCI_BUS(qdev_get_parent_bus(DEVICE(mch))); >> >>+iommu = pci_create_simple(bus, 0x20, TYPE_AMD_IOMMU_DEVICE); > > Pls don't hardcode paths like this. Set addr property instead. > >> >>+iommu_state = AMD_IOMMU_DEVICE(iommu); >> >>+pci_setup_iommu(bus, bridge_host_amd_iommu, iommu_state); >> > >> >pci_setup_iommu third parameter is void*, so you don't need to cast to >> >AMDIOMMUState >> >before passing it. >> >> This include is necessary for the definition of "AMD_IOMMU_STR" either way >> so am leaving this as is. > > This option parsing is just too ugly. > > Looks like it was a mistake to support the iommu > machine property, but I see no reason to add to the > existing mess. > > Can't users create iommu with -device amd-iommu ? You mean getting rid of the above code and starting device with '-device amd-iommu' ? This way am not able to setup IOMMU regions for devices correctly. IIRC 'pci_setup_iommu' when called from IOMMU code sets up IOMMU region for IOMMU only. Calling this from the bus sets up IOMMU regions for all devices though. I need to setup IOMMU regions for all devices from the bus, to be able to do that I need to have created the IOMMU device first. > > It's necessary if we are to support multiple IOMMUs, anyway. > >> > >> >Thanks, >> >Marcel >> > >> >> } >> >> } >> >> >> >>diff --git a/include/hw/i386/intel_iommu.h >> >>b/include/hw/i386/intel_iommu.h >> >>index b024ffa..539530c 100644 >> >>--- a/include/hw/i386/intel_iommu.h >> >>+++ b/include/hw/i386/intel_iommu.h >> >>@@ -27,6 +27,7 @@ >> >> #define TYPE_INTEL_IOMMU_DEVICE "intel-iommu" >> >> #define INTEL_IOMMU_DEVICE(obj) \ >> >> OBJECT_CHECK(IntelIOMMUState, (obj), TYPE_INTEL_IOMMU_DEVICE) >> >>+#define INTEL_IOMMU_STR "intel" >> >> >> >> /* DMAR Hardware Unit Definition address (IOMMU unit) */ >> >> #define Q35_HOST_BRIDGE_IOMMU_ADDR 0xfed9ULL >> >> >> >
Re: [Qemu-devel] [V6 4/4] hw/pci-host: Emulate AMD IOMMU
On Thu, Mar 3, 2016 at 12:49 PM, Michael S. Tsirkin wrote: > On Thu, Mar 03, 2016 at 01:04:31AM +0300, David Kiarie wrote: >> On Thu, Mar 3, 2016 at 12:17 AM, Michael S. Tsirkin wrote: >> > On Thu, Mar 03, 2016 at 12:09:28AM +0300, David Kiarie wrote: >> >> >> >> >> >> On 22/02/16 14:22, Marcel Apfelbaum wrote: >> >> >On 02/21/2016 08:11 PM, David Kiarie wrote: >> >> >>Add AMD IOMMU emulation support to q35 chipset >> >> >> >> >> >>Signed-off-by: David Kiarie >> >> >>--- >> >> >> hw/pci-host/piix.c| 1 + >> >> >> hw/pci-host/q35.c | 14 -- >> >> >> include/hw/i386/intel_iommu.h | 1 + >> >> >> 3 files changed, 14 insertions(+), 2 deletions(-) >> >> >> >> >> >>diff --git a/hw/pci-host/piix.c b/hw/pci-host/piix.c >> >> >>index 41aa66f..ab2e24a 100644 >> >> >>--- a/hw/pci-host/piix.c >> >> >>+++ b/hw/pci-host/piix.c >> >> >>@@ -36,6 +36,7 @@ >> >> >> #include "hw/i386/ioapic.h" >> >> >> #include "qapi/visitor.h" >> >> >> #include "qemu/error-report.h" >> >> >>+#include "hw/i386/amd_iommu.h" >> >> > >> >> >Hi, >> >> > >> >> >I think you don't need this include anymore. >> >> > >> >> >> >> >> >> /* >> >> >> * I440FX chipset data sheet. >> >> >>diff --git a/hw/pci-host/q35.c b/hw/pci-host/q35.c >> >> >>index 115fb8c..355fb32 100644 >> >> >>--- a/hw/pci-host/q35.c >> >> >>+++ b/hw/pci-host/q35.c >> >> >>@@ -31,6 +31,7 @@ >> >> >> #include "hw/hw.h" >> >> >> #include "hw/pci-host/q35.h" >> >> >> #include "qapi/visitor.h" >> >> >>+#include "hw/i386/amd_iommu.h" >> >> >> >> >> >>/ >> >> >> * Q35 host >> >> >>@@ -505,9 +506,18 @@ static void mch_realize(PCIDevice *d, Error **errp) >> >> >> mch->pci_address_space, &mch->pam_regions[i+1], >> >> >> PAM_EXPAN_BASE + i * PAM_EXPAN_SIZE, PAM_EXPAN_SIZE); >> >> >> } >> >> >>-/* Intel IOMMU (VT-d) */ >> >> >>-if (object_property_get_bool(qdev_get_machine(), "iommu", NULL)) { >> >> >>+ >> >> >>+if (g_strcmp0(MACHINE(qdev_get_machine())->iommu, INTEL_IOMMU_STR) >> >> >>== 0) { >> >> >>+/* Intel IOMMU (VT-d) */ >> >> >> mch_init_dmar(mch); >> >> >>+} else if (g_strcmp0(MACHINE(qdev_get_machine())->iommu, >> >> >>AMD_IOMMU_STR) >> >> >>+ == 0) { >> >> >>+AMDIOMMUState *iommu_state; >> >> >>+PCIDevice *iommu; >> >> >>+PCIBus *bus = PCI_BUS(qdev_get_parent_bus(DEVICE(mch))); >> >> >>+iommu = pci_create_simple(bus, 0x20, TYPE_AMD_IOMMU_DEVICE); >> > >> > Pls don't hardcode paths like this. Set addr property instead. >> > >> >> >>+iommu_state = AMD_IOMMU_DEVICE(iommu); >> >> >>+pci_setup_iommu(bus, bridge_host_amd_iommu, iommu_state); >> >> > >> >> >pci_setup_iommu third parameter is void*, so you don't need to cast to >> >> >AMDIOMMUState >> >> >before passing it. >> >> >> >> This include is necessary for the definition of "AMD_IOMMU_STR" either way >> >> so am leaving this as is. >> > >> > This option parsing is just too ugly. >> > >> > Looks like it was a mistake to support the iommu >> > machine property, but I see no reason to add to the >> > existing mess. >> > >> > Can't users create iommu with -device amd-iommu ? >> >> You mean getting rid of the above code and starting device with >> '-device amd-iommu' ? This way am not able to setup IOMMU regions for >> devices correctly. IIRC 'pci_setup_iommu' when called from IOMMU code >> sets up IOMMU region for IOMMU only
Re: [Qemu-devel] [V6 4/4] hw/pci-host: Emulate AMD IOMMU
On Thu, Mar 3, 2016 at 3:06 PM, Marcel Apfelbaum wrote: > On 03/03/2016 02:02 PM, Marcel Apfelbaum wrote: >> >> On 03/03/2016 01:47 PM, David Kiarie wrote: >>> >>> On Thu, Mar 3, 2016 at 12:49 PM, Michael S. Tsirkin >>> wrote: >>>> >>>> On Thu, Mar 03, 2016 at 01:04:31AM +0300, David Kiarie wrote: >>>>> >>>>> On Thu, Mar 3, 2016 at 12:17 AM, Michael S. Tsirkin >>>>> wrote: >>>>>> >>>>>> On Thu, Mar 03, 2016 at 12:09:28AM +0300, David Kiarie wrote: >>>>>>> >>>>>>> >>>>>>> >>>>>>> On 22/02/16 14:22, Marcel Apfelbaum wrote: >>>>>>>> >>>>>>>> On 02/21/2016 08:11 PM, David Kiarie wrote: >>>>>>>>> >>>>>>>>> Add AMD IOMMU emulation support to q35 chipset >>>>>>>>> >>>>>>>>> Signed-off-by: David Kiarie >>>>>>>>> --- >>>>>>>>> hw/pci-host/piix.c| 1 + >>>>>>>>> hw/pci-host/q35.c | 14 -- >>>>>>>>> include/hw/i386/intel_iommu.h | 1 + >>>>>>>>> 3 files changed, 14 insertions(+), 2 deletions(-) >>>>>>>>> >>>>>>>>> diff --git a/hw/pci-host/piix.c b/hw/pci-host/piix.c >>>>>>>>> index 41aa66f..ab2e24a 100644 >>>>>>>>> --- a/hw/pci-host/piix.c >>>>>>>>> +++ b/hw/pci-host/piix.c >>>>>>>>> @@ -36,6 +36,7 @@ >>>>>>>>> #include "hw/i386/ioapic.h" >>>>>>>>> #include "qapi/visitor.h" >>>>>>>>> #include "qemu/error-report.h" >>>>>>>>> +#include "hw/i386/amd_iommu.h" >>>>>>>> >>>>>>>> >>>>>>>> Hi, >>>>>>>> >>>>>>>> I think you don't need this include anymore. >>>>>>>> >>>>>>>>> >>>>>>>>> /* >>>>>>>>>* I440FX chipset data sheet. >>>>>>>>> diff --git a/hw/pci-host/q35.c b/hw/pci-host/q35.c >>>>>>>>> index 115fb8c..355fb32 100644 >>>>>>>>> --- a/hw/pci-host/q35.c >>>>>>>>> +++ b/hw/pci-host/q35.c >>>>>>>>> @@ -31,6 +31,7 @@ >>>>>>>>> #include "hw/hw.h" >>>>>>>>> #include "hw/pci-host/q35.h" >>>>>>>>> #include "qapi/visitor.h" >>>>>>>>> +#include "hw/i386/amd_iommu.h" >>>>>>>>> >>>>>>>>> >>>>>>>>> / >>>>>>>>>* Q35 host >>>>>>>>> @@ -505,9 +506,18 @@ static void mch_realize(PCIDevice *d, Error >>>>>>>>> **errp) >>>>>>>>>mch->pci_address_space, &mch->pam_regions[i+1], >>>>>>>>>PAM_EXPAN_BASE + i * PAM_EXPAN_SIZE, >>>>>>>>> PAM_EXPAN_SIZE); >>>>>>>>> } >>>>>>>>> -/* Intel IOMMU (VT-d) */ >>>>>>>>> -if (object_property_get_bool(qdev_get_machine(), "iommu", >>>>>>>>> NULL)) { >>>>>>>>> + >>>>>>>>> +if (g_strcmp0(MACHINE(qdev_get_machine())->iommu, >>>>>>>>> INTEL_IOMMU_STR) >>>>>>>>> == 0) { >>>>>>>>> +/* Intel IOMMU (VT-d) */ >>>>>>>>> mch_init_dmar(mch); >>>>>>>>> +} else if (g_strcmp0(MACHINE(qdev_get_machine())->iommu, >>>>>>>>> AMD_IOMMU_STR) >>>>>>>>> + == 0) { >>>>>>>>> +AMDIOMMUState *iommu_state; >>>>>>>>> +PCIDevice *iommu; >>>>>>>>> +PCIBus *bus = PCI_BUS(qdev_get_parent_bus(DEVICE(mch))); >>>>>>>>> +iommu = pci_create_simple
Re: [Qemu-devel] [V6 4/4] hw/pci-host: Emulate AMD IOMMU
On Thu, Mar 3, 2016 at 12:49 PM, Michael S. Tsirkin wrote: > On Thu, Mar 03, 2016 at 01:04:31AM +0300, David Kiarie wrote: >> On Thu, Mar 3, 2016 at 12:17 AM, Michael S. Tsirkin wrote: >> > On Thu, Mar 03, 2016 at 12:09:28AM +0300, David Kiarie wrote: >> >> >> >> >> >> On 22/02/16 14:22, Marcel Apfelbaum wrote: >> >> >On 02/21/2016 08:11 PM, David Kiarie wrote: >> >> >>Add AMD IOMMU emulation support to q35 chipset >> >> >> >> >> >>Signed-off-by: David Kiarie >> >> >>--- >> >> >> hw/pci-host/piix.c| 1 + >> >> >> hw/pci-host/q35.c | 14 -- >> >> >> include/hw/i386/intel_iommu.h | 1 + >> >> >> 3 files changed, 14 insertions(+), 2 deletions(-) >> >> >> >> >> >>diff --git a/hw/pci-host/piix.c b/hw/pci-host/piix.c >> >> >>index 41aa66f..ab2e24a 100644 >> >> >>--- a/hw/pci-host/piix.c >> >> >>+++ b/hw/pci-host/piix.c >> >> >>@@ -36,6 +36,7 @@ >> >> >> #include "hw/i386/ioapic.h" >> >> >> #include "qapi/visitor.h" >> >> >> #include "qemu/error-report.h" >> >> >>+#include "hw/i386/amd_iommu.h" >> >> > >> >> >Hi, >> >> > >> >> >I think you don't need this include anymore. >> >> > >> >> >> >> >> >> /* >> >> >> * I440FX chipset data sheet. >> >> >>diff --git a/hw/pci-host/q35.c b/hw/pci-host/q35.c >> >> >>index 115fb8c..355fb32 100644 >> >> >>--- a/hw/pci-host/q35.c >> >> >>+++ b/hw/pci-host/q35.c >> >> >>@@ -31,6 +31,7 @@ >> >> >> #include "hw/hw.h" >> >> >> #include "hw/pci-host/q35.h" >> >> >> #include "qapi/visitor.h" >> >> >>+#include "hw/i386/amd_iommu.h" >> >> >> >> >> >>/ >> >> >> * Q35 host >> >> >>@@ -505,9 +506,18 @@ static void mch_realize(PCIDevice *d, Error **errp) >> >> >> mch->pci_address_space, &mch->pam_regions[i+1], >> >> >> PAM_EXPAN_BASE + i * PAM_EXPAN_SIZE, PAM_EXPAN_SIZE); >> >> >> } >> >> >>-/* Intel IOMMU (VT-d) */ >> >> >>-if (object_property_get_bool(qdev_get_machine(), "iommu", NULL)) { >> >> >>+ >> >> >>+if (g_strcmp0(MACHINE(qdev_get_machine())->iommu, INTEL_IOMMU_STR) >> >> >>== 0) { >> >> >>+/* Intel IOMMU (VT-d) */ >> >> >> mch_init_dmar(mch); >> >> >>+} else if (g_strcmp0(MACHINE(qdev_get_machine())->iommu, >> >> >>AMD_IOMMU_STR) >> >> >>+ == 0) { >> >> >>+AMDIOMMUState *iommu_state; >> >> >>+PCIDevice *iommu; >> >> >>+PCIBus *bus = PCI_BUS(qdev_get_parent_bus(DEVICE(mch))); >> >> >>+iommu = pci_create_simple(bus, 0x20, TYPE_AMD_IOMMU_DEVICE); >> > >> > Pls don't hardcode paths like this. Set addr property instead. >> > >> >> >>+iommu_state = AMD_IOMMU_DEVICE(iommu); >> >> >>+pci_setup_iommu(bus, bridge_host_amd_iommu, iommu_state); >> >> > >> >> >pci_setup_iommu third parameter is void*, so you don't need to cast to >> >> >AMDIOMMUState >> >> >before passing it. >> >> >> >> This include is necessary for the definition of "AMD_IOMMU_STR" either way >> >> so am leaving this as is. >> > >> > This option parsing is just too ugly. >> > >> > Looks like it was a mistake to support the iommu >> > machine property, but I see no reason to add to the >> > existing mess. >> > >> > Can't users create iommu with -device amd-iommu ? >> >> You mean getting rid of the above code and starting device with >> '-device amd-iommu' ? This way am not able to setup IOMMU regions for >> devices correctly. IIRC 'pci_setup_iommu' when called from IOMMU code >> sets up IOMMU region for IOMMU onl
Re: [Qemu-devel] [V6 4/4] hw/pci-host: Emulate AMD IOMMU
On Fri, Mar 11, 2016 at 4:22 PM, Michael S. Tsirkin wrote: > On Sun, Feb 21, 2016 at 09:11:00PM +0300, David Kiarie wrote: >> Add AMD IOMMU emulation support to q35 chipset >> >> Signed-off-by: David Kiarie >> --- >> hw/pci-host/piix.c| 1 + >> hw/pci-host/q35.c | 14 -- >> include/hw/i386/intel_iommu.h | 1 + >> 3 files changed, 14 insertions(+), 2 deletions(-) >> >> diff --git a/hw/pci-host/piix.c b/hw/pci-host/piix.c >> index 41aa66f..ab2e24a 100644 >> --- a/hw/pci-host/piix.c >> +++ b/hw/pci-host/piix.c >> @@ -36,6 +36,7 @@ >> #include "hw/i386/ioapic.h" >> #include "qapi/visitor.h" >> #include "qemu/error-report.h" >> +#include "hw/i386/amd_iommu.h" >> >> /* >> * I440FX chipset data sheet. > > Why is this needed? > >> diff --git a/hw/pci-host/q35.c b/hw/pci-host/q35.c >> index 115fb8c..355fb32 100644 >> --- a/hw/pci-host/q35.c >> +++ b/hw/pci-host/q35.c >> @@ -31,6 +31,7 @@ >> #include "hw/hw.h" >> #include "hw/pci-host/q35.h" >> #include "qapi/visitor.h" >> +#include "hw/i386/amd_iommu.h" >> >> >> / >> * Q35 host >> @@ -505,9 +506,18 @@ static void mch_realize(PCIDevice *d, Error **errp) >> mch->pci_address_space, &mch->pam_regions[i+1], >> PAM_EXPAN_BASE + i * PAM_EXPAN_SIZE, PAM_EXPAN_SIZE); >> } >> -/* Intel IOMMU (VT-d) */ >> -if (object_property_get_bool(qdev_get_machine(), "iommu", NULL)) { >> + >> +if (g_strcmp0(MACHINE(qdev_get_machine())->iommu, INTEL_IOMMU_STR) == >> 0) { >> +/* Intel IOMMU (VT-d) */ >> mch_init_dmar(mch); >> +} else if (g_strcmp0(MACHINE(qdev_get_machine())->iommu, AMD_IOMMU_STR) >> + == 0) { >> +AMDIOMMUState *iommu_state; >> +PCIDevice *iommu; >> +PCIBus *bus = PCI_BUS(qdev_get_parent_bus(DEVICE(mch))); >> +iommu = pci_create_simple(bus, 0x20, TYPE_AMD_IOMMU_DEVICE); > > address can be set through a property. I missed something here, what is the problem ?Is it the hardcoded address ? > >> +iommu_state = AMD_IOMMU_DEVICE(iommu); >> +pci_setup_iommu(bus, bridge_host_amd_iommu, iommu_state); > > > It would be better to move this chunk to a separate function. > >> } >> } >> >> diff --git a/include/hw/i386/intel_iommu.h b/include/hw/i386/intel_iommu.h >> index b024ffa..539530c 100644 >> --- a/include/hw/i386/intel_iommu.h >> +++ b/include/hw/i386/intel_iommu.h >> @@ -27,6 +27,7 @@ >> #define TYPE_INTEL_IOMMU_DEVICE "intel-iommu" >> #define INTEL_IOMMU_DEVICE(obj) \ >> OBJECT_CHECK(IntelIOMMUState, (obj), TYPE_INTEL_IOMMU_DEVICE) >> +#define INTEL_IOMMU_STR "intel" >> >> /* DMAR Hardware Unit Definition address (IOMMU unit) */ >> #define Q35_HOST_BRIDGE_IOMMU_ADDR 0xfed9ULL >> -- >> 2.1.4
[Qemu-devel] [V7 0/4] AMD IOMMU
Hello there, This series adds AMD IOMMU emulation support to Qemu. The only main change since V6 is: -Fixed a cache bug that caused the issue reported by Jan I have assummed that we are running one IOMMU and users don't have the freedom to run many IOMMUs. For instance, I've decided to stick with 'pci_create_simple' since if I change this and manually create the the device inorder to set the addr, I'll be repeating exactly what 'pci_create_simple' does while there is no immediate benefit. Being able to run multiple IOMMUs is a plus but at the moment I experience a few problems with the code while there is no immediate benefit. Other than these patches there's also an planned GSoC project to add features to feature-limited AMD IO MMU listed here[1]. It could also look at the the possibility of running multiple IOMMUs. GSoC is a program that offers students stipends to work on open source projects. You can read more about GSoC here[2]. Am a student and am willing to take up this IO MMU related project but I've not got a full mentor. Yeah, you're right, there are mentors listed on the project's details but they would only want to co-mentor as they may not have much time. They were listed there mainly for purposes of listing the project. I'd like to know if anyone is willing to mentor this project mainly the people involved in the review process or anyone else! David Kiarie (4): hw/i386: Introduce AMD IOMMU hw/i386: ACPI table for AMD IOMMU hw/core: Add AMD IOMMU to machine properties hw/pci-host: Emulate AMD IOMMU hw/core/machine.c | 27 +- hw/i386/Makefile.objs |1 + hw/i386/acpi-build.c | 98 ++- hw/i386/amd_iommu.c | 1431 + hw/i386/amd_iommu.h | 398 hw/pci-host/q35.c | 21 +- include/hw/acpi/acpi-defs.h | 55 ++ include/hw/boards.h |1 + include/hw/i386/intel_iommu.h |2 + include/hw/pci/pci.h |2 + qemu-options.hx |7 +- util/qemu-config.c|4 +- 12 files changed, 2027 insertions(+), 20 deletions(-) create mode 100644 hw/i386/amd_iommu.c create mode 100644 hw/i386/amd_iommu.h [1]http://qemu-project.org/Google_Summer_of_Code_2016#Qemu_AMD_IO_MMU_emulation [2]https://summerofcode.withgoogle.com/ -- 2.1.4
[Qemu-devel] [V7 3/4] hw/core: Add AMD IOMMU to machine properties
Add IOMMU as a string to machine properties which is used to control whether and the type of IOMMU to emulate Signed-off-by: David Kiarie --- hw/core/machine.c | 27 --- include/hw/boards.h | 1 + qemu-options.hx | 7 +-- util/qemu-config.c | 4 ++-- 4 files changed, 32 insertions(+), 7 deletions(-) diff --git a/hw/core/machine.c b/hw/core/machine.c index a8c4680..ce23b3d 100644 --- a/hw/core/machine.c +++ b/hw/core/machine.c @@ -14,6 +14,8 @@ #include "hw/boards.h" #include "qapi-visit.h" #include "qapi/visitor.h" +#include "hw/i386/amd_iommu.h" +#include "hw/i386/intel_iommu.h" #include "hw/sysbus.h" #include "sysemu/sysemu.h" #include "qemu/error-report.h" @@ -298,6 +300,20 @@ static void machine_set_iommu(Object *obj, bool value, Error **errp) ms->iommu = value; } +static bool machine_get_amd_iommu_override(Object *obj, Error **errp) +{ +MachineState *ms = MACHINE(obj); + +return ms->amd_iommu_type; +} + +static void machine_set_amd_iommu_override(Object *obj, bool value, Error **errp) +{ +MachineState *ms = MACHINE(obj); + +ms->amd_iommu_type = value; +} + static void machine_set_suppress_vmdesc(Object *obj, bool value, Error **errp) { MachineState *ms = MACHINE(obj); @@ -471,10 +487,15 @@ static void machine_initfn(Object *obj) "Firmware image", NULL); object_property_add_bool(obj, "iommu", - machine_get_iommu, - machine_set_iommu, NULL); +machine_get_iommu, machine_set_iommu, NULL); object_property_set_description(obj, "iommu", -"Set on/off to enable/disable Intel IOMMU (VT-d)", +"Set on to enable IOMMU emulation", +NULL); +object_property_add_bool(obj, "amd-iommu", +machine_get_amd_iommu_override, +machine_set_amd_iommu_override, NULL); +object_property_set_description(obj, "amd-iommu", +"Set on to override emulated IOMMU to AMD IOMMU", NULL); object_property_add_bool(obj, "suppress-vmdesc", machine_get_suppress_vmdesc, diff --git a/include/hw/boards.h b/include/hw/boards.h index b5d7eae..5bdd0bb 100644 --- a/include/hw/boards.h +++ b/include/hw/boards.h @@ -126,6 +126,7 @@ struct MachineState { bool igd_gfx_passthru; char *firmware; bool iommu; +bool amd_iommu_type; bool suppress_vmdesc; bool enforce_config_section; diff --git a/qemu-options.hx b/qemu-options.hx index 0cf7bb9..de3f02e 100644 --- a/qemu-options.hx +++ b/qemu-options.hx @@ -38,7 +38,8 @@ DEF("machine", HAS_ARG, QEMU_OPTION_machine, \ "kvm_shadow_mem=size of KVM shadow MMU\n" "dump-guest-core=on|off include guest memory in a core dump (default=on)\n" "mem-merge=on|off controls memory merge support (default: on)\n" -"iommu=on|off controls emulated Intel IOMMU (VT-d) support (default=off)\n" +"iommu=on|off controls emulated IOMMU support(default: off)\n" +"amd-iommu=on|off overrides emulated IOMMU to AMD IOMMU (default: off)\n" "igd-passthru=on|off controls IGD GFX passthrough support (default=off)\n" "aes-key-wrap=on|off controls support for AES key wrapping (default=on)\n" "dea-key-wrap=on|off controls support for DEA key wrapping (default=on)\n" @@ -74,7 +75,9 @@ Enables or disables memory merge support. This feature, when supported by the host, de-duplicates identical memory pages among VMs instances (enabled by default). @item iommu=on|off -Enables or disables emulated Intel IOMMU (VT-d) support. The default is off. +Enables and disables IOMMU emulation. The default is off. +@item amd-iommu=on|off +Overrides emulated IOMMU from AMD IOMMU. By default Intel IOMMU is emulated. @item aes-key-wrap=on|off Enables or disables AES key wrapping support on s390-ccw hosts. This feature controls whether AES wrapping keys will be created to allow diff --git a/util/qemu-config.c b/util/qemu-config.c index fb97307..f1b5a3b 100644 --- a/util/qemu-config.c +++ b/util/qemu-config.c @@ -213,8 +213,8 @@ static QemuOptsList machine_opts = { .help = "firmware image", },{ .name = "iommu", -.type = QEMU_OPT_BOOL, -.help = "Set on/off to enable/disable Intel IOMMU (VT-d)", +.type = QEMU_OPT_STRING, +.help = "Enables IOMMU and sets the emulated type", },{ .name = "suppress-vmdesc", .type = QEMU_OPT_BOOL, -- 2.1.4
[Qemu-devel] [V7 4/4] hw/pci-host: Emulate AMD IOMMU
Add AMD IOMMU emulation support to q35 chipset Signed-off-by: David Kiarie --- hw/pci-host/q35.c | 21 +++-- include/hw/i386/intel_iommu.h | 1 + 2 files changed, 20 insertions(+), 2 deletions(-) diff --git a/hw/pci-host/q35.c b/hw/pci-host/q35.c index 115fb8c..5f6298e 100644 --- a/hw/pci-host/q35.c +++ b/hw/pci-host/q35.c @@ -31,6 +31,7 @@ #include "hw/hw.h" #include "hw/pci-host/q35.h" #include "qapi/visitor.h" +#include "hw/i386/amd_iommu.h" / * Q35 host @@ -447,6 +448,19 @@ static void mch_init_dmar(MCHPCIState *mch) pci_setup_iommu(pci_bus, q35_host_dma_iommu, mch->iommu); } +static void mch_init_amdvi(MCHPCIState *mch) +{ +AMDIOMMUState *iommu_state; +PCIBus *bus = PCI_BUS(qdev_get_parent_bus(DEVICE(mch))); +PCIDevice *iommu; + +iommu = pci_create_simple(bus, 0x20, TYPE_AMD_IOMMU_DEVICE); + +iommu_state = AMD_IOMMU_DEVICE(iommu); + +pci_setup_iommu(bus, bridge_host_amd_iommu, iommu_state); +} + static void mch_realize(PCIDevice *d, Error **errp) { int i; @@ -505,8 +519,11 @@ static void mch_realize(PCIDevice *d, Error **errp) mch->pci_address_space, &mch->pam_regions[i+1], PAM_EXPAN_BASE + i * PAM_EXPAN_SIZE, PAM_EXPAN_SIZE); } -/* Intel IOMMU (VT-d) */ -if (object_property_get_bool(qdev_get_machine(), "iommu", NULL)) { + +if (object_property_get_bool(qdev_get_machine(), "iommu", NULL) && +object_property_get_bool(qdev_get_machine(), "amd-iommu", NULL)) { +mch_init_amdvi(mch); +} else if (object_property_get_bool(qdev_get_machine(), "iommu", NULL)) { mch_init_dmar(mch); } } diff --git a/include/hw/i386/intel_iommu.h b/include/hw/i386/intel_iommu.h index 7e511e1..5a520f3 100644 --- a/include/hw/i386/intel_iommu.h +++ b/include/hw/i386/intel_iommu.h @@ -28,6 +28,7 @@ #define TYPE_INTEL_IOMMU_DEVICE "intel-iommu" #define INTEL_IOMMU_DEVICE(obj) \ OBJECT_CHECK(IntelIOMMUState, (obj), TYPE_INTEL_IOMMU_DEVICE) +#define INTEL_IOMMU_STR "intel" /* DMAR Hardware Unit Definition address (IOMMU unit) */ #define Q35_HOST_BRIDGE_IOMMU_ADDR 0xfed9ULL -- 2.1.4
[Qemu-devel] [V7 2/4] hw/i386: ACPI table for AMD IOMMU
Add IVRS table for AMD IOMMU. Generate IVRS or DMAR depending on emulated IOMMU Signed-off-by: David Kiarie --- hw/i386/acpi-build.c | 98 ++- include/hw/acpi/acpi-defs.h | 55 include/hw/i386/intel_iommu.h | 1 + 3 files changed, 143 insertions(+), 11 deletions(-) diff --git a/hw/i386/acpi-build.c b/hw/i386/acpi-build.c index b888008..f6ab533 100644 --- a/hw/i386/acpi-build.c +++ b/hw/i386/acpi-build.c @@ -51,6 +51,7 @@ #include "hw/pci/pci_bus.h" #include "hw/pci-host/q35.h" #include "hw/i386/intel_iommu.h" +#include "hw/i386/amd_iommu.h" #include "hw/timer/hpet.h" #include "hw/acpi/aml-build.h" @@ -121,6 +122,12 @@ typedef struct AcpiBuildPciBusHotplugState { bool pcihp_bridge_en; } AcpiBuildPciBusHotplugState; +typedef enum iommu_type { +TYPE_AMD, +TYPE_INTEL, +TYPE_NONE +} iommu_type; + static int acpi_add_cpu_info(Object *o, void *opaque) { @@ -2542,6 +2549,78 @@ build_dmar_q35(GArray *table_data, GArray *linker) "DMAR", table_data->len - dmar_start, 1, NULL, NULL); } +static void +build_amd_iommu(GArray *table_data, GArray *linker) +{ +int iommu_start = table_data->len; +bool iommu_ambig; + +AcpiAMDIOMMUIVRS *ivrs; +AcpiAMDIOMMUHardwareUnit *iommu; + +/* IVRS definition */ +ivrs = acpi_data_push(table_data, sizeof(*ivrs)); +ivrs->revision = cpu_to_le16(ACPI_IOMMU_IVRS_TYPE); +ivrs->length = cpu_to_le16((sizeof(*ivrs) + sizeof(*iommu))); +ivrs->v_common_info = cpu_to_le64(AMD_IOMMU_HOST_ADDRESS_WIDTH << 8); + +AMDIOMMUState *s = (AMDIOMMUState *)object_resolve_path_type("", +TYPE_AMD_IOMMU_DEVICE, &iommu_ambig); + +/* IVDB definition - type 10h */ +iommu = acpi_data_push(table_data, sizeof(*iommu)); +if (!iommu_ambig) { +iommu->type = cpu_to_le16(0x10); +/* IVHD flags */ +iommu->flags = cpu_to_le16(iommu->flags); +iommu->flags = cpu_to_le16(IVHD_HT_TUNEN | IVHD_PPRSUP | IVHD_IOTLBSUP + | IVHD_PREFSUP); +iommu->length = cpu_to_le16(sizeof(*iommu)); +iommu->device_id = cpu_to_le16(PCI_DEVICE_ID_RD890_IOMMU); +iommu->capability_offset = cpu_to_le16(s->capab_offset); +iommu->mmio_base = cpu_to_le64(s->mmio.addr); +iommu->pci_segment = 0; +iommu->interrupt_info = 0; +/* EFR features */ +iommu->efr_register = cpu_to_le64(IVHD_EFR_GTSUP | IVHD_EFR_HATS + | IVHD_EFR_GATS); +iommu->efr_register = cpu_to_le64(iommu->efr_register); +/* device entries */ +memset(iommu->dev_entries, 0, 20); +/* Add device flags here + * This is are 4-byte device entries currently reporting the range of + * devices 00h - h; all devices + * + * Device setting affecting all devices should be made here + * + * Refer to + * (http://developer.amd.com/wordpress/media/2012/10/488821.pdf) + * 5.2.2.1 + */ +iommu->dev_entries[12] = 3; +iommu->dev_entries[16] = 4; +iommu->dev_entries[17] = 0xff; +iommu->dev_entries[18] = 0xff; +} + +build_header(linker, table_data, (void *)(table_data->data + iommu_start), + "IVRS", table_data->len - iommu_start, 1, NULL, NULL); +} + +static iommu_type has_iommu(void) +{ +bool ambiguous; + +if (object_resolve_path_type("", TYPE_AMD_IOMMU_DEVICE, &ambiguous) +&& !ambiguous) +return TYPE_AMD; +else if (object_resolve_path_type("", TYPE_INTEL_IOMMU_DEVICE, &ambiguous) +&& !ambiguous) +return TYPE_INTEL; +else +return TYPE_NONE; +} + static GArray * build_rsdp(GArray *rsdp_table, GArray *linker, unsigned rsdt) { @@ -2600,16 +2679,6 @@ static bool acpi_get_mcfg(AcpiMcfgInfo *mcfg) return true; } -static bool acpi_has_iommu(void) -{ -bool ambiguous; -Object *intel_iommu; - -intel_iommu = object_resolve_path_type("", TYPE_INTEL_IOMMU_DEVICE, - &ambiguous); -return intel_iommu && !ambiguous; -} - static bool acpi_has_nvdimm(void) { PCMachineState *pcms = PC_MACHINE(qdev_get_machine()); @@ -2630,6 +2699,7 @@ void acpi_build(AcpiBuildTables *tables) AcpiMcfgInfo mcfg; PcPciInfo pci; uint8_t *u; +iommu_type type = has_iommu(); size_t aml_len = 0; GArray *tables_blob = tables->table_data; AcpiSlicOem slic_oem = { .id = NULL, .table_id = NULL }; @@ -2696,7 +2766,13 @@ void acpi_build(AcpiBuildTables *tables) acpi_add_table(table_offsets, tables_blob); build_mcfg_q3
[Qemu-devel] [V7 1/4] hw/i386: Introduce AMD IOMMU
Add AMD IOMMU emulaton to Qemu in addition to Intel IOMMU The IOMMU does basic translation, error checking and has a mininal IOTLB implementation Signed-off-by: David Kiarie --- hw/i386/Makefile.objs |1 + hw/i386/amd_iommu.c | 1431 + hw/i386/amd_iommu.h | 398 ++ include/hw/pci/pci.h |2 + 4 files changed, 1832 insertions(+) create mode 100644 hw/i386/amd_iommu.c create mode 100644 hw/i386/amd_iommu.h diff --git a/hw/i386/Makefile.objs b/hw/i386/Makefile.objs index b52d5b8..2f1a265 100644 --- a/hw/i386/Makefile.objs +++ b/hw/i386/Makefile.objs @@ -3,6 +3,7 @@ obj-y += multiboot.o obj-y += pc.o pc_piix.o pc_q35.o obj-y += pc_sysfw.o obj-y += intel_iommu.o +obj-y += amd_iommu.o obj-$(CONFIG_XEN) += ../xenpv/ xen/ obj-y += kvmvapic.o diff --git a/hw/i386/amd_iommu.c b/hw/i386/amd_iommu.c new file mode 100644 index 000..ff967b3 --- /dev/null +++ b/hw/i386/amd_iommu.c @@ -0,0 +1,1431 @@ +/* + * QEMU emulation of AMD IOMMU (AMD-Vi) + * + * Copyright (C) 2011 Eduard - Gabriel Munteanu + * Copyright (C) 2015 David Kiarie, + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License along + * with this program; if not, see <http://www.gnu.org/licenses/>. + * + * Cache implementation inspired by hw/i386/intel_iommu.c + * + */ +#include "qemu/osdep.h" +#include "hw/i386/amd_iommu.h" + +/*#define DEBUG_AMD_IOMMU*/ +#ifdef DEBUG_AMD_IOMMU +enum { +DEBUG_GENERAL, DEBUG_CAPAB, DEBUG_MMIO, DEBUG_ELOG, +DEBUG_CACHE, DEBUG_COMMAND, DEBUG_MMU, DEBUG_CUSTOM +}; + +#define IOMMU_DBGBIT(x) (1 << DEBUG_##x) +static int iommu_dbgflags = IOMMU_DBGBIT(CUSTOM); + +#define IOMMU_DPRINTF(what, fmt, ...) do { \ +if (iommu_dbgflags & IOMMU_DBGBIT(what)) { \ +fprintf(stderr, "(amd-iommu)%s: " fmt "\n", __func__, \ +## __VA_ARGS__); } \ +} while (0) +#else +#define IOMMU_DPRINTF(what, fmt, ...) do {} while (0) +#endif + +#define ENCODE_EVENT(devid, info, addr, rshift) do { \ +*(uint16_t *)&evt[0] = devid; \ +*(uint8_t *)&evt[3] = info; \ +*(uint64_t *)&evt[4] = rshift ? cpu_to_le64(addr):\ + cpu_to_le64(addr) >> rshift; \ +} while (0) + +typedef struct AMDIOMMUAddressSpace { +uint8_t bus_num;/* bus number */ +uint8_t devfn; /* device function */ +AMDIOMMUState *iommu_state; /* IOMMU - one per machine */ +MemoryRegion iommu; /* Device's iommu region*/ +AddressSpace as;/* device's corresponding address space */ +} AMDIOMMUAddressSpace; + +/* IOMMU cache entry */ +typedef struct IOMMUIOTLBEntry { +uint64_t gfn; +uint16_t domid; +uint64_t devid; +uint64_t perms; +uint64_t translated_addr; +} IOMMUIOTLBEntry; + +/* configure MMIO registers at startup/reset */ +static void amd_iommu_set_quad(AMDIOMMUState *s, hwaddr addr, uint64_t val, + uint64_t romask, uint64_t w1cmask) +{ +stq_le_p(&s->mmior[addr], val); +stq_le_p(&s->romask[addr], romask); +stq_le_p(&s->w1cmask[addr], w1cmask); +} + +static uint16_t amd_iommu_readw(AMDIOMMUState *s, hwaddr addr) +{ +return lduw_le_p(&s->mmior[addr]); +} + +static uint32_t amd_iommu_readl(AMDIOMMUState *s, hwaddr addr) +{ +return ldl_le_p(&s->mmior[addr]); +} + +static uint64_t amd_iommu_readq(AMDIOMMUState *s, hwaddr addr) +{ +return ldq_le_p(&s->mmior[addr]); +} + +/* internal write */ +static void amd_iommu_writeq_raw(AMDIOMMUState *s, uint64_t val, hwaddr addr) +{ +stq_le_p(&s->mmior[addr], val); +} + +/* external write */ +static void amd_iommu_writew(AMDIOMMUState *s, hwaddr addr, uint16_t val) +{ +uint16_t romask = lduw_le_p(&s->romask[addr]); +uint16_t w1cmask = lduw_le_p(&s->w1cmask[addr]); +uint16_t oldval = lduw_le_p(&s->mmior[addr]); +stw_le_p(&s->mmior[addr], (val & ~(val & w1cmask)) | (romask & oldval)); +} + +static void amd_iommu_writel(AMDIOMMUState *s, hwaddr addr, uint32_t val) +{ +uint32_t romask = ldl_le_p(&s->romask[addr]); +uint32_t w1cmask = ldl_le_p(&s->w1cmask[addr]); +uint32_t oldval = ldl_le_p(&s->mmior[addr]); +stl_le_p(&s->mmior[
Re: [Qemu-devel] [V7 3/4] hw/core: Add AMD IOMMU to machine properties
On Mon, Mar 14, 2016 at 11:40 AM, Marcel Apfelbaum wrote: > On 03/14/2016 02:24 AM, David Kiarie wrote: >> >> Add IOMMU as a string to machine properties which is >> used to control whether and the type of IOMMU to emulate >> >> Signed-off-by: David Kiarie >> --- >> hw/core/machine.c | 27 --- >> include/hw/boards.h | 1 + >> qemu-options.hx | 7 +-- >> util/qemu-config.c | 4 ++-- >> 4 files changed, 32 insertions(+), 7 deletions(-) >> >> diff --git a/hw/core/machine.c b/hw/core/machine.c >> index a8c4680..ce23b3d 100644 >> --- a/hw/core/machine.c >> +++ b/hw/core/machine.c >> @@ -14,6 +14,8 @@ >> #include "hw/boards.h" >> #include "qapi-visit.h" >> #include "qapi/visitor.h" >> +#include "hw/i386/amd_iommu.h" >> +#include "hw/i386/intel_iommu.h" >> #include "hw/sysbus.h" >> #include "sysemu/sysemu.h" >> #include "qemu/error-report.h" >> @@ -298,6 +300,20 @@ static void machine_set_iommu(Object *obj, bool >> value, Error **errp) >> ms->iommu = value; >> } >> >> +static bool machine_get_amd_iommu_override(Object *obj, Error **errp) >> +{ >> +MachineState *ms = MACHINE(obj); >> + >> +return ms->amd_iommu_type; >> +} >> + >> +static void machine_set_amd_iommu_override(Object *obj, bool value, Error >> **errp) >> +{ >> +MachineState *ms = MACHINE(obj); >> + >> +ms->amd_iommu_type = value; >> +} >> + >> static void machine_set_suppress_vmdesc(Object *obj, bool value, Error >> **errp) >> { >> MachineState *ms = MACHINE(obj); >> @@ -471,10 +487,15 @@ static void machine_initfn(Object *obj) >> "Firmware image", >> NULL); >> object_property_add_bool(obj, "iommu", >> - machine_get_iommu, >> - machine_set_iommu, NULL); >> +machine_get_iommu, machine_set_iommu, NULL); >> object_property_set_description(obj, "iommu", >> -"Set on/off to enable/disable Intel >> IOMMU (VT-d)", >> +"Set on to enable IOMMU emulation", >> +NULL); >> +object_property_add_bool(obj, "amd-iommu", >> +machine_get_amd_iommu_override, >> +machine_set_amd_iommu_override, NULL); >> +object_property_set_description(obj, "amd-iommu", >> +"Set on to override emulated IOMMU to >> AMD IOMMU", >> NULL); >> object_property_add_bool(obj, "suppress-vmdesc", >>machine_get_suppress_vmdesc, >> diff --git a/include/hw/boards.h b/include/hw/boards.h >> index b5d7eae..5bdd0bb 100644 >> --- a/include/hw/boards.h >> +++ b/include/hw/boards.h >> @@ -126,6 +126,7 @@ struct MachineState { >> bool igd_gfx_passthru; >> char *firmware; >> bool iommu; >> +bool amd_iommu_type; >> bool suppress_vmdesc; >> bool enforce_config_section; >> >> diff --git a/qemu-options.hx b/qemu-options.hx >> index 0cf7bb9..de3f02e 100644 >> --- a/qemu-options.hx >> +++ b/qemu-options.hx >> @@ -38,7 +38,8 @@ DEF("machine", HAS_ARG, QEMU_OPTION_machine, \ >> "kvm_shadow_mem=size of KVM shadow MMU\n" >> "dump-guest-core=on|off include guest memory in a >> core dump (default=on)\n" >> "mem-merge=on|off controls memory merge support >> (default: on)\n" >> -"iommu=on|off controls emulated Intel IOMMU (VT-d) >> support (default=off)\n" >> +"iommu=on|off controls emulated IOMMU >> support(default: off)\n" >> +"amd-iommu=on|off overrides emulated IOMMU to AMD >> IOMMU (default: off)\n" > > > Hi David, > > I think this is a step backward from the last series (in my opinion). > Summarizing what Jan and Michael said, it should be: > iommu=on|off controls emulated IOMMU support(default: off) > x-iommu-type=intel|amd controls the IOMMU emulation type(default:
[Qemu-devel] [V8 0/4] AMD IOMMU
Hello all, Long time no see, at usual ;) AMD IOMMU patches fixing a few issues mentioned in previous version, formatting errors and commit messages David Kiarie (4): hw/i386: Introduce AMD IOMMU hw/i386: ACPI table for AMD IOMMU hw/core: Add AMD IOMMU to machine properties hw/pci-host: Emulate AMD IOMMU hw/core/machine.c | 32 +- hw/i386/Makefile.objs |1 + hw/i386/acpi-build.c | 98 ++- hw/i386/amd_iommu.c | 1426 + hw/i386/amd_iommu.h | 398 hw/pci-host/q35.c | 21 +- include/hw/acpi/acpi-defs.h | 55 ++ include/hw/boards.h |1 + include/hw/i386/intel_iommu.h |2 + include/hw/pci/pci.h |2 + qemu-options.hx |7 +- util/qemu-config.c|8 +- 12 files changed, 2031 insertions(+), 20 deletions(-) create mode 100644 hw/i386/amd_iommu.c create mode 100644 hw/i386/amd_iommu.h -- 2.1.4
[Qemu-devel] [V8 4/4] hw/pci-host: Emulate AMD IOMMU
Add AMD IOMMU emulation support to q35 chipset Signed-off-by: David Kiarie --- hw/pci-host/q35.c | 21 +++-- include/hw/i386/intel_iommu.h | 1 + 2 files changed, 20 insertions(+), 2 deletions(-) diff --git a/hw/pci-host/q35.c b/hw/pci-host/q35.c index 70f897e..37f8a84 100644 --- a/hw/pci-host/q35.c +++ b/hw/pci-host/q35.c @@ -32,6 +32,7 @@ #include "hw/pci-host/q35.h" #include "qapi/error.h" #include "qapi/visitor.h" +#include "hw/i386/amd_iommu.h" / * Q35 host @@ -448,6 +449,19 @@ static void mch_init_dmar(MCHPCIState *mch) pci_setup_iommu(pci_bus, q35_host_dma_iommu, mch->iommu); } +static void mch_init_amdvi(MCHPCIState *mch) +{ +AMDIOMMUState *iommu_state; +PCIBus *bus = PCI_BUS(qdev_get_parent_bus(DEVICE(mch))); +PCIDevice *iommu; + +iommu = pci_create_simple(bus, 0x20, TYPE_AMD_IOMMU_DEVICE); + +iommu_state = AMD_IOMMU_DEVICE(iommu); + +pci_setup_iommu(bus, bridge_host_amd_iommu, iommu_state); +} + static void mch_realize(PCIDevice *d, Error **errp) { int i; @@ -506,8 +520,11 @@ static void mch_realize(PCIDevice *d, Error **errp) mch->pci_address_space, &mch->pam_regions[i+1], PAM_EXPAN_BASE + i * PAM_EXPAN_SIZE, PAM_EXPAN_SIZE); } -/* Intel IOMMU (VT-d) */ -if (object_property_get_bool(qdev_get_machine(), "iommu", NULL)) { + +if (object_property_get_bool(qdev_get_machine(), "iommu", NULL) && +MACHINE(qdev_get_machine())->x_iommu_type) { +mch_init_amdvi(mch); +} else if (object_property_get_bool(qdev_get_machine(), "iommu", NULL)) { mch_init_dmar(mch); } } diff --git a/include/hw/i386/intel_iommu.h b/include/hw/i386/intel_iommu.h index 7e511e1..5a520f3 100644 --- a/include/hw/i386/intel_iommu.h +++ b/include/hw/i386/intel_iommu.h @@ -28,6 +28,7 @@ #define TYPE_INTEL_IOMMU_DEVICE "intel-iommu" #define INTEL_IOMMU_DEVICE(obj) \ OBJECT_CHECK(IntelIOMMUState, (obj), TYPE_INTEL_IOMMU_DEVICE) +#define INTEL_IOMMU_STR "intel" /* DMAR Hardware Unit Definition address (IOMMU unit) */ #define Q35_HOST_BRIDGE_IOMMU_ADDR 0xfed9ULL -- 2.1.4
[Qemu-devel] [V8 2/4] hw/i386: ACPI table for AMD IOMMU
Add IVRS table for AMD IOMMU. Generate IVRS or DMAR depending on emulated IOMMU Signed-off-by: David Kiarie --- hw/i386/acpi-build.c | 98 ++- include/hw/acpi/acpi-defs.h | 55 include/hw/i386/intel_iommu.h | 1 + 3 files changed, 143 insertions(+), 11 deletions(-) diff --git a/hw/i386/acpi-build.c b/hw/i386/acpi-build.c index 35180ef..a54a22c 100644 --- a/hw/i386/acpi-build.c +++ b/hw/i386/acpi-build.c @@ -52,6 +52,7 @@ #include "hw/pci/pci_bus.h" #include "hw/pci-host/q35.h" #include "hw/i386/intel_iommu.h" +#include "hw/i386/amd_iommu.h" #include "hw/timer/hpet.h" #include "hw/acpi/aml-build.h" @@ -118,6 +119,12 @@ typedef struct AcpiBuildPciBusHotplugState { bool pcihp_bridge_en; } AcpiBuildPciBusHotplugState; +typedef enum iommu_type { +TYPE_AMD, +TYPE_INTEL, +TYPE_NONE +} iommu_type; + static void acpi_get_pm_info(AcpiPmInfo *pm) { Object *piix = piix4_pm_find(); @@ -2588,6 +2595,78 @@ build_dmar_q35(GArray *table_data, GArray *linker) "DMAR", table_data->len - dmar_start, 1, NULL, NULL); } +static void +build_amd_iommu(GArray *table_data, GArray *linker) +{ +int iommu_start = table_data->len; +bool iommu_ambig; + +AcpiAMDIOMMUIVRS *ivrs; +AcpiAMDIOMMUHardwareUnit *iommu; + +/* IVRS definition */ +ivrs = acpi_data_push(table_data, sizeof(*ivrs)); +ivrs->revision = cpu_to_le16(ACPI_IOMMU_IVRS_TYPE); +ivrs->length = cpu_to_le16((sizeof(*ivrs) + sizeof(*iommu))); +ivrs->v_common_info = cpu_to_le64(AMD_IOMMU_HOST_ADDRESS_WIDTH << 8); + +AMDIOMMUState *s = (AMDIOMMUState *)object_resolve_path_type("", +TYPE_AMD_IOMMU_DEVICE, &iommu_ambig); + +/* IVDB definition - type 10h */ +iommu = acpi_data_push(table_data, sizeof(*iommu)); +if (!iommu_ambig) { +iommu->type = cpu_to_le16(0x10); +/* IVHD flags */ +iommu->flags = cpu_to_le16(iommu->flags); +iommu->flags = cpu_to_le16(IVHD_HT_TUNEN | IVHD_PPRSUP | IVHD_IOTLBSUP + | IVHD_PREFSUP); +iommu->length = cpu_to_le16(sizeof(*iommu)); +iommu->device_id = cpu_to_le16(PCI_DEVICE_ID_RD890_IOMMU); +iommu->capability_offset = cpu_to_le16(s->capab_offset); +iommu->mmio_base = cpu_to_le64(s->mmio.addr); +iommu->pci_segment = 0; +iommu->interrupt_info = 0; +/* EFR features */ +iommu->efr_register = cpu_to_le64(IVHD_EFR_GTSUP | IVHD_EFR_HATS + | IVHD_EFR_GATS); +iommu->efr_register = cpu_to_le64(iommu->efr_register); +/* device entries */ +memset(iommu->dev_entries, 0, 20); +/* Add device flags here + * This is are 4-byte device entries currently reporting the range of + * devices 00h - h; all devices + * + * Device setting affecting all devices should be made here + * + * Refer to + * (http://developer.amd.com/wordpress/media/2012/10/488821.pdf) + * 5.2.2.1 + */ +iommu->dev_entries[12] = 3; +iommu->dev_entries[16] = 4; +iommu->dev_entries[17] = 0xff; +iommu->dev_entries[18] = 0xff; +} + +build_header(linker, table_data, (void *)(table_data->data + iommu_start), + "IVRS", table_data->len - iommu_start, 1, NULL, NULL); +} + +static iommu_type has_iommu(void) +{ +bool ambiguous; + +if (object_resolve_path_type("", TYPE_AMD_IOMMU_DEVICE, &ambiguous) +&& !ambiguous) +return TYPE_AMD; +else if (object_resolve_path_type("", TYPE_INTEL_IOMMU_DEVICE, &ambiguous) +&& !ambiguous) +return TYPE_INTEL; +else +return TYPE_NONE; +} + static GArray * build_rsdp(GArray *rsdp_table, GArray *linker, unsigned rsdt) { @@ -2646,16 +2725,6 @@ static bool acpi_get_mcfg(AcpiMcfgInfo *mcfg) return true; } -static bool acpi_has_iommu(void) -{ -bool ambiguous; -Object *intel_iommu; - -intel_iommu = object_resolve_path_type("", TYPE_INTEL_IOMMU_DEVICE, - &ambiguous); -return intel_iommu && !ambiguous; -} - static void acpi_build(AcpiBuildTables *tables, MachineState *machine) { @@ -2668,6 +2737,7 @@ void acpi_build(AcpiBuildTables *tables, MachineState *machine) AcpiMcfgInfo mcfg; PcPciInfo pci; uint8_t *u; +iommu_type type = has_iommu(); size_t aml_len = 0; GArray *tables_blob = tables->table_data; AcpiSlicOem slic_oem = { .id = NULL, .table_id = NULL }; @@ -2733,7 +2803,13 @@ void acpi_build(AcpiBuildTables *tables, MachineState *machine) acpi_add_table(tabl
[Qemu-devel] [V8 1/4] hw/i386: Introduce AMD IOMMU
Add AMD IOMMU emulaton to Qemu in addition to Intel IOMMU The IOMMU does basic translation, error checking and has a minimal IOTLB implementation Signed-off-by: David Kiarie --- hw/i386/Makefile.objs |1 + hw/i386/amd_iommu.c | 1426 + hw/i386/amd_iommu.h | 398 ++ include/hw/pci/pci.h |2 + 4 files changed, 1827 insertions(+) create mode 100644 hw/i386/amd_iommu.c create mode 100644 hw/i386/amd_iommu.h diff --git a/hw/i386/Makefile.objs b/hw/i386/Makefile.objs index b52d5b8..2f1a265 100644 --- a/hw/i386/Makefile.objs +++ b/hw/i386/Makefile.objs @@ -3,6 +3,7 @@ obj-y += multiboot.o obj-y += pc.o pc_piix.o pc_q35.o obj-y += pc_sysfw.o obj-y += intel_iommu.o +obj-y += amd_iommu.o obj-$(CONFIG_XEN) += ../xenpv/ xen/ obj-y += kvmvapic.o diff --git a/hw/i386/amd_iommu.c b/hw/i386/amd_iommu.c new file mode 100644 index 000..66dbeb3 --- /dev/null +++ b/hw/i386/amd_iommu.c @@ -0,0 +1,1426 @@ +/* + * QEMU emulation of AMD IOMMU (AMD-Vi) + * + * Copyright (C) 2011 Eduard - Gabriel Munteanu + * Copyright (C) 2015 David Kiarie, + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License along + * with this program; if not, see <http://www.gnu.org/licenses/>. + * + * Cache implementation inspired by hw/i386/intel_iommu.c + * + */ +#include "qemu/osdep.h" +#include "hw/i386/amd_iommu.h" + +/*#define DEBUG_AMD_IOMMU*/ +#ifdef DEBUG_AMD_IOMMU +enum { +DEBUG_GENERAL, DEBUG_CAPAB, DEBUG_MMIO, DEBUG_ELOG, +DEBUG_CACHE, DEBUG_COMMAND, DEBUG_MMU, DEBUG_CUSTOM +}; + +#define IOMMU_DBGBIT(x) (1 << DEBUG_##x) +static int iommu_dbgflags = IOMMU_DBGBIT(CUSTOM); + +#define IOMMU_DPRINTF(what, fmt, ...) do { \ +if (iommu_dbgflags & IOMMU_DBGBIT(what)) { \ +fprintf(stderr, "(amd-iommu)%s: " fmt "\n", __func__, \ +## __VA_ARGS__); } \ +} while (0) +#else +#define IOMMU_DPRINTF(what, fmt, ...) do {} while (0) +#endif + +#define ENCODE_EVENT(devid, info, addr, rshift) do { \ +*(uint16_t *)&evt[0] = devid; \ +*(uint8_t *)&evt[3] = info; \ +*(uint64_t *)&evt[4] = rshift ? cpu_to_le64(addr) :\ + cpu_to_le64(addr) >> rshift; \ +} while (0) + +typedef struct AMDIOMMUAddressSpace { +uint8_t bus_num;/* bus number */ +uint8_t devfn; /* device function */ +AMDIOMMUState *iommu_state; /* IOMMU - one per machine */ +MemoryRegion iommu; /* Device's iommu region*/ +AddressSpace as;/* device's corresponding address space */ +} AMDIOMMUAddressSpace; + +/* IOMMU cache entry */ +typedef struct IOMMUIOTLBEntry { +uint64_t gfn; +uint16_t domid; +uint64_t devid; +uint64_t perms; +uint64_t translated_addr; +} IOMMUIOTLBEntry; + +/* configure MMIO registers at startup/reset */ +static void amd_iommu_set_quad(AMDIOMMUState *s, hwaddr addr, uint64_t val, + uint64_t romask, uint64_t w1cmask) +{ +stq_le_p(&s->mmior[addr], val); +stq_le_p(&s->romask[addr], romask); +stq_le_p(&s->w1cmask[addr], w1cmask); +} + +static uint16_t amd_iommu_readw(AMDIOMMUState *s, hwaddr addr) +{ +return lduw_le_p(&s->mmior[addr]); +} + +static uint32_t amd_iommu_readl(AMDIOMMUState *s, hwaddr addr) +{ +return ldl_le_p(&s->mmior[addr]); +} + +static uint64_t amd_iommu_readq(AMDIOMMUState *s, hwaddr addr) +{ +return ldq_le_p(&s->mmior[addr]); +} + +/* internal write */ +static void amd_iommu_writeq_raw(AMDIOMMUState *s, uint64_t val, hwaddr addr) +{ +stq_le_p(&s->mmior[addr], val); +} + +/* external write */ +static void amd_iommu_writew(AMDIOMMUState *s, hwaddr addr, uint16_t val) +{ +uint16_t romask = lduw_le_p(&s->romask[addr]); +uint16_t w1cmask = lduw_le_p(&s->w1cmask[addr]); +uint16_t oldval = lduw_le_p(&s->mmior[addr]); +stw_le_p(&s->mmior[addr], (val & ~(val & w1cmask)) | (romask & oldval)); +} + +static void amd_iommu_writel(AMDIOMMUState *s, hwaddr addr, uint32_t val) +{ +uint32_t romask = ldl_le_p(&s->romask[addr]); +uint32_t w1cmask = ldl_le_p(&s->w1cmask[addr]); +uint32_t oldval = ldl_le_p(&s->mmior[addr]); +stl_le_p(
[Qemu-devel] [V8 3/4] hw/core: Add AMD IOMMU to machine properties
Added a bool, subject to review to machine properties which it used to override iommu emulated from Intel to AMD. Signed-off-by: David Kiarie --- hw/core/machine.c | 32 +--- include/hw/boards.h | 1 + qemu-options.hx | 7 +-- util/qemu-config.c | 8 ++-- 4 files changed, 41 insertions(+), 7 deletions(-) diff --git a/hw/core/machine.c b/hw/core/machine.c index 6dbbc85..792641b 100644 --- a/hw/core/machine.c +++ b/hw/core/machine.c @@ -15,6 +15,8 @@ #include "qapi/error.h" #include "qapi-visit.h" #include "qapi/visitor.h" +#include "hw/i386/amd_iommu.h" +#include "hw/i386/intel_iommu.h" #include "hw/sysbus.h" #include "sysemu/sysemu.h" #include "qemu/error-report.h" @@ -300,6 +302,26 @@ static void machine_set_iommu(Object *obj, bool value, Error **errp) ms->iommu = value; } +static void machine_set_iommu_override(Object *obj, const char *value, + Error **errp) +{ +MachineState *ms = MACHINE(obj); +Error *err = NULL; + +ms->x_iommu_type = false; +/* ensure a valid iommu type */ +if (g_strcmp0(value, AMD_IOMMU_STR) && +g_strcmp0(value, INTEL_IOMMU_STR)) { +error_setg(errp, "Invalid IOMMU type %s", value); +error_propagate(errp, err); +return; +} + +if ((g_strcmp0(value, AMD_IOMMU_STR) == 0)) { +ms->x_iommu_type = true; +} +} + static void machine_set_suppress_vmdesc(Object *obj, bool value, Error **errp) { MachineState *ms = MACHINE(obj); @@ -473,10 +495,14 @@ static void machine_initfn(Object *obj) "Firmware image", NULL); object_property_add_bool(obj, "iommu", - machine_get_iommu, - machine_set_iommu, NULL); + machine_get_iommu, machine_set_iommu, NULL); object_property_set_description(obj, "iommu", -"Set on/off to enable/disable Intel IOMMU (VT-d)", +"Set on to enable IOMMU emulation", +NULL); +object_property_add_str(obj, "x-iommu-type", +NULL, machine_set_iommu_override, NULL); +object_property_set_description(obj, "x-iommu-type", +"Set on to override emulated IOMMU to AMD IOMMU", NULL); object_property_add_bool(obj, "suppress-vmdesc", machine_get_suppress_vmdesc, diff --git a/include/hw/boards.h b/include/hw/boards.h index aad5f2a..07788fc 100644 --- a/include/hw/boards.h +++ b/include/hw/boards.h @@ -151,6 +151,7 @@ struct MachineState { bool igd_gfx_passthru; char *firmware; bool iommu; +bool x_iommu_type; bool suppress_vmdesc; bool enforce_config_section; diff --git a/qemu-options.hx b/qemu-options.hx index a770086..14d30b7 100644 --- a/qemu-options.hx +++ b/qemu-options.hx @@ -38,7 +38,8 @@ DEF("machine", HAS_ARG, QEMU_OPTION_machine, \ "kvm_shadow_mem=size of KVM shadow MMU\n" "dump-guest-core=on|off include guest memory in a core dump (default=on)\n" "mem-merge=on|off controls memory merge support (default: on)\n" -"iommu=on|off controls emulated Intel IOMMU (VT-d) support (default=off)\n" +"iommu=on|off controls emulated IOMMU support(default: off)\n" +"x-iommu-type=amd|intel overrides emulated IOMMU to AMD IOMMU (default: intel)\n" "igd-passthru=on|off controls IGD GFX passthrough support (default=off)\n" "aes-key-wrap=on|off controls support for AES key wrapping (default=on)\n" "dea-key-wrap=on|off controls support for DEA key wrapping (default=on)\n" @@ -74,7 +75,9 @@ Enables or disables memory merge support. This feature, when supported by the host, de-duplicates identical memory pages among VMs instances (enabled by default). @item iommu=on|off -Enables or disables emulated Intel IOMMU (VT-d) support. The default is off. +Enables and disables IOMMU emulation. The default is off. +@item x-iommu-type=on|off +Overrides emulated IOMMU from AMD IOMMU. By default Intel IOMMU is emulated. @item aes-key-wrap=on|off Enables or disables AES key wrapping support on s390-ccw hosts. This feature controls whether AES wrapping keys will be created to allow diff --git a/util/qemu-config.c b/util/qemu-config.c index fb97307..8886abf 100644 --- a/util/qemu-config.c +++ b/util/
[Qemu-devel] [V9 0/4] AMD IOMMU
Hi all, The current AMD IOMMU patches that fixes Igor's comments. I got rid of structs and instead added individual integer fields into the table data directly, as suggested. I have also got rid of some un-used macros and fixed a few other miscellaneous things. David Kiarie (4): hw/i386: Introduce AMD IOMMU hw/i386: ACPI table for AMD IOMMU hw/core: Add AMD IOMMU to machine properties hw/pci-host: Emulate AMD IOMMU hw/acpi/aml-build.c |2 +- hw/acpi/core.c| 13 - hw/core/machine.c | 32 +- hw/i386/Makefile.objs |1 + hw/i386/acpi-build.c | 101 ++- hw/i386/amd_iommu.c | 1426 + hw/i386/amd_iommu.h | 398 hw/pci-host/q35.c | 21 +- include/hw/acpi/acpi-defs.h | 14 + include/hw/acpi/acpi.h| 16 + include/hw/acpi/aml-build.h |1 + include/hw/boards.h |1 + include/hw/i386/intel_iommu.h |1 + include/hw/pci/pci.h |2 + qemu-options.hx |7 +- util/qemu-config.c|8 +- 16 files changed, 2010 insertions(+), 34 deletions(-) create mode 100644 hw/i386/amd_iommu.c create mode 100644 hw/i386/amd_iommu.h -- 2.1.4
[Qemu-devel] [V9 3/4] hw/core: Add AMD IOMMU to machine properties
Added a bool, subject to review to machine properties which it used to override iommu emulated from Intel to AMD. Signed-off-by: David Kiarie --- hw/core/machine.c | 32 +--- include/hw/boards.h | 1 + include/hw/i386/intel_iommu.h | 1 + qemu-options.hx | 7 +-- util/qemu-config.c| 8 ++-- 5 files changed, 42 insertions(+), 7 deletions(-) diff --git a/hw/core/machine.c b/hw/core/machine.c index 6dbbc85..792641b 100644 --- a/hw/core/machine.c +++ b/hw/core/machine.c @@ -15,6 +15,8 @@ #include "qapi/error.h" #include "qapi-visit.h" #include "qapi/visitor.h" +#include "hw/i386/amd_iommu.h" +#include "hw/i386/intel_iommu.h" #include "hw/sysbus.h" #include "sysemu/sysemu.h" #include "qemu/error-report.h" @@ -300,6 +302,26 @@ static void machine_set_iommu(Object *obj, bool value, Error **errp) ms->iommu = value; } +static void machine_set_iommu_override(Object *obj, const char *value, + Error **errp) +{ +MachineState *ms = MACHINE(obj); +Error *err = NULL; + +ms->x_iommu_type = false; +/* ensure a valid iommu type */ +if (g_strcmp0(value, AMD_IOMMU_STR) && +g_strcmp0(value, INTEL_IOMMU_STR)) { +error_setg(errp, "Invalid IOMMU type %s", value); +error_propagate(errp, err); +return; +} + +if ((g_strcmp0(value, AMD_IOMMU_STR) == 0)) { +ms->x_iommu_type = true; +} +} + static void machine_set_suppress_vmdesc(Object *obj, bool value, Error **errp) { MachineState *ms = MACHINE(obj); @@ -473,10 +495,14 @@ static void machine_initfn(Object *obj) "Firmware image", NULL); object_property_add_bool(obj, "iommu", - machine_get_iommu, - machine_set_iommu, NULL); + machine_get_iommu, machine_set_iommu, NULL); object_property_set_description(obj, "iommu", -"Set on/off to enable/disable Intel IOMMU (VT-d)", +"Set on to enable IOMMU emulation", +NULL); +object_property_add_str(obj, "x-iommu-type", +NULL, machine_set_iommu_override, NULL); +object_property_set_description(obj, "x-iommu-type", +"Set on to override emulated IOMMU to AMD IOMMU", NULL); object_property_add_bool(obj, "suppress-vmdesc", machine_get_suppress_vmdesc, diff --git a/include/hw/boards.h b/include/hw/boards.h index 8d4fe56..5a12a1c 100644 --- a/include/hw/boards.h +++ b/include/hw/boards.h @@ -152,6 +152,7 @@ struct MachineState { bool igd_gfx_passthru; char *firmware; bool iommu; +bool x_iommu_type; bool suppress_vmdesc; bool enforce_config_section; diff --git a/include/hw/i386/intel_iommu.h b/include/hw/i386/intel_iommu.h index b024ffa..7e511e1 100644 --- a/include/hw/i386/intel_iommu.h +++ b/include/hw/i386/intel_iommu.h @@ -24,6 +24,7 @@ #include "hw/qdev.h" #include "sysemu/dma.h" +#define INTEL_IOMMU_STR "intel" #define TYPE_INTEL_IOMMU_DEVICE "intel-iommu" #define INTEL_IOMMU_DEVICE(obj) \ OBJECT_CHECK(IntelIOMMUState, (obj), TYPE_INTEL_IOMMU_DEVICE) diff --git a/qemu-options.hx b/qemu-options.hx index 6106520..81217d3 100644 --- a/qemu-options.hx +++ b/qemu-options.hx @@ -38,7 +38,8 @@ DEF("machine", HAS_ARG, QEMU_OPTION_machine, \ "kvm_shadow_mem=size of KVM shadow MMU\n" "dump-guest-core=on|off include guest memory in a core dump (default=on)\n" "mem-merge=on|off controls memory merge support (default: on)\n" -"iommu=on|off controls emulated Intel IOMMU (VT-d) support (default=off)\n" +"iommu=on|off controls emulated IOMMU support(default: off)\n" +"x-iommu-type=amd|intel overrides emulated IOMMU to AMD IOMMU (default: intel)\n" "igd-passthru=on|off controls IGD GFX passthrough support (default=off)\n" "aes-key-wrap=on|off controls support for AES key wrapping (default=on)\n" "dea-key-wrap=on|off controls support for DEA key wrapping (default=on)\n" @@ -74,7 +75,9 @@ Enables or disables memory merge support. This feature, when supported by the host, de-duplicates identical memory pages among VMs instances (enabled by default). @item iommu=on
[Qemu-devel] [V9 2/4] hw/i386: ACPI table for AMD IOMMU
Add IVRS table for AMD IOMMU. Generate IVRS or DMAR depending on emulated IOMMU Signed-off-by: David Kiarie --- hw/acpi/aml-build.c | 2 +- hw/acpi/core.c | 13 -- hw/i386/acpi-build.c| 101 +++- include/hw/acpi/acpi-defs.h | 14 ++ include/hw/acpi/acpi.h | 16 +++ include/hw/acpi/aml-build.h | 1 + 6 files changed, 122 insertions(+), 25 deletions(-) diff --git a/hw/acpi/aml-build.c b/hw/acpi/aml-build.c index ab89ca6..da11bf8 100644 --- a/hw/acpi/aml-build.c +++ b/hw/acpi/aml-build.c @@ -227,7 +227,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; diff --git a/hw/acpi/core.c b/hw/acpi/core.c index 7925a1a..ee0e687 100644 --- a/hw/acpi/core.c +++ b/hw/acpi/core.c @@ -29,19 +29,6 @@ #include "qapi-visit.h" #include "qapi-event.h" -struct acpi_table_header { -uint16_t _length; /* our length, not actual part of the hdr */ - /* allows easier parsing for fw_cfg clients */ -char sig[4]; /* ACPI signature (4 ASCII characters) */ -uint32_t length; /* Length of table, in bytes, including header */ -uint8_t revision; /* ACPI Specification minor version # */ -uint8_t checksum; /* To make sum of entire table == 0 */ -char oem_id[6]; /* OEM identification */ -char oem_table_id[8]; /* OEM table identification */ -uint32_t oem_revision;/* OEM revision number */ -char asl_compiler_id[4]; /* ASL compiler vendor ID */ -uint32_t asl_compiler_revision; /* ASL compiler revision number */ -} QEMU_PACKED; #define ACPI_TABLE_HDR_SIZE sizeof(struct acpi_table_header) #define ACPI_TABLE_PFX_SIZE sizeof(uint16_t) /* size of the extra prefix */ diff --git a/hw/i386/acpi-build.c b/hw/i386/acpi-build.c index 6477003..19efc68 100644 --- a/hw/i386/acpi-build.c +++ b/hw/i386/acpi-build.c @@ -52,6 +52,7 @@ #include "hw/pci/pci_bus.h" #include "hw/pci-host/q35.h" #include "hw/i386/intel_iommu.h" +#include "hw/i386/amd_iommu.h" #include "hw/timer/hpet.h" #include "hw/acpi/aml-build.h" @@ -118,6 +119,12 @@ typedef struct AcpiBuildPciBusHotplugState { bool pcihp_bridge_en; } AcpiBuildPciBusHotplugState; +typedef enum IommuType { +TYPE_AMD, +TYPE_INTEL, +TYPE_NONE +} IommuType; + static void acpi_get_pm_info(AcpiPmInfo *pm) { Object *piix = piix4_pm_find(); @@ -2598,6 +2605,81 @@ build_dmar_q35(GArray *table_data, GArray *linker) "DMAR", table_data->len - dmar_start, 1, NULL, NULL); } +#define IOMMU_IVRS_LENGTH 0x30 +/* increase ivdb length if more devices are added */ +#define IOMMU_IVDB_LENGTH 0x20 + +static void +build_amd_iommu(GArray *table_data, GArray *linker) +{ +int iommu_start = table_data->len; +bool iommu_ambig; + +/* IVRS definition - table header has an extra 2-byte field */ +acpi_data_push(table_data, (sizeof(acpi_table_header) - 2)); +/* common virtualization information */ +build_append_int_noprefix(table_data, AMD_IOMMU_HOST_ADDRESS_WIDTH << 8, 4); +/* reserved */ +build_append_int_noprefix(table_data, 0, 8); + +AMDIOMMUState *s = (AMDIOMMUState *)object_resolve_path_type("", +TYPE_AMD_IOMMU_DEVICE, &iommu_ambig); + +/* IVDB definition - type 10h */ +if (!iommu_ambig) { +/* IVHD definition - type 10h */ +build_append_int_noprefix(table_data, 0x10, 1); +/* virtualization flags */ +build_append_int_noprefix(table_data, (IVHD_HT_TUNEN | + IVHD_PPRSUP | IVHD_IOTLBSUP | IVHD_PREFSUP), 1); +/* ivhd length */ +build_append_int_noprefix(table_data, IOMMU_IVDB_LENGTH, 2); +/* iommu device id */ +build_append_int_noprefix(table_data, PCI_DEVICE_ID_RD890_IOMMU, 2); +/* offset of capability registers */ +build_append_int_noprefix(table_data, s->capab_offset, 2); +/* mmio base register */ +build_append_int_noprefix(table_data, s->mmio.addr, 8); +/* pci segment */ +build_append_int_noprefix(table_data, 0, 2); +/* interrupt numbers */ +build_append_int_noprefix(table_data, 0, 2); +/* feature reporting */ +build_append_int_noprefix(table_data, (IVHD_EFR_GTSUP | +IVHD_EFR_HATS | IVHD_EFR_GATS), 4); +/* Add device flags here + * This is are 4-byte device entries currently reporting the range of + * devices 00h - h; all devices + * Device setting affecting all devices should be made here + *
[Qemu-devel] [V9 1/4] hw/i386: Introduce AMD IOMMU
Add AMD IOMMU emulaton to Qemu in addition to Intel IOMMU The IOMMU does basic translation, error checking and has a minimal IOTLB implementation Signed-off-by: David Kiarie --- hw/i386/Makefile.objs |1 + hw/i386/amd_iommu.c | 1426 + hw/i386/amd_iommu.h | 398 ++ include/hw/pci/pci.h |2 + 4 files changed, 1827 insertions(+) create mode 100644 hw/i386/amd_iommu.c create mode 100644 hw/i386/amd_iommu.h diff --git a/hw/i386/Makefile.objs b/hw/i386/Makefile.objs index b52d5b8..2f1a265 100644 --- a/hw/i386/Makefile.objs +++ b/hw/i386/Makefile.objs @@ -3,6 +3,7 @@ obj-y += multiboot.o obj-y += pc.o pc_piix.o pc_q35.o obj-y += pc_sysfw.o obj-y += intel_iommu.o +obj-y += amd_iommu.o obj-$(CONFIG_XEN) += ../xenpv/ xen/ obj-y += kvmvapic.o diff --git a/hw/i386/amd_iommu.c b/hw/i386/amd_iommu.c new file mode 100644 index 000..96ed8c3 --- /dev/null +++ b/hw/i386/amd_iommu.c @@ -0,0 +1,1426 @@ +/* + * QEMU emulation of AMD IOMMU (AMD-Vi) + * + * Copyright (C) 2011 Eduard - Gabriel Munteanu + * Copyright (C) 2015 David Kiarie, + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License along + * with this program; if not, see <http://www.gnu.org/licenses/>. + * + * Cache implementation inspired by hw/i386/intel_iommu.c + * + */ +#include "qemu/osdep.h" +#include "hw/i386/amd_iommu.h" + +/*#define DEBUG_AMD_IOMMU*/ +#ifdef DEBUG_AMD_IOMMU +enum { +DEBUG_GENERAL, DEBUG_CAPAB, DEBUG_MMIO, DEBUG_ELOG, +DEBUG_CACHE, DEBUG_COMMAND, DEBUG_MMU, DEBUG_CUSTOM +}; + +#define IOMMU_DBGBIT(x) (1 << DEBUG_##x) +static int iommu_dbgflags = IOMMU_DBGBIT(CUSTOM); + +#define IOMMU_DPRINTF(what, fmt, ...) do { \ +if (iommu_dbgflags & IOMMU_DBGBIT(what)) { \ +fprintf(stderr, "(amd-iommu)%s: " fmt "\n", __func__, \ +## __VA_ARGS__); } \ +} while (0) +#else +#define IOMMU_DPRINTF(what, fmt, ...) do {} while (0) +#endif + +#define ENCODE_EVENT(devid, info, addr, rshift) do { \ +*(uint16_t *)&evt[0] = devid; \ +*(uint8_t *)&evt[3] = info; \ +*(uint64_t *)&evt[4] = rshift ? cpu_to_le64(addr) :\ + cpu_to_le64(addr) >> rshift; \ +} while (0) + +typedef struct AMDIOMMUAddressSpace { +uint8_t bus_num;/* bus number */ +uint8_t devfn; /* device function */ +AMDIOMMUState *iommu_state; /* IOMMU - one per machine */ +MemoryRegion iommu; /* Device's iommu region*/ +AddressSpace as;/* device's corresponding address space */ +} AMDIOMMUAddressSpace; + +/* IOMMU cache entry */ +typedef struct IOMMUIOTLBEntry { +uint64_t gfn; +uint16_t domid; +uint64_t devid; +uint64_t perms; +uint64_t translated_addr; +} IOMMUIOTLBEntry; + +/* configure MMIO registers at startup/reset */ +static void amd_iommu_set_quad(AMDIOMMUState *s, hwaddr addr, uint64_t val, + uint64_t romask, uint64_t w1cmask) +{ +stq_le_p(&s->mmior[addr], val); +stq_le_p(&s->romask[addr], romask); +stq_le_p(&s->w1cmask[addr], w1cmask); +} + +static uint16_t amd_iommu_readw(AMDIOMMUState *s, hwaddr addr) +{ +return lduw_le_p(&s->mmior[addr]); +} + +static uint32_t amd_iommu_readl(AMDIOMMUState *s, hwaddr addr) +{ +return ldl_le_p(&s->mmior[addr]); +} + +static uint64_t amd_iommu_readq(AMDIOMMUState *s, hwaddr addr) +{ +return ldq_le_p(&s->mmior[addr]); +} + +/* internal write */ +static void amd_iommu_writeq_raw(AMDIOMMUState *s, uint64_t val, hwaddr addr) +{ +stq_le_p(&s->mmior[addr], val); +} + +/* external write */ +static void amd_iommu_writew(AMDIOMMUState *s, hwaddr addr, uint16_t val) +{ +uint16_t romask = lduw_le_p(&s->romask[addr]); +uint16_t w1cmask = lduw_le_p(&s->w1cmask[addr]); +uint16_t oldval = lduw_le_p(&s->mmior[addr]); +stw_le_p(&s->mmior[addr], (val & ~(val & w1cmask)) | (romask & oldval)); +} + +static void amd_iommu_writel(AMDIOMMUState *s, hwaddr addr, uint32_t val) +{ +uint32_t romask = ldl_le_p(&s->romask[addr]); +uint32_t w1cmask = ldl_le_p(&s->w1cmask[addr]); +uint32_t oldval = ldl_le_p(&s->mmior[addr]); +stl_le_p(
[Qemu-devel] [V9 4/4] hw/pci-host: Emulate AMD IOMMU
Add AMD IOMMU emulation support to q35 chipset Signed-off-by: David Kiarie --- hw/pci-host/q35.c | 21 +++-- include/hw/i386/intel_iommu.h | 2 +- 2 files changed, 20 insertions(+), 3 deletions(-) diff --git a/hw/pci-host/q35.c b/hw/pci-host/q35.c index 70f897e..37f8a84 100644 --- a/hw/pci-host/q35.c +++ b/hw/pci-host/q35.c @@ -32,6 +32,7 @@ #include "hw/pci-host/q35.h" #include "qapi/error.h" #include "qapi/visitor.h" +#include "hw/i386/amd_iommu.h" / * Q35 host @@ -448,6 +449,19 @@ static void mch_init_dmar(MCHPCIState *mch) pci_setup_iommu(pci_bus, q35_host_dma_iommu, mch->iommu); } +static void mch_init_amdvi(MCHPCIState *mch) +{ +AMDIOMMUState *iommu_state; +PCIBus *bus = PCI_BUS(qdev_get_parent_bus(DEVICE(mch))); +PCIDevice *iommu; + +iommu = pci_create_simple(bus, 0x20, TYPE_AMD_IOMMU_DEVICE); + +iommu_state = AMD_IOMMU_DEVICE(iommu); + +pci_setup_iommu(bus, bridge_host_amd_iommu, iommu_state); +} + static void mch_realize(PCIDevice *d, Error **errp) { int i; @@ -506,8 +520,11 @@ static void mch_realize(PCIDevice *d, Error **errp) mch->pci_address_space, &mch->pam_regions[i+1], PAM_EXPAN_BASE + i * PAM_EXPAN_SIZE, PAM_EXPAN_SIZE); } -/* Intel IOMMU (VT-d) */ -if (object_property_get_bool(qdev_get_machine(), "iommu", NULL)) { + +if (object_property_get_bool(qdev_get_machine(), "iommu", NULL) && +MACHINE(qdev_get_machine())->x_iommu_type) { +mch_init_amdvi(mch); +} else if (object_property_get_bool(qdev_get_machine(), "iommu", NULL)) { mch_init_dmar(mch); } } diff --git a/include/hw/i386/intel_iommu.h b/include/hw/i386/intel_iommu.h index 7e511e1..539530c 100644 --- a/include/hw/i386/intel_iommu.h +++ b/include/hw/i386/intel_iommu.h @@ -24,10 +24,10 @@ #include "hw/qdev.h" #include "sysemu/dma.h" -#define INTEL_IOMMU_STR "intel" #define TYPE_INTEL_IOMMU_DEVICE "intel-iommu" #define INTEL_IOMMU_DEVICE(obj) \ OBJECT_CHECK(IntelIOMMUState, (obj), TYPE_INTEL_IOMMU_DEVICE) +#define INTEL_IOMMU_STR "intel" /* DMAR Hardware Unit Definition address (IOMMU unit) */ #define Q35_HOST_BRIDGE_IOMMU_ADDR 0xfed9ULL -- 2.1.4
Re: [Qemu-devel] [V9 0/4] AMD IOMMU
Sorry, I keep missing Jan's email... On Mon, Apr 25, 2016 at 1:12 AM, David Kiarie wrote: > Hi all, > > The current AMD IOMMU patches that fixes Igor's comments. I got rid of > structs and instead > added individual integer fields into the table data directly, as suggested. > > I have also got rid of some un-used macros and fixed a few other > miscellaneous things. > > David Kiarie (4): > hw/i386: Introduce AMD IOMMU > hw/i386: ACPI table for AMD IOMMU > hw/core: Add AMD IOMMU to machine properties > hw/pci-host: Emulate AMD IOMMU > > hw/acpi/aml-build.c |2 +- > hw/acpi/core.c| 13 - > hw/core/machine.c | 32 +- > hw/i386/Makefile.objs |1 + > hw/i386/acpi-build.c | 101 ++- > hw/i386/amd_iommu.c | 1426 > + > hw/i386/amd_iommu.h | 398 > hw/pci-host/q35.c | 21 +- > include/hw/acpi/acpi-defs.h | 14 + > include/hw/acpi/acpi.h| 16 + > include/hw/acpi/aml-build.h |1 + > include/hw/boards.h |1 + > include/hw/i386/intel_iommu.h |1 + > include/hw/pci/pci.h |2 + > qemu-options.hx |7 +- > util/qemu-config.c|8 +- > 16 files changed, 2010 insertions(+), 34 deletions(-) > create mode 100644 hw/i386/amd_iommu.c > create mode 100644 hw/i386/amd_iommu.h > > -- > 2.1.4 >
Re: [Qemu-devel] [PATCH v5 15/18] intel_iommu: introduce IEC notifiers
On Thu, Apr 28, 2016 at 11:49 AM, Peter Xu wrote: > On Thu, Apr 28, 2016 at 10:36:19AM +0200, Jan Kiszka wrote: >> On 2016-04-28 10:29, Peter Xu wrote: >> > On Thu, Apr 28, 2016 at 09:26:01AM +0200, Jan Kiszka wrote: >> >> On 2016-04-28 09:05, Peter Xu wrote: >> >>> This patch introduces Intel VT-d IEC (Interrupt Entry Cache) >> >>> invalidation notifier list. When vIOMMU receives IEC invalidate request, >> >>> all the registered units will be notified with specific invalidation >> >>> requests. >> >> >> >> This should be designed to be IOMMU-agnostic, i.e. become reusable for >> >> the AMD implementation. I suspect we will have the same need for route >> >> invalidations there as well... >> > >> > Yes possibly... >> > >> > I feel like there are lots of things that can be shared between >> > Intel and AMD IOMMUs. I just do not know what is the most suitable >> > "extent" that we should abstract these shared functionalities >> > between the two, and how. >> >> A rough indicator: if you add something that has "vtd" in its name to >> non-vtd code, think twice about some reusable abstraction ;). So, >> something like "vtd_get_iommu" could already be named and designed to >> have two provides (e.g. allow an IOMMU to register itself as provider, >> return that registered instance(s) when requested). > > Yes, thanks for the hints. :) > > Before that, I was considering that the AMD guy who is going to add > its support will better consider this and finally make sure the two > coops well (anyway, I know nothing about AMD IOMMU before reading > recent patches, and there is still no amd_iommu.c yet for me to read > at..). But you are right, best to start consider it from the very > beginning. I think AMD IOMMU could be a benefit greatly from the Intel IOMMU cache implementation. There could be a few differences but I think much of the code could be reused. The thing is, AMD IOMMU spec doesn't mention anything to do with it's cache design except the available interface (for system programmers) and I have a bit of a hard time trying to design a cache from scratch. Trying to do this will however require me to dig too much into Intel IOMMU and I would prefer to reserve that for later, probably. > >> >> > >> > For example, AFAIU, a better solution for current IOMMU >> > codes (including Intel and AMD) is to provide a common framework >> > (like... X86IOMMU?), abstract these shared things out into a >> > framework, like per device name spaces, iotlb, IEC notifications, >> > etc... However, that will need a lot of further work. Also, I still >> > do not know whether this is a good idea even in the future. >> > >> > So, will this be a good point that we start to think about common >> > code blocks for both Intel and AMD IOMMU? >> >> The core iommu code can still be refactored later on. I'm now more >> concerned about the hooks you add to generic code, see above. > > Will try to make them look better in v6. Hopefully there will have > no vtd_*() in common codes. ;) > > Thanks! > > -- peterx
Re: [Qemu-devel] [V9 2/4] hw/i386: ACPI table for AMD IOMMU
On Fri, Apr 29, 2016 at 9:09 AM, Jan Kiszka wrote: > On 2016-04-25 00:12, David Kiarie wrote: >> Add IVRS table for AMD IOMMU. Generate IVRS or DMAR >> depending on emulated IOMMU > > It seems you lack scope descriptions for the PCI devices in the system. > At least, this is what our jailhouse config generator complains about > right now (didn't look into details yet). If so, the guest OS will > likely not configure the IOMMU appropriately as it thinks that the > devices are passed through anyway. > > On Intel, there is an easy way to state "catch them all" in the ACPI > table. Maybe AMD has this as well so that you don't need to add > individual devices. This is what am currently doing. From what I can see, linux correctly detects the range but I will have a look at it again before sending the next version. There was another issue raised by Michael about denying VFIO in case a user requests for IOMMU support. I did look at this but since VFIO is started with '-device' I didn't find a way to deny it in case of IOMMU support except by parsing command line arguments which turned out to be a bit ugly. We could exclude VFIO from translation by IOMMU by excluding it from the scope descriptions but am not quite sure this will remedy all the problems relating to VFIO and IOMMU. This will also require the device scope to explicitly list all the devices. > > Jan
[Qemu-devel] [V9 0/4] AMD IOMMU
These series adds AMD IOMMU support to Qemu. It's currently in the 9th version. In this series I have (hopefully) addressed all the comments made in the previous version. I have also tested and successfully passed-through PCI device 'ac97' with more devices to be tested. David Kiarie (4): hw/i386: Introduce AMD IOMMU hw/i386: ACPI table for AMD IOMMU hw/core: Add AMD IOMMU to machine properties hw/pci-host: Emulate AMD IOMMU hw/acpi/aml-build.c |2 +- hw/acpi/core.c| 13 - hw/core/machine.c | 33 +- hw/i386/Makefile.objs |1 + hw/i386/acpi-build.c | 93 ++- hw/i386/amd_iommu.c | 1426 + hw/i386/amd_iommu.h | 398 hw/pci-host/q35.c | 25 +- include/hw/acpi/acpi-defs.h | 14 + include/hw/acpi/acpi.h| 16 + include/hw/acpi/aml-build.h |1 + include/hw/boards.h |7 + include/hw/i386/intel_iommu.h |1 + include/hw/pci/pci.h |2 + qemu-options.hx |7 +- util/qemu-config.c|8 +- 16 files changed, 2012 insertions(+), 35 deletions(-) create mode 100644 hw/i386/amd_iommu.c create mode 100644 hw/i386/amd_iommu.h -- 2.1.4
[Qemu-devel] [V9 1/4] hw/i386: Introduce AMD IOMMU
Add AMD IOMMU emulaton to Qemu in addition to Intel IOMMU The IOMMU does basic translation, error checking and has a minimal IOTLB implementation Signed-off-by: David Kiarie --- hw/i386/Makefile.objs |1 + hw/i386/amd_iommu.c | 1426 + hw/i386/amd_iommu.h | 398 ++ include/hw/pci/pci.h |2 + 4 files changed, 1827 insertions(+) create mode 100644 hw/i386/amd_iommu.c create mode 100644 hw/i386/amd_iommu.h diff --git a/hw/i386/Makefile.objs b/hw/i386/Makefile.objs index b52d5b8..2f1a265 100644 --- a/hw/i386/Makefile.objs +++ b/hw/i386/Makefile.objs @@ -3,6 +3,7 @@ obj-y += multiboot.o obj-y += pc.o pc_piix.o pc_q35.o obj-y += pc_sysfw.o obj-y += intel_iommu.o +obj-y += amd_iommu.o obj-$(CONFIG_XEN) += ../xenpv/ xen/ obj-y += kvmvapic.o diff --git a/hw/i386/amd_iommu.c b/hw/i386/amd_iommu.c new file mode 100644 index 000..eea4fac --- /dev/null +++ b/hw/i386/amd_iommu.c @@ -0,0 +1,1426 @@ +/* + * QEMU emulation of AMD IOMMU (AMD-Vi) + * + * Copyright (C) 2011 Eduard - Gabriel Munteanu + * Copyright (C) 2015 David Kiarie, + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License along + * with this program; if not, see <http://www.gnu.org/licenses/>. + * + * Cache implementation inspired by hw/i386/intel_iommu.c + * + */ +#include "qemu/osdep.h" +#include "hw/i386/amd_iommu.h" + +//#define DEBUG_AMD_IOMMU +#ifdef DEBUG_AMD_IOMMU +enum { +DEBUG_GENERAL, DEBUG_CAPAB, DEBUG_MMIO, DEBUG_ELOG, +DEBUG_CACHE, DEBUG_COMMAND, DEBUG_MMU, DEBUG_CUSTOM +}; + +#define IOMMU_DBGBIT(x) (1 << DEBUG_##x) +static int iommu_dbgflags = IOMMU_DBGBIT(CUSTOM) | IOMMU_DBGBIT(MMIO); + +#define IOMMU_DPRINTF(what, fmt, ...) do { \ +if (iommu_dbgflags & IOMMU_DBGBIT(what)) { \ +fprintf(stderr, "(amd-iommu)%s: " fmt "\n", __func__, \ +## __VA_ARGS__); } \ +} while (0) +#else +#define IOMMU_DPRINTF(what, fmt, ...) do {} while (0) +#endif + +#define ENCODE_EVENT(devid, info, addr, rshift) do { \ +*(uint16_t *)&evt[0] = devid; \ +*(uint8_t *)&evt[3] = info; \ +*(uint64_t *)&evt[4] = rshift ? cpu_to_le64(addr) :\ + cpu_to_le64(addr) >> rshift; \ +} while (0) + +typedef struct AMDIOMMUAddressSpace { +uint8_t bus_num;/* bus number */ +uint8_t devfn; /* device function */ +AMDIOMMUState *iommu_state; /* IOMMU - one per machine */ +MemoryRegion iommu; /* Device's iommu region*/ +AddressSpace as;/* device's corresponding address space */ +} AMDIOMMUAddressSpace; + +/* IOMMU cache entry */ +typedef struct IOMMUIOTLBEntry { +uint64_t gfn; +uint16_t domid; +uint64_t devid; +uint64_t perms; +uint64_t translated_addr; +} IOMMUIOTLBEntry; + +/* configure MMIO registers at startup/reset */ +static void amd_iommu_set_quad(AMDIOMMUState *s, hwaddr addr, uint64_t val, + uint64_t romask, uint64_t w1cmask) +{ +stq_le_p(&s->mmior[addr], val); +stq_le_p(&s->romask[addr], romask); +stq_le_p(&s->w1cmask[addr], w1cmask); +} + +static uint16_t amd_iommu_readw(AMDIOMMUState *s, hwaddr addr) +{ +return lduw_le_p(&s->mmior[addr]); +} + +static uint32_t amd_iommu_readl(AMDIOMMUState *s, hwaddr addr) +{ +return ldl_le_p(&s->mmior[addr]); +} + +static uint64_t amd_iommu_readq(AMDIOMMUState *s, hwaddr addr) +{ +return ldq_le_p(&s->mmior[addr]); +} + +/* internal write */ +static void amd_iommu_writeq_raw(AMDIOMMUState *s, uint64_t val, hwaddr addr) +{ +stq_le_p(&s->mmior[addr], val); +} + +/* external write */ +static void amd_iommu_writew(AMDIOMMUState *s, hwaddr addr, uint16_t val) +{ +uint16_t romask = lduw_le_p(&s->romask[addr]); +uint16_t w1cmask = lduw_le_p(&s->w1cmask[addr]); +uint16_t oldval = lduw_le_p(&s->mmior[addr]); +stw_le_p(&s->mmior[addr], (val & ~(val & w1cmask)) | (romask & oldval)); +} + +static void amd_iommu_writel(AMDIOMMUState *s, hwaddr addr, uint32_t val) +{ +uint32_t romask = ldl_le_p(&s->romask[addr]); +uint32_t w1cmask = ldl_le_p(&s->w1cmask[addr]); +uint32_t oldval = ldl_le_p(&s->mmior[addr]); +stl_
[Qemu-devel] [V9 3/4] hw/core: Add AMD IOMMU to machine properties
Added an enum, subject to review, to machine properties which it used to override iommu emulated from Intel to AMD. Signed-off-by: David Kiarie --- hw/core/machine.c | 33 ++--- include/hw/boards.h | 1 + include/hw/i386/intel_iommu.h | 1 + qemu-options.hx | 7 +-- util/qemu-config.c| 8 ++-- 5 files changed, 43 insertions(+), 7 deletions(-) diff --git a/hw/core/machine.c b/hw/core/machine.c index 6dbbc85..ff830f0 100644 --- a/hw/core/machine.c +++ b/hw/core/machine.c @@ -15,6 +15,8 @@ #include "qapi/error.h" #include "qapi-visit.h" #include "qapi/visitor.h" +#include "hw/i386/amd_iommu.h" +#include "hw/i386/intel_iommu.h" #include "hw/sysbus.h" #include "sysemu/sysemu.h" #include "qemu/error-report.h" @@ -300,6 +302,27 @@ static void machine_set_iommu(Object *obj, bool value, Error **errp) ms->iommu = value; } +static void machine_set_iommu_override(Object *obj, const char *value, + Error **errp) +{ +MachineState *ms = MACHINE(obj); +Error *err = NULL; + +ms->iommu_type = TYPE_INTEL; +/* ensure a valid iommu type */ +if (g_strcmp0(value, AMD_IOMMU_STR) == 0) { +} else if(g_strcmp0(value, INTEL_IOMMU_STR) == 0) { +} else { +error_setg(errp, "Invalid IOMMU type %s", value); +error_propagate(errp, err); +return; +} + +if ((g_strcmp0(value, AMD_IOMMU_STR) == 0)) { +ms->iommu_type = TYPE_AMD; +} +} + static void machine_set_suppress_vmdesc(Object *obj, bool value, Error **errp) { MachineState *ms = MACHINE(obj); @@ -473,10 +496,14 @@ static void machine_initfn(Object *obj) "Firmware image", NULL); object_property_add_bool(obj, "iommu", - machine_get_iommu, - machine_set_iommu, NULL); + machine_get_iommu, machine_set_iommu, NULL); object_property_set_description(obj, "iommu", -"Set on/off to enable/disable Intel IOMMU (VT-d)", +"Set on to enable IOMMU emulation", +NULL); +object_property_add_str(obj, "x-iommu-type", +NULL, machine_set_iommu_override, NULL); +object_property_set_description(obj, "x-iommu-type", +"Set on to override emulated IOMMU to AMD IOMMU", NULL); object_property_add_bool(obj, "suppress-vmdesc", machine_get_suppress_vmdesc, diff --git a/include/hw/boards.h b/include/hw/boards.h index dbe6745..5b7eeda 100644 --- a/include/hw/boards.h +++ b/include/hw/boards.h @@ -158,6 +158,7 @@ struct MachineState { bool igd_gfx_passthru; char *firmware; bool iommu; +IommuType iommu_type; bool suppress_vmdesc; bool enforce_config_section; diff --git a/include/hw/i386/intel_iommu.h b/include/hw/i386/intel_iommu.h index b024ffa..7e511e1 100644 --- a/include/hw/i386/intel_iommu.h +++ b/include/hw/i386/intel_iommu.h @@ -24,6 +24,7 @@ #include "hw/qdev.h" #include "sysemu/dma.h" +#define INTEL_IOMMU_STR "intel" #define TYPE_INTEL_IOMMU_DEVICE "intel-iommu" #define INTEL_IOMMU_DEVICE(obj) \ OBJECT_CHECK(IntelIOMMUState, (obj), TYPE_INTEL_IOMMU_DEVICE) diff --git a/qemu-options.hx b/qemu-options.hx index 6106520..81217d3 100644 --- a/qemu-options.hx +++ b/qemu-options.hx @@ -38,7 +38,8 @@ DEF("machine", HAS_ARG, QEMU_OPTION_machine, \ "kvm_shadow_mem=size of KVM shadow MMU\n" "dump-guest-core=on|off include guest memory in a core dump (default=on)\n" "mem-merge=on|off controls memory merge support (default: on)\n" -"iommu=on|off controls emulated Intel IOMMU (VT-d) support (default=off)\n" +"iommu=on|off controls emulated IOMMU support(default: off)\n" +"x-iommu-type=amd|intel overrides emulated IOMMU to AMD IOMMU (default: intel)\n" "igd-passthru=on|off controls IGD GFX passthrough support (default=off)\n" "aes-key-wrap=on|off controls support for AES key wrapping (default=on)\n" "dea-key-wrap=on|off controls support for DEA key wrapping (default=on)\n" @@ -74,7 +75,9 @@ Enables or disables memory merge support. This feature, when supported by the host, de-duplicates identical memory pages among VMs instances (enabled b
[Qemu-devel] [V9 2/4] hw/i386: ACPI table for AMD IOMMU
Add IVRS table for AMD IOMMU. Generate IVRS or DMAR depending on emulated IOMMU Signed-off-by: David Kiarie --- hw/acpi/aml-build.c | 2 +- hw/acpi/core.c | 13 --- hw/i386/acpi-build.c| 93 +++-- include/hw/acpi/acpi-defs.h | 14 +++ include/hw/acpi/acpi.h | 16 include/hw/acpi/aml-build.h | 1 + include/hw/boards.h | 6 +++ 7 files changed, 120 insertions(+), 25 deletions(-) diff --git a/hw/acpi/aml-build.c b/hw/acpi/aml-build.c index ab89ca6..da11bf8 100644 --- a/hw/acpi/aml-build.c +++ b/hw/acpi/aml-build.c @@ -227,7 +227,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; diff --git a/hw/acpi/core.c b/hw/acpi/core.c index 7925a1a..ee0e687 100644 --- a/hw/acpi/core.c +++ b/hw/acpi/core.c @@ -29,19 +29,6 @@ #include "qapi-visit.h" #include "qapi-event.h" -struct acpi_table_header { -uint16_t _length; /* our length, not actual part of the hdr */ - /* allows easier parsing for fw_cfg clients */ -char sig[4]; /* ACPI signature (4 ASCII characters) */ -uint32_t length; /* Length of table, in bytes, including header */ -uint8_t revision; /* ACPI Specification minor version # */ -uint8_t checksum; /* To make sum of entire table == 0 */ -char oem_id[6]; /* OEM identification */ -char oem_table_id[8]; /* OEM table identification */ -uint32_t oem_revision;/* OEM revision number */ -char asl_compiler_id[4]; /* ASL compiler vendor ID */ -uint32_t asl_compiler_revision; /* ASL compiler revision number */ -} QEMU_PACKED; #define ACPI_TABLE_HDR_SIZE sizeof(struct acpi_table_header) #define ACPI_TABLE_PFX_SIZE sizeof(uint16_t) /* size of the extra prefix */ diff --git a/hw/i386/acpi-build.c b/hw/i386/acpi-build.c index 6477003..74ae994 100644 --- a/hw/i386/acpi-build.c +++ b/hw/i386/acpi-build.c @@ -52,6 +52,7 @@ #include "hw/pci/pci_bus.h" #include "hw/pci-host/q35.h" #include "hw/i386/intel_iommu.h" +#include "hw/i386/amd_iommu.h" #include "hw/timer/hpet.h" #include "hw/acpi/aml-build.h" @@ -59,6 +60,8 @@ #include "qapi/qmp/qint.h" #include "qom/qom-qobject.h" +#include "hw/boards.h" + /* These are used to size the ACPI tables for -M pc-i440fx-1.7 and * -M pc-i440fx-2.0. Even if the actual amount of AML generated grows * a little bit, there should be plenty of free space since the DSDT @@ -2598,6 +2601,77 @@ build_dmar_q35(GArray *table_data, GArray *linker) "DMAR", table_data->len - dmar_start, 1, NULL, NULL); } +static void +build_amd_iommu(GArray *table_data, GArray *linker) +{ +int iommu_start = table_data->len; +bool iommu_ambig; + +/* IVRS definition - table header has an extra 2-byte field */ +acpi_data_push(table_data, (sizeof(acpi_table_header) - 2)); +/* common virtualization information */ +build_append_int_noprefix(table_data, AMD_IOMMU_HOST_ADDRESS_WIDTH << 8, 4); +/* reserved */ +build_append_int_noprefix(table_data, 0, 8); + +AMDIOMMUState *s = (AMDIOMMUState *)object_resolve_path_type("", +TYPE_AMD_IOMMU_DEVICE, &iommu_ambig); + +/* IVDB definition - type 10h */ +if (!iommu_ambig) { +/* IVHD definition - type 10h */ +build_append_int_noprefix(table_data, 0x10, 1); +/* virtualization flags */ +build_append_int_noprefix(table_data, (IVHD_HT_TUNEN | + IVHD_PPRSUP | IVHD_IOTLBSUP | IVHD_PREFSUP), 1); +/* ivhd length */ +build_append_int_noprefix(table_data, 0x20, 2); +/* iommu device id */ +build_append_int_noprefix(table_data, PCI_DEVICE_ID_RD890_IOMMU, 2); +/* offset of capability registers */ +build_append_int_noprefix(table_data, s->capab_offset, 2); +/* mmio base register */ +build_append_int_noprefix(table_data, s->mmio.addr, 8); +/* pci segment */ +build_append_int_noprefix(table_data, 0, 2); +/* interrupt numbers */ +build_append_int_noprefix(table_data, 0, 2); +/* feature reporting */ +build_append_int_noprefix(table_data, (IVHD_EFR_GTSUP | +IVHD_EFR_HATS | IVHD_EFR_GATS), 4); +/* Add device flags here + * This is are 4-byte device entries currently reporting the range of + * devices 00h - h; all devices + * Device setting affecting all devices should be made here + * + * Refer to +
Re: [Qemu-devel] [V9 2/4] hw/i386: ACPI table for AMD IOMMU
On Sun, May 1, 2016 at 4:45 PM, Michael S. Tsirkin wrote: > On Sat, Apr 30, 2016 at 01:42:41AM +0300, David Kiarie wrote: >> Add IVRS table for AMD IOMMU. Generate IVRS or DMAR >> depending on emulated IOMMU >> >> Signed-off-by: David Kiarie >> --- >> hw/acpi/aml-build.c | 2 +- >> hw/acpi/core.c | 13 --- >> hw/i386/acpi-build.c| 93 >> +++-- >> include/hw/acpi/acpi-defs.h | 14 +++ >> include/hw/acpi/acpi.h | 16 >> include/hw/acpi/aml-build.h | 1 + >> include/hw/boards.h | 6 +++ >> 7 files changed, 120 insertions(+), 25 deletions(-) >> >> diff --git a/hw/acpi/aml-build.c b/hw/acpi/aml-build.c >> index ab89ca6..da11bf8 100644 >> --- a/hw/acpi/aml-build.c >> +++ b/hw/acpi/aml-build.c >> @@ -227,7 +227,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; >> >> diff --git a/hw/acpi/core.c b/hw/acpi/core.c >> index 7925a1a..ee0e687 100644 >> --- a/hw/acpi/core.c >> +++ b/hw/acpi/core.c >> @@ -29,19 +29,6 @@ >> #include "qapi-visit.h" >> #include "qapi-event.h" >> >> -struct acpi_table_header { >> -uint16_t _length; /* our length, not actual part of the hdr */ >> - /* allows easier parsing for fw_cfg clients */ >> -char sig[4]; /* ACPI signature (4 ASCII characters) */ >> -uint32_t length; /* Length of table, in bytes, including >> header */ >> -uint8_t revision; /* ACPI Specification minor version # */ >> -uint8_t checksum; /* To make sum of entire table == 0 */ >> -char oem_id[6]; /* OEM identification */ >> -char oem_table_id[8]; /* OEM table identification */ >> -uint32_t oem_revision;/* OEM revision number */ >> -char asl_compiler_id[4]; /* ASL compiler vendor ID */ >> -uint32_t asl_compiler_revision; /* ASL compiler revision number */ >> -} QEMU_PACKED; >> >> #define ACPI_TABLE_HDR_SIZE sizeof(struct acpi_table_header) >> #define ACPI_TABLE_PFX_SIZE sizeof(uint16_t) /* size of the extra prefix */ >> diff --git a/hw/i386/acpi-build.c b/hw/i386/acpi-build.c >> index 6477003..74ae994 100644 >> --- a/hw/i386/acpi-build.c >> +++ b/hw/i386/acpi-build.c >> @@ -52,6 +52,7 @@ >> #include "hw/pci/pci_bus.h" >> #include "hw/pci-host/q35.h" >> #include "hw/i386/intel_iommu.h" >> +#include "hw/i386/amd_iommu.h" >> #include "hw/timer/hpet.h" >> >> #include "hw/acpi/aml-build.h" >> @@ -59,6 +60,8 @@ >> #include "qapi/qmp/qint.h" >> #include "qom/qom-qobject.h" >> >> +#include "hw/boards.h" >> + >> /* These are used to size the ACPI tables for -M pc-i440fx-1.7 and >> * -M pc-i440fx-2.0. Even if the actual amount of AML generated grows >> * a little bit, there should be plenty of free space since the DSDT >> @@ -2598,6 +2601,77 @@ build_dmar_q35(GArray *table_data, GArray *linker) >> "DMAR", table_data->len - dmar_start, 1, NULL, NULL); >> } >> >> +static void >> +build_amd_iommu(GArray *table_data, GArray *linker) >> +{ >> +int iommu_start = table_data->len; >> +bool iommu_ambig; >> + >> +/* IVRS definition - table header has an extra 2-byte field */ >> +acpi_data_push(table_data, (sizeof(acpi_table_header) - 2)); > > why won't build_header overwrite the extra fields? > Even if not, that's too hacky. Pls find another way to do this. I was advised to do this by Igor, to get rid of structs defining IVRS table. He actually said it should be done acpi_data_push(table_data, (sizeof(acpi_table_header) - 2)); but looking at acpi_table_header, I noted there's an extra 2-byte field for internal use which corrupts IVRS. The other way I could do this, since I know the size of IVRS table, is to use a constant acpi_data_push(table_data, 0x30)); am not sure whether this isn't even more hacky otherwise I'd have to go back to using the original structs. > >> +/* common virtualization information */ >> +build_append_int_noprefix(table_data, AMD
Re: [Qemu-devel] [V9 0/4] AMD IOMMU
On Sun, May 1, 2016 at 5:00 PM, Michael S. Tsirkin wrote: > On Sun, May 01, 2016 at 04:47:44PM +0300, Michael S. Tsirkin wrote: >> On Sat, Apr 30, 2016 at 01:42:39AM +0300, David Kiarie wrote: >> > These series adds AMD IOMMU support to Qemu. It's currently in the 9th >> > version. >> > >> > In this series I have (hopefully) addressed all the comments made in the >> > previous version. >> >> changelog? >> >> > I have also tested and successfully passed-through PCI device 'ac97' with >> > more devices to be tested. >> >> >> A fundamental problem with AMD IOMMUs is that the VMM must write-protect >> guest I/O page tables from the guest in order to intercept all guest >> updates and propagate the updates to the shadow I/O page tables. >> >> AMD manual says as much. > > Actually while it says so, it's wrong. > There's an NPcache flag which makes guest to invalidations > for invalid to valid transitions. > >> Until this is implemented, I think device assignment must be disabled >> when AMD IOMMU is in use. > > So I take this back. I would, however, like to see how this > interacts with Aviv's patches enabling VFIO support for IOMMU. > The initial consensus was to deny VFIO when user requests for IOMMU and I did actually look at that but I can't get an obvious way to disable, or even tell that a user requested for a device when they do so via '-device'. The only way to disable VFIO was parsing the command line argument which seemed very ugly. Other than that, I would prefer not to add more features to this patchset but I will still be working on IOMMU for the next few months so I'll probably look at that. >> >> > >> > David Kiarie (4): >> > hw/i386: Introduce AMD IOMMU >> > hw/i386: ACPI table for AMD IOMMU >> > hw/core: Add AMD IOMMU to machine properties >> > hw/pci-host: Emulate AMD IOMMU >> > >> > hw/acpi/aml-build.c |2 +- >> > hw/acpi/core.c| 13 - >> > hw/core/machine.c | 33 +- >> > hw/i386/Makefile.objs |1 + >> > hw/i386/acpi-build.c | 93 ++- >> > hw/i386/amd_iommu.c | 1426 >> > + >> > hw/i386/amd_iommu.h | 398 >> > hw/pci-host/q35.c | 25 +- >> > include/hw/acpi/acpi-defs.h | 14 + >> > include/hw/acpi/acpi.h| 16 + >> > include/hw/acpi/aml-build.h |1 + >> > include/hw/boards.h |7 + >> > include/hw/i386/intel_iommu.h |1 + >> > include/hw/pci/pci.h |2 + >> > qemu-options.hx |7 +- >> > util/qemu-config.c|8 +- >> > 16 files changed, 2012 insertions(+), 35 deletions(-) >> > create mode 100644 hw/i386/amd_iommu.c >> > create mode 100644 hw/i386/amd_iommu.h >> > >> > -- >> > 2.1.4
Re: [Qemu-devel] [V9 1/4] hw/i386: Introduce AMD IOMMU
On Sun, May 1, 2016 at 5:14 PM, Michael S. Tsirkin wrote: > On Sat, Apr 30, 2016 at 01:42:40AM +0300, David Kiarie wrote: >> Add AMD IOMMU emulaton to Qemu in addition to Intel IOMMU >> The IOMMU does basic translation, error checking and has a >> minimal IOTLB implementation >> >> Signed-off-by: David Kiarie >> --- >> hw/i386/Makefile.objs |1 + >> hw/i386/amd_iommu.c | 1426 >> + >> hw/i386/amd_iommu.h | 398 ++ >> include/hw/pci/pci.h |2 + >> 4 files changed, 1827 insertions(+) >> create mode 100644 hw/i386/amd_iommu.c >> create mode 100644 hw/i386/amd_iommu.h >> >> diff --git a/hw/i386/Makefile.objs b/hw/i386/Makefile.objs >> index b52d5b8..2f1a265 100644 >> --- a/hw/i386/Makefile.objs >> +++ b/hw/i386/Makefile.objs >> @@ -3,6 +3,7 @@ obj-y += multiboot.o >> obj-y += pc.o pc_piix.o pc_q35.o >> obj-y += pc_sysfw.o >> obj-y += intel_iommu.o >> +obj-y += amd_iommu.o >> obj-$(CONFIG_XEN) += ../xenpv/ xen/ >> >> obj-y += kvmvapic.o >> diff --git a/hw/i386/amd_iommu.c b/hw/i386/amd_iommu.c >> new file mode 100644 >> index 000..eea4fac >> --- /dev/null >> +++ b/hw/i386/amd_iommu.c >> @@ -0,0 +1,1426 @@ >> +/* >> + * QEMU emulation of AMD IOMMU (AMD-Vi) >> + * >> + * Copyright (C) 2011 Eduard - Gabriel Munteanu >> + * Copyright (C) 2015 David Kiarie, >> + * >> + * This program is free software; you can redistribute it and/or modify >> + * it under the terms of the GNU General Public License as published by >> + * the Free Software Foundation; either version 2 of the License, or >> + * (at your option) any later version. >> + >> + * This program is distributed in the hope that it will be useful, >> + * but WITHOUT ANY WARRANTY; without even the implied warranty of >> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the >> + * GNU General Public License for more details. >> + >> + * You should have received a copy of the GNU General Public License along >> + * with this program; if not, see <http://www.gnu.org/licenses/>. >> + * >> + * Cache implementation inspired by hw/i386/intel_iommu.c >> + * >> + */ >> +#include "qemu/osdep.h" >> +#include "hw/i386/amd_iommu.h" >> + >> +//#define DEBUG_AMD_IOMMU >> +#ifdef DEBUG_AMD_IOMMU >> +enum { >> +DEBUG_GENERAL, DEBUG_CAPAB, DEBUG_MMIO, DEBUG_ELOG, >> +DEBUG_CACHE, DEBUG_COMMAND, DEBUG_MMU, DEBUG_CUSTOM >> +}; >> + >> +#define IOMMU_DBGBIT(x) (1 << DEBUG_##x) >> +static int iommu_dbgflags = IOMMU_DBGBIT(CUSTOM) | IOMMU_DBGBIT(MMIO); >> + >> +#define IOMMU_DPRINTF(what, fmt, ...) do { \ >> +if (iommu_dbgflags & IOMMU_DBGBIT(what)) { \ >> +fprintf(stderr, "(amd-iommu)%s: " fmt "\n", __func__, \ >> +## __VA_ARGS__); } \ >> +} while (0) >> +#else >> +#define IOMMU_DPRINTF(what, fmt, ...) do {} while (0) >> +#endif >> + >> +#define ENCODE_EVENT(devid, info, addr, rshift) do { \ >> +*(uint16_t *)&evt[0] = devid; \ >> +*(uint8_t *)&evt[3] = info; \ >> +*(uint64_t *)&evt[4] = rshift ? cpu_to_le64(addr) :\ >> + cpu_to_le64(addr) >> rshift; \ >> +} while (0) >> + >> +typedef struct AMDIOMMUAddressSpace { >> +uint8_t bus_num;/* bus number */ >> +uint8_t devfn; /* device function */ >> +AMDIOMMUState *iommu_state; /* IOMMU - one per machine */ >> +MemoryRegion iommu; /* Device's iommu region*/ >> +AddressSpace as;/* device's corresponding address space */ >> +} AMDIOMMUAddressSpace; >> + >> +/* IOMMU cache entry */ >> +typedef struct IOMMUIOTLBEntry { >> +uint64_t gfn; >> +uint16_t domid; >> +uint64_t devid; >> +uint64_t perms; >> +uint64_t translated_addr; >> +} IOMMUIOTLBEntry; >> + >> +/* configure MMIO registers at startup/reset */ >> +static void amd_iommu_set_quad(AMDIOMMUState *s, hwaddr addr, uint64_t val, >> + uint64_t romask, uint64_t w1cmask) >> +{ >> +stq_le_p(&s->mmior[addr], val); >> +stq_le_p(&s->romask[addr], romask); >> +stq_le_p(&s->w1cmask[addr], w1cmask); >> +} >> + >> +static uint16_t amd_iommu_re
Re: [Qemu-devel] [V9 0/4] AMD IOMMU
On Wed, May 4, 2016 at 9:12 AM, Jan Kiszka wrote: > On 2016-04-30 00:42, David Kiarie wrote: >> These series adds AMD IOMMU support to Qemu. It's currently in the 9th >> version. >> >> In this series I have (hopefully) addressed all the comments made in the >> previous version. >> I have also tested and successfully passed-through PCI device 'ac97' with >> more devices to be tested. >> > > I've done some basic testing with a Jailhouse setup and found it > working. The ACPI table is now properly parsed and the DMA remapping was > not disturbing the system after Jailhouse was activated. > > However, it was also still not intervening after I started to corrupt > the configuration, removed DMA target properties from most of the RAM or > dropped PCI devices. This means you're invalidating DTEs ? > > You are not dropping invalid remapping requests, are you? According to > the logs, you are detecting them at least: > > (amd-iommu)amd_iommu_get_dte: Device Table at 0x3b0d4000 > (amd-iommu)amd_iommu_get_dte: Pte entry at 0x0 is invalid > (amd-iommu)amd_iommu_translate: devid: 00:02.0 gpa 0x32f39480 hpa 0x32f39000 > > It's a bit hard to test right now if remapping is actually properly > working in all important cases if you do not reject invalid ones. > > Jan >