]> xenbits.xensource.com Git - osstest/qemu.git/commitdiff
intel-iommu: add Intel IOMMU emulation to q35 and add a machine option "iommu" as...
authorLe Tan <tamlokveer@gmail.com>
Sat, 16 Aug 2014 05:55:40 +0000 (13:55 +0800)
committerMichael S. Tsirkin <mst@redhat.com>
Thu, 28 Aug 2014 21:10:22 +0000 (23:10 +0200)
Add Intel IOMMU emulation to q35 chipset and expose it to the guest.
1. Add a machine option. Users can use "-machine iommu=on|off" in the command
line to enable/disable Intel IOMMU. The default is off.
2. Accroding to the machine option, q35 will initialize the Intel IOMMU and
use pci_setup_iommu() to setup q35_host_dma_iommu() as the IOMMU function for
the pci bus.
3. q35_host_dma_iommu() will return different address space according to the
bus_num and devfn of the device.

Signed-off-by: Le Tan <tamlokveer@gmail.com>
Reviewed-by: Michael S. Tsirkin <mst@redhat.com>
Signed-off-by: Michael S. Tsirkin <mst@redhat.com>
hw/core/machine.c
hw/pci-host/q35.c
include/hw/boards.h
include/hw/pci-host/q35.h
qemu-options.hx
vl.c

index 7a66c57ab7687e588d33dcbd28dac32834082bab..0708de57f6b41a75f376c14771e39aad4b58ed0d 100644 (file)
@@ -235,6 +235,20 @@ 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)
+{
+    MachineState *ms = MACHINE(obj);
+
+    return ms->iommu;
+}
+
+static void machine_set_iommu(Object *obj, bool value, Error **errp)
+{
+    MachineState *ms = MACHINE(obj);
+
+    ms->iommu = value;
+}
+
 static void machine_initfn(Object *obj)
 {
     object_property_add_str(obj, "accel",
@@ -274,6 +288,9 @@ static void machine_initfn(Object *obj)
     object_property_add_bool(obj, "usb", machine_get_usb, machine_set_usb, NULL);
     object_property_add_str(obj, "firmware",
                             machine_get_firmware, machine_set_firmware, NULL);
+    object_property_add_bool(obj, "iommu",
+                             machine_get_iommu,
+                             machine_set_iommu, NULL);
 }
 
 static void machine_finalize(Object *obj)
index 37f228e77e199620580ef619b996511a2731c7fb..721cf5bcd4d92c135bb335b4362c0c91fb06ab8e 100644 (file)
@@ -347,6 +347,48 @@ static void mch_reset(DeviceState *qdev)
     mch_update(mch);
 }
 
+static AddressSpace *q35_host_dma_iommu(PCIBus *bus, void *opaque, int devfn)
+{
+    IntelIOMMUState *s = opaque;
+    VTDAddressSpace **pvtd_as;
+    int bus_num = pci_bus_num(bus);
+
+    assert(0 <= bus_num && bus_num <= VTD_PCI_BUS_MAX);
+    assert(0 <= devfn && devfn <= VTD_PCI_DEVFN_MAX);
+
+    pvtd_as = s->address_spaces[bus_num];
+    if (!pvtd_as) {
+        /* No corresponding free() */
+        pvtd_as = g_malloc0(sizeof(VTDAddressSpace *) * VTD_PCI_DEVFN_MAX);
+        s->address_spaces[bus_num] = pvtd_as;
+    }
+    if (!pvtd_as[devfn]) {
+        pvtd_as[devfn] = g_malloc0(sizeof(VTDAddressSpace));
+
+        pvtd_as[devfn]->bus_num = (uint8_t)bus_num;
+        pvtd_as[devfn]->devfn = (uint8_t)devfn;
+        pvtd_as[devfn]->iommu_state = s;
+        memory_region_init_iommu(&pvtd_as[devfn]->iommu, OBJECT(s),
+                                 &s->iommu_ops, "intel_iommu", UINT64_MAX);
+        address_space_init(&pvtd_as[devfn]->as,
+                           &pvtd_as[devfn]->iommu, "intel_iommu");
+    }
+    return &pvtd_as[devfn]->as;
+}
+
+static void mch_init_dmar(MCHPCIState *mch)
+{
+    PCIBus *pci_bus = PCI_BUS(qdev_get_parent_bus(DEVICE(mch)));
+
+    mch->iommu = INTEL_IOMMU_DEVICE(qdev_create(NULL, TYPE_INTEL_IOMMU_DEVICE));
+    object_property_add_child(OBJECT(mch), "intel-iommu",
+                              OBJECT(mch->iommu), NULL);
+    qdev_init_nofail(DEVICE(mch->iommu));
+    sysbus_mmio_map(SYS_BUS_DEVICE(mch->iommu), 0, Q35_HOST_BRIDGE_IOMMU_ADDR);
+
+    pci_setup_iommu(pci_bus, q35_host_dma_iommu, mch->iommu);
+}
+
 static int mch_init(PCIDevice *d)
 {
     int i;
@@ -370,6 +412,10 @@ static int mch_init(PCIDevice *d)
                  &mch->pam_regions[i+1], PAM_EXPAN_BASE + i * PAM_EXPAN_SIZE,
                  PAM_EXPAN_SIZE);
     }
