This commit is contained in:
Hector Martin 2021-07-31 12:51:26 +09:00
parent 63e8d0d48e
commit b8f07d3929
25 changed files with 1877 additions and 173 deletions

View file

@ -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()

View file

@ -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!")

View file

@ -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()

View file

@ -461,23 +461,7 @@ KNOWN_MSGS = {
22: getNamedProperty 22: getNamedProperty
""" """
class DCPMessage(Register64): from m1n1.fw.dcp.dcpep import DCPMessage, DCPEp_SetShmem, CallContext, DCPEp_Msg
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
class DCPCallState: class DCPCallState:
pass pass
@ -571,23 +555,26 @@ class DCPEp(EP):
self.state.ch = {} self.state.ch = {}
self.state.dumpfile = None 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_cmd = DCPCallChannel(self, "CMD", 0, 0x8000)
self.ch_async = DCPCallChannel(self, "ASYNC", 0x40000, 0x20000) 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 = { self.cmd_ch = {
CallContext.CALLBACK: self.ch_cmd, CallContext.CB: self.ch_cmd,
CallContext.CMD: self.ch_cmd, CallContext.CMD: self.ch_cmd,
CallContext.ASYNC: self.ch_oob, # guess? CallContext.ASYNC: None, # unknown
CallContext.OOB: self.ch_oob, CallContext.OOBCB: self.ch_oobcmd,
CallContext.OOBCMD: self.ch_oobcmd,
} }
self.cb_ch = { self.cb_ch = {
CallContext.CALLBACK: self.ch_cb, CallContext.CB: self.ch_cb,
CallContext.CMD: None, CallContext.CMD: None,
CallContext.ASYNC: self.ch_async, CallContext.ASYNC: self.ch_async,
CallContext.OOB: None, CallContext.OOBCB: self.ch_oobcb,
CallContext.OOBCMD: None,
} }
def start(self): def start(self):
@ -607,8 +594,8 @@ class DCPEp(EP):
@msg(0, DIR.TX, DCPEp_SetShmem) @msg(0, DIR.TX, DCPEp_SetShmem)
def SetShmem(self, msg): def SetShmem(self, msg):
self.log(f"Shared memory IOVA: {msg.IOVA:#x}") self.log(f"Shared memory DVA: {msg.DVA:#x}")
self.state.shmem_iova = msg.IOVA self.state.shmem_iova = msg.DVA & 0xffffffff
self.add_mon() self.add_mon()
@msg(2, DIR.TX, DCPEp_Msg) @msg(2, DIR.TX, DCPEp_Msg)
@ -625,6 +612,7 @@ class DCPEp(EP):
@msg(2, DIR.RX, DCPEp_Msg) @msg(2, DIR.RX, DCPEp_Msg)
def Rx(self, msg): def Rx(self, msg):
self.log(msg)
if msg.ACK: if msg.ACK:
self.cmd_ch[msg.CTX].ack(msg, "<") self.cmd_ch[msg.CTX].ack(msg, "<")
else: else:
@ -704,6 +692,9 @@ class DCPTracer(ASCTracer):
dart_dcp_tracer = DARTTracer(hv, "/arm-io/dart-dcp") dart_dcp_tracer = DARTTracer(hv, "/arm-io/dart-dcp")
dart_dcp_tracer.start() dart_dcp_tracer.start()
dart_disp0_tracer = DARTTracer(hv, "/arm-io/dart-disp0")
dart_disp0_tracer.start()
def readmem_iova(addr, size): def readmem_iova(addr, size):
try: try:
return dart_dcp_tracer.dart.ioread(0, addr, size) 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 = DCPTracer(hv, "/arm-io/dcp", verbose=1)
dcp_tracer.start(dart_dcp_tracer.dart) 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")

View file

@ -238,6 +238,9 @@ class ADTNode:
t + "}" t + "}"
]) ])
def __repr__(self):
return f"<ADTNode {self.name}>"
def __iter__(self): def __iter__(self):
return iter(self._children) return iter(self._children)

