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