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
|
#!/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)
|