From 9536bae6df5638772a1e8b1c8cf8e321f4ab5452 Mon Sep 17 00:00:00 2001 From: Julius Werner Date: Mon, 31 Jul 2017 18:15:11 -0700 Subject: [PATCH] Add new function-pointer-based console API This patch overhauls the console API to allow for multiple console instances of different drivers that are active at the same time. Instead of binding to well-known function names (like console_core_init), consoles now provide a register function (e.g. console_16550_register()) that will hook them into the list of active consoles. All console operations will be dispatched to all consoles currently in the list. The new API will be selected by the build-time option MULTI_CONSOLE_API, which defaults to ${ERROR_DEPRECATED} for now. The old console API code will be retained to stay backwards-compatible to older platforms, but should no longer be used for any newly added platforms and can hopefully be removed at some point in the future. The new console API is intended to be used for both normal (bootup) and crash use cases, freeing platforms of the need to set up the crash console separately. Consoles can be individually configured to be active active at boot (until first handoff to EL2), at runtime (after first handoff to EL2), and/or after a crash. Console drivers should set a sane default upon registration that can be overridden with the console_set_scope() call. Code to hook up the crash reporting mechanism to this framework will be added with a later patch. This patch only affects AArch64, but the new API could easily be ported to AArch32 as well if desired. Change-Id: I35c5aa2cb3f719cfddd15565eb13c7cde4162549 Signed-off-by: Julius Werner --- Makefile | 2 + drivers/console/aarch64/console.S | 106 +------- drivers/console/aarch64/deprecated_console.S | 110 ++++++++ drivers/console/aarch64/multi_console.S | 260 +++++++++++++++++++ drivers/console/aarch64/skeleton_console.S | 184 +++++++++---- include/common/aarch64/console_macros.S | 43 +++ include/drivers/console.h | 63 ++++- include/drivers/console_assertions.h | 30 +++ make_helpers/defaults.mk | 4 + plat/common/aarch64/plat_common.c | 8 +- 10 files changed, 646 insertions(+), 164 deletions(-) create mode 100644 drivers/console/aarch64/deprecated_console.S create mode 100644 drivers/console/aarch64/multi_console.S create mode 100644 include/common/aarch64/console_macros.S create mode 100644 include/drivers/console_assertions.h diff --git a/Makefile b/Makefile index c0fddcf6..3c3f5a40 100644 --- a/Makefile +++ b/Makefile @@ -474,6 +474,7 @@ $(eval $(call assert_boolean,GENERATE_COT)) $(eval $(call assert_boolean,GICV2_G0_FOR_EL3)) $(eval $(call assert_boolean,HW_ASSISTED_COHERENCY)) $(eval $(call assert_boolean,LOAD_IMAGE_V2)) +$(eval $(call assert_boolean,MULTI_CONSOLE_API)) $(eval $(call assert_boolean,NS_TIMER_SWITCH)) $(eval $(call assert_boolean,PL011_GENERIC_UART)) $(eval $(call assert_boolean,PROGRAMMABLE_RESET_ADDRESS)) @@ -515,6 +516,7 @@ $(eval $(call add_define,GICV2_G0_FOR_EL3)) $(eval $(call add_define,HW_ASSISTED_COHERENCY)) $(eval $(call add_define,LOAD_IMAGE_V2)) $(eval $(call add_define,LOG_LEVEL)) +$(eval $(call add_define,MULTI_CONSOLE_API)) $(eval $(call add_define,NS_TIMER_SWITCH)) $(eval $(call add_define,PL011_GENERIC_UART)) $(eval $(call add_define,PLAT_${PLAT})) diff --git a/drivers/console/aarch64/console.S b/drivers/console/aarch64/console.S index 7cc04ddd..f847ed59 100644 --- a/drivers/console/aarch64/console.S +++ b/drivers/console/aarch64/console.S @@ -1,105 +1,11 @@ /* - * Copyright (c) 2015-2017, ARM Limited and Contributors. All rights reserved. + * Copyright (c) 2017, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ -#include - .globl console_init - .globl console_uninit - .globl console_putc - .globl console_getc - .globl console_flush - - /* - * The console base is in the data section and not in .bss - * even though it is zero-init. In particular, this allows - * the console functions to start using this variable before - * the runtime memory is initialized for images which do not - * need to copy the .data section from ROM to RAM. - */ -.section .data.console_base ; .align 3 - console_base: .quad 0x0 - - /* ----------------------------------------------- - * int console_init(uintptr_t base_addr, - * unsigned int uart_clk, unsigned int baud_rate) - * Function to initialize the console without a - * C Runtime to print debug information. It saves - * the console base to the data section. - * In: x0 - console base address - * w1 - Uart clock in Hz - * w2 - Baud rate - * out: return 1 on success else 0 on error - * Clobber list : x1 - x4 - * ----------------------------------------------- - */ -func console_init - /* Check the input base address */ - cbz x0, init_fail - adrp x3, console_base - str x0, [x3, :lo12:console_base] - b console_core_init -init_fail: - ret -endfunc console_init - - /* ----------------------------------------------- - * void console_uninit(void) - * Function to finish the use of console driver. - * It sets the console_base as NULL so that any - * further invocation of `console_putc` or - * `console_getc` APIs would return error. - * ----------------------------------------------- - */ -func console_uninit - mov x0, #0 - adrp x3, console_base - str x0, [x3, :lo12:console_base] - ret -endfunc console_uninit - - /* --------------------------------------------- - * int console_putc(int c) - * Function to output a character over the - * console. It returns the character printed on - * success or -1 on error. - * In : x0 - character to be printed - * Out : return -1 on error else return character. - * Clobber list : x1, x2 - * --------------------------------------------- - */ -func console_putc - adrp x2, console_base - ldr x1, [x2, :lo12:console_base] - b console_core_putc -endfunc console_putc - - /* --------------------------------------------- - * int console_getc(void) - * Function to get a character from the console. - * It returns the character grabbed on success - * or -1 on error. - * Clobber list : x0, x1 - * --------------------------------------------- - */ -func console_getc - adrp x1, console_base - ldr x0, [x1, :lo12:console_base] - b console_core_getc -endfunc console_getc - - /* --------------------------------------------- - * int console_flush(void) - * Function to force a write of all buffered - * data that hasn't been output. It returns 0 - * upon successful completion, otherwise it - * returns -1. - * Clobber list : x0, x1 - * --------------------------------------------- - */ -func console_flush - adrp x1, console_base - ldr x0, [x1, :lo12:console_base] - b console_core_flush -endfunc console_flush +#if MULTI_CONSOLE_API +#include "multi_console.S" +#else +#include "deprecated_console.S" +#endif diff --git a/drivers/console/aarch64/deprecated_console.S b/drivers/console/aarch64/deprecated_console.S new file mode 100644 index 00000000..c83e2467 --- /dev/null +++ b/drivers/console/aarch64/deprecated_console.S @@ -0,0 +1,110 @@ +/* + * Copyright (c) 2015-2017, ARM Limited and Contributors. All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ +#include + +/* + * This is the common console core code for the deprecated single-console API. + * New platforms should set MULTI_CONSOLE_API=1 and not use this file. + */ + + .globl console_init + .globl console_uninit + .globl console_putc + .globl console_getc + .globl console_flush + + /* + * The console base is in the data section and not in .bss + * even though it is zero-init. In particular, this allows + * the console functions to start using this variable before + * the runtime memory is initialized for images which do not + * need to copy the .data section from ROM to RAM. + */ +.section .data.console_base ; .align 3 + console_base: .quad 0x0 + + /* ----------------------------------------------- + * int console_init(uintptr_t base_addr, + * unsigned int uart_clk, unsigned int baud_rate) + * Function to initialize the console without a + * C Runtime to print debug information. It saves + * the console base to the data section. + * In: x0 - console base address + * w1 - Uart clock in Hz + * w2 - Baud rate + * out: return 1 on success else 0 on error + * Clobber list : x1 - x4 + * ----------------------------------------------- + */ +func console_init + /* Check the input base address */ + cbz x0, init_fail + adrp x3, console_base + str x0, [x3, :lo12:console_base] + b console_core_init +init_fail: + ret +endfunc console_init + + /* ----------------------------------------------- + * void console_uninit(void) + * Function to finish the use of console driver. + * It sets the console_base as NULL so that any + * further invocation of `console_putc` or + * `console_getc` APIs would return error. + * ----------------------------------------------- + */ +func console_uninit + mov x0, #0 + adrp x3, console_base + str x0, [x3, :lo12:console_base] + ret +endfunc console_uninit + + /* --------------------------------------------- + * int console_putc(int c) + * Function to output a character over the + * console. It returns the character printed on + * success or -1 on error. + * In : x0 - character to be printed + * Out : return -1 on error else return character. + * Clobber list : x1, x2 + * --------------------------------------------- + */ +func console_putc + adrp x2, console_base + ldr x1, [x2, :lo12:console_base] + b console_core_putc +endfunc console_putc + + /* --------------------------------------------- + * int console_getc(void) + * Function to get a character from the console. + * It returns the character grabbed on success + * or -1 on error. + * Clobber list : x0, x1 + * --------------------------------------------- + */ +func console_getc + adrp x1, console_base + ldr x0, [x1, :lo12:console_base] + b console_core_getc +endfunc console_getc + + /* --------------------------------------------- + * int console_flush(void) + * Function to force a write of all buffered + * data that hasn't been output. It returns 0 + * upon successful completion, otherwise it + * returns -1. + * Clobber list : x0, x1 + * --------------------------------------------- + */ +func console_flush + adrp x1, console_base + ldr x0, [x1, :lo12:console_base] + b console_core_flush +endfunc console_flush diff --git a/drivers/console/aarch64/multi_console.S b/drivers/console/aarch64/multi_console.S new file mode 100644 index 00000000..15c3ba43 --- /dev/null +++ b/drivers/console/aarch64/multi_console.S @@ -0,0 +1,260 @@ +/* + * Copyright (c) 2015-2017, ARM Limited and Contributors. All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#include +#include +#include + + .globl console_register + .globl console_unregister + .globl console_set_scope + .globl console_switch_state + .globl console_putc + .globl console_getc + .globl console_flush + + /* + * The console list pointer is in the data section and not in + * .bss even though it is zero-init. In particular, this allows + * the console functions to start using this variable before + * the runtime memory is initialized for images which do not + * need to copy the .data section from ROM to RAM. + */ +.section .data.console_list ; .align 3 + console_list: .quad 0x0 +.section .data.console_state ; .align 0 + console_state: .byte CONSOLE_FLAG_BOOT + + /* ----------------------------------------------- + * int console_register(console_t *console) + * Function to insert a new console structure into + * the console list. Should usually be called by + * console__register implementations. The + * data structure passed will be taken over by the + * console framework and *MUST* be allocated in + * persistent memory (e.g. the data section). + * In : x0 - address of console_t structure + * Out: x0 - Always 1 (for easier tail calling) + * Clobber list: x0, x1, x14 + * ----------------------------------------------- + */ +func console_register +#if ENABLE_ASSERTIONS + cmp x0, #0 + ASM_ASSERT(ne) + adrp x1, __STACKS_START__ + add x1, x1, :lo12:__STACKS_START__ + cmp x0, x1 + b.lo not_on_stack + adrp x1, __STACKS_END__ + add x1, x1, :lo12:__STACKS_END__ + cmp x0, x1 + ASM_ASSERT(hs) +not_on_stack: +#endif /* ENABLE_ASSERTIONS */ + adrp x14, console_list + ldr x1, [x14, :lo12:console_list] /* X1 = first struct in list */ + str x0, [x14, :lo12:console_list] /* list head = new console */ + str x1, [x0, #CONSOLE_T_NEXT] /* new console next ptr = X1 */ + mov x0, #1 + ret +endfunc console_register + + /* ----------------------------------------------- + * int console_unregister(console_t *console) + * Function to find a specific console in the list + * of currently active consoles and remove it. + * In: x0 - address of console_t struct to remove + * Out: x0 - removed address, or NULL if not found + * Clobber list: x0, x1, x14 + * ----------------------------------------------- + */ +func console_unregister + adrp x14, console_list + add x14, x14, :lo12:console_list /* X14 = ptr to first struct */ + ldr x1, [x14] /* X1 = first struct */ + +unregister_loop: + cbz x1, unregister_not_found + cmp x0, x1 + b.eq unregister_found + ldr x14, [x14] /* X14 = next ptr of struct */ + ldr x1, [x14] /* X1 = next struct */ + b unregister_loop + +unregister_found: + ldr x1, [x1] /* X1 = next struct */ + str x1, [x14] /* prev->next = cur->next */ + ret + +unregister_not_found: + mov x0, #0 /* return NULL if not found */ + ret +endfunc console_unregister + + /* ----------------------------------------------- + * void console_switch_state(unsigned int new_state) + * Function to switch the current console state. + * The console state determines which of the + * registered consoles are actually used at a time. + * In : w0 - global console state to move to + * Clobber list: x0, x1 + * ----------------------------------------------- + */ +func console_switch_state + adrp x1, console_state + strb w0, [x1, :lo12:console_state] + ret +endfunc console_switch_state + + /* ----------------------------------------------- + * void console_set_scope(console_t *console, + * unsigned int scope) + * Function to update the states that a given console + * may be active in. + * In : x0 - pointer to console_t struct + * : w1 - new active state mask + * Clobber list: x0, x1, x2 + * ----------------------------------------------- + */ +func console_set_scope +#if ENABLE_ASSERTIONS + tst w1, #~CONSOLE_FLAG_SCOPE_MASK + ASM_ASSERT(eq) +#endif /* ENABLE_ASSERTIONS */ + ldr w2, [x0, #CONSOLE_T_FLAGS] + and w2, w2, #~CONSOLE_FLAG_SCOPE_MASK + orr w2, w2, w1 + str w2, [x0, #CONSOLE_T_FLAGS] + ret +endfunc console_set_scope + + /* --------------------------------------------- + * int console_putc(int c) + * Function to output a character. Calls all + * active console's putc() handlers in succession. + * In : x0 - character to be printed + * Out: x0 - printed character on success, or < 0 + if at least one console had an error + * Clobber list : x0, x1, x2, x12, x13, x14, x15 + * --------------------------------------------- + */ +func console_putc + mov x15, x30 + mov w13, #ERROR_NO_VALID_CONSOLE /* W13 = current return value */ + mov w12, w0 /* W12 = character to print */ + adrp x14, console_list + ldr x14, [x14, :lo12:console_list] /* X14 = first console struct */ + +putc_loop: + cbz x14, putc_done + adrp x1, console_state + ldrb w1, [x1, :lo12:console_state] + ldr x2, [x14, #CONSOLE_T_FLAGS] + tst w1, w2 + b.eq putc_continue + ldr x2, [x14, #CONSOLE_T_PUTC] + cbz x2, putc_continue + mov w0, w12 + mov x1, x14 + blr x2 + cmp w13, #ERROR_NO_VALID_CONSOLE /* update W13 if it's NOVALID */ + ccmp w0, #0, #0x8, ne /* else update it if W0 < 0 */ + csel w13, w0, w13, lt +putc_continue: + ldr x14, [x14] /* X14 = next struct */ + b putc_loop + +putc_done: + mov w0, w13 + ret x15 +endfunc console_putc + + /* --------------------------------------------- + * int console_getc(void) + * Function to get a character from any console. + * Keeps looping through all consoles' getc() + * handlers until one of them returns a + * character, then stops iterating and returns + * that character to the caller. Will stop looping + * if all active consoles report real errors + * (other than just not having a char available). + * Out : x0 - read character, or < 0 on error + * Clobber list : x0, x1, x13, x14, x15 + * --------------------------------------------- + */ +func console_getc + mov x15, x30 +getc_try_again: + mov w13, #ERROR_NO_VALID_CONSOLE /* W13 = current return value */ + adrp x14, console_list + ldr x14, [x14, :lo12:console_list] /* X14 = first console struct */ + cbnz x14, getc_loop + mov w0, w13 /* If no consoles registered */ + ret x15 /* return immediately. */ + +getc_loop: + adrp x0, console_state + ldrb w0, [x0, :lo12:console_state] + ldr x1, [x14, #CONSOLE_T_FLAGS] + tst w0, w1 + b.eq getc_continue + ldr x1, [x14, #CONSOLE_T_GETC] + cbz x1, getc_continue + mov x0, x14 + blr x1 + cmp w0, #0 /* if X0 >= 0: return */ + b.ge getc_found + cmp w13, #ERROR_NO_PENDING_CHAR /* may update W13 (NOCHAR has */ + csel w13, w13, w0, eq /* precedence vs real errors) */ +getc_continue: + ldr x14, [x14] /* X14 = next struct */ + cbnz x14, getc_loop + cmp w13, #ERROR_NO_PENDING_CHAR /* Keep scanning if at least */ + b.eq getc_try_again /* one console returns NOCHAR */ + mov w0, w13 + +getc_found: + ret x15 +endfunc console_getc + + /* --------------------------------------------- + * int console_flush(void) + * Function to force a write of all buffered + * data that hasn't been output. Calls all + * console's flush() handlers in succession. + * Out: x0 - 0 on success, < 0 if at least one error + * Clobber list : x0, x1, x2, x3, x4, x5, x13, x14, x15 + * --------------------------------------------- + */ +func console_flush + mov x15, x30 + mov w13, #ERROR_NO_VALID_CONSOLE /* W13 = current return value */ + adrp x14, console_list + ldr x14, [x14, :lo12:console_list] /* X14 = first console struct */ + +flush_loop: + cbz x14, flush_done + adrp x1, console_state + ldrb w1, [x1, :lo12:console_state] + ldr x2, [x14, #CONSOLE_T_FLAGS] + tst w1, w2 + b.eq flush_continue + ldr x1, [x14, #CONSOLE_T_FLUSH] + cbz x1, flush_continue + mov x0, x14 + blr x1 + cmp w13, #ERROR_NO_VALID_CONSOLE /* update W13 if it's NOVALID */ + ccmp w0, #0, #0x8, ne /* else update it if W0 < 0 */ + csel w13, w0, w13, lt +flush_continue: + ldr x14, [x14] /* X14 = next struct */ + b flush_loop + +flush_done: + mov w0, w13 + ret x15 +endfunc console_flush diff --git a/drivers/console/aarch64/skeleton_console.S b/drivers/console/aarch64/skeleton_console.S index 9db6157d..1b5d7393 100644 --- a/drivers/console/aarch64/skeleton_console.S +++ b/drivers/console/aarch64/skeleton_console.S @@ -4,99 +4,171 @@ * SPDX-License-Identifier: BSD-3-Clause */ #include +#include /* - * This file contains a skeleton console implementation that can - * be used as basis for a real console implementation by platforms - * that do not contain PL011 hardware. + * This file contains a skeleton console driver that can be used as + * basis for a real console driver. Console drivers in Trusted Firmware + * can be instantiated multiple times. Each instance is described by a + * separate console_t structure which must be registered with the common + * console framework via console_register(). Console drivers should + * define a console_xxx_register() function that initializes a new + * console_t structure passed in from the caller and registers it after + * initializing the console hardware. Drivers may define their own + * structures extending console_t to store private driver information. + * Console drivers *MUST* take care that the console callbacks they + * implement only change registers allowed in the clobber lists defined + * in this file. (Note that in addition to the explicit clobber lists, + * any function may always clobber the intra-procedure-call registers + * X16 and X17, but may never depend on them retaining their values + * across any function call.) + * Platforms using drivers based on this template need to enable + * MULTI_CONSOLE_API := 1 in their platform.mk. */ - .globl console_core_init - .globl console_core_putc - .globl console_core_getc - .globl console_core_flush + .globl console_xxx_register + .globl console_xxx_putc + .globl console_xxx_getc + .globl console_xxx_flush /* ----------------------------------------------- - * int console_core_init(uintptr_t base_addr, - * unsigned int uart_clk, unsigned int baud_rate) - * Function to initialize the console without a - * C Runtime to print debug information. This - * function will be accessed by console_init and - * crash reporting. - * In: x0 - console base address - * w1 - Uart clock in Hz - * w2 - Baud rate - * Out: return 1 on success else 0 on error - * Clobber list : x1, x2 + * int console_xxx_register(console_xxx_t *console, + * ...additional parameters as desired...) + * Function to initialize and register the console. + * The caller needs to pass an empty console_xxx_t + * structure in which *MUST* be allocated in + * persistent memory (e.g. a global or static local + * variable, *NOT* on the stack). + * In : x0 - pointer to empty console_t structure + * x1 through x7: additional parameters as desired + * Out: x0 - 1 on success, 0 on error + * Clobber list : x0 - x7 * ----------------------------------------------- */ -func console_core_init - /* Check the input base address */ - cbz x0, core_init_fail - /* Check baud rate and uart clock for sanity */ - cbz w1, core_init_fail - cbz w2, core_init_fail - /* Insert implementation here */ - mov w0, #1 - ret -core_init_fail: - mov w0, wzr +func console_xxx_register + /* + * Store parameters (e.g. hardware base address) in driver-specific + * console_xxx_t structure field if they will need to be retrieved + * by later console callback (e.g. putc). + * Example: + */ + str x1, [x0, #CONSOLE_T_XXX_BASE] + str x2, [x0, #CONSOLE_T_XXX_SOME_OTHER_VALUE] + + /* + * Initialize console hardware, using x1 - x7 parameters as needed. + * Keep console_t pointer in x0 for later. + */ + + /* Macro to finish up registration and return (needs valid x0 + x30). */ + finish_console_register xxx + + /* Jump here if hardware init fails or parameters are invalid. */ +register_fail: + mov w0, #0 ret -endfunc console_core_init +endfunc console_xxx_register /* -------------------------------------------------------- - * int console_core_putc(int c, uintptr_t base_addr) + * int console_xxx_putc(int c, console_xxx_t *console) * Function to output a character over the console. It * returns the character printed on success or -1 on error. * In : w0 - character to be printed - * x1 - console base address - * Out : return -1 on error else return character. - * Clobber list : x2 + * x1 - pointer to console_t struct + * Out: w0 - printed character on success, < 0 on error. + * Clobber list : x0, x1, x2 * -------------------------------------------------------- */ -func console_core_putc - /* Check the input parameter */ - cbz x1, putc_error - /* Insert implementation here */ +func console_xxx_putc + /* + * Retrieve values we need (e.g. hardware base address) from + * console_xxx_t structure pointed to by x1. + * Example: + */ + ldr x1, [x1, #CONSOLE_T_XXX_BASE] + + /* + * Write w0 to hardware. + */ + ret + + /* Jump here if output fails for any reason. */ putc_error: mov w0, #-1 ret -endfunc console_core_putc +endfunc console_xxx_putc /* --------------------------------------------- - * int console_core_getc(uintptr_t base_addr) + * int console_xxx_getc(console_xxx_t *console) * Function to get a character from the console. - * It returns the character grabbed on success - * or -1 on error. - * In : x0 - console base address + * Even though console_getc() is blocking, this + * callback has to be non-blocking and always + * return immediately to allow polling multiple + * drivers concurrently. + * Returns the character grabbed on success, + * ERROR_NO_PENDING_CHAR if no character was + * available at this time, or any value + * between -2 and -127 if there was an error. + * In : x0 - pointer to console_t struct + * Out: w0 - character on success, + * ERROR_NO_PENDING_CHAR if no char, + * < -1 on error * Clobber list : x0, x1 * --------------------------------------------- */ -func console_core_getc - cbz x0, getc_error - /* Insert implementation here */ +func console_xxx_getc + /* + * Retrieve values we need (e.g. hardware base address) from + * console_xxx_t structure pointed to by x0. + * Example: + */ + ldr x1, [x0, #CONSOLE_T_XXX_BASE] + + /* + * Try to read character into w0 from hardware. + */ + ret + + /* Jump here if there is no character available at this time. */ +getc_no_char: + mov w0, #ERROR_NO_PENDING_CHAR + ret + + /* Jump here if there was any hardware error. */ getc_error: - mov w0, #-1 + mov w0, #-2 /* may pick error codes between -2 and -127 */ ret -endfunc console_core_getc +endfunc console_xxx_getc /* --------------------------------------------- - * int console_core_flush(uintptr_t base_addr) + * int console_xxx_flush(console_xxx_t *console) * Function to force a write of all buffered * data that hasn't been output. - * In : x0 - console base address - * Out : return -1 on error else return 0. - * Clobber list : x0, x1 + * In : x0 - pointer to console_xxx_t struct + * Out: w0 - 0 on success, < 0 on error + * Clobber list : x0, x1, x2, x3, x4, x5 * --------------------------------------------- */ -func console_core_flush - cbz x0, flush_error - /* Insert implementation here */ +func console_xxx_flush + /* + * Retrieve values we need (e.g. hardware base address) from + * console_xxx_t structure pointed to by x0. + * Example: + */ + ldr x1, [x0, #CONSOLE_T_XXX_BASE] + + /* + * Flush all remaining output from hardware FIFOs. Do not return until + * all data has been flushed or there was an unrecoverable error. + */ + mov w0, #0 ret + + /* Jump here if an unrecoverable error has been encountered. */ flush_error: mov w0, #-1 ret -endfunc console_core_flush +endfunc console_xxx_flush diff --git a/include/common/aarch64/console_macros.S b/include/common/aarch64/console_macros.S new file mode 100644 index 00000000..0ebea2c1 --- /dev/null +++ b/include/common/aarch64/console_macros.S @@ -0,0 +1,43 @@ +/* + * Copyright (c) 2017, ARM Limited and Contributors. All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ +#ifndef __CONSOLE_MACROS_S__ +#define __CONSOLE_MACROS_S__ + +#include + +/* + * This macro encapsulates the common setup that has to be done at the end of + * a console driver's register function. It will register all of the driver's + * callbacks in the console_t structure and initialize the flags field (by + * default consoles are enabled for the "boot" and "crash" states, this can be + * changed after registration with the console_set_scope() function). It ends + * with a tail call that will include return to the caller. + * REQUIRES console_t pointer in x0 and a valid return address in x30. + */ + .macro finish_console_register _driver + /* + * Add these weak definitions so we will automatically write a 0 if the + * function doesn't exist. I'd rather use .ifdef but that only works if + * the function was defined (not just declared .global) above this point + * in the file, which we can't guarantee. + */ + .weak console_\_driver\()_putc + .weak console_\_driver\()_getc + .weak console_\_driver\()_flush + + /* Don't use adrp on weak funcs! See GNU ld bugzilla issue 22589. */ + ldr x1, =console_\_driver\()_putc + str x1, [x0, #CONSOLE_T_PUTC] + ldr x1, =console_\_driver\()_getc + str x1, [x0, #CONSOLE_T_GETC] + ldr x1, =console_\_driver\()_flush + str x1, [x0, #CONSOLE_T_FLUSH] + mov x1, #(CONSOLE_FLAG_BOOT | CONSOLE_FLAG_CRASH) + str x1, [x0, #CONSOLE_T_FLAGS] + b console_register + .endm + +#endif /* __CONSOLE_MACROS_S__ */ diff --git a/include/drivers/console.h b/include/drivers/console.h index da5cb8f7..0629f571 100644 --- a/include/drivers/console.h +++ b/include/drivers/console.h @@ -7,14 +7,69 @@ #ifndef __CONSOLE_H__ #define __CONSOLE_H__ -#include +#include -int console_init(uintptr_t base_addr, - unsigned int uart_clk, unsigned int baud_rate); -void console_uninit(void); +#define CONSOLE_T_NEXT (U(0) * REGSZ) +#define CONSOLE_T_FLAGS (U(1) * REGSZ) +#define CONSOLE_T_PUTC (U(2) * REGSZ) +#define CONSOLE_T_GETC (U(3) * REGSZ) +#define CONSOLE_T_FLUSH (U(4) * REGSZ) +#define CONSOLE_T_DRVDATA (U(5) * REGSZ) + +#define CONSOLE_FLAG_BOOT BIT(0) +#define CONSOLE_FLAG_RUNTIME BIT(1) +#define CONSOLE_FLAG_CRASH BIT(2) +/* Bits 3 to 7 reserved for additional scopes in future expansion. */ +#define CONSOLE_FLAG_SCOPE_MASK ((U(1) << 8) - 1) +/* Bits 8 to 31 reserved for non-scope use in future expansion. */ + +/* Returned by getc callbacks when receive FIFO is empty. */ +#define ERROR_NO_PENDING_CHAR (-1) +/* Returned by console_xxx() if no registered console implements xxx. */ +#define ERROR_NO_VALID_CONSOLE (-128) + +#ifndef __ASSEMBLY__ + +#include + +typedef struct console { + struct console *next; + u_register_t flags; + int (*putc)(int character, struct console *console); + int (*getc)(struct console *console); + int (*flush)(struct console *console); + /* Additional private driver data may follow here. */ +} console_t; +#include /* offset macro assertions for console_t */ + +/* + * NOTE: There is no publicly accessible console_register() function. Consoles + * are registered by directly calling the register function of a specific + * implementation, e.g. console_16550_register() from . Consoles + * registered that way can be unregistered/reconfigured with below functions. + */ +/* Remove a single console_t instance from the console list. */ +int console_unregister(console_t *console); +/* Set scope mask of a console that determines in what states it is active. */ +void console_set_scope(console_t *console, unsigned int scope); + +/* Switch to a new global console state (CONSOLE_FLAG_BOOT/RUNTIME/CRASH). */ +void console_switch_state(unsigned int new_state); +/* Output a character on all consoles registered for the current state. */ int console_putc(int c); +/* Read a character (blocking) from any console registered for current state. */ int console_getc(void); +/* Flush all consoles registered for the current state. */ int console_flush(void); +#if !MULTI_CONSOLE_API +/* DEPRECATED on AArch64 -- use console__register() instead! */ +int console_init(uintptr_t base_addr, + unsigned int uart_clk, unsigned int baud_rate) __deprecated; +void console_uninit(void) __deprecated; +#endif + +#endif /* __ASSEMBLY__ */ + #endif /* __CONSOLE_H__ */ diff --git a/include/drivers/console_assertions.h b/include/drivers/console_assertions.h new file mode 100644 index 00000000..cedce867 --- /dev/null +++ b/include/drivers/console_assertions.h @@ -0,0 +1,30 @@ +/* + * Copyright (c) 2017, ARM Limited and Contributors. All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#ifndef __CONSOLE_ASSERTIONS_H__ +#define __CONSOLE_ASSERTIONS_H__ + +#include + +/* + * This file contains some separate assertions about console_t, moved here to + * keep them out of the way. Should only be included from . + */ +CASSERT(CONSOLE_T_NEXT == __builtin_offsetof(console_t, next), + assert_console_t_next_offset_mismatch); +CASSERT(CONSOLE_T_FLAGS == __builtin_offsetof(console_t, flags), + assert_console_t_flags_offset_mismatch); +CASSERT(CONSOLE_T_PUTC == __builtin_offsetof(console_t, putc), + assert_console_t_putc_offset_mismatch); +CASSERT(CONSOLE_T_GETC == __builtin_offsetof(console_t, getc), + assert_console_t_getc_offset_mismatch); +CASSERT(CONSOLE_T_FLUSH == __builtin_offsetof(console_t, flush), + assert_console_t_flush_offset_mismatch); +CASSERT(CONSOLE_T_DRVDATA == sizeof(console_t), + assert_console_t_drvdata_offset_mismatch); + +#endif /* __CONSOLE_ASSERTIONS_H__ */ + diff --git a/make_helpers/defaults.mk b/make_helpers/defaults.mk index fa0d17de..2eb922f8 100644 --- a/make_helpers/defaults.mk +++ b/make_helpers/defaults.mk @@ -91,6 +91,10 @@ KEY_ALG := rsa # Flag to enable new version of image loading LOAD_IMAGE_V2 := 0 +# Use the new console API that allows registering more than one console instance +# at once. Use = instead of := to dynamically default to ERROR_DEPRECATED. +MULTI_CONSOLE_API = $(ERROR_DEPRECATED) + # NS timer register save and restore NS_TIMER_SWITCH := 0 diff --git a/plat/common/aarch64/plat_common.c b/plat/common/aarch64/plat_common.c index a87e7c67..cfc0c4f4 100644 --- a/plat/common/aarch64/plat_common.c +++ b/plat/common/aarch64/plat_common.c @@ -39,11 +39,11 @@ void bl32_plat_enable_mmu(uint32_t flags) void bl31_plat_runtime_setup(void) { - /* - * Finish the use of console driver in BL31 so that any runtime logs - * from BL31 will be suppressed. - */ +#if MULTI_CONSOLE_API + console_switch_state(CONSOLE_FLAG_RUNTIME); +#else console_uninit(); +#endif } #if !ENABLE_PLAT_COMPAT -- 2.30.2