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