diff options
| author | magh <magh@maghmogh.com> | 2023-03-06 18:44:55 -0600 |
|---|---|---|
| committer | magh <magh@maghmogh.com> | 2023-03-06 18:44:55 -0600 |
| commit | e80d9d8871b325a04b18f90a9ea4bb7fd148fb25 (patch) | |
| tree | 79dbdb8506b7ff1e92549188d1b94cfc0b3503ae /tools/proxyclient/m1n1/fw/asc | |
Diffstat (limited to 'tools/proxyclient/m1n1/fw/asc')
| -rw-r--r-- | tools/proxyclient/m1n1/fw/asc/__init__.py | 125 | ||||
| -rw-r--r-- | tools/proxyclient/m1n1/fw/asc/base.py | 59 | ||||
| -rw-r--r-- | tools/proxyclient/m1n1/fw/asc/crash.py | 248 | ||||
| -rw-r--r-- | tools/proxyclient/m1n1/fw/asc/ioreporting.py | 56 | ||||
| -rw-r--r-- | tools/proxyclient/m1n1/fw/asc/kdebug.py | 57 | ||||
| -rw-r--r-- | tools/proxyclient/m1n1/fw/asc/mgmt.py | 144 | ||||
| -rw-r--r-- | tools/proxyclient/m1n1/fw/asc/oslog.py | 30 | ||||
| -rw-r--r-- | tools/proxyclient/m1n1/fw/asc/syslog.py | 72 |
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 |
