blob: 8f8ca11245827615aad5f925b3302bd716906577 [file] [log] [blame]
Antonio Nino Diaz4bac0452018-10-16 14:32:34 +01001/*
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 <console.h>
14
15 .globl plat_crash_console_init
16 .globl plat_crash_console_putc
17 .globl plat_crash_console_flush
18
Julius Werner351ba732018-11-20 13:02:27 -080019#if !MULTI_CONSOLE_API
20#error "This crash console implementation only works with the MULTI_CONSOLE_API!"
21#endif
Antonio Nino Diaz4bac0452018-10-16 14:32:34 +010022
Julius Werner1338c9c2018-11-19 14:25:55 -080023 /*
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.
Antonio Nino Diaz4bac0452018-10-16 14:32:34 +010027 */
Julius Werner1338c9c2018-11-19 14:25:55 -080028.section .data.crash_console_spinlock
29 define_asm_spinlock crash_console_spinlock
30
Antonio Nino Diaz4bac0452018-10-16 14:32:34 +010031 /*
Julius Werner1338c9c2018-11-19 14:25:55 -080032 * 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.
Antonio Nino Diaz4bac0452018-10-16 14:32:34 +010037 */
Julius Werner1338c9c2018-11-19 14:25:55 -080038.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 */
Antonio Nino Diaz4bac0452018-10-16 14:32:34 +010098 mov x0, #1
Julius Werner1338c9c2018-11-19 14:25:55 -080099 ret
Antonio Nino Diaz4bac0452018-10-16 14:32:34 +0100100#endif
101endfunc plat_crash_console_init
102
Julius Werner1338c9c2018-11-19 14:25:55 -0800103 /* --------------------------------------------------------------------
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 * --------------------------------------------------------------------
Antonio Nino Diaz4bac0452018-10-16 14:32:34 +0100113 */
114func plat_crash_console_putc
Julius Werner1338c9c2018-11-19 14:25:55 -0800115 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
Antonio Nino Diaz4bac0452018-10-16 14:32:34 +0100146endfunc plat_crash_console_putc
147
Julius Werner1338c9c2018-11-19 14:25:55 -0800148 /* --------------------------------------------------------------------
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 * --------------------------------------------------------------------
Antonio Nino Diaz4bac0452018-10-16 14:32:34 +0100153 */
154func plat_crash_console_flush
Julius Werner1338c9c2018-11-19 14:25:55 -0800155 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
Antonio Nino Diaz4bac0452018-10-16 14:32:34 +0100182endfunc plat_crash_console_flush