@samitouri / QOSamiQemu / commits / f16fd27b3f

hw/riscv/riscv-iommu: fix U-bit check to apply only to leaf S/VS-stage PTEs

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") Signed-off-by: Andrew Jones <andrew.jones@oss.qualcomm.com> Reviewed-by: Daniel Henrique Barboza <daniel.barboza@oss.qualcomm.com> Reviewed-by: Nutty Liu <nutty.liu@hotmail.com> Message-ID: <20260717112340.1071148-1-andrew.jones@oss.qualcomm.com> Signed-off-by: Alistair Francis <alistair.francis@wdc.com>

Andrew Jones committed Jul 17, 2026 at 13:23 UTC f16fd27b3fe3c305d95c61d3516e458c45c6e8c9
1 file changed +7 -7
hw/riscv/riscv-iommu.c
+7 -7
@@ -476,13 +476,6 @@ static int riscv_iommu_spa_fetch(RISCVIOMMUState *s, RISCVIOMMUContext *ctx,
476 break; /* Invalid PTE */
477 } else if (pte & PTE_RESERVED(false)) {
478 break; /* Reserved PTE bits set */
479 - } else if (!(pte & PTE_U) && !pv) {
480 - /*
481 - * All accesses are assumed to be User mode unless
482 - * process_id is valid (pv). In case we have a
483 - * non-user mode PTE and !pv we need to fault.
484 - */
485 - break;
479 } else if (!(pte & (PTE_R | PTE_W | PTE_X))) {
480 base = PPN_PHYS(ppn); /* Inner PTE, continue walking */
481 } else if ((pte & (PTE_R | PTE_W | PTE_X)) == PTE_W) {
@@ -491,6 +484,13 @@ static int riscv_iommu_spa_fetch(RISCVIOMMUState *s, RISCVIOMMUContext *ctx,
484 break; /* Reserved leaf PTE flags: PTE_W + PTE_X */
485 } else if (ppn & ((1ULL << (va_skip - TARGET_PAGE_BITS)) - 1)) {
486 break; /* Misaligned PPN */
487 + } else if (!(pte & PTE_U) && !pv) {
488 + /*
489 + * All accesses are assumed to be User mode unless
490 + * process_id is valid (pv). In case we have a
491 + * non-user mode leaf PTE and !pv we need to fault.
492 + */
493 + break;
494 } else if ((iotlb->perm & IOMMU_RO) && !(pte & PTE_R)) {
495 break; /* Read access check failed */
496 } else if ((iotlb->perm & IOMMU_WO) && !(pte & PTE_W)) {