+    /* Intel IOMMU (VT-d) */
+    if (qemu_opt_get_bool(qemu_get_machine_opts(), "iommu", false)) {
+        mch_init_dmar(mch);
+    }
     return 0;
 }
 
index 605a97093476b77205ab7578f593dc4d997069cb..dfb6718dc184c8c3eb0fe2392703a386f8efe767 100644 (file)
@@ -123,6 +123,7 @@ struct MachineState {
     bool mem_merge;
     bool usb;
     char *firmware;
+    bool iommu;
 
     ram_addr_t ram_size;
     ram_addr_t maxram_size;
index d9ee97845b2febd58353193869e6b547692c6fff..025d6e69af23cb50971ac811441d497d4ebab992 100644 (file)
@@ -33,6 +33,7 @@
 #include "hw/acpi/acpi.h"
 #include "hw/acpi/ich9.h"
 #include "hw/pci-host/pam.h"
+#include "hw/i386/intel_iommu.h"
 
 #define TYPE_Q35_HOST_DEVICE "q35-pcihost"
 #define Q35_HOST_DEVICE(obj) \
@@ -60,6 +61,7 @@ typedef struct MCHPCIState {
     uint64_t pci_hole64_size;
     PcGuestInfo *guest_info;
     uint32_t short_root_bus;
+    IntelIOMMUState *iommu;
 } MCHPCIState;
 
 typedef struct Q35PCIHost {
index c573dd8893ede615507f20e6a575637457b74a35..92b4da6427b001e6f6b9d38cfde70817dbc0bf40 100644 (file)
@@ -35,7 +35,8 @@ DEF("machine", HAS_ARG, QEMU_OPTION_machine, \
     "                kernel_irqchip=on|off controls accelerated irqchip support\n"
     "                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",
+    "                mem-merge=on|off controls memory merge support (default: on)\n"
+    "                iommu=on|off controls emulated Intel IOMMU (VT-d) support (default=off)\n",
     QEMU_ARCH_ALL)
 STEXI
 @item -machine [type=]@var{name}[,prop=@var{value}[,...]]
@@ -58,6 +59,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.
 @end table
 ETEXI
 
diff --git a/vl.c b/vl.c
index b796c67e9d7fb6774a5f1b26b52a8711b45f1651..cca012a7dec96d2b94b96f2ac7721c99354925c3 100644 (file)
--- a/vl.c
+++ b/vl.c
@@ -388,6 +388,10 @@ static QemuOptsList qemu_machine_opts = {
             .name = PC_MACHINE_MAX_RAM_BELOW_4G,
             .type = QEMU_OPT_SIZE,
             .help = "maximum ram below the 4G boundary (32bit boundary)",
+        },{
+            .name = "iommu",
+            .type = QEMU_OPT_BOOL,
+            .help = "Set on/off to enable/disable Intel IOMMU (VT-d)",
         },
         { /* End of list */ }
     },