diff options
Diffstat (limited to 'tools/proxyclient/m1n1/fw/dcp/ipc.py')
| -rw-r--r-- | tools/proxyclient/m1n1/fw/dcp/ipc.py | 789 |
1 files changed, 789 insertions, 0 deletions
diff --git a/tools/proxyclient/m1n1/fw/dcp/ipc.py b/tools/proxyclient/m1n1/fw/dcp/ipc.py new file mode 100644 index 0000000..c961a8c --- /dev/null +++ b/tools/proxyclient/m1n1/fw/dcp/ipc.py @@ -0,0 +1,789 @@ +# SPDX-License-Identifier: MIT + +from dataclasses import dataclass +import pprint +from enum import IntEnum + +from ..common import * +from m1n1.utils import * +from construct import * + +@dataclass +class ByRef: + val: object + +class Pointer(Subconstruct): + pass + +class InPtr(Pointer): + pass + +class OutPtr(Pointer): + pass + +class InOutPtr(Pointer): + pass + +class InOut(Subconstruct): + pass + +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 + self.name = name + + if args and kwargs: + 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 = [] + + self.args = args + + in_size = 0 + out_size = 0 + self.in_fields = [] + self.out_fields = [] + + if rtype is not None: + args.append(("ret", rtype)) + + self.dir = [] + self.nullable = [] + self.array_of_p = [] + + for i, (name, field) in enumerate(self.args): + align = 1 + + pfield = field + dir = "in" + + if name == "ret": + dir = "out" + + while isinstance(pfield, Subconstruct): + if isinstance(pfield, InPtr): + dir = "in" + elif isinstance(pfield, OutPtr): + dir = "out" + elif isinstance(pfield, (InOut, InOutPtr)): + dir = "inout" + pfield = pfield.subcon + if isinstance(pfield, FormatField): + align = min(4, pfield.length) + + if dir in ("in", "inout"): + #if in_size % align: + #self.in_fields.append(Padding(align - (in_size % align))) + #in_size += align - (in_size % align) + + self.in_fields.append(name / field) + in_size += field.sizeof() + + if dir in ("out", "inout"): + #if out_size % align: + #self.out_fields.append(Padding(align - (out_size % align))) + #out_size += align - (out_size % align) + + self.out_fields.append(name / field) + out_size += field.sizeof() + + 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: + 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))) + if out_size % 4: + self.out_fields.append(Padding(4 - (out_size % 4))) + + 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 = [] + + for i, (name, field) in enumerate(self.args): + if name == "ret": + continue + + dir = self.dir[i] + nullable = self.nullable[i] + + val = self.get_field_val(i, in_vals, out_vals, nullobj=NULL) + + if val is not None: + if self.is_long(val): + s.append(f"{name}=...") + elif isinstance(val, ListContainer): + s.append(f"{name}={list(val)!r}") + else: + s.append(f"{name}={val!r}") + elif dir == "out": + s.append(f"{name}=<out>") + else: + s.append(f"{name}=?") + + return ", ".join(s) + + def print_long_args(self, indent, in_vals, out_vals=None): + for i, (name, field) in enumerate(self.args): + if name == "ret": + continue + + val = self.get_field_val(i, in_vals, out_vals, nullobj=NULL) + + if name in in_vals and out_vals is not None and name not in out_vals: + continue + + if self.is_long(val): + hdr = f"{indent} {name} = " + if isinstance(val, (ListContainer, Container)): + print(hdr + str(val).replace("\n", "\n" + indent)) + elif isinstance(val, bytes): + print(hdr + f"({len(val):#x} bytes)") + chexdump(val, indent=indent + " ") + else: + dindent = " " * len(hdr) + if isinstance(val, dict) and "_io" in val: + del val["_io"] + print(hdr + pprint.pformat(val, sort_dicts=False).replace("\n", "\n" + dindent)) + + def is_long(self, arg): + if isinstance(arg, (list, bytes)): + return len(arg) > 4 or any(self.is_long(i) for i in arg) + + return isinstance(arg, (dict, list, bytes)) + + def parse_input(self, data): + vals = self.in_struct.parse(data) + + return Container({ k: v() if callable(v) else v for k,v in vals.items() }) + + def parse_output(self, data, in_vals): + context = dict(in_vals) + + if "data" in context: + del context["data"] + + vals = self.out_struct.parse(data, **context) + + 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: + sizeof = f.sizeof() + print(f"{off:#x}: {f} ({sizeof:#x})") + off += sizeof + +class Call(Method): + pass + +class Callback(Method): + pass + +int8_t = Int8sl +uint8_t = Int8ul +int16_t = Int16sl +uint16_t = Int16ul +int32_t = Int32sl +uint32_t = Int32ul +int64_t = Int64sl +uint64_t = Int64ul + +uint = uint32_t +int_ = int32_t +ulong = uint64_t +long_ = int64_t + +void = None + +class IPCObject: + @classmethod + def methods(cls): + ret = {} + for c in cls.mro(): + ret.update({k: (cls, v) for k, v in cls.__dict__.items() if isinstance(v, Method)}) + + return ret + +rt_bw_config_t = Struct( + "unk1" / UnkBytes(8), + "reg1" / Int64ul, + "reg2" / Int64ul, + "unk2" / UnkBytes(4), + "bit" / Int32ul, + "padding" / UnkBytes(0x1c), +) + +IOUserClient = Struct( + "addr" / Hex(Int64ul), + "unk" / Int32ul, + "flag1" / Int8ul, + "flag2" / Int8ul, + Padding(2) +) + +IOMobileFramebufferUserClient = IOUserClient + +IOMFBStatus = Int32ul +IOMFBParameterName = Int32ul + +BufferDescriptor = uint64_t + +SwapCompleteData = Bytes(0x12) +SwapInfoBlob = Bytes(0x6c4) + +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_2e2" / UnkBytes(0x2), + "bl_unk" / Hex(Int64ul), # seen: 0x0, 0x1, 0x101, 0x1_0000, 0x101_010101 + "bl_val" / Hex(Int32ul), # range 0x10000000 - approximately 0x7fe07fc0 for 4 - 510 nits + "bl_power" / Hex(Int8ul), # constant 0x40, 0x00: backlight off + "unk_2f3" / UnkBytes(0x2d), +) + +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), +) + +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), + "xfer_func" / Int8ul, + "colorspace" / 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), +) + +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(14, uint)) + A035 = Call(bool_, "is_hilo") + A036 = Call(bool_, "apt_supported") + A037 = Call(uint, "get_dfb_info", InOutPtr(uint), InOutPtr(Array(4, ulong)), InOutPtr(uint)) + A038 = Call(uint, "get_dfb_compression_info", InOutPtr(uint)) + + D000 = Callback(bool_, "did_boot_signal") + D001 = Callback(bool_, "did_power_on_signal") + D002 = Callback(void, "will_power_off_signal") + D003 = Callback(void, "rt_bandwidth_setup_ap", config=OutPtr(rt_bw_config_t)) + +IdleCachingState = uint32_t + +class UnifiedPipeline2(IPCObject): + A352 = Call(bool_, "applyProperty", uint, uint) + A353 = Call(uint, "get_system_type") + 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") + D102 = Callback(void, "set_number_property", key=string(0x40), value=uint) + D103 = Callback(void, "set_boolean_property", key=string(0x40), value=bool_) + D106 = Callback(void, "removeProperty", key=string(0x40)) + D107 = Callback(bool_, "create_provider_service") + D108 = Callback(bool_, "create_product_service") + D109 = Callback(bool_, "create_PMU_service") + D110 = Callback(bool_, "create_iomfb_service") + D111 = Callback(bool_, "create_backlight_service") + D112 = Callback(void, "set_idle_caching_state_ap", IdleCachingState, uint) + D116 = Callback(bool_, "start_hardware_boot") + D117 = Callback(bool_, "is_dark_boot") + 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)))) + + 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): + A102 = Call(uint64_t, "test_control", cmd=uint64_t, arg=uint) + A103 = Call(void, "get_config_frame_size", width=InOutPtr(uint), height=InOutPtr(uint)) + A104 = Call(void, "set_config_frame_size", width=uint, height=uint) + A105 = Call(void, "program_config_frame_size") + A130 = Call(bool_, "init_ca_pmu") + A131 = Call(bool_, "pmu_service_matched") + A132 = Call(bool_, "backlight_service_matched") + + D201 = Callback(uint32_t, "map_buf", buf=InPtr(BufferDescriptor), vaddr=OutPtr(ulong), dva=OutPtr(ulong), unk=bool_) + D202 = Callback(void, "unmap_buf", buf=InPtr(BufferDescriptor), unk1=uint, unk2=ulong, unkB=uint) + + D206 = Callback(bool_, "match_pmu_service_2") + D207 = Callback(bool_, "match_backlight_service") + D208 = Callback(uint64_t, "get_calendar_time_ms") + D211 = Callback(void, "update_backlight_factor_prop", int_) + +class PropRelay(IPCObject): + 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", swap_id=InOutPtr(uint), client=InOutPtr(IOUserClient)) + A408 = Call(uint32_t, "swap_submit_dcp", + swap_rec=InPtr(IOMFBSwapRec), + 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) + A413 = Call(uint32_t, "get_digital_out_state", InOutPtr(uint)) + A414 = Call(uint32_t, "get_display_area", InOutPtr(ulong)) + A419 = Call(uint32_t, "get_gamma_table", InOutPtr(Bytes(0xc0c))) + A422 = Call(uint32_t, "set_matrix", uint, InPtr(Array(3, Array(3, ulong)))) + A423 = Call(uint32_t, "set_contrast", InOutPtr(Float32l)) + A426 = Call(uint32_t, "get_color_remap_mode", InOutPtr(uint32_t)) + 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) + A439 = Call(uint32_t, "set_parameter_dcp", param=IOMFBParameterName, value=Lazy(SizedArray(4, "count", ulong)), count=uint) + + 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") + A455 = Call(void, "last_client_close_dcp", OutPtr(uint)) + A456 = Call(bool_, "writeDebugInfo", ulong) + A457 = Call(void, "flush_debug_flags", uint) + A458 = Call(bool_, "io_fence_notify", uint, uint, ulong, IOMFBStatus) + A460 = Call(bool_, "setDisplayRefreshProperties") + A463 = Call(void, "flush_supportsPower", bool_) + A464 = Call(uint, "abort_swaps_dcp", InOutPtr(IOMobileFramebufferUserClient)) + + A467 = Call(uint, "update_dfb", surf=InPtr(IOSurface)) + A468 = Call(uint32_t, "setPowerState", ulong, bool_, OutPtr(uint)) + A469 = Call(bool_, "isKeepOnScreen") + + 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_) + + D575 = Callback(bool_, "get_dot_pitch", OutPtr(uint)) + D576 = Callback(void, "hotPlug_notify_gated", ulong) + D577 = Callback(void, "powerstate_notify", bool_, bool_) + D578 = Callback(bool_, "idle_fence_create", IdleCachingState) + D579 = Callback(void, "idle_fence_complete") + + D581 = Callback(void, "swap_complete_head_of_line", uint, bool_, uint, bool_) + D582 = Callback(bool_, "create_default_fb_surface", uint, uint) + D583 = Callback(bool_, "serializeDebugInfoCb", ulong, InPtr(uint64_t), uint) + D584 = Callback(void, "clear_default_surface") + + D588 = Callback(void, "resize_default_fb_surface_gated") + D589 = Callback(void, "swap_complete_ap_gated", swap_id=uint, unkBool=bool_, swap_data=InPtr(SwapCompleteData), swap_info=SwapInfoBlob, unkUint=uint) + + D591 = Callback(void, "swap_complete_intent_gated", swap_id=uint, unkB=bool_, unkInt=uint32_t, width=uint, height=uint) + D593 = Callback(void, "enable_backlight_message_ap_gated", bool_) + D594 = Callback(void, "setSystemConsoleMode", bool_) + + D596 = Callback(bool_, "isDFBAllocated") + D597 = Callback(bool_, "preserveContents") + D598 = Callback(void, "find_swap_function_gated") + +class ServiceRelay(IPCObject): + D400 = Callback(void, "get_property", obj=FourCC, key=string(0x40), value=OutPtr(Bytes(0x200)), lenght=InOutPtr(uint)) + D401 = Callback(bool_, "sr_get_uint_prop", obj=FourCC, key=string(0x40), value=InOutPtr(ulong)) + D404 = Callback(void, "sr_set_uint_prop", obj=FourCC, key=string(0x40), value=uint) + D406 = Callback(void, "set_fx_prop", obj=FourCC, key=string(0x40), value=uint) + 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))) + +mem_desc_id = uint + +class MemDescRelay(IPCObject): + D451 = Callback(mem_desc_id, "allocate_buffer", uint, ulong, uint, OutPtr(ulong), OutPtr(ulong), OutPtr(ulong)) + D452 = Callback(mem_desc_id, "map_physical", paddr=ulong, size=ulong, flags=uint, dva=OutPtr(ulong), dvasize=OutPtr(ulong)) + D453 = Callback(mem_desc_id, "withAddressRange", ulong, ulong, uint, uint64_t, OutPtr(uint), OutPtr(ulong)) + D454 = Callback(IOMFBStatus, "prepare", uint, uint) + D455 = Callback(IOMFBStatus, "complete", uint, uint) + D456 = Callback(bool_, "release_descriptor", uint) + +ALL_CLASSES = [ + UPPipeAP_H13P, + UnifiedPipeline2, + IOMobileFramebufferAP, + ServiceRelay, + PropRelay, + UPPipe2, + MemDescRelay, +] + +ALL_METHODS = {} + +for cls in ALL_CLASSES: + ALL_METHODS.update(cls.methods()) + +SHORT_CHANNELS = { + "CB": "d", + "CMD": "C", + "ASYNC": "a", + "OOBCMD": "O", + "OOBCB": "o", +} + +RDIR = { ">": "<", "<": ">" } + +class Call: + def __init__(self, dir, chan, off, msg, in_size, out_size, in_data=b''): + self.dir = dir + self.chan = chan + self.msg = msg + self.off = off + self.in_size = in_size + self.out_size = out_size + self.in_data = in_data + self.out_data = None + self.complete = False + self.ret = None + + def ack(self, out_data): + self.out_data = out_data + self.complete = True + + def print_req(self, indent=""): + log = f"{indent}{self.dir}{SHORT_CHANNELS[self.chan]}[{self.off:#x}] {self.msg} " + + cls, method = ALL_METHODS.get(self.msg, (None, None)) + if cls is None: + print(log + f"{self.in_size:#x}/{self.out_size:#x}") + return + + log += f"{cls.__name__}::{method.name}(" + in_size = method.in_struct.sizeof() + + if in_size != len(self.in_data): + print(f"{log} !! Expected {in_size:#x} bytes, got {len(self.in_data):#x} bytes (in)") + dump_fields(method.in_fields) + chexdump(self.in_data) + self.in_vals = {} + return + + self.in_vals = method.parse_input(self.in_data) + + log += f"{method.fmt_args(self.in_vals)})" + + print(log) + + method.print_long_args(indent, self.in_vals) + #if method.in_fields: + #print(self.in_vals) + + def print_reply(self, indent=""): + assert self.complete + log = f"{indent}{RDIR[self.dir]}{SHORT_CHANNELS[self.chan]}[{self.off:#x}] {self.msg} " + + cls, method = ALL_METHODS.get(self.msg, (None, None)) + if cls is None: + print(log + f"{self.in_size:#x}/{self.out_size:#x}") + return + + log += f"{cls.__name__}::{method.name}(" + out_size = method.out_struct.sizeof() + + if out_size != len(self.out_data): + print(f"{log} !! Expected {out_size:#x} bytes, got {len(self.out_data):#x} bytes (out)") + dump_fields(method.out_fields) + chexdump(self.out_data) + return + + self.out_vals = method.parse_output(self.out_data, self.in_vals) + + log += f"{method.fmt_args(self.in_vals, self.out_vals)})" + + if "ret" in self.out_vals: + self.ret = self.out_vals.ret + del self.out_vals["ret"] + log += f" = {self.ret!r}" + + print(log) + + method.print_long_args(indent, self.in_vals, self.out_vals) + #if len(method.out_fields) - (self.ret is not None): + #print(self.out_vals) |
