summaryrefslogtreecommitdiffstats
path: root/wiki/Riscv-GSP-RM-Debugger.md
blob: 8155364361ab0aa6b82bc8cc837449366f57206e (plain)
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
# risc-v-gsp-rm-debugger

> **Scope.** risc-v-gsp-rm-debugger runs GSP/uproc firmware off-hardware in a controllable RISC-V machine, instruments it with Frida-like primitives, and records durable sessions so firmware behaviour can be captured and compared with evidence instead of anecdotes. Canonical sources: [`../docs/05-operations/03-risc-v-gsp-rm-vm.md`](../docs/05-operations/03-risc-v-gsp-rm-vm.md) and [`../docs/05-operations/04-risc-v-gsp-rm-debugger-user-guide.md`](../docs/05-operations/04-risc-v-gsp-rm-debugger-user-guide.md); if this page and the docs tree disagree, the docs tree wins.
>
> **Development-only.** Host-side tooling that is never shipped, never a driver dependency and never present in a guest; interfaces and file formats may change without notice.
>
> Status: 2026-10-30, tree `master @ b4930168`. Tags: `[live]` recorded QEMU sessions; `[wip]` partial device model; `[design]` full device model and custom simulator are roadmap.

## 1. What it is

risc-v-gsp-rm-debugger makes the firmware's **runtime behaviour** inspectable. It boots GSP/uproc firmware in `qemu-system-riscv64` (or a deterministic native interpreter) and offers Frida-like primitives on top:

* breakpoints and enter/leave hooks (RV64 ABI aware); watchpoints on firmware variables;
* memory read/write/hexdump/search, structure decoding, snapshot diffing;
* recorded sessions: a replayable event stream plus memory dumps;
* remote calls and run-to-cursor (execute until a chosen address);
* injection: build a position-independent RV64 service, load it into the running firmware and dispatch to it;
* declarative probe specs, a plugin API, and a Ghidra bridge for symbol export, hit annotation and decompiler-driven execution.

Its purpose is **capturing how the firmware server behaves, repeatably and safely**, so emulation changes can be measured against recorded evidence and can survive GSP version, device and architecture churn. The tooling lives under `open-iov/debug/risc-v-gsp-rm-vm/`, with its own documentation set (design, usage, scripting, plugins, bridges, accuracy, portability, roadmap).

## 2. What it is not

* **Not a complete GSP boot environment.** QEMU `virt` has no falcon windows,
  WPR2, CSB/TRANSCOM, PMU, timers or FB DMA. `probe` reports exactly where the
  real image first diverges (for the TU104 570.144 image: a load-access fault
  at firmware vaddr `0x4009014` reading `0x2000000000000A00`) — expected data,
  not a boot. A **partial device model** ("S1") exists and boots the real
  image natively through its relocation copy on the simulator's boot ladder
  ([`../debug/risc-v-gsp-rm-vm/docs/36-GSP-DEVICE-MODEL.md`](../debug/risc-v-gsp-rm-vm/docs/36-GSP-DEVICE-MODEL.md));
  the message-loop rungs and the remaining device environment are roadmap,
  not claims.
* **Not a timing model.** Do not infer latency, jitter or concurrency behaviour from it; its in-scope conclusions are execution flow and memory side effects.
* **Not a replacement for Ghidra or the guest diagnostics.** Ghidra answers *what is the code*; risc-v-gsp-rm-debugger answers *what did it do*; the guest driver remains the oracle for guest-side behaviour.
* **Not a hardware or security tool.** It never attaches to a real GPU, a guest, a kernel module or an mdev, and it is never a security or confidentiality boundary.

## 3. Where it fits

| Layer | Tool | Question answered |
|---|---|---|
| Static | Ghidra and the decompilation corpus | what is the code? |
| Guest driver | guest diagnostics, ptrace tracing | what did the driver request? |
| **Firmware runtime** | **risc-v-gsp-rm-debugger** | **what does the firmware server do, repeatably and safely?** |
| Physical backend | supervised hardware sessions, module logs | what did real silicon / the real GSP-RM do? |

The intended measurement loop: capture the real backend's RPC behaviour, run the same stimulus in risc-v-gsp-rm-debugger, and compare the recorded sessions with the tool's accuracy metrics. A simulator observation is evidence about the firmware, not about silicon; anything that would change the product is reproduced on a physical reference first.

## 4. Quickstart

