[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[PATCH v4 05/22] xen/arm: vsmmuv3: Add dummy support for virtual SMMUv3 for guests


  • To: "xen-devel@xxxxxxxxxxxxxxxxxxxx" <xen-devel@xxxxxxxxxxxxxxxxxxxx>
  • From: Milan Djokic <milan_djokic@xxxxxxxx>
  • Date: Wed, 7 Oct 2026 00:06:50 +0000
  • Accept-language: en-US
  • Arc-authentication-results: i=1; mx.microsoft.com 1; spf=pass smtp.mailfrom=epam.com; dmarc=pass action=none header.from=epam.com; dkim=pass header.d=epam.com; arc=none
  • Arc-message-signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=microsoft.com; s=arcselector10001; h=From:Date:Subject:Message-ID:Content-Type:MIME-Version:X-MS-Exchange-AntiSpam-MessageData-ChunkCount:X-MS-Exchange-AntiSpam-MessageData-0:X-MS-Exchange-AntiSpam-MessageData-1; bh=s6fBeL+MAqASEV6H1dyzlNgG792lYox9FaIzNnli0Ng=; b=uo9pHvkuoplRG3YP102yFpY7CVNHMGlsifuZHbLlCiF3fVmcr0nNBdHhWW9Ov54lszKtwy4y3QwajiaUkTnM7fB//0y+EvOvdOG5VnNEZYQU8vQ0xy/H0SpO//rSUTuYLv8+L+RZHziJnIB5XD0Gt64WSIv5ACJ8jlYOVAeDA0LecBODcn8S7ml64qkdAvVxBtynOph7UVIasTNWh3qIU//1iiomUeio69zsGrKBMmkpRorps5xEpdok1dUPxdPQA8A/m564d7hlJt/Pa8gnEPvQW/FdclT5fey2UbFO2rhhdo7g80fcQRRgLZ4lSJ1QbeODtvGOJcaqKOvdQKgjOA==
  • Arc-seal: i=1; a=rsa-sha256; s=arcselector10001; d=microsoft.com; cv=none; b=b7Lei1rcdxaTlBNDb2vQNiq6Gqspxxu73EkWu5WGZLz+y594x5to86UbnK5WrNjXOUvtJWq+10jq6oy/CjopOV6BzmtuJmGdIfPw9BLQyB5zazKkNiDLIDE5MXbJ8Dzv24p1ad8z4oxKn0BRxrGNsVpTM7s2QABLpf2b1whFWYMUBNYYroL9ozZil2PE3mU1nKelSCOoZKR2KPa8vSA0LYtVc4lLyqIgjHHDz3Mbit56wyBNXCEjo/HOfQ+VcwtpN9quB/r5b3aXAuwkg4AoPOgeMrNE85NcubDpHah/xLl6IeH+rk4MzKIkQ8yl4NxnylCWjAJUETrIVLzXk70S8g==
  • Authentication-results: eu.smtp.expurgate.cloud; dkim=pass header.s=selector1 header.d=epam.com header.i="@epam.com" header.h="From:Date:Subject:Message-ID:Content-Type:MIME-Version:x-ms-exchange-senderadcheck"
  • Authentication-results: mx.microsoft.com 1; dkim=none (message not signed) header.d=none;dmarc=none action=none header.from=epam.com;
  • Cc: Rahul Singh <rahul.singh@xxxxxxx>, Stefano Stabellini <sstabellini@xxxxxxxxxx>, Julien Grall <julien@xxxxxxx>, Bertrand Marquis <bertrand.marquis@xxxxxxx>, Michal Orzel <michal.orzel@xxxxxxx>, Volodymyr Babchuk <Volodymyr_Babchuk@xxxxxxxx>, Jan Beulich <jbeulich@xxxxxxxx>, Roger Pau Monné <roger@xxxxxxxxxxxxxx>, Milan Djokic <milan_djokic@xxxxxxxx>
  • Delivery-date: Wed, 07 Oct 2026 00:06:54 +0000
  • List-id: Xen developer discussion <xen-devel.lists.xenproject.org>
  • Thread-index: AQHdVe/A2h41NhEQxEi7iy+7zdwxbg==
  • Thread-topic: [PATCH v4 05/22] xen/arm: vsmmuv3: Add dummy support for virtual SMMUv3 for guests

From: Rahul Singh <rahul.singh@xxxxxxx>

domain_viommu_init() will be called during domain creation and will add
the dummy trap handler for virtual IOMMUs for guests.

A host IOMMU list will be created when host IOMMU devices are probed
and this list will be used to create the IOMMU device tree node for
dom0. For dom0, 1-1 mapping will be established between vIOMMU in dom0
and physical IOMMU.

For domUs, the 1-N mapping will be established between domU and physical
IOMMUs. A new area has been reserved in the arm guest physical map at
which the emulated vIOMMU node is created in the device tree.

Also set the vIOMMU type to vSMMUv3 to enable vIOMMU framework to call
vSMMUv3 domain creation/destroy functions.

Signed-off-by: Rahul Singh <rahul.singh@xxxxxxx>
Signed-off-by: Milan Djokic <milan_djokic@xxxxxxxx>
---
 xen/arch/arm/domain.c                  |   6 +-
 xen/arch/arm/include/asm/domain.h      |   5 ++
 xen/arch/arm/include/asm/viommu.h      |  36 ++++++++
 xen/drivers/passthrough/Kconfig        |   8 ++
 xen/drivers/passthrough/arm/Makefile   |   1 +
 xen/drivers/passthrough/arm/smmu-v3.c  |   7 ++
 xen/drivers/passthrough/arm/viommu.c   |  83 ++++++++++++++++-
 xen/drivers/passthrough/arm/vsmmu-v3.c | 118 +++++++++++++++++++++++++
 xen/drivers/passthrough/arm/vsmmu-v3.h |  20 +++++
 xen/include/public/arch-arm.h          |   5 ++
 10 files changed, 287 insertions(+), 2 deletions(-)
 create mode 100644 xen/drivers/passthrough/arm/vsmmu-v3.c
 create mode 100644 xen/drivers/passthrough/arm/vsmmu-v3.h

diff --git a/xen/arch/arm/domain.c b/xen/arch/arm/domain.c
index 5c411a2310..003a8d45b9 100644
--- a/xen/arch/arm/domain.c
+++ b/xen/arch/arm/domain.c
@@ -672,7 +672,8 @@ int arch_sanitise_domain_config(struct 
xen_domctl_createdomain *config)
         return -EINVAL;
     }
 
