[PATCH v3 0/2] target/riscv: pmp: fix stale PMP state across reset

Sebastian Alba Vives posted 2 patches 15 hours ago
target/riscv/tcg/pmp.c | 10 +++++++++-
1 file changed, 9 insertions(+), 1 deletion(-)
[PATCH v3 0/2] target/riscv: pmp: fix stale PMP state across reset
Posted by Sebastian Alba Vives 15 hours ago
v2 cleared the whole pmp_state with a memset. Alistair pointed out that
the priv spec only requires the A and L fields to be reset, so v3 splits
the change: 1/2 stays within what the spec mandates, and 2/2 handles the
derived state QEMU keeps alongside the architectural registers.

1/2 is the v1 fix. It bounds the loop by the number of implemented
regions rather than pmp_get_num_rules(), so entries past the last active
rule are no longer skipped.

2/2 clears pmp_state.addr[] and pmp_state.num_rules. Those are not
architectural, so the spec does not speak to them, but they are
recomputed on the pmpaddr and pmpcfg write paths only and never at
reset.

The second one is observable from a guest. A bare-metal M-mode program
configures PMP entry 0 as NA4 over [0x80100000, 0x80100003], resets
through sifive_test, and on the second boot performs an 8-byte load at
0x80100000, which starts inside the old range and ends outside it:

  tree          pmpcfg0 after reset   8-byte load at 0x80100000
  1/2 only      0x00000001            load access fault
  1/2 + 2/2     0x00000001            succeeds

The architectural state is identical in both runs. The difference is
that with 1/2 alone num_rules is still 1 and addr[0] still holds the old
bounds, so pmp_hart_has_privs() skips the no-rules short cut and reaches
the partially-inside check. That check calls pmp_is_in_range(), which
compares against addr[].sa and addr[].ea only, and returns before the A
field is ever tested.

v2: https://lore.kernel.org/qemu-devel/20261011040617.807504-1-sebasjosue84@gmail.com/
v1: https://lore.kernel.org/qemu-devel/20260916034331.2390427-1-sebasjosue84@gmail.com/

Sebastian Alba Vives (2):
  target/riscv: pmp: clear A and L on every implemented PMP entry at
    reset
  target/riscv: pmp: reset the derived PMP bounds and rule count

 target/riscv/tcg/pmp.c | 10 +++++++++-
 1 file changed, 9 insertions(+), 1 deletion(-)

-- 
2.43.0
Re: [PATCH v3 0/2] target/riscv: pmp: fix stale PMP state across reset
Posted by Alistair Francis 14 hours ago
On Wed, 2026-10-21 at 22:02 -0600, Sebastian Alba Vives wrote:
> v2 cleared the whole pmp_state with a memset. Alistair pointed out
> that
> the priv spec only requires the A and L fields to be reset, so v3
> splits
> the change: 1/2 stays within what the spec mandates, and 2/2 handles
> the
> derived state QEMU keeps alongside the architectural registers.
> 
> 1/2 is the v1 fix. It bounds the loop by the number of implemented
> regions rather than pmp_get_num_rules(), so entries past the last
> active
> rule are no longer skipped.
> 
> 2/2 clears pmp_state.addr[] and pmp_state.num_rules. Those are not
> architectural, so the spec does not speak to them, but they are
> recomputed on the pmpaddr and pmpcfg write paths only and never at
> reset.
> 
> The second one is observable from a guest. A bare-metal M-mode
> program
> configures PMP entry 0 as NA4 over [0x80100000, 0x80100003], resets
> through sifive_test, and on the second boot performs an 8-byte load
> at
> 0x80100000, which starts inside the old range and ends outside it:
> 
>   tree          pmpcfg0 after reset   8-byte load at 0x80100000
>   1/2 only      0x00000001            load access fault
>   1/2 + 2/2     0x00000001            succeeds
> 
> The architectural state is identical in both runs. The difference is
> that with 1/2 alone num_rules is still 1 and addr[0] still holds the
> old
> bounds, so pmp_hart_has_privs() skips the no-rules short cut and
> reaches
> the partially-inside check. That check calls pmp_is_in_range(), which
> compares against addr[].sa and addr[].ea only, and returns before the
> A
> field is ever tested.
> 
> v2:
> https://lore.kernel.org/qemu-devel/20261011040617.807504-1-sebasjosue84@gmail.com/
> v1:
> https://lore.kernel.org/qemu-devel/20260916034331.2390427-1-sebasjosue84@gmail.com/

Thanks!

Applied to riscv-to-apply.next

Alistair

> 
> Sebastian Alba Vives (2):
>   target/riscv: pmp: clear A and L on every implemented PMP entry at
>     reset
>   target/riscv: pmp: reset the derived PMP bounds and rule count
> 
>  target/riscv/tcg/pmp.c | 10 +++++++++-
>  1 file changed, 9 insertions(+), 1 deletion(-)