From b8f07d3929f82c973bb6d19767118a781daf8d3f Mon Sep 17 00:00:00 2001 From: Hector Martin Date: Sat, 31 Jul 2021 12:51:26 +0900 Subject: [PATCH] wtf --- proxyclient/experiments/dart_dcp_test.py | 22 ++ proxyclient/experiments/dcp.py | 475 +++++++++++++++++++++++ proxyclient/experiments/dispdump.py | 30 ++ proxyclient/hv/trace_dcp.py | 45 +-- proxyclient/m1n1/adt.py | 3 + proxyclient/m1n1/fw/asc/__init__.py | 68 ++++ proxyclient/m1n1/fw/asc/base.py | 53 +++ proxyclient/m1n1/fw/asc/crash.py | 41 ++ proxyclient/m1n1/fw/asc/ioreporting.py | 50 +++ proxyclient/m1n1/fw/asc/kdebug.py | 38 ++ proxyclient/m1n1/fw/asc/mgmt.py | 112 ++++++ proxyclient/m1n1/fw/asc/oslog.py | 30 ++ proxyclient/m1n1/fw/asc/syslog.py | 70 ++++ proxyclient/m1n1/fw/dcp/client.py | 10 + proxyclient/m1n1/fw/dcp/dcpep.py | 162 ++++++++ proxyclient/m1n1/fw/dcp/ipc.py | 314 +++++++++++---- proxyclient/m1n1/fw/dcp/manager.py | 211 ++++++++++ proxyclient/m1n1/fw/dcp/parse_log.py | 16 +- proxyclient/m1n1/hv.py | 5 +- proxyclient/m1n1/hw/asc.py | 88 +++++ proxyclient/m1n1/hw/dart.py | 99 ++++- proxyclient/m1n1/proxy.py | 3 + proxyclient/m1n1/trace/asc.py | 76 +--- proxyclient/m1n1/utils.py | 27 +- src/hv_exc.c | 2 + 25 files changed, 1877 insertions(+), 173 deletions(-) create mode 100644 proxyclient/experiments/dart_dcp_test.py create mode 100644 proxyclient/experiments/dcp.py create mode 100755 proxyclient/experiments/dispdump.py create mode 100644 proxyclient/m1n1/fw/asc/__init__.py create mode 100644 proxyclient/m1n1/fw/asc/base.py create mode 100644 proxyclient/m1n1/fw/asc/crash.py create mode 100644 proxyclient/m1n1/fw/asc/ioreporting.py create mode 100644 proxyclient/m1n1/fw/asc/kdebug.py create mode 100644 proxyclient/m1n1/fw/asc/mgmt.py create mode 100644 proxyclient/m1n1/fw/asc/oslog.py create mode 100644 proxyclient/m1n1/fw/asc/syslog.py create mode 100644 proxyclient/m1n1/fw/dcp/client.py create mode 100644 proxyclient/m1n1/fw/dcp/dcpep.py create mode 100644 proxyclient/m1n1/fw/dcp/manager.py create mode 100644 proxyclient/m1n1/hw/asc.py diff --git a/proxyclient/experiments/dart_dcp_test.py b/proxyclient/experiments/dart_dcp_test.py new file mode 100644 index 00000000..acc42914 --- /dev/null +++ b/proxyclient/experiments/dart_dcp_test.py @@ -0,0 +1,22 @@ +#!/usr/bin/env python3 +# SPDX-License-Identifier: MIT +import sys, pathlib +sys.path.append(str(pathlib.Path(__file__).resolve().parents[1])) + +import struct + +from m1n1.setup import * +from m1n1 import asm +from m1n1.hw.dart import DART, DARTRegs + +dart_addr = u.adt["arm-io/dart-dcp"].get_reg(0)[0] +disp0 = DART(iface, DARTRegs(u, dart_addr), u) +disp0.dump_all() +disp0.regs.dump_regs() + +buf = u.memalign(16384, 65536) + +disp0.iomap(0, 0x08010000, buf, 65536) +assert disp0.iotranslate(0, 0x08010000, 65536) == [(buf, 65536)] + +disp0.dump_all() diff --git a/proxyclient/experiments/dcp.py b/proxyclient/experiments/dcp.py new file mode 100644 index 00000000..c62d7704 --- /dev/null +++ b/proxyclient/experiments/dcp.py @@ -0,0 +1,475 @@ +#!/usr/bin/env python3 +# SPDX-License-Identifier: MIT +import sys, pathlib +sys.path.append(str(pathlib.Path(__file__).resolve().parents[1])) + +import struct + +from m1n1.setup import * +from m1n1.shell import run_shell +from m1n1 import asm +from m1n1.hw.dart import DART, DARTRegs +from m1n1.fw.dcp.client import DCPClient +from m1n1.fw.dcp.manager import DCPManager +from m1n1.fw.dcp.ipc import ByRef +from m1n1.proxyutils import RegMonitor + +mon = RegMonitor(u) + +#mon.add(0x230000000, 0x18000) +#mon.add(0x230018000, 0x4000) +#mon.add(0x230068000, 0x8000) +#mon.add(0x2300b0000, 0x8000) +#mon.add(0x2300f0000, 0x4000) +#mon.add(0x230100000, 0x10000) +#mon.add(0x230170000, 0x10000) +#mon.add(0x230180000, 0x1c000) +#mon.add(0x2301a0000, 0x10000) +#mon.add(0x2301d0000, 0x4000) +#mon.add(0x230230000, 0x10000) +#mon.add(0x23038c000, 0x10000) +#mon.add(0x230800000, 0x10000) +#mon.add(0x230840000, 0xc000) +#mon.add(0x230850000, 0x2000) +##mon.add(0x230852000, 0x5000) # big curve / gamma table +#mon.add(0x230858000, 0x18000) +#mon.add(0x230870000, 0x4000) +#mon.add(0x230880000, 0x8000) +#mon.add(0x230894000, 0x4000) +#mon.add(0x2308a8000, 0x8000) +#mon.add(0x2308b0000, 0x8000) +#mon.add(0x2308f0000, 0x4000) +##mon.add(0x2308fc000, 0x4000) # stats / RGB color histogram +#mon.add(0x230900000, 0x10000) +#mon.add(0x230970000, 0x10000) +#mon.add(0x230980000, 0x10000) +#mon.add(0x2309a0000, 0x10000) +#mon.add(0x2309d0000, 0x4000) +#mon.add(0x230a30000, 0x20000) +#mon.add(0x230b8c000, 0x10000) +#mon.add(0x231100000, 0x8000) +#mon.add(0x231180000, 0x4000) +#mon.add(0x2311bc000, 0x10000) +#mon.add(0x231300000, 0x8000) +##mon.add(0x23130c000, 0x4000) # - DCP dart +#mon.add(0x231310000, 0x8000) +#mon.add(0x231340000, 0x8000) +##mon.add(0x231800000, 0x8000) # breaks DCP +##mon.add(0x231840000, 0x8000) # breaks DCP +##mon.add(0x231850000, 0x8000) # something DCP? +##mon.add(0x231920000, 0x8000) # breaks DCP +##mon.add(0x231960000, 0x8000) # breaks DCP +##mon.add(0x231970000, 0x10000) # breaks DCP +##mon.add(0x231c00000, 0x10000) # DCP mailbox + +mon.add(0x230845840, 0x40) # error regs + +mon.poll() + +dart_addr = u.adt["arm-io/dart-dcp"].get_reg(0)[0] +dart = DART(iface, DARTRegs(u, dart_addr), u) + +disp_dart_addr = u.adt["arm-io/dart-disp0"].get_reg(0)[0] +disp_dart = DART(iface, DARTRegs(u, disp_dart_addr), u) + +disp_dart.dump_all() + +dcp_addr = u.adt["arm-io/dcp"].get_reg(0)[0] +dcp = DCPClient(u, dcp_addr, dart) + +dcp.start() +dcp.start_ep(0x37) +dcp.dcpep.initialize() + +mgr = DCPManager(dcp.dcpep) + +mon.poll() + +mgr.start_signal() + +mon.poll() + +mgr.get_color_remap_mode(6) +mgr.enable_disable_video_power_savings(0) + +mgr.update_notify_clients_dcp([0,0,0,0,0,0,1,1,1,0,1,1,1]) +mgr.first_client_open() +print(f"keep on: {mgr.isKeepOnScreen()}") +print(f"main display: {mgr.is_main_display()}") +assert mgr.setPowerState(1, False, ByRef(0)) == 0 + +mon.poll() + +assert mgr.set_display_device(2) == 0 +assert mgr.set_parameter_dcp(14, [0], 1) == 0 +#mgr.set_digital_out_mode(86, 38) + +assert mgr.set_display_device(2) == 0 +assert mgr.set_parameter_dcp(14, [0], 1) == 0 +#mgr.set_digital_out_mode(89, 38) + +t = ByRef(b"\x00" * 0xc0c) +assert mgr.get_gamma_table(t) == 2 +assert mgr.set_contrast(0) == 0 +assert mgr.setBrightnessCorrection(65536) == 0 + +assert mgr.set_display_device(2) == 0 +assert mgr.set_parameter_dcp(14, [0], 1) == 0 +#mgr.set_digital_out_mode(89, 72) + +mon.poll() + +# arg: IOUserClient +swapid = ByRef(0) +ret = mgr.swap_start(swapid, { + "addr": 0xFFFFFE1667BA4A00, + "unk": 0, + "flag1": 0, + "flag2": 1 +}) +assert ret == 0 +print(f"swap ID: {swapid.val:#x}") + +mgr.set_matrix(9, [[1<<32, 0, 0], + [0, 1<<32, 0], + [0, 0, 1<<32]]) +mgr.setBrightnessCorrection(65536) +mgr.set_parameter_dcp(3, [65536], 1) +mgr.set_parameter_dcp(6, [65536], 1) + +swap_rec = unhex(f""" +/*000*/ 2e 9e fe 55 00 00 00 00 dd 3e 6b 6b 00 00 00 00 +/*010*/ 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +/*020*/ f6 7f be 5d fe ca 99 00 00 00 00 00 00 00 00 00 +/*030*/ 65 bb 81 6b 00 00 00 00 00 00 00 00 00 00 00 00 +/*040*/ 02 12 86 00 00 00 00 00 04 00 00 00 00 00 00 00 + +/* swap id */ + {swapid.val:02x} 00 00 00 + +/* 54: surface ids */ + 03 00 00 00 12 00 00 00 00 00 00 00 00 00 00 00 + +/* 64: surface dimensions */ +/* w h */ +00 00 00 00 00 00 00 00 80 07 00 00 38 04 00 00 +00 00 00 00 00 00 00 00 80 00 00 00 80 00 00 00 +00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 + +/* a4: valid flags ? */ + 01 00 00 00 01 00 00 00 00 00 00 00 00 00 00 00 + +/* b4: unk */ + 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 + +/* surface rects */ +/* x y w h */ + 00 00 00 00 00 00 00 00 80 07 00 00 38 04 00 00 + 00 01 00 00 00 01 00 00 80 00 00 00 80 00 00 00 + 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 + 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 + +/*100*/ 07 00 00 80 07 00 00 80 00 00 00 ff +/* enabled.... completed.. */ + +/*110*/ 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +""") + b"\x00" * (0x2c0 - 0x120) + unhex(""" + 00 00 00 00 00 00 00 00 00 00 00 01 00 00 00 00 + 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 + 00 00 00 01 00 00 00 00 00 00 00 00 00 00 00 00 +""") + b"\x00" * (0x320 - 0x2f0) + +swap_rec = unhex(f""" +/*000*/ 2e 9e fe 55 00 00 00 00 dd 3e 6b 6b 00 00 00 00 +/*010*/ 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +/*020*/ f6 7f be 5d fe ca 99 00 00 00 00 00 00 00 00 00 +/*030*/ 65 bb 81 6b 00 00 00 00 00 00 00 00 00 00 00 00 +/*040*/ 02 12 86 00 00 00 00 00 04 00 00 00 00 00 00 00 + +/* swap id */ + {swapid.val:02x} 00 00 00 + +/* 54: surface ids */ + 03 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 + +/* 64: src rects */ +/* w h */ +00 00 00 00 00 00 00 00 80 07 00 00 38 04 00 00 +00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 + +/* a4: valid flags ? */ + 01 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 + +/* b4: unk */ + 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 + +/* dst rects */ +/* x y w h */ + 00 00 00 00 00 00 00 00 80 07 00 00 38 04 00 00 + 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 + 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 + 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 + +/*100*/ 07 00 00 80 07 00 00 80 00 00 00 ff +/* enabled.... completed.. */ + +/*110*/ 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +""") + b"\x00" * (0x2c0 - 0x120) + unhex(""" + 00 00 00 00 00 00 00 00 00 00 00 01 00 00 00 00 + 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 + 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +""") + b"\x00" * (0x320 - 0x2f0) + + +assert len(swap_rec) == 0x320 + +chexdump(swap_rec) + +surf_mouse = unhex(""" + 00 00 00 00 + 00 00 00 00 + 00 00 00 + + /* format */ + 41 52 47 42 + 00 00 00 00 + 0D 01 00 02 + 00 00 04 00 + 01 01 00 00 + 00 00 + + 80 00 00 00 /* plane width */ + 80 00 00 00 /* plane height */ + 00 00 01 00 /* plane size in bytes */ + 00 00 00 00 + + 00 00 00 00 + 12 00 00 00 + 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 + 00 00 00 00 00 00 00 00 + + 01 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 + 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 + 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 + 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 + 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 + 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 + 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 + 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 + 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 + 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 + 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 + 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 + 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 + 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 + 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 + 00 00 00 00 00 00 00 00 01 00 00 00 00 00 00 00 + 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 + 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 + 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 + 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 + 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 + 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 + 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 + 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 + 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 + 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 + 00 00 00 00 00 00 00 00 00 00 00 00 AA AA AA AA + AA AA AA +""") + +surf_argb = unhex(""" + 00 00 00 00 + 00 00 00 00 + 00 00 00 + + /* format */ + 41 52 47 42 + 00 00 00 00 + 0D 01 + + 00 1e 00 00 /* stride */ + + 04 00 + 01 01 00 00 + 00 00 + + 80 07 00 00 /* plane width */ + 38 04 00 00 /* plane height */ + 00 90 7e 00 /* plane size in bytes */ + 00 00 00 00 + + 00 00 00 00 + 03 00 00 00 + 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 + 00 00 00 00 00 00 00 00 + + 01 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 + 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 + 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 + 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 + 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 + 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 + 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 + 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 + 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 + 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 + 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 + 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 + 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 + 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 + 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 + 00 00 00 00 00 00 00 00 01 00 00 00 00 00 00 00 + 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 + 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 + 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 + 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 + 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 + 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 + 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 + 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 + 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 + 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 + 00 00 00 00 00 00 00 00 00 00 00 00 AA AA AA AA + AA AA AA +""") + +surf = unhex(""" + 00 00 00 02 + 00 00 00 02 + 00 00 00 + + /* format */ + 38 33 62 26 + + 00 00 00 00 + 0D 02 80 07 + 00 00 01 00 + 01 01 00 00 + 00 00 + + 80 07 00 00 /* plane width */ + 38 04 00 00 /* plane height */ + 00 60 A3 00 /* plane size in bytes */ + 00 00 00 00 00 00 00 00 03 00 00 00 00 AA AA AA AA AA AA + AA 00 AA AA AA AA AA AA AA + + 00 00 00 00 00 00 00 00 01 00 00 00 00 00 00 00 + + 80 07 00 00 /* plane width (compressed only?) */ + 38 04 00 00 /* plane height (compressed only?) */ + 00 00 00 00 00 00 00 00 + + 00 E0 01 00 00 80 81 + 00 00 04 10 10 AA AA AA AA AA AA AA AA AA AA AA + AA AA 05 AA AA AA AA AA AA AA AA AA AA AA AA AA + AA AA AA AA AA AA AA AA AA AA AA AA AA AA AA AA + AA AA AA AA AA AA AA AA AA 80 07 00 00 38 04 00 + 00 00 80 81 00 00 80 81 00 00 78 00 00 00 E0 21 + 00 00 01 10 10 AA AA AA AA AA AA AA AA AA AA AA + AA AA 05 AA AA AA AA AA AA AA AA AA AA AA AA AA + AA AA AA AA AA AA AA AA AA AA AA AA AA AA AA AA + AA AA AA AA AA AA AA AA AA 00 00 00 00 00 00 00 + 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 + 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 + 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 + 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 + 00 00 00 00 00 00 00 00 00 01 00 00 00 00 00 00 + 00 10 00 00 00 10 00 00 00 00 80 7F 00 00 00 00 + 00 08 00 00 00 78 00 00 00 44 00 00 00 00 00 00 + 00 03 00 00 00 00 00 00 00 AA AA AA 00 04 00 00 + 00 E0 01 00 AA 10 00 00 00 10 00 00 00 00 60 A1 + 00 00 80 81 00 08 00 00 00 78 00 00 00 44 00 00 + 00 00 00 00 00 03 00 00 00 00 00 00 00 AA AA AA + 00 01 00 00 00 78 00 00 AA 10 00 00 00 10 00 00 + 00 00 60 A1 00 00 80 81 00 08 00 00 00 78 00 00 + 00 44 00 00 00 00 00 00 00 03 00 00 00 00 00 00 + 00 AA AA AA 00 01 00 00 00 78 00 00 AA 01 00 00 + 00 00 00 00 00 00 00 10 00 00 00 10 00 AA AA AA + AA AA AA AA +""") + +surf = unhex(""" +00 00 00 02 00 00 00 02 00 00 00 38 33 62 26 00 +00 00 00 0D 02 80 07 00 00 01 00 01 01 00 80 A3 +00 80 07 00 00 38 04 00 00 00 60 A3 00 00 00 00 +00 00 00 00 00 05 00 00 00 00 AA AA AA AA AA AA +AA 00 AA AA AA AA AA AA AA 00 00 00 00 00 00 00 +00 01 00 00 00 00 00 00 00 80 07 00 00 38 04 00 +00 00 00 00 00 00 00 00 00 00 E0 01 00 00 80 81 +00 00 04 10 10 AA AA AA AA AA AA AA AA AA AA AA +AA AA 05 AA AA AA AA AA AA AA AA AA AA AA AA AA +AA AA AA AA AA AA AA AA AA AA AA AA AA AA AA AA +AA AA AA AA AA AA AA AA AA 80 07 00 00 38 04 00 +00 00 80 81 00 00 80 81 00 00 78 00 00 00 E0 21 +00 00 01 10 10 AA AA AA AA AA AA AA AA AA AA AA +AA AA 05 AA AA AA AA AA AA AA AA AA AA AA AA AA +AA AA AA AA AA AA AA AA AA AA AA AA AA AA AA AA +AA AA AA AA AA AA AA AA AA 00 00 00 00 00 00 00 +00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +00 00 00 00 00 00 00 00 00 01 00 00 00 00 00 00 +00 10 00 00 00 10 00 00 00 00 80 7F 00 00 00 00 +00 08 00 00 00 78 00 00 00 44 00 00 00 00 00 00 +00 03 00 00 00 00 00 00 00 AA AA AA 00 04 00 00 +00 E0 01 00 AA 10 00 00 00 10 00 00 00 00 60 A1 +00 00 80 81 00 08 00 00 00 78 00 00 00 44 00 00 +00 00 00 00 00 03 00 00 00 00 00 00 00 AA AA AA +00 01 00 00 00 78 00 00 AA 10 00 00 00 10 00 00 +00 00 60 A1 00 00 80 81 00 08 00 00 00 78 00 00 +00 44 00 00 00 00 00 00 00 03 00 00 00 00 00 00 +00 AA AA AA 00 01 00 00 00 78 00 00 AA 01 00 00 +00 00 00 00 00 00 00 10 00 00 00 10 00 AA AA AA +AA AA AA AA +""") + +assert len(surf) == 0x204 +assert len(surf_mouse) == 0x204 + +surfaces = [surf_argb, None, None, None] +surfAddr = [0x7e0000, 0, 0, 0] + +outB = ByRef(False) + +swaps = mgr.swaps + +mon.poll() + +buf = u.memalign(0x4000, 16<<20) + +#iface.writemem(buf, open("fb0.bin", "rb").read()) + +p.memset8(buf, 0, 16<<20) +p.memset8(buf, 0xff, 65536) + +iface.writemem(buf, open("cur1.bin", "rb").read()) + +disp_dart.iomap_at(0, 0x7e0000, buf, 16<<20) + +disp_dart.regs.dump_regs() + +ret = mgr.swap_submit_dcp(swap_rec=swap_rec, surfaces=surfaces, surfAddr=surfAddr, + unkBool=False, unkFloat=0.0, unkInt=0, unkOutBool=outB) +print(f"swap returned {ret} / {outB}") + +time.sleep(0.2) + +mon.poll() +dcp.work() +mon.poll() +dcp.work() +mon.poll() + +disp_dart.regs.dump_regs() + +#while swaps == mgr.swaps: + #dcp.work() + +print("swap complete!") + +run_shell(globals(), msg="Have fun!") diff --git a/proxyclient/experiments/dispdump.py b/proxyclient/experiments/dispdump.py new file mode 100755 index 00000000..ebd4d49d --- /dev/null +++ b/proxyclient/experiments/dispdump.py @@ -0,0 +1,30 @@ +#!/usr/bin/env python3 +# SPDX-License-Identifier: MIT +import sys, pathlib +sys.path.append(str(pathlib.Path(__file__).resolve().parents[1])) + +from m1n1.setup import * + +blacklist = [] + +print("Dumping address space...") +of = None +if len(sys.argv) > 1: + of = open(sys.argv[1],"w") + print("Also dumping to file %s") + +p.iodev_set_usage(IODEV.FB, 0) + +for i in range(0x230000000, 0x232000000, 0x4000): + if i in blacklist: + v = "%08x: SKIPPED"%(i<<16) + else: + a = i + d = p.read32(a) + v = "%08x: %08x"%(a, d) + print(v) + if of: + of.write(v+"\n") + +if of: + of.close() diff --git a/proxyclient/hv/trace_dcp.py b/proxyclient/hv/trace_dcp.py index 474b5f33..df18dd71 100644 --- a/proxyclient/hv/trace_dcp.py +++ b/proxyclient/hv/trace_dcp.py @@ -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) @@ -716,4 +707,4 @@ iomon.readmem = readmem_iova dcp_tracer = DCPTracer(hv, "/arm-io/dcp", verbose=1) dcp_tracer.start(dart_dcp_tracer.dart) -#dcp_tracer.ep.dcpep.state.dumpfile = open("dcp.log", "a") +dcp_tracer.ep.dcpep.state.dumpfile = open("dcp.log", "a") diff --git a/proxyclient/m1n1/adt.py b/proxyclient/m1n1/adt.py index 0d1ecb2d..be264326 100644 --- a/proxyclient/m1n1/adt.py +++ b/proxyclient/m1n1/adt.py @@ -238,6 +238,9 @@ class ADTNode: t + "}" ]) + def __repr__(self): + return f"" + def __iter__(self): return iter(self._children) diff --git a/proxyclient/m1n1/fw/asc/__init__.py b/proxyclient/m1n1/fw/asc/__init__.py new file mode 100644 index 00000000..e706724e --- /dev/null +++ b/proxyclient/m1n1/fw/asc/__init__.py @@ -0,0 +1,68 @@ +# SPDX-License-Identifier: MIT +from ...utils import * + +from .crash import ASCCrashLogEndpoint +from .syslog import ASCSysLogEndpoint +from .mgmt import ASCManagementEndpoint +from .kdebug import ASCKDebugEndpoint +from .ioreporting import ASCIOReportingEndpoint +from .oslog import ASCOSLogEndpoint +from .base import ASCBaseEndpoint +from ...hw.asc import ASC + +__all__ = [] + +class ASCDummyEndpoint(ASCBaseEndpoint): + SHORT = "dummy" + +class StandardASC(ASC): + ENDPOINTS = { + 0: ASCManagementEndpoint, + 1: ASCCrashLogEndpoint, + 2: ASCSysLogEndpoint, + 3: ASCKDebugEndpoint, + 4: ASCIOReportingEndpoint, + 8: ASCOSLogEndpoint, + 0xa: ASCDummyEndpoint, # tracekit + } + + def __init__(self, u, asc_base, dart): + super().__init__(u, asc_base) + self.remote_eps = set() + self.add_ep(0, ASCManagementEndpoint(self, 0)) + self.dart = dart + self.eps = [] + self.epcls = {} + + for cls in type(self).mro(): + eps = getattr(cls, "ENDPOINTS", None) + if eps is None: + break + for k, v in eps.items(): + if k not in self.epcls: + self.epcls[k] = v + + def iomap(self, addr, size): + return 0xf00000000 | self.dart.iomap(0, addr, size) + + def ioalloc(self, size): + paddr = self.u.memalign(0x4000, size) + dva = self.iomap(paddr, size) + return paddr, dva + + def start_ep(self, epno): + if epno not in self.epcls: + raise Exception(f"Unknown endpoint {epno:#x}") + + epcls = self.epcls[epno] + ep = epcls(self, epno) + self.add_ep(epno, ep) + print(f"Starting endpoint #{epno:#x} ({ep.name})") + self.mgmt.start_ep(epno) + ep.start() + + def start(self): + self.mgmt.start() + +__all__.extend(k for k, v in globals().items() + if (callable(v) or isinstance(v, type)) and v.__module__ == __name__) diff --git a/proxyclient/m1n1/fw/asc/base.py b/proxyclient/m1n1/fw/asc/base.py new file mode 100644 index 00000000..9db45916 --- /dev/null +++ b/proxyclient/m1n1/fw/asc/base.py @@ -0,0 +1,53 @@ +# SPDX-License-Identifier: MIT +from ...utils import * + +# System endpoints +def msg_handler(message, regtype=None): + def f(x): + x.is_message = True + x.message = message + x.regtype = regtype + return x + + return f + +class ASCMessage1(Register64): + EP = 7, 0 + +class ASCBaseEndpoint: + BASE_MESSAGE = Register64 + SHORT = None + + def __init__(self, asc, epnum, name=None): + self.asc = asc + self.epnum = epnum + self.name = name or self.SHORT or f"{type(self).__name__}@{epnum:#x}" + + self.msghandler = {} + self.msgtypes = {} + for name in dir(self): + i = getattr(self, name) + if not callable(i): + continue + if not getattr(i, "is_message", False): + continue + self.msghandler[i.message] = i + self.msgtypes[i.message] = i.regtype if i.regtype else self.BASE_MESSAGE + + def handle_msg(self, msg0, msg1): + msg0 = self.BASE_MESSAGE(msg0) + handler = self.msghandler.get(msg0.TYPE, None) + regtype = self.msgtypes.get(msg0.TYPE, self.BASE_MESSAGE) + + if handler is None: + return False + return handler(regtype(msg0.value)) + + def send(self, msg): + self.asc.send(msg, ASCMessage1(EP=self.epnum)) + + def start(self): + pass + + def log(self, msg): + print(f"[{self.name}] {msg}") diff --git a/proxyclient/m1n1/fw/asc/crash.py b/proxyclient/m1n1/fw/asc/crash.py new file mode 100644 index 00000000..8fa43b2d --- /dev/null +++ b/proxyclient/m1n1/fw/asc/crash.py @@ -0,0 +1,41 @@ +# SPDX-License-Identifier: MIT +from .base import * +from ...utils import * + +class CrashLogMessage(Register64): + TYPE = 63, 44 + +class CrashLog_TranslateDva(Register64): + TYPE = 63, 44, Constant(0x104) + ADDR = 43, 0 + +class CrashLog_Crashed(Register64): + TYPE = 63, 44, Constant(0x103) + DVA = 43, 0 + +class ASCCrashLogEndpoint(ASCBaseEndpoint): + SHORT = "crash" + BASE_MESSAGE = CrashLogMessage + + @msg_handler(0x104, CrashLog_TranslateDva) + def TranslateDva(self, msg): + ranges = self.asc.dart.iotranslate(0, msg.ADDR & 0xffffffff, 4096) + assert len(ranges) == 1 + self.crashbuf = ranges[0][0] + self.log(f"Translate {msg.ADDR:#x} -> {self.crashbuf:#x}") + self.send(CrashLog_TranslateDva(ADDR=self.crashbuf)) + return True + + def crash_soft(self): + self.send(0x40) + + def crash_hard(self): + self.send(0x22) + + @msg_handler(0x103, CrashLog_Crashed) + def Crashed(self, msg): + self.log(f"Crashed!") + crashdata = self.asc.dart.ioread(0, msg.DVA & 0xffffffff, 2048) + chexdump(crashdata) + + return True diff --git a/proxyclient/m1n1/fw/asc/ioreporting.py b/proxyclient/m1n1/fw/asc/ioreporting.py new file mode 100644 index 00000000..273a93f0 --- /dev/null +++ b/proxyclient/m1n1/fw/asc/ioreporting.py @@ -0,0 +1,50 @@ +# SPDX-License-Identifier: MIT +from .base import * +from ...utils import * + +class IOReportingMessage(Register64): + TYPE = 63, 52 + +class IOReporting_GetBuf(IOReportingMessage): + TYPE = 63, 52, Constant(1) + BUFTYPE = 51, 44, Constant(4) + DVA = 43, 0 + +class IOReporting_Start(IOReportingMessage): + TYPE = 63, 52, Constant(0xc) + +class IOReporting_Report(IOReportingMessage): + TYPE = 63, 52, Constant(0x8) + +class ASCIOReportingEndpoint(ASCBaseEndpoint): + BASE_MESSAGE = IOReportingMessage + SHORT = "iorep" + + def __init__(self, *args, **kwargs): + super().__init__(*args, **kwargs) + self.iobuffer = None + self.iobuffer_dva = None + + @msg_handler(1, IOReporting_GetBuf) + def GetBuf(self, msg): + if self.iobuffer: + self.log("WARNING: trying to reset iobuffer!") + + size = 0x4000 + self.iobuffer, self.iobuffer_dva = self.asc.ioalloc(size) + self.log(f"buf {self.iobuffer:#x} / {self.iobuffer_dva:#x}") + self.send(IOReporting_GetBuf(DVA=self.iobuffer_dva)) + return True + + @msg_handler(0xc, IOReporting_Start) + def Start(self, msg): + self.log("start") + return True + + @msg_handler(8, IOReporting_Report) + def Init(self, msg): + self.log("report!") + buf = self.asc.iface.readmem(self.iobuffer, 0x4000) + #chexdump(buf) + self.send(IOReporting_Report()) + return True diff --git a/proxyclient/m1n1/fw/asc/kdebug.py b/proxyclient/m1n1/fw/asc/kdebug.py new file mode 100644 index 00000000..fb4b8d29 --- /dev/null +++ b/proxyclient/m1n1/fw/asc/kdebug.py @@ -0,0 +1,38 @@ +# SPDX-License-Identifier: MIT +from .base import * +from ...utils import * + +class KDebugMessage(Register64): + TYPE = 55, 48 + +class KDebugGetBufMessage(KDebugMessage): + TYPE = 55, 48, Constant(1) + COUNT = 47, 0 + +class KDebugSendBufMessage(KDebugMessage): + TYPE = 55, 48 + DVA = 47, 0 + +class KDebugStart(KDebugMessage): + TYPE = 55, 48, Constant(8) + +class ASCKDebugEndpoint(ASCBaseEndpoint): + SHORT = "kdebug" + BASE_MESSAGE = KDebugMessage + + @msg_handler(1, KDebugGetBufMessage) + def GetBuf(self, msg): + size = align_up(msg.COUNT * 0x20, 0x4000) + self.iobuffer0, self.iobuffer0_iova = self.asc.ioalloc(size) + self.send(KDebugSendBufMessage(TYPE=1, DVA=self.iobuffer0_iova)) + + self.iobuffer1, self.iobuffer1_iova = self.asc.ioalloc(0x2000) + self.send(KDebugSendBufMessage(TYPE=2, DVA=self.iobuffer1_iova)) + return True + + def start(self): + self.iobuffer0 = None + self.iobuffer1 = None + self.iobuffer0_iova = None + self.iobuffer1_iova = None + self.send(KDebugStart()) diff --git a/proxyclient/m1n1/fw/asc/mgmt.py b/proxyclient/m1n1/fw/asc/mgmt.py new file mode 100644 index 00000000..22ae4bc7 --- /dev/null +++ b/proxyclient/m1n1/fw/asc/mgmt.py @@ -0,0 +1,112 @@ +# SPDX-License-Identifier: MIT +from .base import * +from ...utils import * + +## Management endpoint +class ManagementMessage(Register64): + TYPE = 59, 52 + +class Mgmt_Hello(ManagementMessage): + TYPE = 59, 52, Constant(1) + UNK1 = 31, 16 + UNK2 = 15, 0 + +class Mgmt_HelloAck(ManagementMessage): + TYPE = 59, 52, Constant(2) + UNK1 = 31, 16 + UNK2 = 15, 0 + +class Mgmt_Ping(ManagementMessage): + TYPE = 59, 52, Constant(3) + +class Mgmt_Pong(ManagementMessage): + TYPE = 59, 52, Constant(4) + +class Mgmt_StartEP(ManagementMessage): + TYPE = 59, 52, Constant(5) + EP = 39, 32 + FLAG = 1 + +class Mgmt_Init(ManagementMessage): + TYPE = 59, 52, Constant(6) + UNK = 15, 0 + +class Mgmt_BootDone(ManagementMessage): + TYPE = 59, 52, Constant(7) + +class Mgmt_EPMap(ManagementMessage): + TYPE = 59, 52, Constant(8) + LAST = 51 + BASE = 34, 32 + BITMAP = 31, 0 + +class Mgmt_EPMap_Ack(ManagementMessage): + TYPE = 59, 52, Constant(8) + LAST = 51 + BASE = 34, 32 + MORE = 0 + +class Mgmt_StartSyslog(ManagementMessage): + TYPE = 59, 52, Constant(0xb) + UNK1 = 15, 0 + +class ASCManagementEndpoint(ASCBaseEndpoint): + BASE_MESSAGE = ManagementMessage + SHORT = "mgmt" + + def __init__(self, *args, **kwargs): + super().__init__(*args, **kwargs) + self.syslog_started = False + self.boot_done = False + + @msg_handler(1, Mgmt_Hello) + def Hello(self, msg): + self.send(Mgmt_HelloAck(UNK1=msg.UNK1, UNK2=msg.UNK2)) + return True + + @msg_handler(8, Mgmt_EPMap) + def EPMap(self, msg): + for i in range(32): + if msg.BITMAP & (1 << i): + epno = 32 * msg.BASE + i + self.asc.eps.append(epno) + + self.send(Mgmt_EPMap_Ack(BASE=msg.BASE, LAST=msg.LAST, MORE=0 if msg.LAST else 1)) + + if msg.LAST: + for ep in self.asc.eps: + if ep == 0: continue + if ep < 0x10: + self.asc.start_ep(ep) + + return True + + @msg_handler(0xb, Mgmt_StartSyslog) + def StartSyslogAck(self, msg): + self.syslog_started = True + return True + + @msg_handler(7, Mgmt_BootDone) + def BootDone(self, msg): + #self.start_syslog() + self.boot_done = True + return True + + @msg_handler(4, Mgmt_Pong) + def Pong(self, msg): + return True + + def start(self): + self.send(Mgmt_Init(UNK=0x220)) + while not self.boot_done or not self.syslog_started: + self.asc.work() + self.log("startup complete") + + def start_ep(self, epno): + self.send(Mgmt_StartEP(EP=epno, FLAG=1)) + + def start_syslog(self): + self.send(Mgmt_StartSyslog(UNK1=0x20)) + + def ping(self): + self.send(Mgmt_Ping()) diff --git a/proxyclient/m1n1/fw/asc/oslog.py b/proxyclient/m1n1/fw/asc/oslog.py new file mode 100644 index 00000000..b1a360be --- /dev/null +++ b/proxyclient/m1n1/fw/asc/oslog.py @@ -0,0 +1,30 @@ +# SPDX-License-Identifier: MIT +from .base import * +from ...utils import * + +## OSLog endpoint + +class OSLogMessage(Register64): + TYPE = 63, 56 + +class OSLog_Init(OSLogMessage): + TYPE = 63, 56, Constant(1) + UNK = 51, 0 + +class OSLog_Ack(OSLogMessage): + TYPE = 63, 56, Constant(3) + +class ASCOSLogEndpoint(ASCBaseEndpoint): + BASE_MESSAGE = OSLogMessage + SHORT = "oslog" + + def __init__(self, *args, **kwargs): + super().__init__(*args, **kwargs) + self.started = False + + @msg_handler(1, OSLog_Init) + def Init(self, msg): + self.log(f"oslog init: {msg.UNK:#x}") + self.send(OSLog_Ack()) + self.started = True + return True diff --git a/proxyclient/m1n1/fw/asc/syslog.py b/proxyclient/m1n1/fw/asc/syslog.py new file mode 100644 index 00000000..886ab218 --- /dev/null +++ b/proxyclient/m1n1/fw/asc/syslog.py @@ -0,0 +1,70 @@ +# SPDX-License-Identifier: MIT +import struct + +from .base import * +from ...utils import * + +## Syslog endpoint + +class SyslogMessage(Register64): + TYPE = 59, 52 + +class Syslog_Init(SyslogMessage): + TYPE = 59, 52, Constant(8) + ENTRYSIZE = 39, 24 + COUNT = 15, 0 + +class Syslog_GetBuf(SyslogMessage): + TYPE = 59, 52, Constant(1) + UNK1 = 51, 44, Constant(3) + DVA = 43, 0 + +class Syslog_Log(SyslogMessage): + TYPE = 59, 52, Constant(5) + INDEX = 7, 0 + +class ASCSysLogEndpoint(ASCBaseEndpoint): + BASE_MESSAGE = SyslogMessage + SHORT = "syslog" + + def __init__(self, *args, **kwargs): + super().__init__(*args, **kwargs) + self.entrysize = None + self.count = None + self.iobuffer = None + self.iobuffer_dva = None + self.started = False + + @msg_handler(8, Syslog_Init) + def Init(self, msg): + self.entrysize = msg.ENTRYSIZE + self.count = msg.COUNT + self.log(f"count {self.count}, entrysize {self.entrysize}") + return True + + @msg_handler(1, Syslog_GetBuf) + def GetBuf(self, msg): + size = 0x4000 + + if self.iobuffer: + print("WARNING: trying to reset iobuffer!") + + self.iobuffer, self.iobuffer_dva = self.asc.ioalloc(size) + self.log(f"buf {self.iobuffer:#x} / {self.iobuffer_dva:#x}") + self.send(Syslog_GetBuf(DVA=self.iobuffer_dva)) + self.started = True + return True + + @msg_handler(5, Syslog_Log) + def Log(self, msg): + stride = 0x20 + self.entrysize + log = self.asc.iface.readmem(self.iobuffer + msg.INDEX * stride, stride) + hdr, unk, context, logmsg = struct.unpack(f"") - 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}=?") @@ -156,17 +195,10 @@ class Method: continue dir = self.dir[i] - - if self.nullable[i] and in_vals.get(name + "_null", None): - continue - - 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: + + 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): @@ -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: @@ -312,15 +466,20 @@ IOMFBParameterName = Int32ul BufferDescriptor = uint64_t SwapCompleteData = Bytes(0x12) -SwapInfoBlob = Bytes(0x600) +SwapInfoBlob = Bytes(0x680) -IOMFBSwapRec = Bytes(0x274) -IOSurface = Bytes(0x204) +IOMFBSwapRec = Bytes(0x320) +IOSurface = HexDump(Bytes(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 +489,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 +501,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(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 +547,26 @@ 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=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") + 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", key=string(0x40), value=InPtr(Padded(0x1000, OSDictionary()))) - D561 = Callback(bool_, "setProperty", key=string(0x40), value=InPtr(Padded(0x1000, OSDictionary()))) - D563 = Callback(bool_, "setProperty", key=string(0x40), value=InPtr(uint64_t)) - D565 = Callback(bool_, "setProperty", key=string(0x40), value=InPtr(Bool(uint32_t))) - D567 = Callback(bool_, "setProperty", 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 +581,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", obj=FourCC, key=string(0x40), value=InPtr(Padded(0x1000, OSDictionary()))) - D414 = Callback(bool_, "setProperty", obj=FourCC, key=string(0x40), value=InPtr(uint64_t)) - D415 = Callback(bool_, "setProperty", 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 +611,8 @@ SHORT_CHANNELS = { "CB": "d", "CMD": "C", "ASYNC": "a", - "OOB": "O", + "OOBCMD": "O", + "OOBCB": "o", } RDIR = { ">": "<", "<": ">" } diff --git a/proxyclient/m1n1/fw/dcp/manager.py b/proxyclient/m1n1/fw/dcp/manager.py new file mode 100644 index 00000000..ccf73d3a --- /dev/null +++ b/proxyclient/m1n1/fw/dcp/manager.py @@ -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 + diff --git a/proxyclient/m1n1/fw/dcp/parse_log.py b/proxyclient/m1n1/fw/dcp/parse_log.py index 6e4f8383..e57f6371 100644 --- a/proxyclient/m1n1/fw/dcp/parse_log.py +++ b/proxyclient/m1n1/fw/dcp/parse_log.py @@ -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 diff --git a/proxyclient/m1n1/hv.py b/proxyclient/m1n1/hv.py index 1d7601c5..f2435bfe 100644 --- a/proxyclient/m1n1/hv.py +++ b/proxyclient/m1n1/hv.py @@ -553,8 +553,9 @@ class HV(Reloadable): if iss.Rt != 31: ctx.regs[iss.Rt] = 0 else: - value = ctx.regs[iss.Rt] - print(f"Skip: msr {name}, x{iss.Rt} = {value:x}") + if iss.Rt != 31: + value = ctx.regs[iss.Rt] + #print(f"Skip: msr {name}, x{iss.Rt} = {value:x}") else: if iss.DIR == MSR_DIR.READ: print(f"Pass: mrs x{iss.Rt}, {name}", end=" ") diff --git a/proxyclient/m1n1/hw/asc.py b/proxyclient/m1n1/hw/asc.py new file mode 100644 index 00000000..2e6b781c --- /dev/null +++ b/proxyclient/m1n1/hw/asc.py @@ -0,0 +1,88 @@ +# SPDX-License-Identifier: MIT +from ..utils import * + +class R_OUTBOX_CTRL(Register32): + EMPTY = 17 + FULL = 16 + +class R_INBOX_CTRL(Register32): + EMPTY = 17 + FULL = 16 + ENABLE = 1 + +class R_CPU_CONTROL(Register32): + RUN = 4 + +class R_INBOX1(Register64): + EP = 7, 0 + +class R_OUTBOX1(Register64): + OUTCNT = 56, 52 + INCNT = 51, 48 + OUTPTR = 47, 44 + INPTR = 43, 40 + EP = 7, 0 + +class ASCRegs(RegMap): + CPU_CONTROL = 0x0044, R_CPU_CONTROL + INBOX_CTRL = 0x8110, R_INBOX_CTRL + OUTBOX_CTRL = 0x8114, R_OUTBOX_CTRL + INBOX0 = 0x8800, Register64 + INBOX1 = 0x8808, R_INBOX1 + OUTBOX0 = 0x8830, Register64 + OUTBOX1 = 0x8838, R_OUTBOX1 + +class ASC: + def __init__(self, u, asc_base): + self.u = u + self.p = u.proxy + self.iface = u.iface + self.asc = ASCRegs(u, asc_base) + self.epmap = {} + + def recv(self): + if self.asc.OUTBOX_CTRL.reg.EMPTY: + return None, None + + msg0 = self.asc.OUTBOX0.val + msg1 = R_INBOX1(self.asc.OUTBOX1.val) + print(f"< {msg1.EP:02x}:{msg0:#x}") + return msg0, msg1 + + def send(self, msg0, msg1): + self.asc.INBOX0.val = msg0 + self.asc.INBOX1.val = msg1 + + print(f"> {msg1.EP:02x}:{msg0}") + + while self.asc.INBOX_CTRL.reg.FULL: + pass + + def boot(self): + self.asc.CPU_CONTROL.set(RUN=1) + self.asc.CPU_CONTROL.set(RUN=0) + + def add_ep(self, idx, ep): + self.epmap[idx] = ep + setattr(self, ep.SHORT, ep) + + def work(self): + if self.asc.OUTBOX_CTRL.reg.EMPTY: + return True + + msg0, msg1 = self.recv() + + handled = False + + ep = self.epmap.get(msg1.EP, None) + if ep: + handled = ep.handle_msg(msg0, msg1) + + if not handled: + print(f"unknown message: {msg0:#16x} / {msg1}") + + return handled + + def work_forever(self): + while self.work(): + pass diff --git a/proxyclient/m1n1/hw/dart.py b/proxyclient/m1n1/hw/dart.py index 9bc95f38..4ad824ce 100644 --- a/proxyclient/m1n1/hw/dart.py +++ b/proxyclient/m1n1/hw/dart.py @@ -3,6 +3,7 @@ import struct from ..utils import * +from ..malloc import Heap __all__ = ["DARTRegs", "DART"] @@ -37,14 +38,19 @@ class R_REMAP(Register32): class PTE(Register64): OFFSET = 36, 14 + VALID2 = 1 VALID = 0 +class R_CONFIG(Register32): + LOCK = 15 + class DARTRegs(RegMap): STREAM_COMMAND = 0x20, R_STREAM_COMMAND STREAM_SELECT = 0x34, Register32 ERROR = 0x40, R_ERROR ERROR_ADDR_LO = 0x50, Register32 ERROR_ADDR_HI = 0x54, Register32 + CONFIG = 0x60, R_CONFIG REMAP = irange(0x80, 4, 4), R_REMAP TCR = irange(0x100, 16, 4), R_TCR @@ -63,10 +69,13 @@ class DART(Reloadable): Lx_SIZE = (1 << IDX_BITS) IDX_MASK = Lx_SIZE - 1 - def __init__(self, iface, regs): + def __init__(self, iface, regs, util=None, iova_range=(0x80000000, 0x90000000)): self.iface = iface self.regs = regs + self.u = util self.pt_cache = {} + self.iova_allocator = [Heap(iova_range[0], iova_range[1], self.PAGE_SIZE) + for i in range(16)] def ioread(self, stream, base, size): if size == 0: @@ -84,6 +93,85 @@ class DART(Reloadable): return b"".join(data) + def iowrite(self, stream, base, data): + if len(data) == 0: + return + + ranges = self.iotranslate(stream, base, len(data)) + + iova = base + p = 0 + for addr, size in ranges: + if addr is None: + raise Exception(f"Unmapped page at iova {iova:#x}") + self.iface.writemem(addr, data[p:p + size]) + p += size + iova += size + + def iomap(self, stream, addr, size): + iova = self.iova_allocator[stream].malloc(size) + + self.iomap_at(stream, iova, addr, size) + return iova + + def iomap_at(self, stream, iova, addr, size): + if size == 0: + return + + tcr = self.regs.TCR[stream].reg + + if tcr.BYPASS_DART and not tcr.TRANSLATE_ENABLE: + raise Exception("Stream is bypassed in DART") + + if tcr.BYPASS_DART or not tcr.TRANSLATE_ENABLE: + raise Exception(f"Unknown DART mode {tcr}") + + if addr & (self.PAGE_SIZE - 1): + raise Exception(f"Unaligned PA {addr:#x}") + + if iova & (self.PAGE_SIZE - 1): + raise Exception(f"Unaligned IOVA {iova:#x}") + + start_page = align_down(iova, self.PAGE_SIZE) + end = iova + size + end_page = align_up(end, self.PAGE_SIZE) + + dirty = set() + + for page in range(start_page, end_page, self.PAGE_SIZE): + paddr = addr + page - start_page + + l0 = page >> self.L0_OFF + assert l0 < self.L0_SIZE + ttbr = self.regs.TTBR[stream, l0].reg + if not ttbr.VALID: + raise Exception(f"L0 page table not ready (TTBR{l0})") + + cached, l1 = self.get_pt(ttbr.ADDR << 12) + l1idx = (page >> self.L1_OFF) & self.IDX_MASK + l1pte = PTE(l1[l1idx]) + if not l1pte.VALID and cached: + cached, l1 = self.get_pt(ttbr.ADDR << 12, uncached=True) + l1pte = PTE(l1[l1idx]) + if not l1pte.VALID: + l2addr = self.u.memalign(self.PAGE_SIZE, self.PAGE_SIZE) + self.pt_cache[l2addr] = [0] * self.Lx_SIZE + l1pte = PTE( + OFFSET=l2addr >> self.PAGE_BITS, VALID=1, VALID2=1) + l1[l1idx] = l1pte.value + dirty.add(ttbr.ADDR << 12) + else: + l2addr = l1pte.OFFSET << self.PAGE_BITS + + dirty.add(l1pte.OFFSET << self.PAGE_BITS) + cached, l2 = self.get_pt(l2addr) + l2idx = (page >> self.L2_OFF) & self.IDX_MASK + self.pt_cache[l2addr][l2idx] = PTE( + OFFSET=paddr >> self.PAGE_BITS, VALID=1, VALID2=1).value + + for page in dirty: + self.flush_pt(page) + def iotranslate(self, stream, start, size): if size == 0: return [] @@ -157,11 +245,15 @@ class DART(Reloadable): cached = True if addr not in self.pt_cache or uncached: cached = False - self.pt_cache[addr] = struct.unpack(f"<{self.Lx_SIZE}Q", - self.iface.readmem(addr, self.PAGE_SIZE)) + self.pt_cache[addr] = list( + struct.unpack(f"<{self.Lx_SIZE}Q", self.iface.readmem(addr, self.PAGE_SIZE))) return cached, self.pt_cache[addr] + def flush_pt(self, addr): + assert addr in self.pt_cache + self.iface.writemem(addr, struct.pack(f"<{self.Lx_SIZE}Q", *self.pt_cache[addr])) + def invalidate_cache(self): self.pt_cache = {} @@ -225,3 +317,4 @@ class DART(Reloadable): def dump_all(self): for i in range(16): self.dump_device(i) + diff --git a/proxyclient/m1n1/proxy.py b/proxyclient/m1n1/proxy.py index 7a389d99..c371879e 100644 --- a/proxyclient/m1n1/proxy.py +++ b/proxyclient/m1n1/proxy.py @@ -364,6 +364,9 @@ class UartInterface(Reloadable): self.reply(self.REQ_MEMWRITE) def readmem(self, addr, size): + if size == 0: + return b"" + req = struct.pack("= 3 and isinstance(field[2], Constant): + setattr(self, k, field[2].value) for k,v in kwargs.items(): setattr(self, k, v) diff --git a/src/hv_exc.c b/src/hv_exc.c index e69274d3..72addd59 100644 --- a/src/hv_exc.c +++ b/src/hv_exc.c @@ -131,6 +131,8 @@ static bool hv_handle_msr(u64 *regs, u64 iss) switch (reg) { /* Some kind of timer */ SYSREG_PASS(sys_reg(3, 7, 15, 1, 1)); + /* Unknown, spammy */ + SYSREG_PASS(sys_reg(3, 5, 15, 10, 1)); /* Noisy traps */ SYSREG_MAP(SYS_ACTLR_EL1, SYS_IMP_APL_ACTLR_EL12) SYSREG_PASS(SYS_IMP_APL_HID4)