xref: /arm-trusted-firmware/plat/common/aarch64/crash_console_helpers.S (revision 91f16700b400a8c0651d24a598fc48ee2997a0d7)
1*91f16700Schasinglulu/*
2*91f16700Schasinglulu * Copyright (c) 2018-2019, ARM Limited and Contributors. All rights reserved.
3*91f16700Schasinglulu *
4*91f16700Schasinglulu * SPDX-License-Identifier: BSD-3-Clause
5*91f16700Schasinglulu */
6*91f16700Schasinglulu
7*91f16700Schasinglulu/*
8*91f16700Schasinglulu * If a platform wishes to use the functions in this file it has to be added to
9*91f16700Schasinglulu * the Makefile of the platform. It is not included in the common Makefile.
10*91f16700Schasinglulu */
11*91f16700Schasinglulu
12*91f16700Schasinglulu#include <asm_macros.S>
13*91f16700Schasinglulu#include <drivers/console.h>
14*91f16700Schasinglulu
15*91f16700Schasinglulu	.globl	plat_crash_console_init
16*91f16700Schasinglulu	.globl	plat_crash_console_putc
17*91f16700Schasinglulu	.globl	plat_crash_console_flush
18*91f16700Schasinglulu
19*91f16700Schasinglulu	/*
20*91f16700Schasinglulu	 * Spinlock to syncronize access to crash_console_triggered. We cannot
21*91f16700Schasinglulu	 * acquire spinlocks when the cache is disabled, so in some cases (like
22*91f16700Schasinglulu	 * late during CPU suspend) some risk remains.
23*91f16700Schasinglulu	 */
24*91f16700Schasinglulu.section .data.crash_console_spinlock
25*91f16700Schasinglulu	define_asm_spinlock crash_console_spinlock
26*91f16700Schasinglulu
27*91f16700Schasinglulu	/*
28*91f16700Schasinglulu	 * Flag to make sure that only one CPU can write a crash dump even if
29*91f16700Schasinglulu	 * multiple crash at the same time. Interleaving crash dumps on the same
30*91f16700Schasinglulu	 * console would just make the output unreadable, so it's better to only
31*91f16700Schasinglulu	 * get a single but uncorrupted dump. This also means that we don't have
32*91f16700Schasinglulu	 * to duplicate the reg_stash below for each CPU.
33*91f16700Schasinglulu	 */
34*91f16700Schasinglulu.section .data.crash_console_triggered
35*91f16700Schasinglulu	crash_console_triggered: .byte 0
36*91f16700Schasinglulu
37*91f16700Schasinglulu	/*
38*91f16700Schasinglulu	 * Space to stash away some register values while we're calling into
39*91f16700Schasinglulu	 * console drivers and don't have a real stack available. We need x14,
40*91f16700Schasinglulu	 * x15 and x30 for bookkeeping within the plat_crash_console functions
41*91f16700Schasinglulu	 * themselves, and some console drivers use x16 and x17 as additional
42*91f16700Schasinglulu	 * scratch space that is not preserved by the main crash reporting
43*91f16700Schasinglulu	 * framework. (Note that x16 and x17 should really never be expected to
44*91f16700Schasinglulu	 * retain their values across any function call, even between carefully
45*91f16700Schasinglulu	 * designed assembly functions, since the linker is always free to
46*91f16700Schasinglulu	 * insert a function call veneer that uses these registers as scratch
47*91f16700Schasinglulu	 * space at any time. The current crash reporting framework doesn't
48*91f16700Schasinglulu	 * really respect that, but since TF is usually linked as a single
49*91f16700Schasinglulu	 * contiguous binary of less than 128MB, it seems to work in practice.)
50*91f16700Schasinglulu	 */
51*91f16700Schasinglulu.section .data.crash_console_reg_stash
52*91f16700Schasinglulu	.align 3
53*91f16700Schasinglulu	crash_console_reg_stash: .quad 0, 0, 0, 0, 0
54*91f16700Schasinglulu
55*91f16700Schasinglulu	/* --------------------------------------------------------------------
56*91f16700Schasinglulu	 * int plat_crash_console_init(void)
57*91f16700Schasinglulu	 * Takes the crash console spinlock (if possible) and checks the trigger
58*91f16700Schasinglulu	 * flag to make sure we're the first CPU to dump. If not, return an
59*91f16700Schasinglulu	 * error (so crash dumping will fail but the CPU will still call
60*91f16700Schasinglulu	 * plat_panic_handler() which may do important platform-specific tasks
61*91f16700Schasinglulu	 * that may be needed on all crashing CPUs). In either case, the lock
62*91f16700Schasinglulu	 * will be released so other CPUs can make forward progress on this.
63*91f16700Schasinglulu	 * Clobbers: x0 - x4, x30
64*91f16700Schasinglulu	 * --------------------------------------------------------------------
65*91f16700Schasinglulu	 */
66*91f16700Schasinglulufunc plat_crash_console_init
67*91f16700Schasinglulu#if defined(IMAGE_BL31)
68*91f16700Schasinglulu	mov	x4, x30		/* x3 and x4 are not clobbered by spin_lock() */
69*91f16700Schasinglulu	mov	x3, #0		/* return value */
70*91f16700Schasinglulu
71*91f16700Schasinglulu	adrp	x0, crash_console_spinlock
72*91f16700Schasinglulu	add	x0, x0, :lo12:crash_console_spinlock
73*91f16700Schasinglulu
74*91f16700Schasinglulu	mrs	x1, sctlr_el3
75*91f16700Schasinglulu	tst	x1, #SCTLR_C_BIT
76*91f16700Schasinglulu	beq	skip_spinlock	/* can't synchronize when cache disabled */
77*91f16700Schasinglulu	bl	spin_lock
78*91f16700Schasinglulu
79*91f16700Schasingluluskip_spinlock:
80*91f16700Schasinglulu	adrp	x1, crash_console_triggered
81*91f16700Schasinglulu	add	x1, x1, :lo12:crash_console_triggered
82*91f16700Schasinglulu	ldarb	w2, [x1]
83*91f16700Schasinglulu	cmp	w2, #0
84*91f16700Schasinglulu	bne	init_error
85*91f16700Schasinglulu
86*91f16700Schasinglulu	mov	x3, #1		/* set return value to success */
87*91f16700Schasinglulu	stlrb	w3, [x1]
88*91f16700Schasinglulu
89*91f16700Schasingluluinit_error:
90*91f16700Schasinglulu	bl	spin_unlock	/* harmless if we didn't acquire the lock */
91*91f16700Schasinglulu	mov	x0, x3
92*91f16700Schasinglulu	ret	x4
93*91f16700Schasinglulu#else	/* Only one CPU in BL1/BL2, no need to synchronize anything */
94*91f16700Schasinglulu	mov	x0, #1
95*91f16700Schasinglulu	ret
96*91f16700Schasinglulu#endif
97*91f16700Schasingluluendfunc plat_crash_console_init
98*91f16700Schasinglulu
99*91f16700Schasinglulu	/* --------------------------------------------------------------------
100*91f16700Schasinglulu	 * int plat_crash_console_putc(char c)
101*91f16700Schasinglulu	 * Prints the character on all consoles registered with the console
102*91f16700Schasinglulu	 * framework that have CONSOLE_FLAG_CRASH set. Note that this is only
103*91f16700Schasinglulu	 * helpful for crashes that occur after the platform intialization code
104*91f16700Schasinglulu	 * has registered a console. Platforms using this implementation need to
105*91f16700Schasinglulu	 * ensure that all console drivers they use that have the CRASH flag set
106*91f16700Schasinglulu	 * support this (i.e. are written in assembly and comply to the register
107*91f16700Schasinglulu	 * clobber requirements of plat_crash_console_putc().
108*91f16700Schasinglulu	 * --------------------------------------------------------------------
109*91f16700Schasinglulu	 */
110*91f16700Schasinglulufunc plat_crash_console_putc
111*91f16700Schasinglulu	adrp	x1, crash_console_reg_stash
112*91f16700Schasinglulu	add	x1, x1, :lo12:crash_console_reg_stash
113*91f16700Schasinglulu	stp	x14, x15, [x1]
114*91f16700Schasinglulu	stp	x16, x17, [x1, #16]
115*91f16700Schasinglulu	str	x30, [x1, #32]
116*91f16700Schasinglulu
117*91f16700Schasinglulu	mov	w14, w0				/* W14 = character to print */
118*91f16700Schasinglulu	adrp	x15, console_list
119*91f16700Schasinglulu	ldr	x15, [x15, :lo12:console_list]	/* X15 = first console struct */
120*91f16700Schasinglulu
121*91f16700Schasingluluputc_loop:
122*91f16700Schasinglulu	cbz	x15, putc_done
123*91f16700Schasinglulu	ldr	w1, [x15, #CONSOLE_T_FLAGS]
124*91f16700Schasinglulu	tst	w1, #CONSOLE_FLAG_CRASH
125*91f16700Schasinglulu	b.eq	putc_continue
126*91f16700Schasinglulu	ldr	x2, [x15, #CONSOLE_T_PUTC]
127*91f16700Schasinglulu	cbz	x2, putc_continue
128*91f16700Schasinglulu	cmp	w14, #'\n'
129*91f16700Schasinglulu	b.ne	putc
130*91f16700Schasinglulu	tst	w1, #CONSOLE_FLAG_TRANSLATE_CRLF
131*91f16700Schasinglulu	b.eq	putc
132*91f16700Schasinglulu	mov	x1, x15
133*91f16700Schasinglulu	mov	w0, #'\r'
134*91f16700Schasinglulu	blr	x2
135*91f16700Schasinglulu	ldr	x2, [x15, #CONSOLE_T_PUTC]
136*91f16700Schasingluluputc:
137*91f16700Schasinglulu	mov	x1, x15
138*91f16700Schasinglulu	mov	w0, w14
139*91f16700Schasinglulu	blr	x2
140*91f16700Schasingluluputc_continue:
141*91f16700Schasinglulu	ldr	x15, [x15]			/* X15 = next struct */
142*91f16700Schasinglulu	b	putc_loop
143*91f16700Schasinglulu
144*91f16700Schasingluluputc_done:
145*91f16700Schasinglulu	adrp	x1, crash_console_reg_stash
146*91f16700Schasinglulu	add	x1, x1, :lo12:crash_console_reg_stash
147*91f16700Schasinglulu	ldp	x14, x15, [x1]
148*91f16700Schasinglulu	ldp	x16, x17, [x1, #16]
149*91f16700Schasinglulu	ldr	x30, [x1, #32]
150*91f16700Schasinglulu	ret
151*91f16700Schasingluluendfunc plat_crash_console_putc
152*91f16700Schasinglulu
153*91f16700Schasinglulu	/* --------------------------------------------------------------------
154*91f16700Schasinglulu	 * int plat_crash_console_flush(char c)
155*91f16700Schasinglulu	 * Flushes all consoles registered with the console framework that have
156*91f16700Schasinglulu	 * CONSOLE_FLAG_CRASH set. Same requirements as putc().
157*91f16700Schasinglulu	 * --------------------------------------------------------------------
158*91f16700Schasinglulu	 */
159*91f16700Schasinglulufunc plat_crash_console_flush
160*91f16700Schasinglulu	adrp	x1, crash_console_reg_stash
161*91f16700Schasinglulu	add	x1, x1, :lo12:crash_console_reg_stash
162*91f16700Schasinglulu	stp	x30, x15, [x1]
163*91f16700Schasinglulu	stp	x16, x17, [x1, #16]
164*91f16700Schasinglulu
165*91f16700Schasinglulu	adrp	x15, console_list
166*91f16700Schasinglulu	ldr	x15, [x15, :lo12:console_list]	/* X15 = first console struct */
167*91f16700Schasinglulu
168*91f16700Schasingluluflush_loop:
169*91f16700Schasinglulu	cbz	x15, flush_done
170*91f16700Schasinglulu	ldr	w1, [x15, #CONSOLE_T_FLAGS]
171*91f16700Schasinglulu	tst	w1, #CONSOLE_FLAG_CRASH
172*91f16700Schasinglulu	b.eq	flush_continue
173*91f16700Schasinglulu	ldr	x2, [x15, #CONSOLE_T_FLUSH]
174*91f16700Schasinglulu	cbz	x2, flush_continue
175*91f16700Schasinglulu	mov	x0, x15
176*91f16700Schasinglulu	blr	x2
177*91f16700Schasingluluflush_continue:
178*91f16700Schasinglulu	ldr	x15, [x15]			/* X15 = next struct */
179*91f16700Schasinglulu	b	flush_loop
180*91f16700Schasinglulu
181*91f16700Schasingluluflush_done:
182*91f16700Schasinglulu	adrp	x1, crash_console_reg_stash
183*91f16700Schasinglulu	add	x1, x1, :lo12:crash_console_reg_stash
184*91f16700Schasinglulu	ldp	x30, x15, [x1]
185*91f16700Schasinglulu	ldp	x16, x17, [x1, #16]
186*91f16700Schasinglulu	ret
187*91f16700Schasingluluendfunc plat_crash_console_flush
188