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

Alistair <[email protected]>
Newsgroups org.nongnu.qemu-riscv,org.nongnu.qemu-devel
Message-ID <[email protected]>
On Fri, 2026-07-17 at 13:23 +0200, Andrew Jones wrote:
> 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 <[email protected]>

Thanks!

Applied to riscv-to-apply.next

Alistair

> ---
>  hw/riscv/riscv-iommu.c | 14 +++++++-------
>  1 file changed, 7 insertions(+), 7 deletions(-)
> 
> diff --git a/hw/riscv/riscv-iommu.c b/hw/riscv/riscv-iommu.c
> index f6865d1e164e..ed9fb09f8bc7 100644
> --- a/hw/riscv/riscv-iommu.c
> +++ b/hw/riscv/riscv-iommu.c
> @@ -476,13 +476,6 @@ static int riscv_iommu_spa_fetch(RISCVIOMMUState
> *s, RISCVIOMMUContext *ctx,
>              break;                /* Invalid PTE */
>          } else if (pte & PTE_RESERVED(false)) {
>              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) {
> @@ -491,6 +484,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)) {
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.