Requirements: Linux, Python 3.10+ (standard library only), `qemu-system-riscv64` (Ubuntu package `qemu-system-misc`), `clang` and `lld`. No GPU, no driver and no kernel module are touched. From the repository root:

```bash
cd 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 the 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: `info` reports QEMU and the demo paths; `demo` prints hook/branch lines and a session directory under `dumps/`; `analyze` renders hook/watch/breakpoint events and a coherent summary; `probe` reports a bounded first divergence (expected data, not a boot); `inject` returns matching values on the direct and firmware-dispatched invocation paths.

A large test suite (hundreds of tests) is run with `make test`, covering unit tests plus live-QEMU smoke runs.

## 5. 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, and from which store PC? |
| `run` / `run_until` | bounded observation; stop at a chosen address |
| `call` | 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 position-independent RV64 service |

Instructions between stops are invisible unless a trace is on (a TCG plugin on QEMU, or `--trace` on the native backend). Two backends — QEMU-RSP and the native interpreter — satisfy the same session API, so scripts, probes, plugins, recordings and comparisons survive a backend change.

## 6. 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** — never 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. Never quote a session for timing, interrupt, security or confidentiality claims; zero hits in a run are a coverage fact, not proof that code is dead.

## 7. Sessions as evidence

Every run records a session directory (format `greeneye-session/1`):

```text
dumps/<stamp>-<uuid>-<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, instruction/access traces, extra captures
  summary.md          rendered analysis
```

Rules that make a session usable 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.** Explain inside the session what was asked and what was changed; a chat log is not evidence.
3. **Attach the provenance.** Firmware SHA-256, version string, 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; a copied event stream alone is not evidence.
5. **State the fidelity.** Say which of L0/L1 was exercised and name the reference capture; do not silently waive L2/L3 gaps.
6. **Report deltas honestly.** Every remaining delta between two runs is explained or listed as open; an empty unexplained-delta list is a claim that must be earned.
7. **Prefer an A/B pair.** Static reading is a hypothesis; a recorded session is evidence; at least two comparable runs are a conclusion.

## 8. Safety and status

* **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 debugger stub.
* **No guest, no hardware, no product.** Nothing runs in a guest; injected services are prototypes, not shipped code; product changes go through the host module and a supervised physical confirmation.
* **Bounded everywhere.** Runs have durations and stop caps; reads and snapshots have size caps; a wedged target is left stopped and restarted clean rather than poked.
* **Local only.** The Ghidra bridge is a localhost transport, unauthenticated by design; never expose it on a network interface.
* **No confidentiality claims.** The tool is a study environment; never use injection to defeat a hardware security boundary.
* **Status.** The audited surfaces are the CLI and the session format.
  Working and live-verified: hooks/watchpoints, memory tools, sessions,
  declarative probes, plugins, remote calls, run-to-cursor, the injection
  SDK, the Ghidra bridges, the first-fault probe and the instruction/access
  trace. A partial device model boots the real GSP image through its
  relocation-copy rung deterministically; the message loop, the custom
  simulator and serving full host message traffic remain roadmap; porting and
  packaging scaffolds are pilot-status. Treat interface changes as reviewed
  events.

## 9. Related documentation

* [`../docs/05-operations/03-risc-v-gsp-rm-vm.md`](../docs/05-operations/03-risc-v-gsp-rm-vm.md) — project-level purpose, status and limits.
* [`../docs/05-operations/04-risc-v-gsp-rm-debugger-user-guide.md`](../docs/05-operations/04-risc-v-gsp-rm-debugger-user-guide.md) — the single user front door.
* [`../docs/05-operations/02-debugging-and-maintenance-workflows.md`](../docs/05-operations/02-debugging-and-maintenance-workflows.md) — captures, failure taxonomy and upgrade workflows.
* [`GSP-570.144W-Firmware-Analysis.md`](GSP-570.144W-Firmware-Analysis.md) and [`GSP-and-GSP-RM.md`](GSP-and-GSP-RM.md) — the firmware image and architecture the sessions exercise.
* [`CUDA-Userspace-Driver.md`](CUDA-Userspace-Driver.md) and [`Physical-GPU-Backend.md`](Physical-GPU-Backend.md) — the client side of the RPC traffic and the supervised backend the simulator complements.
* [`Project-Status.md`](Project-Status.md) and [`../docs/README.md`](../docs/README.md) — honest overall status and the documentation front door.