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
|
"""Route B liveness: the TSU flash/update mailbox (MP0 C2PMSG 115/116).
Verified statically:
tsu_mailbox_task (0xE1CA98): ORs 0x3C0 into the host-permission word (opens 115/116
to the host), registers object 89, sets mbx115 bit31 = ready, then
loops on SVC 0x5A waiting for a doorbell -> tsu_mailbox_dispatch.
tsu_mailbox_dispatch (0xE1C948): command byte = BYTE2 of mbx115; submit = bit31 CLEAR;
replies *mbx115 = (uint16)status | 0x80000000; data/arg in mbx116.
Unknown command -> status 0xFFFF000A (low16 = 0x000A).
Only READ-ONLY commands are used here:
0x01 -> returns platform_state[2132]+1 in mbx116
0x0B -> flash_info_get() in mbx116
Commands 0x02/0x03 (set flash context) and 0x04 (parse/update) are NOT sent.
Stage 1 submits without ringing the shared doorbell (mbx73), which would wake ~5 tasks.
Stage 2 (--doorbell) adds the doorbell only if stage 1 gets no reply.
"""
import sys, time, struct
from tinygrad import Device
USE_DOORBELL = "--doorbell" in sys.argv
d = Device["AMD"]; adev = d.iface.dev_impl
base = adev.reg("regMP0_SMN_C2PMSG_73").addr[0]
def mb(n): return adev.rreg(base + (n - 73))
def mbw(n, v): adev.wreg(base + (n - 73), v)
def bs(v): return struct.unpack('<I', struct.pack('>I', v))[0]
def alive(): return adev.reg("regMP0_SMN_C2PMSG_81").read() != 0
# guard: only trust mailboxes whose writes actually land
def writable(n):
o = mb(n); pat = 0x9234567A
mbw(n, pat); ok = (mb(n) == pat); mbw(n, o)
return ok
print("sOS alive:", alive())
for n in (115, 116, 73):
print(" mbx%-4d writable=%-5s value=%#010x" % (n, writable(n), mb(n)))
def submit(cmd, arg=0, timeout=1.0, doorbell=False):
mbw(116, arg)
mbw(115, (cmd & 0xFF) << 16) # BYTE2 = command, bit31 clear = submit
if doorbell: mbw(73, 1)
t0 = time.time()
while time.time() - t0 < timeout:
v = mb(115)
if v & 0x80000000:
return v, mb(116), time.time() - t0
time.sleep(0.001)
return None, mb(116), time.time() - t0
print("\n=== Route B probe (doorbell=%s) ===" % USE_DOORBELL)
print("cmd reply status data(mbx116) dt alive")
TESTS = [(0x7F, "unknown -> expect 0x8000000A"),
(0x01, "read-only status byte"),
(0x0B, "flash_info_get"),
(0x7E, "unknown control #2")]
for cmd, label in TESTS:
if not alive():
print(" !! sOS dead -- stopping"); break
v, data, dt = submit(cmd, doorbell=USE_DOORBELL)
if v is None:
print(" 0x%02X TIMEOUT %#010x %.3fs %s (%s)"
% (cmd, data, dt, alive(), label))
else:
print(" 0x%02X %#010x %#06x %#010x %.3fs %s (%s)"
% (cmd, v, v & 0xFFFF, data, dt, alive(), label))
print("\nsOS alive at end:", alive())
print("final mbx115=%#010x mbx116=%#010x" % (mb(115), mb(116)))
|