1 // SPDX-License-Identifier: GPL-2.0-only OR MIT 2 /* 3 * Apple RTKit IPC library 4 * Copyright (C) The Asahi Linux Contributors 5 */ 6 #include "rtkit-internal.h" 7 8 #define FOURCC(a, b, c, d) \ 9 (((u32)(a) << 24) | ((u32)(b) << 16) | ((u32)(c) << 8) | ((u32)(d))) 10 11 #define APPLE_RTKIT_CRASHLOG_HEADER FOURCC('C', 'L', 'H', 'E') 12 #define APPLE_RTKIT_CRASHLOG_STR FOURCC('C', 's', 't', 'r') 13 #define APPLE_RTKIT_CRASHLOG_VERSION FOURCC('C', 'v', 'e', 'r') 14 #define APPLE_RTKIT_CRASHLOG_MBOX FOURCC('C', 'm', 'b', 'x') 15 #define APPLE_RTKIT_CRASHLOG_TIME FOURCC('C', 't', 'i', 'm') 16 #define APPLE_RTKIT_CRASHLOG_REGS FOURCC('C', 'r', 'g', '8') 17 18 /* For COMPILE_TEST on non-ARM64 architectures */ 19 #ifndef PSR_MODE_EL0t 20 #define PSR_MODE_EL0t 0x00000000 21 #define PSR_MODE_EL1t 0x00000004 22 #define PSR_MODE_EL1h 0x00000005 23 #define PSR_MODE_EL2t 0x00000008 24 #define PSR_MODE_EL2h 0x00000009 25 #define PSR_MODE_MASK 0x0000000f 26 #endif 27 28 struct apple_rtkit_crashlog_header { 29 u32 fourcc; 30 u32 version; 31 u32 size; 32 u32 flags; 33 u8 _unk[16]; 34 }; 35 static_assert(sizeof(struct apple_rtkit_crashlog_header) == 0x20); 36 37 struct apple_rtkit_crashlog_mbox_entry { 38 u64 msg0; 39 u64 msg1; 40 u32 timestamp; 41 u8 _unk[4]; 42 }; 43 static_assert(sizeof(struct apple_rtkit_crashlog_mbox_entry) == 0x18); 44 45 struct apple_rtkit_crashlog_regs { 46 u32 unk_0; 47 u32 unk_4; 48 u64 regs[31]; 49 u64 sp; 50 u64 pc; 51 u64 psr; 52 u64 cpacr; 53 u64 fpsr; 54 u64 fpcr; 55 u64 unk[64]; 56 u64 far; 57 u64 unk_X; 58 u64 esr; 59 u64 unk_Z; 60 } __packed; 61 static_assert(sizeof(struct apple_rtkit_crashlog_regs) == 0x350); 62 63 static void apple_rtkit_crashlog_dump_str(struct apple_rtkit *rtk, u8 *bfr, 64 size_t size) 65 { 66 u32 idx; 67 u8 *ptr, *end; 68 69 memcpy(&idx, bfr, 4); 70 71 ptr = bfr + 4; 72 end = bfr + size; 73 while (ptr < end) { 74 u8 *newline = memchr(ptr, '\n', end - ptr); 75 76 if (newline) { 77 u8 tmp = *newline; 78 *newline = '\0'; 79 dev_warn(rtk->dev, "RTKit: Message (id=%x): %s\n", idx, 80 ptr); 81 *newline = tmp; 82 ptr = newline + 1; 83 } else { 84 dev_warn(rtk->dev, "RTKit: Message (id=%x): %s", idx, 85 ptr); 86 break; 87 } 88 } 89 } 90 91 static void apple_rtkit_crashlog_dump_version(struct apple_rtkit *rtk, u8 *bfr, 92 size_t size) 93 { 94 dev_warn(rtk->dev, "RTKit: Version: %s", bfr + 16); 95 } 96 97 static void apple_rtkit_crashlog_dump_time(struct apple_rtkit *rtk, u8 *bfr, 98 size_t size) 99 { 100 u64 crash_time; 101 102 memcpy(&crash_time, bfr, 8); 103 dev_warn(rtk->dev, "RTKit: Crash time: %lld", crash_time); 104 } 105 106 static void apple_rtkit_crashlog_dump_mailbox(struct apple_rtkit *rtk, u8 *bfr, 107 size_t size) 108 { 109 u32 type, index, i; 110 size_t n_messages; 111 struct apple_rtkit_crashlog_mbox_entry entry; 112 113 memcpy(&type, bfr + 16, 4); 114 memcpy(&index, bfr + 24, 4); 115 n_messages = (size - 28) / sizeof(entry); 116 117 dev_warn(rtk->dev, "RTKit: Mailbox history (type = %d, index = %d)", 118 type, index); 119 for (i = 0; i < n_messages; ++i) { 120 memcpy(&entry, bfr + 28 + i * sizeof(entry), sizeof(entry)); 121 dev_warn(rtk->dev, "RTKit: #%03d@%08x: %016llx %016llx", i, 122 entry.timestamp, entry.msg0, entry.msg1); 123 } 124 } 125 126 static void apple_rtkit_crashlog_dump_regs(struct apple_rtkit *rtk, u8 *bfr, 127 size_t size) 128 { 129 struct apple_rtkit_crashlog_regs *regs; 130 const char *el; 131 int i; 132 133 if (size < sizeof(*regs)) { 134 dev_warn(rtk->dev, "RTKit: Regs section too small: 0x%zx", size); 135 return; 136 } 137 138 regs = (struct apple_rtkit_crashlog_regs *)bfr; 139 140 switch (regs->psr & PSR_MODE_MASK) { 141 case PSR_MODE_EL0t: 142 el = "EL0t"; 143 break; 144 case PSR_MODE_EL1t: 145 el = "EL1t"; 146 break; 147 case PSR_MODE_EL1h: 148 el = "EL1h"; 149 break; 150 case PSR_MODE_EL2t: 151 el = "EL2t"; 152 break; 153 case PSR_MODE_EL2h: 154 el = "EL2h"; 155 break; 156 default: 157 el = "unknown"; 158 break; 159 } 160 161 dev_warn(rtk->dev, "RTKit: Exception dump:"); 162 dev_warn(rtk->dev, " == Exception taken from %s ==", el); 163 dev_warn(rtk->dev, " PSR = 0x%llx", regs->psr); 164 dev_warn(rtk->dev, " PC = 0x%llx\n", regs->pc); 165 dev_warn(rtk->dev, " ESR = 0x%llx\n", regs->esr); 166 dev_warn(rtk->dev, " FAR = 0x%llx\n", regs->far); 167 dev_warn(rtk->dev, " SP = 0x%llx\n", regs->sp); 168 dev_warn(rtk->dev, "\n"); 169 170 for (i = 0; i < 31; i += 4) { 171 if (i < 28) 172 dev_warn(rtk->dev, 173 " x%02d-x%02d = %016llx %016llx %016llx %016llx\n", 174 i, i + 3, 175 regs->regs[i], regs->regs[i + 1], 176 regs->regs[i + 2], regs->regs[i + 3]); 177 else 178 dev_warn(rtk->dev, 179 " x%02d-x%02d = %016llx %016llx %016llx\n", i, i + 3, 180 regs->regs[i], regs->regs[i + 1], regs->regs[i + 2]); 181 } 182 183 dev_warn(rtk->dev, "\n"); 184 } 185 186 void apple_rtkit_crashlog_dump(struct apple_rtkit *rtk, u8 *bfr, size_t size) 187 { 188 size_t offset; 189 u32 section_fourcc, section_size; 190 struct apple_rtkit_crashlog_header header; 191 192 memcpy(&header, bfr, sizeof(header)); 193 if (header.fourcc != APPLE_RTKIT_CRASHLOG_HEADER) { 194 dev_warn(rtk->dev, "RTKit: Expected crashlog header but got %x", 195 header.fourcc); 196 return; 197 } 198 199 if (header.size > size) { 200 dev_warn(rtk->dev, "RTKit: Crashlog size (%x) is too large", 201 header.size); 202 return; 203 } 204 205 size = header.size; 206 offset = sizeof(header); 207 208 while (offset < size) { 209 memcpy(§ion_fourcc, bfr + offset, 4); 210 memcpy(§ion_size, bfr + offset + 12, 4); 211 212 switch (section_fourcc) { 213 case APPLE_RTKIT_CRASHLOG_HEADER: 214 dev_dbg(rtk->dev, "RTKit: End of crashlog reached"); 215 return; 216 case APPLE_RTKIT_CRASHLOG_STR: 217 apple_rtkit_crashlog_dump_str(rtk, bfr + offset + 16, 218 section_size); 219 break; 220 case APPLE_RTKIT_CRASHLOG_VERSION: 221 apple_rtkit_crashlog_dump_version( 222 rtk, bfr + offset + 16, section_size); 223 break; 224 case APPLE_RTKIT_CRASHLOG_MBOX: 225 apple_rtkit_crashlog_dump_mailbox( 226 rtk, bfr + offset + 16, section_size); 227 break; 228 case APPLE_RTKIT_CRASHLOG_TIME: 229 apple_rtkit_crashlog_dump_time(rtk, bfr + offset + 16, 230 section_size); 231 break; 232 case APPLE_RTKIT_CRASHLOG_REGS: 233 apple_rtkit_crashlog_dump_regs(rtk, bfr + offset + 16, 234 section_size); 235 break; 236 default: 237 dev_warn(rtk->dev, 238 "RTKit: Unknown crashlog section: %x", 239 section_fourcc); 240 } 241 242 offset += section_size; 243 } 244 245 dev_warn(rtk->dev, 246 "RTKit: End of crashlog reached but no footer present"); 247 } 248