From: Dmytro Terletskyi <dmytro_terletskyi@epam.com>
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 <dmytro_terletskyi@epam.com>
---
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