1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
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.
|