Skip to content

[Bug] CSR: MPRV-mediated PMP fault raises wrong exception code (mcause=2 or 3 instead of 5 or 7) #3812

Open

Description

@Security-HC

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 of mcause=5 (Load Access Fault)
  • MPRV store fault → Rocket gives mcause=3 (Store/AMO Address Misaligned) instead of mcause=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.

b12_trigger.log

Discovery method:
Found using ICDT (ISA Contract Differential Testing) — MSTATUS_MPRV contract suite (MS001–MS005).

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions