summaryrefslogtreecommitdiffstats
path: root/debug/risc-v-gsp-rm-vm/harness/value_demos/s10_full_session_evidence.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
commitf909a5f822c5c4a4e9526b861d4171f8925f5113 (patch)
treeed362021c83569f49b48079a774f05775e84b0bd /debug/risc-v-gsp-rm-vm/harness/value_demos/s10_full_session_evidence.py
parent09f241601423b1ae98e97846ee451768ff8a0a9e (diff)
downloadopen-iov-f909a5f822c5c4a4e9526b861d4171f8925f5113.tar.gz
open-iov-f909a5f822c5c4a4e9526b861d4171f8925f5113.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/s10_full_session_evidence.py')
-rw-r--r--debug/risc-v-gsp-rm-vm/harness/value_demos/s10_full_session_evidence.py213
1 files changed, 213 insertions, 0 deletions
diff --git a/debug/risc-v-gsp-rm-vm/harness/value_demos/s10_full_session_evidence.py b/debug/risc-v-gsp-rm-vm/harness/value_demos/s10_full_session_evidence.py
new file mode 100644
index 0000000..f6cd48f
--- /dev/null
+++ b/debug/risc-v-gsp-rm-vm/harness/value_demos/s10_full_session_evidence.py
@@ -0,0 +1,213 @@
+#!/usr/bin/env python3
+"""s10 - full session evidence: one run produces the whole evidence pack.
+
+Real scenario (docs/14-ADVERSARIAL-INTEROP-GUIDE.md 6; Handoff-vGPU-IO.md
+PART 91 ADDENDA 6-7 and PART 92 ADDENDA 6-11, 2026-10-01..10-02): a finding
+is only a finding with firmware hashes, baseline/candidate sessions, an
+analyze report, a compare report, the M1-M6 table, ``greeneye_hits.tsv`` and
+an unexplained-delta list. The physical milestone cycles each gathered this
+by hand across separate boots and log windows (cycle evidence dirs
+``backups/evidence-20261001-cycle{11,12,13}``, P6 evidence dirs).
+
+Analog: one recorded session with hooks/watchpoints/notes/snapshots, a second
+identical run for determinism, an analyze report, a session compare, an
+exported hits TSV and a manifest with hashes - plus measured tool overhead
+(startup, session size, trace slowdown).
+"""
+from __future__ import annotations
+
+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
+
+
+def _stimulus(ge, record, backend: str) -> dict:
+ session = ge.launch(kernel=C.DEMO_ELF, backend=backend, record=record, name=os.path.basename(record))
+ try:
+ ctrl = session.symbols.lookup("gsp_ctrl")
+ stats = {"dispatches": [], "sum_hits": 0, "result_stores": 0}
+ session.hook(
+ "rpc_dispatch",
+ on_enter=lambda hit: stats["dispatches"].append(hit.arg(0)),
+ )
+ session.hook("rpc_sum", on_enter=lambda hit: stats.__setitem__("sum_hits", stats["sum_hits"] + 1))
+ session.watch(ctrl + C.CTRL_RESULT, size=8, kind="w", callback=lambda hit: stats.__setitem__("result_stores", stats["result_stores"] + 1))
+ session.run(duration=0.4)
+ session.snapshot(ctrl, C.CTRL_SIZE, "selftest-done")
+ session.memory.write_u64(ctrl + C.CTRL_ARG0, 0x1234)
+ session.memory.write_u64(ctrl + C.CTRL_MAILBOX, 1)
+ session.run(duration=0.2)
+ session.note("stimulus", cmd=1, arg0=0x1234, expected=0x1234 ^ C.PING_XOR)
+ session.snapshot(ctrl, C.CTRL_SIZE, "after-ping")
+ stats["ping_reply"] = session.memory.read_u64(ctrl + C.CTRL_RESULT)
+ session.memory.write_u64(ctrl + C.CTRL_MAILBOX, 5)
+ session.run(duration=0.2)
+ stats["state_reply"] = session.memory.read_u64(ctrl + C.CTRL_RESULT)
+ stats["rpc_count"] = session.memory.read_u64(ctrl + C.CTRL_RPC_COUNT)
+ return stats
+ finally:
+ session.close()
+
+
+def _dir_size(path: str) -> int:
+ total = 0
+ for root, _dirs, files in os.walk(path):
+ for name in files:
+ total += os.path.getsize(os.path.join(root, name))
+ return total
+
+
+def _trace_overhead(ge, out: str) -> dict:
+ import time
+
+ def timed(trace):
+ record = os.path.join(out, "trace-off" if not trace else "trace-on")
+ start = time.monotonic()
+ session = ge.launch(kernel=C.DEMO_ELF, backend="native", record=record, trace=trace, name="vd-s10-trace")
+ run_start = time.monotonic()
+ try:
+ session.run(duration=0.25)
+ finally:
+ run_s = time.monotonic() - run_start
+ session.close()
+ return run_s, time.monotonic() - start
+
+ off_run, off_total = timed(None)
+ on_run, on_total = timed(True)
+ return {
+ "untraced_run_s": round(off_run, 4),
+ "traced_run_s": round(on_run, 4),
+ "run_slowdown_x": round(on_run / off_run, 2) if off_run else None,
+ "untraced_total_s": round(off_total, 4),
+ "traced_total_s": round(on_total, 4),
+ "total_slowdown_x": round(on_total / off_total, 2) if off_total else None,
+ "note": "total includes writing blobs/trace.jsonl (~200k exec lines) at close",
+ }
+
+
+def run() -> dict:
+ import time
+
+ import greeneye as ge
+ from greeneye.analyze import compare_sessions, render_summary
+ from greeneye.ghidra import export_hits
+
+ backend = C.choose_backend("qemu")
+ out = C.artifact_dir("s10_full_session_evidence")
+ commands = [
+ 'ge.launch(backend="%s", record="session-A") + hooks/watch/notes/snapshots' % backend,
+ "repeat the identical stimulus into session-B",
+ "render_summary(A); compare_sessions(A, B, --symbols); export_hits(A)",
+ "hash firmware + artifacts into manifest.json with the M1-M6 skeleton",
+ ]
+ scenario = C.scenario(
+ ids=[
+ "docs/14-ADVERSARIAL-INTEROP-GUIDE.md 6: evidence-pack checklist and report template",
+ "Handoff-vGPU-IO.md PART 91 ADDENDUM 6-7 (2026-10-01): cycle 11-13 evidence dirs",
+ "PART 92 ADDENDUM 6-11 (2026-10-02): P6 evidence dirs and per-cycle release transcripts",
+ "docs/06-ACCURACY.md 5: M1-M6 measurement contract",
+ ],
+ baseline=(
+ "every physical milestone gathered hash + session + logs + compare "
+ "by hand across separate boots and log windows; cycles 11-13 and "
+ "the P6 runs each have their own evidence directory"
+ ),
+ projection=(
+ "on real firmware the same one-session pack is produced once H2.2 "
+ "executes the image; the manifest/M1-M6 format is backend-agnostic"
+ ),
+ blocked=True,
+ device="H2.2 device model for real .fwimage session evidence",
+ )
+ C.render_banner(
+ "s10_full_session_evidence",
+ "Can one run produce the complete evidence pack (sessions, analyze, compare, hits, hashes, M1-M6)?",
+ "milestone evidence packs gathered manually across boots",
+ scenario["static_baseline"],
+ commands,
+ )
+
+ start = time.monotonic()
+ session_a = _stimulus(ge, os.path.join(out, "session-A"), backend)
+ session_b = _stimulus(ge, os.path.join(out, "session-B"), backend)
+
+ symbols = ge.SymbolDB()
+ symbols.load_elf(ge.load_elf(C.DEMO_ELF))
+ report = render_summary(os.path.join(out, "session-A"), symbols=symbols, max_rows=30)
+ C.write_text(os.path.join(out, "analyze.md"), report)
+ compare = compare_sessions(os.path.join(out, "session-A"), os.path.join(out, "session-B"), symbols=symbols, max_rows=30)
+ C.write_text(os.path.join(out, "compare.md"), compare)
+ hits = export_hits(os.path.join(out, "session-A"), os.path.join(out, "greeneye_hits.tsv"), symbols=symbols)
+ trace = _trace_overhead(ge, out)
+ size_a = _dir_size(os.path.join(out, "session-A"))
+ size_b = _dir_size(os.path.join(out, "session-B"))
+ deltas_match = session_a["dispatches"] == session_b["dispatches"] and session_a["ping_reply"] == session_b["ping_reply"]
+ manifest = {
+ "format": "greeneye-value-evidence/1",
+ "firmware": {
+ "path": os.path.relpath(C.DEMO_ELF, C.TOOL_ROOT),
+ "sha256": C.sha256_file(C.DEMO_ELF),
+ },
+ "sessions": {
+ "a": {"path": os.path.relpath(os.path.join(out, "session-A"), C.TOOL_ROOT), "bytes": size_a, "sha256_manifest": C.sha256_file(os.path.join(out, "session-A", "events.jsonl"))},
+ "b": {"path": os.path.relpath(os.path.join(out, "session-B"), C.TOOL_ROOT), "bytes": size_b, "sha256_manifest": C.sha256_file(os.path.join(out, "session-B", "events.jsonl"))},
+ },
+ "stimulus": {"commands": [1, 5], "arg0": 0x1234, "note": "PING then STATE"},
+ "observed": {"a": session_a, "b": session_b, "delta_match": deltas_match},
+ "metrics": [
+ {"id": "M1", "name": "inventory coverage", "status": "observed", "value": "dispatch inventory [1,2,3,4,5,5,5] self-test + [1,5] stimulus"},
+ {"id": "M2", "name": "reply agreement", "status": "not measured", "reason": "no physical reference capture (needs H2/production trace)"},
+ {"id": "M3", "name": "ordering agreement", "status": "observed", "value": "identical dispatch sequence across A/B"},
+ {"id": "M4", "name": "state agreement", "status": "observed", "value": "rpc_state stage cycling on the control block"},
+ {"id": "M5", "name": "error-path agreement", "status": "not measured", "reason": "error path demoed in s08; no reference to agree against"},
+ {"id": "M6", "name": "memory side-effects", "status": "observed", "value": "2 named region snapshots (selftest-done, after-ping) per session"},
+ ],
+ "artifacts": {
+ "analyze": "analyze.md",
+ "compare": "compare.md",
+ "hits": os.path.relpath(hits, out),
+ "manifest": "manifest.json",
+ },
+ "overhead": {
+ "session_a_bytes": size_a,
+ "session_b_bytes": size_b,
+ "trace": trace,
+ "doc16_trace_slowdown": "~2.4x exec trace on the demo workload (docs/16 measured 0.54 MIPS traced vs 1.5 MIPS untraced)",
+ },
+ "unexplained_deltas": [] if deltas_match else ["session A/B observed values differ"],
+ }
+ payload = {
+ "success": deltas_match and session_a["ping_reply"] == (0x1234 ^ C.PING_XOR) and size_a > 0,
+ "backend": backend,
+ "elapsed_within_demo_s": round(time.monotonic() - start, 3),
+ "manifest": manifest,
+ "question": "one run -> hash + sessions + analyze + compare + hits + M1-M6, plus tool overhead",
+ "answer": (
+ f"one {backend} stimulus pair produced {session_a['dispatches']} dispatches, "
+ f"PING reply {session_a['ping_reply']:#x}, STATE reply {session_a['state_reply']:#x}, "
+ f"{session_a['result_stores']} publication stores; session {size_a} B; "
+ f"A/B deterministic={deltas_match}; analyze+compare+hits+manifest written"
+ ),
+ "success_criteria": {
+ "pass": "reply matches the ABI, both sessions agree, all artifacts exist, deltas list is empty",
+ "fail": "nondeterminism, missing artifact, or an unexplained delta",
+ },
+ "real_case": scenario,
+ }
+ C.write_json(os.path.join(out, "manifest.json"), manifest)
+ C.write_json(os.path.join(out, "evidence.json"), payload)
+ return payload
+
+
+def main() -> int:
+ return 0 if C.timed_demo(run, C.artifact_dir("s10_full_session_evidence"))["success"] else 1
+
+
+if __name__ == "__main__":
+ raise SystemExit(main())