summaryrefslogtreecommitdiff
path: root/tools/proxyclient/m1n1/fw/asc
diff options
context:
space:
mode:
authormagh <magh@maghmogh.com>2023-03-06 18:44:55 -0600
committermagh <magh@maghmogh.com>2023-03-06 18:44:55 -0600
commite80d9d8871b325a04b18f90a9ea4bb7fd148fb25 (patch)
tree79dbdb8506b7ff1e92549188d1b94cfc0b3503ae /tools/proxyclient/m1n1/fw/asc
add m1n1HEADmaster
Diffstat (limited to 'tools/proxyclient/m1n1/fw/asc')
-rw-r--r--tools/proxyclient/m1n1/fw/asc/__init__.py125
-rw-r--r--tools/proxyclient/m1n1/fw/asc/base.py59
-rw-r--r--tools/proxyclient/m1n1/fw/asc/crash.py248
-rw-r--r--tools/proxyclient/m1n1/fw/asc/ioreporting.py56
-rw-r--r--tools/proxyclient/m1n1/fw/asc/kdebug.py57
-rw-r--r--tools/proxyclient/m1n1/fw/asc/mgmt.py144
-rw-r--r--tools/proxyclient/m1n1/fw/asc/oslog.py30
-rw-r--r--tools/proxyclient/m1n1/fw/asc/syslog.py72
8 files changed, 791 insertions, 0 deletions
diff --git a/tools/proxyclient/m1n1/fw/asc/__init__.py b/tools/proxyclient/m1n1/fw/asc/__init__.py
new file mode 100644
index 0000000..4ffdb8b
--- /dev/null
+++ b/tools/proxyclient/m1n1/fw/asc/__init__.py
@@ -0,0 +1,125 @@
+# 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, ASCTimeout
+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=None, stream=0):
+ super().__init__(u, asc_base)
+ self.remote_eps = set()
+ self.add_ep(0, ASCManagementEndpoint(self, 0))
+ self.dart = dart
+ self.stream = stream
+ self.eps = []
+ self.epcls = {}
+ self.dva_offset = 0
+ self.dva_size = 1 << 32
+ self.allow_phys = False
+
+ 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 addr(self, addr):
+ return f"{addr:#x}"
+
+ def iomap(self, addr, size):
+ if self.dart is None:
+ return addr
+ dva = self.dva_offset | self.dart.iomap(self.stream, addr, size)
+
+ self.dart.invalidate_streams(1)
+ return dva
+
+ def ioalloc(self, size):
+ paddr = self.u.memalign(0x4000, size)
+ dva = self.iomap(paddr, size)
+ return paddr, dva
+
+ def ioread(self, dva, size):
+ if self.allow_phys and dva < self.dva_offset or dva >= (self.dva_offset + self.dva_size):
+ return self.iface.readmem(dva, size)
+
+ if self.dart:
+ return self.dart.ioread(self.stream, dva & 0xFFFFFFFFF, size)
+ else:
+ return self.iface.readmem(dva, size)
+
+ def iowrite(self, dva, data):
+ if self.allow_phys and dva < self.dva_offset or dva >= (self.dva_offset + self.dva_size):
+ return self.iface.writemem(dva, data)
+
+ if self.dart:
+ return self.dart.iowrite(self.stream, dva & 0xFFFFFFFFF, data)
+ else:
+ return self.iface.writemem(dva, data)
+
+ def iotranslate(self, dva, size):
+ if self.allow_phys and dva < self.dva_offset or dva >= (self.dva_offset + self.dva_size):
+ return [(dva, size)]
+
+ if self.dart:
+ return self.dart.iotranslate(self.stream, dva & 0xFFFFFFFFF, size)
+ else:
+ return [(dva, size)]
+
+ 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):
+ super().boot()
+ self.mgmt.start()
+ self.mgmt.wait_boot(3)
+
+ def stop(self, state=0x10):
+ for ep in list(self.epmap.values())[::-1]:
+ if ep.epnum < 0x10:
+ continue
+ ep.stop()
+ self.mgmt.stop(state=state)
+ self.epmap = {}
+ self.add_ep(0, ASCManagementEndpoint(self, 0))
+ if state < 0x10:
+ self.shutdown()
+
+ def boot(self):
+ print("Booting ASC...")
+ super().boot()
+ self.mgmt.wait_boot(1)
+
+__all__.extend(k for k, v in globals().items()
+ if (callable(v) or isinstance(v, type)) and v.__module__ == __name__)
diff --git a/tools/proxyclient/m1n1/fw/asc/base.py b/tools/proxyclient/m1n1/fw/asc/base.py
new file mode 100644
index 0000000..b10aaaf
--- /dev/null
+++ b/tools/proxyclient/m1n1/fw/asc/base.py
@@ -0,0 +1,59 @@
+# 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 ASCTimeout(Exception):
+ pass
+
+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 stop(self):
+ pass
+
+ def log(self, msg):
+ print(f"[{self.name}] {msg}")
diff --git a/tools/proxyclient/m1n1/fw/asc/crash.py b/tools/proxyclient/m1n1/fw/asc/crash.py
new file mode 100644
index 0000000..7f590c8
--- /dev/null
+++ b/tools/proxyclient/m1n1/fw/asc/crash.py
@@ -0,0 +1,248 @@
+# SPDX-License-Identifier: MIT
+from .base import *
+from ...utils import *
+from construct import *
+from ...sysreg import *
+
+class CrashLogMessage(Register64):
+ TYPE = 63, 52
+ SIZE = 51, 44
+ DVA = 43, 0
+
+CrashHeader = Struct(
+ "type" / Const("CLHE", FourCC),
+ "ver" / Int32ul,
+ "total_size" / Int32ul,
+ "flags" / Int32ul,
+ Padding(16)
+)
+
+CrashCver = Struct(
+ "uuid" / Bytes(16),
+ "version" / CString("utf8"),
+)
+
+CrashCstr = Struct(
+ "id" / Int32ul,
+ "string" / CString("utf8"),
+)
+
+CrashCtim = Struct(
+ "time" / Int64ul,
+)
+
+CrashCmbx = Struct(
+ "hdr" / Array(4, Hex(Int32ul)),
+ "type" / Int32ul,
+ "unk" / Int32ul,
+ "index" / Int32ul,
+ "messages" / GreedyRange(Struct(
+ "endpoint" / Hex(Int64ul),
+ "message" / Hex(Int64ul),
+ "timestamp" / Hex(Int32ul),
+ Padding(4),
+ )),
+)
+
+CrashCcst = Struct(
+ "task" / Int32ul,
+ "unk" / Int32ul,
+ "stack" / GreedyRange(Int64ul)
+)
+
+CrashCasC = Struct(
+ "l2c_err_sts" / Hex(Int64ul),
+ "l2c_err_adr" / Hex(Int64ul),
+ "l2c_err_inf" / Hex(Int64ul),
+ "lsu_err_sts" / Hex(Int64ul),
+ "fed_err_sts" / Hex(Int64ul),
+ "mmu_err_sts" / Hex(Int64ul)
+)
+
+CrashCrg8 = Struct(
+ "unk_0" / Int32ul,
+ "unk_4" / Int32ul,
+ "regs" / Array(31, Hex(Int64ul)),
+ "sp" / Int64ul,
+ "pc" / Int64ul,
+ "psr" / Int64ul,
+ "cpacr" / Int64ul,
+ "fpsr" / Int64ul,
+ "fpcr" / Int64ul,
+ "unk" / Array(64, Hex(Int64ul)),
+ "far" / Int64ul,
+ "unk_X" / Int64ul,
+ "esr" / Int64ul,
+ "unk_Z" / Int64ul,
+)
+
+CrashEntry = Struct(
+ "type" / FourCC,
+ Padding(4),
+ "flags" / Hex(Int32ul),
+ "len" / Int32ul,
+ "payload" / FixedSized(lambda ctx: ctx.len - 16 if ctx.type != "CLHE" else 16,
+ Switch(this.type, {
+ "Cver": CrashCver,
+ "Ctim": CrashCtim,
+ "Cmbx": CrashCmbx,
+ "Cstr": CrashCstr,
+ "Crg8": CrashCrg8,
+ "Ccst": CrashCcst,
+ "CasC": CrashCasC,
+ }, default=GreedyBytes)),
+)
+
+CrashLog = Struct(
+ "header" / CrashHeader,
+ "entries" / RepeatUntil(this.type == "CLHE", CrashEntry),
+)
+
+class CrashLogParser:
+ def __init__(self, data=None, asc=None):
+ self.asc = asc
+ if data is not None:
+ self.parse(data)
+
+ def parse(self, data):
+ self.data = CrashLog.parse(data)
+ pass
+
+ def default(self, entry):
+ print(f"# {entry.type} flags={entry.flags:#x}")
+ chexdump(entry.payload)
+ print()
+
+ def Ccst(self, entry):
+ print(f"Call stack (task {entry.payload.task}:")
+ for i in entry.payload.stack:
+ if not i:
+ break
+ print(f" - {i:#x}")
+ print()
+
+ def CasC(self, entry):
+ print(f"Async error info:")
+ print(entry.payload)
+ print()
+
+ def Cver(self, entry):
+ print(f"RTKit Version: {entry.payload.version}")
+ print()
+
+ def Crg8(self, entry):
+ print(f"Exception info:")
+
+ ctx = entry.payload
+
+ addr = self.asc.addr
+
+ spsr = SPSR(ctx.psr)
+ esr = ESR(ctx.esr)
+ elr = ctx.pc
+ far_phys = self.asc.iotranslate(ctx.far, 1)[0][0]
+ elr_phys = self.asc.iotranslate(ctx.pc, 1)[0][0]
+ sp_phys = self.asc.iotranslate(ctx.sp, 1)[0][0]
+
+ print(f" == Exception taken from {spsr.M.name} ==")
+ el = spsr.M >> 2
+ print(f" SPSR = {spsr}")
+ print(f" ELR = {addr(elr)}" + (f" (0x{elr_phys:x})" if elr_phys else ""))
+ print(f" ESR = {esr}")
+ print(f" FAR = {addr(ctx.far)}" + (f" (0x{far_phys:x})" if far_phys else ""))
+ print(f" SP = {ctx.sp:#x}" + (f" (0x{sp_phys:x})" if sp_phys else ""))
+
+ for i in range(0, 31, 4):
+ j = min(30, i + 3)
+ print(f" {f'x{i}-x{j}':>7} = {' '.join(f'{r:016x}' for r in ctx.regs[i:j + 1])}")
+
+ if elr_phys:
+ v = self.asc.p.read32(elr_phys)
+
+ print()
+ if v == 0xabad1dea:
+ print(" == Faulting code is not available ==")
+ else:
+ print(" == Faulting code ==")
+ dist = 16
+ self.asc.u.disassemble_at(elr_phys - dist * 4, (dist * 2 + 1) * 4, elr_phys)
+
+ print()
+
+ def Cstr(self, entry):
+ print(f"Message {entry.payload.id}: {entry.payload.string}")
+ print()
+
+ def Ctim(self, entry):
+ print(f"Crash time: {entry.payload.time:#x}")
+ print()
+
+ def Cmbx(self, entry):
+ print(f"Mailbox log (type {entry.payload.type}, index {entry.payload.index}):")
+ for i, msg in enumerate(entry.payload.messages):
+ print(f" #{i:3d} @{msg.timestamp:#10x} ep={msg.endpoint:#4x} {msg.message:#18x}")
+ print()
+
+ def CLHE(self, entry):
+ pass
+
+ def dump(self):
+ print("### Crash dump:")
+ print()
+ for entry in self.data.entries:
+ getattr(self, entry.type, self.default)(entry)
+
+class ASCCrashLogEndpoint(ASCBaseEndpoint):
+ SHORT = "crash"
+ BASE_MESSAGE = CrashLogMessage
+
+ def __init__(self, *args, **kwargs):
+ super().__init__(*args, **kwargs)
+ self.iobuffer = None
+ self.iobuffer_dva = None
+ self.started = False
+
+ @msg_handler(0x1)
+ def Handle(self, msg):
+ if self.started:
+ return self.handle_crashed(msg)
+ else:
+ return self.handle_getbuf(msg)
+
+ def handle_getbuf(self, msg):
+ size = align(0x1000 * msg.SIZE, 0x4000)
+
+ if msg.DVA:
+ self.iobuffer_dva = msg.DVA
+ self.log(f"buf prealloc at dva {self.iobuffer_dva:#x}")
+ else:
+ self.iobuffer, self.iobuffer_dva = self.asc.ioalloc(size)
+ self.log(f"buf {self.iobuffer:#x} / {self.iobuffer_dva:#x}")
+ self.send(CrashLogMessage(TYPE=1, SIZE=size // 0x1000, DVA=self.iobuffer_dva))
+
+ self.started = True
+ return True
+
+ def crash_soft(self):
+ self.send(0x40)
+
+ def crash_hard(self):
+ self.send(0x22)
+
+ def handle_crashed(self, msg):
+ size = 0x1000 * msg.SIZE
+
+ self.log(f"Crashed!")
+ crashdata = self.asc.ioread(msg.DVA, size)
+ open("crash.bin", "wb").write(crashdata)
+ clog = CrashLogParser(crashdata, self.asc)
+ clog.dump()
+ raise Exception("ASC crashed!")
+
+ return True
+
+if __name__ == "__main__":
+ import sys
+ crashdata = open(sys.argv[1], "rb").read()
+ clog = CrashLogParser(crashdata)
+ clog.dump()
diff --git a/tools/proxyclient/m1n1/fw/asc/ioreporting.py b/tools/proxyclient/m1n1/fw/asc/ioreporting.py
new file mode 100644
index 0000000..f81b6c6
--- /dev/null
+++ b/tools/proxyclient/m1n1/fw/asc/ioreporting.py
@@ -0,0 +1,56 @@
+# 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)
+ SIZE = 51, 44
+ 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!")
+
+ self.bufsize = align(0x1000 * msg.SIZE, 0x4000)
+
+ if msg.DVA != 0:
+ self.iobuffer = self.iobuffer_dva = msg.DVA
+ self.log(f"buf {self.iobuffer:#x} / {self.iobuffer_dva:#x}")
+ else:
+ self.iobuffer, self.iobuffer_dva = self.asc.ioalloc(self.bufsize)
+ self.log(f"buf {self.iobuffer:#x} / {self.iobuffer_dva:#x}")
+ self.send(IOReporting_GetBuf(DVA=self.iobuffer_dva, SIZE=self.bufsize // 0x1000))
+
+ 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, self.bufsize)
+ #chexdump(buf)
+ self.send(IOReporting_Report())
+ return True
diff --git a/tools/proxyclient/m1n1/fw/asc/kdebug.py b/tools/proxyclient/m1n1/fw/asc/kdebug.py
new file mode 100644
index 0000000..32a433f
--- /dev/null
+++ b/tools/proxyclient/m1n1/fw/asc/kdebug.py
@@ -0,0 +1,57 @@
+# 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 KDebugPreallocBuf1Message(KDebugMessage):
+ TYPE = 55, 48, Constant(2)
+ DVA = 47, 12
+ FLAGS = 11, 0
+
+class KDebugPreallocBuf2Message(KDebugMessage):
+ TYPE = 55, 48, Constant(3)
+ DVA = 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
+
+ @msg_handler(2, KDebugPreallocBuf1Message)
+ def SetBuf1(self, msg):
+ #self.send(KDebugSendBufMessage(TYPE=1, DVA=msg.DVA))
+ return True
+
+ @msg_handler(3, KDebugPreallocBuf2Message)
+ def SetBuf2(self, msg):
+ #self.send(KDebugSendBufMessage(TYPE=2, DVA=msg.DVA))
+ return True
+
+ def start(self):
+ self.iobuffer0 = None
+ self.iobuffer1 = None
+ self.iobuffer0_iova = None
+ self.iobuffer1_iova = None
+ self.send(KDebugStart())
diff --git a/tools/proxyclient/m1n1/fw/asc/mgmt.py b/tools/proxyclient/m1n1/fw/asc/mgmt.py
new file mode 100644
index 0000000..162fcd2
--- /dev/null
+++ b/tools/proxyclient/m1n1/fw/asc/mgmt.py
@@ -0,0 +1,144 @@
+# SPDX-License-Identifier: MIT
+import time
+
+from .base import *
+from ...utils import *
+
+## Management endpoint
+class ManagementMessage(Register64):
+ TYPE = 59, 52
+
+class Mgmt_Hello(ManagementMessage):
+ TYPE = 59, 52, Constant(1)
+ MAX_VER = 31, 16
+ MIN_VER = 15, 0
+
+class Mgmt_HelloAck(ManagementMessage):
+ TYPE = 59, 52, Constant(2)
+ MAX_VER = 31, 16
+ MIN_VER = 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, 0
+
+class Mgmt_SetIOPPower(ManagementMessage):
+ TYPE = 59, 52, Constant(6)
+ STATE = 15, 0
+
+class Mgmt_IOPPowerAck(ManagementMessage):
+ TYPE = 59, 52, Constant(7)
+ STATE = 15, 0
+
+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_SetAPPower(ManagementMessage):
+ TYPE = 59, 52, Constant(0xb)
+ STATE = 15, 0
+
+class ASCManagementEndpoint(ASCBaseEndpoint):
+ BASE_MESSAGE = ManagementMessage
+ SHORT = "mgmt"
+
+ def __init__(self, *args, **kwargs):
+ super().__init__(*args, **kwargs)
+ self.syslog_started = False
+ self.iop_power_state = 0
+ self.ap_power_state = 0
+ self.verbose = 1
+
+ @msg_handler(1, Mgmt_Hello)
+ def Hello(self, msg):
+ self.log(f"Supported versions {msg.MIN_VER} .. {msg.MAX_VER}")
+ # FIXME: we pick the highest version, we should negotiate
+ self.send(Mgmt_HelloAck(MIN_VER=msg.MAX_VER, MAX_VER=msg.MAX_VER))
+ 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)
+ if self.verbose > 0:
+ self.log(f"Adding endpoint {epno:#x}")
+
+ 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)
+ self.boot_done()
+
+ return True
+
+ @msg_handler(0xb, Mgmt_SetAPPower)
+ def APPowerAck(self, msg):
+ if self.verbose > 0:
+ self.log(f"AP power state is now {msg.STATE:#x}")
+ self.ap_power_state = msg.STATE
+ return True
+
+ @msg_handler(7, Mgmt_IOPPowerAck)
+ def IOPPowerAck(self, msg):
+ if self.verbose > 0:
+ self.log(f"IOP power state is now {msg.STATE:#x}")
+ self.iop_power_state = msg.STATE
+ return True
+
+ @msg_handler(4, Mgmt_Pong)
+ def Pong(self, msg):
+ return True
+
+ def start(self):
+ self.log("Starting via message")
+ self.send(Mgmt_SetIOPPower(STATE=0x220))
+
+ def wait_boot(self, timeout=None):
+ if timeout is not None:
+ timeout += time.time()
+ while self.iop_power_state != 0x20 or self.ap_power_state != 0x20:
+ self.asc.work()
+ if timeout and time.time() > timeout:
+ raise ASCTimeout("Boot timed out")
+ self.log("Startup complete")
+
+ def start_ep(self, epno):
+ self.send(Mgmt_StartEP(EP=epno, FLAG=2))
+
+ def stop_ep(self, epno):
+ self.send(Mgmt_StartEP(EP=epno, FLAG=1))
+
+ def boot_done(self):
+ self.send(Mgmt_SetAPPower(STATE=0x20))
+
+ def ping(self):
+ self.send(Mgmt_Ping())
+
+ def stop(self, state=0x10):
+ self.log("Stopping via message")
+ self.send(Mgmt_SetAPPower(STATE=0x10))
+ while self.ap_power_state == 0x20:
+ self.asc.work()
+ self.send(Mgmt_SetIOPPower(STATE=state))
+ while self.iop_power_state != state:
+ self.asc.work()
diff --git a/tools/proxyclient/m1n1/fw/asc/oslog.py b/tools/proxyclient/m1n1/fw/asc/oslog.py
new file mode 100644
index 0000000..b1a360b
--- /dev/null
+++ b/tools/proxyclient/m1n1/fw/asc/oslog.py
@@ -0,0 +1,30 @@
+# SPDX-License-Identifier: MIT
+from .base import *
+from ...utils import *
+
+## OSLog endpoint
+
+class OSLogMessage(Register64):
+ TYPE = 63, 56
+
+class OSLog_Init(OSLogMessage):
+ TYPE = 63, 56, Constant(1)
+ UNK = 51, 0
+
+class OSLog_Ack(OSLogMessage):
+ TYPE = 63, 56, Constant(3)
+
+class ASCOSLogEndpoint(ASCBaseEndpoint):
+ BASE_MESSAGE = OSLogMessage
+ SHORT = "oslog"
+
+ def __init__(self, *args, **kwargs):
+ super().__init__(*args, **kwargs)
+ self.started = False
+
+ @msg_handler(1, OSLog_Init)
+ def Init(self, msg):
+ self.log(f"oslog init: {msg.UNK:#x}")
+ self.send(OSLog_Ack())
+ self.started = True
+ return True
diff --git a/tools/proxyclient/m1n1/fw/asc/syslog.py b/tools/proxyclient/m1n1/fw/asc/syslog.py
new file mode 100644
index 0000000..3387c27
--- /dev/null
+++ b/tools/proxyclient/m1n1/fw/asc/syslog.py
@@ -0,0 +1,72 @@
+# 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)
+ SIZE = 51, 44
+ 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 = align(0x1000 * msg.SIZE, 0x4000)
+
+ if self.iobuffer:
+ print("WARNING: trying to reset iobuffer!")
+
+ if msg.DVA:
+ self.iobuffer_dva = msg.DVA
+ self.log(f"buf prealloc at dva {self.iobuffer_dva:#x}")
+ else:
+ self.iobuffer, self.iobuffer_dva = self.asc.ioalloc(size)
+ self.log(f"buf {self.iobuffer:#x} / {self.iobuffer_dva:#x}")
+ self.send(Syslog_GetBuf(SIZE=size // 0x1000, 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.ioread(self.iobuffer_dva + 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