target/riscv/tcg/pmp.c | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-)
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
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(-)
© 2016 - 2026 Red Hat, Inc.