Repository navigation
[Bug] CSR: MPRV-mediated PMP fault raises wrong exception code (mcause=2 or 3 instead of 5 or 7) #3812
Description
Introduction
When mstatus.MPRV=1 triggers a PMP access fault (load or store to a region denied for the privilege level in mstatus.MPP), Rocket reports the wrong exception code:
- MPRV load fault → Rocket gives
mcause=2(Illegal Instruction) instead ofmcause=5(Load Access Fault) - MPRV store fault → Rocket gives
mcause=3(Store/AMO Address Misaligned) instead ofmcause=7(Store/AMO Access Fault)
This violates RISC-V Privileged ISA §3.7.4. MPRV PASS contracts complete correctly — the bug is specific to the fault path.
Steps to reproduce
Environment:
- Rocket:
simulator-chipyard.harness-RocketConfig(Chipyard Verilator build) - Reference oracle: Spike ISA simulator 1.1.0
Setup:
PMP entry 0: NAPOT @ secret_region (4 KB), L=1 (locked), R=0, W=0, X=0 ← deny all modes
PMP entry 1: TOR covering all other addresses, L=0, R=1, W=1, X=1 ← allow all else
mstatus.MPRV = 1
mstatus.MPP = 01 (Supervisor mode)
Test sequence:
# MPRV load (effective S-mode privilege):
ld a1, 0(secret_region) # → should raise mcause=5
# trap_handler: csrr a0, mcause; exit(a0)
# MPRV store (effective S-mode privilege):
sd zero, 0(secret_region) # → should raise mcause=7
# trap_handler: csrr a0, mcause; exit(a0)Run:
# Load fault test (MS002.elf equivalent):
spike --isa=rv64imac_zicsr --priv=msu --pmpregions=16 --pmpgranularity=4 ms002.elf
# Spike: *** FAILED *** (tohost = 5) ← mcause=5 correct
./simulator-chipyard.harness-RocketConfig ms002.elf
# Rocket: *** FAILED *** (tohost = 2) ← mcause=2 WRONG (Illegal Instruction)
# Store fault test (MS004.elf equivalent):
spike ... ms004.elf
# Spike: *** FAILED *** (tohost = 7) ← mcause=7 correct
./simulator-chipyard.harness-RocketConfig ms004.elf
# Rocket: *** FAILED *** (tohost = 3) ← mcause=3 WRONG (Store Misaligned)Expected behavior
Per RISC-V Privileged ISA §3.7.4:
"Load access-fault exception (code 5) ... Store/AMO access-fault exception (code 7)."
"When MPRV=1, data memory accesses use the privilege mode in MPP."
The MPRV bit changes which privilege level's PMP permissions apply — it does not change which exception code is generated. A fault on a load must always give mcause=5; a fault on a store must always give mcause=7.
| Contract | Access | Spec | Spike | Rocket |
|---|---|---|---|---|
| MS002 | MPRV load, PMP-deny | mcause=5 | 5 ✓ | 2 ✗ |
| MS004 | MPRV store, PMP-deny | mcause=7 | 7 ✓ | 3 ✗ |
| MS001 | MPRV load, PMP-allow | exit=0 (PASS) | 0 ✓ | 0 ✓ |
| MS003 | MPRV store, PMP-allow | exit=0 (PASS) | 0 ✓ | 0 ✓ |
Observed behavior
Rocket:
- MPRV load fault:
mcause=2(Illegal Instruction) — wrong category entirely - MPRV store fault:
mcause=3(Store/AMO Address Misaligned) — wrong category entirely
The fault is being routed to an instruction-decode error path (mcause=2) or address alignment error path (mcause=3), rather than the memory access fault path (mcause=5/7). This suggests the MPRV-triggered PMP exception is not reaching the correct exception handler.
Additional context
Root cause hypothesis:
When MPRV=1 triggers a PMP fault, the exception may be generated in a pipeline stage (or via a code path) that produces decode-stage or alignment-check exception codes rather than memory-access-fault codes. The MPRV fault path may not connect to the same exception routing logic as non-MPRV PMP faults.
Reproducibility note:
This bug is sensitive to PMP configuration. The wrong-mcause behavior was observed with specific locked/unlocked NAPOT and TOR configurations. Some configurations may produce correct mcause. Exact reproduction requires the specific PMP setup described above (locked entry with no permissions).
Relationship to #3811:
[#3811 and this issue both involve wrong exception codes in Rocket. #3811 affects the CSR privilege violation path (mcause=1 instead of 2). This issue affects the MPRV memory fault path (mcause=2/3 instead of 5/7). Both may share the same root cause in checkExceptions priority ordering in RocketCore.scala.
Security impact:
M-mode exception handlers that dispatch on mcause=5 or mcause=7 to detect MPRV-triggered PMP violations will not be triggered. MPRV faults will appear as instruction decode errors or address misalignment errors, potentially causing incorrect handler invocation, silent fault suppression, or incorrect recovery behavior in TEE runtimes.
Discovery method:
Found using ICDT (ISA Contract Differential Testing) — MSTATUS_MPRV contract suite (MS001–MS005).
Activity