1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
|
#!/usr/bin/env python3
"""Confirm the PSP is really RUNNING the substituted (older) SYS_DRV, not silently falling back.
`rollback_boot.py` showed driver init completes and sOS is alive with an older signed SYS_DRV
injected. That is necessary but not sufficient: it shows the bootloader did not refuse, and
not that the older code is what is executing. If the PSP silently kept a resident copy, or if
the load were skipped, the observable state would look the same.
So dump the PSP mailbox registers after boot for each injected build and DIFF them. A version
register that tracks the injected build is direct evidence the substituted component is what
booted. Registers are dumped wholesale rather than assuming which one carries the version.
argv[1]: 'identity' | path to a sos bin
argv[2]: optional label for the output
"""
import ctypes, hashlib, sys
sys.path.insert(0, '/root/psp/hw')
import tinygrad.runtime.support.am.amdev as amdev
import tinygrad.runtime.autogen.am.am as am
def extract_sysdrv(path):
blob = open(path, 'rb').read()
hdr = am.struct_psp_firmware_header_v2_0.from_buffer_copy(blob)
d = am.struct_psp_fw_bin_desc.from_address(ctypes.addressof(hdr.psp_fw_bin))
if d.fw_type != am.PSP_FW_TYPE_PSP_SYS_DRV:
raise RuntimeError('first descriptor not SYS_DRV')
start = d.offset_bytes + hdr.header.ucode_array_offset_bytes
return blob[start:start + d.size_bytes], d.fw_version
target = sys.argv[1]
label = sys.argv[2] if len(sys.argv) > 2 else target.split('/')[-1]
sub = None; subver = 0
if target != 'identity':
sub, subver = extract_sysdrv(target)
assert sub[16:20] == b'$PS1', 'container magic wrong'
orig = amdev.AMFirmware.__init__
def patched(self, adev):
orig(self, adev)
running = bytes(self.sos_fw[am.PSP_FW_TYPE_PSP_SYS_DRV])
newb = running if sub is None else sub
self.sos_fw[am.PSP_FW_TYPE_PSP_SYS_DRV] = memoryview(bytearray(newb))
print('INJECT %s ver=%#x len=%d sha=%s'
% (label, subver, len(newb), hashlib.sha256(newb).hexdigest()[:16]), flush=True)
amdev.AMFirmware.__init__ = patched
from tinygrad import Device
adev = Device["AMD"].iface.dev_impl
P = adev.psp.reg_pref
print('ALIVE %s' % bool(adev.psp.is_sos_alive()), flush=True)
vals = {}
for r in list(range(32, 40)) + list(range(56, 70)) + [81, 92, 115]:
try: vals[r] = adev.reg(f"{P}_{r}").read()
except Exception: pass
print('REGS ' + ' '.join('%d=%#x' % (r, v) for r, v in sorted(vals.items())), flush=True)
# TA invocation is serviced BY SYS_DRV, so a working TA proves SYS_DRV is live -- which, from
# a cold start with only the injected bytes supplied, means the injected build is live.
import glob
try:
psp = adev.psp
blob = open(glob.glob('/root/psp/contall/ta_42-0-0-6_1c874c3c*')[0], 'rb').read()
def alloc(n):
pa = adev.mm.palloc(n, align=0x1000, zero=True, boot=False)
return pa, adev.paddr2mc(pa)
ap_, amc = alloc(0x80000); cp, cmc = alloc(0x8000)
nn = (len(blob) + 3) & ~3
adev.vram.view(ap_, nn)[:] = blob + b'\x00' * (nn - 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 = amc & 0xFFFFFFFF, amc >> 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 = 0x4000
r = psp._ring_submit(c)
st = r.resp.status & 0xFFFFFFFF; sid = r.resp.session_id
print('TALOAD status=%#x sid=%s' % (st, sid), flush=True)
if st == 0:
iv = am.struct_psp_gfx_cmd_resp(cmd_id=am.GFX_CMD_ID_INVOKE_CMD)
iv.cmd.cmd_invoke_cmd.session_id = sid; iv.cmd.cmd_invoke_cmd.ta_cmd_id = 1
r2 = psp._ring_submit(iv)
print('TAINVOKE status=%#x SYSDRV_SERVICING=True' % (r2.resp.status & 0xFFFFFFFF), flush=True)
except Exception as e:
print('TACHECK ERR %s %s' % (type(e).__name__, str(e)[:120]), flush=True)
|