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

Re: [PATCH v3 21/23] xen/arm: vIOMMU vSID->pSID mapping layer


  • To: Milan Djokic <milan_djokic@xxxxxxxx>
  • From: Luca Fancellu <Luca.Fancellu@xxxxxxx>
  • Date: Mon, 13 Apr 2026 15:10:37 +0000
  • Accept-language: en-GB, en-US
  • Arc-authentication-results: i=2; mx.microsoft.com 1; spf=pass (sender ip is 4.158.2.129) smtp.rcpttodomain=epam.com smtp.mailfrom=arm.com; dmarc=pass (p=none sp=none pct=100) action=none header.from=arm.com; dkim=pass (signature was verified) header.d=arm.com; arc=pass (0 oda=1 ltdi=1 spf=[1,1,smtp.mailfrom=arm.com] dkim=[1,1,header.d=arm.com] dmarc=[1,1,header.from=arm.com])
  • Arc-authentication-results: i=1; mx.microsoft.com 1; spf=pass smtp.mailfrom=arm.com; dmarc=pass action=none header.from=arm.com; dkim=pass header.d=arm.com; arc=none
  • Arc-message-signature: i=2; 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=X+RK/YsyMGkxGoAUBKg19MjBNh2hVfPCdtBx0j51PdE=; b=LAyfuMeAbLX7JA+FboxXBD+Qs2k25FTkUJArue4K6wZ4vuWrAbOYFNtLE6zgwtn0XNSXHK7zG9DY+Le5hPhAo5urXBoFge+hkC9FfwZtlz7qdsjFNP+fl9Nnf2chdTtVLRT6B+XwG9dsUCTcU8J3o8acluHlEDgCvaDnwadztsk0PECKFu/ZbOsvYIZkd7IYReEIyqo88ERLx1Wp4eWAKNPNRZZOepv+dk6TSePe2Xvx0VP/hs5qgz2Q0PCh70KOST2LZEMKYTUOrWL6DDrWR4U1bacFelm6b0XyL0Ppz/SaM1OQ4VhykmSKdYIbh5IctsToW8h42QkW+K9id9Vj5Q==
  • 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=X+RK/YsyMGkxGoAUBKg19MjBNh2hVfPCdtBx0j51PdE=; b=Zy0BuQWNi4XoXAL/6CpXIcWUgoVKCeyUi4CwkVjEukEcfSabAe9g1Pe//w0BSa3E5BvRbFRaeueGe2YEKvLKkQu84QPvpoYWJJ42JgQ/30E1HXuuORw0uO/unUE7C2ThD2u+3nPqxYch4x/u2WyHnN3vOkE6CGFE7g2o55yRsnn5PqwRUxMmqEmJ+JRwRS5aMPmdkm2cym2a/NIDXzftS/cFr24F9Dr3AlcrvpwP/SNDsolisyT1UtBUai9Y5USdlCLgDcLnXB2rGNpgr6K49rNFdJslpS/8ctEsMRKP1wLheBX1AZg4TLO2A2CCGTp+IQS7IkXbPwYMHvc40frHZQ==
  • Arc-seal: i=2; a=rsa-sha256; s=arcselector10001; d=microsoft.com; cv=pass; b=soEeiypCwOyKyW2TRre0iIkDh6jV4zOHPRd0F++csmZD5Mr76URB0DeGK1BlmqIcvGX3xYu8b+HkVZxcs/P4Ta/wHrgf0WVnFbS3zY0yHRxPlZgVloTpl1RXLX/IB25pyvZzrbGsnh5QwKTE6vxFCtR/DXRiMHhWNij5MpuV1s26LJwMPl9yljc71CDmnb9rc6ZlZNUNutBOpbYxaECIA/ITfES/Hq14j/oyCQcdE91CRNxM3o50HIa9B0K0kb/me2HUeIG9sIMdbJGJ+ece7cFbi3qxjt6M+XaruLj0x3vjZ4J+mkQEBcaVZCEbSEtTyz/8nCvLJ/7jO9jP2bFL2A==
  • Arc-seal: i=1; a=rsa-sha256; s=arcselector10001; d=microsoft.com; cv=none; b=gfdPuLhGBlqH6FLjYO1fk8ZXr4xkXDZNC1Xp4qkLMUnMNkDJa+7MzHbWCqPKmTSd5u49CkhoM3OOZndKqGaKa56RqWyohGqIcI0dWN+88g/GRN7Y7CNxPWNIGSnuODw8y+6HEDABHH3VBQSBKVekk6MuDof78HELIKvI00RkBLftxtSVoHLLPiyUqMIsCI6lD6sHXph9peNSKDlR8DV6eCsklCpovqr2JRjzrwUF9PgH9gMM5yhDu5dFraI3+15hcpW8uQN8Tjxb86OogVOqXPQE/Nh4B0SkNJkDGkcV2udM1JnkeEno55csUCaLgo9FAB3wJKqa7GQwe5I+sB2rmw==
  • Authentication-results: eu.smtp.expurgate.cloud; dkim=pass header.s=selector1 header.d=arm.com header.i="@arm.com" header.h="From:Date:Subject:Message-ID:Content-Type:MIME-Version:X-MS-Exchange-SenderADCheck"; dkim=pass header.s=selector1 header.d=arm.com header.i="@arm.com" header.h="From:Date:Subject:Message-ID:Content-Type:MIME-Version:X-MS-Exchange-SenderADCheck"
  • Authentication-results-original: dkim=none (message not signed) header.d=none;dmarc=none action=none header.from=arm.com;
  • Cc: "xen-devel@xxxxxxxxxxxxxxxxxxxx" <xen-devel@xxxxxxxxxxxxxxxxxxxx>, Stefano Stabellini <sstabellini@xxxxxxxxxx>, Julien Grall <julien@xxxxxxx>, Bertrand Marquis <Bertrand.Marquis@xxxxxxx>, Michal Orzel <michal.orzel@xxxxxxx>, Volodymyr Babchuk <Volodymyr_Babchuk@xxxxxxxx>
  • Delivery-date: Mon, 13 Apr 2026 15:12:00 +0000
  • List-id: Xen developer discussion <xen-devel.lists.xenproject.org>
  • Nodisclaimer: true
  • Thread-index: AQHcy1evF3Gl2rIueUOP2AqRDPAGLg==
  • Thread-topic: [PATCH v3 21/23] xen/arm: vIOMMU vSID->pSID mapping layer

