Linux Audio

Check our new training course

Loading...
Note: File does not exist in v5.4.
  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
 28struct apple_rtkit_crashlog_header {
 29	u32 fourcc;
 30	u32 version;
 31	u32 size;
 32	u32 flags;
 33	u8 _unk[16];
 34};
 35static_assert(sizeof(struct apple_rtkit_crashlog_header) == 0x20);
 36
 37struct apple_rtkit_crashlog_mbox_entry {
 38	u64 msg0;
 39	u64 msg1;
 40	u32 timestamp;
 41	u8 _unk[4];
 42};
 43static_assert(sizeof(struct apple_rtkit_crashlog_mbox_entry) == 0x18);
 44
 45struct 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;
 61static_assert(sizeof(struct apple_rtkit_crashlog_regs) == 0x350);
 62
 63static 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
 91static 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
 97static 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
106static 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
126static 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
186void 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(&section_fourcc, bfr + offset, 4);
210		memcpy(&section_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}