All the Sv schemes are one design — a radix tree of 4 KiB page-table nodes, walked by hardware — differing only in depth. Sv32 (SXLEN=32): 2 levels, 4-byte PTEs pte Page Table Entry: V validity, R/W/X permissions (000 = pointer to next level; W without R reserved), U user-accessible, G global, A accessed, D dirty, RSW software bits, PPN. RV64 formats add N (Svnapot) and PBMT (Svpbmt) in the high bits. defined in ch. II·12 — open in glossary . Sv39/48/57 (SXLEN=64): 3/4/5 levels, 8-byte PTEs, 512 entries per node. Every table is exactly one page, page-aligned; the root’s physical page number lives in satp.
Address formats
Sv48 prepends VPN[3] (bits 47:39, canonical above 47); Sv57 prepends VPN[4] (bits 56:48). The translated PPN is 22 bits on Sv32 (34-bit physical addresses — RV32 reaches beyond 4 GiB) and 44 bits on all the RV64 schemes (56-bit physical). Canonicality is sign-based, not zero-based: the entrenched OS convention of user-low/kernel-high falls out of one bit test.
The PTE
Sv32’s PTE is the 4-byte tail of this (PPN[1] 12b, PPN[0] 10b, bits 9:0 identical). Any level may hold a leaf: Sv32 offers 4 MiB megapages; Sv39 adds 2 MiB megapages + 1 GiB gigapages; Sv48 adds 512 GiB terapages — each virtually and physically aligned to its size, or page fault. Fetch from X=0, load from R=0 (MXR relaxes to R∨X), store to W=0 → the corresponding page fault; AMOs raise only store faults. For non-leaf PTEs, D/A/U are reserved-zero. With A and paging, the LR/SC reservation set must fit in one 4 KiB page.
Accessed & Dirty
Two conformant schemes, all harts alike:
- Svade: touching a page with A=0 (or storing with D=0) page faults; the OS maintains A/D in the handler. Radically simpler hardware.
- Hardware update (Svadu, gated by menvcfg.ADUE): the walker sets A (and D on stores) itself — atomically compare-and-swap against the value it walked, re-running all checks, restarting the walk on mismatch. A may be set speculatively (prefetcher-friendly); D must be exact and program-ordered, and the PTE update must hit the global memory order before the store that caused it. Page tables must live in RsrvEventual PMA memory.
The algorithm
a= satp.ppn × 4096,i= LEVELS−1 (satp must be active).- Read
pteata + va.vpn[i] × PTESIZE— one atomic PTESIZE-wide access; PMA/PMP violation → access fault. pte.v=0, or R=0∧W=1, or any reserved bit set → page fault.- R∨X → leaf (step 5). Else descend:
i−−(i<0→ page fault),a= pte.ppn × 4096, back to 2. - Leaf at i>0 with ppn[i−1:0] ≠ 0 → misaligned superpage, page fault.
- Privilege check (U bit vs mode, SUM, MXR) → page fault if denied.
- Shadow-stack rules (Zicfiss) → access fault if violated.
- R/W/X permission check → page fault.
- A=0, or store with D=0 → Svade: page fault; else the CAS update (PMP/PMA-checked as a store now; mismatch → step 2).
- Done:
pa.pgoff = va.pgoff; superpage:pa.ppn[i−1:0] = va.vpn[i−1:0];pa.ppn[LEVELS−1:i] = pte.ppn[LEVELS−1:i].
Step-2 reads may be served by the SFENCE.VMA sfence.vma Supervisor memory-management fence: orders prior stores before subsequent implicit page-table reads and invalidates address-translation cache entries, filtered by rs1 (one VA) and rs2 (one ASID) — x0 meaning 'all'. Local-hart only; cross-hart shootdown = fence + IPI + remote SFENCE.VMA. defined in ch. II·12 — open in glossary -governed translation cache — hart-private, read-only, incoherent, arbitrarily many entries per (VA, ASID). Step 9 never uses the cache: A/D updates go to memory. Speculative walks may pre-warm the cache any time satp is active, but must not set D, fault, or install entries an intervening fence would have killed.
Hardware Designer Notes
The walker is roughly: a 3-state FSM (issue read, check, descend/finish)
- one PTESIZE register + the permission-check combinational block, with its memory port arbitrated into the L2 or D-cache. Latency is LEVELS × memory-round-trip on a TLB miss — which is why walk caches holding non-leaf PTEs matter long before associativity tuning does.
Minimal Linux-boot hart MUST
- Build the walker as the 10-step state machine: PTESIZE-atomic reads, PMP/PMA check on every step-2 access, reserved-bit and W-without-R rejection, superpage alignment check, and the U/SUM/MXR permission mux
- Pick an A/D scheme: Svade (trap, no write path in the walker) or Svadu (CAS loop + RsrvEventual requirement) — all harts identical
- Enforce canonical-VA checks at effective-address generation (a wide AND/NAND tree on the high bits) raising PAGE faults, not access faults
MAY simplify / trap-and-emulate
- Implement Sv39 only — the Linux-boot floor; add Sv48/57 as market demands (same PTE format, one more index mux level each)
- Cache non-leaf PTEs ("walk caches") and leaves in split TLBs — all invisible under the translation-cache abstraction
- Start with Svade: Linux supports it, and it deletes the walker’s entire store path
Check yourself — Sv32/Sv39/Sv48 translation
1.During a walk, the walker reads a PTE with V=1, R=0, W=1. What happens?
2.A leaf is found at level i=1 of an Sv39 walk with pte.ppn[0] ≠ 0. What happens, and why does the rule exist?
3.How does hardware A/D-bit updating (the non-Svade scheme) interact with a concurrent PTE modification by another hart?
4.Why does Sv39 demand VA bits 63:39 equal bit 38 (canonical form) instead of zero-extension?
5.An Sv48 walker wants to read a level-2 PTE with two 4-byte reads. Legal?