Baseline PMP protects upward: it can wall S/U out of firmware memory. It cannot protect downward — M-mode ignores every unlocked rule, so a tricked firmware can be steered into executing attacker-staged code in user memory. S-mode already has defenses against the analogous attack (the U-bit execution ban, sstatus.SUM); Smepmp smepmp PMP enhancements: mseccfg.MML (sticky) reinterprets pmpcfg.L as rule ownership (L=1 M-only, L=0 S/U-only, RW=01 & LRWX=1111 shared regions) and restricts M-mode execution to M-rules; MMWP (sticky) denies no-match M accesses; RLB temporarily unlocks locked rules. Discovery via BootROM setting the sticky bits. defined in ch. II·6 — open in glossary gives M-mode the same, via three mseccfg fields (specified in ch. II·3).
MML: the reinterpreted L bit
With mseccfg.MML=1 (sticky), pmpcfg.L stops meaning “locked for
everyone” and starts meaning whose rule this is:
| M-mode | S/U-mode | |
|---|---|---|
| L=0 0000 | Access exception | Access exception (inaccessible) |
| L=0 rwx=001 | Access exception | Execute-only |
| L=0 rwx=010 | Read/write | Read-only |
| L=0 rwx=011 | Read/write (shared data) | Read/write |
| L=0 rwx=100/101/110/111 | Access exception | RO / RX / RW / RWX — ordinary S/U-only rules |
| L=1 0000* | Access exception | Access exception (locked inaccessible) |
| L=1 rwx=001* | Execute-only | Access exception |
| L=1 rwx=010* | Execute-only (shared code) | Execute-only |
| L=1 rwx=011* | Read/execute (shared code) | Execute-only |
| L=1 rwx=100/101/110* | RO / RX / RW — M-mode-only rules | Access exception |
| L=1 rwx=111* | Read-only (shared data) | Read-only |
Two enforcement teeth come with it: adding executable M-mode rules after lockdown is impossible (such pmpcfg writes are ignored — RLB excepted), and M-mode may execute only from M-only or locked shared-code rules — no-rule or S/U-rule regions never feed the M-mode fetch unit.
MMWP and RLB
MMWP (sticky) flips M-mode’s no-match default from allowed to denied — combined with MML, machine mode operates under a strict allowlist frozen at boot. RLB is the escape hatch: while 1, locked rules may be edited (boot-time layout optimization, debug); once any locked rule exists with RLB=0, RLB is stuck at 0 until PMP reset. Vendors who dislike the weakening may hardwire RLB=0.
Hardware Designer Notes
Hardware delta over baseline PMP: one mseccfg decode, a 16-row permission ROM, and the fetch-path check. The payoff is the property security reviews actually ask for: after boot, machine mode cannot be made to execute anything outside its frozen allowlist — even by machine mode itself.
Minimal Linux-boot hart MUST
- Implement the MML permission table as a second decode of pmpcfg, selected by mseccfg.MML
- Enforce the M-mode fetch allowlist (M executes only from M-only/locked-shared-code rules) in the FETCH path
- Ignore post-lock writes that would create executable M-mode rules (unless RLB)
- Make MML/MMWP set-only and RLB stick-at-0, cleared only by PMP reset
MAY simplify / trap-and-emulate
- Hardwire RLB to 0 for a hardened product
- Skip Smepmp on a first Linux bring-up — OpenSBI runs without it — and add it with the secure-boot story
Check yourself — Smepmp
1.What attack does baseline PMP fundamentally fail to stop, motivating Smepmp?
2.With MML=1, what does an L=0, R=1, W=1, X=1 rule grant?
3.Why can't software probe mseccfg to detect Smepmp, and what's the sanctioned discovery?
4.MML=1 and MMWP=1. From which regions may M-mode fetch instructions?