mirror of
https://github.com/AsahiLinux/m1n1
synced 2024-12-18 09:53:04 +00:00
wtf
This commit is contained in:
parent
63e8d0d48e
commit
b8f07d3929
25 changed files with 1877 additions and 173 deletions
22
proxyclient/experiments/dart_dcp_test.py
Normal file
22
proxyclient/experiments/dart_dcp_test.py
Normal 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()
|
475
proxyclient/experiments/dcp.py
Normal file
475
proxyclient/experiments/dcp.py
Normal 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!")
|
30
proxyclient/experiments/dispdump.py
Executable file
30
proxyclient/experiments/dispdump.py
Executable 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()
|
|
@ -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")
|
||||||
|
|
|
@ -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)
|
||||||
|
|
||||||
|
|
68
proxyclient/m1n1/fw/asc/__init__.py
Normal file
68
proxyclient/m1n1/fw/asc/__init__.py
Normal 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__)
|
53
proxyclient/m1n1/fw/asc/base.py
Normal file
53
proxyclient/m1n1/fw/asc/base.py
Normal 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}")
|
41
proxyclient/m1n1/fw/asc/crash.py
Normal file
41
proxyclient/m1n1/fw/asc/crash.py
Normal 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
|
50
proxyclient/m1n1/fw/asc/ioreporting.py
Normal file
50
proxyclient/m1n1/fw/asc/ioreporting.py
Normal 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
|
38
proxyclient/m1n1/fw/asc/kdebug.py
Normal file
38
proxyclient/m1n1/fw/asc/kdebug.py
Normal 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())
|
112
proxyclient/m1n1/fw/asc/mgmt.py
Normal file
112
proxyclient/m1n1/fw/asc/mgmt.py
Normal 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())
|
30
proxyclient/m1n1/fw/asc/oslog.py
Normal file
30
proxyclient/m1n1/fw/asc/oslog.py
Normal 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
|
70
proxyclient/m1n1/fw/asc/syslog.py
Normal file
70
proxyclient/m1n1/fw/asc/syslog.py
Normal 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()
|
10
proxyclient/m1n1/fw/dcp/client.py
Normal file
10
proxyclient/m1n1/fw/dcp/client.py
Normal file
|
@ -0,0 +1,10 @@
|
||||||
|
# SPDX-License-Identifier: MIT
|
||||||
|
from ...utils import *
|
||||||
|
|
||||||
|
from ..asc import StandardASC
|
||||||
|
from .dcpep import DCPEndpoint
|
||||||
|
|
||||||
|
class DCPClient(StandardASC):
|
||||||
|
ENDPOINTS = {
|
||||||
|
0x37: DCPEndpoint,
|
||||||
|
}
|
162
proxyclient/m1n1/fw/dcp/dcpep.py
Normal file
162
proxyclient/m1n1/fw/dcp/dcpep.py
Normal file
|
@ -0,0 +1,162 @@
|
||||||
|
# SPDX-License-Identifier: MIT
|
||||||
|
import struct
|
||||||
|
from dataclasses import dataclass
|
||||||
|
from enum import IntEnum
|
||||||
|
|
||||||
|
from ..asc.base import *
|
||||||
|
from ...utils import *
|
||||||
|
|
||||||
|
## DCP main endpoint
|
||||||
|
|
||||||
|
class DCPMessage(Register64):
|
||||||
|
TYPE = 3, 0
|
||||||
|
|
||||||
|
class DCPEp_SetShmem(DCPMessage):
|
||||||
|
DVA = 63, 16
|
||||||
|
FLAG = 7, 4, Constant(4)
|
||||||
|
TYPE = 3, 0, Constant(0)
|
||||||
|
|
||||||
|
class DCPEp_InitComplete(DCPMessage):
|
||||||
|
TYPE = 3, 0, Constant(1)
|
||||||
|
|
||||||
|
class CallContext(IntEnum):
|
||||||
|
CB = 0
|
||||||
|
CMD = 2
|
||||||
|
ASYNC = 3
|
||||||
|
OOBCB = 4
|
||||||
|
OOBCMD = 6
|
||||||
|
|
||||||
|
class DCPEp_Msg(DCPMessage):
|
||||||
|
LEN = 63, 32
|
||||||
|
OFF = 31, 16
|
||||||
|
CTX = 11, 8, CallContext
|
||||||
|
ACK = 6
|
||||||
|
TYPE = 3, 0, Constant(2)
|
||||||
|
|
||||||
|
@dataclass
|
||||||
|
class DCPCallState:
|
||||||
|
tag: str
|
||||||
|
off: int
|
||||||
|
in_len: int
|
||||||
|
in_data: bytes
|
||||||
|
out_addr: int
|
||||||
|
out_len: int
|
||||||
|
complete: bool = False
|
||||||
|
|
||||||
|
class DCPCallChannel(Reloadable):
|
||||||
|
def __init__(self, dcpep, name, buf, bufsize):
|
||||||
|
self.dcp = dcpep
|
||||||
|
self.name = name
|
||||||
|
self.buf = buf
|
||||||
|
self.bufsize = bufsize
|
||||||
|
self.off = 0
|
||||||
|
self.pending = []
|
||||||
|
|
||||||
|
def ack(self):
|
||||||
|
if not self.pending:
|
||||||
|
raise Exception("ACK with no calls pending")
|
||||||
|
|
||||||
|
self.pending[-1].complete = True
|
||||||
|
|
||||||
|
def call(self, ctx, tag, inbuf, out_len):
|
||||||
|
in_len = len(inbuf)
|
||||||
|
data = tag.encode("ascii")[::-1] + struct.pack("<II", in_len, out_len) + inbuf
|
||||||
|
data_size = len(data) + out_len
|
||||||
|
assert (self.off + data_size) <= self.bufsize
|
||||||
|
|
||||||
|
self.dcp.asc.iface.writemem(self.dcp.shmem + self.buf + self.off, data)
|
||||||
|
|
||||||
|
state = DCPCallState(off=self.off, tag=tag, in_len=in_len, in_data=data, out_len=out_len,
|
||||||
|
out_addr=self.buf + self.off + 12 + in_len)
|
||||||
|
|
||||||
|
self.off += align_up(data_size, 0x40)
|
||||||
|
self.pending.append(state)
|
||||||
|
|
||||||
|
print(f"len={data_size:#x} {in_len}")
|
||||||
|
self.dcp.send(DCPEp_Msg(LEN=data_size, OFF=state.off, CTX=ctx, ACK=0))
|
||||||
|
|
||||||
|
while not state.complete:
|
||||||
|
self.dcp.asc.work()
|
||||||
|
|
||||||
|
print(f"off={state.out_addr:#x} len={out_len}")
|
||||||
|
out_data = self.dcp.asc.iface.readmem(self.dcp.shmem + state.out_addr, out_len)
|
||||||
|
|
||||||
|
assert self.pending.pop() is state
|
||||||
|
self.off = state.off
|
||||||
|
|
||||||
|
return out_data
|
||||||
|
|
||||||
|
class DCPCallbackChannel(Reloadable):
|
||||||
|
def __init__(self, dcpep, name, buf, bufsize):
|
||||||
|
self.dcp = dcpep
|
||||||
|
self.name = name
|
||||||
|
self.buf = buf
|
||||||
|
self.bufsize = bufsize
|
||||||
|
self.pending = []
|
||||||
|
|
||||||
|
def cb(self, msg):
|
||||||
|
data = self.dcp.asc.iface.readmem(self.dcp.shmem + self.buf + msg.OFF, msg.LEN)
|
||||||
|
tag = data[:4][::-1].decode("ascii")
|
||||||
|
in_len, out_len = struct.unpack("<II", data[4:12])
|
||||||
|
in_data = data[12:12 + in_len]
|
||||||
|
|
||||||
|
state = DCPCallState(off=msg.OFF, tag=tag, in_len=in_len, out_len=out_len,
|
||||||
|
in_data=in_data, out_addr=self.buf + msg.OFF + 12 + in_len)
|
||||||
|
|
||||||
|
self.pending.append(state)
|
||||||
|
|
||||||
|
out_data = self.dcp.mgr.handle_cb(state)
|
||||||
|
self.dcp.asc.iface.writemem(self.dcp.shmem + state.out_addr, out_data)
|
||||||
|
self.dcp.send(DCPEp_Msg(CTX=msg.CTX, ACK=1))
|
||||||
|
|
||||||
|
assert self.pending.pop() is state
|
||||||
|
|
||||||
|
|
||||||
|
class DCPEndpoint(ASCBaseEndpoint):
|
||||||
|
BASE_MESSAGE = DCPMessage
|
||||||
|
SHORT = "dcpep"
|
||||||
|
|
||||||
|
def __init__(self, *args, **kwargs):
|
||||||
|
super().__init__(*args, **kwargs)
|
||||||
|
self.shmem = self.shmem_dva = None
|
||||||
|
self.init_complete = False
|
||||||
|
self.mgr = None
|
||||||
|
|
||||||
|
self.ch_cb = DCPCallbackChannel(self, "CB", 0x60000, 0x8000)
|
||||||
|
self.ch_cmd = DCPCallChannel(self, "CMD", 0, 0x8000)
|
||||||
|
self.ch_async = DCPCallbackChannel(self, "ASYNC", 0x40000, 0x20000)
|
||||||
|
self.ch_oobcb = DCPCallbackChannel(self, "OOBCB", 0x68000, 0x8000)
|
||||||
|
self.ch_oobcmd = DCPCallChannel(self, "OOBCMD", 0x8000, 0x8000)
|
||||||
|
|
||||||
|
@msg_handler(2, DCPEp_Msg)
|
||||||
|
def Rx(self, msg):
|
||||||
|
if msg.ACK:
|
||||||
|
if msg.CTX in (CallContext.CMD, CallContext.CB):
|
||||||
|
self.ch_cmd.ack()
|
||||||
|
elif msg.CTX in (CallContext.OOBCMD, CallContext.OOBCB):
|
||||||
|
self.ch_oobcmd.ack()
|
||||||
|
else:
|
||||||
|
raise Exception(f"Unknown RX ack channel {msg.CTX}")
|
||||||
|
else:
|
||||||
|
if msg.CTX == CallContext.CB:
|
||||||
|
self.ch_cb.cb(msg)
|
||||||
|
elif msg.CTX == CallContext.OOBCMD:
|
||||||
|
self.ch_oobcb.cb(msg)
|
||||||
|
elif msg.CTX == CallContext.ASYNC:
|
||||||
|
self.ch_async.cb(msg)
|
||||||
|
else:
|
||||||
|
raise Exception(f"Unknown RX callback channel {msg.CTX}")
|
||||||
|
return True
|
||||||
|
|
||||||
|
@msg_handler(1, DCPEp_InitComplete)
|
||||||
|
def InitComplete(self, msg):
|
||||||
|
self.log("init complete")
|
||||||
|
self.init_complete = True
|
||||||
|
return True
|
||||||
|
|
||||||
|
def initialize(self):
|
||||||
|
self.shmem, self.shmem_dva = self.asc.ioalloc(0x100000)
|
||||||
|
self.send(DCPEp_SetShmem(DVA=self.shmem_dva))
|
||||||
|
while not self.init_complete:
|
||||||
|
self.asc.work()
|
||||||
|
|
|
@ -1,10 +1,16 @@
|
||||||
# SPDX-License-Identifier: MIT
|
# 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 = { ">": "<", "<": ">" }
|
||||||
|
|
211
proxyclient/m1n1/fw/dcp/manager.py
Normal file
211
proxyclient/m1n1/fw/dcp/manager.py
Normal file
|
@ -0,0 +1,211 @@
|
||||||
|
# SPDX-License-Identifier: MIT
|
||||||
|
import struct, functools
|
||||||
|
from dataclasses import dataclass
|
||||||
|
from enum import IntEnum
|
||||||
|
|
||||||
|
from construct.lib import hexundump
|
||||||
|
|
||||||
|
from ..asc.base import *
|
||||||
|
from ...utils import *
|
||||||
|
|
||||||
|
from . import ipc
|
||||||
|
from .dcpep import CallContext
|
||||||
|
|
||||||
|
## DCP API manager
|
||||||
|
|
||||||
|
class DCPBaseManager:
|
||||||
|
def __init__(self, dcpep):
|
||||||
|
self.dcpep = dcpep
|
||||||
|
self.dcp = dcpep.asc
|
||||||
|
dcpep.mgr = self
|
||||||
|
|
||||||
|
self.name_map = {}
|
||||||
|
self.tag_map = {}
|
||||||
|
|
||||||
|
self.in_callback = 0
|
||||||
|
|
||||||
|
for k, (cls, v) in ipc.ALL_METHODS.items():
|
||||||
|
self.name_map[v.name] = k, v
|
||||||
|
self.tag_map[k] = v
|
||||||
|
|
||||||
|
def handle_cb(self, state):
|
||||||
|
method = self.tag_map.get(state.tag, None)
|
||||||
|
if method is None:
|
||||||
|
raise Exception(f"Unknown callback {state.tag}")
|
||||||
|
|
||||||
|
func = getattr(self, method.name, None)
|
||||||
|
|
||||||
|
if func is None:
|
||||||
|
raise Exception(f"Unimplemented callback {method!s} [{state.tag}]")
|
||||||
|
|
||||||
|
self.in_callback += 1
|
||||||
|
try:
|
||||||
|
retval = method.callback(func, state.in_data)
|
||||||
|
except Exception as e:
|
||||||
|
print(f"Exception in callback {method.name}")
|
||||||
|
raise
|
||||||
|
self.in_callback -= 1
|
||||||
|
return retval
|
||||||
|
|
||||||
|
def __getattr__(self, attr):
|
||||||
|
tag, method = self.name_map.get(attr, (None, None))
|
||||||
|
if method is None or tag.startswith("D"):
|
||||||
|
raise AttributeError(f"Unknown method {attr}")
|
||||||
|
|
||||||
|
out_len = method.out_struct.sizeof()
|
||||||
|
if self.in_callback:
|
||||||
|
ctx = CallContext.CB
|
||||||
|
else:
|
||||||
|
ctx = CallContext.CMD
|
||||||
|
rpc = functools.partial(self.dcpep.ch_cmd.call, ctx, tag, out_len=out_len)
|
||||||
|
return functools.partial(method.call, rpc)
|
||||||
|
|
||||||
|
class DCPManager(DCPBaseManager):
|
||||||
|
def __init__(self, dcpep):
|
||||||
|
super().__init__(dcpep)
|
||||||
|
|
||||||
|
self.iomfb_prop = {}
|
||||||
|
self.dcpav_prop = {}
|
||||||
|
self.service_prop = {}
|
||||||
|
self.pr_prop = {}
|
||||||
|
|
||||||
|
self.swaps = 0
|
||||||
|
self.frame = 0
|
||||||
|
|
||||||
|
self.mapid = 0
|
||||||
|
|
||||||
|
## IOMobileFramebufferAP methods
|
||||||
|
|
||||||
|
def find_swap_function_gated(self):
|
||||||
|
pass
|
||||||
|
|
||||||
|
def create_provider_service(self):
|
||||||
|
return True
|
||||||
|
|
||||||
|
def create_product_service(self):
|
||||||
|
return True
|
||||||
|
|
||||||
|
def create_PMU_service(self):
|
||||||
|
return True
|
||||||
|
|
||||||
|
def create_iomfb_service(self):
|
||||||
|
return True
|
||||||
|
|
||||||
|
def create_backlight_service(self):
|
||||||
|
return False
|
||||||
|
|
||||||
|
def setProperty(self, key, value):
|
||||||
|
self.iomfb_prop[key] = value
|
||||||
|
print(f"setProperty({key} = {value!r})")
|
||||||
|
return True
|
||||||
|
|
||||||
|
setProperty_dict = setProperty_int = setProperty_bool = setProperty_str = setProperty
|
||||||
|
|
||||||
|
def swap_complete_ap_gated(self, arg0, arg1, arg2, arg3, arg4):
|
||||||
|
print(f"swap_complete_ap_gated({arg0}, {arg1}, ..., ..., {arg4}")
|
||||||
|
chexdump(arg2)
|
||||||
|
chexdump(arg3)
|
||||||
|
self.swaps += 1
|
||||||
|
self.frame = arg0
|
||||||
|
|
||||||
|
## UPPipeAP_H13P methods
|
||||||
|
|
||||||
|
def did_boot_signal(self):
|
||||||
|
return True
|
||||||
|
|
||||||
|
def did_power_on_signal(self):
|
||||||
|
return True
|
||||||
|
|
||||||
|
def rt_bandwidth_setup_ap(self, config):
|
||||||
|
print("rt_bandwidth_setup_ap(...)")
|
||||||
|
config.val = {"data":unhex("""
|
||||||
|
6C 43 6C 6F 63 6B 00 44 14 80 73 3B 02 00 00 00
|
||||||
|
00 C0 C3 3B 02 00 00 00 00 00 00 00 02 00 00 00
|
||||||
|
00 00 00 00 90 26 FB 43 FF FF FF FF 04 00 00 00
|
||||||
|
00 00 00 00 65 04 00 00 00 00 00 00
|
||||||
|
""")}
|
||||||
|
## UnifiedPipeline2 methods
|
||||||
|
|
||||||
|
def match_pmu_service(self):
|
||||||
|
pass
|
||||||
|
|
||||||
|
def create_provider_service(self):
|
||||||
|
return True
|
||||||
|
|
||||||
|
def read_edt_data(self, key, count, value):
|
||||||
|
return False
|
||||||
|
|
||||||
|
def UNK_get_some_field(self):
|
||||||
|
return 0
|
||||||
|
|
||||||
|
def start_hardware_boot(self):
|
||||||
|
self.set_create_DFB()
|
||||||
|
self.do_create_default_frame_buffer()
|
||||||
|
self.setup_video_limits()
|
||||||
|
self.flush_supportsPower(True)
|
||||||
|
self.late_init_signal()
|
||||||
|
self.setDisplayRefreshProperties()
|
||||||
|
return True
|
||||||
|
|
||||||
|
def setDCPAVPropStart(self, length):
|
||||||
|
print(f"setDCPAVPropStart({length:#x})")
|
||||||
|
return True
|
||||||
|
|
||||||
|
def setDCPAVPropChunk(self, data, offset, length):
|
||||||
|
print(f"setDCPAVPropChunk(..., {offset:#x}, {length:#x})")
|
||||||
|
return True
|
||||||
|
|
||||||
|
def setDCPAVPropEnd(self, key):
|
||||||
|
print(f"setDCPAVPropEnd({key!r})")
|
||||||
|
return True
|
||||||
|
|
||||||
|
def is_waking_from_hibernate(self):
|
||||||
|
return False
|
||||||
|
|
||||||
|
## UPPipe2 methods
|
||||||
|
|
||||||
|
def match_pmu_service_2(self):
|
||||||
|
return True
|
||||||
|
|
||||||
|
def match_backlight_service(self):
|
||||||
|
return True
|
||||||
|
|
||||||
|
## ServiceRelay methods
|
||||||
|
|
||||||
|
def sr_setProperty(self, obj, key, value):
|
||||||
|
self.service_prop.setdefault(obj, {})[key] = value
|
||||||
|
print(f"sr_setProperty({obj}/{key} = {value!r})")
|
||||||
|
return True
|
||||||
|
|
||||||
|
def sr_getClockFrequency(self, obj, arg):
|
||||||
|
print(f"sr_getClockFrequency({obj}, {arg})")
|
||||||
|
return 533333328
|
||||||
|
|
||||||
|
sr_setProperty_dict = sr_setProperty_int = sr_setProperty_bool = sr_setProperty_str = sr_setProperty
|
||||||
|
|
||||||
|
def sr_get_uint_prop(self, obj, key, value):
|
||||||
|
value.val = 0
|
||||||
|
return False
|
||||||
|
|
||||||
|
def sr_mapDeviceMemoryWithIndex(self, obj, index, flags, addr, length):
|
||||||
|
assert obj == "PROV"
|
||||||
|
addr.val, length.val = self.dcp.u.adt["/arm-io/disp0"].get_reg(index)
|
||||||
|
print(f"sr_mapDeviceMemoryWithIndex({obj}, {index}, {flags}, {addr.val:#x}, {length.val:#x})")
|
||||||
|
return 0
|
||||||
|
|
||||||
|
## PropRelay methods
|
||||||
|
|
||||||
|
def pr_publish(self, prop_id, value):
|
||||||
|
self.pr_prop[prop_id] = value
|
||||||
|
print(f"pr_publish({prop_id}, {value!r})")
|
||||||
|
|
||||||
|
## MemDescRelay methods:
|
||||||
|
|
||||||
|
def map_physical(self, paddr, size, flags, dva, dvasize):
|
||||||
|
dvasize.val = align_up(size, 4096)
|
||||||
|
dva.val = self.dcp.dart.iomap(0, paddr, size)
|
||||||
|
print(f"map_physical({paddr:#x}, {size:#x}, {flags}, {dva.val:#x}, {dvasize.val:#x})")
|
||||||
|
|
||||||
|
self.mapid += 1
|
||||||
|
return self.mapid
|
||||||
|
|
|
@ -23,14 +23,20 @@ def parse_log(fd):
|
||||||
yield op
|
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
|
||||||
|
|
|
@ -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=" ")
|
||||||
|
|
88
proxyclient/m1n1/hw/asc.py
Normal file
88
proxyclient/m1n1/hw/asc.py
Normal 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
|
|
@ -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)
|
||||||
|
|
||||||
|
|
|
@ -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)
|
||||||
|
|
|
@ -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}")
|
||||||
|
|
|
@ -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)
|
||||||
|
|
|
@ -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)
|
||||||
|
|
Loading…
Reference in a new issue