m1n1.hw/fw.asc: Add basic ASC driver and RTKit handling

Signed-off-by: Hector Martin <marcan@marcan.st>
This commit is contained in:
Hector Martin 2021-08-14 16:35:59 +09:00
parent 7b01b0525b
commit 27a0a15eee
9 changed files with 550 additions and 0 deletions

View file

@ -0,0 +1,68 @@
# SPDX-License-Identifier: MIT
from ...utils import *
from .crash import ASCCrashLogEndpoint
from .syslog import ASCSysLogEndpoint
from .mgmt import ASCManagementEndpoint
from .kdebug import ASCKDebugEndpoint
from .ioreporting import ASCIOReportingEndpoint
from .oslog import ASCOSLogEndpoint
from .base import ASCBaseEndpoint
from ...hw.asc import ASC
__all__ = []
class ASCDummyEndpoint(ASCBaseEndpoint):
SHORT = "dummy"
class StandardASC(ASC):
ENDPOINTS = {
0: ASCManagementEndpoint,
1: ASCCrashLogEndpoint,
2: ASCSysLogEndpoint,
3: ASCKDebugEndpoint,
4: ASCIOReportingEndpoint,
8: ASCOSLogEndpoint,
0xa: ASCDummyEndpoint, # tracekit
}
def __init__(self, u, asc_base, dart):
super().__init__(u, asc_base)
self.remote_eps = set()
self.add_ep(0, ASCManagementEndpoint(self, 0))
self.dart = dart
self.eps = []
self.epcls = {}
for cls in type(self).mro():
eps = getattr(cls, "ENDPOINTS", None)
if eps is None:
break
for k, v in eps.items():
if k not in self.epcls:
self.epcls[k] = v
def iomap(self, addr, size):
return 0xf00000000 | self.dart.iomap(0, addr, size)
def ioalloc(self, size):
paddr = self.u.memalign(0x4000, size)
dva = self.iomap(paddr, size)
return paddr, dva
def start_ep(self, epno):
if epno not in self.epcls:
raise Exception(f"Unknown endpoint {epno:#x}")
epcls = self.epcls[epno]
ep = epcls(self, epno)
self.add_ep(epno, ep)
print(f"Starting endpoint #{epno:#x} ({ep.name})")
self.mgmt.start_ep(epno)
ep.start()
def start(self):
self.mgmt.start()
__all__.extend(k for k, v in globals().items()
if (callable(v) or isinstance(v, type)) and v.__module__ == __name__)

View file

@ -0,0 +1,53 @@
# SPDX-License-Identifier: MIT
from ...utils import *
# System endpoints
def msg_handler(message, regtype=None):
def f(x):
x.is_message = True
x.message = message
x.regtype = regtype
return x
return f
class ASCMessage1(Register64):
EP = 7, 0
class ASCBaseEndpoint:
BASE_MESSAGE = Register64
SHORT = None
def __init__(self, asc, epnum, name=None):
self.asc = asc
self.epnum = epnum
self.name = name or self.SHORT or f"{type(self).__name__}@{epnum:#x}"
self.msghandler = {}
self.msgtypes = {}
for name in dir(self):
i = getattr(self, name)
if not callable(i):
continue
if not getattr(i, "is_message", False):
continue
self.msghandler[i.message] = i
self.msgtypes[i.message] = i.regtype if i.regtype else self.BASE_MESSAGE
def handle_msg(self, msg0, msg1):
msg0 = self.BASE_MESSAGE(msg0)
handler = self.msghandler.get(msg0.TYPE, None)
regtype = self.msgtypes.get(msg0.TYPE, self.BASE_MESSAGE)
if handler is None:
return False
return handler(regtype(msg0.value))
def send(self, msg):
self.asc.send(msg, ASCMessage1(EP=self.epnum))
def start(self):
pass
def log(self, msg):
print(f"[{self.name}] {msg}")

View file

@ -0,0 +1,41 @@
# SPDX-License-Identifier: MIT
from .base import *
from ...utils import *
class CrashLogMessage(Register64):
TYPE = 63, 44
class CrashLog_TranslateDva(Register64):
TYPE = 63, 44, Constant(0x104)
ADDR = 43, 0
class CrashLog_Crashed(Register64):
TYPE = 63, 44, Constant(0x103)
DVA = 43, 0
class ASCCrashLogEndpoint(ASCBaseEndpoint):
SHORT = "crash"
BASE_MESSAGE = CrashLogMessage
@msg_handler(0x104, CrashLog_TranslateDva)
def TranslateDva(self, msg):
ranges = self.asc.dart.iotranslate(0, msg.ADDR & 0xffffffff, 4096)
assert len(ranges) == 1
self.crashbuf = ranges[0][0]
self.log(f"Translate {msg.ADDR:#x} -> {self.crashbuf:#x}")
self.send(CrashLog_TranslateDva(ADDR=self.crashbuf))
return True
def crash_soft(self):
self.send(0x40)
def crash_hard(self):
self.send(0x22)
@msg_handler(0x103, CrashLog_Crashed)
def Crashed(self, msg):
self.log(f"Crashed!")
crashdata = self.asc.dart.ioread(0, msg.DVA & 0xffffffff, 2048)
chexdump(crashdata)
return True

