Skip to content

Commit 80df459

Browse files
WhatAmISupposedToPutHerejannau
authored andcommitted
proxyclient: Add PMP experiments
Signed-off-by: Sasha Finkelstein <[email protected]>
1 parent 1c6309d commit 80df459

3 files changed

Lines changed: 489 additions & 0 deletions

File tree

Lines changed: 276 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,276 @@
1+
#!/usr/bin/env python3
2+
# SPDX-License-Identifier: MIT
3+
import sys, pathlib
4+
sys.path.append(str(pathlib.Path(__file__).resolve().parents[1]))
5+
6+
import struct
7+
from construct import *
8+
from copy import deepcopy
9+
from m1n1.setup import *
10+
from m1n1.shell import run_shell
11+
from m1n1.fw.asc import StandardASC
12+
from m1n1.fw.asc.base import ASCBaseEndpoint, msg_handler
13+
from m1n1.utils import *
14+
from m1n1.hw.dart import DART
15+
16+
def round_up(x, y): return ((x + (y - 1)) & (-y))
17+
def round_down(x, y): return (x - (x % y))
18+
19+
AOPBootargsItem = Struct(
20+
"key" / PaddedString(4, "utf8"),
21+
"size" / Int32ul,
22+
)
23+
24+
class AOPBootargs:
25+
def __init__(self, bytes_):
26+
self.blob = bytearray(bytes_)
27+
self.index = self.build_index(self.blob)
28+
29+
def build_index(self, blob):
30+
off = 0
31+
fields = []
32+
while off < len(blob):
33+
item = AOPBootargsItem.parse(blob[off:off+AOPBootargsItem.sizeof()])
34+
off += AOPBootargsItem.sizeof()
35+
fields.append((item.key, (off, item.size)))
36+
off += item.size
37+
if off > len(blob):
38+
raise ValueError('blob overran during parsing')
39+
return dict(fields)
40+
41+
def items(self):
42+
for key, span in self.index.items():
43+
off, length = span
44+
yield key, self.blob[off:off + length]
45+
46+
def __getitem__(self, key):
47+
off, length = self.index[key]
48+
return bytes(self.blob[off:off + length])
49+
50+
def __setitem__(self, key, value):
51+
off, length = self.index[key]
52+
if type(value) is int:
53+
value = int.to_bytes(value, length, byteorder='little')
54+
elif type(value) is str:
55+
value = value.encode('ascii')
56+
if len(value) > length:
57+
raise ValueError(f'field {key:s} overflown')
58+
self.blob[off:off + length] = value
59+
60+
def update(self, keyvals):
61+
for key, val in keyvals.items():
62+
self[key] = val
63+
64+
def keys(self):
65+
return self.index.keys()
66+
67+
def dump(self, logger):
68+
for key, val in self.items():
69+
logger(f"{key:4s} = {val}")
70+
71+
def dump_diff(self, other, logger):
72+
assert self.index == other.index
73+
for key in self.keys():
74+
if self[key] != other[key]:
75+
logger(f"\t{key:4s} = {self[key]} -> {other[key]}")
76+
77+
def to_bytes(self):
78+
return bytes(self.blob)
79+
80+
class AOPBase:
81+
def __init__(self, u):
82+
self.u = u
83+
self.nub_base = u.adt["/arm-io/pmp/iop-pmp-nub"].region_base
84+
85+
@property
86+
def _bootargs_span(self):
87+
"""
88+
[cpu1] MMIO: R.4 0x24ac0022c (aop[2], offset 0x22c) = 0xaffd8 // offset
89+
[cpu1] MMIO: R.4 0x24ac00230 (aop[2], offset 0x230) = 0x2ae // size
90+
[cpu1] MMIO: R.4 0x24ac00234 (aop[2], offset 0x234) = 0x82000 // va? low
91+
[cpu1] MMIO: R.4 0x24ac00238 (aop[2], offset 0x238) = 0x0 // va? high
92+
[cpu1] MMIO: R.4 0x24ac0023c (aop[2], offset 0x23c) = 0x4ac82000 // phys low
93+
[cpu1] MMIO: R.4 0x24ac00240 (aop[2], offset 0x240) = 0x2 // phys high
94+
[cpu1] MMIO: W.4 0x24acaffd8 (aop[2], offset 0xaffd8) = 0x53544b47 // start of bootargs
95+
[cpu1] MMIO: W.4 0x24acaffdc (aop[2], offset 0xaffdc) = 0x8
96+
[cpu1] MMIO: W.4 0x24acaffe0 (aop[2], offset 0xaffe0) = 0x73eed2a3
97+
...
98+
[cpu1] MMIO: W.4 0x24acb0280 (aop[2], offset 0xb0280) = 0x10000
99+
[cpu1] MMIO: W.4 0x24acb0284 (aop[2], offset 0xb0284) = 0x0 // end of bootargs
100+
"""
101+
offset = self.u.proxy.read32(self.nub_base + 0x22c) # 0x224 in 12.3
102+
size = self.u.proxy.read32(self.nub_base + 0x230) # 0x228 in 12.3
103+
return (self.nub_base + offset, size)
104+
105+
def read_bootargs(self):
106+
addr, size = self._bootargs_span
107+
blob = self.u.proxy.iface.readmem(addr, size)
108+
return AOPBootargs(blob)
109+
110+
def write_bootargs(self, args):
111+
base, _ = self._bootargs_span
112+
self.u.proxy.iface.writemem(base, args.to_bytes())
113+
114+
def update_bootargs(self, keyval, logger=print):
115+
args = self.read_bootargs()
116+
old = deepcopy(args)
117+
args.update(keyval)
118+
self.write_bootargs(args)
119+
old.dump_diff(args, logger)
120+
121+
class PMPMessage(Register64):
122+
TYPE = 56, 48
123+
124+
class PMPMessage_IOVATableAck(PMPMessage):
125+
TYPE = 56, 48, Constant(0x11)
126+
IOVA = 47, 0
127+
128+
class PMPMessage_Malloc(PMPMessage):
129+
TYPE = 56, 48, Constant(0x12)
130+
SIZE = 23, 0
131+
132+
class PMPMessage_MallocAck(PMPMessage):
133+
TYPE = 56, 48, Constant(0x13)
134+
IOVA = 47, 0
135+
136+
class PMPMessage_Free(PMPMessage):
137+
TYPE = 56, 48, Constant(0x14)
138+
IOVA = 47, 0
139+
140+
class PMPMessage_SetBuf(PMPMessage):
141+
TYPE = 56, 48, Constant(0x30)
142+
IOVA = 47, 0
143+
144+
class PMPMessage_Advertise(PMPMessage):
145+
TYPE = 56, 48, Constant(0x32)
146+
IOVA = 47, 0
147+
148+
class PMPMessage_AdvertiseAck(PMPMessage):
149+
TYPE = 56, 48, Constant(0x33)
150+
INDEX = 47, 32
151+
SIZE = 31, 0
152+
153+
class PMPMessage_SetVal(PMPMessage):
154+
TYPE = 56, 48, Constant(0x34)
155+
INDEX = 15, 0
156+
157+
class PMPMessage_SetValAck(PMPMessage):
158+
TYPE = 56, 48, Constant(0x35)
159+
SIZE = 31, 0
160+
161+
class PMPEp(ASCBaseEndpoint):
162+
BASE_MESSAGE = PMPMessage
163+
SHORT = "pmp"
164+
def __init__(self, *args, **kwargs):
165+
super().__init__(*args, **kwargs)
166+
self.allocs = {}
167+
self.ioregs = []
168+
169+
@msg_handler(0x10, PMPMessage)
170+
def GetIOVATable(self, msg):
171+
self.log(f'IovaTable: {msg}')
172+
table, table_dva = self.asc.ioalloc(512)
173+
self.asc.iowrite(table_dva, b'\0' * 512)
174+
pio_base = u.adt["/arm-io/dart-pmp"].pio_vm_base
175+
granularity = u.adt["/arm-io/dart-pmp"].pio_granularity
176+
i = 0
177+
for j in range(4, len(u.adt["/arm-io/pmp"].reg)):
178+
host_addr, size = u.adt["/arm-io/pmp"].get_reg(j)
179+
self.asc.dart.iomap_at(0, pio_base, host_addr, size)
180+
self.asc.dart.invalidate_streams(1)
181+
self.asc.iowrite(table_dva + 24 * i, struct.pack("<QQQ", host_addr, pio_base, size))
182+
pio_base += granularity
183+
i += 1
184+
self.send(PMPMessage_IOVATableAck(IOVA=table_dva))
185+
@msg_handler(0x12, PMPMessage_Malloc)
186+
def Malloc(self, msg):
187+
self.log(f'Malloc: {msg}')
188+
addr, dva = self.asc.ioalloc(msg.SIZE)
189+
self.allocs[dva] = addr
190+
self.send(PMPMessage_MallocAck(IOVA=dva))
191+
@msg_handler(0x14, PMPMessage_Free)
192+
def Free(self, msg):
193+
self.log(f'Free: {msg}')
194+
#i dont think we can
195+
self.send(PMPMessage(TYPE=0x15))
196+
197+
@msg_handler(0x30, PMPMessage_SetBuf)
198+
def SetBuf(self, msg):
199+
self.log(f'SetBuf: {msg}')
200+
self.buf_ptr, _ = struct.unpack("<QQ", self.asc.ioread(msg.IOVA, 16))
201+
self.send(PMPMessage(TYPE=0x31))
202+
@msg_handler(0x32, PMPMessage_Advertise)
203+
def Advertise(self, msg):
204+
self.log(f'Advertise: {msg}')
205+
data = self.asc.ioread(msg.IOVA, 0x50)
206+
name = data[:0x30] + b'\0'
207+
size = struct.unpack("<I", data[0x40:0x44])[0]
208+
if size == 0:
209+
i = 0
210+
print(name)
211+
while name[i] != 0:
212+
i += 1
213+
name = name[:i].decode()
214+
self.log(f"Reading prop {name}")
215+
data = getattr(u.adt["/arm-io/pmp/iop-pmp-nub"], name, None)
216+
if data is None:
217+
self.log("unknown property")
218+
size = 0
219+
else:
220+
if isinstance(data, int):
221+
if data > 0xffffffff:
222+
data = struct.pack("<Q", data)
223+
else:
224+
data = struct.pack("<I", data)
225+
self.asc.iowrite(self.buf_ptr, data)
226+
size = len(data)
227+
self.ioregs.append(size)
228+
index = len(self.ioregs)
229+
self.send(PMPMessage_AdvertiseAck(INDEX=index, SIZE=size))
230+
231+
@msg_handler(0x34, PMPMessage_SetVal)
232+
def SetVal(self, msg):
233+
self.log(f'SetVal: {msg}')
234+
self.send(PMPMessage_SetValAck(SIZE=self.ioregs[msg.INDEX]))
235+
236+
237+
class PMPClient(StandardASC, AOPBase):
238+
ENDPOINTS = {0x20: PMPEp}
239+
def __init__(self, u, dev_path, dart=None):
240+
node = u.adt[dev_path]
241+
asc_base = node.get_reg(0)[0]
242+
AOPBase.__init__(self, u)
243+
super().__init__(u, asc_base, dart)
244+
self.dart = dart
245+
246+
if u.adt['/arm-io'].compatible[0].startswith('arm-io,t8103'):
247+
print("you have a pmp v1, this script is for v2 only")
248+
exit(1)
249+
elif u.adt['/arm-io'].compatible[0].startswith('arm-io,t600'):
250+
p.write64(0x28e3d07c0, 0x1000)
251+
elif u.adt['/arm-io'].compatible[0].startswith('arm-io,t602'):
252+
p.write64(0x28e3d1000, 0x2000)
253+
elif u.adt['/arm-io'].compatible[0].startswith('arm-io,t8112'):
254+
p.write64(0x23b3d0500, 0x80)
255+
else:
256+
print("FIXME: put the correct SOC-DEV-PS-REQ offset for your machine here")
257+
exit(1)
258+
259+
dart = DART.from_adt(u, "/arm-io/dart-pmp")
260+
dart.verbose = 1
261+
dart.initialize()
262+
263+
pmp = PMPClient(u, "/arm-io/pmp", dart)
264+
pmp.verbose = 4
265+
pmp.update_bootargs({
266+
'BDID'[::-1]: u.adt['/chosen'].board_id,
267+
'DCAP'[::-1]: u.adt["/arm-io/pmp/iop-pmp-nub"].dram_capacity,
268+
'DVID'[::-1]: u.adt['/chosen'].dram_vendor_id,
269+
})
270+
p.dapf_init_all()
271+
272+
pmp.start()
273+
pmp.start_ep(0x20)
274+
pmp.work_for(10)
275+
276+
run_shell(locals(), poll_func=pmp.work)

0 commit comments

Comments
 (0)