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
|
"""Does the SMU clamp NumCmds to MAX_SW_I2C_COMMANDS (24)?
port=1 demonstrably reaches the I2C engine (transaction time scales with work,
vs port=0 which is rejected in ~0.3ms). If the firmware clamps NumCmds to 24,
elapsed time flattens at n=24. If it walks all NumCmds entries, time keeps
scaling past 24 -> the array walk is unbounded -> OOB read of SwI2cCmds[].
SAFETY: READ commands only (READWRITE bit clear) => nothing is written to any
I2C device. NumCmds kept <= 56 so any over-walk stays inside the 116-byte table
buffer that the SMU DMA'd from our own DRAM.
"""
import time, struct, statistics
from tinygrad import Device
import tinygrad.runtime.autogen.am.smu_13_0_0 as smu
d=Device["AMD"]; adev=d.iface.dev_impl
TP=adev.smu.driver_table_paddr; SIZE=116
MSG=adev.mmMP1_SMN_C2PMSG_66; ARG=adev.mmMP1_SMN_C2PMSG_82; RESP=adev.mmMP1_SMN_C2PMSG_90
N={0:'BUSY',1:'OK',0xFF:'FAILED',0xFE:'UNKNOWN',0xFD:'BAD_PREREQ',0xFC:'REJ_BUSY',0xFB:'REJ_PREREQ'}
def send(msg,param=0,tmo=5.0):
RESP.write(0); ARG.write(param&0xffffffff); MSG.write(msg)
t0=time.monotonic()
while time.monotonic()-t0<tmo:
r=RESP.read()
if r!=0: return N.get(r,hex(r)),(time.monotonic()-t0)*1000
return 'TIMEOUT',(time.monotonic()-t0)*1000
def wr(b):
v=adev.vram.view(TP,len(b),'I')
for i in range(len(b)//4): v[i]=struct.unpack_from('<I',b,4*i)[0]
STOP=smu.CMDCONFIG_STOP_MASK; RESTART=smu.CMDCONFIG_RESTART_MASK
def build(n, port=1, speed=2, slave=0x50):
b=bytearray(SIZE)
b[0]=port; b[1]=speed; b[2]=slave; b[3]=n&0xFF
for i in range(24):
b[4+2*i]=0x00; b[5+2*i]=0 # READ, no stop
b[5]|=RESTART
# deliberately DO NOT set STOP on the last in-bounds entry, so a firmware that
# keeps walking has to run off the end to find one.
for off in range(52,SIZE): b[off]=0xCC # 0xCC config => STOP|RESTART bits set
return bytes(b)
print("=== NumCmds vs elapsed time (port=1, READ cmds) ===")
print(" n resp median_ms samples")
res={}
for n in (1,2,4,8,16,24,28,32,40,48,56):
ts=[]; rr=None
for _ in range(7):
wr(build(n))
r,ms=send(smu.PPSMC_MSG_TransferTableDram2Smu,9)
rr=r; ts.append(ms)
res[n]=statistics.median(ts)
print(" %-5d %-10s %8.2f %s"%(n,rr,res[n]," ".join("%.1f"%x for x in sorted(ts))))
print()
base=res[24]
print("median(n=24) = %.2f ms"%base)
for n in (28,32,40,48,56):
print(" n=%-3d %.2f ms ratio vs n=24: %.2fx"%(n,res[n],res[n]/base if base else 0))
print()
print("MEMSIZE:",hex(adev.rreg(0xde3)))
|