View file

@ -0,0 +1,50 @@
# SPDX-License-Identifier: MIT
from .base import *
from ...utils import *
class IOReportingMessage(Register64):
TYPE = 63, 52
class IOReporting_GetBuf(IOReportingMessage):
TYPE = 63, 52, Constant(1)
BUFTYPE = 51, 44, Constant(4)
DVA = 43, 0
class IOReporting_Start(IOReportingMessage):
TYPE = 63, 52, Constant(0xc)
class IOReporting_Report(IOReportingMessage):
TYPE = 63, 52, Constant(0x8)
class ASCIOReportingEndpoint(ASCBaseEndpoint):
BASE_MESSAGE = IOReportingMessage
SHORT = "iorep"
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
self.iobuffer = None
self.iobuffer_dva = None
@msg_handler(1, IOReporting_GetBuf)
def GetBuf(self, msg):
if self.iobuffer:
self.log("WARNING: trying to reset iobuffer!")
size = 0x4000
self.iobuffer, self.iobuffer_dva = self.asc.ioalloc(size)
self.log(f"buf {self.iobuffer:#x} / {self.iobuffer_dva:#x}")
self.send(IOReporting_GetBuf(DVA=self.iobuffer_dva))
return True
@msg_handler(0xc, IOReporting_Start)
def Start(self, msg):
self.log("start")
return True
@msg_handler(8, IOReporting_Report)
def Init(self, msg):
self.log("report!")
buf = self.asc.iface.readmem(self.iobuffer, 0x4000)
#chexdump(buf)
self.send(IOReporting_Report())
return True

View file

@ -0,0 +1,38 @@
# SPDX-License-Identifier: MIT
from .base import *
from ...utils import *
class KDebugMessage(Register64):
TYPE = 55, 48
class KDebugGetBufMessage(KDebugMessage):
TYPE = 55, 48, Constant(1)
COUNT = 47, 0
class KDebugSendBufMessage(KDebugMessage):
TYPE = 55, 48
DVA = 47, 0
class KDebugStart(KDebugMessage):
TYPE = 55, 48, Constant(8)
class ASCKDebugEndpoint(ASCBaseEndpoint):
SHORT = "kdebug"
BASE_MESSAGE = KDebugMessage
@msg_handler(1, KDebugGetBufMessage)
def GetBuf(self, msg):
size = align_up(msg.COUNT * 0x20, 0x4000)
self.iobuffer0, self.iobuffer0_iova = self.asc.ioalloc(size)
self.send(KDebugSendBufMessage(TYPE=1, DVA=self.iobuffer0_iova))
self.iobuffer1, self.iobuffer1_iova = self.asc.ioalloc(0x2000)
self.send(KDebugSendBufMessage(TYPE=2, DVA=self.iobuffer1_iova))
return True
def start(self):
self.iobuffer0 = None
self.iobuffer1 = None
self.iobuffer0_iova = None
self.iobuffer1_iova = None
self.send(KDebugStart())

View file

