From: Dmytro Terletskyi <[email protected]> This commit extends the ARM virt machine to support attaching virtio-mmio devices to an SMMUv3 controller.
Key changes: - Implemented virtio_mmio_get_dma_as() callback, invoked from get_dma_as() when a device is behind an SMMUv3. - Added stream ID support for virtio-mmio devices registered with the SMMU. With these changes, virtio-mmio devices can perform DMA through SMMUv3, enabling proper address translation and isolation in ARM virt platforms. Signed-off-by: Dmytro Terletskyi <[email protected]> --- hw/virtio/virtio-mmio.c | 29 +++++++++++++++++++++++++++++ include/hw/virtio/virtio-mmio.h | 3 +++ 2 files changed, 32 insertions(+) diff --git a/hw/virtio/virtio-mmio.c b/hw/virtio/virtio-mmio.c index c05c00bcd4..8f19492e3f 100644 --- a/hw/virtio/virtio-mmio.c +++ b/hw/virtio/virtio-mmio.c @@ -31,6 +31,7 @@ #include "system/kvm.h" #include "system/replay.h" #include "hw/virtio/virtio-mmio.h" +#include "system/address-spaces.h" #include "qemu/error-report.h" #include "qemu/log.h" #include "trace.h" @@ -775,6 +776,7 @@ static void virtio_mmio_realizefn(DeviceState *d, Error **errp) { VirtIOMMIOProxy *proxy = VIRTIO_MMIO(d); SysBusDevice *sbd = SYS_BUS_DEVICE(d); + static uint32_t stream_id = VIRTIO_MMIO_STREAM_ID_OFFSET; qbus_init(&proxy->bus, sizeof(proxy->bus), TYPE_VIRTIO_MMIO_BUS, d, NULL); sysbus_init_irq(sbd, &proxy->irq); @@ -784,6 +786,8 @@ static void virtio_mmio_realizefn(DeviceState *d, Error **errp) proxy->flags &= ~VIRTIO_IOMMIO_FLAG_USE_IOEVENTFD; } + proxy->stream_id = stream_id++; + if (proxy->legacy) { memory_region_init_io(&proxy->iomem, OBJECT(d), &virtio_legacy_mem_ops, proxy, @@ -867,6 +871,27 @@ static void virtio_mmio_vmstate_change(DeviceState *d, bool running) } } +static AddressSpace *virtio_mmio_get_dma_as(DeviceState *parent) +{ + // BusState *iommu_bus = qdev_get_parent_bus(parent); + BusState *iommu_bus = sysbus_get_default(); + VirtIOMMIOProxy *proxy = VIRTIO_MMIO(parent); + AddressSpace *as = NULL; + + if (iommu_bus && iommu_bus->iommu_ops) { + as = iommu_bus->iommu_ops->get_address_space( + iommu_bus, iommu_bus->iommu_opaque, proxy->stream_id); + } + + return as ? as : &address_space_memory; +} + +static bool virtio_mmio_iommu_enabled(DeviceState *parent) +{ + AddressSpace *as = virtio_mmio_get_dma_as(parent); + return as == &address_space_memory; +} + static void virtio_mmio_bus_class_init(ObjectClass *klass, const void *data) { BusClass *bus_class = BUS_CLASS(klass); @@ -884,6 +909,10 @@ static void virtio_mmio_bus_class_init(ObjectClass *klass, const void *data) k->pre_plugged = virtio_mmio_pre_plugged; k->vmstate_change = virtio_mmio_vmstate_change; k->has_variable_vring_alignment = true; + + k->get_dma_as = virtio_mmio_get_dma_as; + k->iommu_enabled = virtio_mmio_iommu_enabled; + bus_class->max_dev = 1; bus_class->get_dev_path = virtio_mmio_bus_get_dev_path; } diff --git a/include/hw/virtio/virtio-mmio.h b/include/hw/virtio/virtio-mmio.h index aa49262022..f0a1a5e3ab 100644 --- a/include/hw/virtio/virtio-mmio.h +++ b/include/hw/virtio/virtio-mmio.h @@ -53,6 +53,8 @@ typedef struct VirtIOMMIOQueue { #define VIRTIO_IOMMIO_FLAG_USE_IOEVENTFD \ (1 << VIRTIO_IOMMIO_FLAG_USE_IOEVENTFD_BIT) +#define VIRTIO_MMIO_STREAM_ID_OFFSET 0x50 + struct VirtIOMMIOProxy { /* Generic */ SysBusDevice parent_obj; @@ -67,6 +69,7 @@ struct VirtIOMMIOProxy { /* virtio-bus */ VirtioBusState bus; bool format_transport_address; + uint32_t stream_id; /* Fields only used for non-legacy (v2) devices */ uint32_t guest_features[2]; VirtIOMMIOQueue vqs[VIRTIO_QUEUE_MAX]; -- 2.43.0
