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)