@ -0,0 +1,112 @@
# SPDX-License-Identifier: MIT
from .base import *
from ...utils import *
## Management endpoint
class ManagementMessage(Register64):
TYPE = 59, 52
class Mgmt_Hello(ManagementMessage):
TYPE = 59, 52, Constant(1)
UNK1 = 31, 16
UNK2 = 15, 0
class Mgmt_HelloAck(ManagementMessage):
TYPE = 59, 52, Constant(2)
UNK1 = 31, 16
UNK2 = 15, 0
class Mgmt_Ping(ManagementMessage):
TYPE = 59, 52, Constant(3)
class Mgmt_Pong(ManagementMessage):
TYPE = 59, 52, Constant(4)
class Mgmt_StartEP(ManagementMessage):
TYPE = 59, 52, Constant(5)
EP = 39, 32
FLAG = 1
class Mgmt_Init(ManagementMessage):
TYPE = 59, 52, Constant(6)
UNK = 15, 0
class Mgmt_BootDone(ManagementMessage):
TYPE = 59, 52, Constant(7)
class Mgmt_EPMap(ManagementMessage):
TYPE = 59, 52, Constant(8)
LAST = 51
BASE = 34, 32
BITMAP = 31, 0
class Mgmt_EPMap_Ack(ManagementMessage):
TYPE = 59, 52, Constant(8)
LAST = 51
BASE = 34, 32
MORE = 0
class Mgmt_StartSyslog(ManagementMessage):
TYPE = 59, 52, Constant(0xb)
UNK1 = 15, 0
class ASCManagementEndpoint(ASCBaseEndpoint):
BASE_MESSAGE = ManagementMessage
SHORT = "mgmt"
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
self.syslog_started = False
self.boot_done = False
@msg_handler(1, Mgmt_Hello)
def Hello(self, msg):
self.send(Mgmt_HelloAck(UNK1=msg.UNK1, UNK2=msg.UNK2))
return True
@msg_handler(8, Mgmt_EPMap)
def EPMap(self, msg):
for i in range(32):
if msg.BITMAP & (1 << i):
epno = 32 * msg.BASE + i
self.asc.eps.append(epno)
self.send(Mgmt_EPMap_Ack(BASE=msg.BASE, LAST=msg.LAST, MORE=0 if msg.LAST else 1))
if msg.LAST:
for ep in self.asc.eps:
if ep == 0: continue
if ep < 0x10:
self.asc.start_ep(ep)
return True
@msg_handler(0xb, Mgmt_StartSyslog)
def StartSyslogAck(self, msg):
self.syslog_started = True
return True
@msg_handler(7, Mgmt_BootDone)
def BootDone(self, msg):
#self.start_syslog()
self.boot_done = True
return True
@msg_handler(4, Mgmt_Pong)
def Pong(self, msg):
return True
def start(self):
self.send(Mgmt_Init(UNK=0x220))
while not self.boot_done or not self.syslog_started:
self.asc.work()
self.log("startup complete")
def start_ep(self, epno):
self.send(Mgmt_StartEP(EP=epno, FLAG=1))
def start_syslog(self):
self.send(Mgmt_StartSyslog(UNK1=0x20))
def ping(self):
self.send(Mgmt_Ping())

View file

@ -0,0 +1,30 @@
# SPDX-License-Identifier: MIT
from .base import *
from ...utils import *
## OSLog endpoint
class OSLogMessage(Register64):
TYPE = 63, 56
class OSLog_Init(OSLogMessage):
TYPE = 63, 56, Constant(1)
UNK = 51, 0
class OSLog_Ack(OSLogMessage):
TYPE = 63, 56, Constant(3)
class ASCOSLogEndpoint(ASCBaseEndpoint):
BASE_MESSAGE = OSLogMessage
SHORT = "oslog"
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
self.started = False
@msg_handler(1, OSLog_Init)
def Init(self, msg):
self.log(f"oslog init: {msg.UNK:#x}")
self.send(OSLog_Ack())
self.started = True
return True

View file

@ -0,0 +1,70 @@
# SPDX-License-Identifier: MIT
import struct
from .base import *
from ...utils import *
## Syslog endpoint
class SyslogMessage(Register64):
TYPE = 59, 52
class Syslog_Init(SyslogMessage):
TYPE = 59, 52, Constant(8)
ENTRYSIZE = 39, 24
COUNT = 15, 0
class Syslog_GetBuf(SyslogMessage):
TYPE = 59, 52, Constant(1)
UNK1 = 51, 44, Constant(3)
DVA = 43, 0
class Syslog_Log(SyslogMessage):
TYPE = 59, 52, Constant(5)
INDEX = 7, 0
class ASCSysLogEndpoint(ASCBaseEndpoint):
BASE_MESSAGE = SyslogMessage
SHORT = "syslog"
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
self.entrysize = None
self.count = None
self.iobuffer = None
self.iobuffer_dva = None
self.started = False
@msg_handler(8, Syslog_Init)
def Init(self, msg):
self.entrysize = msg.ENTRYSIZE
self.count = msg.COUNT
self.log(f"count {self.count}, entrysize {self.entrysize}")
return True
@msg_handler(1, Syslog_GetBuf)
def GetBuf(self, msg):
size = 0x4000
if self.iobuffer:
print("WARNING: trying to reset iobuffer!")
self.iobuffer, self.iobuffer_dva = self.asc.ioalloc(size)
self.log(f"buf {self.iobuffer:#x} / {self.iobuffer_dva:#x}")
self.send(Syslog_GetBuf(DVA=self.iobuffer_dva))
self.started = True
return True
@msg_handler(5, Syslog_Log)
def Log(self, msg):
stride = 0x20 + self.entrysize
log = self.asc.iface.readmem(self.iobuffer + msg.INDEX * stride, stride)
hdr, unk, context, logmsg = struct.unpack(f"<II24s{self.entrysize}s", log)
context = context.split(b"\x00")[0].decode("ascii")
logmsg = logmsg.split(b"\x00")[0].decode("ascii").rstrip("\n")
self.log(f"* [{context}]{logmsg}")
self.send(msg)
return True
def start(self):
self.asc.mgmt.start_syslog()

View file

@ -0,0 +1,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