From mboxrd@z Thu Jan 1 00:00:00 1970 Received: from eggs.gnu.org ([2001:4830:134:3::10]:54416) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1XOpgF-0006cy-Fw for qemu-devel@nongnu.org; Tue, 02 Sep 2014 11:07:43 -0400 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1XOpg9-0000tT-9T for qemu-devel@nongnu.org; Tue, 02 Sep 2014 11:07:35 -0400 Received: from mx1.redhat.com ([209.132.183.28]:46371) by eggs.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1XOpg9-0000tN-2K for qemu-devel@nongnu.org; Tue, 02 Sep 2014 11:07:29 -0400 Date: Tue, 2 Sep 2014 18:07:16 +0300 From: "Michael S. Tsirkin" Message-ID: <1409670380-22943-5-git-send-email-mst@redhat.com> References: <1409670380-22943-1-git-send-email-mst@redhat.com> MIME-Version: 1.0 Content-Type: text/plain; charset=us-ascii Content-Disposition: inline In-Reply-To: <1409670380-22943-1-git-send-email-mst@redhat.com> Subject: [Qemu-devel] [PULL 04/13] intel-iommu: add Intel IOMMU emulation to q35 and add a machine option "iommu" as a switch List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , To: qemu-devel@nongnu.org Cc: Peter Maydell , Stefan Hajnoczi , Marcel Apfelbaum , Michael Tokarev , Michael Roth , Le Tan , Alexander Graf , Anthony Liguori , Paolo Bonzini , Igor Mammedov , =?us-ascii?B?PT9VVEYtOD9xP0FuZHJlYXM9MjBGPUMzPUE0cmJlcj89?= From: Le Tan 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 Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin --- include/hw/boards.h | 1 + include/hw/pci-host/q35.h | 2 ++ hw/core/machine.c | 17 +++++++++++++++++ hw/pci-host/q35.c | 46 ++++++++++++++++++++++++++++++++++++++++++++++ vl.c | 4 ++++ qemu-options.hx | 5 ++++- 6 files changed, 74 insertions(+), 1 deletion(-) diff --git a/include/hw/boards.h b/include/hw/boards.h index 605a970..dfb6718 100644 --- a/include/hw/boards.h +++ b/include/hw/boards.h @@ -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; diff --git a/include/hw/pci-host/q35.h b/include/hw/pci-host/q35.h index d9ee978..025d6e6 100644 --- a/include/hw/pci-host/q35.h +++ b/include/hw/pci-host/q35.h @@ -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 { diff --git a/hw/core/machine.c b/hw/core/machine.c index 7a66c57..0708de5 100644 --- a/hw/core/machine.c +++ b/hw/core/machine.c @@ -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) diff --git a/hw/pci-host/q35.c b/hw/pci-host/q35.c index 37f228e..721cf5b 100644 --- a/hw/pci-host/q35.c +++ b/hw/pci-host/q35.c @@ -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; } diff --git a/vl.c b/vl.c index b796c67..cca012a 100644 --- 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 */ } }, diff --git a/qemu-options.hx b/qemu-options.hx index c573dd8..92b4da6 100644 --- a/qemu-options.hx +++ b/qemu-options.hx @@ -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 -- MST