aboutsummaryrefslogtreecommitdiffstats
path: root/psp_out/test_range_polarity.py
blob: cff1d44e330df7c098ffeb9b3147e2e3141cbca7 (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
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
"""DECISIVE: is the RAS TRIGGER_ERROR range check inverted?

dram_range_query returns:
   0xFFFF0001  address IS inside a valid DRAM range
   0           address is NOT in any range  (also: not-initialised / recovery)
   0xFFFF0006  address has bits above bit 43
and ras_dram_range_config does `CBZ R0 -> proceed`, i.e. proceeds on 0.

If that is the real polarity, then:
   VALID   in-range address -> rejected with 40986
   INVALID out-of-range     -> ACCEPTED, proceeds to program the UMC inject regs
which is exactly backwards. Test with addresses whose validity we know.
"""
import ctypes,struct,collections
from tinygrad import Device
from tinygrad.runtime.autogen.am import am
from tinygrad.helpers import lo32,hi32
d=Device["AMD"]; adev=d.iface.dev_impl; psp=adev.psp
SZ=ctypes.sizeof(am.struct_psp_gfx_cmd_resp); P='/Users/user/dev/amd-psp-re/psp_out/'; S=0x8000
def stat(): return int.from_bytes(bytes(adev.vram.view(psp.cmd_paddr,SZ)[:])[864:868],"little")
def alloc(n):
    pa=adev.mm.palloc(n,align=0x1000,zero=True); return pa,adev.paddr2mc(pa)
def load(cmd,blob):
    ap,amc=alloc(0x40000); cp,cmc=alloc(S)
    adev.vram.view(ap,len(blob))[:]=blob; adev.gmc.flush_hdp()
    adev.vram.view(psp.cmd_paddr,SZ)[:]=b"\x00"*SZ
    c=am.struct_psp_gfx_cmd_resp(cmd_id=cmd); t=c.cmd.cmd_load_ta
    t.app_phy_addr_hi,t.app_phy_addr_lo=hi32(amc),lo32(amc); t.app_len=len(blob)
    t.cmd_buf_phy_addr_hi,t.cmd_buf_phy_addr_lo=hi32(cmc),lo32(cmc); t.cmd_buf_len=S
    return psp._ring_submit(c).resp.session_id, cp
def inv(sid,shm,buf,tc):
    adev.vram.view(shm,S)[:]=bytes(buf); adev.gmc.flush_hdp()
    adev.vram.view(psp.cmd_paddr,SZ)[:]=b"\x00"*SZ
    ic=am.struct_psp_gfx_cmd_resp(cmd_id=am.GFX_CMD_ID_INVOKE_CMD); iv=ic.cmd.cmd_invoke_cmd
    iv.session_id,iv.ta_cmd_id=sid,tc
    try: psp._ring_submit(ic); ps=0
    except RuntimeError: ps=stat()
    except TimeoutError: return "TIMEOUT",None
    return ps, bytes(adev.vram.view(shm,S)[:])
ras,rsh=load(am.GFX_CMD_ID_LOAD_TA, open(P+'ras_full.bin','rb').read())
# a definitely-valid VRAM address we own
mypa,mymc=alloc(0x10000)
print("RAS sid=%s   our VRAM buffer: pa=%#x mc=%#x   MEMSIZE=%s"%(ras,mypa,mymc,hex(adev.rreg(0xde3))))
def trigger(addr, blk=2, v5=0):
    b=bytearray(S); base=0x10
    struct.pack_into('<I',b,0,2)                      # cmd 2 TRIGGER ERROR
    struct.pack_into('<I',b,base+0,0)                 # request type must be 0
    struct.pack_into('<I',b,base+4, blk)              # v4 block type (2 or 4)
    struct.pack_into('<I',b,base+8, 0)
    struct.pack_into('<I',b,base+16, addr & 0xffffffff)   # injection address lo
    struct.pack_into('<I',b,base+20, (addr>>32) & 0xffffffff)
    struct.pack_into('<I',b,base+24, v5)
    struct.pack_into('<I',b,base+28, 0)
    ps,o=inv(ras,rsh,b,2)
    return None if o is None else struct.unpack_from('<I',o,8)[0]
NAMES={40986:'40986 REJECTED (0xA01A, range-query non-zero)',
       40962:'40962 (0xA002 bad block/param)',40977:'40977 (0xA011 reg-access layer REACHED)',0:'0 OK'}
def show(label, addr, **kw):
    r=trigger(addr, **kw)
    print("  %-46s addr=%#014x -> %s"%(label,addr,NAMES.get(r,str(r))))
print("\n=== addresses that ARE valid DRAM (ours / low VRAM) ===")
for lbl,a in (("our allocated VRAM buffer (mc)",mymc),
              ("our allocated VRAM buffer (pa)",mypa),
              ("low VRAM 0x9a000",0x9a000),
              ("VRAM 0x1600000",0x1600000)):
    for v5 in (0,4):
        show(lbl+" v5=%d"%v5, a, v5=v5)
print("\n=== addresses that are NOT valid DRAM ===")
for lbl,a in (("zero",0),("tiny 0x40",0x40),("0xdead000",0xdead000),
              ("huge but <2^44 0xFFFFFFFF000",0xFFFFFFFF000),
              ("above bit43 (should be 0xFFFF0006)",0x1FFFFFFFF000)):
    for v5 in (0,4):
        show(lbl+" v5=%d"%v5, a, v5=v5)
print("\nMEMSIZE=%s sos_alive=%s"%(hex(adev.rreg(0xde3)),psp.is_sos_alive()))