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


Reply via email to