summaryrefslogtreecommitdiffstats
path: root/docs/05-operations/04-risc-v-gsp-rm-debugger-user-guide.md
diff options
context:
space:
mode:
authorArthur Hanson Rasmusson <arthur@vgpu.io>2026-10-02 11:44:31 -0400
committerArthur Hanson Rasmusson <arthur@vgpu.io>2026-10-02 11:44:31 -0400
commit1c99bfbeffff04529f6f669601fdf835a73778da (patch)
tree5867bab46e5848541df36c703f6fd8d6d0256e54 /docs/05-operations/04-risc-v-gsp-rm-debugger-user-guide.md
parent2fd653044127a665e4677a2cdfb58120d7b3e16b (diff)
downloadopen-iov-1c99bfbeffff04529f6f669601fdf835a73778da.tar.gz
open-iov-1c99bfbeffff04529f6f669601fdf835a73778da.zip
rename (cosmetic): green-eye -> risc-v-gsp-rm-debugger in user-facing names, docs, CLI, launcher and CI workflow; internal greeneye package/module identifiers unchanged (includes in-flight greeneye module edits present in the tree)
Diffstat (limited to 'docs/05-operations/04-risc-v-gsp-rm-debugger-user-guide.md')
-rw-r--r--docs/05-operations/04-risc-v-gsp-rm-debugger-user-guide.md439
1 files changed, 439 insertions, 0 deletions
diff --git a/docs/05-operations/04-risc-v-gsp-rm-debugger-user-guide.md b/docs/05-operations/04-risc-v-gsp-rm-debugger-user-guide.md
new file mode 100644
index 0000000..f12230a
--- /dev/null
+++ b/docs/05-operations/04-risc-v-gsp-rm-debugger-user-guide.md
@@ -0,0 +1,439 @@
+# risc-v-gsp-rm-debugger User Guide (experimental)
+
+> **# TOOL IN DEVELOPMENT - NOT READY YET!**
+> risc-v-gsp-rm-debugger is the development environment for running GSP/uproc firmware
+> off-hardware, observing it, injecting into it and comparing runs as evidence.
+> It is never shipped, never a driver dependency and never present in a guest;
+> interfaces and file formats may change without notice. For incident response
+> procedures see the [Open-IOV Defensive Operations Runbook](../RUNBOOK.md).
+
+This guide is the single front door for a new user: what risc-v-gsp-rm-debugger is, how to
+get a first recorded run in ten minutes, which tool to use for which task, how
+to treat sessions as evidence, and what to do when something is wrong. The
+authoritative details live in the tool's own documentation set
+([documentation map](#10-documentation-map)).
+
+## 1. What risc-v-gsp-rm-debugger is
+
+risc-v-gsp-rm-debugger runs GSP/uproc firmware in a controllable machine, instruments it
+with Frida-like primitives, records a durable session, changes the machine's
+inputs (including injected code), and compares runs so that emulation changes
+in `open-iov-vfio` land with evidence instead of anecdotes.
+
+| It is | It is not |
+|---|---|
+| A firmware runtime microscope (execution + memory: L0/L1) | A timing, interrupt or device model (L2/L3 absent) |
+| A scriptable `Session` API with two backends (QEMU-RSP and native) | A GDB wrapper; there is no GDB dependency |
+| A recorded-evidence system with a versioned session format | A product component, a guest agent or a shipped dependency |
+| A static/dynamic join for Ghidra | A decompiler or a CUDA-corpus replacement |
+| An automation layer (harnesses, MCP, CI) | A fuzzing service against hardware; simulator/re-hosted code only |
+
+Ghidra answers *what is the code*; risc-v-gsp-rm-debugger answers *what did it do*. Guest
+diagnostics answer *what did the driver request*; a supervised physical cycle
+answers *what does silicon do*. risc-v-gsp-rm-debugger makes the middle question repeatable
+and safe.
+
+## 2. Ten-minute quickstart
+
+Requirements: Linux, Python 3.10+ (stdlib only), `qemu-system-riscv64`
+(Ubuntu `qemu-system-misc`), `clang` and `lld`. No GPU, no driver and no
+kernel module are touched.
+
+```bash
+cd open-iov/debug/risc-v-gsp-rm-vm
+
+./risc-v-gsp-rm-debugger.sh info # environment check: QEMU, toolchain, paths
+make demo && make sdk # build the bundled RV64 uproc demo and injection SDK
+
+./risc-v-gsp-rm-debugger.sh demo # canned run: boot, hooks, watchpoints, session
+./risc-v-gsp-rm-debugger.sh analyze dumps/<printed-session-dir>
+
+./risc-v-gsp-rm-debugger.sh probe # real GSP image: report the first divergence
+./risc-v-gsp-rm-debugger.sh inject # load and invoke a position-independent service
+```
+
+What "good" looks like:
+
+1. `info` reports QEMU and the demo paths;
+2. `demo` prints hook/branch lines and a session directory under `dumps/`;
+3. `analyze` renders hook/watch/breakpoint events and a coherent summary;
+4. `probe` reports a bounded first divergence (for the TU104 570.144 image, a
+ load-access fault at firmware vaddr `0x4009014` reading
+ `0x2000000000000A00`) — that is expected data, not a boot;
+5. `inject` returns matching values on the direct and firmware-dispatched
+ paths.
+
+Next steps: [choose a tool](#5-choosing-the-right-tool) for your task and read
+[Common recipes](#7-common-recipes).
+
+## 3. Mental model
+
+### 3.1 Two backends, one session API
+
+```text
+CLI / REPL / Python ─┐
+MCP (stdio) ────────┼─► GreenEyeAPI ─► Session ─┬─► QEMU-RSP backend (qemu-system-riscv64)
+Ghidra bridge ──────┤ hooks, watchpoints, └─► native backend (sim/machine.py)
+harness/ + rmharness┘ memory, symbols, recorder ──► session directory
+```
+
+* **QEMU-RSP** is the default: full RV64 execution, gdbstub transport without
+ GDB, TCG trace plugin optional.
+* **native** (`--backend native`) is the in-process interpreter: deterministic
+ virtual time (instruction counts), fast startup, an exec/access trace, and
+ lenient MMIO for first-touch exploration.
+* Both satisfy the same `Session` primitives (registers/memory, breakpoints,
+ watchpoints, step/continue, snapshots), so scripts, probes, plugins,
+ recordings and comparisons survive a backend change.
+
+### 3.2 The primitives
+
+| Primitive | Use it for |
+|---|---|
+| `breakpoint` / `hook` | did this function run? with what arguments and return value? |
+| `watch` (`w`/`r`/`a`) | when did this field change, from which store PC? |
+| `run` / `run_until` | bounded observation; stop at a chosen address |
+| `call` | Frida-like remote call to unit-test a function in isolation |
+| `step` / `note` | single-step with dispatch; annotate the event stream |
+| `Memory.read/write/hexdump/search/snapshot/diff` | inspect and diff memory regions |
+| `SymbolDB` | resolve file/program/runtime addresses across sources |
+| `Recorder` | write the durable session (events, snapshots, blobs) |
+| injection SDK | load, register and invoke your own PIC RV64 service |
+
+Instructions between stops are invisible unless a trace is on: the TCG plugin
+(`-plugin qemu/greeneye-trace.so`) on QEMU, or `--trace` on the native backend.
+
+### 3.3 Fidelity levels (what a result can mean)
+
+| Level | Property | risc-v-gsp-rm-debugger today |
+|---|---|---|
+| **L0** | instruction semantics | high (QEMU TCG, same ISA family) |
+| **L1** | memory behaviour | high for RAM-resident code, conditional on mapping |
+| **L2** | time/concurrency | **not modelled** (do not claim) |
+| **L3** | device environment (falcon, WPR2, CSB, PMU, timers, DMA, IRQ) | **absent** (device model is roadmap) |
+
+A simulator observation is evidence about the firmware, not about silicon;
+anything that would change the product is reproduced on a physical/vfio-mdev
+reference first. Never quote a risc-v-gsp-rm-debugger session for timing, interrupt or
+security claims.
+
+### 3.4 A session is the unit of work
+
+Every run records a `greeneye-session/1` directory:
+
+```text
+dumps/<stamp>-<name>/
+ session.json format, name, counts, snapshot inventory, meta
+ events.jsonl append-only event stream (hooks, watches, memory, notes)
+ snapshots/*.bin.z zlib-compressed region captures with sha256
+ blobs/* QEMU logs, trace.jsonl, host-oracle stdout
+ summary.md rendered analysis
+```
+
+Partial sessions stay readable; the format evolves additively. A copied
+`events.jsonl` without its `session.json`, snapshots and metadata is not
+evidence.
+
+## 4. Tool inventory
+
+Run everything from `open-iov/debug/risc-v-gsp-rm-vm/` unless stated.
+
+### 4.1 CLI (`./risc-v-gsp-rm-debugger.sh`)
+
+| Command | One-line purpose |
+|---|---|
+| `info` | environment/tooling check (QEMU, paths, capabilities) |
+| `demo` | canned boot + hooks + watchpoints + recording on the bundled uproc |
+| `run <script.py>` | run a Python instrumentation session against the demo/ELF |
+| `attach` / `launch` | interactive REPL; keep a target alive and print its gdbstub port |
+| `record` | boot and record with watches/snapshots (and `--trace` on native) |
+| `probe <image>` | bounded run of a raw image; first-divergence report |
+| `analyze <session>` | session to symbol-annotated Markdown report |
+| `compare <a> <b>` | symbolic A/B delta of two recorded sessions |
+| `symbols export\|resolve` | build/inspect a runtime-address symbol DB |
+| `inject` | load, register and invoke an SDK service (direct + mailbox) |
+| `ghidra` | serve the live session to GhidraScripts over localhost |
+| `plugins` | list discoverable plugins |
+
+### 4.2 Harnesses (`harness/`)
+
+| Tool | One-line purpose |
+|---|---|
+| `portability_matrix.py` | probe + fixed scenario + compare across targets, with an M1–M6 skeleton |
+| `mutation_harness.py` | seeded one-input mutations with outcome classes and per-attempt sessions |
+| `control_discovery.py` | sweep a call surface to find known/unknown/injected handler IDs |
+| `reach.py` | is one symbol reachable, what triggers it, with what arguments and effects |
+| `version_diff.py` | old vs new image: shape, symbols, corpus hints, probe, behavior |
+| `ci_release.py` | version_diff → matrix → mutation smoke, hashed into one bundle |
+| `port_driver_versions.py`, `port_new_device.py`, `package_sim.py` | porting/packaging scaffolds (dry-run default; pilot status and evaluation in [docs/28](../../debug/risc-v-gsp-rm-vm/docs/28-PORTING-AUTOMATION.md), [docs/29](../../debug/risc-v-gsp-rm-vm/docs/29-PACKAGING-AND-TRIALING.md)) |
+| `value_demos/run_all.py` | ten fixed scenarios s01–s10 with measured time-to-value |
+| `common.py` | shared helpers (flat relocation, sessions, bounded log reads) |
+
+### 4.3 Native simulator, plugins, host oracle, bridges
+
+| Tool | One-line purpose |
+|---|---|
+| `sim/` (`--backend native`, `--trace`) | deterministic RV64IMAC interpreter with exec/access trace and lenient MMIO |
+| `python3 -m greeneye.device_map harvest\|show\|merge\|demo` | first-touch MMIO map: authoring, inspection, merge |
+| `qemu/greeneye_trace.c` (`make -C qemu`) | full TCG exec/access JSONL trace with `start=`/`end=` filters |
+| `plugins/example_plugin.py` | plugin authoring reference |
+| `plugins/mcp_server.py` | MCP server for agents (stdio or loopback; read-only by default) |
+| `plugins/rmharness_plugin.py` | REPL commands for the host RM oracle |
+| `rmharness/harness.sh` + `rmtool`/`rmtop`/`rmq` | read-only host oracle captures appended into a session |
+| `ghidra/ExportForGreenEye.java`, `MarkGreenEyeHits.java`, `GreenEyeControl.java` | symbol export, hit annotation and decompiler-driven execution |
+| `sdk/` + `greeneye inject` | position-independent service ABI v1 |
+
+## 5. Choosing the right tool
+
+| Task | Tool | Notes |
+|---|---|---|
+| "Does this run?" / first divergence of a raw image | `./risc-v-gsp-rm-debugger.sh probe` | no device model: expected early fault is data |
+| "What does this firmware do on this stimulus?" | `record` / `run` + `analyze` | fixed stimulus, bounded budgets, hooks/watchpoints |
+| "Which command IDs exist / what is undiscovered?" | `harness/control_discovery.py` | fresh session per probe; deterministic seed |
+| "Is this function reachable, and how?" | `harness/reach.py` | `auto|stimulus|trigger|run|call`; emits a replayable probe spec |
+| "What changed between two firmware versions?" | `harness/version_diff.py`, `./risc-v-gsp-rm-debugger.sh compare` | static inventory + dynamic profile |
+| "Does the new firmware move behaviour or code?" | `harness/version_diff.py` + docs/14 decision table | code vs behaviour classification |
+| "Prove an error path / fail-closed rule" | `harness/mutation_harness.py` | simulator only; seeded and replayable |
+| "Prototype an RM service before product code" | `sdk/` + `./risc-v-gsp-rm-debugger.sh inject` | PIC blob; direct and mailbox paths |
+| "Join Ghidra static addresses to runtime hits" | `./risc-v-gsp-rm-debugger.sh ghidra` + Java bridges | localhost only; no auth |
+| "What does a control reply look like on real RM?" | `rmharness/harness.sh … rmtool` | read-only host oracle; safe beside a CUDA job |
+| "Explore MMIO the firmware touches first" | `probe` → `python3 -m greeneye.device_map` | versioned JSON; feeds the device model |
+| "Triage a release end to end" | `harness/ci_release.py` | always `--dry-run` first |
+| "Let an agent monitor a run" | `plugins/mcp_server.py` | read/observe by default; writes gated |
+
+Decision rule: static reading is a hypothesis; a recorded session is evidence;
+at least an A/B pair is a conclusion.
+
+## 6. Sessions as evidence
+
+1. **Record with a fixed stimulus.** The same script, seed, budgets and image
+ hash make runs comparable; a self-comparison must be empty.
+2. **Annotate as you go.** `s.note(...)` inside the session explains what was
+ asked and what was mutated; a chat log is not evidence.
+3. **Attach the provenance.** Firmware SHA-256, version string, pairing notes,
+ symbol DB source/hash/bias, and the exact command or script.
+4. **Keep the directory together.** `session.json` + `events.jsonl` +
+ `snapshots/` + blobs are one artifact; publish a SHA-256 list when moving
+ it.
+5. **State the fidelity.** L0/L1 exercised; L2/L3 not claimed; reference
+ capture named (hardware, vfio-mdev, host oracle or none).
+6. **Report deltas honestly.** `compare` marks non-semantic fields (time, host
+ paths, backend identity) as such; every remaining delta is explained or
+ listed as open. An empty unexplained-delta list is a claim that must be
+ earned.
+7. **Bundle for triage.** A release bundle is
+ `bundle-manifest.json` + `release-report.json` + version-diff + portability
+ matrix + mutation smoke; see
+ [docs/21](../../debug/risc-v-gsp-rm-vm/docs/21-CI-RELEASE-PIPELINE.md) §4.3.
+
+The M1–M6 metric contract (inventory, reply, ordering, state, error-path and
+memory-side-effect agreement) is defined in
+[docs/06-ACCURACY](../../debug/risc-v-gsp-rm-vm/docs/06-ACCURACY.md) §5 and is
+authoritative for every claim.
+
+## 7. Common recipes
+
+### 7.1 First record and analyze
+
+```bash
+cd debug/risc-v-gsp-rm-vm
+make demo
+./risc-v-gsp-rm-debugger.sh demo # prints the session directory
+./risc-v-gsp-rm-debugger.sh analyze dumps/<session> # symbol-annotated report
+```
+
+### 7.2 Probe a new firmware image
+
+```bash
+./risc-v-gsp-rm-debugger.sh symbols export --index <export.tsv> --bias 0 -o symbols-<ver>.json
+./risc-v-gsp-rm-debugger.sh probe <gsp-<VER>.fwimage.bin> --symbols symbols-<ver>.json --record
+python3 harness/version_diff.py --old <old> --new <new> --out dumps/vdiff-<ver> \
+ --old-symbols symbols-<old>.json --new-symbols symbols-<new>.json
+```
+
+### 7.3 Discover controls and prove reachability
+
+```bash
+python3 harness/control_discovery.py --out dumps/discovery --max-id 32 \
+ --patterns zero --seed 5
+python3 harness/reach.py --target rpc_ping --method call --args 0x41 \
+ --out dumps/reach-ping
+```
+
+### 7.4 Mutate an input surface (simulator only)
+
+```bash
+python3 harness/mutation_harness.py --out dumps/mutation-7 \
+ --iterations 64 --seed 7 --timeout 0.25 --settle 0.2
+```
+
+### 7.5 Portability pipeline across targets
+
+```bash
+python3 harness/portability_matrix.py \
+ --target <reference-fwimage> --target <candidate-fwimage> \
+ --out dumps/matrix-candidate --probe-instructions 200 --scenario-duration 0.2
+```
+
+### 7.6 Inject and debug a service
+
+```bash
+make -C sdk
+make -C sdk relocs
+./risc-v-gsp-rm-debugger.sh inject --service sdk/build/injected_demo.elf --cmd 1 --arg0 0x41 --arg1 0x42
+```
+
+The direct call is the unit test; the mailbox call is the integration test.
+Both are recorded.
+
+### 7.7 Drive execution from Ghidra
+
+```bash
+# terminal 1
+./risc-v-gsp-rm-debugger.sh ghidra --kernel <elf> --bridge-port 7000
+# terminal 2 (Ghidra headless)
+$GHIDRA/support/analyzeHeadless <proj> <name> -process <program> -noanalysis \
+ -scriptPath open-iov/debug/risc-v-gsp-rm-vm/ghidra \
+ -postScript GreenEyeControl.java 7000 0x<address>
+```
+
+### 7.8 Host oracle capture (read-only)
+
+```bash
+./rmharness/harness.sh --session dumps/real-<anchor> --name before \
+ -- rmtool engine list --format=json
+./rmharness/harness.sh --session dumps/real-<anchor> -- rmtop --once
+```
+
+### 7.9 Release rehearsal
+
+```bash
+python3 harness/ci_release.py --old <old> --new <new> --out dumps/release-<ver> \
+ --old-label <OLD> --new-label <NEW> --dry-run
+```
+
+`--dry-run` prints the plan and creates nothing; the RM 610 gate refuses 610
+labels (exit 3) until a human approves in writing.
+
+### 7.10 Let an agent monitor
+
+```bash
+python3 plugins/mcp_server.py --stdio --backend native --record
+# read/observe by default; --allow-write and --allow-inject are explicit opt-ins
+```
+
+### 7.11 First-touch device map
+
+```bash
+./risc-v-gsp-rm-debugger.sh probe <fwimage> --record
+python3 -m greeneye.device_map harvest dumps/<probe-session> --out dumps/<ver>-device-map.json
+python3 -m greeneye.device_map show dumps/<ver>-device-map.json
+```
+
+## 8. Troubleshooting
+
+| Symptom | Likely cause | Fix |
+|---|---|---|
+| `qemu-system-riscv64 not found` | QEMU absent or not on `PATH` | install `qemu-system-misc` or point `GREENEYE_QEMU` at the binary |
+| QEMU starts but the script cannot attach | wrong port / target exited | use the port `launch`/`demo` printed; re-run `launch` and `attach --port <port>` |
+| `Address already in use` on a bridge/trace port | stale bridge or another session | choose another `--bridge-port`; check `pgrep -fa greeneye` and `pgrep -fa qemu-system-riscv64` |
+| QEMU survives Ctrl-C of a script | `launch` keeps the target alive by design | close the session or stop the reported PID; do not kill an unrelated QEMU |
+| Session analyzer shows no hits/events | recording off, or the stimulus never ran | use the CLI (records by default); check hooks/watchpoints with a known symbol (`rpc_sum`) |
+| `NameError: __file__` in `run` scripts | script invoked outside `risc-v-gsp-rm-debugger.sh run` | run through `./risc-v-gsp-rm-debugger.sh run`, keep scripts inside the tool tree |
+| Empty TCG trace blob | plugin window missed or target never resumed | `make -C qemu`; widen `start=`/`end=`, set `exec=on`, resume the target |
+| MCP writes refused / no tools | server read-only by default; stdout polluted | pass `--allow-write`/`--allow-inject` deliberately; keep stdout protocol-only |
+| `greeneye error:` on a valid path | wrong relative path or `--db` file | `./risc-v-gsp-rm-debugger.sh info` shows resolved paths; bad symbol DBs fail with a clear error |
+| Harness findings not reproducible | seed/budget changed | pin `--seed` and budgets; compare `findings.jsonl` byte-for-byte |
+| Everything "unreachable" | wrong surface/timeouts | run `--surface demo` on the built demo first; raise `--settle`/`--timeout` |
+| `Unknown symbol` in the optional OpenRM build | module-tag drift | re-pin build glue; see the [RUNBOOK](../RUNBOOK.md) S2 |
+
+Marker status: every tool document carries the
+**# TOOL IN DEVELOPMENT - NOT READY YET!** banner. The marker is removed only
+when the acceptance list in
+[docs/00-OVERVIEW](../../debug/risc-v-gsp-rm-vm/docs/00-OVERVIEW.md) passes on a
+clean checkout, the usage recipes verify end-to-end, a second person can run
+the quickstart unaided, and the session format and CLI are declared stable.
+
+## 9. Safety
+
+* **Simulator only.** The tools launch their own QEMU or native machine
+ against the bundled demo or an explicitly allowed re-hosted ELF. They never
+ attach to hardware, a guest, a kernel module, an mdev or an existing
+ gdbstub.
+* **No guest, no hardware, no product.** Nothing runs in a guest; injected
+ services are prototypes, not shipped code; product changes go through
+ `open-iov-vfio` with physical confirmation.
+* **Read by default; writes gated.** MCP `write_mem`/`call_function` need
+ `--allow-write`, injection needs `--allow-inject`, and every write is
+ recorded in the session.
+* **Bounded everywhere.** Runs have durations/stop caps; reads and snapshots
+ have size caps; harness subprocesses have timeouts; a wedged target is left
+ stopped and restarted clean rather than poked.
+* **Local only.** Ghidra and MCP transports are localhost/stdio; the bridge is
+ unauthenticated by design, so never expose it on a network interface.
+* **No confidentiality claims.** The simulator is a study environment, never a
+ security or confidentiality boundary; never use injection to defeat a
+ hardware security boundary.
+* **Fuzzing is gated.** Mutation runs only against the simulator or re-hosted
+ code, behind explicit harnesses, with recorded evidence.
+* **RM 610 is a hard human gate.** No acquisition, analysis, emulation edit,
+ physical work or support claim before written approval; the gate is enforced
+ by the CLIs.
+
+## 10. Documentation map
+
+Tool documentation (`debug/risc-v-gsp-rm-vm/docs/`): [00 overview](../../debug/risc-v-gsp-rm-vm/docs/00-OVERVIEW.md),
+[01 design](../../debug/risc-v-gsp-rm-vm/docs/01-DESIGN.md),
+[02 usage](../../debug/risc-v-gsp-rm-vm/docs/02-USAGE.md),
+[03 scripting](../../debug/risc-v-gsp-rm-vm/docs/03-SCRIPTING.md),
+[04 plugins](../../debug/risc-v-gsp-rm-vm/docs/04-PLUGINS.md),
+[05 Ghidra bridge](../../debug/risc-v-gsp-rm-vm/docs/05-GHIDRA-BRIDGE.md),
+[06 accuracy](../../debug/risc-v-gsp-rm-vm/docs/06-ACCURACY.md),
+[07 portability playbooks](../../debug/risc-v-gsp-rm-vm/docs/07-PORTABILITY-PLAYBOOKS.md),
+[08 roadmap](../../debug/risc-v-gsp-rm-vm/docs/08-ROADMAP.md),
+[09 firmware notes](../../debug/risc-v-gsp-rm-vm/docs/09-GSP-FIRMWARE-NOTES.md),
+[10 related work](../../debug/risc-v-gsp-rm-vm/docs/10-RELATED-WORK.md),
+[11 RM service guide](../../debug/risc-v-gsp-rm-vm/docs/11-GSP-RM-SERVICE-DEVELOPER-GUIDE.md),
+[12 injection SDK](../../debug/risc-v-gsp-rm-vm/docs/12-INJECTION-SDK.md),
+[13 Ghidra control](../../debug/risc-v-gsp-rm-vm/docs/13-GHIDRA-CONTROL.md),
+[14 adversarial interop](../../debug/risc-v-gsp-rm-vm/docs/14-ADVERSARIAL-INTEROP-GUIDE.md),
+[15 agentic GSP IDE](../../debug/risc-v-gsp-rm-vm/docs/15-AGENTIC-GSP-IDE.md),
+[16 custom simulator](../../debug/risc-v-gsp-rm-vm/docs/16-CUSTOM-SIMULATOR.md),
+[17 RM harness](../../debug/risc-v-gsp-rm-vm/docs/17-RM-HARNESS.md),
+[18 harness automation](../../debug/risc-v-gsp-rm-vm/docs/18-HARNESS-AUTOMATION.md),
+[19 control discovery](../../debug/risc-v-gsp-rm-vm/docs/19-CONTROL-DISCOVERY.md),
+[20 MCP server](../../debug/risc-v-gsp-rm-vm/docs/20-MCP-SERVER.md),
+[21 CI/release pipeline](../../debug/risc-v-gsp-rm-vm/docs/21-CI-RELEASE-PIPELINE.md),
+[22 porting CUDA and devices](../../debug/risc-v-gsp-rm-vm/docs/22-PORTING-CUDA-AND-DEVICES.md),
+[23 RM 610 readiness](../../debug/risc-v-gsp-rm-vm/docs/23-RM610-READINESS.md),
+[24 device map](../../debug/risc-v-gsp-rm-vm/docs/24-DEVICE-MAP.md),
+[25 value validation](../../debug/risc-v-gsp-rm-vm/docs/25-VALUE-VALIDATION.md),
+[26 architecture](../../debug/risc-v-gsp-rm-vm/docs/26-ARCHITECTURE.md),
+[27 tool audit](../../debug/risc-v-gsp-rm-vm/docs/27-TOOL-AUDIT.md),
+[28 porting automation](../../debug/risc-v-gsp-rm-vm/docs/28-PORTING-AUTOMATION.md),
+[29 packaging and trialing](../../debug/risc-v-gsp-rm-vm/docs/29-PACKAGING-AND-TRIALING.md), and the
+[long-term roadmap](../../debug/risc-v-gsp-rm-vm/RISC-V-GSP-RM-DEBUGGER-ROADMAP.md).
+
+Project documentation:
+
+* [Open-IOV Defensive Operations Runbook](../RUNBOOK.md) — incident scenarios
+ S1–S10, evidence bundles, escalation tree;
+* [GSP in a RISC-V VM](03-risc-v-gsp-rm-vm.md) — project-level purpose, status
+ and limits;
+* [Debugging and maintenance workflows](02-debugging-and-maintenance-workflows.md)
+ — captures, failure taxonomy and the upgrade runbook;
+* [Hardware and software matrix](../06-portability/hardware-software-matrix.md)
+ — support ladder and the portability pipeline;
+* [Adversarial interoperability](../04-implementation/02-practical-challenges-and-adversarial-interop.md)
+ — the no-patch rule;
+* [Engineering operations](../eng-ops.md) — tool admission, workflows and
+ retirement (the cross-cutting engineering-operations document);
+* CUDA playbook:
+ [`userspace/cuda/docs/07-version-upgrade-playbook.md`](../../userspace/cuda/docs/07-version-upgrade-playbook.md)
+ and [`userspace/cuda/READ-ME-FIRST.md`](../../userspace/cuda/READ-ME-FIRST.md);
+* [Documentation front door](../README.md) — the full reading order.
+
+<!-- change (2026-10-02): correct the TCG plugin filename to the actual
+qemu/greeneye_trace.c, list the docs 28/29 scaffolds in the tool inventory and
+documentation map; scope: §4.2, §4.3, §10 only; benefit: copied commands and
+doc-map navigation match the tool tree. -->