aboutsummaryrefslogtreecommitdiffstats
path: root/hw/gfx13_probe.py
blob: 5acffa554c5994fd9b9939e53a22fca8c6047c0c (plain) (blame)
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
#!/usr/bin/env python3
"""GFX command 13: which fields does it consume, and can it be made to act?

Hardware shows cmd 13 returns 0x0 with a zeroed struct and 0xffff0006 when bytes 16..64 are
filled, so it is implemented and input-sensitive -- and it was never read
(GFX-HANDLER-COVERAGE.md lists 13 as "still unread").

Mutate one dword at a time across the command struct, recording which offsets change the
status, then try plausible {address,length} shapes at the offsets that matter.
"""
import ctypes, struct, sys, time
sys.path.insert(0,'/root/psp/hw')
from tinygrad import Device
import tinygrad.runtime.autogen.am.am as am
from ring_wrap import install
adev=Device["AMD"].iface.dev_impl; psp=adev.psp
submit=install(psp,adev)
def alloc(n):
    pa=adev.mm.palloc(n,align=0x1000,zero=True,boot=False); return pa,adev.paddr2mc(pa)
pa,mc=alloc(0x8000)
PAT=0xA5A5A5A5
adev.vram.view(pa,0x8000)[:]=bytes(struct.pack('<I',PAT)*(0x8000//4)); adev.gmc.flush_hdp()
def send(mut):
    c=am.struct_psp_gfx_cmd_resp(cmd_id=13)
    raw=memoryview(c).cast('B')
    for off,val in mut: struct.pack_into('<I', raw, off, val)
    t0=time.time()
    try: r=submit(c); st=r.resp.status&0xFFFFFFFF
    except Exception as e:
        try: st=int(str(e).strip().split()[-1])&0xFFFFFFFF
        except Exception: st=-1
    return st, time.time()-t0
base,_=send([])
print('baseline (zeroed) status %#x'%base, flush=True)
sens=[]
for off in range(16, 96, 4):
    s,dt=send([(off, 0xFFFFFFFF)])
    if s!=base: sens.append((hex(off), hex(s)))
    if dt>5: print('  STALL at off %#x'%off, flush=True); break
print('offsets whose value changes the status: %s'%(sens[:12] or 'none'), flush=True)
# try an {addr,len} shape at the first sensitive offset pair
if sens:
    o=int(sens[0][0],16)
    for val,tag in ((mc&0xFFFFFFFF,'our buffer lo'),(0x0,'zero'),(0xFFFFFFFF,'all ones')):
        s,dt=send([(o,val),(o+4,mc>>32),(o+8,0x1000)])
        print('  off %#x = %-16s -> %#-12x %.1fs'%(o,tag,s,dt), flush=True)
    adev.gmc.flush_hdp()
    out=bytes(adev.vram.view(pa,0x8000)[:])
    ch=[x for x in range(0,0x8000,4) if struct.unpack_from('<I',out,x)[0]!=PAT]
    print('  our buffer dwords changed by cmd 13: %d'%len(ch), flush=True)