[PATCH v2] hw/riscv/riscv-iommu.c: Correct the validness check of iova

Jason Chien posted 1 patch 1 week, 2 days ago
hw/riscv/riscv-iommu.c | 23 ++++++++++++++++++++---
1 file changed, 20 insertions(+), 3 deletions(-)
[PATCH v2] hw/riscv/riscv-iommu.c: Correct the validness check of iova
Posted by Jason Chien 1 week, 2 days ago
From RISCV IOMMU spec section 2.1.3:
When SXL is 1, the following rules apply:
- If the first-stage is not Bare, then a page fault corresponding to the
original access type occurs if the IOVA has bits beyond bit 31 set to 1.
- If the second-stage is not Bare, then a guest page fault corresponding
to the original access type occurs if the incoming GPA has bits beyond bit
33 set to 1.

From RISCV IOMMU spec section 2.3 step 17:
Use the process specified in Section "Two-Stage Address Translation" of
the RISC-V Privileged specification to determine the GPA accessed by the
transaction.

From RISCV IOMMU spec section 2.3 step 19:
Use the second-stage address translation process specified in Section
"Two-Stage Address Translation" of the RISC-V Privileged specification
to translate the GPA A to determine the SPA accessed by the transaction.

This commit adds the iova check with the following rules:
- For Sv32, Sv32x4, Sv39x4, Sv48x4 and Sv57x4, the iova must be zero
extended.
- For Sv39, Sv48 and Sv57, the iova must be signed extended with most
significant bit.

Signed-off-by: Jason Chien <jason.chien@sifive.com>
Reviewed-by: Daniel Henrique Barboza <dbarboza@ventanamicro.com>
---
 hw/riscv/riscv-iommu.c | 23 ++++++++++++++++++++---
 1 file changed, 20 insertions(+), 3 deletions(-)

diff --git a/hw/riscv/riscv-iommu.c b/hw/riscv/riscv-iommu.c
index bbc95425b3..ff9deefe37 100644
--- a/hw/riscv/riscv-iommu.c
+++ b/hw/riscv/riscv-iommu.c
@@ -392,9 +392,26 @@ static int riscv_iommu_spa_fetch(RISCVIOMMUState *s, RISCVIOMMUContext *ctx,
 
         /* Address range check before first level lookup */
         if (!sc[pass].step) {
-            const uint64_t va_mask = (1ULL << (va_skip + va_bits)) - 1;
-            if ((addr & va_mask) != addr) {
-                return RISCV_IOMMU_FQ_CAUSE_DMA_DISABLED;
+            const uint64_t va_len = va_skip + va_bits;
+            const uint64_t va_mask = (1ULL << va_len) - 1;
+
+            if (pass == S_STAGE && va_len > 32) {
+                target_ulong mask, masked_msbs;
+
+                mask = (1L << (TARGET_LONG_BITS - (va_len - 1))) - 1;
+                masked_msbs = (addr >> (va_len - 1)) & mask;
+
+                if (masked_msbs != 0 && masked_msbs != mask) {
+                    return (iotlb->perm & IOMMU_WO) ?
+                                RISCV_IOMMU_FQ_CAUSE_WR_FAULT_S :
+                                RISCV_IOMMU_FQ_CAUSE_RD_FAULT_S;
+                }
+            } else {
+                if ((addr & va_mask) != addr) {
+                    return (iotlb->perm & IOMMU_WO) ?
+                                RISCV_IOMMU_FQ_CAUSE_WR_FAULT_VS :
+                                RISCV_IOMMU_FQ_CAUSE_RD_FAULT_VS;
+                }
             }
         }
 
-- 
2.43.2
Re: [PATCH v2] hw/riscv/riscv-iommu.c: Correct the validness check of iova
Posted by Alistair Francis 4 days, 12 hours ago
On Thu, Nov 14, 2024 at 4:57 PM Jason Chien <jason.chien@sifive.com> wrote:
>
> From RISCV IOMMU spec section 2.1.3:
> When SXL is 1, the following rules apply:
> - If the first-stage is not Bare, then a page fault corresponding to the
> original access type occurs if the IOVA has bits beyond bit 31 set to 1.
> - If the second-stage is not Bare, then a guest page fault corresponding
> to the original access type occurs if the incoming GPA has bits beyond bit
> 33 set to 1.
>
> From RISCV IOMMU spec section 2.3 step 17:
> Use the process specified in Section "Two-Stage Address Translation" of
> the RISC-V Privileged specification to determine the GPA accessed by the
> transaction.
>
> From RISCV IOMMU spec section 2.3 step 19:
> Use the second-stage address translation process specified in Section
> "Two-Stage Address Translation" of the RISC-V Privileged specification
> to translate the GPA A to determine the SPA accessed by the transaction.
>
> This commit adds the iova check with the following rules:
> - For Sv32, Sv32x4, Sv39x4, Sv48x4 and Sv57x4, the iova must be zero
> extended.
> - For Sv39, Sv48 and Sv57, the iova must be signed extended with most
> significant bit.
>
> Signed-off-by: Jason Chien <jason.chien@sifive.com>
> Reviewed-by: Daniel Henrique Barboza <dbarboza@ventanamicro.com>

Thanks!

Applied to riscv-to-apply.next

Alistair

> ---
>  hw/riscv/riscv-iommu.c | 23 ++++++++++++++++++++---
>  1 file changed, 20 insertions(+), 3 deletions(-)
>
> diff --git a/hw/riscv/riscv-iommu.c b/hw/riscv/riscv-iommu.c
> index bbc95425b3..ff9deefe37 100644
> --- a/hw/riscv/riscv-iommu.c
> +++ b/hw/riscv/riscv-iommu.c
> @@ -392,9 +392,26 @@ static int riscv_iommu_spa_fetch(RISCVIOMMUState *s, RISCVIOMMUContext *ctx,
>
>          /* Address range check before first level lookup */
>          if (!sc[pass].step) {
> -            const uint64_t va_mask = (1ULL << (va_skip + va_bits)) - 1;
> -            if ((addr & va_mask) != addr) {
> -                return RISCV_IOMMU_FQ_CAUSE_DMA_DISABLED;
> +            const uint64_t va_len = va_skip + va_bits;
> +            const uint64_t va_mask = (1ULL << va_len) - 1;
> +
> +            if (pass == S_STAGE && va_len > 32) {
> +                target_ulong mask, masked_msbs;
> +
> +                mask = (1L << (TARGET_LONG_BITS - (va_len - 1))) - 1;
> +                masked_msbs = (addr >> (va_len - 1)) & mask;
> +
> +                if (masked_msbs != 0 && masked_msbs != mask) {
> +                    return (iotlb->perm & IOMMU_WO) ?
> +                                RISCV_IOMMU_FQ_CAUSE_WR_FAULT_S :
> +                                RISCV_IOMMU_FQ_CAUSE_RD_FAULT_S;
> +                }
> +            } else {
> +                if ((addr & va_mask) != addr) {
> +                    return (iotlb->perm & IOMMU_WO) ?
> +                                RISCV_IOMMU_FQ_CAUSE_WR_FAULT_VS :
> +                                RISCV_IOMMU_FQ_CAUSE_RD_FAULT_VS;
> +                }
>              }
>          }
>
> --
> 2.43.2
>
>