diff options
Diffstat (limited to 'debug/risc-v-gsp-rm-vm/harness/value_demos/s06_inject_service.py')
| -rw-r--r-- | debug/risc-v-gsp-rm-vm/harness/value_demos/s06_inject_service.py | 124 |
1 files changed, 124 insertions, 0 deletions
diff --git a/debug/risc-v-gsp-rm-vm/harness/value_demos/s06_inject_service.py b/debug/risc-v-gsp-rm-vm/harness/value_demos/s06_inject_service.py new file mode 100644 index 0000000..04dd001 --- /dev/null +++ b/debug/risc-v-gsp-rm-vm/harness/value_demos/s06_inject_service.py @@ -0,0 +1,124 @@ +#!/usr/bin/env python3 +"""s06 - inject a service: add an RM engine without rebuilding the firmware. + +Real scenario (Handoff-vGPU-IO.md PART 92 ADDENDUM 5-11, 2026-10-02): the P6 +work wired guest-originated CE copies through the real engine; every change to +the service/wiring path cost a kernel rebuild plus a supervised physical boot +cycle (P6a/b/c, ~5-8 min each, one device-write experiment per cycle) and was +only accepted after guest smoke ``ALL OK 64/64``. docs/12-INJECTION-SDK.md +defines the in-simulator equivalent: load a position-independent service blob +and register it with the firmware's dispatch table (commands 16..23). + +Analog: load ``sdk/build/injected_demo.elf`` into slot 6, invoke it directly +(Frida NativeFunction) and through the firmware mailbox, and record the +``service_injected`` evidence event. No kernel rebuild, no hardware. +""" +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 run() -> dict: + import greeneye as ge + from greeneye.inject import invoke_remote, invoke_via_firmware, load_service + + backend = C.choose_backend("native") + out = C.artifact_dir("s06_inject_service") + commands = [ + 'load_service(s, "sdk/build/injected_demo.elf", slot=6)', + "invoke_remote(s, svc, cmd=1, a0=0x41) # debugger-side call", + "invoke_via_firmware(s, svc, cmd=1, a0=0x41) # mailbox cmd=16", + "read gsp_ctrl.result / handlers[6]", + ] + scenario = C.scenario( + ids=[ + "Handoff-vGPU-IO.md PART 92 ADDENDUM 5-11 (2026-10-02): P6 service/wiring rungs", + "PART 92 ADDENDUM 6 (2026-10-02): p6run7 first real engine copy after service wiring", + "docs/12-INJECTION-SDK.md: blob/ABI contract for injecting RM services", + ], + baseline=( + "each P6 rung was a kernel rebuild plus a supervised physical cycle " + "(~5-8 min boots; P6a->P6c spanned ~02:20-08:30) with fail-safe " + "release discipline after every run" + ), + projection=( + "on real GSP-RM the registry is the RM service table (M5), gated on " + "H2.2; the load/register/invoke/observe shape is identical to the " + "demo handler-table slot" + ), + blocked=True, + device="H2.2 device model + M5 RM service registry", + ) + C.render_banner( + "s06_inject_service", + "Can a new service be loaded, registered and invoked without rebuilding the firmware?", + "guest-originated CE service wiring (P6a-P6c): kernel rebuild + supervised boot per rung", + scenario["static_baseline"], + commands, + ) + + if not os.path.isfile(C.SDK_ELF): + payload = { + "success": False, + "skipped": True, + "failure": "sdk/build/injected_demo.elf not built (run: make sdk)", + "backend": backend, + "real_case": scenario, + } + C.write_json(os.path.join(out, "inject.json"), payload) + return payload + + session = ge.launch(kernel=C.DEMO_ELF, backend=backend, record=os.path.join(out, "session"), name="vd-s06") + try: + ctrl = session.symbols.lookup("gsp_ctrl") + session.run(duration=0.25) + service = load_service(session, C.SDK_ELF, slot=C.SERVICE_SLOT) + remote_ping = invoke_remote(session, service, 1, 0x41) + remote_sum = invoke_remote(session, service, 2, 0x10, 0x20) + via_fw_ping = invoke_via_firmware(session, service, 1, 0x41) + via_fw_sum = invoke_via_firmware(session, service, 2, 0x10, 0x20) + handlers7 = session.memory.read_u64(ctrl + 0x150 + 8 * C.SERVICE_SLOT) + payload = { + "success": remote_ping == (0x41 ^ C.PING_XOR) and remote_sum == 0x30 + and via_fw_ping == remote_ping and via_fw_sum == remote_sum, + "backend": backend, + "service": service.summary(), + "service_sha256": C.sha256_file(C.SDK_ELF), + "handlers_slot6": f"{handlers7:#x}", + "remote": {"ping": remote_ping, "sum": remote_sum}, + "via_firmware": {"ping": via_fw_ping, "sum": via_fw_sum}, + "mailbox_command": C.INJECT_CMD_BASE + C.SERVICE_SLOT, + "session": os.path.relpath(os.path.join(out, "session"), C.TOOL_ROOT), + "question": "load/register/invoke a service blob end-to-end, both routes", + "answer": ( + f"service loaded at {service.load_addr:#x}, slot {service.slot} " + f"(handlers[{service.slot}]={handlers7:#x}); remote ping={remote_ping:#x} " + f"sum={remote_sum:#x}; via mailbox cmd={C.INJECT_CMD_BASE + C.SERVICE_SLOT} " + f"ping={via_fw_ping:#x} sum={via_fw_sum:#x} - both paths agree, one session" + ), + "success_criteria": { + "pass": "remote and firmware-mailbox invocations return the SDK ABI values and agree", + "fail": "a route disagrees, the slot is not registered, or the blob cannot load", + }, + "real_case": scenario, + } + C.write_json(os.path.join(out, "inject.json"), payload) + finally: + session.close() + return payload + + +def main() -> int: + return 0 if C.timed_demo(run, C.artifact_dir("s06_inject_service"))["success"] else 1 + + +if __name__ == "__main__": + raise SystemExit(main()) |
