#!/usr/bin/env python3 """Poll the VT1200 diagnostic handoff cells over rdebug during a boot. rdebug only exists once the OS/network stack is up, so this cannot see the level-1 tests themselves. It *can* catch the window between the network stack starting and the Terminal Manager consuming the diagnostic result: 0x27C190 diagnostic mailbox pointer (Ghidra: FUN_rom_07f5a026 dereferences it) 0x16F0 level-1 dispatcher's transient status code slot If the mailbox pointer becomes non-zero, the nine fields it points at are dumped. The log records every value change, so a value that exists only for a few polls is still captured. Usage: python3 dwt/mailbox_watch.py --host 100.103.100.103 --seconds 180 Start it, then power-cycle the terminal. """ from __future__ import annotations import argparse import struct import sys import time import exploit MAILBOX = 0x27C190 SLOT = 0x16F0 FIELDS = 9 def u32(rd: exploit.RDebug, bit: int) -> int: return struct.unpack(" None: log.write(line + "\n") log.flush() emit(f"watch {a.host}:{a.port} for {a.seconds:.0f}s -> {a.out}") while time.time() < deadline: if rd is None: try: rd = exploit.RDebug(a.host, a.port, 2.0, False) rd.connect() emit(f"{time.time():.3f} connected") except Exception as exc: # noqa: BLE001 time.sleep(0.4) continue try: m = u32(rd, MAILBOX) s = u32(rd, SLOT) if m != last_m or s != last_s: emit(f"{time.time():.3f} mailbox={m:#010x} slot={s:#010x}") last_m, last_s = m, s if m: for i in range(FIELDS): try: v = u32(rd, m + 0x20 * i) except Exception: # noqa: BLE001 break emit(f" +0x{0x20 * i:03x}: {v:#010x}") except Exception as exc: # noqa: BLE001 emit(f"{time.time():.3f} lost: {type(exc).__name__}: {exc}") try: rd.close() except Exception: # noqa: BLE001 pass rd = None time.sleep(0.2) if rd is not None: rd.close() log.close() return 0 if __name__ == "__main__": sys.exit(main(sys.argv))