blob: 7f076c6233c7a5e79dbf3adec4011578a3afb0f4 [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
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 Diaz4f31ad52018-04-30 20:14:07 +010013 .globl console_is_registered
14 .globl console_set_scope
Julius Werner94f89072017-07-31 18:15:11 -070015 .globl console_switch_state
16 .globl console_putc
17 .globl console_getc
18 .globl console_flush
19
20 /*
21 * The console list pointer is in the data section and not in
22 * .bss even though it is zero-init. In particular, this allows
23 * the console functions to start using this variable before
24 * the runtime memory is initialized for images which do not
25 * need to copy the .data section from ROM to RAM.
26 */
27.section .data.console_list ; .align 3
28 console_list: .quad 0x0
29.section .data.console_state ; .align 0
30 console_state: .byte CONSOLE_FLAG_BOOT
31
32 /* -----------------------------------------------
33 * int console_register(console_t *console)
34 * Function to insert a new console structure into
35 * the console list. Should usually be called by
36 * console_<driver>_register implementations. The
37 * data structure passed will be taken over by the
38 * console framework and *MUST* be allocated in
39 * persistent memory (e.g. the data section).
40 * In : x0 - address of console_t structure
41 * Out: x0 - Always 1 (for easier tail calling)
Sathees Balya28cfffc2018-07-31 15:11:11 +010042 * Clobber list: x0, x1
Julius Werner94f89072017-07-31 18:15:11 -070043 * -----------------------------------------------
44 */
45func console_register
Sathees Balya28cfffc2018-07-31 15:11:11 +010046 stp x21, x30, [sp, #-16]!
Julius Werner94f89072017-07-31 18:15:11 -070047#if ENABLE_ASSERTIONS
Antonio Nino Diaz4f31ad52018-04-30 20:14:07 +010048 /* Assert that x0 isn't a NULL pointer */
Julius Werner94f89072017-07-31 18:15:11 -070049 cmp x0, #0
50 ASM_ASSERT(ne)
Antonio Nino Diaz4f31ad52018-04-30 20:14:07 +010051 /* Assert that the struct isn't in the stack */
Julius Werner94f89072017-07-31 18:15:11 -070052 adrp x1, __STACKS_START__
53 add x1, x1, :lo12:__STACKS_START__
54 cmp x0, x1
55 b.lo not_on_stack
56 adrp x1, __STACKS_END__
57 add x1, x1, :lo12:__STACKS_END__
58 cmp x0, x1
59 ASM_ASSERT(hs)
60not_on_stack:
Antonio Nino Diaz4f31ad52018-04-30 20:14:07 +010061 /* Assert that this struct isn't in the list */
62 mov x1, x0 /* Preserve x0 and x30 */
Antonio Nino Diaz4f31ad52018-04-30 20:14:07 +010063 bl console_is_registered
64 cmp x0, #0
65 ASM_ASSERT(eq)
Antonio Nino Diaz4f31ad52018-04-30 20:14:07 +010066 mov x0, x1
Julius Werner94f89072017-07-31 18:15:11 -070067#endif /* ENABLE_ASSERTIONS */
Sathees Balya28cfffc2018-07-31 15:11:11 +010068 adrp x21, console_list
69 ldr x1, [x21, :lo12:console_list] /* X1 = first struct in list */
70 str x0, [x21, :lo12:console_list] /* list head = new console */
Julius Werner94f89072017-07-31 18:15:11 -070071 str x1, [x0, #CONSOLE_T_NEXT] /* new console next ptr = X1 */
72 mov x0, #1
Sathees Balya28cfffc2018-07-31 15:11:11 +010073 ldp x21, x30, [sp], #16
Julius Werner94f89072017-07-31 18:15:11 -070074 ret
75endfunc console_register
76
77 /* -----------------------------------------------
78 * int console_unregister(console_t *console)
79 * Function to find a specific console in the list
80 * of currently active consoles and remove it.
81 * In: x0 - address of console_t struct to remove
82 * Out: x0 - removed address, or NULL if not found
Sathees Balya28cfffc2018-07-31 15:11:11 +010083 * Clobber list: x0, x1
Julius Werner94f89072017-07-31 18:15:11 -070084 * -----------------------------------------------
85 */
86func console_unregister
Antonio Nino Diaz4f31ad52018-04-30 20:14:07 +010087#if ENABLE_ASSERTIONS
88 /* Assert that x0 isn't a NULL pointer */
89 cmp x0, #0
90 ASM_ASSERT(ne)
91#endif /* ENABLE_ASSERTIONS */
Sathees Balya28cfffc2018-07-31 15:11:11 +010092 stp x21, xzr, [sp, #-16]!
93 adrp x21, console_list
94 add x21, x21, :lo12:console_list /* X21 = ptr to first struct */
95 ldr x1, [x21] /* X1 = first struct */
Julius Werner94f89072017-07-31 18:15:11 -070096
97unregister_loop:
98 cbz x1, unregister_not_found
99 cmp x0, x1
100 b.eq unregister_found
Sathees Balya28cfffc2018-07-31 15:11:11 +0100101 ldr x21, [x21] /* X21 = next ptr of struct */
102 ldr x1, [x21] /* X1 = next struct */
Julius Werner94f89072017-07-31 18:15:11 -0700103 b unregister_loop
104
105unregister_found:
106 ldr x1, [x1] /* X1 = next struct */
Sathees Balya28cfffc2018-07-31 15:11:11 +0100107 str x1, [x21] /* prev->next = cur->next */
108 ldp x21, xzr, [sp], #16
Julius Werner94f89072017-07-31 18:15:11 -0700109 ret
110
111unregister_not_found:
112 mov x0, #0 /* return NULL if not found */
Sathees Balya28cfffc2018-07-31 15:11:11 +0100113 ldp x21, xzr, [sp], #16
Julius Werner94f89072017-07-31 18:15:11 -0700114 ret
115endfunc console_unregister
116
117 /* -----------------------------------------------
Antonio Nino Diaz4f31ad52018-04-30 20:14:07 +0100118 * int console_is_registered(console_t *console)
119 * Function to detect if a specific console is
120 * registered or not.
121 * In: x0 - address of console_t struct to remove
122 * Out: x0 - 1 if it is registered, 0 if not.
Sathees Balya28cfffc2018-07-31 15:11:11 +0100123 * Clobber list: x0
Antonio Nino Diaz4f31ad52018-04-30 20:14:07 +0100124 * -----------------------------------------------
125 */
126func console_is_registered
127#if ENABLE_ASSERTIONS
128 /* Assert that x0 isn't a NULL pointer */
129 cmp x0, #0
130 ASM_ASSERT(ne)
131#endif /* ENABLE_ASSERTIONS */
Sathees Balya28cfffc2018-07-31 15:11:11 +0100132 stp x21, xzr, [sp, #-16]!
133 adrp x21, console_list
134 ldr x21, [x21, :lo12:console_list] /* X21 = first console struct */
Antonio Nino Diaz4f31ad52018-04-30 20:14:07 +0100135check_registered_loop:
Sathees Balya28cfffc2018-07-31 15:11:11 +0100136 cbz x21, console_not_registered /* Check if end of list */
137 cmp x0, x21 /* Check if the pointers are different */
Antonio Nino Diaz4f31ad52018-04-30 20:14:07 +0100138 b.eq console_registered
Sathees Balya28cfffc2018-07-31 15:11:11 +0100139 ldr x21, [x21, #CONSOLE_T_NEXT] /* Get pointer to next struct */
Antonio Nino Diaz4f31ad52018-04-30 20:14:07 +0100140 b check_registered_loop
141console_not_registered:
142 mov x0, #0
Sathees Balya28cfffc2018-07-31 15:11:11 +0100143 ldp x21, xzr, [sp], #16
Antonio Nino Diaz4f31ad52018-04-30 20:14:07 +0100144 ret
145console_registered:
146 mov x0, #1
Sathees Balya28cfffc2018-07-31 15:11:11 +0100147 ldp x21, xzr, [sp], #16
Antonio Nino Diaz4f31ad52018-04-30 20:14:07 +0100148 ret
149endfunc console_is_registered
150
151 /* -----------------------------------------------
Julius Werner94f89072017-07-31 18:15:11 -0700152 * void console_switch_state(unsigned int new_state)
153 * Function to switch the current console state.
154 * The console state determines which of the
155 * registered consoles are actually used at a time.
156 * In : w0 - global console state to move to
157 * Clobber list: x0, x1
158 * -----------------------------------------------
159 */
160func console_switch_state
161 adrp x1, console_state
162 strb w0, [x1, :lo12:console_state]
163 ret
164endfunc console_switch_state
165
166 /* -----------------------------------------------
167 * void console_set_scope(console_t *console,
168 * unsigned int scope)
169 * Function to update the states that a given console
170 * may be active in.
171 * In : x0 - pointer to console_t struct
172 * : w1 - new active state mask
173 * Clobber list: x0, x1, x2
174 * -----------------------------------------------
175 */
176func console_set_scope
177#if ENABLE_ASSERTIONS
178 tst w1, #~CONSOLE_FLAG_SCOPE_MASK
179 ASM_ASSERT(eq)
180#endif /* ENABLE_ASSERTIONS */
181 ldr w2, [x0, #CONSOLE_T_FLAGS]
182 and w2, w2, #~CONSOLE_FLAG_SCOPE_MASK
183 orr w2, w2, w1
184 str w2, [x0, #CONSOLE_T_FLAGS]
185 ret
186endfunc console_set_scope
187
188 /* ---------------------------------------------
189 * int console_putc(int c)
190 * Function to output a character. Calls all
191 * active console's putc() handlers in succession.
192 * In : x0 - character to be printed
193 * Out: x0 - printed character on success, or < 0
194 if at least one console had an error
Sathees Balya28cfffc2018-07-31 15:11:11 +0100195 * Clobber list : x0, x1, x2
Julius Werner94f89072017-07-31 18:15:11 -0700196 * ---------------------------------------------
197 */
198func console_putc
Sathees Balya28cfffc2018-07-31 15:11:11 +0100199 stp x21, x30, [sp, #-16]!
200 stp x19, x20, [sp, #-16]!
201 mov w20, #ERROR_NO_VALID_CONSOLE /* W20 = current return value */
202 mov w19, w0 /* W19 = character to print */
203 adrp x21, console_list
204 ldr x21, [x21, :lo12:console_list] /* X21 = first console struct */
Julius Werner94f89072017-07-31 18:15:11 -0700205
206putc_loop:
Sathees Balya28cfffc2018-07-31 15:11:11 +0100207 cbz x21, putc_done
Julius Werner94f89072017-07-31 18:15:11 -0700208 adrp x1, console_state
209 ldrb w1, [x1, :lo12:console_state]
Sathees Balya28cfffc2018-07-31 15:11:11 +0100210 ldr w2, [x21, #CONSOLE_T_FLAGS]
Julius Werner94f89072017-07-31 18:15:11 -0700211 tst w1, w2
212 b.eq putc_continue
Sathees Balya28cfffc2018-07-31 15:11:11 +0100213 ldr x2, [x21, #CONSOLE_T_PUTC]
Julius Werner94f89072017-07-31 18:15:11 -0700214 cbz x2, putc_continue
Sathees Balya28cfffc2018-07-31 15:11:11 +0100215 mov w0, w19
216 mov x1, x21
Julius Werner94f89072017-07-31 18:15:11 -0700217 blr x2
Sathees Balya28cfffc2018-07-31 15:11:11 +0100218 cmp w20, #ERROR_NO_VALID_CONSOLE /* update W20 if it's NOVALID */
Julius Werner94f89072017-07-31 18:15:11 -0700219 ccmp w0, #0, #0x8, ne /* else update it if W0 < 0 */
Sathees Balya28cfffc2018-07-31 15:11:11 +0100220 csel w20, w0, w20, lt
Julius Werner94f89072017-07-31 18:15:11 -0700221putc_continue:
Sathees Balya28cfffc2018-07-31 15:11:11 +0100222 ldr x21, [x21] /* X21 = next struct */
Julius Werner94f89072017-07-31 18:15:11 -0700223 b putc_loop
224
225putc_done:
Sathees Balya28cfffc2018-07-31 15:11:11 +0100226 mov w0, w20
227 ldp x19, x20, [sp], #16
228 ldp x21, x30, [sp], #16
229 ret
Julius Werner94f89072017-07-31 18:15:11 -0700230endfunc console_putc
231
232 /* ---------------------------------------------
233 * int console_getc(void)
234 * Function to get a character from any console.
235 * Keeps looping through all consoles' getc()
236 * handlers until one of them returns a
237 * character, then stops iterating and returns
238 * that character to the caller. Will stop looping
239 * if all active consoles report real errors
240 * (other than just not having a char available).
241 * Out : x0 - read character, or < 0 on error
Sathees Balya28cfffc2018-07-31 15:11:11 +0100242 * Clobber list : x0, x1
Julius Werner94f89072017-07-31 18:15:11 -0700243 * ---------------------------------------------
244 */
245func console_getc
Sathees Balya28cfffc2018-07-31 15:11:11 +0100246 stp x30, xzr, [sp, #-16]!
247 stp x20, x21, [sp, #-16]!
Julius Werner94f89072017-07-31 18:15:11 -0700248getc_try_again:
Sathees Balya28cfffc2018-07-31 15:11:11 +0100249 mov w20, #ERROR_NO_VALID_CONSOLE /* W20 = current return value */
250 adrp x21, console_list
251 ldr x21, [x21, :lo12:console_list] /* X21 = first console struct */
252 cbnz x21, getc_loop
253 mov w0, w20 /* If no consoles registered */
254 ldp x20, x21, [sp], #16
255 ldp x30, xzr, [sp], #16
256 ret /* return immediately. */
Julius Werner94f89072017-07-31 18:15:11 -0700257
258getc_loop:
259 adrp x0, console_state
260 ldrb w0, [x0, :lo12:console_state]
Sathees Balya28cfffc2018-07-31 15:11:11 +0100261 ldr w1, [x21, #CONSOLE_T_FLAGS]
Julius Werner94f89072017-07-31 18:15:11 -0700262 tst w0, w1
263 b.eq getc_continue
Sathees Balya28cfffc2018-07-31 15:11:11 +0100264 ldr x1, [x21, #CONSOLE_T_GETC]
Julius Werner94f89072017-07-31 18:15:11 -0700265 cbz x1, getc_continue
Sathees Balya28cfffc2018-07-31 15:11:11 +0100266 mov x0, x21
Julius Werner94f89072017-07-31 18:15:11 -0700267 blr x1
268 cmp w0, #0 /* if X0 >= 0: return */
269 b.ge getc_found
Sathees Balya28cfffc2018-07-31 15:11:11 +0100270 cmp w20, #ERROR_NO_PENDING_CHAR /* may update W20 (NOCHAR has */
271 csel w20, w20, w0, eq /* precedence vs real errors) */
Julius Werner94f89072017-07-31 18:15:11 -0700272getc_continue:
Sathees Balya28cfffc2018-07-31 15:11:11 +0100273 ldr x21, [x21] /* X21 = next struct */
274 cbnz x21, getc_loop
275 cmp w20, #ERROR_NO_PENDING_CHAR /* Keep scanning if at least */
Julius Werner94f89072017-07-31 18:15:11 -0700276 b.eq getc_try_again /* one console returns NOCHAR */
Sathees Balya28cfffc2018-07-31 15:11:11 +0100277 mov w0, w20
Julius Werner94f89072017-07-31 18:15:11 -0700278
279getc_found:
Sathees Balya28cfffc2018-07-31 15:11:11 +0100280 ldp x20, x21, [sp], #16
281 ldp x30, xzr, [sp], #16
282 ret
Julius Werner94f89072017-07-31 18:15:11 -0700283endfunc console_getc
284
285 /* ---------------------------------------------
286 * int console_flush(void)
287 * Function to force a write of all buffered
288 * data that hasn't been output. Calls all
289 * console's flush() handlers in succession.
290 * Out: x0 - 0 on success, < 0 if at least one error
Sathees Balya28cfffc2018-07-31 15:11:11 +0100291 * Clobber list : x0, x1, x2
Julius Werner94f89072017-07-31 18:15:11 -0700292 * ---------------------------------------------
293 */
294func console_flush
Sathees Balya28cfffc2018-07-31 15:11:11 +0100295 stp x30, xzr, [sp, #-16]!
296 stp x20, x21, [sp, #-16]!
297 mov w20, #ERROR_NO_VALID_CONSOLE /* W20 = current return value */
298 adrp x21, console_list
299 ldr x21, [x21, :lo12:console_list] /* X21 = first console struct */
Julius Werner94f89072017-07-31 18:15:11 -0700300
301flush_loop:
Sathees Balya28cfffc2018-07-31 15:11:11 +0100302 cbz x21, flush_done
Julius Werner94f89072017-07-31 18:15:11 -0700303 adrp x1, console_state
304 ldrb w1, [x1, :lo12:console_state]
Sathees Balya28cfffc2018-07-31 15:11:11 +0100305 ldr w2, [x21, #CONSOLE_T_FLAGS]
Julius Werner94f89072017-07-31 18:15:11 -0700306 tst w1, w2
307 b.eq flush_continue
Sathees Balya28cfffc2018-07-31 15:11:11 +0100308 ldr x1, [x21, #CONSOLE_T_FLUSH]
Julius Werner94f89072017-07-31 18:15:11 -0700309 cbz x1, flush_continue
Sathees Balya28cfffc2018-07-31 15:11:11 +0100310 mov x0, x21
Julius Werner94f89072017-07-31 18:15:11 -0700311 blr x1
Sathees Balya28cfffc2018-07-31 15:11:11 +0100312 cmp w20, #ERROR_NO_VALID_CONSOLE /* update W20 if it's NOVALID */
Julius Werner94f89072017-07-31 18:15:11 -0700313 ccmp w0, #0, #0x8, ne /* else update it if W0 < 0 */
Sathees Balya28cfffc2018-07-31 15:11:11 +0100314 csel w20, w0, w20, lt
Julius Werner94f89072017-07-31 18:15:11 -0700315flush_continue:
Sathees Balya28cfffc2018-07-31 15:11:11 +0100316 ldr x21, [x21] /* X21 = next struct */
Julius Werner94f89072017-07-31 18:15:11 -0700317 b flush_loop
318
319flush_done:
Sathees Balya28cfffc2018-07-31 15:11:11 +0100320 mov w0, w20
321 ldp x20, x21, [sp], #16
322 ldp x30, xzr, [sp], #16
323 ret
Julius Werner94f89072017-07-31 18:15:11 -0700324endfunc console_flush