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
apple_rtkit_crashlog_dump_str(struct apple_rtkit * rtk,u8 * bfr,size_t size)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
apple_rtkit_crashlog_dump_version(struct apple_rtkit * rtk,u8 * bfr,size_t size)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
apple_rtkit_crashlog_dump_time(struct apple_rtkit * rtk,u8 * bfr,size_t size)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
apple_rtkit_crashlog_dump_mailbox(struct apple_rtkit * rtk,u8 * bfr,size_t size)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
apple_rtkit_crashlog_dump_regs(struct apple_rtkit * rtk,u8 * bfr,size_t size)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
apple_rtkit_crashlog_dump(struct apple_rtkit * rtk,u8 * bfr,size_t size)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