crash_reporting.S 10.6 KB
Newer Older
1
/*
2
 * Copyright (c) 2014-2019, ARM Limited and Contributors. All rights reserved.
3
 *
dp-arm's avatar
dp-arm committed
4
 * SPDX-License-Identifier: BSD-3-Clause
5
 */
6
7
8
9

#include <plat_macros.S>
#include <platform_def.h>

10
11
12
#include <arch.h>
#include <asm_macros.S>
#include <context.h>
13
14
#include <lib/el3_runtime/cpu_data.h>
#include <lib/utils_def.h>
15

16
17
18
	.globl	report_unhandled_exception
	.globl	report_unhandled_interrupt
	.globl	el3_panic
19

20
#if CRASH_REPORTING
21

22
23
24
25
26
27
28
	/* ------------------------------------------------------
	 * The below section deals with dumping the system state
	 * when an unhandled exception is taken in EL3.
	 * The layout and the names of the registers which will
	 * be dumped during a unhandled exception is given below.
	 * ------------------------------------------------------
	 */
29
30
.section .rodata.crash_prints, "aS"
print_spacer:
31
	.asciz	"             = 0x"
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47

gp_regs:
	.asciz	"x0", "x1", "x2", "x3", "x4", "x5", "x6", "x7",\
		"x8", "x9", "x10", "x11", "x12", "x13", "x14", "x15",\
		"x16", "x17", "x18", "x19", "x20", "x21", "x22",\
		"x23", "x24", "x25", "x26", "x27", "x28", "x29", ""
el3_sys_regs:
	.asciz	"scr_el3", "sctlr_el3", "cptr_el3", "tcr_el3",\
		"daif", "mair_el3", "spsr_el3", "elr_el3", "ttbr0_el3",\
		"esr_el3", "far_el3", ""

non_el3_sys_regs:
	.asciz	"spsr_el1", "elr_el1", "spsr_abt", "spsr_und",\
		"spsr_irq", "spsr_fiq", "sctlr_el1", "actlr_el1", "cpacr_el1",\
		"csselr_el1", "sp_el1", "esr_el1", "ttbr0_el1", "ttbr1_el1",\
		"mair_el1", "amair_el1", "tcr_el1", "tpidr_el1", "tpidr_el0",\
48
49
50
51
52
53
54
55
		"tpidrro_el0",  "par_el1", "mpidr_el1", "afsr0_el1", "afsr1_el1",\
		"contextidr_el1", "vbar_el1", "cntp_ctl_el0", "cntp_cval_el0",\
		"cntv_ctl_el0", "cntv_cval_el0", "cntkctl_el1", "sp_el0", "isr_el1", ""

#if CTX_INCLUDE_AARCH32_REGS
aarch32_regs:
	.asciz	"dacr32_el2", "ifsr32_el2", ""
#endif /* CTX_INCLUDE_AARCH32_REGS */
56
57

panic_msg:
58
	.asciz "PANIC in EL3.\nx30"
59
excpt_msg:
60
	.asciz "Unhandled Exception in EL3.\nx30"
61
intr_excpt_msg:
62
	.asciz "Unhandled Interrupt Exception in EL3.\nx30"
63
64
65

	/*
	 * Helper function to print newline to console.
66
	 */
67
68
69
func print_newline
	mov	x0, '\n'
	b	plat_crash_console_putc
70
endfunc print_newline
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96

	/*
	 * Helper function to print from crash buf.
	 * The print loop is controlled by the buf size and
	 * ascii reg name list which is passed in x6. The
	 * function returns the crash buf address in x0.
	 * Clobbers : x0 - x7, sp
	 */
func size_controlled_print
	/* Save the lr */
	mov	sp, x30
	/* load the crash buf address */
	mrs	x7, tpidr_el3
test_size_list:
	/* Calculate x5 always as it will be clobbered by asm_print_hex */
	mrs	x5, tpidr_el3
	add	x5, x5, #CPU_DATA_CRASH_BUF_SIZE
	/* Test whether we have reached end of crash buf */
	cmp	x7, x5
	b.eq	exit_size_print
	ldrb	w4, [x6]
	/* Test whether we are at end of list */
	cbz	w4, exit_size_print
	mov	x4, x6
	/* asm_print_str updates x4 to point to next entry in list */
	bl	asm_print_str
97
98
	/* x0 = number of symbols printed + 1 */
	sub	x0, x4, x6
99
100
	/* update x6 with the updated list pointer */
	mov	x6, x4
101
	bl	print_alignment
102
	ldr	x4, [x7], #REGSZ
103
104
105
106
107
108
	bl	asm_print_hex
	bl	print_newline
	b	test_size_list
exit_size_print:
	mov	x30, sp
	ret
109
endfunc size_controlled_print
110

111
112
113
114
115
116
117
118
119
120
121
122
123
124
	/* -----------------------------------------------------
	 * This function calculates and prints required number
	 * of space characters followed by "= 0x", based on the
	 * length of ascii register name.
 	 * x0: length of ascii register name + 1
	 * ------------------------------------------------------
 	 */
