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
81
82
83
84
85
86
87
88
|
#!/usr/bin/env python3
"""Sweep index space and diff the VCN MMIO window after each batch.
First attempt used indices 0x100..0x13E and nothing in MMIO 0x7800..0x7F00 held
the magic. Either the mapping is not base+index into that window, or the writes
land in the DPG shadow register file rather than the MMIO-visible set.
Cover the low index space densely (0..503, 8 calls x 63 entries) and also probe
a wider MMIO window, so a mapping offset cannot hide the effect.
"""
import struct, time
from tinygrad import Device
import tinygrad.runtime.autogen.am.am as am
OUT = "/tmp/vcnsweep.txt"
MAGIC = 0xA5A50000
def say(s):
with open(OUT, "a") as f:
f.write(s + "\n")
print(s, flush=True)
adev = Device["AMD"].iface.dev_impl
psp = adev.psp
hb = adev.reg("regMP0_SMN_C2PMSG_81")
def alive():
a = hb.read(); time.sleep(0.25); return hb.read() != a
BASE, END = 0x7000, 0x8200 # wider than the VCN bases 0x7800 / 0x7E00
def snap():
o = {}
for r in range(BASE, END):
try:
o[r] = adev.rreg(r)
except Exception:
pass
return o
def submit(payload):
psp._prep_msg1(memoryview(bytes(payload)))
c = am.struct_psp_gfx_cmd_resp(cmd_id=am.GFX_CMD_ID_LOAD_IP_FW)
c.cmd.cmd_load_ip_fw.fw_phy_addr_lo = psp.msg1_addr & 0xFFFFFFFF
c.cmd.cmd_load_ip_fw.fw_phy_addr_hi = psp.msg1_addr >> 32
c.cmd.cmd_load_ip_fw.fw_size = len(payload)
c.cmd.cmd_load_ip_fw.fw_type = 49
try:
return psp._ring_submit(c).resp.status & 0xFFFFFFFF
except RuntimeError as e:
return int(str(e).rsplit(" ", 1)[-1]) & 0xFFFFFFFF
def ent(i, v):
return struct.pack("<II", i, v)
say("\n######## dense index sweep + wide diff ########")
say("MMIO window %#x..%#x" % (BASE, END))
before = snap()
say("snapshot: %d regs, %d non-trivial" % (len(before), sum(1 for v in before.values() if v not in (0, 0xFFFFFFFF))))
ok = 0
for batch in range(8):
lo = batch * 63
tbl = ent(195, 0) + b"".join(ent(lo + i, MAGIC | (lo + i)) for i in range(63))
st = submit(tbl)
ok += (st == 0)
say(" batch %d indices %3d..%3d -> status %#010x" % (batch, lo, lo + 62, st))
if not alive():
say(" !! heartbeat stopped"); break
after = snap()
d = {k: (before.get(k), after.get(k)) for k in after if before.get(k) != after.get(k)}
hits = {k: b for k, (a, b) in d.items() if b is not None and (b & 0xFFFF0000) == MAGIC}
say("\naccepted batches: %d/8" % ok)
say("regs changed: %d ; holding magic: %d" % (len(d), len(hits)))
for k, v in list(hits.items())[:16]:
say(" MMIO dword %#06x = %#010x <= index %d" % (k, v, v & 0xFFFF))
if not hits:
say(" changed (first 10): %s" % [(hex(k), hex(a or 0), hex(b or 0)) for k, (a, b) in list(d.items())[:10]])
say("\npsp alive %s / smu alive %s" % (alive(), adev.smu.is_smu_alive()))
|