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