[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[Qemu-devel] [RFC 4/6] hw/vfio: vsmmu device
From: |
Baptiste Reynal |
Subject: |
[Qemu-devel] [RFC 4/6] hw/vfio: vsmmu device |
Date: |
Fri, 12 Jun 2015 16:20:08 +0200 |
This patches introduces support for ARM virtual SMMU, enabling two stages
address translation.
The vSMMU device can be instantiated from the command line using following
option:
-device vsmmu,x-group=1
Signed-off-by: Baptiste Reynal <address@hidden>
---
hw/vfio/Makefile.objs | 1 +
hw/vfio/common.c | 8 ++-
hw/vfio/platform.c | 1 +
hw/vfio/smmu.c | 157 ++++++++++++++++++++++++++++++++++++++++++++
include/hw/vfio/vfio-smmu.h | 50 ++++++++++++++
5 files changed, 215 insertions(+), 2 deletions(-)
create mode 100644 hw/vfio/smmu.c
create mode 100644 include/hw/vfio/vfio-smmu.h
diff --git a/hw/vfio/Makefile.objs b/hw/vfio/Makefile.objs
index d540c9d..4b91901 100644
--- a/hw/vfio/Makefile.objs
+++ b/hw/vfio/Makefile.objs
@@ -3,4 +3,5 @@ obj-$(CONFIG_SOFTMMU) += common.o
obj-$(CONFIG_PCI) += pci.o
obj-$(CONFIG_SOFTMMU) += platform.o
obj-$(CONFIG_SOFTMMU) += calxeda-xgmac.o
+obj-$(CONFIG_SOFTMMU) += smmu.o
endif
diff --git a/hw/vfio/common.c b/hw/vfio/common.c
index b1045da..a3ee72f 100644
--- a/hw/vfio/common.c
+++ b/hw/vfio/common.c
@@ -676,8 +676,12 @@ static int vfio_connect_container(VFIOGroup *group,
AddressSpace *as)
goto free_container_exit;
}
- ret = ioctl(fd, VFIO_SET_IOMMU,
- v2 ? VFIO_TYPE1v2_IOMMU : VFIO_TYPE1_IOMMU);
+ if (ioctl(fd, VFIO_CHECK_EXTENSION, VFIO_TYPE1_NESTING_IOMMU)) {
+ ret = ioctl(fd, VFIO_SET_IOMMU, VFIO_TYPE1_NESTING_IOMMU);
+ } else {
+ ret = ioctl(fd, VFIO_SET_IOMMU,
+ v2 ? VFIO_TYPE1v2_IOMMU : VFIO_TYPE1_IOMMU);
+ }
if (ret) {
error_report("vfio: failed to set iommu for container: %m");
ret = -errno;
diff --git a/hw/vfio/platform.c b/hw/vfio/platform.c
index 9382bb7..6192458 100644
--- a/hw/vfio/platform.c
+++ b/hw/vfio/platform.c
@@ -475,6 +475,7 @@ static int vfio_base_device_init(VFIODevice *vbasedev)
error_report("vfio: failed to get group %d", groupid);
return -ENOENT;
}
+ vbasedev->group = group;
g_snprintf(path, sizeof(path), "%s", vbasedev->name);
diff --git a/hw/vfio/smmu.c b/hw/vfio/smmu.c
new file mode 100644
index 0000000..467abbe
--- /dev/null
+++ b/hw/vfio/smmu.c
@@ -0,0 +1,157 @@
+/*
+ * support for vsmmu interface to use it with vfio devices
+ *
+ * Copyright (C) 2015 - Virtual Open Systems
+ *
+ * Author: Baptiste Reynal <address@hidden>
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2. See
+ * the COPYING file in the top-level directory.
+ */
+
+#include <sys/ioctl.h>
+
+#include "hw/vfio/vfio-smmu.h"
+#include "sysemu/kvm.h"
+#include "sysemu/sysemu.h"
+#include "qemu/error-report.h"
+#include "hw/platform-bus.h"
+#include "hw/vfio/vfio.h"
+#include "hw/vfio/vfio-common.h"
+
+static void vsmmu_notify(Notifier *notifier, void *data)
+{
+ SmmuNotifierParams *p = DO_UPCAST(SmmuNotifierParams,
+ notifier, notifier);
+
+ DeviceState *dev;
+ PlatformBusDevice *pbus;
+ SysBusDevice *sbdev = SYS_BUS_DEVICE(p->vsmmu);
+
+ dev = qdev_find_recursive(sysbus_get_default(), TYPE_PLATFORM_BUS_DEVICE);
+ pbus = PLATFORM_BUS_DEVICE(dev);
+ assert(pbus->done_gathering);
+
+ hwaddr base = platform_bus_get_mmio_addr(pbus, sbdev, 0);
+ base += pbus->base_address;
+
+ struct kvm_device_attr attr = {
+ .group = KVM_DEV_ARM_SMMU_V2_CFG,
+ .attr = KVM_DEV_ARM_SMMU_V2_CFG_INIT,
+ .addr = (uint64_t)(unsigned long) &base,
+ };
+
+ if (ioctl(p->vsmmu->kvm_device, KVM_SET_DEVICE_ATTR, &attr)) {
+ error_report("Error during vSMMU initialization: %m.\n");
+ } else {
+ p->vsmmu->base = base;
+ }
+}
+
+static void smmu_realize(DeviceState *dev, Error **errp)
+{
+ VFIOSmmuDevice *vsmmu = VFIO_SMMU_DEVICE(dev);
+ SysBusDevice *sbdev = SYS_BUS_DEVICE(dev);
+ VFIOGroup *group;
+ int ret;
+ const char *name = "smmu memory";
+
+ group = vfio_get_group(vsmmu->group, &address_space_memory);
+ if (!group) {
+ error_report("vfio: failed to get group %d", vsmmu->group);
+ goto fail;
+ }
+
+ /* Create ARM_SMMU_V2 */
+ struct kvm_create_device cd = {
+ .type = KVM_DEV_TYPE_ARM_SMMU_V2,
+ };
+
+ ret = kvm_vm_ioctl(kvm_state, KVM_CREATE_DEVICE, &cd);
+ if (ret < 0) {
+ error_report("vfio: error creating vSMMU: %m");
+ goto fail;
+ };
+ vsmmu->kvm_device = cd.fd;
+
+ /* Add group */
+ struct arm_smmu_v2_vfio_group_sid group_sid = {
+ .fd = group->fd,
+ .sid = group->groupid,
+ };
+
+ struct kvm_device_attr attr = {
+ .group = KVM_DEV_ARM_SMMU_V2_VFIO,
+ .attr = KVM_DEV_ARM_SMMU_V2_VFIO_GROUP_ADD,
+ .addr = (uint64_t)(unsigned long) &group_sid,
+ };
+
+ if (ioctl(cd.fd, KVM_SET_DEVICE_ATTR, &attr)) {
+ error_report("Failed to add group %d to vSMMU: %m",
+ group->groupid);
+ goto fail;
+ }
+
+ /* Initialize the virtual device */
+ /* Get vSMMU size for allocation */
+ int size;
+
+ attr.group = KVM_DEV_ARM_SMMU_V2_CFG;
+ attr.attr = KVM_DEV_ARM_SMMU_V2_CFG_SIZE;
+ attr.addr = (uint64_t)(unsigned long) &size;
+
+ ret = ioctl(cd.fd, KVM_GET_DEVICE_ATTR, &attr);
+
+ if (ret) {
+ error_report("Failed to get vSMMU size: %m");
+ goto fail;
+ }
+
+ vsmmu->size = size;
+
+ memory_region_init_reservation(&vsmmu->mem, OBJECT(vsmmu), name, size);
+ sysbus_init_mmio(sbdev, &vsmmu->mem);
+
+ /* Register a machine init done notifier to initialize the
+ * vSMMU at the right address */
+ SmmuNotifierParams *p = g_new(SmmuNotifierParams, 1);
+ p->vsmmu = vsmmu;
+ p->notifier.notify = vsmmu_notify;
+ qemu_add_platform_bus_link_done_notifier(&p->notifier);
+fail:
+ return;
+}
+
+static const VMStateDescription vfio_platform_vmstate = {
+ .name = TYPE_VFIO_SMMU,
+ .unmigratable = 1,
+};
+
+static Property vfio_smmu_dev_properties[] = {
+ DEFINE_PROP_UINT32("x-group", VFIOSmmuDevice,
+ group, -1),
+ DEFINE_PROP_END_OF_LIST(),
+};
+
+static void vfio_smmu_class_init(ObjectClass *klass, void *data)
+{
+ DeviceClass *dc = DEVICE_CLASS(klass);
+ dc->realize = smmu_realize;
+ dc->desc = "VFIO SMMU";
+ dc->props = vfio_smmu_dev_properties;
+}
+
+static const TypeInfo vfio_smmu_dev_info = {
+ .name = TYPE_VFIO_SMMU,
+ .parent = TYPE_SYS_BUS_DEVICE,
+ .instance_size = sizeof(VFIOSmmuDevice),
+ .class_init = vfio_smmu_class_init,
+ .class_size = sizeof(VFIOSmmuDeviceClass),
+};
+
+static void register_smmu_dev_type(void)
+{
+ type_register_static(&vfio_smmu_dev_info);
+}
+
+type_init(register_smmu_dev_type)
diff --git a/include/hw/vfio/vfio-smmu.h b/include/hw/vfio/vfio-smmu.h
new file mode 100644
index 0000000..c14ff8e
--- /dev/null
+++ b/include/hw/vfio/vfio-smmu.h
@@ -0,0 +1,50 @@
+/*
+ * support for vsmmu interface to use it with vfio devices
+ *
+ * Copyright (C) 2015 - Virtual Open Systems
+ *
+ * Author: Baptiste Reynal <address@hidden>
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2. See
+ * the COPYING file in the top-level directory.
+ */
+
+#ifndef HW_VFIO_SMMU_H
+#define HW_VFIO_SMMU_H
+
+#include "hw/sysbus.h"
+
+#define TYPE_VFIO_SMMU "vfio-smmu"
+
+typedef struct VFIOSmmuDevice {
+ SysBusDevice sbdev;
+ int kvm_device;
+ int size;
+ hwaddr base;
+
+ MemoryRegion mem;
+
+ uint32_t group;
+} VFIOSmmuDevice;
+
+typedef struct SmmuNotifierParams {
+ Notifier notifier;
+ VFIOSmmuDevice *vsmmu;
+} SmmuNotifierParams;
+
+typedef struct VFIOSmmuDeviceClass {
+ /*< private >*/
+ SysBusDeviceClass parent_class;
+ /*< public >*/
+} VFIOSmmuDeviceClass;
+
+#define VFIO_SMMU_DEVICE(obj) \
+ OBJECT_CHECK(VFIOSmmuDevice, (obj), TYPE_VFIO_SMMU)
+#define VFIO_SMMU_DEVICE_CLASS(klass) \
+ OBJECT_CLASS_CHECK(VFIOSmmuDeviceClass, (klass), \
+ TYPE_VFIO_SMMU)
+#define VFIO_SMMU_DEVICE_GET_CLASS(obj) \
+ OBJECT_GET_CLASS(VFIOSmmuDeviceClass, (obj), \
+ TYPE_VFIO_SMMU)
+
+#endif
--
2.4.3
- [Qemu-devel] [RFC 0/6] vSMMU initialization, Baptiste Reynal, 2015/06/12
- [Qemu-devel] [RFC 1/6] headers sync, Baptiste Reynal, 2015/06/12
- [Qemu-devel] [RFC 2/6] hw/core/platform-bus: initialization notifier, Baptiste Reynal, 2015/06/12
- [Qemu-devel] [RFC 3/6] hw/core/platform-bus: add base_address field, Baptiste Reynal, 2015/06/12
- [Qemu-devel] [RFC 4/6] hw/vfio: vsmmu device,
Baptiste Reynal <=
- [Qemu-devel] [RFC 5/6] hw/arm/sysbus-fdt: enable vsmmu dynamic instantiation, Baptiste Reynal, 2015/06/12
- [Qemu-devel] [RFC 6/6] hw/arm/sysbus-fdt: add smmu masters in device tree, Baptiste Reynal, 2015/06/12
- Re: [Qemu-devel] [RFC 0/6] vSMMU initialization, Will Deacon, 2015/06/12