xref: /rk3399_ARM-atf/bl31/aarch64/crash_reporting.S (revision e8e8fc56c53b5735104d9b27d8974568c68cafdb)
1/*
2 * Copyright (c) 2014-2026, Arm Limited and Contributors. All rights reserved.
3 *
4 * SPDX-License-Identifier: BSD-3-Clause
5 */
6
7#include <plat_macros.S>
8#include <platform_def.h>
9
10#include <arch.h>
11#include <asm_macros.S>
12#include <context.h>
13#include <lib/utils_def.h>
14
15	.globl	report_unhandled_exception
16	.globl	report_unhandled_interrupt
17	.globl	report_el3_panic
18
19#if CRASH_REPORTING
20/* need enough space in crash buffer to save 8 registers */
21#define CRASH_BUF_SIZE		(8 * CPU_WORD_SIZE)
22#define CRASH_BUF_SPACE		(CRASH_BUF_SIZE * PLATFORM_CORE_COUNT)
23
24.section .data.crash_buf
25crash_buf:
26	.align	3 /* log2 of CPU_WORD_SIZE */
27	.space  CRASH_BUF_SPACE
28
29	/* ------------------------------------------------------
30	 * The below section deals with dumping the system state
31	 * when an unhandled exception is taken in EL3.
32	 * The layout and the names of the registers which will
33	 * be dumped during a unhandled exception is given below.
34	 * ------------------------------------------------------
35	 */
36.section .rodata.crash_prints, "aS"
37print_spacer:
38	.asciz	"             = 0x"
39
40gp_regs:
41	.asciz	"x0", "x1", "x2", "x3", "x4", "x5", "x6", "x7",\
42		"x8", "x9", "x10", "x11", "x12", "x13", "x14", "x15",\
43		"x16", "x17", "x18", "x19", "x20", "x21", "x22",\
44		"x23", "x24", "x25", "x26", "x27", "x28", "x29", ""
45el3_sys_regs:
46	.asciz	"scr_el3", "sctlr_el3", "cptr_el3", "tcr_el3",\
47		"daif", "mair_el3", "spsr_el3", "elr_el3", "ttbr0_el3",\
48		"esr_el3", "far_el3", ""
49
50non_el3_sys_regs:
51	.asciz	"mpidr_el1", "sp_el0", "isr_el1", ""
52
53#if CTX_INCLUDE_AARCH32_REGS
54aarch32_regs:
55	.asciz	"dacr32_el2", "ifsr32_el2", ""
56#endif /* CTX_INCLUDE_AARCH32_REGS */
57
58panic_msg:
59	.asciz "PANIC in EL3.\nx30"
60excpt_msg:
61	.asciz "Unhandled Exception in EL3.\nx30"
62intr_excpt_msg:
63	.ascii "Unhandled Interrupt Exception in EL3.\n"
64x30_msg:
65	.asciz "x30"
66
67	/*
68	 * Helper function to print from crash buf.
69	 * The print loop is controlled by the buf size and
70	 * ascii reg name list which is passed in x6. The
71	 * function returns the crash buf address in x0.
72	 * Clobbers : x0 - x7, x20, sp
73	 */
74func size_controlled_print_helper
75#if ENABLE_FEAT_D128
76size_controlled_print_128:
77	/* Set flag to print 128-bit registers */
78	mov	x20, #1
79	b	1f
80
81size_controlled_print:
82	/* Set flag to print 64-bit registers */
83	mov	x20, #0
841:
85#else
86size_controlled_print:
87#endif
88	/* Save the lr */
89	mov	sp, x30
90	/* load the crash buf address */
91	mrs	x7, tpidr_el3
92test_size_list:
93	/* Calculate x5 always as it will be clobbered by asm_print_hex */
94	mrs	x5, tpidr_el3
95	add	x5, x5, #CRASH_BUF_SIZE
96	/* Test whether we have reached end of crash buf */
97	cmp	x7, x5
98	b.eq	exit_size_print
99	ldrb	w4, [x6]
100	/* Test whether we are at end of list */
101	cbz	w4, exit_size_print
102	mov	x4, x6
103	/* asm_print_str updates x4 to point to next entry in list */
104	bl	asm_print_str
105	/* x0 = number of symbols printed + 1 */
106	sub	x0, x4, x6
107	/* update x6 with the updated list pointer */
108	mov	x6, x4
109	bl	print_alignment
110	/* Print the high 64 bits (or whole 64-bit register) */
111	ldr	x4, [x7], #REGSZ
112	bl	asm_print_hex
113#if ENABLE_FEAT_D128
114	cbz	x20, 2f
115	/* Print the low 64 bits in case of a 128-bit register */
116	ldr	x4, [x7], #REGSZ
117	bl	asm_print_hex
1182:
119#endif
120	bl	asm_print_newline
121	b	test_size_list
122exit_size_print:
123	mov	x30, sp
124	ret
125endfunc size_controlled_print_helper
126
127	/* -----------------------------------------------------
128	 * This function calculates and prints required number
129	 * of space characters followed by "= 0x", based on the
130	 * length of ascii register name.
131 	 * x0: length of ascii register name + 1
132	 * ------------------------------------------------------
133 	 */
134func print_alignment
135	/* The minimum ascii length is 3, e.g. for "x0" */
136	adr	x4, print_spacer - 3
137	add	x4, x4, x0
138	b	asm_print_str
139endfunc print_alignment
140
141	/*
142	 * Helper function to store x8 - x15 registers to
143	 * the crash buf. The system registers values are
144	 * copied to x8 to x15 by the caller which are then
145	 * copied to the crash buf by this function.
146	 * x0 points to the crash buf. It then calls
147	 * size_controlled_print to print to console.
148	 * Clobbers : x0 - x7, x20, sp
149	 */
150func str_in_crash_buf_print
151	/* restore the crash buf address in x0 */
152	mrs	x0, tpidr_el3
153	stp	x8, x9, [x0]
154	stp	x10, x11, [x0, #REGSZ * 2]
155	stp	x12, x13, [x0, #REGSZ * 4]
156	stp	x14, x15, [x0, #REGSZ * 6]
157	b	size_controlled_print
158endfunc str_in_crash_buf_print
159
160	/*
161	 * An equivalent helper function for storing x8 - x15
162	 * registers in a different order inside the crash buf.
163	 * In the end the function size_controlled_print_128 is
164	 * called to print the registers to the console.
165	 * Clobbers : x0 - x7, x20, sp
166	 */
167func str_in_crash_buf_print_128
168	/* restore the crash buf address in x0 */
169	mrs	x0, tpidr_el3
170	stp	x8, x9, [x0]
171	stp	x10, x11, [x0, #REGSZ * 2]
172	stp	x12, x13, [x0, #REGSZ * 4]
173	stp	x14, x15, [x0, #REGSZ * 6]
174	b	size_controlled_print_128
175endfunc str_in_crash_buf_print_128
176
177	/* ---------------------------------------------------------------------
178	 * This macro calculates the offset to crash buf and stores it in
179	 * tpidr_el3. It also saves x0 to x6 and x30 in the crash buf by using
180	 * system registers as temporary registers. These are selected to be
181	 * present in a minimal ARMv8.0 implementation and not overwrite context
182	 * we want to report.
183	 * ---------------------------------------------------------------------
184	 */
185	.macro prepare_crash_buf_and_save_regs
186	msr	tpidr_el3,	x0
187
188	/* PMUv3 is presumed to be always present. Disable counting so
189	 * pmccntr_el0 can be used */
190	mrs	x0, pmcr_el0
191	bic	x0, x0, #PMCR_EL0_E_BIT
192	msr	pmcr_el0, x0
193
194	msr	far_el1,	x1
195	msr	elr_el1,	x2
196	msr	tpidr_el1,	x3
197	msr	mair_el1,	x4
198	msr	sp_el1,		x5
199	msr	vbar_el1,	x6
200	msr	tpidr_el0,	x7
201	msr	tpidrro_el0,	x8
202	msr	pmccntr_el0,	x30
203
204	/* calculate crash_buf[core_pos] */
205	bl	plat_my_core_pos
206	mov_imm	x1, CRASH_BUF_SIZE
207	mul	x0, x0, x1
208	adr_l	x1, crash_buf
209	add	x0, x0, x1
210
211	/* put x0 in the crash buffer */
212	mrs	x1, tpidr_el3
213	str	x1, [x0]
214
215	/* Store crash buffer address in tpidr_el3 */
216	msr	tpidr_el3, x0
217
218	/* put x1 - x7 in the crash buffer */
219	mrs	x1, far_el1
220	mrs	x2, elr_el1
221	mrs	x3, tpidr_el1
222	mrs	x4, mair_el1
223	mrs	x5, sp_el1
224	mrs	x6, vbar_el1
225	mrs	x30, pmccntr_el0
226
227	str	x1, [x0, #REGSZ]
228	stp	x2, x3, [x0, #REGSZ * 2]
229	stp	x4, x5, [x0, #REGSZ * 4]
230	stp	x6, x30, [x0, #REGSZ * 6]
231
232	/* put these back as there's no space in the buffer */
233	mrs	x7, tpidr_el0
234	mrs	x8, tpidrro_el0
235	.endm
236
237	/* -----------------------------------------------------
238	 * This function allows to report a crash (if crash
239	 * reporting is enabled) when an unhandled exception
240	 * occurs. It prints the CPU state via the crash console
241	 * making use of the crash buf. This function will
242	 * not return.
243	 * -----------------------------------------------------
244	 */
245func report_unhandled_exception
246	/* Switch to SP_ELx */
247	msr     spsel, #MODE_SP_ELX
248	prepare_crash_buf_and_save_regs
249	adr	x0, excpt_msg
250	mov	sp, x0
251	/* This call will not return */
252	b	do_crash_reporting
253endfunc report_unhandled_exception
254
255	/* -----------------------------------------------------
256	 * This function allows to report a crash (if crash
257	 * reporting is enabled) when an unhandled interrupt
258	 * occurs. It prints the CPU state via the crash console
259	 * making use of the crash buf. This function will
260	 * not return.
261	 * -----------------------------------------------------
262	 */
263func report_unhandled_interrupt
264	prepare_crash_buf_and_save_regs
265	adr	x0, intr_excpt_msg
266	mov	sp, x0
267	/* This call will not return */
268	b	do_crash_reporting
269endfunc report_unhandled_interrupt
270
271	/* -----------------------------------------------------
272	 * This function allows to report a crash (if crash
273	 * reporting is enabled) when panic() is invoked from
274	 * C Runtime. It prints the CPU state via the crash
275	 * console making use of the crash buf. This function
276	 * will not return.
277	 * -----------------------------------------------------
278	 */
279func report_el3_panic
280	msr	spsel, #MODE_SP_ELX
281	prepare_crash_buf_and_save_regs
282	adr	x0, panic_msg
283	mov	sp, x0
284	/* Fall through to 'do_crash_reporting' */
285
286	/* ------------------------------------------------------------
287	 * The common crash reporting functionality. It requires x0
288	 * and x1 has already been stored in crash buf, sp points to
289	 * crash message and tpidr_el3 contains the crash buf address.
290	 * The function does the following:
291	 *   - Retrieve the crash buffer from tpidr_el3
292	 *   - Store x2 to x6 in the crash buffer
293	 *   - Initialise the crash console.
294	 *   - Print the crash message by using the address in sp.
295	 *   - Print x30 value to the crash console.
296	 *   - Print x0 - x7 from the crash buf to the crash console.
297	 *   - Print x8 - x29 (in groups of 8 registers) using the
298	 *     crash buf to the crash console.
299	 *   - Print el3 sys regs (in groups of 8 registers) using the
300	 *     crash buf to the crash console.
301	 *   - Print non el3 sys regs (in groups of 8 registers) using
302	 *     the crash buf to the crash console. A group may be
303	 *     interrupted in case a potential group of 128-bit
304	 *     sys regs needs to be printed.
305	 * ------------------------------------------------------------
306	 */
307do_crash_reporting:
308	/* Initialize the crash console */
309	bl	plat_crash_console_init
310	/* Verify the console is initialized */
311	cbz	x0, crash_panic
312	/* Print the crash message. sp points to the crash message */
313	mov	x4, sp
314	bl	asm_print_str
315	/* Print spaces to align "x30" string */
316	mov	x0, #4
317	bl	print_alignment
318	/* Load the crash buf address */
319	mrs	x0, tpidr_el3
320	/* Report x30 first from the crash buf */
321	ldr	x4, [x0, #REGSZ * 7]
322
323#if ENABLE_PAUTH
324#if ENABLE_PAUTH == 2
325	/* Skip if not present in hardware */
326	is_feat_pauth_present_asm x0, x1
327	beq	1f
328#endif
329	/*
330	 * The assembler must see support for xpaci. So turn the compiler
331	 * extension on. GCC prior to 10 doesn't understand the PAuth extension
332	 * but it does understand armv8.3-a in general. Avoid using 8.3 if
333	 * the compiler understands "pauth" so we don't downgrade a higher
334	 * -march that was specified on the commandline.
335	 */
336#if __GNUC__ < 10
337	.arch armv8.3-a
338#else
339	.arch_extension pauth
340#endif
341	/* Demangle address */
342	xpaci	x4
3431:
344#endif
345	bl	asm_print_hex
346	bl	asm_print_newline
347	/* Load the crash buf address */
348	mrs	x0, tpidr_el3
349	/* Now mov x7 into crash buf */
350	str	x7, [x0, #REGSZ * 7]
351
352	/* Report x0 - x29 values stored in crash buf */
353	/* Store the ascii list pointer in x6 */
354	adr	x6, gp_regs
355	/* Print x0 to x7 from the crash buf */
356	bl	size_controlled_print
357	/* Store x8 - x15 in crash buf and print */
358	bl	str_in_crash_buf_print
359	/* Load the crash buf address */
360	mrs	x0, tpidr_el3
361	/* Store the rest of gp regs and print */
362	stp	x16, x17, [x0]
363	stp	x18, x19, [x0, #REGSZ * 2]
364	stp	x20, x21, [x0, #REGSZ * 4]
365	stp	x22, x23, [x0, #REGSZ * 6]
366	bl	size_controlled_print
367	/* Load the crash buf address */
368	mrs	x0, tpidr_el3
369	stp	x24, x25, [x0]
370	stp	x26, x27, [x0, #REGSZ * 2]
371	stp	x28, x29, [x0, #REGSZ * 4]
372	bl	size_controlled_print
373
374	/* Print the el3 sys registers */
375print_el3_sys_regs:
376	adr	x6, el3_sys_regs
377	mrs	x8, scr_el3
378	mrs	x9, sctlr_el3
379	mrs	x10, cptr_el3
380	mrs	x11, tcr_el3
381	mrs	x12, daif
382	mrs	x13, mair_el3
383	mrs	x14, spsr_el3
384	mrs	x15, elr_el3
385	bl	str_in_crash_buf_print
386	mrs	x8, ttbr0_el3
387	mrs	x9, esr_el3
388	mrs	x10, far_el3
389	bl	str_in_crash_buf_print
390
391	/* Print the non el3 sys registers */
392	adr	x6, non_el3_sys_regs
393	mrs	x8, mpidr_el1
394	mrs	x9, sp_el0
395	mrs	x10, isr_el1
396	bl	str_in_crash_buf_print
397
398#if CTX_INCLUDE_AARCH32_REGS
399	/* Print the AArch32 registers */
400	adr	x6, aarch32_regs
401	mrs	x8, dacr32_el2
402	mrs	x9, ifsr32_el2
403	bl	str_in_crash_buf_print
404#endif /* CTX_INCLUDE_AARCH32_REGS */
405
406	/* Get the cpu specific registers to report */
407	bl	do_cpu_reg_dump
408	bl	str_in_crash_buf_print
409
410	/* Print some platform registers */
411	plat_crash_print_regs
412
413	bl	plat_crash_console_flush
414
415	/* Done reporting */
416	no_ret	plat_panic_handler
417endfunc report_el3_panic
418
419#else	/* CRASH_REPORTING */
420func report_unhandled_exception
421report_unhandled_interrupt:
422	no_ret	plat_panic_handler
423endfunc report_unhandled_exception
424#endif	/* CRASH_REPORTING */
425
426func crash_panic
427	no_ret	plat_panic_handler
428endfunc crash_panic
429