blob: 40d500d2f8183c4e1982bb3ca6515269ef450718 [file] [log] [blame]
Julius Werner94f89072017-07-31 18:15:11 -07001/*
Antonio Nino Diaz4f31ad52018-04-30 20:14:07 +01002 * Copyright (c) 2015-2018, ARM Limited and Contributors. All rights reserved.
Julius Werner94f89072017-07-31 18:15:11 -07003 *
4 * SPDX-License-Identifier: BSD-3-Clause
5 */
6
Julius Werner6b88b652018-11-27 17:50:28 -08007#if MULTI_CONSOLE_API
8
Julius Werner94f89072017-07-31 18:15:11 -07009#include <asm_macros.S>
10#include <assert_macros.S>
11#include <console.h>
12
13 .globl console_register
14 .globl console_unregister
Antonio Nino Diaz4f31ad52018-04-30 20:14:07 +010015 .globl console_is_registered
16 .globl console_set_scope
Julius Werner94f89072017-07-31 18:15:11 -070017 .globl console_switch_state
18 .globl console_putc
19 .globl console_getc
20 .globl console_flush
Julius Werner1338c9c2018-11-19 14:25:55 -080021 .globl console_list
Julius Werner94f89072017-07-31 18:15:11 -070022
23 /*
24 * The console list pointer is in the data section and not in
25 * .bss even though it is zero-init. In particular, this allows
26 * the console functions to start using this variable before
27 * the runtime memory is initialized for images which do not
28 * need to copy the .data section from ROM to RAM.
29 */
30.section .data.console_list ; .align 3
31 console_list: .quad 0x0
32.section .data.console_state ; .align 0
33 console_state: .byte CONSOLE_FLAG_BOOT
34
35 /* -----------------------------------------------
36 * int console_register(console_t *console)
37 * Function to insert a new console structure into
38 * the console list. Should usually be called by
39 * console_<driver>_register implementations. The
40 * data structure passed will be taken over by the
41 * console framework and *MUST* be allocated in
42 * persistent memory (e.g. the data section).
43 * In : x0 - address of console_t structure
44 * Out: x0 - Always 1 (for easier tail calling)
Sathees Balya28cfffc2018-07-31 15:11:11 +010045 * Clobber list: x0, x1
Julius Werner94f89072017-07-31 18:15:11 -070046 * -----------------------------------------------
47 */
48func console_register
Sathees Balya28cfffc2018-07-31 15:11:11 +010049 stp x21, x30, [sp, #-16]!
Julius Werner94f89072017-07-31 18:15:11 -070050#if ENABLE_ASSERTIONS
Antonio Nino Diaz4f31ad52018-04-30 20:14:07 +010051 /* Assert that x0 isn't a NULL pointer */
Julius Werner94f89072017-07-31 18:15:11 -070052 cmp x0, #0
53 ASM_ASSERT(ne)
Antonio Nino Diaz4f31ad52018-04-30 20:14:07 +010054 /* Assert that the struct isn't in the stack */
Julius Werner94f89072017-07-31 18:15:11 -070055 adrp x1, __STACKS_START__
56 add x1, x1, :lo12:__STACKS_START__
57 cmp x0, x1
58 b.lo not_on_stack
59 adrp x1, __STACKS_END__
60 add x1, x1, :lo12:__STACKS_END__
61 cmp x0, x1
62 ASM_ASSERT(hs)
63not_on_stack:
Antonio Nino Diaz4f31ad52018-04-30 20:14:07 +010064 /* Assert that this struct isn't in the list */
65 mov x1, x0 /* Preserve x0 and x30 */
Antonio Nino Diaz4f31ad52018-04-30 20:14:07 +010066 bl console_is_registered
67 cmp x0, #0
68 ASM_ASSERT(eq)
Antonio Nino Diaz4f31ad52018-04-30 20:14:07 +010069 mov x0, x1
Julius Werner94f89072017-07-31 18:15:11 -070070#endif /* ENABLE_ASSERTIONS */
Sathees Balya28cfffc2018-07-31 15:11:11 +010071 adrp x21, console_list
72 ldr x1, [x21, :lo12:console_list] /* X1 = first struct in list */
73 str x0, [x21, :lo12:console_list] /* list head = new console */
Julius Werner94f89072017-07-31 18:15:11 -070074 str x1, [x0, #CONSOLE_T_NEXT] /* new console next ptr = X1 */
75 mov x0, #1
Sathees Balya28cfffc2018-07-31 15:11:11 +010076 ldp x21, x30, [sp], #16
Julius Werner94f89072017-07-31 18:15:11 -070077 ret
78endfunc console_register
79
80 /* -----------------------------------------------
81 * int console_unregister(console_t *console)
82 * Function to find a specific console in the list
83 * of currently active consoles and remove it.
84 * In: x0 - address of console_t struct to remove
85 * Out: x0 - removed address, or NULL if not found
Sathees Balya28cfffc2018-07-31 15:11:11 +010086 * Clobber list: x0, x1
Julius Werner94f89072017-07-31 18:15:11 -070087 * -----------------------------------------------
88 */
89func console_unregister
Antonio Nino Diaz4f31ad52018-04-30 20:14:07 +010090#if ENABLE_ASSERTIONS
91 /* Assert that x0 isn't a NULL pointer */
92 cmp x0, #0
93 ASM_ASSERT(ne)
94#endif /* ENABLE_ASSERTIONS */
Sathees Balya28cfffc2018-07-31 15:11:11 +010095 stp x21, xzr, [sp, #-16]!
96 adrp x21, console_list
97 add x21, x21, :lo12:console_list /* X21 = ptr to first struct */
98 ldr x1, [x21] /* X1 = first struct */
Julius Werner94f89072017-07-31 18:15:11 -070099
100unregister_loop:
101 cbz x1, unregister_not_found
102 cmp x0, x1
103 b.eq unregister_found
Sathees Balya28cfffc2018-07-31 15:11:11 +0100104 ldr x21, [x21] /* X21 = next ptr of struct */
105 ldr x1, [x21] /* X1 = next struct */
Julius Werner94f89072017-07-31 18:15:11 -0700106 b unregister_loop
107
108unregister_found:
109 ldr x1, [x1] /* X1 = next struct */
Sathees Balya28cfffc2018-07-31 15:11:11 +0100110 str x1, [x21] /* prev->next = cur->next */
111 ldp x21, xzr, [sp], #16
Julius Werner94f89072017-07-31 18:15:11 -0700112 ret
113
114unregister_not_found:
115 mov x0, #0 /* return NULL if not found */
Sathees Balya28cfffc2018-07-31 15:11:11 +0100116 ldp x21, xzr, [sp], #16
Julius Werner94f89072017-07-31 18:15:11 -0700117 ret
118endfunc console_unregister
119
120 /* -----------------------------------------------
Antonio Nino Diaz4f31ad52018-04-30 20:14:07 +0100121 * int console_is_registered(console_t *console)
122 * Function to detect if a specific console is
123 * registered or not.
124 * In: x0 - address of console_t struct to remove
125 * Out: x0 - 1 if it is registered, 0 if not.
Sathees Balya28cfffc2018-07-31 15:11:11 +0100126 * Clobber list: x0
Antonio Nino Diaz4f31ad52018-04-30 20:14:07 +0100127 * -----------------------------------------------
128 */
129func console_is_registered
130#if ENABLE_ASSERTIONS
131 /* Assert that x0 isn't a NULL pointer */
132 cmp x0, #0
133 ASM_ASSERT(ne)
134#endif /* ENABLE_ASSERTIONS */
Sathees Balya28cfffc2018-07-31 15:11:11 +0100135 stp x21, xzr, [sp, #-16]!
136 adrp x21, console_list
137 ldr x21, [x21, :lo12:console_list] /* X21 = first console struct */
Antonio Nino Diaz4f31ad52018-04-30 20:14:07 +0100138check_registered_loop:
Sathees Balya28cfffc2018-07-31 15:11:11 +0100139 cbz x21, console_not_registered /* Check if end of list */
140 cmp x0, x21 /* Check if the pointers are different */
Antonio Nino Diaz4f31ad52018-04-30 20:14:07 +0100141 b.eq console_registered
Sathees Balya28cfffc2018-07-31 15:11:11 +0100142 ldr x21, [x21, #CONSOLE_T_NEXT] /* Get pointer to next struct */
Antonio Nino Diaz4f31ad52018-04-30 20:14:07 +0100143 b check_registered_loop
144console_not_registered:
145 mov x0, #0
Sathees Balya28cfffc2018-07-31 15:11:11 +0100146 ldp x21, xzr, [sp], #16
Antonio Nino Diaz4f31ad52018-04-30 20:14:07 +0100147 ret
148console_registered:
149 mov x0, #1
Sathees Balya28cfffc2018-07-31 15:11:11 +0100150 ldp x21, xzr, [sp], #16
Antonio Nino Diaz4f31ad52018-04-30 20:14:07 +0100151 ret
152endfunc console_is_registered
153
154 /* -----------------------------------------------
Julius Werner94f89072017-07-31 18:15:11 -0700155 * void console_switch_state(unsigned int new_state)
156 * Function to switch the current console state.
157 * The console state determines which of the
158 * registered consoles are actually used at a time.
159 * In : w0 - global console state to move to
160 * Clobber list: x0, x1
161 * -----------------------------------------------
162 */
163func console_switch_state
164 adrp x1, console_state
165 strb w0, [x1, :lo12:console_state]
166 ret
167endfunc console_switch_state
168
169 /* -----------------------------------------------
170 * void console_set_scope(console_t *console,
171 * unsigned int scope)
172 * Function to update the states that a given console
173 * may be active in.
174 * In : x0 - pointer to console_t struct
175 * : w1 - new active state mask
176 * Clobber list: x0, x1, x2
177 * -----------------------------------------------
178 */
179func console_set_scope
180#if ENABLE_ASSERTIONS
181 tst w1, #~CONSOLE_FLAG_SCOPE_MASK
182 ASM_ASSERT(eq)
183#endif /* ENABLE_ASSERTIONS */
184 ldr w2, [x0, #CONSOLE_T_FLAGS]
185 and w2, w2, #~CONSOLE_FLAG_SCOPE_MASK
186 orr w2, w2, w1
187 str w2, [x0, #CONSOLE_T_FLAGS]
188 ret
189endfunc console_set_scope
190
191 /* ---------------------------------------------
192 * int console_putc(int c)
193 * Function to output a character. Calls all
194 * active console's putc() handlers in succession.
195 * In : x0 - character to be printed
196 * Out: x0 - printed character on success, or < 0
197 if at least one console had an error
Sathees Balya28cfffc2018-07-31 15:11:11 +0100198 * Clobber list : x0, x1, x2
Julius Werner94f89072017-07-31 18:15:11 -0700199 * ---------------------------------------------
200 */
201func console_putc
Sathees Balya28cfffc2018-07-31 15:11:11 +0100202 stp x21, x30, [sp, #-16]!
203 stp x19, x20, [sp, #-16]!
204 mov w20, #ERROR_NO_VALID_CONSOLE /* W20 = current return value */
205 mov w19, w0 /* W19 = character to print */
206 adrp x21, console_list
207 ldr x21, [x21, :lo12:console_list] /* X21 = first console struct */
Julius Werner94f89072017-07-31 18:15:11 -0700208
209putc_loop:
Sathees Balya28cfffc2018-07-31 15:11:11 +0100210 cbz x21, putc_done
Julius Werner94f89072017-07-31 18:15:11 -0700211 adrp x1, console_state
212 ldrb w1, [x1, :lo12:console_state]
Sathees Balya28cfffc2018-07-31 15:11:11 +0100213 ldr w2, [x21, #CONSOLE_T_FLAGS]
Julius Werner94f89072017-07-31 18:15:11 -0700214 tst w1, w2
215 b.eq putc_continue
Sathees Balya28cfffc2018-07-31 15:11:11 +0100216 ldr x2, [x21, #CONSOLE_T_PUTC]
Julius Werner94f89072017-07-31 18:15:11 -0700217 cbz x2, putc_continue
Sathees Balya28cfffc2018-07-31 15:11:11 +0100218 mov w0, w19
219 mov x1, x21
Julius Werner94f89072017-07-31 18:15:11 -0700220 blr x2
Sathees Balya28cfffc2018-07-31 15:11:11 +0100221 cmp w20, #ERROR_NO_VALID_CONSOLE /* update W20 if it's NOVALID */
Julius Werner94f89072017-07-31 18:15:11 -0700222 ccmp w0, #0, #0x8, ne /* else update it if W0 < 0 */
Sathees Balya28cfffc2018-07-31 15:11:11 +0100223 csel w20, w0, w20, lt
Julius Werner94f89072017-07-31 18:15:11 -0700224putc_continue:
Sathees Balya28cfffc2018-07-31 15:11:11 +0100225 ldr x21, [x21] /* X21 = next struct */
Julius Werner94f89072017-07-31 18:15:11 -0700226 b putc_loop
227
228putc_done:
Sathees Balya28cfffc2018-07-31 15:11:11 +0100229 mov w0, w20
230 ldp x19, x20, [sp], #16
231 ldp x21, x30, [sp], #16
232 ret
Julius Werner94f89072017-07-31 18:15:11 -0700233endfunc console_putc
234
235 /* ---------------------------------------------
236 * int console_getc(void)
237 * Function to get a character from any console.
238 * Keeps looping through all consoles' getc()
239 * handlers until one of them returns a
240 * character, then stops iterating and returns
241 * that character to the caller. Will stop looping
242 * if all active consoles report real errors
243 * (other than just not having a char available).
244 * Out : x0 - read character, or < 0 on error
Sathees Balya28cfffc2018-07-31 15:11:11 +0100245 * Clobber list : x0, x1
Julius Werner94f89072017-07-31 18:15:11 -0700246 * ---------------------------------------------
247 */
248func console_getc
Sathees Balya28cfffc2018-07-31 15:11:11 +0100249 stp x30, xzr, [sp, #-16]!
250 stp x20, x21, [sp, #-16]!
Julius Werner94f89072017-07-31 18:15:11 -0700251getc_try_again:
Sathees Balya28cfffc2018-07-31 15:11:11 +0100252 mov w20, #ERROR_NO_VALID_CONSOLE /* W20 = current return value */
253 adrp x21, console_list
254 ldr x21, [x21, :lo12:console_list] /* X21 = first console struct */
255 cbnz x21, getc_loop
256 mov w0, w20 /* If no consoles registered */
257 ldp x20, x21, [sp], #16
258 ldp x30, xzr, [sp], #16
259 ret /* return immediately. */
Julius Werner94f89072017-07-31 18:15:11 -0700260
261getc_loop:
262 adrp x0, console_state
263 ldrb w0, [x0, :lo12:console_state]
Sathees Balya28cfffc2018-07-31 15:11:11 +0100264 ldr w1, [x21, #CONSOLE_T_FLAGS]
Julius Werner94f89072017-07-31 18:15:11 -0700265 tst w0, w1
266 b.eq getc_continue
Sathees Balya28cfffc2018-07-31 15:11:11 +0100267 ldr x1, [x21, #CONSOLE_T_GETC]
Julius Werner94f89072017-07-31 18:15:11 -0700268 cbz x1, getc_continue
Sathees Balya28cfffc2018-07-31 15:11:11 +0100269 mov x0, x21
Julius Werner94f89072017-07-31 18:15:11 -0700270 blr x1
271 cmp w0, #0 /* if X0 >= 0: return */
272 b.ge getc_found
Sathees Balya28cfffc2018-07-31 15:11:11 +0100273 cmp w20, #ERROR_NO_PENDING_CHAR /* may update W20 (NOCHAR has */
274 csel w20, w20, w0, eq /* precedence vs real errors) */
Julius Werner94f89072017-07-31 18:15:11 -0700275getc_continue:
Sathees Balya28cfffc2018-07-31 15:11:11 +0100276 ldr x21, [x21] /* X21 = next struct */
277 cbnz x21, getc_loop
278 cmp w20, #ERROR_NO_PENDING_CHAR /* Keep scanning if at least */
Julius Werner94f89072017-07-31 18:15:11 -0700279 b.eq getc_try_again /* one console returns NOCHAR */
Sathees Balya28cfffc2018-07-31 15:11:11 +0100280 mov w0, w20
Julius Werner94f89072017-07-31 18:15:11 -0700281
282getc_found:
Sathees Balya28cfffc2018-07-31 15:11:11 +0100283 ldp x20, x21, [sp], #16
284 ldp x30, xzr, [sp], #16
285 ret
Julius Werner94f89072017-07-31 18:15:11 -0700286endfunc console_getc
287
288 /* ---------------------------------------------
289 * int console_flush(void)
290 * Function to force a write of all buffered
291 * data that hasn't been output. Calls all
292 * console's flush() handlers in succession.
293 * Out: x0 - 0 on success, < 0 if at least one error
Sathees Balya28cfffc2018-07-31 15:11:11 +0100294 * Clobber list : x0, x1, x2
Julius Werner94f89072017-07-31 18:15:11 -0700295 * ---------------------------------------------
296 */
297func console_flush
Sathees Balya28cfffc2018-07-31 15:11:11 +0100298 stp x30, xzr, [sp, #-16]!
299 stp x20, x21, [sp, #-16]!
300 mov w20, #ERROR_NO_VALID_CONSOLE /* W20 = current return value */
301 adrp x21, console_list
302 ldr x21, [x21, :lo12:console_list] /* X21 = first console struct */
Julius Werner94f89072017-07-31 18:15:11 -0700303
304flush_loop:
Sathees Balya28cfffc2018-07-31 15:11:11 +0100305 cbz x21, flush_done
Julius Werner94f89072017-07-31 18:15:11 -0700306 adrp x1, console_state
307 ldrb w1, [x1, :lo12:console_state]
Sathees Balya28cfffc2018-07-31 15:11:11 +0100308 ldr w2, [x21, #CONSOLE_T_FLAGS]
Julius Werner94f89072017-07-31 18:15:11 -0700309 tst w1, w2
310 b.eq flush_continue
Sathees Balya28cfffc2018-07-31 15:11:11 +0100311 ldr x1, [x21, #CONSOLE_T_FLUSH]
Julius Werner94f89072017-07-31 18:15:11 -0700312 cbz x1, flush_continue
Sathees Balya28cfffc2018-07-31 15:11:11 +0100313 mov x0, x21
Julius Werner94f89072017-07-31 18:15:11 -0700314 blr x1
Sathees Balya28cfffc2018-07-31 15:11:11 +0100315 cmp w20, #ERROR_NO_VALID_CONSOLE /* update W20 if it's NOVALID */
Julius Werner94f89072017-07-31 18:15:11 -0700316 ccmp w0, #0, #0x8, ne /* else update it if W0 < 0 */
Sathees Balya28cfffc2018-07-31 15:11:11 +0100317 csel w20, w0, w20, lt
Julius Werner94f89072017-07-31 18:15:11 -0700318flush_continue:
Sathees Balya28cfffc2018-07-31 15:11:11 +0100319 ldr x21, [x21] /* X21 = next struct */
Julius Werner94f89072017-07-31 18:15:11 -0700320 b flush_loop
321
322flush_done:
Sathees Balya28cfffc2018-07-31 15:11:11 +0100323 mov w0, w20
324 ldp x20, x21, [sp], #16
325 ldp x30, xzr, [sp], #16
326 ret
Julius Werner94f89072017-07-31 18:15:11 -0700327endfunc console_flush
Julius Werner6b88b652018-11-27 17:50:28 -0800328
329#endif /* MULTI_CONSOLE_API */