xref: /rk3399_ARM-atf/plat/common/aarch64/crash_console_helpers.S (revision 09d40e0e08283a249e7dce0e106c07c5141f9b7e)
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>
13*09d40e0eSAntonio Nino Diaz#include <drivers/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
2363c52d00SJulius Werner	/*
2463c52d00SJulius Werner	 * Spinlock to syncronize access to crash_console_triggered. We cannot
2563c52d00SJulius Werner	 * acquire spinlocks when the cache is disabled, so in some cases (like
2663c52d00SJulius Werner	 * late during CPU suspend) some risk remains.
2763c52d00SJulius Werner	 */
2863c52d00SJulius Werner.section .data.crash_console_spinlock
2963c52d00SJulius Werner	define_asm_spinlock crash_console_spinlock
3063c52d00SJulius Werner
3163c52d00SJulius Werner	/*
3263c52d00SJulius Werner	 * Flag to make sure that only one CPU can write a crash dump even if
3363c52d00SJulius Werner	 * multiple crash at the same time. Interleaving crash dumps on the same
3463c52d00SJulius Werner	 * console would just make the output unreadable, so it's better to only
3563c52d00SJulius Werner	 * get a single but uncorrupted dump. This also means that we don't have
3663c52d00SJulius Werner	 * to duplicate the reg_stash below for each CPU.
3763c52d00SJulius Werner	 */
3863c52d00SJulius Werner.section .data.crash_console_triggered
3963c52d00SJulius Werner	crash_console_triggered: .byte 0
4063c52d00SJulius Werner
4163c52d00SJulius Werner	/*
4263c52d00SJulius Werner	 * Space to stash away some register values while we're calling into
4363c52d00SJulius Werner	 * console drivers and don't have a real stack available. We need x14,
4463c52d00SJulius Werner	 * x15 and x30 for bookkeeping within the plat_crash_console functions
4563c52d00SJulius Werner	 * themselves, and some console drivers use x16 and x17 as additional
4663c52d00SJulius Werner	 * scratch space that is not preserved by the main crash reporting
4763c52d00SJulius Werner	 * framework. (Note that x16 and x17 should really never be expected to
4863c52d00SJulius Werner	 * retain their values across any function call, even between carefully
4963c52d00SJulius Werner	 * designed assembly functions, since the linker is always free to
5063c52d00SJulius Werner	 * insert a function call veneer that uses these registers as scratch
5163c52d00SJulius Werner	 * space at any time. The current crash reporting framework doesn't
5263c52d00SJulius Werner	 * really respect that, but since TF is usually linked as a single
5363c52d00SJulius Werner	 * contiguous binary of less than 128MB, it seems to work in practice.)
5463c52d00SJulius Werner	 */
5563c52d00SJulius Werner.section .data.crash_console_reg_stash
5663c52d00SJulius Werner	.align 3
5763c52d00SJulius Werner	crash_console_reg_stash: .quad 0, 0, 0, 0, 0
5863c52d00SJulius Werner
5963c52d00SJulius Werner	/* --------------------------------------------------------------------
606c9ada31SAntonio Nino Diaz	 * int plat_crash_console_init(void)
6163c52d00SJulius Werner	 * Takes the crash console spinlock (if possible) and checks the trigger
6263c52d00SJulius Werner	 * flag to make sure we're the first CPU to dump. If not, return an
6363c52d00SJulius Werner	 * error (so crash dumping will fail but the CPU will still call
6463c52d00SJulius Werner	 * plat_panic_handler() which may do important platform-specific tasks
6563c52d00SJulius Werner	 * that may be needed on all crashing CPUs). In either case, the lock
6663c52d00SJulius Werner	 * will be released so other CPUs can make forward progress on this.
6763c52d00SJulius Werner	 * Clobbers: x0 - x4, x30
6863c52d00SJulius Werner	 * --------------------------------------------------------------------
696c9ada31SAntonio Nino Diaz	 */
706c9ada31SAntonio Nino Diazfunc plat_crash_console_init
7163c52d00SJulius Werner#if defined(IMAGE_BL31)
7263c52d00SJulius Werner	mov	x4, x30		/* x3 and x4 are not clobbered by spin_lock() */
7363c52d00SJulius Werner	mov	x3, #0		/* return value */
7463c52d00SJulius Werner
7563c52d00SJulius Werner	mrs	x1, sctlr_el3
7663c52d00SJulius Werner	tst	x1, #SCTLR_C_BIT
7763c52d00SJulius Werner	beq	skip_spinlock	/* can't synchronize when cache disabled */
7863c52d00SJulius Werner
7963c52d00SJulius Werner	adrp	x0, crash_console_spinlock
8063c52d00SJulius Werner	add	x0, x0, :lo12:crash_console_spinlock
8163c52d00SJulius Werner	bl	spin_lock
8263c52d00SJulius Werner
8363c52d00SJulius Wernerskip_spinlock:
8463c52d00SJulius Werner	adrp	x1, crash_console_triggered
8563c52d00SJulius Werner	add	x1, x1, :lo12:crash_console_triggered
8663c52d00SJulius Werner	ldarb	w2, [x1]
8763c52d00SJulius Werner	cmp	w2, #0
8863c52d00SJulius Werner	bne	init_error
8963c52d00SJulius Werner
9063c52d00SJulius Werner	mov	x3, #1		/* set return value to success */
9163c52d00SJulius Werner	stlrb	w3, [x1]
9263c52d00SJulius Werner
9363c52d00SJulius Wernerinit_error:
9463c52d00SJulius Werner	bl	spin_unlock	/* harmless if we didn't acquire the lock */
9563c52d00SJulius Werner	mov	x0, x3
9663c52d00SJulius Werner	ret	x4
9763c52d00SJulius Werner#else	/* Only one CPU in BL1/BL2, no need to synchronize anything */
986c9ada31SAntonio Nino Diaz	mov	x0, #1
9963c52d00SJulius Werner	ret
1006c9ada31SAntonio Nino Diaz#endif
1016c9ada31SAntonio Nino Diazendfunc plat_crash_console_init
1026c9ada31SAntonio Nino Diaz
10363c52d00SJulius Werner	/* --------------------------------------------------------------------
10463c52d00SJulius Werner	 * int plat_crash_console_putc(char c)
10563c52d00SJulius Werner	 * Prints the character on all consoles registered with the console
10663c52d00SJulius Werner	 * framework that have CONSOLE_FLAG_CRASH set. Note that this is only
10763c52d00SJulius Werner	 * helpful for crashes that occur after the platform intialization code
10863c52d00SJulius Werner	 * has registered a console. Platforms using this implementation need to
10963c52d00SJulius Werner	 * ensure that all console drivers they use that have the CRASH flag set
11063c52d00SJulius Werner	 * support this (i.e. are written in assembly and comply to the register
11163c52d00SJulius Werner	 * clobber requirements of plat_crash_console_putc().
11263c52d00SJulius Werner	 * --------------------------------------------------------------------
1136c9ada31SAntonio Nino Diaz	 */
1146c9ada31SAntonio Nino Diazfunc plat_crash_console_putc
11563c52d00SJulius Werner	adrp	x1, crash_console_reg_stash
11663c52d00SJulius Werner	add	x1, x1, :lo12:crash_console_reg_stash
11763c52d00SJulius Werner	stp	x14, x15, [x1]
11863c52d00SJulius Werner	stp	x16, x17, [x1, #16]
11963c52d00SJulius Werner	str	x30, [x1, #32]
12063c52d00SJulius Werner
12163c52d00SJulius Werner	mov	w14, w0				/* W14 = character to print */
12263c52d00SJulius Werner	adrp	x15, console_list
12363c52d00SJulius Werner	ldr	x15, [x15, :lo12:console_list]	/* X15 = first console struct */
12463c52d00SJulius Werner
12563c52d00SJulius Wernerputc_loop:
12663c52d00SJulius Werner	cbz	x15, putc_done
12763c52d00SJulius Werner	ldr	w1, [x15, #CONSOLE_T_FLAGS]
12863c52d00SJulius Werner	tst	w1, #CONSOLE_FLAG_CRASH
12963c52d00SJulius Werner	b.eq	putc_continue
13063c52d00SJulius Werner	ldr	x2, [x15, #CONSOLE_T_PUTC]
13163c52d00SJulius Werner	cbz	x2, putc_continue
13263c52d00SJulius Werner	mov	x1, x15
13363c52d00SJulius Werner	blr	x2
13463c52d00SJulius Werner	mov	w0, w14
13563c52d00SJulius Wernerputc_continue:
13663c52d00SJulius Werner	ldr	x15, [x15]			/* X15 = next struct */
13763c52d00SJulius Werner	b	putc_loop
13863c52d00SJulius Werner
13963c52d00SJulius Wernerputc_done:
14063c52d00SJulius Werner	adrp	x1, crash_console_reg_stash
14163c52d00SJulius Werner	add	x1, x1, :lo12:crash_console_reg_stash
14263c52d00SJulius Werner	ldp	x14, x15, [x1]
14363c52d00SJulius Werner	ldp	x16, x17, [x1, #16]
14463c52d00SJulius Werner	ldr	x30, [x1, #32]
14563c52d00SJulius Werner	ret
1466c9ada31SAntonio Nino Diazendfunc plat_crash_console_putc
1476c9ada31SAntonio Nino Diaz
14863c52d00SJulius Werner	/* --------------------------------------------------------------------
14963c52d00SJulius Werner	 * int plat_crash_console_flush(char c)
15063c52d00SJulius Werner	 * Flushes all consoles registered with the console framework that have
15163c52d00SJulius Werner	 * CONSOLE_FLAG_CRASH set. Same requirements as putc().
15263c52d00SJulius Werner	 * --------------------------------------------------------------------
1536c9ada31SAntonio Nino Diaz	 */
1546c9ada31SAntonio Nino Diazfunc plat_crash_console_flush
15563c52d00SJulius Werner	adrp	x1, crash_console_reg_stash
15663c52d00SJulius Werner	add	x1, x1, :lo12:crash_console_reg_stash
15763c52d00SJulius Werner	stp	x30, x15, [x1]
15863c52d00SJulius Werner	stp	x16, x17, [x1, #16]
15963c52d00SJulius Werner
16063c52d00SJulius Werner	adrp	x15, console_list
16163c52d00SJulius Werner	ldr	x15, [x15, :lo12:console_list]	/* X15 = first console struct */
16263c52d00SJulius Werner
16363c52d00SJulius Wernerflush_loop:
16463c52d00SJulius Werner	cbz	x15, flush_done
16563c52d00SJulius Werner	ldr	w1, [x15, #CONSOLE_T_FLAGS]
16663c52d00SJulius Werner	tst	w1, #CONSOLE_FLAG_CRASH
16763c52d00SJulius Werner	b.eq	flush_continue
16863c52d00SJulius Werner	ldr	x2, [x15, #CONSOLE_T_FLUSH]
16963c52d00SJulius Werner	cbz	x2, flush_continue
17063c52d00SJulius Werner	mov	x0, x15
17163c52d00SJulius Werner	blr	x2
17263c52d00SJulius Wernerflush_continue:
17363c52d00SJulius Werner	ldr	x15, [x15]			/* X15 = next struct */
17463c52d00SJulius Werner	b	flush_loop
17563c52d00SJulius Werner
17663c52d00SJulius Wernerflush_done:
17763c52d00SJulius Werner	adrp	x1, crash_console_reg_stash
17863c52d00SJulius Werner	add	x1, x1, :lo12:crash_console_reg_stash
17963c52d00SJulius Werner	ldp	x30, x15, [x1]
18063c52d00SJulius Werner	ldp	x16, x17, [x1, #16]
18163c52d00SJulius Werner	ret
1826c9ada31SAntonio Nino Diazendfunc plat_crash_console_flush
183