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
|
"""Locate the host-side mirror of PSP MMIO 0x03010000 via the crash-dump magic.
The PSP fatal handler writes:
MEMORY[0x3010A48] = 0
MEMORY[0x3010A4C] = (exc_class << 28) | (x << 24) | 0xE504FF <-- magic
MEMORY[0x3010A50] = faulting LR
MEMORY[0x3010A54] = DFSR/IFSR
MEMORY[0x3010A58] = DFAR/IFAR
Plan: snapshot all of BAR5, deliberately crash the PSP, snapshot again,
then hunt for a dword whose low 24 bits are 0xE504FF.
"""
import ctypes, struct, time, array
from tinygrad import Device
from tinygrad.runtime.autogen.am import am
d = Device["AMD"]; adev = d.iface.dev_impl; psp = adev.psp
SZ = ctypes.sizeof(am.struct_psp_gfx_cmd_resp)
NDW = len(adev.mmio)
CHUNK = 0x4000
def scan():
out = array.array('I')
for base in range(0, NDW, CHUNK):
n = min(CHUNK, NDW - base)
out.extend(array.array('I', bytes(adev.mmio[base:base+n])[:n*4]))
return out
print(f"sOS alive: {psp.is_sos_alive()} scanning {NDW} dwords ({NDW*4/1e6:.2f} MB)")
t0 = time.perf_counter(); before = scan()
print(f" baseline scan: {time.perf_counter()-t0:.2f}s, {len(before)} dwords")
MAGIC = 0xE504FF
pre_hits = [i for i, v in enumerate(before) if (v & 0xFFFFFF) == MAGIC]
print(f" magic {MAGIC:#08x} present BEFORE crash: {len(pre_hits)} {[hex(x) for x in pre_hits[:5]]}")
print("\n>>> crashing the PSP (LOAD_IP_FW fw_size=0x100, addr=0) ...")
adev.vram.view(psp.cmd_paddr, SZ)[:] = b"\x00" * SZ
c = am.struct_psp_gfx_cmd_resp(cmd_id=am.GFX_CMD_ID_LOAD_IP_FW)
c.cmd.cmd_load_ip_fw.fw_size = 0x100
c.cmd.cmd_load_ip_fw.fw_type = 0
try:
psp._ring_submit(c); print(" (unexpectedly returned)")
except Exception as e:
print(f" {type(e).__name__}: {str(e)[:70]}")
time.sleep(1.0)
t0 = time.perf_counter(); after = scan()
print(f" post-crash scan: {time.perf_counter()-t0:.2f}s")
hits = [i for i, v in enumerate(after) if (v & 0xFFFFFF) == MAGIC]
print(f"\n=== dwords with low-24 == {MAGIC:#08x} AFTER crash: {len(hits)} ===")
for i in hits:
print(f" dword {i:#08x} (byte {i*4:#08x}) = {after[i]:#010x} exc_class={(after[i]>>28)&0xF}")
base_dw = i - (0xA4C // 4)
print(f" => PSP 0x03010000 maps to BAR5 dword {base_dw:#08x} (byte {base_dw*4:#08x})")
print(f" neighbourhood (PSP 0x3010A48..0x3010A60):")
for off in (0xA48, 0xA4C, 0xA50, 0xA54, 0xA58, 0xA5C, 0xA60):
j = base_dw + off//4
if 0 <= j < len(after):
print(f" 0x{0x3010000+off:08x} -> dw {j:#08x} before={before[j]:#010x} after={after[j]:#010x}")
diff = [(i, before[i], after[i]) for i in range(len(before)) if before[i] != after[i]]
print(f"\n=== total dwords changed by the crash: {len(diff)} ===")
for i, b, a in diff[:40]:
print(f" dw {i:#08x} (byte {i*4:#08x}) {b:#010x} -> {a:#010x}")
if len(diff) > 40: print(f" ... and {len(diff)-40} more")
|