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
|
"""Can the HOST invoke ASD directly, choosing the command id?
DISTINCT-WRITE-HUNT.md excluded ASD cmd 0x301 (sub_D132A8 — a clean
content-controlled write of up to 5120 bytes) purely on reachability: no TA
forwarder builds 0x301. Census across all 10 HDCP builds + DTM + RAS confirms
that, so rollback does not open it.
But that argument only covers TA->ASD cross-process RPC. ASD is loaded through
the ordinary TA path (`tee_cmd_dispatch` routes case 1 and case 4 both to
`tee_load_ta`), its header entry is a trampoline
`MOV R0,R2 ; BLX asd_rpc_dispatch ; SVC 0x75`, and asd_rpc_dispatch takes its
opcode from frame[0]. Existing probes call LOAD_ASD but DISCARD the returned
session_id and only ever invoke HDCP.
This probe keeps ASD's session_id and invokes ASD directly, sweeping ta_cmd_id.
Reference points from the dispatcher's own opcode map:
0x100-0x10D topology/session 0x160-0x161 link 0x180-0x1BF HDCP1.x
0x1A0-0x1AA HDCP2.2 0x200-0x20E service 0x300-0x309 SRM/revocation
Known-forwarded (so should behave): 0x300 0x302 0x303 0x307 0x308
Target (never forwarded): 0x301
Controls: 0x999 (no such opcode), 0x200 (service)
"""
import ctypes, struct, time
from tinygrad import Device
from tinygrad.runtime.autogen.am import am
from tinygrad.helpers import lo32, hi32
d = Device["AMD"]; adev = d.iface.dev_impl; psp = adev.psp
SZ = ctypes.sizeof(am.struct_psp_gfx_cmd_resp)
P = '/Users/user/dev/amd-psp-re/psp_out/'
def stat(): return int.from_bytes(bytes(adev.vram.view(psp.cmd_paddr, SZ)[:])[864:868], "little")
def alloc(n):
pa = adev.mm.palloc(n, align=0x1000, zero=True); return pa, adev.paddr2mc(pa)
def load(cmd, blob):
ap, amc = alloc(0x40000); cp, cmc = alloc(0x8000)
adev.vram.view(ap, len(blob))[:] = blob; adev.gmc.flush_hdp()
adev.vram.view(psp.cmd_paddr, SZ)[:] = b"\x00" * SZ
c = am.struct_psp_gfx_cmd_resp(cmd_id=cmd); t = c.cmd.cmd_load_ta
t.app_phy_addr_hi, t.app_phy_addr_lo = hi32(amc), lo32(amc); t.app_len = len(blob)
t.cmd_buf_phy_addr_hi, t.cmd_buf_phy_addr_lo = hi32(cmc), lo32(cmc); t.cmd_buf_len = 0x8000
r = psp._ring_submit(c)
return r.resp.session_id, cp
asd_sid, asd_shm = load(am.GFX_CMD_ID_LOAD_ASD, open(P + 'asd_full.bin', 'rb').read())
print("ASD loaded: session_id=%#x shm=%#x" % (asd_sid, asd_shm))
if asd_sid == 0:
print("!! LOAD_ASD returned session_id 0 -- ASD may not be invokable this way")
def invoke_asd(tc, payload=None):
b = bytearray(0x8000)
if payload: b[:len(payload)] = payload
adev.vram.view(asd_shm, 0x8000)[:] = bytes(b); adev.gmc.flush_hdp()
adev.vram.view(psp.cmd_paddr, SZ)[:] = b"\x00" * SZ
ic = am.struct_psp_gfx_cmd_resp(cmd_id=am.GFX_CMD_ID_INVOKE_CMD)
iv = ic.cmd.cmd_invoke_cmd
iv.session_id, iv.ta_cmd_id = asd_sid, tc
t0 = time.time()
try:
psp._ring_submit(ic); ps = 0
except RuntimeError:
ps = stat()
except TimeoutError:
return "TIMEOUT", None, time.time() - t0
out = bytes(adev.vram.view(asd_shm, 0x40)[:])
return ps, out, time.time() - t0
print("\n%-28s %-12s %-12s %s" % ("ta_cmd_id", "psp_status", "shm[0:4]", "dt"))
for tc, note in ((0x300, "SRM read (forwarded)"), (0x301, "*** TARGET ***"),
(0x302, "SRM query (forwarded)"), (0x303, "SRM check (fwd)"),
(0x200, "service/log"), (0x999, "bogus control")):
ps, out, dt = invoke_asd(tc)
first = out[:4].hex() if out else "-"
pss = ps if isinstance(ps, str) else hex(ps)
print(" %#06x %-20s %-12s %-12s %.3fs" % (tc, note, pss, first, dt))
|