summaryrefslogtreecommitdiffstats
path: root/debug/risc-v-gsp-rm-vm/harness/value_demos/s03_unknown_command.py
diff options
context:
space:
mode:
authorArthur Hanson Rasmusson <arthur@vgpu.io>2026-10-02 10:58:21 -0400
committerArthur Hanson Rasmusson <arthur@vgpu.io>2026-10-02 10:58:21 -0400
commit002e3d7d13c414ea874abbee8d82803dd3a72fe5 (patch)
tree6627c12fa07f6a1cf73e5aaeb7390e698dd3a896 /debug/risc-v-gsp-rm-vm/harness/value_demos/s03_unknown_command.py
parent2f249817df327f5dcccf0464ad517fa60d6071d3 (diff)
downloadopen-iov-002e3d7d13c414ea874abbee8d82803dd3a72fe5.tar.gz
open-iov-002e3d7d13c414ea874abbee8d82803dd3a72fe5.zip
debug: green-eye wave 3 - RM harness, local simulator, device map, MCP plugin, value-validation demos, CI pipeline, toolchain docs; add host RM tools rmtool/rmtop
Diffstat (limited to 'debug/risc-v-gsp-rm-vm/harness/value_demos/s03_unknown_command.py')
-rw-r--r--debug/risc-v-gsp-rm-vm/harness/value_demos/s03_unknown_command.py167
1 files changed, 167 insertions, 0 deletions
diff --git a/debug/risc-v-gsp-rm-vm/harness/value_demos/s03_unknown_command.py b/debug/risc-v-gsp-rm-vm/harness/value_demos/s03_unknown_command.py
new file mode 100644
index 0000000..162bc47
--- /dev/null
+++ b/debug/risc-v-gsp-rm-vm/harness/value_demos/s03_unknown_command.py
@@ -0,0 +1,167 @@
+#!/usr/bin/env python3
+"""s03 - unknown command discovery: which IDs are handled, injected, or new?
+
+Real scenario (docs/19-CONTROL-DISCOVERY.md, measured 2026-10-02): a swept
+input surface is how new/undocumented controls are found between firmware
+versions. On the demo, IDs 16..23 were *discovered* to fall through the
+switch into the injected-service handler table (16..21 alias the built-in
+handlers, 22..23 are NULL slots returning ``~id``) - wiring a new image can
+add silently. Statically this requires reading an indirect dispatch table
+per version; behaviorally it is a bounded sweep.
+
+Analog: 24 command IDs, zero arguments, deterministic, fresh session per ID
+(the same safety strategy as the real discovery tool), classified by hooks on
+the dispatcher and every handler-table entry.
+"""
+from __future__ import annotations
+
+import json
+import os
+
+try: # package import (tests) or direct script execution (run_all)
+ from . import _common as C
+except ImportError:
+ import sys as _sys
+
+ _sys.path.insert(0, os.path.dirname(os.path.abspath(__file__)))
+ import _common as C
+
+HANDLERS = ("rpc_ping", "rpc_echo", "rpc_fill", "rpc_sum", "rpc_state", "rpc_fault")
+
+
+def _classify(cmd: int, handler_hits, dispatch_seen, result, trap) -> str:
+ if 16 <= cmd <= 23:
+ return "injected-slot"
+ if 1 <= cmd <= 6:
+ return "known-handler"
+ if trap:
+ return "trap"
+ if result is not None and result == (~cmd) & 0xFFFFFFFFFFFFFFFF:
+ return "default-path"
+ return "no-progress"
+
+
+def run() -> dict:
+ import greeneye as ge
+
+ backend = C.choose_backend("native")
+ out = C.artifact_dir("s03_unknown_command")
+ commands = [
+ 'for cmd in 1..24: ge.launch(backend="%s"); hook(rpc_dispatch + 6 handlers)' % backend,
+ "write mailbox cmd with zero args; run bounded; classify",
+ "record: outcome, handler alias, result, trap signal, rpc_count delta",
+ ]
+ scenario = C.scenario(
+ ids=[
+ "docs/19-CONTROL-DISCOVERY.md (2026-10-02): 189-probe demo sweep in ~36 s",
+ "Handoff-vGPU-IO.md PART 91 (2026-10-01): new controls appear between images (0x59 era)",
+ "docs/14-ADVERSARIAL-INTEROP-GUIDE.md 4.1: static diff says code changed, not which input activates it",
+ ],
+ baseline=(
+ "static-only: read the indirect dispatcher table in Ghidra for every "
+ "image; on the real corpus the demo sweep took ~36 s for 189 probes "
+ "and still found an undocumented injected-slot class"
+ ),
+ projection=(
+ "the RM surface (control IDs by class, method opcodes) is gated on "
+ "H1.3/H2.2; the sweep/classification shape demonstrated here is "
+ "exactly what docs/19 section 5 designs for it"
+ ),
+ blocked=True,
+ device="H1.3/H2.2: RM dispatch table exposed to the simulator",
+ )
+ C.render_banner(
+ "s03_unknown_command",
+ "Which command IDs are handled, which route to injected slots, and which are new/default?",
+ "unknown-control discovery between stripped firmware versions",
+ scenario["static_baseline"],
+ commands,
+ )
+
+ findings = []
+ for cmd in range(1, 25):
+ session = ge.launch(kernel=C.DEMO_ELF, backend=backend, name=f"vd-s03-{cmd:02d}")
+ try:
+ ctrl = session.symbols.lookup("gsp_ctrl")
+ dispatch = []
+ handler_hits = []
+ signals = []
+ session.hook(
+ "rpc_dispatch",
+ on_enter=lambda hit, d=dispatch: d.append(
+ {"cmd": hit.arg(0), "arg0": hit.arg(1), "arg1": hit.arg(2), "arg2": hit.arg(3)}
+ ),
+ )
+ for name in HANDLERS:
+ try:
+ session.hook(name, on_enter=lambda hit, n=name: handler_hits.append(n))
+ except Exception:
+ pass
+ session.on_event("stop", lambda hit, sig=signals: sig.append(hit.stop.signal) if hit.stop else None)
+ session.run(duration=0.15)
+ session.memory.write_u64(ctrl + C.CTRL_MAILBOX, cmd)
+ session.run(duration=0.15)
+ result = session.memory.read_u64(ctrl + C.CTRL_RESULT)
+ trap = 5 in [s for s in signals if s]
+ outcome = _classify(cmd, handler_hits, bool(dispatch), result, trap)
+ findings.append(
+ {
+ "cmd": cmd,
+ "outcome": outcome,
+ "trap": trap,
+ "signals": [s for s in signals if s],
+ "handler_alias": handler_hits[0] if handler_hits else None,
+ "dispatch_seen": bool(dispatch),
+ "result": result,
+ "result_hex": f"{result:#x}",
+ "expected_default": f"{(~cmd) & 0xFFFFFFFFFFFFFFFF:#x}",
+ }
+ )
+ finally:
+ session.close()
+
+ by_class: dict[str, list[int]] = {}
+ for finding in findings:
+ by_class.setdefault(finding["outcome"], []).append(finding["cmd"])
+ injected = by_class.get("injected-slot", [])
+ aliases = {f["cmd"]: f["handler_alias"] for f in findings if f["cmd"] in injected}
+ payload = {
+ "success": len(injected) == 8 and len(by_class.get("known-handler", [])) == 6,
+ "backend": backend,
+ "ids_swept": len(findings),
+ "classes": {key: {"count": len(v), "ids": v} for key, v in sorted(by_class.items())},
+ "injected_aliases": aliases,
+ "findings": findings,
+ "question": "enumerate handled / injected / default command space in one bounded sweep",
+ "answer": (
+ f"{len(by_class.get('known-handler', []))} known handlers, "
+ f"{len(injected)} injected-slot IDs ({injected}), aliases {aliases}, "
+ f"{len(by_class.get('default-path', []))} default-path IDs; "
+ "the same shape (sweep + dispatcher/handler hooks) is what found the "
+ "silent 16..23 wiring the static map did not highlight"
+ ),
+ "success_criteria": {
+ "pass": "IDs 1..6 classified known, 16..23 classified injected-slot, remaining default; cmd 6 traps",
+ "fail": "an ID is misclassified or a fresh-session probe cannot be replayed",
+ },
+ "real_case": scenario,
+ }
+ os.makedirs(out, exist_ok=True)
+ with open(os.path.join(out, "findings.jsonl"), "w", encoding="utf-8") as fh:
+ for finding in findings:
+ fh.write(json.dumps(finding, sort_keys=True) + "\n")
+ lines = ["# control discovery (analog)", "", f"* backend: {backend}", f"* ids swept: {len(findings)}", ""]
+ for key, value in sorted(by_class.items()):
+ lines.append(f"* {key}: {value}")
+ lines.append("")
+ C.write_text(os.path.join(out, "control-discovery.md"), "\n".join(lines) + "\n")
+ C.write_json(os.path.join(out, "discovery.json"), payload)
+ return payload
+
+
+def main() -> int:
+ return 0 if C.timed_demo(run, C.artifact_dir("s03_unknown_command"))["success"] else 1
+
+
+if __name__ == "__main__":
+ raise SystemExit(main())