xref: /linux/drivers/soc/apple/rtkit-crashlog.c (revision 5d7f3375cd574fc83f0cd30839b21455c0e79ae2)
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_AARCH32 FOURCC('C', 'r', 'g', 'A')
17 #define APPLE_RTKIT_CRASHLOG_AARCH64 FOURCC('C', 'r', 'g', '8')
18 
19 /* For COMPILE_TEST on non-ARM64 architectures */
20 #ifndef PSR_MODE_EL0t
21 #define PSR_MODE_EL0t	0x00000000
22 #define PSR_MODE_EL1t	0x00000004
23 #define PSR_MODE_EL1h	0x00000005
24 #define PSR_MODE_EL2t	0x00000008
25 #define PSR_MODE_EL2h	0x00000009
26 #define PSR_MODE_MASK	0x0000000f
27 #endif
28 
29 /*
30  * AArch32 mode definitions: APPLE_RTKIT depends on APPLE_MAILBOX, which
31  * depends on 64BIT, so there is no need to care about COMPILE_TEST on ARM.
32  */
33 #define USR_MODE        0x00000010
34 #define FIQ_MODE        0x00000011
35 #define IRQ_MODE        0x00000012
36 #define SVC_MODE        0x00000013
37 #define MON_MODE        0x00000016
38 #define ABT_MODE        0x00000017
39 #define HYP_MODE        0x0000001a
40 #define UND_MODE        0x0000001b
41 #define SYSTEM_MODE     0x0000001f
42 #define MODE_MASK_32    0x0000001f
43 
44 struct apple_rtkit_crashlog_header {
45 	u32 fourcc;
46 	u32 version;
47 	u32 size;
48 	u32 flags;
49 	u8 _unk[16];
50 };
51 static_assert(sizeof(struct apple_rtkit_crashlog_header) == 0x20);
52 
53 struct apple_rtkit_crashlog_mbox_entry {
54 	u64 msg0;
55 	u64 msg1;
56 	u32 timestamp;
57 	u8 _unk[4];
58 };
59 static_assert(sizeof(struct apple_rtkit_crashlog_mbox_entry) == 0x18);
60 
61 struct apple_rtkit_crashlog_aarch64 {
62 	u32 unk_0;
63 	u32 unk_4;
64 	u64 regs[31];
65 	u64 sp;
66 	u64 pc;
67 	u64 psr;
68 	u64 cpacr;
69 	u64 fpsr;
70 	u64 fpcr;
71 	u64 unk[64];
72 	u64 far;
73 	u64 unk_X;
74 	u64 esr;
75 	u64 unk_Z;
76 } __packed;
77 static_assert(sizeof(struct apple_rtkit_crashlog_aarch64) == 0x350);
78 
79 struct apple_rtkit_crashlog_aarch32 {
80 	u32 unk_0;
81 	u32 unk_4;
82 	u32 regs[16];
83 	u32 psr;
84 	u32 unk_x1;
85 	u8 stack[0x100];
86 	u32 unk_x2;
87 	u32 unk_x3;
88 	u32 unk_x4;
89 	u32 unk_x5;
90 } __packed;
91 static_assert(sizeof(struct apple_rtkit_crashlog_aarch32) == 0x160);
92 
93 static void apple_rtkit_crashlog_dump_str(struct apple_rtkit *rtk, u8 *bfr,
94 					  size_t size)
95 {
96 	u32 idx;
97 	u8 *ptr, *end;
98 
99 	memcpy(&idx, bfr, 4);
100 
101 	ptr = bfr + 4;
102 	end = bfr + size;
103 	while (ptr < end) {
104 		u8 *newline = memchr(ptr, '\n', end - ptr);
105 
106 		if (newline) {
107 			u8 tmp = *newline;
108 			*newline = '\0';
109 			dev_warn(rtk->dev, "RTKit: Message (id=%x): %s\n", idx,
110 				 ptr);
111 			*newline = tmp;
112 			ptr = newline + 1;
113 		} else {
114 			dev_warn(rtk->dev, "RTKit: Message (id=%x): %s", idx,
115 				 ptr);
116 			break;
117 		}
118 	}
119 }
120 
121 static void apple_rtkit_crashlog_dump_version(struct apple_rtkit *rtk, u8 *bfr,
122 					      size_t size)
123 {
124 	dev_warn(rtk->dev, "RTKit: Version: %s", bfr + 16);
125 }
126 
127 static void apple_rtkit_crashlog_dump_time(struct apple_rtkit *rtk, u8 *bfr,
128 					   size_t size)
129 {
130 	u64 crash_time;
131 
132 	memcpy(&crash_time, bfr, 8);
133 	dev_warn(rtk->dev, "RTKit: Crash time: %lld", crash_time);
134 }
135 
136 static void apple_rtkit_crashlog_dump_mailbox(struct apple_rtkit *rtk, u8 *bfr,
137 					      size_t size)
138 {
139 	u32 type, index, i;
140 	size_t n_messages;
141 	struct apple_rtkit_crashlog_mbox_entry entry;
142 
143 	memcpy(&type, bfr + 16, 4);
144 	memcpy(&index, bfr + 24, 4);
145 	n_messages = (size - 28) / sizeof(entry);
146 
147 	dev_warn(rtk->dev, "RTKit: Mailbox history (type = %d, index = %d)",
148 		 type, index);
149 	for (i = 0; i < n_messages; ++i) {
150 		memcpy(&entry, bfr + 28 + i * sizeof(entry), sizeof(entry));
151 		dev_warn(rtk->dev, "RTKit:  #%03d@%08x: %016llx %016llx", i,
152 			 entry.timestamp, entry.msg0, entry.msg1);
153 	}
154 }
155 
156 static void apple_rtkit_crashlog_dump_aarch32(struct apple_rtkit *rtk, u8 *bfr,
157 					      size_t size)
158 {
159 	struct apple_rtkit_crashlog_aarch32 *state;
160 	const char *mode;
161 	int i;
162 
163 	if (size < sizeof(*state)) {
164 		dev_warn(rtk->dev, "RTKit: AArch32 section too small: 0x%zx", size);
165 		return;
166 	}
167 
168 	state = (struct apple_rtkit_crashlog_aarch32 *)bfr;
169 
170 	switch (state->psr & MODE_MASK_32) {
171 	case USR_MODE:
172 		mode = "User";
173 		break;
174 	case FIQ_MODE:
175 		mode = "FIQ";
176 		break;
177 	case IRQ_MODE:
178 		mode = "IRQ";
179 		break;
180 	case SVC_MODE:
181 		mode = "Supervisor";
182 		break;
183 	case MON_MODE:
184 		mode = "Monitor";
185 		break;
186 	case ABT_MODE:
187 		mode = "Abort";
188 		break;
189 	case HYP_MODE:
190 		mode = "Hypervisor";
191 		break;
192 	case UND_MODE:
193 		mode = "Undefined";
194 		break;
195 	case SYSTEM_MODE:
196 		mode = "System";
197 		break;
198 	default:
199 		mode = "Unknown";
200 		break;
201 	}
202 
203 	dev_warn(rtk->dev, "RTKit: Exception dump:");
204 	dev_warn(rtk->dev, "  == Exception taken from %s mode ==", mode);
205 	dev_warn(rtk->dev, "  PSR    = 0x%x", state->psr);
206 	dev_warn(rtk->dev, "\n");
207 
208 	for (i = 0; i < 16; i += 4)
209 		dev_warn(rtk->dev,
210 				 "  r%02d-r%02d = %08x %08x %08x %08x\n",
211 				 i, i + 3,
212 				 state->regs[i], state->regs[i + 1],
213 				 state->regs[i + 2], state->regs[i + 3]);
214 
215 	dev_warn(rtk->dev, "\n");
216 }
217 
218 static void apple_rtkit_crashlog_dump_aarch64(struct apple_rtkit *rtk, u8 *bfr,
219 					      size_t size)
220 {
221 	struct apple_rtkit_crashlog_aarch64 *state;
222 	const char *el;
223 	int i;
224 
225 	if (size < sizeof(*state)) {
226 		dev_warn(rtk->dev, "RTKit: AArch64 section too small: 0x%zx",
227 			 size);
228 		return;
229 	}
230 
231 	state = (struct apple_rtkit_crashlog_aarch64 *)bfr;
232 
233 	switch (state->psr & PSR_MODE_MASK) {
234 	case PSR_MODE_EL0t:
235 		el = "EL0t";
236 		break;
237 	case PSR_MODE_EL1t:
238 		el = "EL1t";
239 		break;
240 	case PSR_MODE_EL1h:
241 		el = "EL1h";
242 		break;
243 	case PSR_MODE_EL2t:
244 		el = "EL2t";
245 		break;
246 	case PSR_MODE_EL2h:
247 		el = "EL2h";
248 		break;
249 	default:
250 		el = "unknown";
251 		break;
252 	}
253 
254 	dev_warn(rtk->dev, "RTKit: Exception dump:");
255 	dev_warn(rtk->dev, "  == Exception taken from %s ==", el);
256 	dev_warn(rtk->dev, "  PSR    = 0x%llx", state->psr);
257 	dev_warn(rtk->dev, "  PC     = 0x%llx\n", state->pc);
258 	dev_warn(rtk->dev, "  ESR    = 0x%llx\n", state->esr);
259 	dev_warn(rtk->dev, "  FAR    = 0x%llx\n", state->far);
260 	dev_warn(rtk->dev, "  SP     = 0x%llx\n", state->sp);
261 	dev_warn(rtk->dev, "\n");
262 
263 	for (i = 0; i < 31; i += 4) {
264 		if (i < 28)
265 			dev_warn(rtk->dev,
266 					 "  x%02d-x%02d = %016llx %016llx %016llx %016llx\n",
267 					 i, i + 3,
268 					 state->regs[i], state->regs[i + 1],
269 					 state->regs[i + 2], state->regs[i + 3]);
270 		else
271 			dev_warn(rtk->dev,
272 					 "  x%02d-x%02d = %016llx %016llx %016llx\n", i, i + 3,
273 					 state->regs[i], state->regs[i + 1], state->regs[i + 2]);
274 	}
275 
276 	dev_warn(rtk->dev, "\n");
277 }
278 
279 void apple_rtkit_crashlog_dump(struct apple_rtkit *rtk, u8 *bfr, size_t size)
280 {
281 	size_t offset;
282 	u32 section_fourcc, section_size;
283 	struct apple_rtkit_crashlog_header header;
284 
285 	memcpy(&header, bfr, sizeof(header));
286 	if (header.fourcc != APPLE_RTKIT_CRASHLOG_HEADER) {
287 		dev_warn(rtk->dev, "RTKit: Expected crashlog header but got %x",
288 			 header.fourcc);
289 		return;
290 	}
291 
292 	if (header.size > size) {
293 		dev_warn(rtk->dev, "RTKit: Crashlog size (%x) is too large",
294 			 header.size);
295 		return;
296 	}
297 
298 	size = header.size;
299 	offset = sizeof(header);
300 
301 	while (offset < size) {
302 		memcpy(&section_fourcc, bfr + offset, 4);
303 		memcpy(&section_size, bfr + offset + 12, 4);
304 
305 		switch (section_fourcc) {
306 		case APPLE_RTKIT_CRASHLOG_HEADER:
307 			dev_dbg(rtk->dev, "RTKit: End of crashlog reached");
308 			return;
309 		case APPLE_RTKIT_CRASHLOG_STR:
310 			apple_rtkit_crashlog_dump_str(rtk, bfr + offset + 16,
311 						      section_size);
312 			break;
313 		case APPLE_RTKIT_CRASHLOG_VERSION:
314 			apple_rtkit_crashlog_dump_version(
315 				rtk, bfr + offset + 16, section_size);
316 			break;
317 		case APPLE_RTKIT_CRASHLOG_MBOX:
318 			apple_rtkit_crashlog_dump_mailbox(
319 				rtk, bfr + offset + 16, section_size);
320 			break;
321 		case APPLE_RTKIT_CRASHLOG_TIME:
322 			apple_rtkit_crashlog_dump_time(rtk, bfr + offset + 16,
323 						       section_size);
324 			break;
325 		case APPLE_RTKIT_CRASHLOG_AARCH32:
326 			apple_rtkit_crashlog_dump_aarch32(rtk, bfr + offset + 16,
327 							  section_size);
328 			break;
329 		case APPLE_RTKIT_CRASHLOG_AARCH64:
330 			apple_rtkit_crashlog_dump_aarch64(rtk, bfr + offset + 16,
331 							  section_size);
332 			break;
333 		default:
334 			dev_warn(rtk->dev,
335 				 "RTKit: Unknown crashlog section: %x",
336 				 section_fourcc);
337 		}
338 
339 		offset += section_size;
340 	}
341 
342 	dev_warn(rtk->dev,
343 		 "RTKit: End of crashlog reached but no footer present");
344 }
345