Hi Milan,

> On 31 Mar 2026, at 02:52, Milan Djokic <milan_djokic@xxxxxxxx> wrote:
> 
> Introduce vIOMMU mapping layer in order to support passthrough of IOMMU
> devices attached to different physical IOMMUs (e.g. devices with the same 
> streamID).
> New generic vIOMMU API is added: viommu_allocate_free_vid().
> This function will allocate a new guest vSID and map it to input pSID.
> Once mapping is established, guest will use vSID for stage-1 commands
> and xen will translate vSID->pSID and propagate it towards stage-2.
> Introduced naming is generic (vID/pID), since this API could be used
> for other IOMMU types in the future.
> Implemented usage of the new API for dom0less guests. vSIDs are allocated
> on guest device tree creation and the original pSID is
> replaced with vSID which shall be used by the guest driver.
> 
> Signed-off-by: Milan Djokic <milan_djokic@xxxxxxxx>
> ---
> xen/arch/arm/include/asm/viommu.h       | 10 ++++
> xen/common/device-tree/dom0less-build.c | 32 +++++++++---
> xen/drivers/passthrough/arm/viommu.c    |  7 +++
> xen/drivers/passthrough/arm/vsmmu-v3.c  | 67 ++++++++++++++++++++++++-
> 4 files changed, 106 insertions(+), 10 deletions(-)
> 
> diff --git a/xen/arch/arm/include/asm/viommu.h 
> b/xen/arch/arm/include/asm/viommu.h
> index 01d4d0dfef..6a2fc56e38 100644
> --- a/xen/arch/arm/include/asm/viommu.h
> +++ b/xen/arch/arm/include/asm/viommu.h
> @@ -33,6 +33,15 @@ struct viommu_ops {
>      * Called during domain destruction to free resources used by vIOMMU.
>      */
>     int (*relinquish_resources)(struct domain *d);
> +
> +    /*
> +     * Allocate free vSID/vRID for the guest device and establish vID->pID 
> mapping
> +     * Called during domain device assignment.
> +     * Returns 0 on success and sets vid argument to newly allocated 
> vSID/vRID
> +     * mapped to physical ID (id argument).
> +     * Negative error code returned if allocation fails.
> +     */
> +    int (*allocate_free_vid)(struct domain *d, uint32_t id, uint32_t *vid);
> };
> 
> struct viommu_desc {
> @@ -48,6 +57,7 @@ struct viommu_desc {
> 
> int domain_viommu_init(struct domain *d, uint16_t viommu_type);
> int viommu_relinquish_resources(struct domain *d);
> +int viommu_allocate_free_vid(struct domain *d, uint32_t id, uint32_t *vid);
> uint16_t viommu_get_type(void);
> void add_to_host_iommu_list(paddr_t addr, paddr_t size,
>                             const struct dt_device_node *node);
> diff --git a/xen/common/device-tree/dom0less-build.c 
> b/xen/common/device-tree/dom0less-build.c
> index 4b74d2f705..f5afdf381c 100644
> --- a/xen/common/device-tree/dom0less-build.c
> +++ b/xen/common/device-tree/dom0less-build.c
> @@ -31,6 +31,8 @@
> #include <xen/static-memory.h>
> #include <xen/static-shmem.h>
> 
> +#include <asm/viommu.h>
> +
> #define XENSTORE_PFN_LATE_ALLOC UINT64_MAX
> 
> static domid_t __initdata xs_domid = DOMID_INVALID;
> @@ -318,22 +320,33 @@ static int __init handle_prop_pfdt(struct kernel_info 
> *kinfo,
>     return ( propoff != -FDT_ERR_NOTFOUND ) ? propoff : 0;
> }
> 
> -static void modify_pfdt_node(void *pfdt, int nodeoff)
> +#ifdef CONFIG_ARM_VIRTUAL_IOMMU
> +static void modify_pfdt_node(void *pfdt, int nodeoff, struct domain *d)
> {
>     int proplen, i, rc;
>     const fdt32_t *prop;
>     fdt32_t *prop_c;
> +    uint32_t vsid;
> 
> -    prop = fdt_getprop(pfdt, nodeoff, "iommus", &proplen);
> +    prop = fdt_getprop(pfdt, nodeoff, "iommus", &proplen); 
>     if ( !prop )
>         return;
> 
>     prop_c = xzalloc_bytes(proplen);
> 
> +    /* 
> +     * Assign <vIOMMU vSID> pairs to iommus property and establish
> +     * vSID->pSID mappings
> +    */
>     for ( i = 0; i < proplen / 8; ++i )
>     {
>         prop_c[i * 2] = cpu_to_fdt32(GUEST_PHANDLE_VSMMUV3);
> -        prop_c[i * 2 + 1] = prop[i * 2 + 1];
> +        rc = viommu_allocate_free_vid(d, fdt32_to_cpu(prop[i * 2 + 1]), 
> &vsid);
> +        if( rc ) {

NIT: codestyle, space after ‘if'

> +            dprintk(XENLOG_ERR, "Failed to allocate new vSID for iommu 
> device");
> +            return;
> +        }
> +        prop_c[i * 2 + 1] = cpu_to_fdt32(vsid);
>     }
> 
>     rc = fdt_setprop(pfdt, nodeoff, "iommus", prop_c, proplen);
> @@ -345,11 +358,14 @@ static void modify_pfdt_node(void *pfdt, int nodeoff)
> 
>     return;
> }
> +#else
> +    static void modify_pfdt_node(void *pfdt, int nodeoff, struct domain *d) 
> {}
> +#endif
> 
> static int __init scan_pfdt_node(struct kernel_info *kinfo, void *pfdt,
>                                  int nodeoff,
>                                  uint32_t address_cells, uint32_t size_cells,
> -                                 bool scan_passthrough_prop)
> +                                 bool scan_passthrough_prop, struct domain 
> *d)
> {
>     int rc = 0;
>     void *fdt = kinfo->fdt;
> @@ -372,9 +388,9 @@ static int __init scan_pfdt_node(struct kernel_info 
> *kinfo, void *pfdt,
>     node_next = fdt_first_subnode(pfdt, nodeoff);
>     while ( node_next > 0 )
>     {
> -        modify_pfdt_node(pfdt, node_next);
> +        modify_pfdt_node(pfdt, node_next, d);
>         rc = scan_pfdt_node(kinfo, pfdt, node_next, address_cells, size_cells,
> -                            scan_passthrough_prop);
> +                            scan_passthrough_prop, d);
>         if ( rc )
>             return rc;
> 
> @@ -443,7 +459,7 @@ static int __init domain_handle_dtb_boot_module(struct 
> domain *d,
>             res = scan_pfdt_node(kinfo, pfdt, node_next,
>                                  DT_ROOT_NODE_ADDR_CELLS_DEFAULT,
>                                  DT_ROOT_NODE_SIZE_CELLS_DEFAULT,
> -                                 false);
> +                                 false, d);
>             if ( res )
>                 goto out;
>             continue;
> @@ -453,7 +469,7 @@ static int __init domain_handle_dtb_boot_module(struct 
> domain *d,
>             res = scan_pfdt_node(kinfo, pfdt, node_next,
>                                  DT_ROOT_NODE_ADDR_CELLS_DEFAULT,
>                                  DT_ROOT_NODE_SIZE_CELLS_DEFAULT,
> -                                 true);
> +                                 true, d);
>             if ( res )
>                 goto out;
>             continue;
> diff --git a/xen/drivers/passthrough/arm/viommu.c 
> b/xen/drivers/passthrough/arm/viommu.c
> index 5f5892fbb2..4b7837a91f 100644
> --- a/xen/drivers/passthrough/arm/viommu.c
> +++ b/xen/drivers/passthrough/arm/viommu.c
> @@ -71,6 +71,13 @@ int viommu_relinquish_resources(struct domain *d)
>     return cur_viommu->ops->relinquish_resources(d);
> }
> 
> +int viommu_allocate_free_vid(struct domain *d, uint32_t id, uint32_t *vid) {
> +    if ( !cur_viommu )
> +        return -ENODEV;
> +
> +    return cur_viommu->ops->allocate_free_vid(d, id, vid);
> +}
> +
> uint16_t viommu_get_type(void)
> {
>     if ( !cur_viommu )
> diff --git a/xen/drivers/passthrough/arm/vsmmu-v3.c 
> b/xen/drivers/passthrough/arm/vsmmu-v3.c
> index 5d0dabd2b2..604f09e980 100644
> --- a/xen/drivers/passthrough/arm/vsmmu-v3.c
> +++ b/xen/drivers/passthrough/arm/vsmmu-v3.c
> @@ -53,6 +53,8 @@ extern const struct viommu_desc __read_mostly *cur_viommu;
> #define smmu_get_ste_s1ctxptr(x)    FIELD_PREP(STRTAB_STE_0_S1CTXPTR_MASK, \
>                                     FIELD_GET(STRTAB_STE_0_S1CTXPTR_MASK, x))
> 
> +#define MAX_VSID   (1 << SMMU_IDR1_SIDSIZE)
> +
> /* event queue entry */
> struct arm_smmu_evtq_ent {
>     /* Common fields */
> @@ -100,6 +102,14 @@ struct arm_vsmmu_queue {
>     uint8_t     max_n_shift;
> };
> 
> +/* vSID->pSID mapping entry */
> +struct vsid_entry {
> +    bool        valid;
> +    uint32_t    vsid;
> +    struct host_iommu *phys_smmu;
> +    uint32_t    psid;
> +};
> +
> struct virt_smmu {
>     struct      domain *d;
>     struct      list_head viommu_list;
> @@ -118,6 +128,7 @@ struct virt_smmu {
>     uint64_t    evtq_irq_cfg0;
>     struct      arm_vsmmu_queue evtq, cmdq;
>     spinlock_t  cmd_queue_lock;
> +    struct vsid_entry *vsids;
> };
> 
> /* Queue manipulation functions */
> @@ -426,6 +437,29 @@ static int arm_vsmmu_handle_cfgi_ste(struct virt_smmu 
> *smmu, uint64_t *cmdptr)
>     struct arm_vsmmu_s1_trans_cfg s1_cfg = {0};
>     uint32_t sid = smmu_cmd_get_sid(cmdptr[0]);
>     struct iommu_guest_config guest_cfg = {0};
> +    uint32_t psid;
> +    struct arm_smmu_evtq_ent ent = {
> +        .opcode = EVT_ID_BAD_STE,
> +        .sid = sid,
> +        .c_bad_ste_streamid = {
> +            .ssid = 0,
> +            .ssv = false,
> +        },
> +    };
> +
> +    /* SIDs identity mapped for HW domain */
> +    if ( is_hardware_domain(d) )
> +        psid = sid;
> +    else {
> +        /* vSID out of range or not mapped to pSID */
> +        if ( sid >= MAX_VSID || !smmu->vsids[sid].valid )
> +        {
> +            arm_vsmmu_send_event(smmu, &ent);
> +            return -EINVAL;
> +        }
> +
> +        psid = smmu->vsids[sid].psid;
> +    }
> 
>     ret = arm_vsmmu_find_ste(smmu, sid, ste);
>     if ( ret )
> @@ -446,7 +480,7 @@ static int arm_vsmmu_handle_cfgi_ste(struct virt_smmu 
> *smmu, uint64_t *cmdptr)
>     else
>         guest_cfg.config = ARM_SMMU_DOMAIN_NESTED;
> 
> -    ret = hd->platform_ops->attach_guest_config(d, sid, &guest_cfg);
> +    ret = hd->platform_ops->attach_guest_config(d, psid, &guest_cfg);
>     if ( ret )
>         return ret;
> 
> @@ -791,6 +825,7 @@ static int vsmmuv3_init_single(struct domain *d, paddr_t 
> addr,
>     smmu->cmdq.ent_size = CMDQ_ENT_DWORDS * DWORDS_BYTES;
>     smmu->evtq.q_base = FIELD_PREP(Q_BASE_LOG2SIZE, SMMU_EVTQS);
>     smmu->evtq.ent_size = EVTQ_ENT_DWORDS * DWORDS_BYTES;
> +    smmu->vsids = xzalloc_array(struct vsid_entry, MAX_VSID);

we should check if allocation is ok

> 
>     spin_lock_init(&smmu->cmd_queue_lock);
> 
> @@ -850,8 +885,9 @@ int vsmmuv3_relinquish_resources(struct domain *d)
>     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_for_each_entry_safe(pos, temp, &d->arch.viommu_list, viommu_list)
>     {
> +        xfree(pos->vsids);
>         list_del(&pos->viommu_list);
>         xfree(pos);
>     }
> @@ -859,8 +895,35 @@ int vsmmuv3_relinquish_resources(struct domain *d)
>     return 0;
> }
> 
> +int vsmmuv3_allocate_free_vid(struct domain *d, uint32_t id, uint32_t *vid) {
> +    uint16_t i = 0;
> +    struct virt_smmu *smmu;
> +
> +    if ( list_head_is_null(&d->arch.viommu_list) )
> +        return -ENODEV;
> +
> +    smmu = list_first_entry(&d->arch.viommu_list, struct virt_smmu, 
> viommu_list);
> +
> +    /* Get first free vSID index */
> +    while ( smmu->vsids[i].valid && i++ < MAX_VSID );

This will access OOB when you will reach MAX_VSID and later evaluate 
smmu->vsids[i].valid,
I suggest to modify like this:

while ( i < MAX_VSID && smmu->vsids[i].valid )
    i++;

> +
> +    /* Max number of vSIDs already allocated? */
> +    if ( i == MAX_VSID) {

NIT: code style, space before ‘)'

> +        return -ENOMEM;
> +    }
> +
> +    /* Establish vSID->pSID mapping */
> +    smmu->vsids[i].valid = true;
> +    smmu->vsids[i].vsid = i;
> +    smmu->vsids[i].psid = id;
> +    *vid = smmu->vsids[i].vsid;

Why is phys_smmu never populated and used?

> +
> +    return 0;
> +}
> +
> static const struct viommu_ops vsmmuv3_ops = {
>     .domain_init = domain_vsmmuv3_init,
> +    .allocate_free_vid = vsmmuv3_allocate_free_vid,
>     .relinquish_resources = vsmmuv3_relinquish_resources,
> };
> 

Cheers,
Luca


 


Rackspace

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