提交 a52a7fdf 编写于 作者: L Le Tan 提交者: Michael S. Tsirkin

intel-iommu: add Intel IOMMU emulation to q35 and add a machine option "iommu" as a switch

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: NLe Tan <tamlokveer@gmail.com>
Reviewed-by: NMichael S. Tsirkin <mst@redhat.com>
Signed-off-by: NMichael S. Tsirkin <mst@redhat.com>
上级 d4eb9119
...@@ -235,6 +235,20 @@ static void machine_set_firmware(Object *obj, const char *value, Error **errp) ...@@ -235,6 +235,20 @@ static void machine_set_firmware(Object *obj, const char *value, Error **errp)
ms->firmware = g_strdup(value); 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) static void machine_initfn(Object *obj)
{ {
object_property_add_str(obj, "accel", object_property_add_str(obj, "accel",
...@@ -274,6 +288,9 @@ static void machine_initfn(Object *obj) ...@@ -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_bool(obj, "usb", machine_get_usb, machine_set_usb, NULL);
object_property_add_str(obj, "firmware", object_property_add_str(obj, "firmware",
machine_get_firmware, machine_set_firmware, NULL); 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) static void machine_finalize(Object *obj)
......
...@@ -347,6 +347,48 @@ static void mch_reset(DeviceState *qdev) ...@@ -347,6 +347,48 @@ static void mch_reset(DeviceState *qdev)
mch_update(mch); 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) static int mch_init(PCIDevice *d)
{ {
int i; int i;
...@@ -370,6 +412,10 @@ static int mch_init(PCIDevice *d) ...@@ -370,6 +412,10 @@ static int mch_init(PCIDevice *d)
&mch->pam_regions[i+1], PAM_EXPAN_BASE + i * PAM_EXPAN_SIZE, &mch->pam_regions[i+1], PAM_EXPAN_BASE + i * PAM_EXPAN_SIZE,
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; return 0;
} }
......
...@@ -123,6 +123,7 @@ struct MachineState { ...@@ -123,6 +123,7 @@ struct MachineState {
bool mem_merge; bool mem_merge;
bool usb; bool usb;
char *firmware; char *firmware;
bool iommu;
ram_addr_t ram_size; ram_addr_t ram_size;
ram_addr_t maxram_size; ram_addr_t maxram_size;
......
...@@ -33,6 +33,7 @@ ...@@ -33,6 +33,7 @@
#include "hw/acpi/acpi.h" #include "hw/acpi/acpi.h"
#include "hw/acpi/ich9.h" #include "hw/acpi/ich9.h"
#include "hw/pci-host/pam.h" #include "hw/pci-host/pam.h"
#include "hw/i386/intel_iommu.h"
#define TYPE_Q35_HOST_DEVICE "q35-pcihost" #define TYPE_Q35_HOST_DEVICE "q35-pcihost"
#define Q35_HOST_DEVICE(obj) \ #define Q35_HOST_DEVICE(obj) \
...@@ -60,6 +61,7 @@ typedef struct MCHPCIState { ...@@ -60,6 +61,7 @@ typedef struct MCHPCIState {
uint64_t pci_hole64_size; uint64_t pci_hole64_size;
PcGuestInfo *guest_info; PcGuestInfo *guest_info;
uint32_t short_root_bus; uint32_t short_root_bus;
IntelIOMMUState *iommu;
} MCHPCIState; } MCHPCIState;
typedef struct Q35PCIHost { typedef struct Q35PCIHost {
......
...@@ -35,7 +35,8 @@ DEF("machine", HAS_ARG, QEMU_OPTION_machine, \ ...@@ -35,7 +35,8 @@ DEF("machine", HAS_ARG, QEMU_OPTION_machine, \
" kernel_irqchip=on|off controls accelerated irqchip support\n" " kernel_irqchip=on|off controls accelerated irqchip support\n"
" kvm_shadow_mem=size of KVM shadow MMU\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" " 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) QEMU_ARCH_ALL)
STEXI STEXI
@item -machine [type=]@var{name}[,prop=@var{value}[,...]] @item -machine [type=]@var{name}[,prop=@var{value}[,...]]
...@@ -58,6 +59,8 @@ Include guest memory in a core dump. The default is on. ...@@ -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 Enables or disables memory merge support. This feature, when supported by
the host, de-duplicates identical memory pages among VMs instances the host, de-duplicates identical memory pages among VMs instances
(enabled by default). (enabled by default).
@item iommu=on|off
Enables or disables emulated Intel IOMMU (VT-d) support. The default is off.
@end table @end table
ETEXI ETEXI
......
...@@ -388,6 +388,10 @@ static QemuOptsList qemu_machine_opts = { ...@@ -388,6 +388,10 @@ static QemuOptsList qemu_machine_opts = {
.name = PC_MACHINE_MAX_RAM_BELOW_4G, .name = PC_MACHINE_MAX_RAM_BELOW_4G,
.type = QEMU_OPT_SIZE, .type = QEMU_OPT_SIZE,
.help = "maximum ram below the 4G boundary (32bit boundary)", .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 */ } { /* End of list */ }
}, },
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册