-    if ( config->arch.viommu_type != XEN_DOMCTL_CONFIG_VIOMMU_NONE )
+    if ( config->arch.viommu_type != XEN_DOMCTL_CONFIG_VIOMMU_NONE &&
+         config->arch.viommu_type != viommu_get_type() )
     {
         dprintk(XENLOG_INFO,
                 "vIOMMU type requested not supported by the platform or 
Xen\n");
@@ -728,6 +729,9 @@ int arch_domain_create(struct domain *d,
 
     count += domain_vpci_get_num_mmio_handlers(d);
 
+    if ( config->arch.viommu_type != XEN_DOMCTL_CONFIG_VIOMMU_NONE )
+        count += domain_viommu_get_num_mmio_handlers(d);
+
     if ( (rc = domain_io_init(d, count + MAX_IO_HANDLER)) != 0 )
         goto fail;
 
diff --git a/xen/arch/arm/include/asm/domain.h 
b/xen/arch/arm/include/asm/domain.h
index c3d2c4981f..70af0bf8b7 100644
--- a/xen/arch/arm/include/asm/domain.h
+++ b/xen/arch/arm/include/asm/domain.h
@@ -102,6 +102,11 @@ struct arch_domain
 #ifdef CONFIG_MPU
     uint8_t v8r_el1_msa;
 #endif
+
+#ifdef CONFIG_ARM_VIRTUAL_IOMMU
+    struct list_head viommu_list;     /* List of virtual IOMMUs */
+#endif
+
 }  __cacheline_aligned;
 
 struct arch_vcpu
diff --git a/xen/arch/arm/include/asm/viommu.h 
b/xen/arch/arm/include/asm/viommu.h
index 95f82d9cf5..287595068b 100644
--- a/xen/arch/arm/include/asm/viommu.h
+++ b/xen/arch/arm/include/asm/viommu.h
@@ -3,9 +3,23 @@
 #define __ARCH_ARM_VIOMMU_H__
 
 #include <xen/lib.h>
+#include <xen/list.h>
 #include <xen/types.h>
 #include <public/xen.h>
 
+/* data structure for each hardware IOMMU */
+struct host_iommu {
+    struct list_head entry;
+    /* IOMMU DT node used to establish virtual to physical IOMMU/SID mapping */
+    const struct dt_device_node *dt_node;
+    /* Used for dom0 vIOMMU instantiation (1-1 MMIO regions mappings) */
+    paddr_t addr;
+    /* Used for dom0 vIOMMU instantiation (1-1 MMIO regions mappings) */
+    paddr_t size;
+    /* Used for dom0 EVTQ and GERROR interrupts (1-1 IRQ mapping) */
+    uint32_t irq;
+};
+
 struct viommu_ops {
     /*
      * Called during domain construction if toolstack requests to enable
@@ -32,9 +46,15 @@ struct viommu_desc {
 
 #ifdef CONFIG_ARM_VIRTUAL_IOMMU
 
+extern struct list_head host_iommu_list;
+
 int domain_viommu_init(struct domain *d, uint8_t viommu_type);
 int viommu_relinquish_resources(struct domain *d);
 uint8_t viommu_get_type(void);
+void add_to_host_iommu_list(paddr_t addr, paddr_t size,
+                            const struct dt_device_node *node);
+void set_cur_viommu(const struct viommu_desc *desc);
+unsigned int domain_viommu_get_num_mmio_handlers(struct domain *d);
 
 #else
 
@@ -56,6 +76,22 @@ static inline int viommu_relinquish_resources(struct domain 
*d)
     return 0;
 }
 
+static inline void __init add_to_host_iommu_list(paddr_t addr, paddr_t size,
+                                          const struct dt_device_node *node)
+{
+    return;
+}
+
+static inline unsigned int domain_viommu_get_num_mmio_handlers(struct domain 
*d)
+{
+    return 0;
+}
+
+static inline void __init set_cur_viommu(const struct viommu_desc *desc)
+{
+    return;
+}
+
 #endif /* CONFIG_ARM_VIRTUAL_IOMMU */
 
 #endif /* __ARCH_ARM_VIOMMU_H__ */
diff --git a/xen/drivers/passthrough/Kconfig b/xen/drivers/passthrough/Kconfig
index a92cfbea98..40d072822f 100644
--- a/xen/drivers/passthrough/Kconfig
+++ b/xen/drivers/passthrough/Kconfig
@@ -40,6 +40,14 @@ config ARM_VIRTUAL_IOMMU
        help
          Support virtual IOMMU infrastructure to implement vIOMMU.
 
+config VIRTUAL_ARM_SMMU_V3
+       bool "ARM Ltd. Virtual SMMUv3 Support (UNSUPPORTED)"
+       depends on ARM_SMMU_V3 && ARM_VIRTUAL_IOMMU
+       help
+        Support for implementations of the virtual ARM System MMU architecture
+        version 3. Virtual SMMUv3 is unsupported feature and should not be used
+        in production.
+
 endif
 
 config AMD_IOMMU
diff --git a/xen/drivers/passthrough/arm/Makefile 
b/xen/drivers/passthrough/arm/Makefile
index c3783188e3..c8f0a5f802 100644
--- a/xen/drivers/passthrough/arm/Makefile
+++ b/xen/drivers/passthrough/arm/Makefile
@@ -3,3 +3,4 @@ obj-$(CONFIG_ARM_SMMU) += smmu.o
 obj-$(CONFIG_IPMMU_VMSA) += ipmmu-vmsa.o
 obj-$(CONFIG_ARM_SMMU_V3) += smmu-v3.o
 obj-$(CONFIG_ARM_VIRTUAL_IOMMU) += viommu.o
+obj-$(CONFIG_VIRTUAL_ARM_SMMU_V3) += vsmmu-v3.o
diff --git a/xen/drivers/passthrough/arm/smmu-v3.c 
b/xen/drivers/passthrough/arm/smmu-v3.c
index bd0689664b..21b82eba85 100644
--- a/xen/drivers/passthrough/arm/smmu-v3.c
+++ b/xen/drivers/passthrough/arm/smmu-v3.c
@@ -93,6 +93,7 @@
 #include <asm/platform.h>
 
 #include "smmu-v3.h"
+#include "vsmmu-v3.h"
 
 #define ARM_SMMU_VTCR_SH_IS            3
 #define ARM_SMMU_VTCR_RGN_WBWA         1
@@ -2829,6 +2830,9 @@ static int __init arm_smmu_device_probe(struct 
platform_device *pdev)
        list_add(&smmu->devices, &arm_smmu_devices);
        spin_unlock(&arm_smmu_devices_lock);
 
+       /* Add to host IOMMU list to initialize vIOMMU for dom0 */
+       add_to_host_iommu_list(ioaddr, iosize, dev_to_dt(pdev));
+
        return 0;
 
 
@@ -3181,6 +3185,9 @@ static __init int arm_smmu_dt_init(struct dt_device_node 
*dev,
 
        platform_features &= smmu->features;
 
+       /* Set vIOMMU type to SMMUv3 */
+       vsmmuv3_set_type();
+
        return 0;
 }
 
diff --git a/xen/drivers/passthrough/arm/viommu.c 
b/xen/drivers/passthrough/arm/viommu.c
index 0c0efd668e..3401e4f7d9 100644
--- a/xen/drivers/passthrough/arm/viommu.c
+++ b/xen/drivers/passthrough/arm/viommu.c
@@ -2,12 +2,54 @@
 
 #include <xen/errno.h>
 #include <xen/init.h>
+#include <xen/irq.h>
 #include <xen/types.h>
+#include <xen/sched.h>
 
 #include <asm/viommu.h>
 
+/* List of all host IOMMUs */
+LIST_HEAD(host_iommu_list);
+
 /* Struct to hold the vIOMMU ops and vIOMMU type */
 static const struct viommu_desc __ro_after_init *cur_viommu;
+static bool host_iommu_list_incomplete;
+
+/* Common function for adding to host_iommu_list */
+void __init add_to_host_iommu_list(paddr_t addr, paddr_t size,
+                            const struct dt_device_node *node)
+{
+    struct host_iommu *iommu_data;
+    int irq;
+
+    iommu_data = xzalloc(struct host_iommu);
+    if ( !iommu_data )
+    {
+        host_iommu_list_incomplete = true;
+        printk(XENLOG_WARNING
+               "vIOMMU: Cannot allocate memory for host IOMMU data\n");
+        return;
+    }
+
+    iommu_data->addr = addr;
+    iommu_data->size = size;
+    iommu_data->dt_node = node;
+    irq = platform_get_irq(node, 0);
+    if ( irq < 0 )
+    {
+        host_iommu_list_incomplete = true;
+        printk(XENLOG_WARNING
+               "vIOMMU: disabling support because IOMMU @0x%"PRIx64
+               " has no usable IRQ (%d)\n", addr, irq);
+        xfree(iommu_data);
+        return;
+    }
+    iommu_data->irq = irq;
+
+    printk("vIOMMU: Found IOMMU @0x%"PRIx64"\n", addr);
+
+    list_add_tail(&iommu_data->entry, &host_iommu_list);
+}
 
 int domain_viommu_init(struct domain *d, uint8_t viommu_type)
 {
@@ -33,12 +75,51 @@ int viommu_relinquish_resources(struct domain *d)
 
 uint8_t viommu_get_type(void)
 {
-    if ( !cur_viommu )
+    if ( !cur_viommu || host_iommu_list_incomplete ||
+         list_empty(&host_iommu_list) )
         return XEN_DOMCTL_CONFIG_VIOMMU_NONE;
 
     return cur_viommu->viommu_type;
 }
 
+void __init set_cur_viommu(const struct viommu_desc *desc)
+{
+    if ( cur_viommu && (cur_viommu != desc) )
+    {
+        printk("WARNING: Cannot set vIOMMU, already set to a different 
value\n");
+        return;
+    }
+
+    cur_viommu = desc;
+}
+
+unsigned int domain_viommu_get_num_mmio_handlers(struct domain *d)
+{
+    if ( is_hardware_domain(d) )
+    {
+        struct host_iommu *hw_iommu;
+        int count = 0;
+
+        /*
+        * For hardware domain, vIOMMU per pIOMMU is exposed. Number of
+        * regions required for the configuration space is equal to number of
+        * host IOMMUs.
+        */
+        list_for_each_entry(hw_iommu, &host_iommu_list, entry)
+        {
+            count++;
+        }
+
+        return count;
+    }
+
+    /*
+     * For unpriviliged domains, single vIOMMU is exposed and requires one
+     * region to cover the configuration space.
+     */
+    return 1;
+}
+
 /*
  * Local variables:
  * mode: C
diff --git a/xen/drivers/passthrough/arm/vsmmu-v3.c 
b/xen/drivers/passthrough/arm/vsmmu-v3.c
new file mode 100644
index 0000000000..ea3b5bb34d
--- /dev/null
+++ b/xen/drivers/passthrough/arm/vsmmu-v3.c
@@ -0,0 +1,118 @@
+/* SPDX-License-Identifier: (GPL-2.0-or-later OR BSD-2-Clause) */
+
+#include <xen/param.h>
+#include <xen/sched.h>
+#include <asm/mmio.h>
+#include <asm/viommu.h>
+
+struct virt_smmu {
+    struct      domain *d;
+    struct      list_head viommu_list;
+};
+
+static int vsmmuv3_mmio_write(struct vcpu *v, mmio_info_t *info,
+                              register_t r, void *priv)
+{
+    BUG_ON("unimplemented");
+    return IO_HANDLED;
+}
+
+static int vsmmuv3_mmio_read(struct vcpu *v, mmio_info_t *info,
+                             register_t *r, void *priv)
+{
+    BUG_ON("unimplemented");
+    return IO_HANDLED;
+}
+
+static const struct mmio_handler_ops vsmmuv3_mmio_handler = {
+    .read  = vsmmuv3_mmio_read,
+    .write = vsmmuv3_mmio_write,
+};
+
+static int vsmmuv3_init_single(struct domain *d, paddr_t addr, paddr_t size)
+{
+    struct virt_smmu *smmu;
+
+    smmu = xzalloc(struct virt_smmu);
+    if ( !smmu )
+        return -ENOMEM;
+
+    smmu->d = d;
+
+    register_mmio_handler(d, &vsmmuv3_mmio_handler, addr, size, smmu);
+
+    /* Register the vIOMMU to be able to clean it up later. */
+    list_add_tail(&smmu->viommu_list, &d->arch.viommu_list);
+
+    return 0;
+}
+
+static int domain_vsmmuv3_init(struct domain *d)
+{
+    int ret;
+
+    INIT_LIST_HEAD(&d->arch.viommu_list);
+
+    if ( is_hardware_domain(d) )
+    {
+        struct host_iommu *hw_iommu;
+
+        list_for_each_entry(hw_iommu, &host_iommu_list, entry)
+        {
+            ret = vsmmuv3_init_single(d, hw_iommu->addr, hw_iommu->size);
+            if ( ret )
+                return ret;
+        }
+    }
+    else
+    {
+        ret = vsmmuv3_init_single(d, GUEST_VSMMUV3_BASE, GUEST_VSMMUV3_SIZE);
+        if ( ret )
+            return ret;
+    }
+
+    return 0;
+}
+
+static int vsmmuv3_relinquish_resources(struct domain *d)
+{
+    struct virt_smmu *pos, *temp;
+
+    /* Cope with uninitialized vIOMMU */
+    if ( list_head_is_null(&d->arch.viommu_list) )
+        return 0;
+
+    list_for_each_entry_safe(pos, temp, &d->arch.viommu_list, viommu_list )
+    {
+        list_del(&pos->viommu_list);
+        xfree(pos);
+    }
+
+    return 0;
+}
+
+static const struct viommu_ops vsmmuv3_ops = {
+    .domain_init = domain_vsmmuv3_init,
+    .relinquish_resources = vsmmuv3_relinquish_resources,
+};
+
+static const struct viommu_desc vsmmuv3_desc = {
+    .ops = &vsmmuv3_ops,
+    .viommu_type = XEN_DOMCTL_CONFIG_VIOMMU_SMMUV3,
+};
+
+void __init vsmmuv3_set_type(void)
+{
+    const struct viommu_desc *desc = &vsmmuv3_desc;
+
+    set_cur_viommu(desc);
+}
+
+/*
+ * Local variables:
+ * mode: C
+ * c-file-style: "BSD"
+ * c-basic-offset: 4
+ * indent-tabs-mode: nil
+ * End:
+ */
diff --git a/xen/drivers/passthrough/arm/vsmmu-v3.h 
b/xen/drivers/passthrough/arm/vsmmu-v3.h
new file mode 100644
index 0000000000..9f4c86abd5
--- /dev/null
+++ b/xen/drivers/passthrough/arm/vsmmu-v3.h
@@ -0,0 +1,20 @@
+/* SPDX-License-Identifier: (GPL-2.0-or-later OR BSD-2-Clause) */
+#ifndef __ARCH_ARM_VSMMU_V3_H__
+#define __ARCH_ARM_VSMMU_V3_H__
+
+#include <asm/viommu.h>
+
+#ifdef CONFIG_VIRTUAL_ARM_SMMU_V3
+
+void vsmmuv3_set_type(void);
+
+#else
+
+static inline void __init vsmmuv3_set_type(void)
+{
+    return;
+}
+
+#endif /* CONFIG_VIRTUAL_ARM_SMMU_V3 */
+
+#endif /* __ARCH_ARM_VSMMU_V3_H__ */
diff --git a/xen/include/public/arch-arm.h b/xen/include/public/arch-arm.h
index a1491f9cf7..8863e2e457 100644
--- a/xen/include/public/arch-arm.h
+++ b/xen/include/public/arch-arm.h
@@ -335,6 +335,7 @@ DEFINE_XEN_GUEST_HANDLE(vcpu_guest_context_t);
 #define XEN_DOMCTL_CONFIG_ARM_V8R_EL1_MSA_VMSA    2
 
 #define XEN_DOMCTL_CONFIG_VIOMMU_NONE   0
+#define XEN_DOMCTL_CONFIG_VIOMMU_SMMUV3 1
 
 struct xen_arch_domainconfig {
     /* IN/OUT */
@@ -463,6 +464,10 @@ typedef uint64_t xen_callback_t;
 #define GUEST_GICV3_GICR0_BASE     xen_mk_ullong(0x03020000) /* vCPU0..127 */
 #define GUEST_GICV3_GICR0_SIZE     xen_mk_ullong(0x01000000)
 
+/* vsmmuv3 MMIO mappings */
+#define GUEST_VSMMUV3_BASE     xen_mk_ullong(0x04040000)
+#define GUEST_VSMMUV3_SIZE     xen_mk_ullong(0x00020000)
+
 /*
  * 256 MB is reserved for VPCI configuration space based on calculation
  * 256 buses x 32 devices x 8 functions x 4 KB = 256 MB
-- 
2.43.0

 


Rackspace

Lists.xenproject.org is hosted with RackSpace, monitoring our
servers 24x7x365 and backed by RackSpace's Fanatical Support®.