From: Andrew Jones <[email protected]>
Commit b795ea0ba471 ("hw/riscv/riscv-iommu.c: fault when !PTE_U and
no priv access") placed its check ahead of the leaf-vs-non-leaf
branch in riscv_iommu_spa_fetch(), so it fires on every PTE walked,
including non-leaf/table entries. Per the RISC-V privileged spec's
address translation algorithm (Sv39/Sv48/etc., the "leaf PTE has
been reached" step, followed separately by the U-bit permission
check), the U bit is only defined and checked for the leaf PTE
reached at the end of the walk -- non-leaf PTEs don't carry a
meaningful U bit at all.
Move the check after the leaf/non-leaf branch, alongside the other
leaf-only checks, mirroring how the G_STAGE U-bit check (added in
9158c900ab30) is already correctly placed.
Fixes: b795ea0ba471 ("hw/riscv/riscv-iommu.c: fault when !PTE_U and no priv
access")
Fixes: 5952919d777c in 10.0.x
Signed-off-by: Andrew Jones <[email protected]>
Reviewed-by: Daniel Henrique Barboza <[email protected]>
Reviewed-by: Nutty Liu <[email protected]>
Message-ID: <[email protected]>
Signed-off-by: Alistair Francis <[email protected]>
(cherry picked from commit f16fd27b3fe3c305d95c61d3516e458c45c6e8c9)
Signed-off-by: Michael Tokarev <[email protected]>
diff --git a/hw/riscv/riscv-iommu.c b/hw/riscv/riscv-iommu.c
index 9c725027aa5..97796a414ff 100644
--- a/hw/riscv/riscv-iommu.c
+++ b/hw/riscv/riscv-iommu.c
@@ -473,13 +473,6 @@ static int riscv_iommu_spa_fetch(RISCVIOMMUState *s,
RISCVIOMMUContext *ctx,
break; /* Invalid PTE */
} else if (pte & PTE_RESERVED) {
break; /* Reserved PTE bits set */
- } else if (!(pte & PTE_U) && !pv) {
- /*
- * All accesses are assumed to be User mode unless
- * process_id is valid (pv). In case we have a
- * non-user mode PTE and !pv we need to fault.
- */
- break;
} else if (!(pte & (PTE_R | PTE_W | PTE_X))) {
base = PPN_PHYS(ppn); /* Inner PTE, continue walking */
} else if ((pte & (PTE_R | PTE_W | PTE_X)) == PTE_W) {
@@ -488,6 +481,13 @@ static int riscv_iommu_spa_fetch(RISCVIOMMUState *s,
RISCVIOMMUContext *ctx,
break; /* Reserved leaf PTE flags: PTE_W + PTE_X */
} else if (ppn & ((1ULL << (va_skip - TARGET_PAGE_BITS)) - 1)) {
break; /* Misaligned PPN */
+ } else if (!(pte & PTE_U) && !pv) {
+ /*
+ * All accesses are assumed to be User mode unless
+ * process_id is valid (pv). In case we have a
+ * non-user mode leaf PTE and !pv we need to fault.
+ */
+ break;
} else if ((iotlb->perm & IOMMU_RO) && !(pte & PTE_R)) {
break; /* Read access check failed */
} else if ((iotlb->perm & IOMMU_WO) && !(pte & PTE_W)) {
--
2.47.3