On Wed, 2026-10-21 at 22:02 -0600, Sebastian Alba Vives wrote:
> The priv spec only requires the A and L fields to be reset, which the
> previous patch now does for every implemented entry. QEMU
> additionally
> keeps derived state next to the architectural registers:
> pmp_state.addr[] holds the decoded start and end address of each
> entry
> and pmp_state.num_rules caches the active rule count. Both are
> recomputed from the pmpaddr and pmpcfg write paths only, never at
> reset.
> 
> pmp_is_in_range() compares against addr[].sa and addr[].ea without
> consulting the A field, and the partially-inside check in
> pmp_hart_has_privs() runs before the A field is tested, so a range
> left over from before the reset can still deny an access that
> straddles its boundary once the guest configures any entry again.
> 
> Clear the derived state alongside the architectural fields so the two
> cannot disagree.
> 
> Signed-off-by: Sebastian Alba Vives <[email protected]>

Reviewed-by: Alistair Francis <[email protected]>

Alistair

> ---
>  target/riscv/tcg/pmp.c | 8 ++++++++
>  1 file changed, 8 insertions(+)
> 
> diff --git a/target/riscv/tcg/pmp.c b/target/riscv/tcg/pmp.c
> index 061f0e078d..04df53c234 100644
> --- a/target/riscv/tcg/pmp.c
> +++ b/target/riscv/tcg/pmp.c
> @@ -207,6 +207,14 @@ void pmp_unlock_entries(CPURISCVState *env)
>      for (i = 0; i < pmp_num; i++) {
>          env->pmp_state.pmp[i].cfg_reg &= ~(PMP_LOCK | PMP_AMATCH);
>      }
> +
> +    /*
> +     * addr[] and num_rules are derived from the pmpaddr and pmpcfg
> write
> +     * paths and are not recomputed at reset. Clear them here so
> they
> +     * cannot disagree with the architectural fields cleared above.
> +     */
> +    memset(env->pmp_state.addr, 0, sizeof(env->pmp_state.addr));
> +    env->pmp_state.num_rules = 0;
>  }
>  
>  static void pmp_decode_napot(hwaddr a, hwaddr *sa, hwaddr *ea)

Reply via email to