View file

@ -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__)

View file

@ -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}")

View file

@ -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

View file

@ -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

View file

@ -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())

View file

@ -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())

View file

@ -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

View file

@ -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"<II24s{self.entrysize}s", log)
context = context.split(b"\x00")[0].decode("ascii")
logmsg = logmsg.split(b"\x00")[0].decode("ascii").rstrip("\n")
self.log(f"* [{context}]{logmsg}")
self.send(msg)
return True
def start(self):
self.asc.mgmt.start_syslog()

View 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,
}

View 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()

View file

@ -1,10 +1,16 @@
# SPDX-License-Identifier: MIT # SPDX-License-Identifier: MIT
from dataclasses import dataclass
import pprint import pprint
from enum import IntEnum
from m1n1.utils import * from m1n1.utils import *
from construct import * from construct import *
@dataclass
class ByRef:
val: object
class Pointer(Subconstruct): class Pointer(Subconstruct):
pass pass
@ -22,6 +28,13 @@ class InOut(Subconstruct):
Ptr = InOutPtr Ptr = InOutPtr
class NULL:
def __str__(self):
return "NULL"
def __repr__(self):
return "NULL"
NULL = NULL()
class Method: class Method:
def __init__(self, rtype, name, *args, **kwargs): def __init__(self, rtype, name, *args, **kwargs):
self.rtype = rtype self.rtype = rtype
@ -31,8 +44,10 @@ class Method:
raise Exception("Cannot specify args and kwargs") raise Exception("Cannot specify args and kwargs")
elif args: elif args:
args = [(f"arg{i}", arg) for i, arg in enumerate(args)] args = [(f"arg{i}", arg) for i, arg in enumerate(args)]
self.as_kwargs = False
elif kwargs: elif kwargs:
args = list(kwargs.items()) args = list(kwargs.items())
self.as_kwargs = True
else: else:
args = [] args = []
@ -48,6 +63,7 @@ class Method:
self.dir = [] self.dir = []
self.nullable = [] self.nullable = []
self.array_of_p = []
for i, (name, field) in enumerate(self.args): for i, (name, field) in enumerate(self.args):
align = 1 align = 1
@ -88,19 +104,29 @@ class Method:
self.dir.append(dir) self.dir.append(dir)
for i, (name, field) in enumerate(self.args): for i, (name, field) in enumerate(self.args):
array_size = None
array_of_p = False
nullable = False nullable = False
pfield = field pfield = field
while isinstance(pfield, Subconstruct): while isinstance(pfield, Subconstruct):
if isinstance(pfield, Array) and array_size is None:
array_size = pfield.count
if isinstance(pfield, Pointer): if isinstance(pfield, Pointer):
nullable = True nullable = True
array_of_p = array_size is not None
pfield = pfield.subcon pfield = pfield.subcon
if nullable: if nullable:
self.in_fields.append((name + "_null") / bool_) if array_of_p:
in_size += 1 self.in_fields.append((name + "_null") / Array(array_size, bool_))
in_size += array_size
else:
self.in_fields.append((name + "_null") / bool_)
in_size += 1
self.nullable.append(nullable) self.nullable.append(nullable)
self.array_of_p.append(array_of_p)
if in_size % 4: if in_size % 4:
self.in_fields.append(Padding(4 - (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.in_struct = Struct(*self.in_fields)
self.out_struct = Struct(*self.out_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): def fmt_args(self, in_vals, out_vals=None):
s = [] s = []
@ -119,32 +172,18 @@ class Method:
dir = self.dir[i] dir = self.dir[i]
nullable = self.nullable[i] nullable = self.nullable[i]
val = self.get_field_val(i, in_vals, out_vals, nullobj=NULL)
if nullable: if val is not None:
null = in_vals.get(name + "_null", None) if self.is_long(val):
if null is None:
s.append(f"{name}=?")
continue
elif null:
s.append(f"{name}=NULL")
continue
if out_vals and name in out_vals:
if self.is_long(out_vals[name]):
s.append(f"{name}=...") s.append(f"{name}=...")
elif isinstance(out_vals[name], ListContainer): elif isinstance(val, ListContainer):
s.append(f"{name}={list(out_vals[name])!r}") s.append(f"{name}={list(val)!r}")
else: else:
s.append(f"{name}={out_vals[name]!r}") s.append(f"{name}={val!r}")
elif dir == "out": elif dir == "out":
s.append(f"{name}=<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: else:
s.append(f"{name}=?") s.append(f"{name}=?")
@ -156,17 +195,10 @@ class Method:
continue continue
dir = self.dir[i] dir = self.dir[i]
if self.nullable[i] and in_vals.get(name + "_null", None): val = self.get_field_val(i, in_vals, out_vals, nullobj=NULL)
continue
if name in in_vals and out_vals is not None and name not in out_vals:
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:
continue continue
if self.is_long(val): if self.is_long(val):
@ -184,7 +216,7 @@ class Method:
def is_long(self, arg): def is_long(self, arg):
if isinstance(arg, (list, bytes)): 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)) 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() }) 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): def dump_fields(fields):
off = 0 off = 0
for f in fields: for f in fields:
@ -312,15 +466,20 @@ IOMFBParameterName = Int32ul
BufferDescriptor = uint64_t BufferDescriptor = uint64_t
SwapCompleteData = Bytes(0x12) SwapCompleteData = Bytes(0x12)
SwapInfoBlob = Bytes(0x600) SwapInfoBlob = Bytes(0x680)
IOMFBSwapRec = Bytes(0x274) IOMFBSwapRec = Bytes(0x320)
IOSurface = Bytes(0x204) IOSurface = HexDump(Bytes(0x204))
IOMFBColorFixedMatrix = Array(5, Array(3, ulong))
class PropID(IntEnum):
BrightnessCorrection = 14
class UPPipeAP_H13P(IPCObject): class UPPipeAP_H13P(IPCObject):
A000 = Call(bool_, "late_init_signal") A000 = Call(bool_, "late_init_signal")
A029 = Call(void, "setup_video_limits") 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") A036 = Call(bool_, "apt_supported")
D000 = Callback(bool_, "did_boot_signal") D000 = Callback(bool_, "did_boot_signal")
@ -330,6 +489,7 @@ class UPPipeAP_H13P(IPCObject):
class UnifiedPipeline2(IPCObject): class UnifiedPipeline2(IPCObject):
A357 = Call(void, "set_create_DFB") A357 = Call(void, "set_create_DFB")
A358 = Call(IOMFBStatus, "vi_set_temperature_hint")
D100 = Callback(void, "match_pmu_service") D100 = Callback(void, "match_pmu_service")
D101 = Callback(uint32_t, "UNK_get_some_field") D101 = Callback(uint32_t, "UNK_get_some_field")
@ -341,40 +501,44 @@ class UnifiedPipeline2(IPCObject):
D110 = Callback(bool_, "create_iomfb_service") D110 = Callback(bool_, "create_iomfb_service")
D111 = Callback(bool_, "create_backlight_service") D111 = Callback(bool_, "create_backlight_service")
D116 = Callback(bool_, "start_hardware_boot") 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_, "setDCPAVPropStart", length=uint)
D122 = Callback(bool_, "setDCPAVPropChunk", data=HexDump(SizedBytes(0x1000, "length")), offset=uint, length=uint) D123 = Callback(bool_, "setDCPAVPropChunk", data=HexDump(SizedBytes(0x1000, "length")), offset=uint, length=uint)
D123 = Callback(bool_, "setDCPAVPropEnd", key=string(0x40)) D124 = Callback(bool_, "setDCPAVPropEnd", key=string(0x40))
class UPPipe2(IPCObject): class UPPipe2(IPCObject):
A103 = Call(uint64_t, "test_control", cmd=uint64_t, arg=uint) 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_) 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") D207 = Callback(bool_, "match_backlight_service")
D208 = Callback(uint64_t, "get_calendar_time_ms") D208 = Callback(uint64_t, "get_calendar_time_ms")
class PropRelay(IPCObject): 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): class IOMobileFramebufferAP(IPCObject):
A401 = Call(uint32_t, "start_signal") 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", A408 = Call(uint32_t, "swap_submit_dcp",
swap_rec=InPtr(IOMFBSwapRec), swap_rec=InPtr(IOMFBSwapRec),
surf0=InPtr(IOSurface), surfaces=Array(4, InPtr(IOSurface)),
surf1=InPtr(IOSurface), surfAddr=Array(4, Hex(ulong)),
surf2=InPtr(IOSurface),
surfInfo=Array(3, uint),
unkBool=bool_, unkBool=bool_,
unkFloat=Float64l, unkFloat=Float64l,
unkInt=uint, unkInt=uint,
unkOutBool=OutPtr(bool_)) unkOutBool=OutPtr(bool_))
A410 = Call(uint32_t, "set_display_device", uint) 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) A412 = Call(uint32_t, "set_digital_out_mode", uint, uint)
A419 = Call(uint32_t, "get_gamma_table", InOutPtr(Bytes(0xc0c))) A419 = Call(uint32_t, "get_gamma_table", InOutPtr(Bytes(0xc0c)))
A422 = Call(uint32_t, "set_matrix", uint, InPtr(Array(3, Array(3, ulong)))) 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) 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) 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)) A440 = Call(uint, "display_width")
A442 = Call(int_, "do_create_default_frame_buffer") A441 = Call(uint, "display_height")
A446 = Call(int_, "enable_disable_video_power_savings", uint) A442 = Call(void, "get_display_size", OutPtr(uint), OutPtr(uint))
A453 = Call(void, "first_client_open") A443 = Call(int_, "do_create_default_frame_buffer")
A455 = Call(bool_, "writeDebugInfo", ulong) A447 = Call(int_, "enable_disable_video_power_savings", uint)
A459 = Call(bool_, "setDisplayRefreshProperties") A454 = Call(void, "first_client_open")
A462 = Call(void, "flush_supportsPower", bool_) A456 = Call(bool_, "writeDebugInfo", ulong)
A467 = Call(uint32_t, "setPowerState", ulong, bool_, OutPtr(uint)) A458 = Call(bool_, "io_fence_notify", uint, uint, ulong, IOMFBStatus)
A468 = Call(bool_, "isKeepOnScreen") 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()))) D552 = Callback(bool_, "setProperty_dict", key=string(0x40), value=InPtr(Padded(0x1000, OSDictionary())))
D561 = Callback(bool_, "setProperty<OSDictionary>", 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<OSNumber>", key=string(0x40), value=InPtr(uint64_t)) D563 = Callback(bool_, "setProperty_int", key=string(0x40), value=InPtr(uint64_t))
D565 = Callback(bool_, "setProperty<OSBoolean>", key=string(0x40), value=InPtr(Bool(uint32_t))) D565 = Callback(bool_, "setProperty_bool", key=string(0x40), value=InPtr(Bool(uint32_t)))
D567 = Callback(bool_, "setProperty<AFKString>", key=string(0x40), value=string(0x40)) D567 = Callback(bool_, "setProperty_str", key=string(0x40), value=string(0x40))
D574 = Callback(IOMFBStatus, "powerUpDART", bool_) D574 = Callback(IOMFBStatus, "powerUpDART", bool_)
@ -414,16 +581,16 @@ class IOMobileFramebufferAP(IPCObject):
D598 = Callback(void, "find_swap_function_gated") D598 = Callback(void, "find_swap_function_gated")
class ServiceRelay(IPCObject): class ServiceRelay(IPCObject):
D401 = Callback(bool_, "get_uint_prop", obj=FourCC, key=string(0x40), value=InOutPtr(ulong)) D401 = Callback(bool_, "sr_get_uint_prop", obj=FourCC, key=string(0x40), value=InOutPtr(ulong))
D408 = Callback(uint64_t, "getClockFrequency", uint, uint) D408 = Callback(uint64_t, "sr_getClockFrequency", obj=FourCC, arg=uint)
D411 = Callback(IOMFBStatus, "mapDeviceMemoryWithIndex", uint, uint, uint, OutPtr(ulong), OutPtr(ulong)) D411 = Callback(IOMFBStatus, "sr_mapDeviceMemoryWithIndex", obj=FourCC, index=uint, flags=uint, addr=OutPtr(ulong), length=OutPtr(ulong))
D413 = Callback(bool_, "setProperty<OSDictionary>", obj=FourCC, key=string(0x40), value=InPtr(Padded(0x1000, OSDictionary()))) D413 = Callback(bool_, "sr_setProperty_dict", obj=FourCC, key=string(0x40), value=InPtr(Padded(0x1000, OSDictionary())))
D414 = Callback(bool_, "setProperty<OSNumber>", obj=FourCC, key=string(0x40), value=InPtr(uint64_t)) D414 = Callback(bool_, "sr_setProperty_int", obj=FourCC, key=string(0x40), value=InPtr(uint64_t))
D415 = Callback(bool_, "setProperty<OSBoolean>", obj=FourCC, key=string(0x40), value=InPtr(Bool(uint32_t))) D415 = Callback(bool_, "sr_setProperty_bool", obj=FourCC, key=string(0x40), value=InPtr(Bool(uint32_t)))
class MemDescRelay(IPCObject): class MemDescRelay(IPCObject):
D451 = Callback(uint, "allocate_buffer", uint, ulong, uint, OutPtr(ulong), OutPtr(ulong), OutPtr(ulong)) 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 = [ ALL_CLASSES = [
UPPipeAP_H13P, UPPipeAP_H13P,
@ -444,7 +611,8 @@ SHORT_CHANNELS = {
"CB": "d", "CB": "d",
"CMD": "C", "CMD": "C",
"ASYNC": "a", "ASYNC": "a",
"OOB": "O", "OOBCMD": "O",
"OOBCB": "o",
} }
RDIR = { ">": "<", "<": ">" } RDIR = { ">": "<", "<": ">" }

View 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

View file

@ -23,14 +23,20 @@ def parse_log(fd):
yield op yield op
def dump_log(fd): def dump_log(fd):
nesting = 0 nesting = {
"": 0,
"OOB": 0,
}
for op in parse_log(fd): for op in parse_log(fd):
ctx = ""
if "OOB" in op.chan:
ctx = "[OOB] -----------> "
if not op.complete: if not op.complete:
op.print_req(indent=" " * nesting) op.print_req(indent=ctx + " " * nesting.setdefault(ctx, 0))
nesting += 1 nesting[ctx] += 1
else: else:
nesting -= 1 nesting[ctx] -= 1
op.print_reply(indent=" " * nesting) op.print_reply(indent=ctx + " " * nesting.setdefault(ctx, 0))
if __name__ == "__main__": if __name__ == "__main__":
import sys import sys

View file

@ -553,8 +553,9 @@ class HV(Reloadable):
if iss.Rt != 31: if iss.Rt != 31:
ctx.regs[iss.Rt] = 0 ctx.regs[iss.Rt] = 0
else: else:
value = ctx.regs[iss.Rt] if iss.Rt != 31:
print(f"Skip: msr {name}, x{iss.Rt} = {value:x}") value = ctx.regs[iss.Rt]
#print(f"Skip: msr {name}, x{iss.Rt} = {value:x}")
else: else:
if iss.DIR == MSR_DIR.READ: if iss.DIR == MSR_DIR.READ:
print(f"Pass: mrs x{iss.Rt}, {name}", end=" ") print(f"Pass: mrs x{iss.Rt}, {name}", end=" ")

View file

@ -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

View file

@ -3,6 +3,7 @@
import struct import struct
from ..utils import * from ..utils import *
from ..malloc import Heap
__all__ = ["DARTRegs", "DART"] __all__ = ["DARTRegs", "DART"]
@ -37,14 +38,19 @@ class R_REMAP(Register32):
class PTE(Register64): class PTE(Register64):
OFFSET = 36, 14 OFFSET = 36, 14
VALID2 = 1
VALID = 0 VALID = 0
class R_CONFIG(Register32):
LOCK = 15
class DARTRegs(RegMap): class DARTRegs(RegMap):
STREAM_COMMAND = 0x20, R_STREAM_COMMAND STREAM_COMMAND = 0x20, R_STREAM_COMMAND
STREAM_SELECT = 0x34, Register32 STREAM_SELECT = 0x34, Register32
ERROR = 0x40, R_ERROR ERROR = 0x40, R_ERROR
ERROR_ADDR_LO = 0x50, Register32 ERROR_ADDR_LO = 0x50, Register32
ERROR_ADDR_HI = 0x54, Register32 ERROR_ADDR_HI = 0x54, Register32
CONFIG = 0x60, R_CONFIG
REMAP = irange(0x80, 4, 4), R_REMAP REMAP = irange(0x80, 4, 4), R_REMAP
TCR = irange(0x100, 16, 4), R_TCR TCR = irange(0x100, 16, 4), R_TCR
@ -63,10 +69,13 @@ class DART(Reloadable):
Lx_SIZE = (1 << IDX_BITS) Lx_SIZE = (1 << IDX_BITS)
IDX_MASK = Lx_SIZE - 1 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.iface = iface
self.regs = regs self.regs = regs
self.u = util
self.pt_cache = {} 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): def ioread(self, stream, base, size):
if size == 0: if size == 0:
@ -84,6 +93,85 @@ class DART(Reloadable):
return b"".join(data) 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): def iotranslate(self, stream, start, size):
if size == 0: if size == 0:
return [] return []
@ -157,11 +245,15 @@ class DART(Reloadable):
cached = True cached = True
if addr not in self.pt_cache or uncached: if addr not in self.pt_cache or uncached:
cached = False cached = False
self.pt_cache[addr] = struct.unpack(f"<{self.Lx_SIZE}Q", self.pt_cache[addr] = list(
self.iface.readmem(addr, self.PAGE_SIZE)) struct.unpack(f"<{self.Lx_SIZE}Q", self.iface.readmem(addr, self.PAGE_SIZE)))
return cached, self.pt_cache[addr] 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): def invalidate_cache(self):
self.pt_cache = {} self.pt_cache = {}
@ -225,3 +317,4 @@ class DART(Reloadable):
def dump_all(self): def dump_all(self):
for i in range(16): for i in range(16):
self.dump_device(i) self.dump_device(i)

