#!/usr/bin/env python3 """Will the runtime bootloader interface accept a VALID component load after sOS is up? Established in pass 141: `_35` answers a bogus component id with status `0xa` while sOS is alive, so the bootloader mailbox is live at runtime, concurrently with sOS and the ring. The consequence depends on whether it will ACT. A component load reinitialises PSP firmware in place, so if accepted post-boot it overwrites live PSP memory while sOS is running. Least disruptive first: the payload is the EXACT bytes this boot already loaded for that component, so acceptance changes no content and only demonstrates that the path acts. Loading a *different* (older) signed build is a separate, explicit step, not done here. Deliberately NOT used: LOAD_IP_FW (known wedge with junk payloads) and the DRAM training ids (would retrain memory on a running system). argv[1]: sysdrv | kdb | socdrv """ import sys, time 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 P = psp.reg_pref def snap(tag): d = {r: adev.reg(f"{P}_{r}").read() for r in (33, 35, 36, 64, 81)} print(' %-8s _35=%#-12x _36=%#-10x _64=%#-12x _81=%#x' % (tag, d[35], d[36], d[64], d[81]), flush=True) return d # only components this boot actually loaded: SYS_DRV, SOS, TOC, KDB, SPL, RL CHOICES = { 'sysdrv': ('PSP_FW_TYPE_PSP_SYS_DRV', 'PSP_BL__LOAD_SYSDRV'), 'kdb': ('PSP_FW_TYPE_PSP_KDB', 'PSP_BL__LOAD_KEY_DATABASE'), 'spl': ('PSP_FW_TYPE_PSP_SPL', 'PSP_BL__LOAD_TOS_SPL_TABLE'), 'sos': ('PSP_FW_TYPE_PSP_SOS', 'PSP_BL__LOAD_SOSDRV'), } mode = sys.argv[1] if len(sys.argv) > 1 else 'sysdrv' fwname, cname = CHOICES[mode] if not hasattr(am, fwname): print(' fw type %s not present in headers -> void' % fwname); sys.exit(2) fwtype = getattr(am, fwname); compid = getattr(am, cname) if fwtype not in adev.fw.sos_fw: print(' this boot did not load %s -> void' % fwname); sys.exit(2) data = bytes(adev.fw.sos_fw[fwtype]) print('mode=%s compid=%#x payload=%d bytes (the build this boot loaded)' % (mode, compid, len(data)), flush=True) before = snap('before') if not (before[35] & 0x80000000): print(' BLREADY not set -> void'); sys.exit(2) size = (len(data) + 0xFFFFF) & ~0xFFFFF pa = adev.mm.palloc(max(0x100000, size), align=0x100000, zero=True, boot=False) adev.vram.view(pa, len(data))[:] = data adev.gmc.flush_hdp() mc = adev.paddr2mc(pa) adev.reg(f"{P}_36").write(mc >> 20) adev.reg(f"{P}_35").write(compid) t0 = time.time(); resp = None while time.time() - t0 < 15.0: v = adev.reg(f"{P}_35").read() if (v & 0x80000000) and v != compid and v != before[35]: resp = v; break time.sleep(0.05) after = snap('after') if resp is None and after[35] == before[35]: print(' VERDICT no response within 15s (ready bit unchanged)', flush=True) else: st = after[35] & 0xFFFF print(' VERDICT status=%#x -> %s' % (st, 'ACCEPTED - bootloader acted on a component load while sOS was running' if st == 0 else 'REJECTED with a status'), flush=True) print(' SOSALIVE_after=%s HB_advancing=%s' % (bool(psp.is_sos_alive()), after[81] != before[81]), flush=True)