[PATCH] hw/riscv/riscv-iommu: Fix MSI table size limit

Andrew Jones posted 1 patch 1 day, 22 hours ago
Patches applied successfully (tree, apply log)
git fetch https://github.com/patchew-project/qemu tags/patchew/20250904132723.614507-2-ajones@ventanamicro.com
Maintainers: Palmer Dabbelt <palmer@dabbelt.com>, Alistair Francis <alistair.francis@wdc.com>, Weiwei Li <liwei1518@gmail.com>, Daniel Henrique Barboza <dbarboza@ventanamicro.com>, Liu Zhiwei <zhiwei_liu@linux.alibaba.com>
hw/riscv/riscv-iommu.c | 17 ++++++++++-------
1 file changed, 10 insertions(+), 7 deletions(-)
[PATCH] hw/riscv/riscv-iommu: Fix MSI table size limit
Posted by Andrew Jones 1 day, 22 hours ago
The MSI table is not limited to 4k. The only constraint the table has
is that its base address must be aligned to its size, ensuring no
offsets of the table size will overrun when added to the base address
(see "8.5. MSI page tables" of the AIA spec).

Fixes: 0c54acb8243d ("hw/riscv: add RISC-V IOMMU base emulation")
Signed-off-by: Andrew Jones <ajones@ventanamicro.com>
---
 hw/riscv/riscv-iommu.c | 17 ++++++++++-------
 1 file changed, 10 insertions(+), 7 deletions(-)

diff --git a/hw/riscv/riscv-iommu.c b/hw/riscv/riscv-iommu.c
index 96a7fbdefcf3..155190d032dd 100644
--- a/hw/riscv/riscv-iommu.c
+++ b/hw/riscv/riscv-iommu.c
@@ -558,6 +558,7 @@ static MemTxResult riscv_iommu_msi_write(RISCVIOMMUState *s,
     MemTxResult res;
     dma_addr_t addr;
     uint64_t intn;
+    size_t offset;
     uint32_t n190;
     uint64_t pte[2];
     int fault_type = RISCV_IOMMU_FQ_TTYPE_UADDR_WR;
@@ -565,16 +566,18 @@ static MemTxResult riscv_iommu_msi_write(RISCVIOMMUState *s,
 
     /* Interrupt File Number */
     intn = riscv_iommu_pext_u64(PPN_DOWN(gpa), ctx->msi_addr_mask);
-    if (intn >= 256) {
-        /* Interrupt file number out of range */
-        res = MEMTX_ACCESS_ERROR;
-        cause = RISCV_IOMMU_FQ_CAUSE_MSI_LOAD_FAULT;
-        goto err;
-    }
+    offset = intn * sizeof(pte);
 
     /* fetch MSI PTE */
     addr = PPN_PHYS(get_field(ctx->msiptp, RISCV_IOMMU_DC_MSIPTP_PPN));
-    addr = addr | (intn * sizeof(pte));
+    if (addr & offset) {
+        /* Interrupt file number out of range */
+        res = MEMTX_ACCESS_ERROR;
+        cause = RISCV_IOMMU_FQ_CAUSE_MSI_LOAD_FAULT;
+        goto err;
+    }
+
+    addr |= offset;
     res = dma_memory_read(s->target_as, addr, &pte, sizeof(pte),
             MEMTXATTRS_UNSPECIFIED);
     if (res != MEMTX_OK) {
-- 
2.49.0
Re: [PATCH] hw/riscv/riscv-iommu: Fix MSI table size limit
Posted by Daniel Henrique Barboza 1 day, 18 hours ago

On 9/4/25 10:27 AM, Andrew Jones wrote:
> The MSI table is not limited to 4k. The only constraint the table has
> is that its base address must be aligned to its size, ensuring no
> offsets of the table size will overrun when added to the base address
> (see "8.5. MSI page tables" of the AIA spec).
> 
> Fixes: 0c54acb8243d ("hw/riscv: add RISC-V IOMMU base emulation")
> Signed-off-by: Andrew Jones <ajones@ventanamicro.com>
> ---

Reviewed-by: Daniel Henrique Barboza <dbarboza@ventanamicro.com>

>   hw/riscv/riscv-iommu.c | 17 ++++++++++-------
>   1 file changed, 10 insertions(+), 7 deletions(-)
> 
> diff --git a/hw/riscv/riscv-iommu.c b/hw/riscv/riscv-iommu.c
> index 96a7fbdefcf3..155190d032dd 100644
> --- a/hw/riscv/riscv-iommu.c
> +++ b/hw/riscv/riscv-iommu.c
> @@ -558,6 +558,7 @@ static MemTxResult riscv_iommu_msi_write(RISCVIOMMUState *s,
>       MemTxResult res;
>       dma_addr_t addr;
>       uint64_t intn;
> +    size_t offset;
>       uint32_t n190;
>       uint64_t pte[2];
>       int fault_type = RISCV_IOMMU_FQ_TTYPE_UADDR_WR;
> @@ -565,16 +566,18 @@ static MemTxResult riscv_iommu_msi_write(RISCVIOMMUState *s,
>   
>       /* Interrupt File Number */
>       intn = riscv_iommu_pext_u64(PPN_DOWN(gpa), ctx->msi_addr_mask);
> -    if (intn >= 256) {
> -        /* Interrupt file number out of range */
> -        res = MEMTX_ACCESS_ERROR;
> -        cause = RISCV_IOMMU_FQ_CAUSE_MSI_LOAD_FAULT;
> -        goto err;
> -    }
> +    offset = intn * sizeof(pte);
>   
>       /* fetch MSI PTE */
>       addr = PPN_PHYS(get_field(ctx->msiptp, RISCV_IOMMU_DC_MSIPTP_PPN));
> -    addr = addr | (intn * sizeof(pte));
> +    if (addr & offset) {
> +        /* Interrupt file number out of range */
> +        res = MEMTX_ACCESS_ERROR;
> +        cause = RISCV_IOMMU_FQ_CAUSE_MSI_LOAD_FAULT;
> +        goto err;
> +    }
> +
> +    addr |= offset;
>       res = dma_memory_read(s->target_as, addr, &pte, sizeof(pte),
>               MEMTXATTRS_UNSPECIFIED);
>       if (res != MEMTX_OK) {