diff options
Diffstat (limited to 'debug/risc-v-gsp-rm-vm/docs/42-GMMU-FBIF-OBSERVABILITY.md')
| -rw-r--r-- | debug/risc-v-gsp-rm-vm/docs/42-GMMU-FBIF-OBSERVABILITY.md | 203 |
1 files changed, 203 insertions, 0 deletions
diff --git a/debug/risc-v-gsp-rm-vm/docs/42-GMMU-FBIF-OBSERVABILITY.md b/debug/risc-v-gsp-rm-vm/docs/42-GMMU-FBIF-OBSERVABILITY.md new file mode 100644 index 0000000..4a2d6ee --- /dev/null +++ b/debug/risc-v-gsp-rm-vm/docs/42-GMMU-FBIF-OBSERVABILITY.md @@ -0,0 +1,203 @@ +# 42 — GMMU/FBIF observability (in development) + +> **Status: in development (2026-10-03, G1 work package).** This page +> documents the observe-only GMMU and FBIF/FBPA register windows added to the +> device model, the `greeneye-gmmu-fbif-trace/1` document and the boot-runner +> flags that produce it. Development-only: nothing here authorises GPU +> hardware, kernel modules, mdev, guest access or reboots, and nothing here is +> a silicon-accuracy claim. +> +> **See also:** `36-GSP-DEVICE-MODEL.md` (the device model this plugs into), +> `06-ACCURACY.md` (fidelity levels), `24-DEVICE-MAP.md` (harvested access +> maps), `35-GREENEYE-SIMULATOR-DESIGN.md` §4.1 (the Phase G inventory this +> observability de-risks). + +## 1. What this is + +The Phase G board model needs the GMMU and the FB interface eventually. Before +modelling either, we need to know **what the firmware actually touches** in +those register windows, with which width and direction, from which PC, and +without pretending to know register behaviour we have not established. + +`sim/devices/observe.py` adds **observer windows**: device-model windows that +record every access and then **decline** it, so execution follows the existing +device-map / lenient / unknown path exactly as it did before the window +existed. They never invent a read value. + +## 2. What is observed + +The TU104 profile (`sim/profiles/tu104-570.144.json`) declares 23 observer +windows, all `observe-only`. Bases are runtime addresses in the GSP RISC-V +PRIV aperture (`0x2000_0000_0000_0000` + BAR0 offset); offsets/names come from +the hardware register/field headers (evidence kind: **header**). The B0–B2 +runs did not touch any of them; the B3 wave reaches the WPR2 read pair +(`0x1FA824/0x1FA828`), which falls inside the `gmmu-wpr-lock` window and is +recorded observe-only (2 accesses, 0 served; the fwsec device answers). + +| Window label | Runtime base | Size | Covers | +|---|---|---|---| +| `gmmu-pri-mmu` | `0x2000000000100C80` | `0x280` | `NV_PFB_PRI_MMU_*` cluster (`NV_PFB_PRI_MMU_CTRL` first) | +| `gmmu-wpr-lock` | `0x20000000001FA7D8` | `0x5C` | MMU per-engine PRIV_LEVEL masks + VPR/WPR/lock address pair | +| `gmmu-hsmmu` | `0x20000000001FAC00` | `0x400` | `NV_PFB_HSMMU_PRI_MMU_*` (secondary MMU block) | +| `fbpa` | `0x20000000009A0000` | `0x4000` | main FBPA block (`NV_PFB_FBPA_*`) | +| `fbpa-partition-0..15` | `0x2000000000900000` + i·`0x4000` | `0x4000` | per-partition FBPA instances | +| `fbpa-mc-0..2` | `0x2000000000980000` + i·`0x4000` | `0x4000` | FBPA MC instances | + +Register names (and, for a few control/status registers, header field names +with bit positions) are declared per window so traces are readable; offsets +inside a window that the profile does not name are still recorded and land +under `unclassified`. `gmmu-pri-mmu` spans the `NV_PFB_PRI_MMU_*` cluster +`0x100C80–0x100EFC`; the few non-MMU PFB registers interleaved in that span +(e.g. the PRI_FB clock/power-gating registers) are recorded as unclassified, +never renamed. + +## 3. Mechanism: record, then decline + +Each `ObservedWindow` is a normal device-model window and is consulted by the +registry like any other. Its `read`/`write` always record: + +```text +addr, offset, size, rw, value-if-known, pc, vt, window, register, served +``` + +and then return `None`/`False` unless the window is declared `storage` **and** +the accessed offset is a declared plain read/write register **and** (for +reads) that register has been written before. Declining means the registry +falls through to the next matching window and the machine's existing path +applies unchanged: + +* lenient mode: the access is logged/counted as before and reads 0; +* fault mode: the same `Fault(cause, tval)` as without the window; +* a modelled window underneath (e.g. the PMC block) is consulted exactly as + before and serves the access if it models it, and the observer records that + it happened. (The `gmmu-wpr-lock` window overlaps the fwsec WPR2 window, so + it exercises this fall-through; it asserts nothing about whether the + underlying WPR2 path serves — that path is unchanged by the observer and + currently serves nothing through the registry, a pre-existing condition.) + +**No-fake-read guarantee.** An observe-only read records `"value": null` and +returns `None`; a storage read before any write is declined the same way; no +reset value is synthesised. The only read value a storage window can return +is one this same run wrote to that register. All profile windows for +GMMU/FBIF are `observe-only`; the `storage` mode exists for surfaces whose +header proves plain read/write behaviour and is exercised by tests. + +`pc` is the faulting instruction address (the registry forwards it only to +devices that opt in). `vt` is the machine instruction counter at the access; +it advances at `Machine.run` boundaries, so accesses inside one bounded run +share the run-start value — a documented granularity, not a timing claim +(fidelity L2 is not modelled). + +**Size limit.** Each window's access log is capped (`max_access_log`, default +65536 entries); accesses beyond the cap are counted, not written. The trace +document reports `dropped_accesses` per window and in the summary and +separates `accesses` (total observed) from `retained_accesses` (present in +the document), so truncation is never silent. + +## 4. Trace document: `greeneye-gmmu-fbif-trace/1` + +`--trace-out <path>` writes a trace file: a path that is an existing +directory (or ends in `/`, which makes that directory) gets the canonical +filename `gmmu-fbif-trace.json` inside; anything else is used as the file +name. Accesses are grouped per window and per declared register; undeclared +offsets go to `unclassified`. Shape: + +```json +{ + "schema": "greeneye-gmmu-fbif-trace/1", + "image_sha256": "…", + "profile": "tu104-570.144.json", + "profile_name": "tu104-570.144", + "symbols": "symbols.json", + "summary": {"windows": 23, "windows_touched": 0, "accesses": 0, + "retained_accesses": 0, "dropped_accesses": 0, + "reads": 0, "writes": 0, "served": 0, "registers_touched": 0}, + "windows": [ + {"label": "gmmu-pri-mmu", "base": "0x2000000000100c80", "size": "0x280", + "mode": "observe-only", "evidence": "…", + "counts": {"r": 0, "w": 0, "served": 0, "declined": 0}, + "retained_accesses": 0, "dropped_accesses": 0, + "registers": [ + {"offset": "0x0", "name": "NV_PFB_PRI_MMU_CTRL", "access": "rw", + "counts": {"r": 0, "w": 1, "served": 0}, + "accesses": [ + {"addr": "0x2000000000100c80", "offset": "0x0", "size": 4, + "rw": "w", "value": "0x1", "pc": "0x4001234", + "pc_symbol": "rm_init+0x20", "vt": 0, + "window": "gmmu-pri-mmu", "register": "NV_PFB_PRI_MMU_CTRL", + "served": false, "decoded": {"VM_PG_SIZE": 1}} + ]} + ], + "unclassified": {"counts": {"r": 0, "w": 0, "served": 0}, + "accesses": []}} + ] +} +``` + +`pc_symbol` is `null` unless `--symbols <greeneye-symbols/1 JSON>` is given; +`decoded` is present only when a value is known and the register declares +fields (bit positions from the header). `value`/`addr`/`offset`/`pc` are hex +strings; `vt` is an integer. The document is deterministic for a fixed image, +profile, flags and stimulus. + +The **count summary is always in the boot report** (and session metadata under +`gmmu_fbif`) even when `--trace-out` is off; the trace blob is added to the +recorded session only when the flag is on. + +## 5. Commands + +```bash +cd open-iov/debug/risc-v-gsp-rm-vm + +# B2 run with the observer summary, trace written to a directory: +python3 -m sim.gsp_boot --instructions 20000 --record dumps/gsp-boot-b2-observe \ + --trace-out dumps/gsp-boot-b2-observe + +# Resolve recorded PCs through a symbol database: +python3 -m sim.gsp_boot --trace-out /tmp/trace.json --symbols symbols.json + +# Ad-hoc window whose base is not established yet (repeatable, no guessing): +python3 -m sim.gsp_boot --observe-window 0x20000000009A0000:0x4000:fbpa \ + --observe-window 0x2000000000100C80:0x280:gmmu +``` + +`--observe-window BASE:SIZE[:LABEL[:MODE]]` is the escape hatch: the trace +accepts a runtime window list, so an unknown surface can be observed before +any profile entry exists. A runtime window is `observe-only` unless +`MODE=storage` is given (storage without declared registers still records and +declines). + +## 6. What is NOT modelled + +* **No GMMU page walk, no PTE/PDE decode, no TLB, no fault handling, no ATS.** + Window accesses are recorded; their semantics are not interpreted. +* **No FBIF transaction semantics, compression, ECC or partition hashing.** + FBPA register offsets/names are labels, not behaviour. +* **No interrupt or timing (L2) claims.** `vt` is the modeled instruction + counter, not cycles. +* **No device-environment (L3) claims.** The windows exist because the + simulator serves them; silicon behaviour is not asserted. +* **Storage is not semantics.** A storage window only echoes values written in + the same run; it is not evidence that the real register stores them. +* **No product or hardware action.** Nothing in this workstream touches + `vgsp`, a GPU, a module, mdev, or a guest. + +## 7. Evidence, limits and tests + +* Evidence kind for every window/offset is the hardware register/field header + (block ranges and register offsets); observed firmware use in B0–B2 was + **zero accesses** (measured at the B2 stop: 14 682 instructions, 0 unknown + MMIO, 1 device access — the PMC chip-ID read). The B3 wave's WPR2 reads are + the first observed accesses (2 reads inside `gmmu-wpr-lock`, observe-only, + 0 served). The mechanism is still tested end-to-end with runtime windows. +* Boot numbers are unchanged by the observer windows (instructions, stop + PC/reason, unknown MMIO, unhandled-in-window, served accesses); the only + session difference is the added device-state entries for the observers. +* Tests: `tests/test_gmmu_fbif_trace.py` — no-semantic-change (lenient and + fault paths match a registry without the window), storage read-back, + field decode, profile expansion, trace schema, access-log-cap reporting, + WPR2-overlap pass-through, B2 invariance, symbol resolution, runtime + windows. +* Public artifacts carry only component register names/offsets and behaviour; + the window/register tables come from the tracked analysis and recorded + sessions. |
