blob: 95423b0278be56a3370639fd6ce41d32cab32869 [file] [log] [blame]
Julius Werner9536bae2017-07-31 18:15:11 -07001/*
Antonio Nino Diazc2e05bb2018-04-30 20:14:07 +01002 * Copyright (c) 2015-2018, ARM Limited and Contributors. All rights reserved.
Julius Werner9536bae2017-07-31 18:15:11 -07003 *
4 * SPDX-License-Identifier: BSD-3-Clause
5 */
6
7#include <asm_macros.S>
8#include <assert_macros.S>
9#include <console.h>
10
11 .globl console_register
12 .globl console_unregister
Antonio Nino Diazc2e05bb2018-04-30 20:14:07 +010013 .globl console_is_registered
14 .globl console_set_scope
Julius Werner9536bae2017-07-31 18:15:11 -070015 .globl console_switch_state
16 .globl console_putc
17 .globl console_getc
18 .globl console_flush
Julius Werner63c52d02018-11-19 14:25:55 -080019 .globl console_list
Julius Werner9536bae2017-07-31 18:15:11 -070020
21 /*
22 * The console list pointer is in the data section and not in
23 * .bss even though it is zero-init. In particular, this allows
24 * the console functions to start using this variable before
25 * the runtime memory is initialized for images which do not
26 * need to copy the .data section from ROM to RAM.
27 */
28.section .data.console_list ; .align 3
29 console_list: .quad 0x0
30.section .data.console_state ; .align 0
31 console_state: .byte CONSOLE_FLAG_BOOT
32
33 /* -----------------------------------------------
34 * int console_register(console_t *console)
35 * Function to insert a new console structure into
36 * the console list. Should usually be called by
37 * console_<driver>_register implementations. The
38 * data structure passed will be taken over by the
39 * console framework and *MUST* be allocated in
40 * persistent memory (e.g. the data section).
41 * In : x0 - address of console_t structure
42 * Out: x0 - Always 1 (for easier tail calling)
Sathees Balyad35cc342018-07-31 15:11:11 +010043 * Clobber list: x0, x1
Julius Werner9536bae2017-07-31 18:15:11 -070044 * -----------------------------------------------
45 */
46func console_register
Sathees Balyad35cc342018-07-31 15:11:11 +010047 stp x21, x30, [sp, #-16]!
Julius Werner9536bae2017-07-31 18:15:11 -070048#if ENABLE_ASSERTIONS
Antonio Nino Diazc2e05bb2018-04-30 20:14:07 +010049 /* Assert that x0 isn't a NULL pointer */
Julius Werner9536bae2017-07-31 18:15:11 -070050 cmp x0, #0
51 ASM_ASSERT(ne)
Antonio Nino Diazc2e05bb2018-04-30 20:14:07 +010052 /* Assert that the struct isn't in the stack */
Julius Werner9536bae2017-07-31 18:15:11 -070053 adrp x1, __STACKS_START__
54 add x1, x1, :lo12:__STACKS_START__
55 cmp x0, x1
56 b.lo not_on_stack
57 adrp x1, __STACKS_END__
58 add x1, x1, :lo12:__STACKS_END__
59 cmp x0, x1
60 ASM_ASSERT(hs)
61not_on_stack:
Antonio Nino Diazc2e05bb2018-04-30 20:14:07 +010062 /* Assert that this struct isn't in the list */
63 mov x1, x0 /* Preserve x0 and x30 */
Antonio Nino Diazc2e05bb2018-04-30 20:14:07 +010064 bl console_is_registered
65 cmp x0, #0
66 ASM_ASSERT(eq)
Antonio Nino Diazc2e05bb2018-04-30 20:14:07 +010067 mov x0, x1
Julius Werner9536bae2017-07-31 18:15:11 -070068#endif /* ENABLE_ASSERTIONS */
Sathees Balyad35cc342018-07-31 15:11:11 +010069 adrp x21, console_list
70 ldr x1, [x21, :lo12:console_list] /* X1 = first struct in list */
71 str x0, [x21, :lo12:console_list] /* list head = new console */
Julius Werner9536bae2017-07-31 18:15:11 -070072 str x1, [x0, #CONSOLE_T_NEXT] /* new console next ptr = X1 */
73 mov x0, #1
Sathees Balyad35cc342018-07-31 15:11:11 +010074 ldp x21, x30, [sp], #16
Julius Werner9536bae2017-07-31 18:15:11 -070075 ret
76endfunc console_register
77
78 /* -----------------------------------------------
79 * int console_unregister(console_t *console)
80 * Function to find a specific console in the list
81 * of currently active consoles and remove it.
82 * In: x0 - address of console_t struct to remove
83 * Out: x0 - removed address, or NULL if not found
Sathees Balyad35cc342018-07-31 15:11:11 +010084 * Clobber list: x0, x1
Julius Werner9536bae2017-07-31 18:15:11 -070085 * -----------------------------------------------
86 */
87func console_unregister
Antonio Nino Diazc2e05bb2018-04-30 20:14:07 +010088#if ENABLE_ASSERTIONS
89 /* Assert that x0 isn't a NULL pointer */
90 cmp x0, #0
91 ASM_ASSERT(ne)
92#endif /* ENABLE_ASSERTIONS */
Sathees Balyad35cc342018-07-31 15:11:11 +010093 stp x21, xzr, [sp, #-16]!
94 adrp x21, console_list
95 add x21, x21, :lo12:console_list /* X21 = ptr to first struct */
96 ldr x1, [x21] /* X1 = first struct */
Julius Werner9536bae2017-07-31 18:15:11 -070097
98unregister_loop:
99 cbz x1, unregister_not_found
100 cmp x0, x1
101 b.eq unregister_found
Sathees Balyad35cc342018-07-31 15:11:11 +0100102 ldr x21, [x21] /* X21 = next ptr of struct */
103 ldr x1, [x21] /* X1 = next struct */
Julius Werner9536bae2017-07-31 18:15:11 -0700104 b unregister_loop
105
106unregister_found:
107 ldr x1, [x1] /* X1 = next struct */
Sathees Balyad35cc342018-07-31 15:11:11 +0100108 str x1, [x21] /* prev->next = cur->next */
109 ldp x21, xzr, [sp], #16
Julius Werner9536bae2017-07-31 18:15:11 -0700110 ret
111
112unregister_not_found:
113 mov x0, #0 /* return NULL if not found */
Sathees Balyad35cc342018-07-31 15:11:11 +0100114 ldp x21, xzr, [sp], #16
Julius Werner9536bae2017-07-31 18:15:11 -0700115 ret
116endfunc console_unregister
117
118 /* -----------------------------------------------
Antonio Nino Diazc2e05bb2018-04-30 20:14:07 +0100119 * int console_is_registered(console_t *console)
120 * Function to detect if a specific console is
121 * registered or not.
122 * In: x0 - address of console_t struct to remove
123 * Out: x0 - 1 if it is registered, 0 if not.
Sathees Balyad35cc342018-07-31 15:11:11 +0100124 * Clobber list: x0
Antonio Nino Diazc2e05bb2018-04-30 20:14:07 +0100125 * -----------------------------------------------
126 */
127func console_is_registered
128#if ENABLE_ASSERTIONS
129 /* Assert that x0 isn't a NULL pointer */
130 cmp x0, #0
131 ASM_ASSERT(ne)
132#endif /* ENABLE_ASSERTIONS */
Sathees Balyad35cc342018-07-31 15:11:11 +0100133 stp x21, xzr, [sp, #-16]!
134 adrp x21, console_list
135 ldr x21, [x21, :lo12:console_list] /* X21 = first console struct */
Antonio Nino Diazc2e05bb2018-04-30 20:14:07 +0100136check_registered_loop:
Sathees Balyad35cc342018-07-31 15:11:11 +0100137 cbz x21, console_not_registered /* Check if end of list */
138 cmp x0, x21 /* Check if the pointers are different */
Antonio Nino Diazc2e05bb2018-04-30 20:14:07 +0100139 b.eq console_registered
Sathees Balyad35cc342018-07-31 15:11:11 +0100140 ldr x21, [x21, #CONSOLE_T_NEXT] /* Get pointer to next struct */
Antonio Nino Diazc2e05bb2018-04-30 20:14:07 +0100141 b check_registered_loop
142console_not_registered:
143 mov x0, #0
Sathees Balyad35cc342018-07-31 15:11:11 +0100144 ldp x21, xzr, [sp], #16
Antonio Nino Diazc2e05bb2018-04-30 20:14:07 +0100145 ret
146console_registered:
147 mov x0, #1
Sathees Balyad35cc342018-07-31 15:11:11 +0100148 ldp x21, xzr, [sp], #16
Antonio Nino Diazc2e05bb2018-04-30 20:14:07 +0100149 ret
150endfunc console_is_registered
151
152 /* -----------------------------------------------
Julius Werner9536bae2017-07-31 18:15:11 -0700153 * void console_switch_state(unsigned int new_state)
154 * Function to switch the current console state.
155 * The console state determines which of the
156 * registered consoles are actually used at a time.
157 * In : w0 - global console state to move to
158 * Clobber list: x0, x1
159 * -----------------------------------------------
160 */
161func console_switch_state
162 adrp x1, console_state
163 strb w0, [x1, :lo12:console_state]
164 ret
165endfunc console_switch_state
166
167 /* -----------------------------------------------
168 * void console_set_scope(console_t *console,
169 * unsigned int scope)
170 * Function to update the states that a given console
171 * may be active in.
172 * In : x0 - pointer to console_t struct
173 * : w1 - new active state mask
174 * Clobber list: x0, x1, x2
175 * -----------------------------------------------
176 */
177func console_set_scope
178#if ENABLE_ASSERTIONS
179 tst w1, #~CONSOLE_FLAG_SCOPE_MASK
180 ASM_ASSERT(eq)
181#endif /* ENABLE_ASSERTIONS */
182 ldr w2, [x0, #CONSOLE_T_FLAGS]
183 and w2, w2, #~CONSOLE_FLAG_SCOPE_MASK
184 orr w2, w2, w1
185 str w2, [x0, #CONSOLE_T_FLAGS]
186 ret
187endfunc console_set_scope
188
189 /* ---------------------------------------------
190 * int console_putc(int c)
191 * Function to output a character. Calls all
192 * active console's putc() handlers in succession.
193 * In : x0 - character to be printed
194 * Out: x0 - printed character on success, or < 0
195 if at least one console had an error
Sathees Balyad35cc342018-07-31 15:11:11 +0100196 * Clobber list : x0, x1, x2
Julius Werner9536bae2017-07-31 18:15:11 -0700197 * ---------------------------------------------
198 */
199func console_putc
Sathees Balyad35cc342018-07-31 15:11:11 +0100200 stp x21, x30, [sp, #-16]!
201 stp x19, x20, [sp, #-16]!
202 mov w20, #ERROR_NO_VALID_CONSOLE /* W20 = current return value */
203 mov w19, w0 /* W19 = character to print */
204 adrp x21, console_list
205 ldr x21, [x21, :lo12:console_list] /* X21 = first console struct */
Julius Werner9536bae2017-07-31 18:15:11 -0700206
207putc_loop:
Sathees Balyad35cc342018-07-31 15:11:11 +0100208 cbz x21, putc_done
Julius Werner9536bae2017-07-31 18:15:11 -0700209 adrp x1, console_state
210 ldrb w1, [x1, :lo12:console_state]
Sathees Balyad35cc342018-07-31 15:11:11 +0100211 ldr w2, [x21, #CONSOLE_T_FLAGS]
Julius Werner9536bae2017-07-31 18:15:11 -0700212 tst w1, w2
213 b.eq putc_continue
Sathees Balyad35cc342018-07-31 15:11:11 +0100214 ldr x2, [x21, #CONSOLE_T_PUTC]
Julius Werner9536bae2017-07-31 18:15:11 -0700215 cbz x2, putc_continue
Sathees Balyad35cc342018-07-31 15:11:11 +0100216 mov w0, w19
217 mov x1, x21
Julius Werner9536bae2017-07-31 18:15:11 -0700218 blr x2
Sathees Balyad35cc342018-07-31 15:11:11 +0100219 cmp w20, #ERROR_NO_VALID_CONSOLE /* update W20 if it's NOVALID */
Julius Werner9536bae2017-07-31 18:15:11 -0700220 ccmp w0, #0, #0x8, ne /* else update it if W0 < 0 */
Sathees Balyad35cc342018-07-31 15:11:11 +0100221 csel w20, w0, w20, lt
Julius Werner9536bae2017-07-31 18:15:11 -0700222putc_continue:
Sathees Balyad35cc342018-07-31 15:11:11 +0100223 ldr x21, [x21] /* X21 = next struct */
Julius Werner9536bae2017-07-31 18:15:11 -0700224 b putc_loop
225
226putc_done:
Sathees Balyad35cc342018-07-31 15:11:11 +0100227 mov w0, w20
228 ldp x19, x20, [sp], #16
229 ldp x21, x30, [sp], #16
230 ret
Julius Werner9536bae2017-07-31 18:15:11 -0700231endfunc console_putc
232
233 /* ---------------------------------------------
234 * int console_getc(void)
235 * Function to get a character from any console.
236 * Keeps looping through all consoles' getc()
237 * handlers until one of them returns a
238 * character, then stops iterating and returns
239 * that character to the caller. Will stop looping
240 * if all active consoles report real errors
241 * (other than just not having a char available).
242 * Out : x0 - read character, or < 0 on error
Sathees Balyad35cc342018-07-31 15:11:11 +0100243 * Clobber list : x0, x1
Julius Werner9536bae2017-07-31 18:15:11 -0700244 * ---------------------------------------------
245 */
246func console_getc
Sathees Balyad35cc342018-07-31 15:11:11 +0100247 stp x30, xzr, [sp, #-16]!
248 stp x20, x21, [sp, #-16]!
Julius Werner9536bae2017-07-31 18:15:11 -0700249getc_try_again:
Sathees Balyad35cc342018-07-31 15:11:11 +0100250 mov w20, #ERROR_NO_VALID_CONSOLE /* W20 = current return value */
251 adrp x21, console_list
252 ldr x21, [x21, :lo12:console_list] /* X21 = first console struct */
253 cbnz x21, getc_loop
254 mov w0, w20 /* If no consoles registered */
255 ldp x20, x21, [sp], #16
256 ldp x30, xzr, [sp], #16
257 ret /* return immediately. */
Julius Werner9536bae2017-07-31 18:15:11 -0700258
259getc_loop:
260 adrp x0, console_state
261 ldrb w0, [x0, :lo12:console_state]
Sathees Balyad35cc342018-07-31 15:11:11 +0100262 ldr w1, [x21, #CONSOLE_T_FLAGS]
Julius Werner9536bae2017-07-31 18:15:11 -0700263 tst w0, w1
264 b.eq getc_continue
Sathees Balyad35cc342018-07-31 15:11:11 +0100265 ldr x1, [x21, #CONSOLE_T_GETC]
Julius Werner9536bae2017-07-31 18:15:11 -0700266 cbz x1, getc_continue
Sathees Balyad35cc342018-07-31 15:11:11 +0100267 mov x0, x21
Julius Werner9536bae2017-07-31 18:15:11 -0700268 blr x1
269 cmp w0, #0 /* if X0 >= 0: return */
270 b.ge getc_found
Sathees Balyad35cc342018-07-31 15:11:11 +0100271 cmp w20, #ERROR_NO_PENDING_CHAR /* may update W20 (NOCHAR has */
272 csel w20, w20, w0, eq /* precedence vs real errors) */
Julius Werner9536bae2017-07-31 18:15:11 -0700273getc_continue:
Sathees Balyad35cc342018-07-31 15:11:11 +0100274 ldr x21, [x21] /* X21 = next struct */
275 cbnz x21, getc_loop
276 cmp w20, #ERROR_NO_PENDING_CHAR /* Keep scanning if at least */
Julius Werner9536bae2017-07-31 18:15:11 -0700277 b.eq getc_try_again /* one console returns NOCHAR */
Sathees Balyad35cc342018-07-31 15:11:11 +0100278 mov w0, w20
Julius Werner9536bae2017-07-31 18:15:11 -0700279
280getc_found:
Sathees Balyad35cc342018-07-31 15:11:11 +0100281 ldp x20, x21, [sp], #16
282 ldp x30, xzr, [sp], #16
283 ret
Julius Werner9536bae2017-07-31 18:15:11 -0700284endfunc console_getc
285
286 /* ---------------------------------------------
287 * int console_flush(void)
288 * Function to force a write of all buffered
289 * data that hasn't been output. Calls all
290 * console's flush() handlers in succession.
291 * Out: x0 - 0 on success, < 0 if at least one error
Sathees Balyad35cc342018-07-31 15:11:11 +0100292 * Clobber list : x0, x1, x2
Julius Werner9536bae2017-07-31 18:15:11 -0700293 * ---------------------------------------------
294 */
295func console_flush
Sathees Balyad35cc342018-07-31 15:11:11 +0100296 stp x30, xzr, [sp, #-16]!
297 stp x20, x21, [sp, #-16]!
298 mov w20, #ERROR_NO_VALID_CONSOLE /* W20 = current return value */
299 adrp x21, console_list
300 ldr x21, [x21, :lo12:console_list] /* X21 = first console struct */
Julius Werner9536bae2017-07-31 18:15:11 -0700301
302flush_loop:
Sathees Balyad35cc342018-07-31 15:11:11 +0100303 cbz x21, flush_done
Julius Werner9536bae2017-07-31 18:15:11 -0700304 adrp x1, console_state
305 ldrb w1, [x1, :lo12:console_state]
Sathees Balyad35cc342018-07-31 15:11:11 +0100306 ldr w2, [x21, #CONSOLE_T_FLAGS]
Julius Werner9536bae2017-07-31 18:15:11 -0700307 tst w1, w2
308 b.eq flush_continue
Sathees Balyad35cc342018-07-31 15:11:11 +0100309 ldr x1, [x21, #CONSOLE_T_FLUSH]
Julius Werner9536bae2017-07-31 18:15:11 -0700310 cbz x1, flush_continue
Sathees Balyad35cc342018-07-31 15:11:11 +0100311 mov x0, x21
Julius Werner9536bae2017-07-31 18:15:11 -0700312 blr x1
Sathees Balyad35cc342018-07-31 15:11:11 +0100313 cmp w20, #ERROR_NO_VALID_CONSOLE /* update W20 if it's NOVALID */
Julius Werner9536bae2017-07-31 18:15:11 -0700314 ccmp w0, #0, #0x8, ne /* else update it if W0 < 0 */
Sathees Balyad35cc342018-07-31 15:11:11 +0100315 csel w20, w0, w20, lt
Julius Werner9536bae2017-07-31 18:15:11 -0700316flush_continue:
Sathees Balyad35cc342018-07-31 15:11:11 +0100317 ldr x21, [x21] /* X21 = next struct */
Julius Werner9536bae2017-07-31 18:15:11 -0700318 b flush_loop
319
320flush_done:
Sathees Balyad35cc342018-07-31 15:11:11 +0100321 mov w0, w20
322 ldp x20, x21, [sp], #16
323 ldp x30, xzr, [sp], #16
324 ret
Julius Werner9536bae2017-07-31 18:15:11 -0700325endfunc console_flush