View file

@ -364,6 +364,9 @@ class UartInterface(Reloadable):
self.reply(self.REQ_MEMWRITE) self.reply(self.REQ_MEMWRITE)
def readmem(self, addr, size): def readmem(self, addr, size):
if size == 0:
return b""
req = struct.pack("<QQ", addr, size) req = struct.pack("<QQ", addr, size)
self.cmd(self.REQ_MEMREAD, req) self.cmd(self.REQ_MEMREAD, req)
reply = self.reply(self.REQ_MEMREAD) reply = self.reply(self.REQ_MEMREAD)

View file

@ -5,35 +5,12 @@ from enum import IntEnum
from ..hv import TraceMode from ..hv import TraceMode
from ..utils import * from ..utils import *
from . import ADTDevTracer from . import ADTDevTracer
from ..hw.asc import *
class DIR(IntEnum): class DIR(IntEnum):
RX = 0 RX = 0
TX = 1 TX = 1
class R_OUTBOX_CTRL(Register32):
EMPTY = 17
class R_INBOX_CTRL(Register32):
ENABLE = 1
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):
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
def msg(message, direction=None, regtype=None, name=None): def msg(message, direction=None, regtype=None, name=None):
def f(x): def f(x):
x.is_message = True x.is_message = True
@ -154,7 +131,7 @@ class BaseASCTracer(ADTDevTracer):
return return
d = ">" if direction == DIR.TX else "<" d = ">" if direction == DIR.TX else "<"
self.log(f"{d}{r1.EP:02x} {r0.value:016x} ({r0.str_fields()})") self.log(f"{d}ep:{r1.EP:02x} {r0.value:016x} ({r0.str_fields()})")
def start(self, dart=None): def start(self, dart=None):
super().start() super().start()
@ -188,29 +165,12 @@ class BaseASCTracer(ADTDevTracer):
# System endpoints # System endpoints
class SystemMessage(Register64):
TYPE = 59, 52
## Management endpoint ## Management endpoint
class Mgmt_EPMap(SystemMessage): from ..fw.asc.mgmt import ManagementMessage, Mgmt_EPMap, Mgmt_EPMap_Ack, Mgmt_StartEP, Mgmt_StartSyslog
LAST = 51
BASE = 34, 32
BITMAP = 31, 0
class Mgmt_EPMap_Ack(SystemMessage):
LAST = 51
BASE = 34, 32
MORE = 0
class Mgmt_StartEP(SystemMessage):
EP = 39, 32
class Mgmt_StartSyslog(SystemMessage):
UNK1 = 15, 0
class Management(EP): class Management(EP):
BASE_MESSAGE = SystemMessage BASE_MESSAGE = ManagementMessage
HELLO = msg_log(1, DIR.RX) HELLO = msg_log(1, DIR.RX)
HELLO_ACK = msg_log(2, DIR.TX) HELLO_ACK = msg_log(2, DIR.TX)
@ -223,7 +183,7 @@ class Management(EP):
self.log(f" Starting endpoint #{msg.EP:#02x} ({ep.name})") self.log(f" Starting endpoint #{msg.EP:#02x} ({ep.name})")
else: else:
self.log(f" Starting endpoint #{msg.EP:#02x}") self.log(f" Starting endpoint #{msg.EP:#02x}")
return True #return True
Init = msg_log(6, DIR.TX) Init = msg_log(6, DIR.TX)
@ -246,34 +206,30 @@ class Management(EP):
## Syslog endpoint ## Syslog endpoint
class Syslog_Init(SystemMessage): from ..fw.asc.syslog import SyslogMessage, Syslog_Init, Syslog_GetBuf, Syslog_Log
BUFSIZE = 7, 0
class Syslog_GetBuf(SystemMessage):
UNK1 = 51, 44
UNK2 = 39, 32
IOVA = 31, 0
class Syslog_Log(SystemMessage):
INDEX = 7, 0
class Syslog(EP): class Syslog(EP):
BASE_MESSAGE = SystemMessage BASE_MESSAGE = SyslogMessage
Init = msg_log(8, DIR.RX, Syslog_Init)
GetBuf = msg_log(1, DIR.RX, Syslog_GetBuf) GetBuf = msg_log(1, DIR.RX, Syslog_GetBuf)
@msg(8, DIR.RX, Syslog_Init)
def Init(self, msg):
self.state.count = msg.COUNT
self.state.entrysize = msg.ENTRYSIZE
@msg(1, DIR.TX, Syslog_GetBuf) @msg(1, DIR.TX, Syslog_GetBuf)
def GetBuf_Ack(self, msg): def GetBuf_Ack(self, msg):
self.state.syslog_buf = msg.IOVA self.state.syslog_buf = msg.DVA & 0xffffffff
@msg(5, DIR.RX, Syslog_Log) @msg(5, DIR.RX, Syslog_Log)
def Log(self, msg): def Log(self, msg):
if self.tracer.dart is None: if self.tracer.dart is None:
return False return False
buf = self.state.syslog_buf buf = self.state.syslog_buf
log = self.tracer.dart.ioread(0, buf + msg.INDEX * 0xa0, 0xa0) stride = 0x20 + self.state.entrysize
hdr, unk, context, logmsg = struct.unpack("<II24s128s", log) log = self.tracer.dart.ioread(0, buf + msg.INDEX * stride, stride)
hdr, unk, context, logmsg = struct.unpack(f"<II24s{self.state.entrysize}s", log)
context = context.split(b"\x00")[0].decode("ascii") context = context.split(b"\x00")[0].decode("ascii")
logmsg = logmsg.split(b"\x00")[0].decode("ascii").rstrip("\n") logmsg = logmsg.split(b"\x00")[0].decode("ascii").rstrip("\n")
self.log(f"* [{context}]{logmsg}") self.log(f"* [{context}]{logmsg}")

