Assign separate address space for each device in the remote processes. Signed-off-by: Elena Ufimtseva <elena.ufimts...@oracle.com> Signed-off-by: John G Johnson <john.g.john...@oracle.com> Signed-off-by: Jagannathan Raman <jag.ra...@oracle.com> --- include/hw/pci/pci.h | 2 + include/hw/remote/iommu.h | 24 ++++++++ hw/pci/pci.c | 2 +- hw/remote/iommu.c | 117 ++++++++++++++++++++++++++++++++++++++ hw/remote/machine.c | 5 ++ hw/remote/vfio-user-obj.c | 20 ++++++- MAINTAINERS | 2 + hw/remote/meson.build | 1 + 8 files changed, 169 insertions(+), 4 deletions(-) create mode 100644 include/hw/remote/iommu.h create mode 100644 hw/remote/iommu.c
diff --git a/include/hw/pci/pci.h b/include/hw/pci/pci.h index 5c4016b995..f2fc2d5375 100644 --- a/include/hw/pci/pci.h +++ b/include/hw/pci/pci.h @@ -734,6 +734,8 @@ void lsi53c8xx_handle_legacy_cmdline(DeviceState *lsi_dev); qemu_irq pci_allocate_irq(PCIDevice *pci_dev); void pci_set_irq(PCIDevice *pci_dev, int level); +void pci_init_bus_master(PCIDevice *pci_dev); + static inline void pci_irq_assert(PCIDevice *pci_dev) { pci_set_irq(pci_dev, 1); diff --git a/include/hw/remote/iommu.h b/include/hw/remote/iommu.h new file mode 100644 index 0000000000..42ce0ca383 --- /dev/null +++ b/include/hw/remote/iommu.h @@ -0,0 +1,24 @@ +/* + * IOMMU for remote device + * + * Copyright © 2021 Oracle and/or its affiliates. + * + * This work is licensed under the terms of the GNU GPL, version 2 or later. + * See the COPYING file in the top-level directory. + * + */ + +#ifndef REMOTE_IOMMU_H +#define REMOTE_IOMMU_H + +#include "hw/pci/pci_bus.h" + +void remote_iommu_free(PCIDevice *pci_dev); + +void remote_iommu_init(void); + +void remote_iommu_set(PCIBus *bus); + +MemoryRegion *remote_iommu_get_ram(PCIDevice *pci_dev); + +#endif diff --git a/hw/pci/pci.c b/hw/pci/pci.c index 4a84e478ce..57d561cc03 100644 --- a/hw/pci/pci.c +++ b/hw/pci/pci.c @@ -95,7 +95,7 @@ static const VMStateDescription vmstate_pcibus = { } }; -static void pci_init_bus_master(PCIDevice *pci_dev) +void pci_init_bus_master(PCIDevice *pci_dev) { AddressSpace *dma_as = pci_device_iommu_address_space(pci_dev); diff --git a/hw/remote/iommu.c b/hw/remote/iommu.c new file mode 100644 index 0000000000..30c866badb --- /dev/null +++ b/hw/remote/iommu.c @@ -0,0 +1,117 @@ +/* + * Remote IOMMU + * + * Copyright © 2021 Oracle and/or its affiliates. + * + * This work is licensed under the terms of the GNU GPL, version 2 or later. + * See the COPYING file in the top-level directory. + * + */ + +#include "qemu/osdep.h" +#include "qemu-common.h" + +#include "hw/remote/iommu.h" +#include "hw/pci/pci_bus.h" +#include "exec/memory.h" +#include "exec/address-spaces.h" +#include "trace.h" + +struct VFUIOMMU { + AddressSpace as; + MemoryRegion mr; +}; + +typedef struct VFUPciBus { + PCIBus *bus; + struct VFUIOMMU *iommu[]; +} VFUPciBus; + +GHashTable *remote_as_table; + +static AddressSpace *remote_iommu_get_as(PCIBus *bus, void *opaque, int devfn) +{ + VFUPciBus *vfu_pci_bus = NULL; + struct VFUIOMMU *iommu = NULL; + + if (!remote_as_table) { + return &address_space_memory; + } + + vfu_pci_bus = g_hash_table_lookup(remote_as_table, bus); + + if (!vfu_pci_bus) { + vfu_pci_bus = g_malloc0(sizeof(VFUPciBus)); + vfu_pci_bus->bus = bus; + g_hash_table_insert(remote_as_table, bus, vfu_pci_bus); + } + + iommu = vfu_pci_bus->iommu[devfn]; + + if (!iommu) { + g_autofree char *mr_name = g_strdup_printf("vfu-ram-%d", devfn); + g_autofree char *as_name = g_strdup_printf("vfu-as-%d", devfn); + + iommu = g_malloc0(sizeof(struct VFUIOMMU)); + + memory_region_init(&iommu->mr, NULL, mr_name, UINT64_MAX); + address_space_init(&iommu->as, &iommu->mr, as_name); + + vfu_pci_bus->iommu[devfn] = iommu; + } + + return &iommu->as; +} + +void remote_iommu_free(PCIDevice *pci_dev) +{ + VFUPciBus *vfu_pci_bus = NULL; + struct VFUIOMMU *iommu = NULL; + + if (!remote_as_table) { + return; + } + + vfu_pci_bus = g_hash_table_lookup(remote_as_table, pci_get_bus(pci_dev)); + + if (!vfu_pci_bus) { + return; + } + + iommu = vfu_pci_bus->iommu[pci_dev->devfn]; + + vfu_pci_bus->iommu[pci_dev->devfn] = NULL; + + if (iommu) { + memory_region_unref(&iommu->mr); + address_space_destroy(&iommu->as); + g_free(iommu); + } +} + +void remote_iommu_init(void) +{ + remote_as_table = g_hash_table_new_full(NULL, NULL, NULL, NULL); +} + +void remote_iommu_set(PCIBus *bus) +{ + pci_setup_iommu(bus, remote_iommu_get_as, NULL); +} + +MemoryRegion *remote_iommu_get_ram(PCIDevice *pci_dev) +{ + PCIBus *bus = pci_get_bus(pci_dev); + VFUPciBus *vfu_pci_bus; + + if (!remote_as_table) { + return get_system_memory(); + } + + vfu_pci_bus = g_hash_table_lookup(remote_as_table, bus); + if (!vfu_pci_bus) { + return get_system_memory(); + } + + return &vfu_pci_bus->iommu[pci_dev->devfn]->mr; +} diff --git a/hw/remote/machine.c b/hw/remote/machine.c index 952105eab5..023be0491e 100644 --- a/hw/remote/machine.c +++ b/hw/remote/machine.c @@ -21,6 +21,7 @@ #include "qapi/error.h" #include "hw/pci/pci_host.h" #include "hw/remote/iohub.h" +#include "hw/remote/iommu.h" static void remote_machine_init(MachineState *machine) { @@ -52,6 +53,10 @@ static void remote_machine_init(MachineState *machine) remote_iohub_init(&s->iohub); + remote_iommu_init(); + + remote_iommu_set(pci_host->bus); + pci_bus_irqs(pci_host->bus, remote_iohub_set_irq, remote_iohub_map_irq, &s->iohub, REMOTE_IOHUB_NB_PIRQS); } diff --git a/hw/remote/vfio-user-obj.c b/hw/remote/vfio-user-obj.c index 9399e87cbe..ae375e69b9 100644 --- a/hw/remote/vfio-user-obj.c +++ b/hw/remote/vfio-user-obj.c @@ -49,6 +49,7 @@ #include "hw/qdev-core.h" #include "hw/pci/pci.h" #include "qemu/timer.h" +#include "hw/remote/iommu.h" #define TYPE_VFU_OBJECT "x-vfio-user-server" OBJECT_DECLARE_TYPE(VfuObject, VfuObjectClass, VFU_OBJECT) @@ -210,6 +211,7 @@ static ssize_t vfu_object_cfg_access(vfu_ctx_t *vfu_ctx, char * const buf, static void dma_register(vfu_ctx_t *vfu_ctx, vfu_dma_info_t *info) { + VfuObject *o = vfu_get_private(vfu_ctx); MemoryRegion *subregion = NULL; g_autofree char *name = NULL; static unsigned int suffix; @@ -226,14 +228,15 @@ static void dma_register(vfu_ctx_t *vfu_ctx, vfu_dma_info_t *info) memory_region_init_ram_ptr(subregion, NULL, name, iov->iov_len, info->vaddr); - memory_region_add_subregion(get_system_memory(), (hwaddr)iov->iov_base, - subregion); + memory_region_add_subregion(remote_iommu_get_ram(o->pci_dev), + (hwaddr)iov->iov_base, subregion); trace_vfu_dma_register((uint64_t)iov->iov_base, iov->iov_len); } static void dma_unregister(vfu_ctx_t *vfu_ctx, vfu_dma_info_t *info) { + VfuObject *o = vfu_get_private(vfu_ctx); MemoryRegion *mr = NULL; ram_addr_t offset; @@ -242,7 +245,7 @@ static void dma_unregister(vfu_ctx_t *vfu_ctx, vfu_dma_info_t *info) return; } - memory_region_del_subregion(get_system_memory(), mr); + memory_region_del_subregion(remote_iommu_get_ram(o->pci_dev), mr); object_unparent((OBJECT(mr))); @@ -320,6 +323,7 @@ static vfu_region_access_cb_t *vfu_object_bar_handlers[PCI_NUM_REGIONS] = { */ static void vfu_object_register_bars(vfu_ctx_t *vfu_ctx, PCIDevice *pdev) { + VfuObject *o = vfu_get_private(vfu_ctx); int i; for (i = 0; i < PCI_NUM_REGIONS; i++) { @@ -332,6 +336,12 @@ static void vfu_object_register_bars(vfu_ctx_t *vfu_ctx, PCIDevice *pdev) vfu_object_bar_handlers[i], VFU_REGION_FLAG_RW, NULL, 0, -1, 0); + if ((o->pci_dev->io_regions[i].type & PCI_BASE_ADDRESS_SPACE) == 0) { + memory_region_unref(o->pci_dev->io_regions[i].address_space); + o->pci_dev->io_regions[i].address_space = + remote_iommu_get_ram(o->pci_dev); + } + trace_vfu_bar_register(i, pdev->io_regions[i].addr, pdev->io_regions[i].size); } @@ -490,6 +500,10 @@ static void vfu_object_finalize(Object *obj) o->device = NULL; + if (o->pci_dev) { + remote_iommu_free(o->pci_dev); + } + o->pci_dev = NULL; if (!k->nr_devs && !k->daemon) { diff --git a/MAINTAINERS b/MAINTAINERS index b5eb306662..5dc67d79a1 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -3466,6 +3466,8 @@ F: hw/remote/iohub.c F: include/hw/remote/iohub.h F: subprojects/libvfio-user F: hw/remote/vfio-user-obj.c +F: include/hw/remote/iommu.h +F: hw/remote/iommu.c EBPF: M: Jason Wang <jasow...@redhat.com> diff --git a/hw/remote/meson.build b/hw/remote/meson.build index 534ac5df79..bcef83c8cc 100644 --- a/hw/remote/meson.build +++ b/hw/remote/meson.build @@ -6,6 +6,7 @@ remote_ss.add(when: 'CONFIG_MULTIPROCESS', if_true: files('message.c')) remote_ss.add(when: 'CONFIG_MULTIPROCESS', if_true: files('remote-obj.c')) remote_ss.add(when: 'CONFIG_MULTIPROCESS', if_true: files('proxy.c')) remote_ss.add(when: 'CONFIG_MULTIPROCESS', if_true: files('iohub.c')) +remote_ss.add(when: 'CONFIG_MULTIPROCESS', if_true: files('iommu.c')) remote_ss.add(when: 'CONFIG_VFIO_USER_SERVER', if_true: files('vfio-user-obj.c')) remote_ss.add(when: 'CONFIG_VFIO_USER_SERVER', if_true: vfiouser) -- 2.20.1