func print_alignment
	/* The minimum ascii length is 3, e.g. for "x0" */
	adr	x4, print_spacer - 3
	add	x4, x4, x0
	b	asm_print_str
endfunc print_alignment

125
126
127
128
129
130
131
132
133
134
135
136
137
	/*
	 * Helper function to store x8 - x15 registers to
	 * the crash buf. The system registers values are
	 * copied to x8 to x15 by the caller which are then
	 * copied to the crash buf by this function.
	 * x0 points to the crash buf. It then calls
	 * size_controlled_print to print to console.
	 * Clobbers : x0 - x7, sp
	 */
func str_in_crash_buf_print
	/* restore the crash buf address in x0 */
	mrs	x0, tpidr_el3
	stp	x8, x9, [x0]
138
139
140
	stp	x10, x11, [x0, #REGSZ * 2]
	stp	x12, x13, [x0, #REGSZ * 4]
	stp	x14, x15, [x0, #REGSZ * 6]
141
	b	size_controlled_print
142
endfunc str_in_crash_buf_print
143

144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
	/* ------------------------------------------------------
	 * This macro calculates the offset to crash buf from
	 * cpu_data and stores it in tpidr_el3. It also saves x0
	 * and x1 in the crash buf by using sp as a temporary
	 * register.
	 * ------------------------------------------------------
	 */
	.macro prepare_crash_buf_save_x0_x1
	/* we can corrupt this reg to free up x0 */
	mov	sp, x0
	/* tpidr_el3 contains the address to cpu_data structure */
	mrs	x0, tpidr_el3
	/* Calculate the Crash buffer offset in cpu_data */
	add	x0, x0, #CPU_DATA_CRASH_BUF_OFFSET
	/* Store crash buffer address in tpidr_el3 */
	msr	tpidr_el3, x0
160
	str	x1, [x0, #REGSZ]
161
	mov	x1, sp
162
	str	x1, [x0]
163
164
	.endm

165
166
167
168
169
170
171
172
173
174
175
176
177
178
	/* -----------------------------------------------------
	 * This function allows to report a crash (if crash
	 * reporting is enabled) when an unhandled exception
	 * occurs. It prints the CPU state via the crash console
	 * making use of the crash buf. This function will
	 * not return.
	 * -----------------------------------------------------
	 */
func report_unhandled_exception
	prepare_crash_buf_save_x0_x1
	adr	x0, excpt_msg
	mov	sp, x0
	/* This call will not return */
	b	do_crash_reporting
179
endfunc report_unhandled_exception
180
181


182
183
184
185
186
187
188
189
190
191
192
193
194
195
	/* -----------------------------------------------------
	 * This function allows to report a crash (if crash
	 * reporting is enabled) when an unhandled interrupt
	 * occurs. It prints the CPU state via the crash console
	 * making use of the crash buf. This function will
	 * not return.
	 * -----------------------------------------------------
	 */
func report_unhandled_interrupt
	prepare_crash_buf_save_x0_x1
	adr	x0, intr_excpt_msg
	mov	sp, x0
	/* This call will not return */
	b	do_crash_reporting
196
endfunc report_unhandled_interrupt
197

198
199
200
201
202
203
204
205
206
	/* -----------------------------------------------------
	 * This function allows to report a crash (if crash
	 * reporting is enabled) when panic() is invoked from
	 * C Runtime. It prints the CPU state via the crash
	 * console making use of the crash buf. This function
	 * will not return.
	 * -----------------------------------------------------
	 */
func el3_panic
207
	msr	spsel, #MODE_SP_ELX
208
209
210
211
212
	prepare_crash_buf_save_x0_x1
	adr	x0, panic_msg
	mov	sp, x0
	/* This call will not return */
	b	do_crash_reporting
213
endfunc el3_panic
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237

	/* ------------------------------------------------------------
	 * The common crash reporting functionality. It requires x0
	 * and x1 has already been stored in crash buf, sp points to
	 * crash message and tpidr_el3 contains the crash buf address.
	 * The function does the following:
	 *   - Retrieve the crash buffer from tpidr_el3
	 *   - Store x2 to x6 in the crash buffer
	 *   - Initialise the crash console.
	 *   - Print the crash message by using the address in sp.
	 *   - Print x30 value to the crash console.
	 *   - Print x0 - x7 from the crash buf to the crash console.
	 *   - Print x8 - x29 (in groups of 8 registers) using the
	 *     crash buf to the crash console.
	 *   - Print el3 sys regs (in groups of 8 registers) using the
	 *     crash buf to the crash console.
	 *   - Print non el3 sys regs (in groups of 8 registers) using
	 *     the crash buf to the crash console.
	 * ------------------------------------------------------------
	 */
func do_crash_reporting
	/* Retrieve the crash buf from tpidr_el3 */
	mrs	x0, tpidr_el3
	/* Store x2 - x6, x30 in the crash buffer */
238
239
240
	stp	x2, x3, [x0, #REGSZ * 2]
	stp	x4, x5, [x0, #REGSZ * 4]
	stp	x6, x30, [x0, #REGSZ * 6]
241
242
243
244
245
246
247
	/* Initialize the crash console */
	bl	plat_crash_console_init
	/* Verify the console is initialized */
	cbz	x0, crash_panic
	/* Print the crash message. sp points to the crash message */
	mov	x4, sp
	bl	asm_print_str
248
249
250
	/* Print spaces to align "x30" string */
	mov	x0, #4
	bl	print_alignment
251
252
253
	/* load the crash buf address */
	mrs	x0, tpidr_el3
	/* report x30 first from the crash buf */
254
	ldr	x4, [x0, #REGSZ * 7]
255
256
257
258
259
	bl	asm_print_hex
	bl	print_newline
	/* Load the crash buf address */
	mrs	x0, tpidr_el3
	/* Now mov x7 into crash buf */
260
	str	x7, [x0, #REGSZ * 7]
261
262
263
264
265
266
267
268
269
270
271
272

	/* Report x0 - x29 values stored in crash buf*/
	/* Store the ascii list pointer in x6 */
	adr	x6, gp_regs
	/* Print x0 to x7 from the crash buf */
	bl	size_controlled_print
	/* Store x8 - x15 in crash buf and print */
	bl	str_in_crash_buf_print
	/* Load the crash buf address */
	mrs	x0, tpidr_el3
	/* Store the rest of gp regs and print */
	stp	x16, x17, [x0]
273
274
275
	stp	x18, x19, [x0, #REGSZ * 2]
	stp	x20, x21, [x0, #REGSZ * 4]
	stp	x22, x23, [x0, #REGSZ * 6]
276
277
278
279
	bl	size_controlled_print
	/* Load the crash buf address */
	mrs	x0, tpidr_el3
	stp	x24, x25, [x0]
280
281
	stp	x26, x27, [x0, #REGSZ * 2]
	stp	x28, x29, [x0, #REGSZ * 4]
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
	bl	size_controlled_print

	/* Print the el3 sys registers */
	adr	x6, el3_sys_regs
	mrs	x8, scr_el3
	mrs	x9, sctlr_el3
	mrs	x10, cptr_el3
	mrs	x11, tcr_el3
	mrs	x12, daif
	mrs	x13, mair_el3
	mrs	x14, spsr_el3
	mrs	x15, elr_el3
	bl	str_in_crash_buf_print
	mrs	x8, ttbr0_el3
	mrs	x9, esr_el3
	mrs	x10, far_el3
	bl	str_in_crash_buf_print

	/* Print the non el3 sys registers */
	adr	x6, non_el3_sys_regs
	mrs	x8, spsr_el1
	mrs	x9, elr_el1
	mrs	x10, spsr_abt
	mrs	x11, spsr_und
	mrs	x12, spsr_irq
	mrs	x13, spsr_fiq
	mrs	x14, sctlr_el1
	mrs	x15, actlr_el1
	bl	str_in_crash_buf_print
	mrs	x8, cpacr_el1
	mrs	x9, csselr_el1
313
314
315
316
317
318
	mrs	x10, sp_el1
	mrs	x11, esr_el1
	mrs	x12, ttbr0_el1
	mrs	x13, ttbr1_el1
	mrs	x14, mair_el1
	mrs	x15, amair_el1
319
320
321
322
323
	bl	str_in_crash_buf_print
	mrs	x8, tcr_el1
	mrs	x9, tpidr_el1
	mrs	x10, tpidr_el0
	mrs	x11, tpidrro_el0
324
325
326
327
328
329
330
331
332
333
334
335
336
	mrs	x12, par_el1
	mrs	x13, mpidr_el1
	mrs	x14, afsr0_el1
	mrs	x15, afsr1_el1
	bl	str_in_crash_buf_print
	mrs	x8, contextidr_el1
	mrs	x9, vbar_el1
	mrs	x10, cntp_ctl_el0
	mrs	x11, cntp_cval_el0
	mrs	x12, cntv_ctl_el0
	mrs	x13, cntv_cval_el0
	mrs	x14, cntkctl_el1
	mrs	x15, sp_el0
337
	bl	str_in_crash_buf_print
338
	mrs	x8, isr_el1
339
	bl	str_in_crash_buf_print
340
341
342
343
344
345

#if CTX_INCLUDE_AARCH32_REGS
	/* Print the AArch32 registers */
	adr	x6, aarch32_regs
	mrs	x8, dacr32_el2
	mrs	x9, ifsr32_el2
346
	bl	str_in_crash_buf_print
347
#endif /* CTX_INCLUDE_AARCH32_REGS */
348

349
350
351
	/* Get the cpu specific registers to report */
	bl	do_cpu_reg_dump
	bl	str_in_crash_buf_print
352

353
354
	/* Print some platform registers */
	plat_crash_print_regs
355

356
357
	bl	plat_crash_console_flush

358
	/* Done reporting */
359
	no_ret	plat_panic_handler
360
endfunc do_crash_reporting
361
362
363
364

#else	/* CRASH_REPORTING */
func report_unhandled_exception
report_unhandled_interrupt:
365
	no_ret	plat_panic_handler
366
endfunc report_unhandled_exception
367
#endif	/* CRASH_REPORTING */
368

369

370
func crash_panic
371
	no_ret	plat_panic_handler
372
endfunc crash_panic