Pointer masking pointer masking RV64 family (Ssnpm/Smnpm/Smmpm): the top PMLEN bits (7 or 16) of every explicit-access effective address are ignored — sign-extended away for virtual addresses, zeroed for physical — so software like HWASAN can keep tags there. Per-mode enables live in the next-higher mode's envcfg PMM field; MXR suppresses it; implicit accesses and fences are never masked. defined in ch. II·18 — open in glossary makes the CPU ignore the top PMLEN bits (7 or 16, RV64 only) of every explicit memory access’s effective address — so HWASAN-style tools can keep a tag there and check it (in software, for now) without stripping it before every load. The transformation is purely arithmetic and mode-blind: the same tagged pointer works identically wherever the code runs.
The ignore transformation
| Rule | Transformed | |
|---|---|---|
| Virtual (satp.MODE ≠ Bare) | Top PMLEN bits ← sign-extension of bit XLEN−PMLEN−1 — the result is always CANONICAL. | 0xFFFF_FFFF_1234_5678 (bit 56 was 1) |
| Physical (Bare, M-mode, GPAs) | Top PMLEN bits ← zero — the result is always a valid physical address. | 0x01FF_FFFF_1234_5678 |
Each rule reproduces its regime’s validity convention (VA: sign; PA: zero), which enables the cheap implementation: if PMLEN ≤ NVBITS of your largest translation mode, “masking” is merely relaxing the canonicality check — no datapath change. Masking into TLB-tag bits (PMLEN=16 with Sv48) or into VBITS costs real hardware.
Who configures whom
| Configured by | Extension | |
|---|---|---|
| M-mode | mseccfg.PMM | Smmpm |
| S / HS | menvcfg.PMM | Smnpm |
| VS | henvcfg.PMM | Ssnpm |
| U / VU | senvcfg.PMM (+ hstatus.HUPMM for U-mode HLV/HSV acting as VU) | Ssnpm |
The active privilege mode (or, under MPRV/SPVP, the effective one) selects the setting — never the address value. Linux’s kernel-high/user-low MSB convention migrates to bit XLEN−PMLEN−1; an ABI may require the real MSB to replicate it. Profile markers Sspm/Supm assert “PM is available at S/U somehow” without naming the controlling CSR. On RV32 — or whenever UXL/SXL/MXL drops a mode to 32 bits — enabling PM is an illegal WARL write, and narrowing XLEN clears the PMM bits non-restoratively.
What gets masked
Everything explicit: base/FP/atomic/compressed loads and stores (SP-relative included), RVV memory ops, Zicfiss shadow-stack ops, HLV/HSV per hstatus’s rules, and all cache management operations — CBO.ZERO is a store, and an unmasked CBO.FLUSH would hand U-mode a flush-arbitrary-addresses side channel.
Never masked: implicit accesses (page walks, fetches), SFENCE/HFENCE/SINVAL/HINVAL address arguments, DMA/IOMMU/device traffic (software untags for them), and — the subtle one — any access where MXR is in effect, even under Bare translation where MXR otherwise does nothing. Misaligned accesses behave as if each byte were individually transformed. CSRs are never masked on software access (WARL widths unchanged), but hardware address writes — stval on a fault, debug trigger matching — do apply the mask; trap delivery from stvec doesn’t.
Hardware Designer Notes
Decide early whether PMLEN=16 must coexist with Sv57 — that single choice determines whether your TLB tags are fixed-width or mode-conditional, and it’s miserable to retrofit.
Minimal Linux-boot hart MUST
- Put the PM mux in address generation: per-effective-mode 2-bit setting selecting off / sign-extend-from-56 / sign-extend-from-47 (VA) or zero-fill (PA)
- Gate PM off when MXR is in effect, and apply it to every CMO address
- Route the TRANSFORMED address to stval/trigger comparators, while leaving software CSR accesses untouched
MAY simplify / trap-and-emulate
- Support only the PMLEN ≤ NVBITS cases and implement masking as relaxed canonicality checks — zero datapath cost
- Skip the whole family for Linux boot (all PMM fields RO-0); add Ssnpm+Smnpm when userspace HWASAN demand appears (Supm is in RVA23)
Check yourself — pointer masking
1.Why does the ignore transformation SIGN-extend for virtual addresses but ZERO the bits for physical ones?
2.Which of these does pointer masking NOT apply to?
3.Software writes a tagged address to stvec. A trap later delivers there. Then the trap's faulting address is written to stval. Where does masking apply?
4.Which extension lets M-mode itself run with masked pointers, and what happens on RV32?