diff options
| author | Arthur Hanson Rasmusson <arthur@vgpu.io> | 2026-10-02 10:58:21 -0400 |
|---|---|---|
| committer | Arthur Hanson Rasmusson <arthur@vgpu.io> | 2026-10-02 10:58:21 -0400 |
| commit | 002e3d7d13c414ea874abbee8d82803dd3a72fe5 (patch) | |
| tree | 6627c12fa07f6a1cf73e5aaeb7390e698dd3a896 /debug/risc-v-gsp-rm-vm/harness/value_demos/s05_snapshot_diff.py | |
| parent | 2f249817df327f5dcccf0464ad517fa60d6071d3 (diff) | |
| download | open-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/s05_snapshot_diff.py')
| -rw-r--r-- | debug/risc-v-gsp-rm-vm/harness/value_demos/s05_snapshot_diff.py | 143 |
1 files changed, 143 insertions, 0 deletions
diff --git a/debug/risc-v-gsp-rm-vm/harness/value_demos/s05_snapshot_diff.py b/debug/risc-v-gsp-rm-vm/harness/value_demos/s05_snapshot_diff.py new file mode 100644 index 0000000..fd89131 --- /dev/null +++ b/debug/risc-v-gsp-rm-vm/harness/value_demos/s05_snapshot_diff.py @@ -0,0 +1,143 @@ +#!/usr/bin/env python3 +"""s05 - snapshot diff: which control-block fields did one command change? + +Real scenario (Handoff-vGPU-IO.md PART 91 ADDENDUM 6, 2026-10-01 cycle 12/13): +the fn72 ``GSP_SET_SYSTEM_INFO`` payload carried *unpacked* identity fields and +the reference sends raw config-space dwords; the server read the device id +back as zero and only a field-level comparison of the live payload/reply +could confirm the fix ("all zeroed fn72 fields cannot matter to this failure" +was settled by decoding, not by reading). Static review (REVIEW-FN72.md, +cycle 13's 1656-byte static-config reply) still needed a live before/after of +the control block to call the fix verified. + +Analog: snapshot the decoded control block before and after one command, +attribute every changed byte run to its named schema field, and show ECHO's +buffer side-effect separately. +""" +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 _fields_hit(schema, diffs) -> list[str]: + names = [] + for diff in diffs: + for field in schema.fields: + start = field.offset + end = field.offset + field.nbytes + if start <= diff.addr < end: + if field.name not in names: + names.append(field.name) + return names + + +def run() -> dict: + import greeneye as ge + from greeneye.memory import Memory + + backend = C.choose_backend("native") + out = C.artifact_dir("s05_snapshot_diff") + commands = [ + 's.snapshot(gsp_ctrl, 0x188, "before")', + "write mailbox cmd=2 (ECHO) with a known string; run", + 's.snapshot(gsp_ctrl, 0x188, "after")', + "Memory.diff(before, after); decode both via gsp_ctrl.schema.json", + ] + scenario = C.scenario( + ids=[ + "Handoff-vGPU-IO.md PART 91 ADDENDUM 6 cycle 12 (2026-10-01): unpacked fn72 identity fields", + "PART 91 ADDENDUM 7 (2026-10-01): 1656-byte static-config reply decoded field-by-field", + "docs/06-ACCURACY.md M6: memory side-effect agreement / snapshot hashes", + ], + baseline=( + "the malformed identity value was suspected statically (REVIEW-FN72) " + "but accepting the fix required a live boot per iteration; ten NOCAT " + "cycles ran before the field-level root cause was visible" + ), + projection=( + "the same before/after diff runs against any firmware region once " + "the H2 device model exposes the real RM control pages" + ), + blocked=True, + device="H2.2 RM control/reply pages for the real GSP-RM", + ) + C.render_banner( + "s05_snapshot_diff", + "Which named control-block fields did this one command change?", + "fn72/static-config field-level validation (identity fix, cycle 12/13)", + scenario["static_baseline"], + commands, + ) + + schema = C.load_schema(ge) + session = ge.launch(kernel=C.DEMO_ELF, backend=backend, name="vd-s05") + try: + ctrl = session.symbols.lookup("gsp_ctrl") + session.run(duration=0.25) + before = session.snapshot(ctrl, C.CTRL_SIZE, "before-echo") + message = b"hello-green-eye" + # Locate the string literal in the loaded image so the stimulus is + # self-describing (no hardcoded address). + hits = session.memory.search(0x80000000, 0x2000, message) + literal = hits[0] if hits else 0 + session.memory.write_u64(ctrl + C.CTRL_ARG0, literal) + session.memory.write_u64(ctrl + C.CTRL_MAILBOX, 2) + session.run(duration=0.25) + after = session.snapshot(ctrl, C.CTRL_SIZE, "after-echo") + + before_dec = C.decode_ctrl(ge, before, schema) + after_dec = C.decode_ctrl(ge, after, schema) + diffs = Memory.diff(before, after) + changed_fields = _fields_hit(schema, diffs) + changed_names = [name for name in changed_fields if before_dec.get(name) != after_dec.get(name)] + rendered = Memory.render_diff(diffs, symbols=session.symbols) + payload = { + "success": bool(changed_names) + and set(changed_names) >= {"rpc_count", "last_rpc", "result", "buf"} + and after_dec.get("result") == len(message), + "backend": backend, + "changed_field_names": changed_names, + "changed_byte_runs": len(diffs), + "before": {k: v for k, v in before_dec.items() if k in changed_names}, + "after": {k: v for k, v in after_dec.items() if k in changed_names}, + "rendered_diff": rendered, + "question": "attribute every changed byte in one region to a named field", + "answer": ( + f"ECHO changed {len(changed_names)} named fields {changed_names}; " + f"buf={after_dec.get('buf')!r} result={after_dec.get('result')} " + f"(len={len(message)}); {len(diffs)} byte runs exactly covered by the schema - " + "the field-level 'what did the reply actually consume' check" + ), + "success_criteria": { + "pass": "rpc_count/last_rpc/result/buf change, result equals the ECHO length, no unattributed run", + "fail": "a region changes with no named field, or the ECHO reply length disagrees", + }, + "real_case": scenario, + } + C.write_json(os.path.join(out, "snapshot-diff.json"), payload) + C.write_text( + os.path.join(out, "snapshot-diff.md"), + "# snapshot diff (analog)\n\n" + f"* changed fields: {changed_names}\n" + f"* changed byte runs: {len(diffs)}\n\n" + "```\n" + rendered + "\n```\n", + ) + finally: + session.close() + return payload + + +def main() -> int: + return 0 if C.timed_demo(run, C.artifact_dir("s05_snapshot_diff"))["success"] else 1 + + +if __name__ == "__main__": + raise SystemExit(main()) |
