summaryrefslogtreecommitdiffstats
path: root/debug/risc-v-gsp-rm-vm/docs/12-INJECTION-SDK.md
blob: 26f1ffb619e0976597ee95c6a9f141facc9c5a9a (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
141
142
143
144
145
146
147
148
149
# 12 — Injection SDK specification (v1, demo ABI)

> **# TOOL IN DEVELOPMENT - NOT READY YET!** See 00 for status and
> [`GREEN-EYE-ROADMAP.md`](../GREEN-EYE-ROADMAP.md) §H1/H3 for the program.

## 1. Goals and non-goals

**Goals**
* a repeatable, scriptable way to compile a piece of RV64 code, load it into a
  live firmware target, register it, invoke it, and observe it with the same
  hooks/sessions/analysis as firmware;
* a clear ABI so services can be written once and run under the demo uproc
  today and under a simulated RM core later;
* an evidence trail: every load, registration and invocation is recorded.

**Non-goals (v1)**
* shipping any injected code (development-only);
* hot-patching signed firmware on hardware;
* bypassing security boundaries (the simulator is a study environment).

## 2. Blob contract

* **Format:** ELF64 `EM_RISCV`, `RV64IMAC`, soft-float ABI, one or more
  `PT_LOAD` segments.
* **Position independence:** built PIC (`-fPIC`, `-mcmodel=medany`,
  `-mno-relax`, `-fno-asynchronous-unwind-tables`), no dynamic relocations.
  The loader verifies by writing segments at the chosen load address; the SDK
  `make relocs` target must report none.
* **Self-sufficiency:** no libc, no global data containing addresses.
  Caller-provided addresses (future RM-core tables) arrive as arguments.
* **Entry symbol:** `ge_demo_service_dispatch` by default (override with
  `--entry`/`entry_symbol=`).
* **Optional metadata:** a `ge_service_t` block can be exported for future
  loaders (`magic 0x47455356`, version 1, name, dispatch).

## 3. ABI v1

```c
typedef ge_u64 (*ge_service_fn)(ge_u64 cmd, ge_u64 a0, ge_u64 a1);
```

* `a0`, `a1`, `a2` registers carry `(cmd, a0, a1)` on entry.
* The return value is `a0`.
* The service may use `a3..a7`, `t0..t6`, `s0..s11` and the stack; the
  injector supplies a private stack below the scratch page.
* Traps do not return: the call loop times out, records the stop, restores
  registers and raises `RspTimeout`.
* No calling convention for callbacks in v1; the loader registers a **single
  dispatch entry** per slot.

## 4. Demo registration model

* The firmware exposes eight handler slots (`gsp_ctrl.handlers[0..7]`).
* Mailbox commands **16..23** select slot `cmd-16`.
* On dispatch the firmware calls
  `handlers[slot](arg0, arg1, arg2)` — i.e. `cmd = arg0`, parameters
  `arg1`, `arg2`.
* Slots 0..5 are used by the built-in demo RPCs; **slot 6** is the SDK
  default (`--slot`).

### Control-block fields used (demo)

| Field | Offset | Role |
|---|---|---|
| `mailbox` | `+0x20` | command (`16 + slot` selects an injected service) |
| `arg0` | `+0x28` | service command |
| `arg1` | `+0x30` | parameter 0 |
| `arg2` | `+0x38` | parameter 1 |
| `result` | `+0x40` | service return value |
| `handlers` | `+0x150` | eight entry slots |

Offsets are demo-firmware-specific; use `greeneye/inject.py` constants and the
schema at `firmware/uproc_demo/gsp_ctrl.schema.json` rather than hardcoding.

## 5. Lifecycle

```
compile (PIC) ──► verify relocations ──► load PT_LOADs at load_addr
      │                                            │
      │                                            ├─► register entry in slot
      │                                            └─► record "service_injected"
      ▼
invoke_remote (direct call)          invoke_via_firmware (mailbox dispatch)
      └──────────────► both record call_enter/call_return events
```

* **Load address:** default `ram_base + 0x01000000`, auto-shrunk to fit if
  the image is larger; explicit with `--load-addr`.
* **Cleanup:** v1 does not unregister automatically. A service is removed by
  zeroing its slot and (optionally) clearing the blob; sessions record the
  injection so runs are reproducible from a known state.
* **Multiple services:** one per slot; multi-entry services are one dispatch
  with subcommands.

## 6. Observability contract

The injector records, in the session directory:
* `service_injected` — path, name, load address, entry address, slot, size;
* `mem_write` events for every segment written;
* `call_enter` / `call_return` — address, args, return value;
* hook/watch events from user instrumentation inside the service;
* `qemu.log`-style blobs are not applicable (no probe here), but the TCG
  trace can be enabled for full coverage.

Comparison of injected-service runs uses the standard `greeneye compare`
profiles, so a change in a service's behaviour is visible like any firmware
change.

## 7. Building (reference)

```makefile
CC  := clang
LLD ?= /usr/lib/llvm-18/bin/ld.lld
CFLAGS := --target=riscv64-unknown-elf -march=rv64imac -mabi=lp64 \
          -mcmodel=medany -mno-relax -fPIC -ffreestanding -nostdlib \
          -fno-builtin -fno-stack-protector -fno-asynchronous-unwind-tables -O2
$(LLD) -m elf64lriscv --no-relax -e ge_demo_service_dispatch -o service.elf service.o
```

The tracked SDK (`sdk/`) is the executable reference.

## 8. Versioning and compatibility

* ABI version 1 is the demo contract described here.
* Future ABI v2 (RM-core shim) will pass a call table and a service context
  instead of relying on firmware slots; blobs declare their ABI via the
  optional metadata block so loaders can refuse mismatches.
* Breaking ABI changes require a compatibility shim plus a note in the
  session metadata and this document.

## 9. Security and safety

* Injected code runs with the simulator's full privileges; the bridge and
  injector are local-only tools.
* Never inject into a guest or a shipped environment; never use injection to
  bypass a hardware protection.
* Fuzzing/mutation harnesses (roadmap H4.3) must run against the simulator
  or re-hosted code, with sessions attached as evidence.
* Treat every injected service as untrusted code for the purposes of
  watching: it may corrupt firmware state, so always record and restart clean
  after crashes.

## 10. Roadmap hooks

* **H1.3** — RM service registration and RM-core call interception.
* **H3** — native-simulator loader with snapshots and branch exploration.
* **H4** — differential testing of injected services across firmware
  versions and capability inference from their access patterns.
* **H5** — services spanning GSP and adjacent microcontrollers.