summaryrefslogtreecommitdiffstats
path: root/debug/risc-v-gsp-rm-vm/docs/11-GSP-RM-SERVICE-DEVELOPER-GUIDE.md
diff options
context:
space:
mode:
authorArthur Hanson Rasmusson <arthur@vgpu.io>2026-10-02 09:13:00 -0400
committerArthur Hanson Rasmusson <arthur@vgpu.io>2026-10-02 09:13:00 -0400
commit1e701396b1b6d204dfd8e5a8ddcd3007038029ac (patch)
tree8dde895cf9d3e66ce912d01cb1a72ff674dc850f /debug/risc-v-gsp-rm-vm/docs/11-GSP-RM-SERVICE-DEVELOPER-GUIDE.md
parentab48e44832db55fdedadcf44f55fa9904ca36f2f (diff)
downloadopen-iov-1e701396b1b6d204dfd8e5a8ddcd3007038029ac.tar.gz
open-iov-1e701396b1b6d204dfd8e5a8ddcd3007038029ac.zip
debug: green-eye wave 2 - injection SDK, Frida-like calls, Ghidra control bridge, long-term docs
Adds to debug/risc-v-gsp-rm-vm/: - Session.call / run_until: Frida-like remote function calls and run-to-cursor, with register restoration; verified live (rpc_ping -> 0xaffe). - symbol+offset target resolution (gsp_ctrl+0x10) across all APIs and the REPL. - Injection SDK (sdk/) and 'greeneye inject': position-independent RV64 service blobs (verified zero relocations), loaded into RAM, registered in the demo handler table, and invoked either directly or through the firmware mailbox dispatcher. Demo ABI extended: mailbox 16..23 selects slots, arg0 carries the service command, arg2 added (struct now 0x190; schema updated). - Ghidra control bridge (greeneye ghidra + GreenEyeControl.java): run-until-here, breakpoints, memory/register access, remote calls, hit export; verified end-to-end with Ghidra headless (run_until reached rpc_sum from a GhidraScript). - MarkGreenEyeHits.java fixed for the Ghidra 12 createBookmark API; verified headless together with ExportForGreenEye.java. - Analyzer renders a QEMU first-fault table for probe sessions (fault count, epc with firmware vaddr translation, access address/size, reason). - Tests now 35 green, including injection, Ghidra bridge, remote call, run-until and REPL command smoke tests. - Documentation: docs/11-16 (GSP RM service developer guide, injection SDK specification, Ghidra control, adversarial interoperability guide, agentic GSP IDE, custom simulator design) and GREEN-EYE-ROADMAP.md (long-term H1-H7 program); doc maps and the project RISC-V VM doc updated.
Diffstat (limited to 'debug/risc-v-gsp-rm-vm/docs/11-GSP-RM-SERVICE-DEVELOPER-GUIDE.md')
-rw-r--r--debug/risc-v-gsp-rm-vm/docs/11-GSP-RM-SERVICE-DEVELOPER-GUIDE.md181
1 files changed, 181 insertions, 0 deletions
diff --git a/debug/risc-v-gsp-rm-vm/docs/11-GSP-RM-SERVICE-DEVELOPER-GUIDE.md b/debug/risc-v-gsp-rm-vm/docs/11-GSP-RM-SERVICE-DEVELOPER-GUIDE.md
new file mode 100644
index 0000000..6ba8d69
--- /dev/null
+++ b/debug/risc-v-gsp-rm-vm/docs/11-GSP-RM-SERVICE-DEVELOPER-GUIDE.md
@@ -0,0 +1,181 @@
+# 11 — GSP RM firmware service developer guide
+
+> **# TOOL IN DEVELOPMENT - NOT READY YET!** See 00 for status and 06 for the
+> fidelity caveats. Exact proprietary API names are not reproduced in tracked
+> docs; local provenance lives in the local analysis notes.
+
+## 1. What this guide is for
+
+The GSP runs a resource manager (RM) as **services**: message handlers, state
+machines and engines that own objects (devices, address spaces, channels,
+memory, notifiers) and answer controls. Open-IOV emulates those services; the
+long-term goal of green-eye is to let a developer **write, inject, run and
+debug their own versions of these services** before (or instead of) changing
+the product emulation.
+
+This guide teaches the loop on the demo uproc — which implements the same
+shape as a GSP service — and maps each step to the future GSP-RM work in
+[`GREEN-EYE-ROADMAP.md`](../GREEN-EYE-ROADMAP.md) H1.3.
+
+## 2. Service anatomy
+
+| Concept | Demo uproc (today) | GSP-RM (roadmap H1.3) |
+|---|---|---|
+| Entry point | exported symbol `ge_demo_service_dispatch` | service entry registered with the RM core |
+| Dispatch ABI | `u64 dispatch(u64 cmd, u64 a0, u64 a1)` | same shape via the service registry shim |
+| Reachability | firmware mailbox commands 16..23 select handler slot 0..7; `arg0` is the service command, `arg1`/`arg2` are parameters | RM message/control dispatch routed by the simulator's RM-core |
+| State | service-local (stack/registers) or the control block | RM objects and service-private memory |
+| Talking to peers | control-block fields + mailbox; debugger calls | RM-core calls and inter-service messages |
+| Observability | hooks/watchpoints/sessions/TCG trace | same, plus RM-core call interception |
+
+A service must be **position-independent**: no globals, no libc, no absolute
+addresses. Everything it calls is either its own code or an address passed in
+by the injector (the future RM-core shim will pass a table of callable
+entry points, which is also the interception point).
+
+## 3. Writing a service
+
+1. Copy the SDK shape from `sdk/`:
+ * `greeneye_service.h` — the ABI header;
+ * `injected_demo.c` — a working multi-command service.
+2. Implement `ge_service_fn`:
+ ```c
+ __attribute__((noinline)) ge_u64 my_service_dispatch(ge_u64 cmd, ge_u64 a0, ge_u64 a1)
+ {
+ switch (cmd) {
+ case 1: return a0 ^ 0xbeefu;
+ case 2: return a0 + a1;
+ default: return ~cmd;
+ }
+ }
+ ```
+3. Keep it PIC-clean: no `static` data with pointers, no string globals, no
+ division (the demo build has no libc), no stack beyond a few KiB.
+4. Build:
+ ```bash
+ make -C sdk # or point the Makefile at your source
+ make -C sdk relocs # must print "no relocations in this file"
+ ```
+5. Fix any relocation the linker reports before injecting; relocations mean
+ the blob will not run at an arbitrary load address.
+
+## 4. Injecting and invoking
+
+```bash
+./greeneye.sh inject --service sdk/build/injected_demo.elf \
+ --cmd 1 --arg0 0x41 --arg1 0x42
+```
+
+What happens (all recorded):
+1. Every `PT_LOAD` is written into RAM (default `0x81000000`; auto-sized to
+ fit the target).
+2. The service dispatch entry is patched into handler slot 6
+ (`--slot` selects 0..7).
+3. A **direct debugger-side call** runs the service immediately
+ (`greeneye.inject.invoke_remote`): this is the unit-test path, independent
+ of firmware state.
+4. After the firmware settles, a **firmware-dispatched call** writes
+ `arg0=cmd, arg1=a0, arg2=a1, mailbox=16+slot` and reads `result`
+ (`greeneye.inject.invoke_via_firmware`): this is the integration path.
+
+Programmatic form:
+
+```python
+from greeneye.inject import load_service, invoke_remote, invoke_via_firmware
+svc = load_service(s, "sdk/build/injected_demo.elf", slot=6)
+print(hex(invoke_remote(s, svc, 2, 0x10, 0x20))) # 0x30
+s.run(duration=0.3)
+print(hex(invoke_via_firmware(s, svc, 2, 0x10, 0x20))) # 0x30
+```
+
+## 5. Talking to other services and the host
+
+On the demo:
+* the **control block** is the shared state (`gsp_ctrl`); services coordinate
+ through its fields and the mailbox command range;
+* the **host/debugger** is a peer via hooks, watchpoints and `Session.call`;
+* a service can call another service if it is handed the other entry address
+ (the SDK's second export `ge_demo_service_answer` demonstrates a second
+ callable point; the injector resolves any exported symbol).
+
+On real GSP-RM (H1.3) the same roles are filled by RM-core allocation and
+control calls and by messages between services. The simulator will intercept
+those calls so they can be logged, stubbed, or forwarded to the real
+implementation — which is exactly what makes the environment powerful for
+prototyping: a service you write can be exercised against recorded RM-core
+behaviour before the product emulation implements it.
+
+## 6. Resource surfaces an engine can use
+
+Category map (details are RM-version-specific and tracked privately where
+provenance requires it):
+
+| Surface | Purpose | How green-eye helps today |
+|---|---|---|
+| Memory / descriptors | allocate, map, free, register host or vidmem ranges | watchpoints on allocation state; snapshot/diff; schema decode |
+| Address spaces / page tables | GPU VA translation, mapping updates | hooks on map/unmap routines; memory diffs; TCG trace of accesses |
+| Channels / GPFIFO / USERD | submission plumbing | hooks and remote calls; observe ring state via snapshots |
+| Sync: semaphores, notifiers, interrupts | completion and signalling | watchpoints on sem values; event ordering in sessions |
+| Engine scheduling / runlists | prioritisation, preemption | call-graph and hook evidence; compare runs |
+| Controls / messages | configuration and queries | declarative probes; replay/compare across versions |
+| Device identity / caps / clocks | what the RM reports | schema decode of the static-config block; A/B vs hardware oracle |
+
+Everything here is observed through the same primitives, so an engine
+prototype is analysed exactly like firmware code.
+
+## 7. Debugging workflow
+
+1. **Unit-test with `call`:** breakpoints and hooks around the service entry,
+ `Session.call(entry, (cmd, a0, a1))`, inspect the return and watchpoints on
+ its data. Failures raise `RspTimeout` and leave the session recording.
+2. **Integration run:** `invoke_via_firmware` with the mailbox path, while
+ hooks on the firmware's dispatcher and watchpoints on the control block
+ record the full route.
+3. **Ghidra-driven:** `greeneye ghidra` + `GreenEyeControl.java` — execute
+ until a service address, set breakpoints from the decompiler, read
+ registers/memory, export hits (docs/13).
+4. **Coverage:** run with the TCG plugin filtered to the service load range
+ (`qemu/greeneye-trace.c`, `start=`/`end=` args) to see every access.
+5. **Regression:** record a session per command; `greeneye compare` detects
+ changed hit/watch/write profiles when the service or firmware changes.
+
+## 8. Rules and pitfalls
+
+* **PIC purity first.** If the blob needs relocation, it is not injectable
+ at an arbitrary address.
+* **No absolute addresses from the host.** Use exported symbols and
+ `load_service`, never hardcoded addresses.
+* **No unbounded loops.** A service that never returns blocks the call loop
+ until the timeout and then leaves the target stopped; the recorder shows
+ the last PC.
+* **Watchpoint the state, hook the entry.** Watchpoints are immediate (one
+ instruction step) and ideal for counters; hooks give arguments/returns.
+* **Never ship a service.** Injected code is a development experiment; the
+ product changes go through `open-iov-vfio` with the accuracy loop.
+* **Record everything.** A claim about a service without a session is not
+ evidence.
+
+## 9. Worked example: add a command
+
+```c
+/* sdk/injected_demo.c */
+case 7:
+ return (a0 | (a1 << 8)) & 0xFFFFFFFFull;
+```
+
+```bash
+make -C sdk
+./greeneye.sh inject --cmd 7 --arg0 0xab --arg1 0xcd
+# direct call -> 0xcdab
+# firmware call -> 0xcdab
+./greeneye.sh analyze <printed session dir> # event/hit report
+```
+
+## 10. What comes next (roadmap)
+
+* H1.3: services built against an RM shim, registered with a simulated RM
+ core, calling intercepted RM-core surfaces.
+* H2: the device model that lets real GSP-RM run in the simulator at all.
+* H4: adversarial navigation — diff service behaviour across firmware
+ versions, mutate inputs, infer capabilities.
+* H5: services that interact with PMU/SEC2/ACR models.