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