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
|
#!/usr/bin/env python3
"""Does the DF FabricIndirectConfigAccess port work from the host? READ ONLY.
NV22 map:
DF.FabricConfigAccessControl SMN 0x1D040
DF.FabricIndirectConfigAccessAddress SMN 0x1D050
DF.FabricIndirectConfigAccessDataLo SMN 0x1D080
DF.FabricIndirectConfigAccessDataHi SMN 0x1D084
This is an index/data port into the Data Fabric's CONFIG space, which is where
address-map routing (DramBase/DramLimit style) lives. If it is host-readable we
can enumerate how the fabric routes physical addresses -- including, possibly,
how the PSP's TMR carve-out is expressed.
Nothing here writes a DF config register. The only writes are to the ADDRESS
half of the port, which is how a read is performed -- the same pattern the
driver uses for SMN itself.
Safety: the four registers are checked for decode FIRST. If the port does not
decode, nothing else is attempted.
"""
import struct, time
from tinygrad import Device
adev = Device["AMD"].iface.dev_impl
idx = adev.reg("regBIF_BX0_PCIE_INDEX2")
dat = adev.reg("regBIF_BX0_PCIE_DATA2")
hb = adev.reg("regMP0_SMN_C2PMSG_81")
def alive():
a = hb.read(); time.sleep(0.2); return hb.read() != a
def bswap(x):
return struct.unpack("<I", struct.pack(">I", x & 0xFFFFFFFF))[0]
def rd(a):
idx.write(a & 0xFFFFFFFF)
return dat.read()
def wr(a, v):
idx.write(a & 0xFFFFFFFF)
dat.write(v & 0xFFFFFFFF)
def cls(a):
v = rd(a)
return v, ("MIRROR" if v == bswap(a) else "all-ones" if v == 0xFFFFFFFF else "DECODED")
CTL, ADDR, DLO, DHI = 0x1D040, 0x1D050, 0x1D080, 0x1D084
print("control C2PMSG_58 = %#x (expect 0x310036)" % rd(0x581E8))
print("psp alive: %s\n" % alive())
print("%-38s %-12s %s" % ("register", "value", "verdict"))
ok = True
for a, nm in ((CTL, "DF.FabricConfigAccessControl"),
(ADDR, "DF.FabricIndirectConfigAccessAddress"),
(DLO, "DF.FabricIndirectConfigAccessDataLo"),
(DHI, "DF.FabricIndirectConfigAccessDataHi")):
v, k = cls(a)
ok &= (k == "DECODED")
print(" %-36s %#010x %s" % (nm, v, k))
if not ok:
print("\nport does not decode -- stopping, nothing further attempted")
raise SystemExit(0)
print("\nport decodes. Reading DF config space through it (address-half writes only).")
# DF config: instance/function/offset packing varies; sweep a small offset range
# on instance 0 and look for non-trivial, non-repeating data.
seen = {}
for off in range(0, 0x100, 4):
wr(ADDR, off)
lo = rd(DLO)
seen[off] = lo
print(" read %d offsets; distinct values: %d" % (len(seen), len(set(seen.values()))))
for off in sorted(seen)[:16]:
print(" cfg offset %#05x = %#010x" % (off, seen[off]))
print("\npsp alive: %s" % alive())
|