blob: 0464776b2d83db2464b774fff53566572ffcb2ef [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)
Antonio Nino Diaz4f31ad52018-04-30 20:14:07 +010042 * Clobber list: x0, x1, x14, x15
Julius Werner94f89072017-07-31 18:15:11 -070043 * -----------------------------------------------
44 */
45func console_register
46#if ENABLE_ASSERTIONS
Antonio Nino Diaz4f31ad52018-04-30 20:14:07 +010047 /* Assert that x0 isn't a NULL pointer */
Julius Werner94f89072017-07-31 18:15:11 -070048 cmp x0, #0
49 ASM_ASSERT(ne)
Antonio Nino Diaz4f31ad52018-04-30 20:14:07 +010050 /* Assert that the struct isn't in the stack */
Julius Werner94f89072017-07-31 18:15:11 -070051 adrp x1, __STACKS_START__
52 add x1, x1, :lo12:__STACKS_START__
53 cmp x0, x1
54 b.lo not_on_stack
55 adrp x1, __STACKS_END__
56 add x1, x1, :lo12:__STACKS_END__
57 cmp x0, x1
58 ASM_ASSERT(hs)
59not_on_stack:
Antonio Nino Diaz4f31ad52018-04-30 20:14:07 +010060 /* Assert that this struct isn't in the list */
61 mov x1, x0 /* Preserve x0 and x30 */
62 mov x15, x30
63 bl console_is_registered
64 cmp x0, #0
65 ASM_ASSERT(eq)
66 mov x30, x15
67 mov x0, x1
Julius Werner94f89072017-07-31 18:15:11 -070068#endif /* ENABLE_ASSERTIONS */
69 adrp x14, console_list
70 ldr x1, [x14, :lo12:console_list] /* X1 = first struct in list */
71 str x0, [x14, :lo12:console_list] /* list head = new console */
72 str x1, [x0, #CONSOLE_T_NEXT] /* new console next ptr = X1 */
73 mov x0, #1
74 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
83 * Clobber list: x0, x1, x14
84 * -----------------------------------------------
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 */
Julius Werner94f89072017-07-31 18:15:11 -070092 adrp x14, console_list
93 add x14, x14, :lo12:console_list /* X14 = ptr to first struct */
94 ldr x1, [x14] /* X1 = first struct */
95
96unregister_loop:
97 cbz x1, unregister_not_found
98 cmp x0, x1
99 b.eq unregister_found
100 ldr x14, [x14] /* X14 = next ptr of struct */
101 ldr x1, [x14] /* X1 = next struct */
102 b unregister_loop
103
104unregister_found:
105 ldr x1, [x1] /* X1 = next struct */
106 str x1, [x14] /* prev->next = cur->next */
107 ret
108
109unregister_not_found:
110 mov x0, #0 /* return NULL if not found */
111 ret
112endfunc console_unregister
113
114 /* -----------------------------------------------
Antonio Nino Diaz4f31ad52018-04-30 20:14:07 +0100115 * int console_is_registered(console_t *console)
116 * Function to detect if a specific console is
117 * registered or not.
118 * In: x0 - address of console_t struct to remove
119 * Out: x0 - 1 if it is registered, 0 if not.
120 * Clobber list: x0, x14
121 * -----------------------------------------------
122 */
123func console_is_registered
124#if ENABLE_ASSERTIONS
125 /* Assert that x0 isn't a NULL pointer */
126 cmp x0, #0
127 ASM_ASSERT(ne)
128#endif /* ENABLE_ASSERTIONS */
129 adrp x14, console_list
130 ldr x14, [x14, :lo12:console_list] /* X14 = first console struct */
131check_registered_loop:
132 cbz x14, console_not_registered /* Check if end of list */
133 cmp x0, x14 /* Check if the pointers are different */
134 b.eq console_registered
135 ldr x14, [x14, #CONSOLE_T_NEXT] /* Get pointer to next struct */
136 b check_registered_loop
137console_not_registered:
138 mov x0, #0
139 ret
140console_registered:
141 mov x0, #1
142 ret
143endfunc console_is_registered
144
145 /* -----------------------------------------------
Julius Werner94f89072017-07-31 18:15:11 -0700146 * void console_switch_state(unsigned int new_state)
147 * Function to switch the current console state.
148 * The console state determines which of the
149 * registered consoles are actually used at a time.
150 * In : w0 - global console state to move to
151 * Clobber list: x0, x1
152 * -----------------------------------------------
153 */
154func console_switch_state
155 adrp x1, console_state
156 strb w0, [x1, :lo12:console_state]
157 ret
158endfunc console_switch_state
159
160 /* -----------------------------------------------
161 * void console_set_scope(console_t *console,
162 * unsigned int scope)
163 * Function to update the states that a given console
164 * may be active in.
165 * In : x0 - pointer to console_t struct
166 * : w1 - new active state mask
167 * Clobber list: x0, x1, x2
168 * -----------------------------------------------
169 */
170func console_set_scope
171#if ENABLE_ASSERTIONS
172 tst w1, #~CONSOLE_FLAG_SCOPE_MASK
173 ASM_ASSERT(eq)
174#endif /* ENABLE_ASSERTIONS */
175 ldr w2, [x0, #CONSOLE_T_FLAGS]
176 and w2, w2, #~CONSOLE_FLAG_SCOPE_MASK
177 orr w2, w2, w1
178 str w2, [x0, #CONSOLE_T_FLAGS]
179 ret
180endfunc console_set_scope
181
182 /* ---------------------------------------------
183 * int console_putc(int c)
184 * Function to output a character. Calls all
185 * active console's putc() handlers in succession.
186 * In : x0 - character to be printed
187 * Out: x0 - printed character on success, or < 0
188 if at least one console had an error
189 * Clobber list : x0, x1, x2, x12, x13, x14, x15
190 * ---------------------------------------------
191 */
192func console_putc
193 mov x15, x30
194 mov w13, #ERROR_NO_VALID_CONSOLE /* W13 = current return value */
195 mov w12, w0 /* W12 = character to print */
196 adrp x14, console_list
197 ldr x14, [x14, :lo12:console_list] /* X14 = first console struct */
198
199putc_loop:
200 cbz x14, putc_done
201 adrp x1, console_state
202 ldrb w1, [x1, :lo12:console_state]
Daniel Boulby99e4a482018-05-16 16:04:35 +0100203 ldr w2, [x14, #CONSOLE_T_FLAGS]
Julius Werner94f89072017-07-31 18:15:11 -0700204 tst w1, w2
205 b.eq putc_continue
206 ldr x2, [x14, #CONSOLE_T_PUTC]
207 cbz x2, putc_continue
208 mov w0, w12
209 mov x1, x14
210 blr x2
211 cmp w13, #ERROR_NO_VALID_CONSOLE /* update W13 if it's NOVALID */
212 ccmp w0, #0, #0x8, ne /* else update it if W0 < 0 */
213 csel w13, w0, w13, lt
214putc_continue:
215 ldr x14, [x14] /* X14 = next struct */
216 b putc_loop
217
218putc_done:
219 mov w0, w13
220 ret x15
221endfunc console_putc
222
223 /* ---------------------------------------------
224 * int console_getc(void)
225 * Function to get a character from any console.
226 * Keeps looping through all consoles' getc()
227 * handlers until one of them returns a
228 * character, then stops iterating and returns
229 * that character to the caller. Will stop looping
230 * if all active consoles report real errors
231 * (other than just not having a char available).
232 * Out : x0 - read character, or < 0 on error
233 * Clobber list : x0, x1, x13, x14, x15
234 * ---------------------------------------------
235 */
236func console_getc
237 mov x15, x30
238getc_try_again:
239 mov w13, #ERROR_NO_VALID_CONSOLE /* W13 = current return value */
240 adrp x14, console_list
241 ldr x14, [x14, :lo12:console_list] /* X14 = first console struct */
242 cbnz x14, getc_loop
243 mov w0, w13 /* If no consoles registered */
244 ret x15 /* return immediately. */
245
246getc_loop:
247 adrp x0, console_state
248 ldrb w0, [x0, :lo12:console_state]
Daniel Boulby99e4a482018-05-16 16:04:35 +0100249 ldr w1, [x14, #CONSOLE_T_FLAGS]
Julius Werner94f89072017-07-31 18:15:11 -0700250 tst w0, w1
251 b.eq getc_continue
252 ldr x1, [x14, #CONSOLE_T_GETC]
253 cbz x1, getc_continue
254 mov x0, x14
255 blr x1
256 cmp w0, #0 /* if X0 >= 0: return */
257 b.ge getc_found
258 cmp w13, #ERROR_NO_PENDING_CHAR /* may update W13 (NOCHAR has */
259 csel w13, w13, w0, eq /* precedence vs real errors) */
260getc_continue:
261 ldr x14, [x14] /* X14 = next struct */
262 cbnz x14, getc_loop
263 cmp w13, #ERROR_NO_PENDING_CHAR /* Keep scanning if at least */
264 b.eq getc_try_again /* one console returns NOCHAR */
265 mov w0, w13
266
267getc_found:
268 ret x15
269endfunc console_getc
270
271 /* ---------------------------------------------
272 * int console_flush(void)
273 * Function to force a write of all buffered
274 * data that hasn't been output. Calls all
275 * console's flush() handlers in succession.
276 * Out: x0 - 0 on success, < 0 if at least one error
277 * Clobber list : x0, x1, x2, x3, x4, x5, x13, x14, x15
278 * ---------------------------------------------
279 */
280func console_flush
281 mov x15, x30
282 mov w13, #ERROR_NO_VALID_CONSOLE /* W13 = current return value */
283 adrp x14, console_list
284 ldr x14, [x14, :lo12:console_list] /* X14 = first console struct */
285
286flush_loop:
287 cbz x14, flush_done
288 adrp x1, console_state
289 ldrb w1, [x1, :lo12:console_state]
Daniel Boulby99e4a482018-05-16 16:04:35 +0100290 ldr w2, [x14, #CONSOLE_T_FLAGS]
Julius Werner94f89072017-07-31 18:15:11 -0700291 tst w1, w2
292 b.eq flush_continue
293 ldr x1, [x14, #CONSOLE_T_FLUSH]
294 cbz x1, flush_continue
295 mov x0, x14
296 blr x1
297 cmp w13, #ERROR_NO_VALID_CONSOLE /* update W13 if it's NOVALID */
298 ccmp w0, #0, #0x8, ne /* else update it if W0 < 0 */
299 csel w13, w0, w13, lt
300flush_continue:
301 ldr x14, [x14] /* X14 = next struct */
302 b flush_loop
303
304flush_done:
305 mov w0, w13
306 ret x15
307endfunc console_flush