View file

@ -1,6 +1,6 @@
# SPDX-License-Identifier: MIT # SPDX-License-Identifier: MIT
from enum import Enum from enum import Enum
import bisect, copy, heapq, importlib, sys, itertools, time, os, functools import bisect, copy, heapq, importlib, sys, itertools, time, os, functools, struct, re
from construct import Adapter, Int64ul, Int32ul, Int16ul, Int8ul from construct import Adapter, Int64ul, Int32ul, Int16ul, Int8ul
__all__ = [] __all__ = []
@ -63,6 +63,10 @@ def chexdump32(s, st=0, abbreviate=True):
last = val last = val
skip = False skip = False
def unhex(s):
s = re.sub(r"/\*.*?\*/", "", s)
return bytes.fromhex(s.replace(" ", "").replace("\n", ""))
class ReloadableMeta(type): class ReloadableMeta(type):
def __new__(cls, name, bases, dct): def __new__(cls, name, bases, dct):
m = super().__new__(cls, name, bases, dct) m = super().__new__(cls, name, bases, dct)
@ -97,6 +101,14 @@ class Reloadable(metaclass=ReloadableMeta):
def _reloadme(self): def _reloadme(self):
self.__class__ = self._reloadcls() self.__class__ = self._reloadcls()
class Constant:
def __init__(self, value):
self.value = value
def __call__(self, v):
assert v == self.value
return v
class RegisterMeta(ReloadableMeta): class RegisterMeta(ReloadableMeta):
def __new__(cls, name, bases, dct): def __new__(cls, name, bases, dct):
m = super().__new__(cls, name, bases, dct) m = super().__new__(cls, name, bases, dct)
@ -119,8 +131,17 @@ class RegisterMeta(ReloadableMeta):
return m return m
class Register(Reloadable, metaclass=RegisterMeta): class Register(Reloadable, metaclass=RegisterMeta):
def __init__(self, v=0, **kwargs): def __init__(self, v=None, **kwargs):
self._value = v if v is not None:
self._value = v
for k in self._fields_list:
getattr(self, k) # validate
else:
self._value = 0
for k in self._fields_list:
field = getattr(self.__class__, k)
if isinstance(field, tuple) and len(field) >= 3 and isinstance(field[2], Constant):
setattr(self, k, field[2].value)
for k,v in kwargs.items(): for k,v in kwargs.items():
setattr(self, k, v) setattr(self, k, v)

View file

@ -131,6 +131,8 @@ static bool hv_handle_msr(u64 *regs, u64 iss)
switch (reg) { switch (reg) {
/* Some kind of timer */ /* Some kind of timer */
SYSREG_PASS(sys_reg(3, 7, 15, 1, 1)); SYSREG_PASS(sys_reg(3, 7, 15, 1, 1));
/* Unknown, spammy */
SYSREG_PASS(sys_reg(3, 5, 15, 10, 1));
/* Noisy traps */ /* Noisy traps */
SYSREG_MAP(SYS_ACTLR_EL1, SYS_IMP_APL_ACTLR_EL12) SYSREG_MAP(SYS_ACTLR_EL1, SYS_IMP_APL_ACTLR_EL12)
SYSREG_PASS(SYS_IMP_APL_HID4) SYSREG_PASS(SYS_IMP_APL_HID4)