RISC-V PMP Regions: Check Entry Priority and the Entire Memory Access
A memory operation faults even though a PMP dump contains a broad region with the required permission. The tempting interpretation is that any matching allow entry should authorize it. Base RISC-V PMP does not combine overlapping entries that way.
Decode the entries in priority order, identify the first one that touches the operation, and then check whether that entry covers its complete byte span. This article concerns base PMP; Smepmp changes require a separate policy review.
Decode address matching before reading permissions
The Machine-Level ISA PMP section defines OFF, TOR, NA4 and NAPOT address-matching modes. The address registers contain encoded addresses rather than ordinary byte pointers.
For a TOR entry, the preceding address register supplies the lower bound and the current address register supplies the exclusive upper bound. The preceding entry's own configuration does not have to enable a region for its address to serve as that lower bound. Entry zero uses a lower bound of zero.
NAPOT encodes a naturally aligned power-of-two region using low-order address bits. As an illustrative 16-byte region starting at 0x80000000, the encoding is 0x20000001: the byte address is shifted right by two and the appropriate low bit marks the region size. Do not copy a byte base directly into pmpaddr.
The OpenSBI v1.9 PMP helper makes that distinction concrete. Its encoder selects NA4 for a four-byte request and NAPOT for larger supported powers of two, then masks and encodes the address. Its decoder is not a general TOR-region decoder; a diagnostic must still interpret TOR using the neighboring register.
The first partial match can reject an otherwise allowed operation
PMP priority is the lowest-numbered entry matching any byte of a memory operation. That selected entry must cover every byte of the operation. If it covers only part, the operation fails even when a later entry would allow the whole span.
Suppose entry zero covers bytes 0x0c through 0x0f, and entry one allows the wider surrounding region. An eight-byte memory operation at 0x08 spans 0x08 through 0x0f. Entry zero touches it first but does not contain it, so the broad entry one cannot rescue that operation. The addresses are hypothetical and illustrate the specification's matching rule.
Do not interpret the entries as a union of allowed ranges or as a last-match-wins firewall. Record entry index, decoded interval and complete operation interval together.

Separate one memory operation from one instruction
An instruction can be decomposed into multiple memory operations. The specification warns that some portions of a misaligned or wider store may become visible before another portion fails its PMP check.
Consequently, an access-fault trap is not a general rollback guarantee for the instruction. A proposed boundary test should use disposable buffers and account for the implementation's permitted decomposition, rather than assuming that all bytes remain untouched after a fault.
The first-partial-match rule applies to each memory operation. A trace showing a decomposed access must be interpreted differently from the single eight-byte operation in the example.
Include privilege, locking and implemented granularity
With the base rules, a matching unlocked entry does not enforce its R/W/X permissions on an M-mode access, while a locked entry does. That exception does not waive the complete-coverage matching rule. If no entry matches, M-mode succeeds; S/U accesses fail when PMP entries are implemented, even when all entries are OFF.
Implemented granularity can also make an apparent small region unavailable. Read the documented configuration and actual WARL readback. The lock bit can persist until reset and a locked TOR entry also constrains modification of its lower-bound address register, so live experiments with locking are inappropriate.
A useful review reconstructs the effective regions and predicts boundary outcomes before running controlled target checks. No PMP registers were programmed and no protected-memory accesses were attempted here.