|
| 1 | +from enum import IntEnum |
| 2 | +from construct import Struct, Default, Container, Int32ul |
| 3 | + |
| 4 | +import traceback |
| 5 | +from m1n1.setup import * # remove |
| 6 | + |
| 7 | +from m1n1.utils import * |
| 8 | +from m1n1.hw.dart import DART |
| 9 | +from m1n1.fw.asc import StandardASC, ASCBaseEndpoint, ASCTimeout |
| 10 | +from m1n1.fw.asc.base import msg_handler |
| 11 | + |
| 12 | +class SIOMessage(Register64): |
| 13 | + EP = 7, 0 |
| 14 | + TAG = 13, 8 |
| 15 | + TYPE = 23, 16 |
| 16 | + PARAM = 31, 24 |
| 17 | + DATA = 63, 32 |
| 18 | + |
| 19 | +class SIOStart(SIOMessage): |
| 20 | + TYPE = 23, 16, Constant(2) |
| 21 | + |
| 22 | +class SIOSetup(SIOMessage): |
| 23 | + TYPE = 23, 16, Constant(3) |
| 24 | + |
| 25 | +class SIOReadyChannel(SIOMessage): |
| 26 | + TYPE = 23, 16, Constant(5) |
| 27 | + |
| 28 | +class SIOIssueDescriptor(SIOMessage): |
| 29 | + TYPE = 23, 16, Constant(6) |
| 30 | + |
| 31 | +class SIOTerminate(SIOMessage): |
| 32 | + TYPE = 23, 16, Constant(8) |
| 33 | + |
| 34 | +class SIOAck(SIOMessage): |
| 35 | + TYPE = 23, 16, Constant(0x65) |
| 36 | + |
| 37 | +class SIONack(SIOMessage): |
| 38 | + TYPE = 23, 16, Constant(0x66) |
| 39 | + |
| 40 | +class SIOStarted(SIOMessage): |
| 41 | + TYPE = 23, 16, Constant(0x67) |
| 42 | + |
| 43 | +class SIODescriptorDone(SIOMessage): |
| 44 | + TYPE = 23, 16, Constant(0x68) |
| 45 | + |
| 46 | +class SIOShmem(IntEnum): |
| 47 | + MAIN = 0x1 |
| 48 | + |
| 49 | + UNK_0b = 0xb # macos size: 0x1b80 |
| 50 | + UNK_0f = 0xf # 0x1e000 |
| 51 | + UNK_1a = 0x1a # 0x50 |
| 52 | + UNK_1c = 0x1c # 0x40 |
| 53 | + UNK_1e = 0x1e # 0x30 |
| 54 | + UNK_22 = 0x22 # 0xa0 |
| 55 | + |
| 56 | + UNK_EP3_0d = 0x3_0d # 0x4000 |
| 57 | + |
| 58 | +class SIOChannel: |
| 59 | + def __init__(self, parent, channo): |
| 60 | + self.p = parent |
| 61 | + self.ch = channo |
| 62 | + |
| 63 | +SIOChannelConfig = Struct( |
| 64 | + "unk_0" / Default(Int32ul, 0), |
| 65 | + "unk_4" / Default(Int32ul, 0), |
| 66 | + "unk_8" / Default(Int32ul, 0), |
| 67 | + "unk_c" / Default(Int32ul, 0), |
| 68 | + "unk_10" / Default(Int32ul, 0), |
| 69 | +) |
| 70 | + |
| 71 | +def undump(text): |
| 72 | + return b"".join([int(v, 16).to_bytes(4, byteorder="little") for v in text.strip().split()]) |
| 73 | + |
| 74 | +class SIOEndpoint(ASCBaseEndpoint): |
| 75 | + BASE_MESSAGE = SIOMessage |
| 76 | + SHORT = "sioep" |
| 77 | + |
| 78 | + def __init__(self, *args, **kwargs): |
| 79 | + super().__init__(*args, **kwargs) |
| 80 | + self.tag = 0 |
| 81 | + self.acked, self.nacked = set(), set() |
| 82 | + self.bufs = {} |
| 83 | + self.started = False |
| 84 | + |
| 85 | + @msg_handler(0x65, SIOAck) |
| 86 | + def Ack(self, msg): |
| 87 | + self.acked.add(msg.TAG) |
| 88 | + return True |
| 89 | + |
| 90 | + @msg_handler(0x66, SIONack) |
| 91 | + def Nack(self, msg): |
| 92 | + self.nacked.add(msg.TAG) |
| 93 | + return True |
| 94 | + |
| 95 | + @msg_handler(0x67, SIOStarted) |
| 96 | + def Started(self, msg): |
| 97 | + self.started = True |
| 98 | + return True |
| 99 | + |
| 100 | + def next_tag(self): |
| 101 | + self.tag = (self.tag + 1) % 0x10 |
| 102 | + return self.tag |
| 103 | + |
| 104 | + def roundtrip(self, msg, timeout=0.1): |
| 105 | + msg.TAG = self.next_tag() |
| 106 | + self.send(msg) |
| 107 | + self.acked.discard(msg.TAG) |
| 108 | + self.nacked.discard(msg.TAG) |
| 109 | + deadline = time.time() + timeout |
| 110 | + while time.time() < deadline and msg.TAG not in self.acked: |
| 111 | + self.asc.work() |
| 112 | + if msg.TAG in self.nacked: |
| 113 | + raise Exception("ASC nacked a message") |
| 114 | + if msg.TAG not in self.acked: |
| 115 | + raise ASCTimeout("ASC reply timed out") |
| 116 | + |
| 117 | + def wait_for_started_msg(self, timeout=0.1): |
| 118 | + deadline = time.time() + timeout |
| 119 | + while time.time() < deadline and not self.started: |
| 120 | + self.asc.work() |
| 121 | + if not self.started: |
| 122 | + raise ASCTimeout("ASC reply timed out") |
| 123 | + |
| 124 | + def alloc_buf(self, param_id, size, data=b""): |
| 125 | + paddr, iova = self.asc.ioalloc(size) |
| 126 | + self.bufs[param_id] = (iova, size) |
| 127 | + self.write_shmem(param_id, 0, data) |
| 128 | + ep = param_id >> 8; param_id &= 0xff |
| 129 | + self.roundtrip(SIOSetup(EP=ep, PARAM=param_id, DATA=iova >> 12)) |
| 130 | + self.roundtrip(SIOSetup(EP=ep, PARAM=param_id + 1, DATA=size)) |
| 131 | + |
| 132 | + def start(self): |
| 133 | + self.send(SIOStart()) |
| 134 | + self.wait_for_started_msg() |
| 135 | + self.alloc_buf(SIOShmem.UNK_0f, 0x1e000) |
| 136 | + self.alloc_buf(SIOShmem.UNK_1a, 0x50, # map-range= |
| 137 | + undump(""" |
| 138 | + 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 |
| 139 | + 00000000 00000000 00000000 00000000 35000000 00000002 00004000 00000000 |
| 140 | + 00000000 00000000 00000000 00000000 |
| 141 | + """)) |
| 142 | + self.alloc_buf(SIOShmem.UNK_1e, 0x30, # asio-ascwrap-tunables= |
| 143 | + undump(""" |
| 144 | + 00000040 00000004 0000ff00 00000000 00000400 00000000 0000080c 00000004 |
| 145 | + 60000001 00000000 60000001 00000000 |
| 146 | + """)) |
| 147 | + dmashim_data = b"".join([ |
| 148 | + v.to_bytes(4, byteorder="little") \ |
| 149 | + for data in self.asc.node.dmashim |
| 150 | + for v in data.unk |
| 151 | + ]) |
| 152 | + self.alloc_buf(SIOShmem.UNK_22, 0xa0, dmashim_data) |
| 153 | + self.alloc_buf(SIOShmem.UNK_1c, 0x40, # device-type= |
| 154 | + undump(""" |
| 155 | + 00000005 00000000 00000009 00000000 00000000 00000000 00000002 0000000c |
| 156 | + 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 |
| 157 | + """)) |
| 158 | + self.alloc_buf(SIOShmem.UNK_EP3_0d, 0x4000) |
| 159 | + self.alloc_buf(SIOShmem.MAIN, 0xaaa) |
| 160 | + self.alloc_buf(SIOShmem.UNK_0b, 0x1b80) |
| 161 | + |
| 162 | + def write_shmem(self, area, base, data): |
| 163 | + iova, shmem_size = self.bufs[area] |
| 164 | + assert base + len(data) <= shmem_size |
| 165 | + print(iova + base, chexdump(data)) |
| 166 | + self.asc.iowrite(iova + base, data) |
| 167 | + |
| 168 | + def open_channel(self, channo, **config): |
| 169 | + self.write_shmem( |
| 170 | + SIOShmem.MAIN, 0, |
| 171 | + SIOChannelConfig.build(Container(**config)) |
| 172 | + ) |
| 173 | + self.roundtrip(SIOReadyChannel(EP=channo)) |
| 174 | + return SIOChannel(self, channo) |
| 175 | + |
| 176 | +class SIOClient(StandardASC): |
| 177 | + ENDPOINTS = { |
| 178 | + 0x20: SIOEndpoint, |
| 179 | + } |
| 180 | + |
| 181 | + def __init__(self, u, adtpath, dart=None): |
| 182 | + node = u.adt[adtpath] |
| 183 | + self.node = node |
| 184 | + self.base = node.get_reg(0)[0] |
| 185 | + super().__init__(u, self.base, dart) |
| 186 | + |
| 187 | + def map_data(self): |
| 188 | + segments = struct.unpack("<8q", self.node.segment_ranges) |
| 189 | + self.dart.iomap_at(0, segments[6], segments[4], segments[7] & ~(-1 << 32)) |
| 190 | + |
| 191 | +p.pmgr_adt_clocks_enable("/arm-io/dart-sio") |
| 192 | +p.pmgr_adt_clocks_enable("/arm-io/sio") |
| 193 | +p.pmgr_adt_clocks_enable("/arm-io/dp-audio0") |
| 194 | + |
| 195 | +dart = DART.from_adt(u, "/arm-io/dart-sio", iova_range=(0x30000, 0x10_000_000)) |
| 196 | + |
| 197 | +dart.initialize() |
| 198 | +dart.regs.TCR[0].set(BYPASS_DAPF=0, BYPASS_DART=0, TRANSLATE_ENABLE=1) |
| 199 | +dart.regs.TCR[15].set(BYPASS_DAPF=0, BYPASS_DART=1, TRANSLATE_ENABLE=0) |
| 200 | + |
| 201 | +sio = SIOClient(u, "/arm-io/sio", dart) |
| 202 | +sio.asc.CPU_CONTROL.val = 0x0 |
| 203 | +sio.verbose = 4 |
| 204 | +sio.map_data() |
| 205 | +sio.boot() |
| 206 | + |
| 207 | +try: |
| 208 | + sio.start_ep(0x20) |
| 209 | + dpaudio0 = sio.sioep.open_channel(0x64, |
| 210 | + unk_0=0x2, |
| 211 | + unk_8=0x800, |
| 212 | + unk_c=0x800, |
| 213 | + unk_10=0x800, |
| 214 | + ) |
| 215 | +except: |
| 216 | + traceback.print_exc() |
| 217 | + p.reboot() |
0 commit comments