mirror of
https://github.com/AsahiLinux/m1n1
synced 2024-11-10 09:44:13 +00:00
m1n1.fw.dcp: Add DCP client framework, port tracer to it
This also includes an update to the macOS 12.0 beta ABI Signed-off-by: Hector Martin <marcan@marcan.st>
This commit is contained in:
parent
b32aec3786
commit
de5b5d996c
6 changed files with 748 additions and 104 deletions
|
@ -461,23 +461,7 @@ KNOWN_MSGS = {
|
|||
22: getNamedProperty
|
||||
"""
|
||||
|
||||
class DCPMessage(Register64):
|
||||
TYPE = 3, 0
|
||||
|
||||
class DCPEp_SetShmem(DCPMessage):
|
||||
IOVA = 47, 16
|
||||
|
||||
class CallContext(IntEnum):
|
||||
CALLBACK = 0
|
||||
CMD = 2
|
||||
ASYNC = 3
|
||||
OOB = 6
|
||||
|
||||
class DCPEp_Msg(DCPMessage):
|
||||
LEN = 63, 32
|
||||
OFF = 31, 16
|
||||
CTX = 11, 8, CallContext
|
||||
ACK = 6
|
||||
from m1n1.fw.dcp.dcpep import DCPMessage, DCPEp_SetShmem, CallContext, DCPEp_Msg
|
||||
|
||||
class DCPCallState:
|
||||
pass
|
||||
|
@ -571,23 +555,26 @@ class DCPEp(EP):
|
|||
self.state.ch = {}
|
||||
self.state.dumpfile = None
|
||||
|
||||
self.ch_cb = DCPCallChannel(self, "CB", 0x60000, 0x20000)
|
||||
self.ch_cb = DCPCallChannel(self, "CB", 0x60000, 0x8000)
|
||||
self.ch_cmd = DCPCallChannel(self, "CMD", 0, 0x8000)
|
||||
self.ch_async = DCPCallChannel(self, "ASYNC", 0x40000, 0x20000)
|
||||
self.ch_oob = DCPCallChannel(self, "OOB", 0x8000, 0x8000)
|
||||
self.ch_oobcb = DCPCallChannel(self, "OOBCB", 0x68000, 0x8000)
|
||||
self.ch_oobcmd = DCPCallChannel(self, "OOBCMD", 0x8000, 0x8000)
|
||||
|
||||
self.cmd_ch = {
|
||||
CallContext.CALLBACK: self.ch_cmd,
|
||||
CallContext.CB: self.ch_cmd,
|
||||
CallContext.CMD: self.ch_cmd,
|
||||
CallContext.ASYNC: self.ch_oob, # guess?
|
||||
CallContext.OOB: self.ch_oob,
|
||||
CallContext.ASYNC: None, # unknown
|
||||
CallContext.OOBCB: self.ch_oobcmd,
|
||||
CallContext.OOBCMD: self.ch_oobcmd,
|
||||
}
|
||||
|
||||
self.cb_ch = {
|
||||
CallContext.CALLBACK: self.ch_cb,
|
||||
CallContext.CB: self.ch_cb,
|
||||
CallContext.CMD: None,
|
||||
CallContext.ASYNC: self.ch_async,
|
||||
CallContext.OOB: None,
|
||||
CallContext.OOBCB: self.ch_oobcb,
|
||||
CallContext.OOBCMD: None,
|
||||
}
|
||||
|
||||
def start(self):
|
||||
|
@ -607,8 +594,8 @@ class DCPEp(EP):
|
|||
|
||||
@msg(0, DIR.TX, DCPEp_SetShmem)
|
||||
def SetShmem(self, msg):
|
||||
self.log(f"Shared memory IOVA: {msg.IOVA:#x}")
|
||||
self.state.shmem_iova = msg.IOVA
|
||||
self.log(f"Shared memory DVA: {msg.DVA:#x}")
|
||||
self.state.shmem_iova = msg.DVA & 0xffffffff
|
||||
self.add_mon()
|
||||
|
||||
@msg(2, DIR.TX, DCPEp_Msg)
|
||||
|
@ -625,6 +612,7 @@ class DCPEp(EP):
|
|||
|
||||
@msg(2, DIR.RX, DCPEp_Msg)
|
||||
def Rx(self, msg):
|
||||
self.log(msg)
|
||||
if msg.ACK:
|
||||
self.cmd_ch[msg.CTX].ack(msg, "<")
|
||||
else:
|
||||
|
@ -704,6 +692,9 @@ class DCPTracer(ASCTracer):
|
|||
dart_dcp_tracer = DARTTracer(hv, "/arm-io/dart-dcp")
|
||||
dart_dcp_tracer.start()
|
||||
|
||||
dart_disp0_tracer = DARTTracer(hv, "/arm-io/dart-disp0")
|
||||
dart_disp0_tracer.start()
|
||||
|
||||
def readmem_iova(addr, size):
|
||||
try:
|
||||
return dart_dcp_tracer.dart.ioread(0, addr, size)
|
||||
|
|
10
proxyclient/m1n1/fw/dcp/client.py
Normal file
10
proxyclient/m1n1/fw/dcp/client.py
Normal file
|
@ -0,0 +1,10 @@
|
|||
# SPDX-License-Identifier: MIT
|
||||
from ...utils import *
|
||||
|
||||
from ..asc import StandardASC
|
||||
from .dcpep import DCPEndpoint
|
||||
|
||||
class DCPClient(StandardASC):
|
||||
ENDPOINTS = {
|
||||
0x37: DCPEndpoint,
|
||||
}
|
162
proxyclient/m1n1/fw/dcp/dcpep.py
Normal file
162
proxyclient/m1n1/fw/dcp/dcpep.py
Normal file
|
@ -0,0 +1,162 @@
|
|||
# SPDX-License-Identifier: MIT
|
||||
import struct
|
||||
from dataclasses import dataclass
|
||||
from enum import IntEnum
|
||||
|
||||
from ..asc.base import *
|
||||
from ...utils import *
|
||||
|
||||
## DCP main endpoint
|
||||
|
||||
class DCPMessage(Register64):
|
||||
TYPE = 3, 0
|
||||
|
||||
class DCPEp_SetShmem(DCPMessage):
|
||||
DVA = 63, 16
|
||||
FLAG = 7, 4, Constant(4)
|
||||
TYPE = 3, 0, Constant(0)
|
||||
|
||||
class DCPEp_InitComplete(DCPMessage):
|
||||
TYPE = 3, 0, Constant(1)
|
||||
|
||||
class CallContext(IntEnum):
|
||||
CB = 0
|
||||
CMD = 2
|
||||
ASYNC = 3
|
||||
OOBCB = 4
|
||||
OOBCMD = 6
|
||||
|
||||
class DCPEp_Msg(DCPMessage):
|
||||
LEN = 63, 32
|
||||
OFF = 31, 16
|
||||
CTX = 11, 8, CallContext
|
||||
ACK = 6
|
||||
TYPE = 3, 0, Constant(2)
|
||||
|
||||
@dataclass
|
||||
class DCPCallState:
|
||||
tag: str
|
||||
off: int
|
||||
in_len: int
|
||||
in_data: bytes
|
||||
out_addr: int
|
||||
out_len: int
|
||||
complete: bool = False
|
||||
|
||||
class DCPCallChannel(Reloadable):
|
||||
def __init__(self, dcpep, name, buf, bufsize):
|
||||
self.dcp = dcpep
|
||||
self.name = name
|
||||
self.buf = buf
|
||||
self.bufsize = bufsize
|
||||
self.off = 0
|
||||
self.pending = []
|
||||
|
||||
def ack(self):
|
||||
if not self.pending:
|
||||
raise Exception("ACK with no calls pending")
|
||||
|
||||
self.pending[-1].complete = True
|
||||
|
||||
def call(self, ctx, tag, inbuf, out_len):
|
||||
in_len = len(inbuf)
|
||||
data = tag.encode("ascii")[::-1] + struct.pack("<II", in_len, out_len) + inbuf
|
||||
data_size = len(data) + out_len
|
||||
assert (self.off + data_size) <= self.bufsize
|
||||
|
||||
self.dcp.asc.iface.writemem(self.dcp.shmem + self.buf + self.off, data)
|
||||
|
||||
state = DCPCallState(off=self.off, tag=tag, in_len=in_len, in_data=data, out_len=out_len,
|
||||
out_addr=self.buf + self.off + 12 + in_len)
|
||||
|
||||
self.off += align_up(data_size, 0x40)
|
||||
self.pending.append(state)
|
||||
|
||||
print(f"len={data_size:#x} {in_len}")
|
||||
self.dcp.send(DCPEp_Msg(LEN=data_size, OFF=state.off, CTX=ctx, ACK=0))
|
||||
|
||||
while not state.complete:
|
||||
self.dcp.asc.work()
|
||||
|
||||
print(f"off={state.out_addr:#x} len={out_len}")
|
||||
out_data = self.dcp.asc.iface.readmem(self.dcp.shmem + state.out_addr, out_len)
|
||||
|
||||
assert self.pending.pop() is state
|
||||
self.off = state.off
|
||||
|
||||
return out_data
|
||||
|
||||
class DCPCallbackChannel(Reloadable):
|
||||
def __init__(self, dcpep, name, buf, bufsize):
|
||||
self.dcp = dcpep
|
||||
self.name = name
|
||||
self.buf = buf
|
||||
self.bufsize = bufsize
|
||||
self.pending = []
|
||||
|
||||
def cb(self, msg):
|
||||
data = self.dcp.asc.iface.readmem(self.dcp.shmem + self.buf + msg.OFF, msg.LEN)
|
||||
tag = data[:4][::-1].decode("ascii")
|
||||
in_len, out_len = struct.unpack("<II", data[4:12])
|
||||
in_data = data[12:12 + in_len]
|
||||
|
||||
state = DCPCallState(off=msg.OFF, tag=tag, in_len=in_len, out_len=out_len,
|
||||
in_data=in_data, out_addr=self.buf + msg.OFF + 12 + in_len)
|
||||
|
||||
self.pending.append(state)
|
||||
|
||||
out_data = self.dcp.mgr.handle_cb(state)
|
||||
self.dcp.asc.iface.writemem(self.dcp.shmem + state.out_addr, out_data)
|
||||
self.dcp.send(DCPEp_Msg(CTX=msg.CTX, ACK=1))
|
||||
|
||||
assert self.pending.pop() is state
|
||||
|
||||
|
||||
class DCPEndpoint(ASCBaseEndpoint):
|
||||
BASE_MESSAGE = DCPMessage
|
||||
SHORT = "dcpep"
|
||||
|
||||
def __init__(self, *args, **kwargs):
|
||||
super().__init__(*args, **kwargs)
|
||||
self.shmem = self.shmem_dva = None
|
||||
self.init_complete = False
|
||||
self.mgr = None
|
||||
|
||||
self.ch_cb = DCPCallbackChannel(self, "CB", 0x60000, 0x8000)
|
||||
self.ch_cmd = DCPCallChannel(self, "CMD", 0, 0x8000)
|
||||
self.ch_async = DCPCallbackChannel(self, "ASYNC", 0x40000, 0x20000)
|
||||
self.ch_oobcb = DCPCallbackChannel(self, "OOBCB", 0x68000, 0x8000)
|
||||
self.ch_oobcmd = DCPCallChannel(self, "OOBCMD", 0x8000, 0x8000)
|
||||
|
||||
@msg_handler(2, DCPEp_Msg)
|
||||
def Rx(self, msg):
|
||||
if msg.ACK:
|
||||
if msg.CTX in (CallContext.CMD, CallContext.CB):
|
||||
self.ch_cmd.ack()
|
||||
elif msg.CTX in (CallContext.OOBCMD, CallContext.OOBCB):
|
||||
self.ch_oobcmd.ack()
|
||||
else:
|
||||
raise Exception(f"Unknown RX ack channel {msg.CTX}")
|
||||
else:
|
||||
if msg.CTX == CallContext.CB:
|
||||
self.ch_cb.cb(msg)
|
||||
elif msg.CTX == CallContext.OOBCMD:
|
||||
self.ch_oobcb.cb(msg)
|
||||
elif msg.CTX == CallContext.ASYNC:
|
||||
self.ch_async.cb(msg)
|
||||
else:
|
||||
raise Exception(f"Unknown RX callback channel {msg.CTX}")
|
||||
return True
|
||||
|
||||
@msg_handler(1, DCPEp_InitComplete)
|
||||
def InitComplete(self, msg):
|
||||
self.log("init complete")
|
||||
self.init_complete = True
|
||||
return True
|
||||
|
||||
def initialize(self):
|
||||
self.shmem, self.shmem_dva = self.asc.ioalloc(0x100000)
|
||||
self.send(DCPEp_SetShmem(DVA=self.shmem_dva))
|
||||
while not self.init_complete:
|
||||
self.asc.work()
|
||||
|
|
@ -1,10 +1,16 @@
|
|||
# SPDX-License-Identifier: MIT
|
||||
|
||||
from dataclasses import dataclass
|
||||
import pprint
|
||||
from enum import IntEnum
|
||||
|
||||
from m1n1.utils import *
|
||||
from construct import *
|
||||
|
||||
@dataclass
|
||||
class ByRef:
|
||||
val: object
|
||||
|
||||
class Pointer(Subconstruct):
|
||||
pass
|
||||
|
||||
|
@ -22,6 +28,13 @@ class InOut(Subconstruct):
|
|||
|
||||
Ptr = InOutPtr
|
||||
|
||||
class NULL:
|
||||
def __str__(self):
|
||||
return "NULL"
|
||||
def __repr__(self):
|
||||
return "NULL"
|
||||
NULL = NULL()
|
||||
|
||||
class Method:
|
||||
def __init__(self, rtype, name, *args, **kwargs):
|
||||
self.rtype = rtype
|
||||
|
@ -31,8 +44,10 @@ class Method:
|
|||
raise Exception("Cannot specify args and kwargs")
|
||||
elif args:
|
||||
args = [(f"arg{i}", arg) for i, arg in enumerate(args)]
|
||||
self.as_kwargs = False
|
||||
elif kwargs:
|
||||
args = list(kwargs.items())
|
||||
self.as_kwargs = True
|
||||
else:
|
||||
args = []
|
||||
|
||||
|
@ -48,6 +63,7 @@ class Method:
|
|||
|
||||
self.dir = []
|
||||
self.nullable = []
|
||||
self.array_of_p = []
|
||||
|
||||
for i, (name, field) in enumerate(self.args):
|
||||
align = 1
|
||||
|
@ -88,19 +104,29 @@ class Method:
|
|||
self.dir.append(dir)
|
||||
|
||||
for i, (name, field) in enumerate(self.args):
|
||||
array_size = None
|
||||
array_of_p = False
|
||||
nullable = False
|
||||
pfield = field
|
||||
|
||||
while isinstance(pfield, Subconstruct):
|
||||
if isinstance(pfield, Array) and array_size is None:
|
||||
array_size = pfield.count
|
||||
if isinstance(pfield, Pointer):
|
||||
nullable = True
|
||||
array_of_p = array_size is not None
|
||||
pfield = pfield.subcon
|
||||
|
||||
if nullable:
|
||||
self.in_fields.append((name + "_null") / bool_)
|
||||
in_size += 1
|
||||
if array_of_p:
|
||||
self.in_fields.append((name + "_null") / bool_[array_size])
|
||||
in_size += array_size
|
||||
else:
|
||||
self.in_fields.append((name + "_null") / bool_)
|
||||
in_size += 1
|
||||
|
||||
self.nullable.append(nullable)
|
||||
self.array_of_p.append(array_of_p)
|
||||
|
||||
if in_size % 4:
|
||||
self.in_fields.append(Padding(4 - (in_size % 4)))
|
||||
|
@ -110,6 +136,33 @@ class Method:
|
|||
self.in_struct = Struct(*self.in_fields)
|
||||
self.out_struct = Struct(*self.out_fields)
|
||||
|
||||
def get_field_val(self, i, in_vals, out_vals=None, nullobj=None):
|
||||
name, field = self.args[i]
|
||||
|
||||
nullable = self.nullable[i]
|
||||
array_of_p = self.array_of_p[i]
|
||||
|
||||
val = None
|
||||
|
||||
if out_vals:
|
||||
val = out_vals.get(name, val)
|
||||
if val is None and in_vals:
|
||||
val = in_vals.get(name, val)
|
||||
|
||||
if nullable and val is not None:
|
||||
null = in_vals.get(name + "_null", None)
|
||||
if null is None:
|
||||
return None
|
||||
if not array_of_p:
|
||||
val = nullobj if null else val
|
||||
else:
|
||||
val2 = [nullobj if n else val for val, n in zip(val, null)]
|
||||
if isinstance(val, ListContainer):
|
||||
val2 = ListContainer(val2)
|
||||
val = val2
|
||||
|
||||
return val
|
||||
|
||||
def fmt_args(self, in_vals, out_vals=None):
|
||||
s = []
|
||||
|
||||
|
@ -120,31 +173,17 @@ class Method:
|
|||
dir = self.dir[i]
|
||||
nullable = self.nullable[i]
|
||||
|
||||
if nullable:
|
||||
null = in_vals.get(name + "_null", None)
|
||||
if null is None:
|
||||
s.append(f"{name}=?")
|
||||
continue
|
||||
elif null:
|
||||
s.append(f"{name}=NULL")
|
||||
continue
|
||||
val = self.get_field_val(i, in_vals, out_vals, nullobj=NULL)
|
||||
|
||||
if out_vals and name in out_vals:
|
||||
if self.is_long(out_vals[name]):
|
||||
if val is not None:
|
||||
if self.is_long(val):
|
||||
s.append(f"{name}=...")
|
||||
elif isinstance(out_vals[name], ListContainer):
|
||||
s.append(f"{name}={list(out_vals[name])!r}")
|
||||
elif isinstance(val, ListContainer):
|
||||
s.append(f"{name}={list(val)!r}")
|
||||
else:
|
||||
s.append(f"{name}={out_vals[name]!r}")
|
||||
s.append(f"{name}={val!r}")
|
||||
elif dir == "out":
|
||||
s.append(f"{name}=<out>")
|
||||
elif name in in_vals:
|
||||
if self.is_long(in_vals[name]):
|
||||
s.append(f"{name}=...")
|
||||
elif isinstance(in_vals[name], ListContainer):
|
||||
s.append(f"{name}={list(in_vals[name])!r}")
|
||||
else:
|
||||
s.append(f"{name}={in_vals[name]!r}")
|
||||
else:
|
||||
s.append(f"{name}=?")
|
||||
|
||||
|
@ -157,16 +196,9 @@ class Method:
|
|||
|
||||
dir = self.dir[i]
|
||||
|
||||
if self.nullable[i] and in_vals.get(name + "_null", None):
|
||||
continue
|
||||
val = self.get_field_val(i, in_vals, out_vals, nullobj=NULL)
|
||||
|
||||
if out_vals and name in out_vals:
|
||||
val = out_vals[name]
|
||||
elif out_vals:
|
||||
continue
|
||||
elif name in in_vals:
|
||||
val = in_vals[name]
|
||||
else:
|
||||
if name in in_vals and out_vals is not None and name not in out_vals:
|
||||
continue
|
||||
|
||||
if self.is_long(val):
|
||||
|
@ -184,7 +216,7 @@ class Method:
|
|||
|
||||
def is_long(self, arg):
|
||||
if isinstance(arg, (list, bytes)):
|
||||
return len(arg) > 4
|
||||
return len(arg) > 4 or any(self.is_long(i) for i in arg)
|
||||
|
||||
return isinstance(arg, (dict, list, bytes))
|
||||
|
||||
|
@ -203,6 +235,128 @@ class Method:
|
|||
|
||||
return Container({ k: v() if callable(v) else v for k,v in vals.items() })
|
||||
|
||||
def __str__(self):
|
||||
if self.rtype is None:
|
||||
rtype = "void"
|
||||
else:
|
||||
rtype = str(self.rtype)
|
||||
|
||||
args = []
|
||||
for name, field in self.args:
|
||||
if name == "ret":
|
||||
continue
|
||||
args.append(f"{field} {name}")
|
||||
|
||||
return f"{rtype} {self.name}({', '.join(args)})"
|
||||
|
||||
def callback(self, func, in_data):
|
||||
in_vals = self.parse_input(in_data)
|
||||
|
||||
args = []
|
||||
kwargs = {}
|
||||
|
||||
out_vals = {}
|
||||
|
||||
for i, (name, field) in enumerate(self.args):
|
||||
if name == "ret":
|
||||
continue
|
||||
|
||||
dir = self.dir[i]
|
||||
|
||||
val = self.get_field_val(i, in_vals, out_vals, nullobj=NULL)
|
||||
is_null = val is NULL
|
||||
if is_null:
|
||||
val = None
|
||||
|
||||
if dir == "inout":
|
||||
if val is not None and not isinstance(val, list):
|
||||
val = ByRef(val)
|
||||
out_vals[name] = val
|
||||
elif dir == "out" and not is_null:
|
||||
val = ByRef(None)
|
||||
out_vals[name] = val
|
||||
|
||||
if self.as_kwargs:
|
||||
kwargs[name] = val
|
||||
else:
|
||||
args.append(val)
|
||||
|
||||
retval = func(*args, **kwargs)
|
||||
|
||||
if self.rtype is None:
|
||||
assert retval is None
|
||||
else:
|
||||
assert retval is not None
|
||||
out_vals["ret"] = retval
|
||||
|
||||
out_vals = {k: v.val if isinstance(v, ByRef) else v for k, v in out_vals.items()}
|
||||
|
||||
context = dict(in_vals)
|
||||
|
||||
if "obj" in context:
|
||||
del context["obj"]
|
||||
|
||||
out_data = self.out_struct.build(out_vals, **context)
|
||||
return out_data
|
||||
|
||||
|
||||
def call(self, call, *args, **kwargs):
|
||||
if args and kwargs:
|
||||
raise Exception("Cannot use both args and kwargs")
|
||||
|
||||
if args:
|
||||
for arg, (name, field) in zip(args, self.args):
|
||||
kwargs[name] = arg
|
||||
|
||||
in_vals = {}
|
||||
out_refs = {}
|
||||
|
||||
for i, (name, field) in enumerate(self.args):
|
||||
if name == "ret":
|
||||
continue
|
||||
|
||||
val = kwargs[name]
|
||||
dir = self.dir[i]
|
||||
nullable = self.nullable[i]
|
||||
array_of_p = self.array_of_p[i]
|
||||
|
||||
if nullable:
|
||||
if not array_of_p:
|
||||
in_vals[name + "_null"] = val is None
|
||||
else:
|
||||
defaults = field.parse(b"\x00" * field.sizeof())
|
||||
in_vals[name + "_null"] = [i is None for i in val]
|
||||
val = [v if v is not None else defaults[i] for i, v in enumerate(val)]
|
||||
else:
|
||||
assert val is not None
|
||||
|
||||
if val is None:
|
||||
continue
|
||||
|
||||
if dir == "out":
|
||||
assert isinstance(val, ByRef)
|
||||
out_refs[name] = val
|
||||
elif dir == "inout":
|
||||
if isinstance(val, ByRef):
|
||||
in_vals[name] = val.val
|
||||
out_refs[name] = val
|
||||
elif val is not None:
|
||||
in_vals[name] = val
|
||||
elif val is not None:
|
||||
in_vals[name] = val
|
||||
|
||||
in_data = self.in_struct.build(in_vals)
|
||||
print(f"{self.name}({self.fmt_args(in_vals)})")
|
||||
|
||||
out_data = call(in_data)
|
||||
out_vals = self.parse_output(out_data, in_vals)
|
||||
|
||||
for k, v in out_refs.items():
|
||||
v.val = out_vals[k]
|
||||
|
||||
if self.rtype is not None:
|
||||
return out_vals["ret"]
|
||||
|
||||
def dump_fields(fields):
|
||||
off = 0
|
||||
for f in fields:
|
||||
|
@ -234,11 +388,14 @@ def Bool(c):
|
|||
return ExprAdapter(c, lambda d, ctx: bool(d & 1), lambda d, ctx: int(d))
|
||||
|
||||
def SizedArray(count, svar, subcon):
|
||||
return Lazy(Padded(subcon.sizeof() * count, Array(lambda ctx: ctx.get(svar) or ctx._.get(svar), subcon)))
|
||||
return Padded(subcon.sizeof() * count, Array(lambda ctx: min(count, ctx.get(svar, ctx._.get(svar))), subcon))
|
||||
|
||||
def SizedBytes(count, svar):
|
||||
return Lazy(Padded(count, Bytes(lambda ctx: ctx.get(svar) or ctx._.get(svar))))
|
||||
|
||||
def UnkBytes(s):
|
||||
return Default(HexDump(Bytes(s)), b"\x00" * s)
|
||||
|
||||
bool_ = Bool(int8_t)
|
||||
|
||||
class OSObject(Construct):
|
||||
|
@ -277,8 +434,8 @@ class OSDictionary(OSObject):
|
|||
TYPE = 'd'
|
||||
|
||||
FourCC = ExprAdapter(uint32_t,
|
||||
lambda d, ctx: d.to_bytes(4, "big").decode("ascii"),
|
||||
lambda d, ctx: int.from_bytes(d.encode("ascii"), "big"))
|
||||
lambda d, ctx: d.to_bytes(4, "big").decode("latin-1"),
|
||||
lambda d, ctx: int.from_bytes(d.encode("latin-1"), "big"))
|
||||
|
||||
void = None
|
||||
|
||||
|
@ -312,15 +469,112 @@ IOMFBParameterName = Int32ul
|
|||
BufferDescriptor = uint64_t
|
||||
|
||||
SwapCompleteData = Bytes(0x12)
|
||||
SwapInfoBlob = Bytes(0x600)
|
||||
SwapInfoBlob = Bytes(0x680)
|
||||
|
||||
IOMFBSwapRec = Bytes(0x274)
|
||||
IOSurface = Bytes(0x204)
|
||||
SWAP_SURFACES = 4
|
||||
|
||||
Rect = NamedTuple("rect", "x y w h", Int32ul[4])
|
||||
|
||||
IOMFBSwapRec = Struct(
|
||||
"ts1" / Default(Int64ul, 0),
|
||||
"ts2" / Default(Int64ul, 0),
|
||||
"unk_10" / Default(Int64ul, 0),
|
||||
"unk_18" / Default(Int64ul, 0),
|
||||
"ts64_unk" / Default(Int64ul, 0),
|
||||
"unk_28" / Default(Int64ul, 0),
|
||||
"ts3" / Default(Int64ul, 0),
|
||||
"unk_38" / Default(Int64ul, 0),
|
||||
"flags1" / Hex(Int64ul),
|
||||
"flags2" / Hex(Int64ul),
|
||||
"swap_id" / Int32ul,
|
||||
"surf_ids" / Int32ul[SWAP_SURFACES],
|
||||
"src_rect" / Rect[SWAP_SURFACES],
|
||||
"surf_flags" / Int32ul[SWAP_SURFACES],
|
||||
"surf_unk" / Int32ul[SWAP_SURFACES],
|
||||
"dst_rect" / Rect[SWAP_SURFACES],
|
||||
"swap_enabled" / Hex(Int32ul),
|
||||
"swap_completed" / Hex(Int32ul),
|
||||
"unk_10c" / Hex(Default(Int32ul, 0)),
|
||||
"unk_110" / UnkBytes(0x1b8),
|
||||
"unk_2c8" / Hex(Default(Int32ul, 0)),
|
||||
"unk_2cc" / UnkBytes(0x14),
|
||||
"unk_2e0" / Hex(Default(Int32ul, 0)),
|
||||
"unk_2e4" / UnkBytes(0x3c),
|
||||
)
|
||||
|
||||
assert IOMFBSwapRec.sizeof() == 0x320
|
||||
|
||||
MAX_PLANES = 3
|
||||
|
||||
ComponentTypes = Struct(
|
||||
"count" / Int8ul,
|
||||
"types" / SizedArray(7, "count", Int8ul),
|
||||
)
|
||||
|
||||
#ComponentTypes = Bytes(8)
|
||||
|
||||
PlaneInfo = Struct(
|
||||
"width" / Int32ul,
|
||||
"height" / Int32ul,
|
||||
"base" / Hex(Int32ul),
|
||||
"offset" / Hex(Int32ul),
|
||||
"stride" / Hex(Int32ul),
|
||||
"size" / Hex(Int32ul),
|
||||
"tile_size" / Int16ul,
|
||||
"tile_w" / Int8ul,
|
||||
"tile_h" / Int8ul,
|
||||
"unk1" / UnkBytes(0xd),
|
||||
"unk2" / Hex(Int8ul),
|
||||
"unk3" / UnkBytes(0x26),
|
||||
)
|
||||
|
||||
print(hex(PlaneInfo.sizeof()))
|
||||
assert PlaneInfo.sizeof() == 0x50
|
||||
|
||||
IOSurface = Struct(
|
||||
"is_tiled" / bool_,
|
||||
"unk_1" / bool_,
|
||||
"unk_2" / bool_,
|
||||
"plane_cnt" / Int32ul,
|
||||
"plane_cnt2" / Int32ul,
|
||||
"format" / FourCC,
|
||||
"unk_f" / Default(Hex(Int32ul), 0),
|
||||
"unk_13" / Int8ul,
|
||||
"unk_14" / Int8ul,
|
||||
"stride" / Int32ul,
|
||||
"pix_size" / Int16ul,
|
||||
"pel_w" / Int8ul,
|
||||
"pel_h" / Int8ul,
|
||||
"offset" / Default(Hex(Int32ul), 0),
|
||||
"width" / Int32ul,
|
||||
"height" / Int32ul,
|
||||
"buf_size" / Hex(Int32ul),
|
||||
"unk_2d" / Default(Int32ul, 0),
|
||||
"unk_31" / Default(Int32ul, 0),
|
||||
"surface_id" / Int32ul,
|
||||
"comp_types" / Default(SizedArray(MAX_PLANES, "plane_cnt", ComponentTypes), []),
|
||||
"has_comp" / Bool(Int64ul),
|
||||
"planes" / Default(SizedArray(MAX_PLANES, "plane_cnt", PlaneInfo), []),
|
||||
"has_planes" / Bool(Int64ul),
|
||||
"compression_info" / Default(SizedArray(MAX_PLANES, "plane_cnt", UnkBytes(0x34)), []),
|
||||
"has_compr_info" / Bool(Int64ul),
|
||||
"unk_1f5" / Int32ul,
|
||||
"unk_1f9" / Int32ul,
|
||||
"padding" / UnkBytes(7),
|
||||
)
|
||||
|
||||
print(hex(IOSurface.sizeof()))
|
||||
assert IOSurface.sizeof() == 0x204
|
||||
|
||||
IOMFBColorFixedMatrix = Array(5, Array(3, ulong))
|
||||
|
||||
class PropID(IntEnum):
|
||||
BrightnessCorrection = 14
|
||||
|
||||
class UPPipeAP_H13P(IPCObject):
|
||||
A000 = Call(bool_, "late_init_signal")
|
||||
A029 = Call(void, "setup_video_limits")
|
||||
A034 = Call(void, "update_notify_clients_dcp", Array(11, uint))
|
||||
A034 = Call(void, "update_notify_clients_dcp", Array(13, uint))
|
||||
A036 = Call(bool_, "apt_supported")
|
||||
|
||||
D000 = Callback(bool_, "did_boot_signal")
|
||||
|
@ -330,6 +584,7 @@ class UPPipeAP_H13P(IPCObject):
|
|||
|
||||
class UnifiedPipeline2(IPCObject):
|
||||
A357 = Call(void, "set_create_DFB")
|
||||
A358 = Call(IOMFBStatus, "vi_set_temperature_hint")
|
||||
|
||||
D100 = Callback(void, "match_pmu_service")
|
||||
D101 = Callback(uint32_t, "UNK_get_some_field")
|
||||
|
@ -341,40 +596,44 @@ class UnifiedPipeline2(IPCObject):
|
|||
D110 = Callback(bool_, "create_iomfb_service")
|
||||
D111 = Callback(bool_, "create_backlight_service")
|
||||
D116 = Callback(bool_, "start_hardware_boot")
|
||||
D119 = Callback(bool_, "read_edt_data", key=string(0x40), count=uint, value=InOut(SizedArray(8, "count", uint32_t)))
|
||||
D118 = Callback(bool_, "is_waking_from_hibernate")
|
||||
D120 = Callback(bool_, "read_edt_data", key=string(0x40), count=uint, value=InOut(Lazy(SizedArray(8, "count", uint32_t))))
|
||||
|
||||
D121 = Callback(bool_, "setDCPAVPropStart", length=uint)
|
||||
D122 = Callback(bool_, "setDCPAVPropChunk", data=HexDump(SizedBytes(0x1000, "length")), offset=uint, length=uint)
|
||||
D123 = Callback(bool_, "setDCPAVPropEnd", key=string(0x40))
|
||||
D122 = Callback(bool_, "setDCPAVPropStart", length=uint)
|
||||
D123 = Callback(bool_, "setDCPAVPropChunk", data=HexDump(SizedBytes(0x1000, "length")), offset=uint, length=uint)
|
||||
D124 = Callback(bool_, "setDCPAVPropEnd", key=string(0x40))
|
||||
|
||||
class UPPipe2(IPCObject):
|
||||
A103 = Call(uint64_t, "test_control", cmd=uint64_t, arg=uint)
|
||||
A131 = Call(bool_, "pmu_service_matched")
|
||||
|
||||
D201 = Callback(uint32_t, "map_buf", InPtr(BufferDescriptor), OutPtr(ulong), OutPtr(ulong), bool_)
|
||||
|
||||
D206 = Callback(bool_, "match_pmu_service")
|
||||
D206 = Callback(bool_, "match_pmu_service_2")
|
||||
D207 = Callback(bool_, "match_backlight_service")
|
||||
D208 = Callback(uint64_t, "get_calendar_time_ms")
|
||||
|
||||
class PropRelay(IPCObject):
|
||||
D300 = Callback(void, "publish", prop_id=uint32_t, value=int_)
|
||||
D300 = Callback(void, "pr_publish", prop_id=uint32_t, value=int_)
|
||||
|
||||
class IOMobileFramebufferAP(IPCObject):
|
||||
A401 = Call(uint32_t, "start_signal")
|
||||
|
||||
A407 = Call(uint32_t, "swap_start", InOutPtr(uint), InOutPtr(IOUserClient))
|
||||
A407 = Call(uint32_t, "swap_start", swap_id=InOutPtr(uint), client=InOutPtr(IOUserClient))
|
||||
A408 = Call(uint32_t, "swap_submit_dcp",
|
||||
swap_rec=InPtr(IOMFBSwapRec),
|
||||
surf0=InPtr(IOSurface),
|
||||
surf1=InPtr(IOSurface),
|
||||
surf2=InPtr(IOSurface),
|
||||
surfInfo=Array(3, uint),
|
||||
surfaces=Array(4, InPtr(IOSurface)),
|
||||
surfAddr=Array(4, Hex(ulong)),
|
||||
unkBool=bool_,
|
||||
unkFloat=Float64l,
|
||||
unkInt=uint,
|
||||
unkOutBool=OutPtr(bool_))
|
||||
|
||||
A410 = Call(uint32_t, "set_display_device", uint)
|
||||
A411 = Call(bool_, "is_main_display")
|
||||
A438 = Call(uint32_t, "swap_set_color_matrix", matrix=InOutPtr(IOMFBColorFixedMatrix), func=uint32_t, unk=uint)
|
||||
#"A438": "IOMobileFramebufferAP::swap_set_color_matrix(IOMFBColorFixedMatrix*, IOMFBColorMatrixFunction, unsigned int)",
|
||||
|
||||
A412 = Call(uint32_t, "set_digital_out_mode", uint, uint)
|
||||
A419 = Call(uint32_t, "get_gamma_table", InOutPtr(Bytes(0xc0c)))
|
||||
A422 = Call(uint32_t, "set_matrix", uint, InPtr(Array(3, Array(3, ulong))))
|
||||
|
@ -383,23 +642,27 @@ class IOMobileFramebufferAP(IPCObject):
|
|||
A427 = Call(uint32_t, "setBrightnessCorrection", uint)
|
||||
|
||||
A435 = Call(uint32_t, "set_block_dcp", arg1=uint64_t, arg2=uint, arg3=uint, arg4=Array(8, ulong), arg5=uint, data=SizedBytes(0x1000, "length"), length=ulong)
|
||||
A438 = Call(uint32_t, "set_parameter_dcp", param=IOMFBParameterName, value=SizedArray(4, "count", ulong), count=uint)
|
||||
A439 = Call(uint32_t, "set_parameter_dcp", param=IOMFBParameterName, value=Lazy(SizedArray(4, "count", ulong)), count=uint)
|
||||
|
||||
A441 = Call(void, "get_display_size", OutPtr(uint), OutPtr(uint))
|
||||
A442 = Call(int_, "do_create_default_frame_buffer")
|
||||
A446 = Call(int_, "enable_disable_video_power_savings", uint)
|
||||
A453 = Call(void, "first_client_open")
|
||||
A455 = Call(bool_, "writeDebugInfo", ulong)
|
||||
A459 = Call(bool_, "setDisplayRefreshProperties")
|
||||
A462 = Call(void, "flush_supportsPower", bool_)
|
||||
A467 = Call(uint32_t, "setPowerState", ulong, bool_, OutPtr(uint))
|
||||
A468 = Call(bool_, "isKeepOnScreen")
|
||||
A440 = Call(uint, "display_width")
|
||||
A441 = Call(uint, "display_height")
|
||||
A442 = Call(void, "get_display_size", OutPtr(uint), OutPtr(uint))
|
||||
A443 = Call(int_, "do_create_default_frame_buffer")
|
||||
A444 = Call(void, "printRegs")
|
||||
A447 = Call(int_, "enable_disable_video_power_savings", uint)
|
||||
A454 = Call(void, "first_client_open")
|
||||
A456 = Call(bool_, "writeDebugInfo", ulong)
|
||||
A458 = Call(bool_, "io_fence_notify", uint, uint, ulong, IOMFBStatus)
|
||||
A460 = Call(bool_, "setDisplayRefreshProperties")
|
||||
A463 = Call(void, "flush_supportsPower", bool_)
|
||||
A468 = Call(uint32_t, "setPowerState", ulong, bool_, OutPtr(uint))
|
||||
A469 = Call(bool_, "isKeepOnScreen")
|
||||
|
||||
D552 = Callback(bool_, "setProperty<OSDictionary>", key=string(0x40), value=InPtr(Padded(0x1000, OSDictionary())))
|
||||
D561 = Callback(bool_, "setProperty<OSDictionary>", key=string(0x40), value=InPtr(Padded(0x1000, OSDictionary())))
|
||||
D563 = Callback(bool_, "setProperty<OSNumber>", key=string(0x40), value=InPtr(uint64_t))
|
||||
D565 = Callback(bool_, "setProperty<OSBoolean>", key=string(0x40), value=InPtr(Bool(uint32_t)))
|
||||
D567 = Callback(bool_, "setProperty<AFKString>", key=string(0x40), value=string(0x40))
|
||||
D552 = Callback(bool_, "setProperty_dict", key=string(0x40), value=InPtr(Padded(0x1000, OSDictionary())))
|
||||
D561 = Callback(bool_, "setProperty_dict", key=string(0x40), value=InPtr(Padded(0x1000, OSDictionary())))
|
||||
D563 = Callback(bool_, "setProperty_int", key=string(0x40), value=InPtr(uint64_t))
|
||||
D565 = Callback(bool_, "setProperty_bool", key=string(0x40), value=InPtr(Bool(uint32_t)))
|
||||
D567 = Callback(bool_, "setProperty_str", key=string(0x40), value=string(0x40))
|
||||
|
||||
D574 = Callback(IOMFBStatus, "powerUpDART", bool_)
|
||||
|
||||
|
@ -414,16 +677,16 @@ class IOMobileFramebufferAP(IPCObject):
|
|||
D598 = Callback(void, "find_swap_function_gated")
|
||||
|
||||
class ServiceRelay(IPCObject):
|
||||
D401 = Callback(bool_, "get_uint_prop", obj=FourCC, key=string(0x40), value=InOutPtr(ulong))
|
||||
D408 = Callback(uint64_t, "getClockFrequency", uint, uint)
|
||||
D411 = Callback(IOMFBStatus, "mapDeviceMemoryWithIndex", uint, uint, uint, OutPtr(ulong), OutPtr(ulong))
|
||||
D413 = Callback(bool_, "setProperty<OSDictionary>", obj=FourCC, key=string(0x40), value=InPtr(Padded(0x1000, OSDictionary())))
|
||||
D414 = Callback(bool_, "setProperty<OSNumber>", obj=FourCC, key=string(0x40), value=InPtr(uint64_t))
|
||||
D415 = Callback(bool_, "setProperty<OSBoolean>", obj=FourCC, key=string(0x40), value=InPtr(Bool(uint32_t)))
|
||||
D401 = Callback(bool_, "sr_get_uint_prop", obj=FourCC, key=string(0x40), value=InOutPtr(ulong))
|
||||
D408 = Callback(uint64_t, "sr_getClockFrequency", obj=FourCC, arg=uint)
|
||||
D411 = Callback(IOMFBStatus, "sr_mapDeviceMemoryWithIndex", obj=FourCC, index=uint, flags=uint, addr=OutPtr(ulong), length=OutPtr(ulong))
|
||||
D413 = Callback(bool_, "sr_setProperty_dict", obj=FourCC, key=string(0x40), value=InPtr(Padded(0x1000, OSDictionary())))
|
||||
D414 = Callback(bool_, "sr_setProperty_int", obj=FourCC, key=string(0x40), value=InPtr(uint64_t))
|
||||
D415 = Callback(bool_, "sr_setProperty_bool", obj=FourCC, key=string(0x40), value=InPtr(Bool(uint32_t)))
|
||||
|
||||
class MemDescRelay(IPCObject):
|
||||
D451 = Callback(uint, "allocate_buffer", uint, ulong, uint, OutPtr(ulong), OutPtr(ulong), OutPtr(ulong))
|
||||
D452 = Callback(uint, "map_physical", ulong, ulong, uint, OutPtr(ulong), OutPtr(ulong))
|
||||
D452 = Callback(uint, "map_physical", paddr=ulong, size=ulong, flags=uint, dva=OutPtr(ulong), dvasize=OutPtr(ulong))
|
||||
|
||||
ALL_CLASSES = [
|
||||
UPPipeAP_H13P,
|
||||
|
@ -444,7 +707,8 @@ SHORT_CHANNELS = {
|
|||
"CB": "d",
|
||||
"CMD": "C",
|
||||
"ASYNC": "a",
|
||||
"OOB": "O",
|
||||
"OOBCMD": "O",
|
||||
"OOBCB": "o",
|
||||
}
|
||||
|
||||
RDIR = { ">": "<", "<": ">" }
|
||||
|
|
211
proxyclient/m1n1/fw/dcp/manager.py
Normal file
211
proxyclient/m1n1/fw/dcp/manager.py
Normal file
|
@ -0,0 +1,211 @@
|
|||
# SPDX-License-Identifier: MIT
|
||||
import struct, functools
|
||||
from dataclasses import dataclass
|
||||
from enum import IntEnum
|
||||
|
||||
from construct.lib import hexundump
|
||||
|
||||
from ..asc.base import *
|
||||
from ...utils import *
|
||||
|
||||
from . import ipc
|
||||
from .dcpep import CallContext
|
||||
|
||||
## DCP API manager
|
||||
|
||||
class DCPBaseManager:
|
||||
def __init__(self, dcpep):
|
||||
self.dcpep = dcpep
|
||||
self.dcp = dcpep.asc
|
||||
dcpep.mgr = self
|
||||
|
||||
self.name_map = {}
|
||||
self.tag_map = {}
|
||||
|
||||
self.in_callback = 0
|
||||
|
||||
for k, (cls, v) in ipc.ALL_METHODS.items():
|
||||
self.name_map[v.name] = k, v
|
||||
self.tag_map[k] = v
|
||||
|
||||
def handle_cb(self, state):
|
||||
method = self.tag_map.get(state.tag, None)
|
||||
if method is None:
|
||||
raise Exception(f"Unknown callback {state.tag}")
|
||||
|
||||
func = getattr(self, method.name, None)
|
||||
|
||||
if func is None:
|
||||
raise Exception(f"Unimplemented callback {method!s} [{state.tag}]")
|
||||
|
||||
self.in_callback += 1
|
||||
try:
|
||||
retval = method.callback(func, state.in_data)
|
||||
except Exception as e:
|
||||
print(f"Exception in callback {method.name}")
|
||||
raise
|
||||
self.in_callback -= 1
|
||||
return retval
|
||||
|
||||
def __getattr__(self, attr):
|
||||
tag, method = self.name_map.get(attr, (None, None))
|
||||
if method is None or tag.startswith("D"):
|
||||
raise AttributeError(f"Unknown method {attr}")
|
||||
|
||||
out_len = method.out_struct.sizeof()
|
||||
if self.in_callback:
|
||||
ctx = CallContext.CB
|
||||
else:
|
||||
ctx = CallContext.CMD
|
||||
rpc = functools.partial(self.dcpep.ch_cmd.call, ctx, tag, out_len=out_len)
|
||||
return functools.partial(method.call, rpc)
|
||||
|
||||
class DCPManager(DCPBaseManager):
|
||||
def __init__(self, dcpep):
|
||||
super().__init__(dcpep)
|
||||
|
||||
self.iomfb_prop = {}
|
||||
self.dcpav_prop = {}
|
||||
self.service_prop = {}
|
||||
self.pr_prop = {}
|
||||
|
||||
self.swaps = 0
|
||||
self.frame = 0
|
||||
|
||||
self.mapid = 0
|
||||
|
||||
## IOMobileFramebufferAP methods
|
||||
|
||||
def find_swap_function_gated(self):
|
||||
pass
|
||||
|
||||
def create_provider_service(self):
|
||||
return True
|
||||
|
||||
def create_product_service(self):
|
||||
return True
|
||||
|
||||
def create_PMU_service(self):
|
||||
return True
|
||||
|
||||
def create_iomfb_service(self):
|
||||
return True
|
||||
|
||||
def create_backlight_service(self):
|
||||
return False
|
||||
|
||||
def setProperty(self, key, value):
|
||||
self.iomfb_prop[key] = value
|
||||
print(f"setProperty({key} = {value!r})")
|
||||
return True
|
||||
|
||||
setProperty_dict = setProperty_int = setProperty_bool = setProperty_str = setProperty
|
||||
|
||||
def swap_complete_ap_gated(self, arg0, arg1, arg2, arg3, arg4):
|
||||
print(f"swap_complete_ap_gated({arg0}, {arg1}, ..., ..., {arg4}")
|
||||
chexdump(arg2)
|
||||
chexdump(arg3)
|
||||
self.swaps += 1
|
||||
self.frame = arg0
|
||||
|
||||
## UPPipeAP_H13P methods
|
||||
|
||||
def did_boot_signal(self):
|
||||
return True
|
||||
|
||||
def did_power_on_signal(self):
|
||||
return True
|
||||
|
||||
def rt_bandwidth_setup_ap(self, config):
|
||||
print("rt_bandwidth_setup_ap(...)")
|
||||
config.val = {"data":unhex("""
|
||||
6C 43 6C 6F 63 6B 00 44 14 80 73 3B 02 00 00 00
|
||||
00 C0 C3 3B 02 00 00 00 00 00 00 00 02 00 00 00
|
||||
00 00 00 00 90 26 FB 43 FF FF FF FF 04 00 00 00
|
||||
00 00 00 00 65 04 00 00 00 00 00 00
|
||||
""")}
|
||||
## UnifiedPipeline2 methods
|
||||
|
||||
def match_pmu_service(self):
|
||||
pass
|
||||
|
||||
def create_provider_service(self):
|
||||
return True
|
||||
|
||||
def read_edt_data(self, key, count, value):
|
||||
return False
|
||||
|
||||
def UNK_get_some_field(self):
|
||||
return 0
|
||||
|
||||
def start_hardware_boot(self):
|
||||
self.set_create_DFB()
|
||||
self.do_create_default_frame_buffer()
|
||||
self.setup_video_limits()
|
||||
self.flush_supportsPower(True)
|
||||
self.late_init_signal()
|
||||
self.setDisplayRefreshProperties()
|
||||
return True
|
||||
|
||||
def setDCPAVPropStart(self, length):
|
||||
print(f"setDCPAVPropStart({length:#x})")
|
||||
return True
|
||||
|
||||
def setDCPAVPropChunk(self, data, offset, length):
|
||||
print(f"setDCPAVPropChunk(..., {offset:#x}, {length:#x})")
|
||||
return True
|
||||
|
||||
def setDCPAVPropEnd(self, key):
|
||||
print(f"setDCPAVPropEnd({key!r})")
|
||||
return True
|
||||
|
||||
def is_waking_from_hibernate(self):
|
||||
return False
|
||||
|
||||
## UPPipe2 methods
|
||||
|
||||
def match_pmu_service_2(self):
|
||||
return True
|
||||
|
||||
def match_backlight_service(self):
|
||||
return True
|
||||
|
||||
## ServiceRelay methods
|
||||
|
||||
def sr_setProperty(self, obj, key, value):
|
||||
self.service_prop.setdefault(obj, {})[key] = value
|
||||
print(f"sr_setProperty({obj}/{key} = {value!r})")
|
||||
return True
|
||||
|
||||
def sr_getClockFrequency(self, obj, arg):
|
||||
print(f"sr_getClockFrequency({obj}, {arg})")
|
||||
return 533333328
|
||||
|
||||
sr_setProperty_dict = sr_setProperty_int = sr_setProperty_bool = sr_setProperty_str = sr_setProperty
|
||||
|
||||
def sr_get_uint_prop(self, obj, key, value):
|
||||
value.val = 0
|
||||
return False
|
||||
|
||||
def sr_mapDeviceMemoryWithIndex(self, obj, index, flags, addr, length):
|
||||
assert obj == "PROV"
|
||||
addr.val, length.val = self.dcp.u.adt["/arm-io/disp0"].get_reg(index)
|
||||
print(f"sr_mapDeviceMemoryWithIndex({obj}, {index}, {flags}, {addr.val:#x}, {length.val:#x})")
|
||||
return 0
|
||||
|
||||
## PropRelay methods
|
||||
|
||||
def pr_publish(self, prop_id, value):
|
||||
self.pr_prop[prop_id] = value
|
||||
print(f"pr_publish({prop_id}, {value!r})")
|
||||
|
||||
## MemDescRelay methods:
|
||||
|
||||
def map_physical(self, paddr, size, flags, dva, dvasize):
|
||||
dvasize.val = align_up(size, 4096)
|
||||
dva.val = self.dcp.dart.iomap(0, paddr, size)
|
||||
print(f"map_physical({paddr:#x}, {size:#x}, {flags}, {dva.val:#x}, {dvasize.val:#x})")
|
||||
|
||||
self.mapid += 1
|
||||
return self.mapid
|
||||
|
|
@ -23,14 +23,20 @@ def parse_log(fd):
|
|||
yield op
|
||||
|
||||
def dump_log(fd):
|
||||
nesting = 0
|
||||
nesting = {
|
||||
"": 0,
|
||||
"OOB": 0,
|
||||
}
|
||||
for op in parse_log(fd):
|
||||
ctx = ""
|
||||
if "OOB" in op.chan:
|
||||
ctx = "[OOB] -----------> "
|
||||
if not op.complete:
|
||||
op.print_req(indent=" " * nesting)
|
||||
nesting += 1
|
||||
op.print_req(indent=ctx + " " * nesting.setdefault(ctx, 0))
|
||||
nesting[ctx] += 1
|
||||
else:
|
||||
nesting -= 1
|
||||
op.print_reply(indent=" " * nesting)
|
||||
nesting[ctx] -= 1
|
||||
op.print_reply(indent=ctx + " " * nesting.setdefault(ctx, 0))
|
||||
|
||||
if __name__ == "__main__":
|
||||
import sys
|
||||
|
|
Loading…
Reference in a new issue