18.1-2Pointer Masking: Tags in the Top Bits

Part II Linux boot: optional Vol. II (Privileged) pp. 194–200 · ~3 min read

  • pointer masking

Pointer masking 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

Worked example (Table 61): PMLEN=7, address 0xABFF_FFFF_1234_5678
RuleTransformed
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
Dotted-underlined cells have explanations — click one.

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

PMM fields (WARL: 00 off, 10 PMLEN=7, 11 PMLEN=16, 01 reserved) — always in the next-higher mode’s CSR
Configured byExtension
M-modemseccfg.PMMSmmpm
S / HSmenvcfg.PMMSmnpm
VShenvcfg.PMMSsnpm
U / VUsenvcfg.PMM (+ hstatus.HUPMM for U-mode HLV/HSV acting as VU)Ssnpm
Dotted-underlined cells have explanations — click one.

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?

4 questions