# 43 — GMMU PTE/PDE decoder for TU104 (in development) > **Status: in development (2026-10-03, G2 work package).** This page > documents `sim/gmmu_pte.py`: a clean-room decoder for captured Turing > (TU104) GMMU page-table entries. It is decode-only tooling — no hardware, > no kernel module, no mdev, no guest, no RM 610. Development-only, never > shipped. > > **Rule: decode captured data only; validate against a capture before > trusting.** Every field position below is a reverse-engineering result; > none of it is a silicon-accuracy or timing claim (`06-ACCURACY.md` > fidelity levels apply). ## 1. What this is — and is not `sim/gmmu_pte.py` turns a captured page-table value or blob into named fields with exact bit positions. It is **not** a page-table walker: it never dereferences a decoded address, never reads a target table, and never fills a gap with a guess. Unsupported encodings and levels raise `E_UNSUPPORTED`; set bits that no named field covers are reported (`reserved_bits` / `reserved_mask`) and never dropped. The evidence base is the Turing GMMU entry-format definitions (field names, bit ranges, aperture/KIND numeric IDs) together with the driver's own page-table encoder/decoder behaviour, which is what proves which of the several described encodings Turing actually uses (VER2) and how the page-tree geometry maps to virtual-address bits. ## 2. Encodings shipped | Encoding | Size | Used for | |---|---|---| | `ver2` | 8 bytes | VER2 leaf PTE and directory PDE — the encoding the Turing driver's page-tree path programs | | `ver2_dual` | 16 bytes | VER2 dual PDE0 slot for mixed 64K/4K page tables: BIG half (low 64 bits) + SMALL half (high 64 bits) | Known-but-unsupported encodings (explicit `E_UNSUPPORTED`): the older non-VER2 PTE/PDE encoding and the "NEW"/VER1 encodings also described by the same register definitions. They are not shipped because the Turing driver's page-tree path uses VER2; adding them without a capture to validate against would be unverified surface. See §8. ## 3. VER2 leaf PTE (8 bytes) | Field (our name) | Bits | Meaning | |---|---|---| | `valid` | 0 | entry is present | | `aperture` / `aperture_name` | 2:1 | 0 video, 1 peer, 2 system coherent, 3 system non-coherent | | `volatile` | 3 | cache/volatility bit: 0 = cached, 1 = volatile (the format's cache-related field) | | `encrypted` | 4 | encrypted memory | | `privilege` | 5 | privileged access | | `read_only` (`writable`) | 6 | write protection | | `atomic_disable` | 7 | atomics disabled | | `address_sys` | 53:8 | system-aperture address bits (PA 53:12) | | `address_vid` | 32:8 | video/peer address bits (PA 36:12) | | `peer_id` | 35:33 | peer/fabric id (peer aperture) | | `comptagline` | 55:36 | compression tag; overloaded as high address bits for the documented 47-bit peer case | | `kind` / `kind_name` | 63:56 | memory kind id (see §6); unknown ids are reported, not guessed | ## 4. VER2 directory PDE (8 bytes) | Field (our name) | Bits | Meaning | |---|---|---| | `is_pde_pointer` / `is_leaf` | 0 | 0 = pointer to a lower table, 1 = 2 MB leaf PTE stored at PDE0 | | `aperture` / `aperture_name` | 2:1 | 0 invalid, 1 video, 2 system coherent, 3 system non-coherent | | `volatile` | 3 | as PTE | | `no_ats` | 5 | skip the ATS lookup for the covered range (driver sets it at depth 2) | | `address_sys` | 53:8 | next-table address bits (system aperture) | | `address_vid` | 32:8 | next-table address bits (video aperture) | | `peer_id` | 35:33 | peer/fabric id | Note the aperture-id difference: for a leaf PTE aperture 0 is video memory; for a directory PDE aperture 0 is invalid. ## 5. VER2 dual PDE0 (16 bytes) The BIG half is the low 64 bits, the SMALL half the high 64 bits. Bit 0 applies to the whole slot. | Field (our name) | Bits | Meaning | |---|---|---| | `is_pde_pointer` / `is_leaf` | 0 | whole-slot discriminator | | `aperture_big` | 2:1 | 0 invalid, 1 video, 2 system coherent, 3 system non-coherent | | `volatile_big` | 3 | as PTE | | `no_ats` | 5 | ATS skip; lies inside the BIG address field (see §7) | | `address_big_sys` | 53:4 | BIG target address; stores address >> 8 (PA 57:8) | | `address_big_vid` | 32:4 | BIG target address, video aperture | | `peer_id_big` | 35:33 | BIG peer/fabric id | | `aperture_small` | 66:65 | as `aperture_big` | | `volatile_small` | 67 | as PTE | | `address_small_sys` | 117:72 | SMALL target address; stores address >> 12 (PA 57:12) | | `address_small_vid` | 96:72 | SMALL target address, video aperture | | `peer_id_small` | 99:97 | SMALL peer/fabric id | Bits 54–64, 68–71 and 118–127 are unnamed by the format definitions and are reported as reserved when set. ## 6. Page-tree geometry and KIND ids Turing's page-tree path inherits the Pascal/Volta geometry and uses the VER2 entry encoding. Depths are root (0) to leaf (4): | Depth | HW level | VA bits | Index bits | Entry size | Role | |---|---|---|---|---|---| | 0 | PDE3 | 48:47 | 2 | 8 | pointer PDE | | 1 | PDE2 | 46:38 | 9 | 8 | pointer PDE | | 2 | PDE1 | 37:29 | 9 | 8 | pointer PDE (NO_ATS here) | | 3 | PDE0 | 28:21 | 8 | 16 (dual) / 8 (2 MB leaf) | dual 64K/4K PDE, or a 2 MB leaf PTE | | 4 | PTE | 20:12 (4 KB) / 20:16 (64 KB) | 9 (4 KB) / 5 (64 KB) | 8 | leaf PTE | Supported page sizes: 2 MB (depth 3), 64 KB and 4 KB (depth 4); VA width 49 bits. A leaf entry alone does not tell 4 KB from 64 KB — the table's depth and page-size context do, so the decoder reports `page_size` as `4k_or_64k` when the depth is pinned to 4. The PTE `kind` field carries numeric ids (243 named values re-derived from the format definitions). Common compute values: `0x00 PITCH`, `0x06 GENERIC_MEMORY`, `0x07 INVALID`, `0x0F SMSKED_MESSAGE`, `0xFE GENERIC_16BX2`. Unknown ids decode as `kind_name: null`, `kind_known: false` with the raw value preserved. ## 7. Address decode and uncertainty * System apertures (`system_coherent_memory`, `system_non_coherent_memory`): the reconstructed `address` is complete (`address_complete: true`). * Video/peer apertures: only the low address bits are unambiguous (`address_complete: false`). `comptagline` is a compression tag in the normal case and is documented as overloaded for 47-bit peer addresses; the decoder therefore does not claim a complete video address. * Dual BIG address: the field stores `address >> 8`, so `address` is reconstructed as `field << 8`. Bit 5 of the slot is named `no_ats` and also lies inside the BIG address field (address bit 9). The decoder reports the flag from bit 5 and excludes that bit from the reconstructed BIG address; the raw `address_big_sys` / `address_big_vid` fields keep the bit visible. This assumes the target table is 4 KB aligned, which is the normal GPU allocation granularity — if a capture shows a non-aligned target, treat that entry as an unexplained case, not as proof of a different format. * Reserved-bit policy: `reserved_bits` lists every set bit not covered by a named field; `reserved_mask` is the same set as a mask. Nothing is silently dropped. * The VER2 PTE has no separate cache field: `volatile` (bit 3) is the only cache-related bit the format defines, so no cache encoding is invented. * `decode_table` is little-endian and never follows pointers; a blob whose length is not a multiple of `entry_size` raises `E_TRUNCATED`, an empty blob decodes to `[]`. ## 8. Supported levels and explicit gaps `levels` may pin the page-tree depth (0–4) or a sequence of acceptable depths. `None` (default) uses the full supported set and lets each entry's bit-0 discriminator choose between the leaf-PTE and directory-PDE views, reporting `level: null` plus `level_candidates` instead of guessing a single depth. Any depth outside 0–4 raises `E_UNSUPPORTED`. Explicit gaps (never guessed): 1. Pre-VER2 and "NEW"/VER1 encodings are not decoded (`E_UNSUPPORTED`). 2. The decoder does not walk tables, resolve virtual addresses, or infer a 4 KB vs 64 KB leaf page size from the entry alone. 3. No capture has been validated yet: the golden vectors are constructed field-by-field from the format definitions, not sampled from silicon. **Validate against a real capture before trusting a decode.** 4. No timing, device-environment, isolation or security claim is made; the simulator fidelity levels in `06-ACCURACY.md` apply. ## 9. Usage Python: ```python from sim.gmmu_pte import decode_pte, decode_table pte = decode_pte(0x0600000000123456, pte_kind="ver2") entries = decode_table(blob, base_pa=0x2000, entry_size=8, levels=4) dual = decode_table(blob16, base_pa=0x2000, entry_size=16, kind="ver2_dual", levels=3) ``` CLI: ```bash # one entry (default role "auto": bit 0 picks leaf vs directory) python3 -m sim.gmmu_pte --value 0x0600000000123456 --role pte python3 -m sim.gmmu_pte --value 0x0600000000123456 --json # a captured table blob, with the blob's GPU physical base address python3 -m sim.gmmu_pte --blob table.bin --base-pa 0x2000 python3 -m sim.gmmu_pte --blob table.bin --base-pa 0x2000 --levels 4 --json # a dual PDE0 slot python3 -m sim.gmmu_pte --blob dual.bin --base-pa 0x2000 \ --kind ver2_dual --entry-size 16 --levels 3 --json ``` Exit code 0 on success; 2 with an `E_*` code on stderr for unsupported kinds/levels, truncated blobs or bad values. JSON output is sorted-key and deterministic. ## 10. Tests `tests/test_gmmu_pte.py` builds every vector field-by-field from the tables above, asserts field round-trips, reserved-bit reporting (including the unnamed dual bit 64 and the unnamed PDE bits 4, 6, 7, 54–63), the NO_ATS overlap behaviour, unknown-kind reporting, unsupported kind/level/entry-size errors, empty and truncated blobs, deterministic output, and CLI success and error paths. 44 constructed golden entry vectors across 43 tests.