From 155a10068ac6feefcc783b7b023fc90390e5cc44 Mon Sep 17 00:00:00 2001 From: Julius Werner Date: Tue, 12 Dec 2017 14:23:26 -0800 Subject: [PATCH 01/11] utils_def: Add REGSZ and make BIT() assembly-compatible In assembly code it can be useful to have a constant for the width of a register in the current architecture, so this patch adds one to and replaces the existing custom one in crash_reporting.S with that. It also fixes up the BIT() macro in the same file so that it can be safely used in assembly code. Change-Id: I10513a311f3379e767396e6ddfbae8d2d8201464 Signed-off-by: Julius Werner --- bl31/aarch64/crash_reporting.S | 32 ++++++++++++++++---------------- include/lib/utils_def.h | 9 ++++++++- 2 files changed, 24 insertions(+), 17 deletions(-) diff --git a/bl31/aarch64/crash_reporting.S b/bl31/aarch64/crash_reporting.S index cf32b31d7..0986a0a19 100644 --- a/bl31/aarch64/crash_reporting.S +++ b/bl31/aarch64/crash_reporting.S @@ -9,13 +9,13 @@ #include #include #include +#include .globl report_unhandled_exception .globl report_unhandled_interrupt .globl el3_panic #if CRASH_REPORTING -#define REG_SIZE 0x8 /* ------------------------------------------------------ * The below section deals with dumping the system state @@ -92,7 +92,7 @@ test_size_list: mov x6, x4 adr x4, print_spacer bl asm_print_str - ldr x4, [x7], #REG_SIZE + ldr x4, [x7], #REGSZ bl asm_print_hex bl print_newline b test_size_list @@ -114,9 +114,9 @@ func str_in_crash_buf_print /* restore the crash buf address in x0 */ mrs x0, tpidr_el3 stp x8, x9, [x0] - stp x10, x11, [x0, #REG_SIZE * 2] - stp x12, x13, [x0, #REG_SIZE * 4] - stp x14, x15, [x0, #REG_SIZE * 6] + stp x10, x11, [x0, #REGSZ * 2] + stp x12, x13, [x0, #REGSZ * 4] + stp x14, x15, [x0, #REGSZ * 6] b size_controlled_print endfunc str_in_crash_buf_print @@ -136,7 +136,7 @@ endfunc str_in_crash_buf_print add x0, x0, #CPU_DATA_CRASH_BUF_OFFSET /* Store crash buffer address in tpidr_el3 */ msr tpidr_el3, x0 - str x1, [x0, #REG_SIZE] + str x1, [x0, #REGSZ] mov x1, sp str x1, [x0] .endm @@ -214,9 +214,9 @@ func do_crash_reporting /* Retrieve the crash buf from tpidr_el3 */ mrs x0, tpidr_el3 /* Store x2 - x6, x30 in the crash buffer */ - stp x2, x3, [x0, #REG_SIZE * 2] - stp x4, x5, [x0, #REG_SIZE * 4] - stp x6, x30, [x0, #REG_SIZE * 6] + stp x2, x3, [x0, #REGSZ * 2] + stp x4, x5, [x0, #REGSZ * 4] + stp x6, x30, [x0, #REGSZ * 6] /* Initialize the crash console */ bl plat_crash_console_init /* Verify the console is initialized */ @@ -227,13 +227,13 @@ func do_crash_reporting /* load the crash buf address */ mrs x0, tpidr_el3 /* report x30 first from the crash buf */ - ldr x4, [x0, #REG_SIZE * 7] + ldr x4, [x0, #REGSZ * 7] bl asm_print_hex bl print_newline /* Load the crash buf address */ mrs x0, tpidr_el3 /* Now mov x7 into crash buf */ - str x7, [x0, #REG_SIZE * 7] + str x7, [x0, #REGSZ * 7] /* Report x0 - x29 values stored in crash buf*/ /* Store the ascii list pointer in x6 */ @@ -246,15 +246,15 @@ func do_crash_reporting mrs x0, tpidr_el3 /* Store the rest of gp regs and print */ stp x16, x17, [x0] - stp x18, x19, [x0, #REG_SIZE * 2] - stp x20, x21, [x0, #REG_SIZE * 4] - stp x22, x23, [x0, #REG_SIZE * 6] + stp x18, x19, [x0, #REGSZ * 2] + stp x20, x21, [x0, #REGSZ * 4] + stp x22, x23, [x0, #REGSZ * 6] bl size_controlled_print /* Load the crash buf address */ mrs x0, tpidr_el3 stp x24, x25, [x0] - stp x26, x27, [x0, #REG_SIZE * 2] - stp x28, x29, [x0, #REG_SIZE * 4] + stp x26, x27, [x0, #REGSZ * 2] + stp x28, x29, [x0, #REGSZ * 4] bl size_controlled_print /* Print the el3 sys registers */ diff --git a/include/lib/utils_def.h b/include/lib/utils_def.h index 185a1c129..bda3b0735 100644 --- a/include/lib/utils_def.h +++ b/include/lib/utils_def.h @@ -16,7 +16,7 @@ #define SIZE_FROM_LOG2_WORDS(n) (4 << (n)) -#define BIT(nr) (1ULL << (nr)) +#define BIT(nr) (ULL(1) << (nr)) /* * This variant of div_round_up can be used in macro definition but should not @@ -84,6 +84,13 @@ # define ULL(_x) (_x##ull) #endif +/* Register size of the current architecture. */ +#ifdef AARCH32 +#define REGSZ U(4) +#else +#define REGSZ U(8) +#endif + /* * Test for the current architecture version to be at least the version * expected. From a33e763c40b532859a1793025075b06adc553c4c Mon Sep 17 00:00:00 2001 From: Julius Werner Date: Mon, 19 Jun 2017 17:05:30 -0700 Subject: [PATCH 02/11] rockchip: Implement a panic handler that will reboot the system The current Rockchip platform code retains the "common" default panic handler which simply hangs the system (until the watchdog kicks in, if enabled). This is usually not a great user experience. This patch implements a Rockchip-specific panic handler that calls the platform's reboot implementation to reset the system. Change-Id: I4cbe09c48f1b3f86ebdfc0108c186565f9ffc119 Signed-off-by: Julius Werner --- plat/rockchip/common/aarch64/plat_helpers.S | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/plat/rockchip/common/aarch64/plat_helpers.S b/plat/rockchip/common/aarch64/plat_helpers.S index abfb5a795..24cb8e45a 100644 --- a/plat/rockchip/common/aarch64/plat_helpers.S +++ b/plat/rockchip/common/aarch64/plat_helpers.S @@ -23,6 +23,7 @@ .globl plat_crash_console_putc .globl plat_my_core_pos .globl plat_reset_handler + .globl plat_panic_handler /* * void plat_reset_handler(void); @@ -107,6 +108,19 @@ func plat_crash_console_putc b console_core_putc endfunc plat_crash_console_putc + /* -------------------------------------------------------------------- + * void plat_panic_handler(void) + * Call system reset function on panic. Set up an emergency stack so we + * can run C functions (it only needs to last for a few calls until we + * reboot anyway). + * -------------------------------------------------------------------- + */ +func plat_panic_handler + msr spsel, #0 + bl plat_set_my_stack + b rockchip_soc_soft_reset +endfunc plat_panic_handler + /* -------------------------------------------------------------------- * void platform_cpu_warmboot (void); * cpus online or resume enterpoint From 9536bae6df5638772a1e8b1c8cf8e321f4ab5452 Mon Sep 17 00:00:00 2001 From: Julius Werner Date: Mon, 31 Jul 2017 18:15:11 -0700 Subject: [PATCH 03/11] 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 c0fddcf64..3c3f5a40c 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 7cc04ddd7..f847ed597 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 000000000..c83e2467b --- /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 000000000..15c3ba43d --- /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 9db6157de..1b5d7393c 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 +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 -core_init_fail: - mov w0, wzr - 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 000000000..0ebea2c1b --- /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 da5cb8f7b..0629f5717 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 000000000..cedce8679 --- /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 fa0d17dec..2eb922f89 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 a87e7c673..cfc0c4f41 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 From 17cd67d2af885913427be5c0d8af47647d72896e Mon Sep 17 00:00:00 2001 From: Julius Werner Date: Mon, 18 Sep 2017 16:49:48 -0700 Subject: [PATCH 04/11] Add default crash console code to hook up to new console API This patch expands the weak stubs for the plat_crash_console_xxx functions in common platform code to use the new console API for crash output. This should make crash console output "just work" for most cases without the need for the platform to explicitly set up a crash console. For cases where the normal console framework doesn't work (e.g. very early crashes, before the platform can register any consoles), platforms are still able to override the functions just like before. This feature requires the MULTI_CONSOLE_API compile-time flag to work. For builds which don't have it set, this patch has no practical effect. Change-Id: I80dd161cb43f9db59a0bad2dae33c6560cfac584 Signed-off-by: Julius Werner --- docs/porting-guide.rst | 65 ++++++++++++++++++------ plat/common/aarch64/platform_helpers.S | 70 +++++++++++++++++++++----- 2 files changed, 108 insertions(+), 27 deletions(-) diff --git a/docs/porting-guide.rst b/docs/porting-guide.rst index f020ec97d..10a6da7e4 100644 --- a/docs/porting-guide.rst +++ b/docs/porting-guide.rst @@ -1846,12 +1846,8 @@ Function : bl31\_plat\_runtime\_setup() [optional] The purpose of this function is allow the platform to perform any BL31 runtime setup just prior to BL31 exit during cold boot. The default weak -implementation of this function will invoke ``console_uninit()`` which will -suppress any BL31 runtime logs. - -In ARM Standard platforms, this function will initialize the BL31 runtime -console which will cause all further BL31 logs to be output to the -runtime console. +implementation of this function will invoke ``console_switch_state()`` to switch +console output to consoles marked for use in the ``runtime`` state. Function : bl31\_get\_next\_image\_info() [mandatory] ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ @@ -2619,14 +2615,20 @@ as Group 0 secure interrupt, Group 1 secure interrupt or Group 1 NS interrupt. Crash Reporting mechanism (in BL31) ----------------------------------- -BL31 implements a crash reporting mechanism which prints the various registers -of the CPU to enable quick crash analysis and debugging. It requires that a -console is designated as the crash console by the platform which will be used to -print the register dump. +NOTE: This section assumes that your platform is enabling the MULTI_CONSOLE_API +flag in its platform.mk. Not using this flag is deprecated for new platforms. -The following functions must be implemented by the platform if it wants crash -reporting mechanism in BL31. The functions are implemented in assembly so that -they can be invoked without a C Runtime stack. +BL31 implements a crash reporting mechanism which prints the various registers +of the CPU to enable quick crash analysis and debugging. By default, the +definitions in ``plat/common/aarch64/platform\_helpers.S`` will cause the crash +output to be routed over the normal console infrastructure and get printed on +consoles configured to output in crash state. ``console_set_scope()`` can be +used to control whether a console is used for crash output. + +In some cases (such as debugging very early crashes that happen before the +normal boot console can be set up), platforms may want to control crash output +more explicitly. For these, the following functions can be overridden by +platform code. They are executed outside of a C environment and without a stack. Function : plat\_crash\_console\_init ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ @@ -2637,9 +2639,30 @@ Function : plat\_crash\_console\_init Return : int This API is used by the crash reporting mechanism to initialize the crash -console. It must only use the general purpose registers x0 to x4 to do the +console. It must only use the general purpose registers x0 through x7 to do the initialization and returns 1 on success. +If you are trying to debug crashes before the console driver would normally get +registered, you can use this to register a driver from assembly with hardcoded +parameters. For example, you could register the 16550 driver like this: + +:: + + .section .data.crash_console /* Reserve space for console structure */ + crash_console: + .zero 6 * 8 /* console_16550_t has 6 8-byte words */ + func plat_crash_console_init + ldr x0, =YOUR_16550_BASE_ADDR + ldr x1, =YOUR_16550_SRCCLK_IN_HZ + ldr x2, =YOUR_16550_TARGET_BAUD_RATE + adrp x3, crash_console + add x3, x3, :lo12:crash_console + b console_16550_register /* tail call, returns 1 on success */ + endfunc plat_crash_console_init + +If you're trying to debug crashes in BL1, you can call the console_xxx_core_init +function exported by some console drivers from here. + Function : plat\_crash\_console\_putc ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ @@ -2653,6 +2676,12 @@ designated crash console. It must only use general purpose registers x1 and x2 to do its work. The parameter and the return value are in general purpose register x0. +If you have registered a normal console driver in ``plat_crash_console_init``, +you can keep the default implementation here (which calls ``console_putc()``). + +If you're trying to debug crashes in BL1, you can call the console_xxx_core_putc +function exported by some console drivers from here. + Function : plat\_crash\_console\_flush ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ @@ -2663,9 +2692,15 @@ Function : plat\_crash\_console\_flush This API is used by the crash reporting mechanism to force write of all buffered data on the designated crash console. It should only use general purpose -registers x0 and x1 to do its work. The return value is 0 on successful +registers x0 through x5 to do its work. The return value is 0 on successful completion; otherwise the return value is -1. +If you have registered a normal console driver in ``plat_crash_console_init``, +you can keep the default implementation here (which calls ``console_flush()``). + +If you're trying to debug crashes in BL1, you can call the console_xx_core_flush +function exported by some console drivers from here. + Build flags ----------- diff --git a/plat/common/aarch64/platform_helpers.S b/plat/common/aarch64/platform_helpers.S index 797a93639..852675277 100644 --- a/plat/common/aarch64/platform_helpers.S +++ b/plat/common/aarch64/platform_helpers.S @@ -6,6 +6,7 @@ #include #include +#include #include .weak plat_report_exception @@ -56,9 +57,63 @@ func plat_report_exception ret endfunc plat_report_exception +#if MULTI_CONSOLE_API /* ----------------------------------------------------- - * Placeholder function which should be redefined by - * each platform. + * int plat_crash_console_init(void) + * Use normal console by default. Switch it to crash + * mode so serial consoles become active again. + * NOTE: This default implementation will only work for + * crashes that occur after a normal console (marked + * valid for the crash state) has been registered with + * the console framework. To debug crashes that occur + * earlier, the platform has to override these functions + * with an implementation that initializes a console + * driver with hardcoded parameters. See + * docs/porting-guide.rst for more information. + * ----------------------------------------------------- + */ +func plat_crash_console_init +#if defined(IMAGE_BL1) + /* + * BL1 code can possibly crash so early that the data segment is not yet + * accessible. Don't risk undefined behavior by trying to run the normal + * console framework. Platforms that want to debug BL1 will need to + * override this with custom functions that can run from registers only. + */ + mov x0, #0 + ret +#else /* IMAGE_BL1 */ + mov x3, x30 + mov x0, #CONSOLE_FLAG_CRASH + bl console_switch_state + mov x0, #1 + ret x3 +#endif +endfunc plat_crash_console_init + + /* ----------------------------------------------------- + * void plat_crash_console_putc(int character) + * Output through the normal console by default. + * ----------------------------------------------------- + */ +func plat_crash_console_putc + b console_putc +endfunc plat_crash_console_putc + + /* ----------------------------------------------------- + * void plat_crash_console_flush(void) + * Flush normal console by default. + * ----------------------------------------------------- + */ +func plat_crash_console_flush + b console_flush +endfunc plat_crash_console_flush + +#else /* MULTI_CONSOLE_API */ + + /* ----------------------------------------------------- + * In the old API these are all no-op stubs that need to + * be overridden by the platform to be useful. * ----------------------------------------------------- */ func plat_crash_console_init @@ -66,23 +121,14 @@ func plat_crash_console_init ret endfunc plat_crash_console_init - /* ----------------------------------------------------- - * Placeholder function which should be redefined by - * each platform. - * ----------------------------------------------------- - */ func plat_crash_console_putc ret endfunc plat_crash_console_putc - /* ----------------------------------------------------- - * Placeholder function which should be redefined by - * each platform. - * ----------------------------------------------------- - */ func plat_crash_console_flush ret endfunc plat_crash_console_flush +#endif /* ----------------------------------------------------- * Placeholder function which should be redefined by From 36c42ca111ea44e10d3589e93fa18a2b8162b6a3 Mon Sep 17 00:00:00 2001 From: Julius Werner Date: Mon, 18 Sep 2017 16:57:51 -0700 Subject: [PATCH 05/11] drivers: ti: uart: Update 16550 UART driver to support MULTI_CONSOLE_API This patch updates the TI 16550 console driver to support the new console API. The driver will continue to support the old API as well by checking the MULTI_CONSOLE_API compile-time flag. Change-Id: I60a44b7ba3c35c74561824c04b8dbe3e3039324c Signed-off-by: Julius Werner --- drivers/ti/uart/aarch64/16550_console.S | 149 +++++++++++++++++++----- include/drivers/ti/uart/uart_16550.h | 24 ++++ 2 files changed, 147 insertions(+), 26 deletions(-) diff --git a/drivers/ti/uart/aarch64/16550_console.S b/drivers/ti/uart/aarch64/16550_console.S index f9ccd5773..b02209dfb 100644 --- a/drivers/ti/uart/aarch64/16550_console.S +++ b/drivers/ti/uart/aarch64/16550_console.S @@ -6,15 +6,24 @@ #include #include +#include +#include #include - .globl console_core_init - .globl console_core_putc - .globl console_core_getc - .globl console_core_flush + /* + * "core" functions are low-level implementations that don't require + * writable memory and are thus safe to call in BL1 crash context. + */ + .globl console_16550_core_init + .globl console_16550_core_putc + .globl console_16550_core_getc + + .globl console_16550_putc + .globl console_16550_getc + /* ----------------------------------------------- - * int console_core_init(unsigned long base_addr, + * int console_16550_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 @@ -23,11 +32,11 @@ * In: x0 - console base address * w1 - Uart clock in Hz * w2 - Baud rate - * Out: return 1 on success + * Out: return 1 on success, 0 on error * Clobber list : x1, x2, x3 * ----------------------------------------------- */ -func console_core_init +func console_16550_core_init /* Check the input base address */ cbz x0, init_fail /* Check baud rate and uart clock for sanity */ @@ -63,12 +72,57 @@ func console_core_init mov w3, #3 str w3, [x0, #UARTMCR] mov w0, #1 -init_fail: ret -endfunc console_core_init +init_fail: + mov w0, #0 + ret +endfunc console_16550_core_init + +#if MULTI_CONSOLE_API + .globl console_16550_register + + /* ----------------------------------------------- + * int console_16550_register(console_16550_t *console, + uintptr_t base, uint32_t clk, uint32_t baud) + * Function to initialize and register a new 16550 + * console. Storage passed in for the console struct + * *must* be persistent (i.e. not from the stack). + * In: x0 - UART register base address + * w1 - UART clock in Hz + * w2 - Baud rate + * x3 - pointer to empty console_16550_t struct + * Out: return 1 on success, 0 on error + * Clobber list : x0, x1, x2, x6, x7, x14 + * ----------------------------------------------- + */ +func console_16550_register + mov x7, x30 + mov x6, x3 + cbz x6, register_fail + str x0, [x6, #CONSOLE_T_16550_BASE] + + bl console_16550_core_init + cbz x0, register_fail + + mov x0, x6 + mov x30, x7 + finish_console_register 16550 + +register_fail: + ret x7 +endfunc console_16550_register +#else + .globl console_core_init + .globl console_core_putc + .globl console_core_getc + .globl console_core_flush + .equ console_core_init,console_16550_core_init + .equ console_core_putc,console_16550_core_putc + .equ console_core_getc,console_16550_core_getc +#endif /* -------------------------------------------------------- - * int console_core_putc(int c, unsigned int base_addr) + * int console_16550_core_putc(int c, uintptr_t base_addr) * 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 @@ -77,9 +131,11 @@ endfunc console_core_init * Clobber list : x2 * -------------------------------------------------------- */ -func console_core_putc - /* Check the input parameter */ - cbz x1, putc_error +func console_16550_core_putc +#if ENABLE_ASSERTIONS + cmp x1, #0 + ASM_ASSERT(ne) +#endif /* ENABLE_ASSERTIONS */ /* Prepend '\r' to '\n' */ cmp w0, #0xA @@ -99,34 +155,75 @@ func console_core_putc b.ne 2b str w0, [x1, #UARTTX] ret -putc_error: - mov w0, #-1 - ret -endfunc console_core_putc +endfunc console_16550_core_putc + + /* -------------------------------------------------------- + * int console_16550_putc(int c, console_16550_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 - pointer to console_t structure + * Out : return -1 on error else return character. + * Clobber list : x2 + * -------------------------------------------------------- + */ +func console_16550_putc +#if ENABLE_ASSERTIONS + cmp x1, #0 + ASM_ASSERT(ne) +#endif /* ENABLE_ASSERTIONS */ + ldr x1, [x1, #CONSOLE_T_16550_BASE] + b console_16550_core_putc +endfunc console_16550_putc /* --------------------------------------------- - * int console_core_getc(void) + * int console_16550_core_getc(uintptr_t base_addr) * Function to get a character from the console. * It returns the character grabbed on success - * or -1 on error. - * In : w0 - console base address - * Out : return -1 on error else return character. + * or -1 on if no character is available. + * In : x0 - console base address + * Out : w0 - character if available, else -1 * Clobber list : x0, x1 * --------------------------------------------- */ -func console_core_getc +func console_16550_core_getc +#if ENABLE_ASSERTIONS + cmp x0, #0 + ASM_ASSERT(ne) +#endif /* ENABLE_ASSERTIONS */ + /* Check if the receive FIFO is empty */ 1: ldr w1, [x0, #UARTLSR] - tbz w1, #UARTLSR_RDR_BIT, 1b + tbz w1, #UARTLSR_RDR_BIT, no_char ldr w0, [x0, #UARTRX] ret -getc_error: - mov w0, #-1 +no_char: + mov w0, #ERROR_NO_PENDING_CHAR ret -endfunc console_core_getc +endfunc console_16550_core_getc + + /* --------------------------------------------- + * int console_16550_getc(console_16550_t *console) + * Function to get a character from the console. + * It returns the character grabbed on success + * or -1 on if no character is available. + * In : x0 - pointer to console_t stucture + * Out : w0 - character if available, else -1 + * Clobber list : x0, x1 + * --------------------------------------------- + */ +func console_16550_getc +#if ENABLE_ASSERTIONS + cmp x1, #0 + ASM_ASSERT(ne) +#endif /* ENABLE_ASSERTIONS */ + ldr x0, [x0, #CONSOLE_T_16550_BASE] + b console_16550_core_getc +endfunc console_16550_getc /* --------------------------------------------- * int console_core_flush(uintptr_t base_addr) + * DEPRECATED: Not used with MULTI_CONSOLE_API! * Function to force a write of all buffered * data that hasn't been output. * In : x0 - console base address diff --git a/include/drivers/ti/uart/uart_16550.h b/include/drivers/ti/uart/uart_16550.h index f258d45bd..9eba41aa6 100644 --- a/include/drivers/ti/uart/uart_16550.h +++ b/include/drivers/ti/uart/uart_16550.h @@ -7,6 +7,8 @@ #ifndef __UART_16550_H__ #define __UART_16550_H__ +#include + /* UART16550 Registers */ #define UARTTX 0x0 #define UARTRX 0x0 @@ -67,4 +69,26 @@ #define UARTLSR_RDR_BIT (0) /* Rx Data Ready Bit */ #define UARTLSR_RDR (1 << UARTLSR_RDR_BIT) /* Rx Data Ready */ +#define CONSOLE_T_16550_BASE CONSOLE_T_DRVDATA + +#ifndef __ASSEMBLY__ + +#include + +typedef struct { + console_t console; + uintptr_t base; +} console_16550_t; + +/* + * Initialize a new 16550 console instance and register it with the console + * framework. The |console| pointer must point to storage that will be valid + * for the lifetime of the console, such as a global or static local variable. + * Its contents will be reinitialized from scratch. + */ +int console_16550_register(uintptr_t baseaddr, uint32_t clock, uint32_t baud, + console_16550_t *console); + +#endif /*__ASSEMBLY__*/ + #endif /* __UART_16550_H__ */ From 4a0c45716df6b0e9c1142c768bb2578ad87ce8c7 Mon Sep 17 00:00:00 2001 From: Julius Werner Date: Mon, 18 Sep 2017 16:59:43 -0700 Subject: [PATCH 06/11] drivers: arm: pl011: Update PL011 driver to support MULTI_CONSOLE_API This patch updates the ARM PL011 console driver to support the new console API. The driver will continue to support the old API as well by checking the MULTI_CONSOLE_API compile-time flag. Change-Id: Ic34e4158addbb0c5fae500c9cff899c05a4f4206 Signed-off-by: Julius Werner --- drivers/arm/pl011/aarch64/pl011_console.S | 176 ++++++++++++++++++---- include/drivers/arm/pl011.h | 24 +++ 2 files changed, 167 insertions(+), 33 deletions(-) diff --git a/drivers/arm/pl011/aarch64/pl011_console.S b/drivers/arm/pl011/aarch64/pl011_console.S index 8b15d565d..6f2510ad4 100644 --- a/drivers/arm/pl011/aarch64/pl011_console.S +++ b/drivers/arm/pl011/aarch64/pl011_console.S @@ -5,6 +5,7 @@ */ #include #include +#include #include /* @@ -13,15 +14,21 @@ */ #include "../../../console/aarch64/console.S" + /* + * "core" functions are low-level implementations that don't require + * writable memory and are thus safe to call in BL1 crash context. + */ + .globl console_pl011_core_init + .globl console_pl011_core_putc + .globl console_pl011_core_getc + .globl console_pl011_core_flush - .globl console_core_init - .globl console_core_putc - .globl console_core_getc - .globl console_core_flush - + .globl console_pl011_putc + .globl console_pl011_getc + .globl console_pl011_flush /* ----------------------------------------------- - * int console_core_init(uintptr_t base_addr, + * int console_pl011_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 @@ -34,7 +41,7 @@ * Clobber list : x1, x2, x3, x4 * ----------------------------------------------- */ -func console_core_init +func console_pl011_core_init /* Check the input base address */ cbz x0, core_init_fail #if !PL011_GENERIC_UART @@ -71,10 +78,54 @@ func console_core_init core_init_fail: mov w0, wzr ret -endfunc console_core_init +endfunc console_pl011_core_init + +#if MULTI_CONSOLE_API + .globl console_pl011_register + + /* ----------------------------------------------- + * int console_pl011_register(console_pl011_t *console, + uintptr_t base, uint32_t clk, uint32_t baud) + * Function to initialize and register a new PL011 + * console. Storage passed in for the console struct + * *must* be persistent (i.e. not from the stack). + * In: x0 - UART register base address + * w1 - UART clock in Hz + * w2 - Baud rate + * x3 - pointer to empty console_pl011_t struct + * Out: return 1 on success, 0 on error + * Clobber list : x0, x1, x2, x6, x7, x14 + * ----------------------------------------------- + */ +func console_pl011_register + mov x7, x30 + mov x6, x3 + cbz x6, register_fail + str x0, [x6, #CONSOLE_T_PL011_BASE] + + bl console_pl011_core_init + cbz x0, register_fail + + mov x0, x6 + mov x30, x7 + finish_console_register pl011 + +register_fail: + ret x7 +endfunc console_pl011_register +#else + .globl console_core_init + .globl console_core_putc + .globl console_core_getc + .globl console_core_flush + .equ console_core_init,console_pl011_core_init + .equ console_core_putc,console_pl011_core_putc + .equ console_core_getc,console_pl011_core_getc + .equ console_core_flush,console_pl011_core_flush +#endif /* -------------------------------------------------------- - * int console_core_putc(int c, uintptr_t base_addr) + * int console_pl011_core_putc(int c, uintptr_t base_addr) * 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 @@ -83,9 +134,12 @@ endfunc console_core_init * Clobber list : x2 * -------------------------------------------------------- */ -func console_core_putc - /* Check the input parameter */ - cbz x1, putc_error +func console_pl011_core_putc +#if ENABLE_ASSERTIONS + cmp x1, #0 + ASM_ASSERT(ne) +#endif /* ENABLE_ASSERTIONS */ + /* Prepend '\r' to '\n' */ cmp w0, #0xA b.ne 2f @@ -101,36 +155,75 @@ func console_core_putc tbnz w2, #PL011_UARTFR_TXFF_BIT, 2b str w0, [x1, #UARTDR] ret -putc_error: - mov w0, #-1 - ret -endfunc console_core_putc +endfunc console_pl011_core_putc + + /* -------------------------------------------------------- + * int console_pl011_putc(int c, console_pl011_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 - pointer to console_t structure + * Out : return -1 on error else return character. + * Clobber list : x2 + * -------------------------------------------------------- + */ +func console_pl011_putc +#if ENABLE_ASSERTIONS + cmp x1, #0 + ASM_ASSERT(ne) +#endif /* ENABLE_ASSERTIONS */ + ldr x1, [x1, #CONSOLE_T_PL011_BASE] + b console_pl011_core_putc +endfunc console_pl011_putc /* --------------------------------------------- - * int console_core_getc(uintptr_t base_addr) + * int console_pl011_core_getc(uintptr_t base_addr) * Function to get a character from the console. * It returns the character grabbed on success - * or -1 on error. + * or -1 if no character is available. * In : x0 - console base address + * Out: w0 - character if available, else -1 * Clobber list : x0, x1 * --------------------------------------------- */ -func console_core_getc - cbz x0, getc_error -1: +func console_pl011_core_getc +#if ENABLE_ASSERTIONS + cmp x0, #0 + ASM_ASSERT(ne) +#endif /* ENABLE_ASSERTIONS */ + /* Check if the receive FIFO is empty */ ldr w1, [x0, #UARTFR] - tbnz w1, #PL011_UARTFR_RXFE_BIT, 1b + tbnz w1, #PL011_UARTFR_RXFE_BIT, no_char ldr w1, [x0, #UARTDR] mov w0, w1 ret -getc_error: - mov w0, #-1 +no_char: + mov w0, #ERROR_NO_PENDING_CHAR ret -endfunc console_core_getc +endfunc console_pl011_core_getc /* --------------------------------------------- - * int console_core_flush(uintptr_t base_addr) + * int console_pl011_getc(console_pl011_t *console) + * Function to get a character from the console. + * It returns the character grabbed on success + * or -1 if no character is available. + * In : x0 - pointer to console_t structure + * Out: w0 - character if available, else -1 + * Clobber list : x0, x1 + * --------------------------------------------- + */ +func console_pl011_getc +#if ENABLE_ASSERTIONS + cmp x0, #0 + ASM_ASSERT(ne) +#endif /* ENABLE_ASSERTIONS */ + ldr x0, [x0, #CONSOLE_T_PL011_BASE] + b console_pl011_core_getc +endfunc console_pl011_getc + + /* --------------------------------------------- + * int console_pl011_core_flush(uintptr_t base_addr) * Function to force a write of all buffered * data that hasn't been output. * In : x0 - console base address @@ -138,9 +231,11 @@ endfunc console_core_getc * Clobber list : x0, x1 * --------------------------------------------- */ -func console_core_flush - cbz x0, flush_error - +func console_pl011_core_flush +#if ENABLE_ASSERTIONS + cmp x0, #0 + ASM_ASSERT(ne) +#endif /* ENABLE_ASSERTIONS */ 1: /* Loop until the transmit FIFO is empty */ ldr w1, [x0, #UARTFR] @@ -148,7 +243,22 @@ func console_core_flush mov w0, #0 ret -flush_error: - mov w0, #-1 - ret -endfunc console_core_flush +endfunc console_pl011_core_flush + + /* --------------------------------------------- + * int console_pl011_flush(console_pl011_t *console) + * Function to force a write of all buffered + * data that hasn't been output. + * In : x0 - pointer to console_t structure + * Out : return -1 on error else return 0. + * Clobber list : x0, x1 + * --------------------------------------------- + */ +func console_pl011_flush +#if ENABLE_ASSERTIONS + cmp x0, #0 + ASM_ASSERT(ne) +#endif /* ENABLE_ASSERTIONS */ + ldr x0, [x0, #CONSOLE_T_PL011_BASE] + b console_pl011_core_flush +endfunc console_pl011_flush diff --git a/include/drivers/arm/pl011.h b/include/drivers/arm/pl011.h index cd259c5e1..06d754353 100644 --- a/include/drivers/arm/pl011.h +++ b/include/drivers/arm/pl011.h @@ -7,6 +7,8 @@ #ifndef __PL011_H__ #define __PL011_H__ +#include + /* PL011 Registers */ #define UARTDR 0x000 #define UARTRSR 0x004 @@ -79,4 +81,26 @@ #endif /* !PL011_GENERIC_UART */ +#define CONSOLE_T_PL011_BASE CONSOLE_T_DRVDATA + +#ifndef __ASSEMBLY__ + +#include + +typedef struct { + console_t console; + uintptr_t base; +} console_pl011_t; + +/* + * Initialize a new PL011 console instance and register it with the console + * framework. The |console| pointer must point to storage that will be valid + * for the lifetime of the console, such as a global or static local variable. + * Its contents will be reinitialized from scratch. + */ +int console_pl011_register(uintptr_t baseaddr, uint32_t clock, uint32_t baud, + console_pl011_t *console); + +#endif /*__ASSEMBLY__*/ + #endif /* __PL011_H__ */ From 38ba8e9327a3911e8a24ada75346c0765ffffba1 Mon Sep 17 00:00:00 2001 From: Julius Werner Date: Mon, 18 Sep 2017 17:01:06 -0700 Subject: [PATCH 07/11] drivers: cadence: cdns: Update CDNS driver to support MULTI_CONSOLE_API This patch updates the Cadence CDNS console driver to support the new console API. The driver will continue to support the old API as well by checking the MULTI_CONSOLE_API compile-time flag. Change-Id: I2ef8fb0d6ab72696997db1e0243a533499569d6b Signed-off-by: Julius Werner --- drivers/cadence/uart/aarch64/cdns_console.S | 145 ++++++++++++++++---- include/drivers/cadence/cdns_uart.h | 24 ++++ 2 files changed, 139 insertions(+), 30 deletions(-) diff --git a/drivers/cadence/uart/aarch64/cdns_console.S b/drivers/cadence/uart/aarch64/cdns_console.S index f6a1532c9..fc357f8a4 100644 --- a/drivers/cadence/uart/aarch64/cdns_console.S +++ b/drivers/cadence/uart/aarch64/cdns_console.S @@ -5,16 +5,22 @@ */ #include #include +#include #include - .globl console_core_init - .globl console_core_putc - .globl console_core_getc - .globl console_core_flush + /* + * "core" functions are low-level implementations that don't require + * writable memory and are thus safe to call in BL1 crash context. + */ + .globl console_cdns_core_init + .globl console_cdns_core_putc + .globl console_cdns_core_getc + + .globl console_cdns_putc + .globl console_cdns_getc /* ----------------------------------------------- - * int console_core_init(unsigned long base_addr, - * unsigned int uart_clk, unsigned int baud_rate) + * int console_cdns_core_init(uintptr_t base_addr) * Function to initialize the console without a * C Runtime to print debug information. This * function will be accessed by console_init and @@ -23,18 +29,13 @@ * the HW (baud, ...) and only enable the trans- * mitter and receiver here. * 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, x3 * ----------------------------------------------- */ -func console_core_init +func console_cdns_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 /* RX/TX enabled & reset */ mov w3, #(R_UART_CR_TX_EN | R_UART_CR_RX_EN | R_UART_CR_TXRST | R_UART_CR_RXRST) @@ -45,10 +46,51 @@ func console_core_init core_init_fail: mov w0, wzr ret -endfunc console_core_init +endfunc console_cdns_core_init + +#if MULTI_CONSOLE_API + .globl console_cdns_register + + /* ----------------------------------------------- + * int console_cdns_register(console_cdns_t *console, + uintptr_t base, uint32_t clk, uint32_t baud) + * Function to initialize and register a new CDNS + * console. Storage passed in for the console struct + * *must* be persistent (i.e. not from the stack). + * In: x0 - UART register base address + * x1 - pointer to empty console_cdns_t struct + * Out: return 1 on success, 0 on error + * Clobber list : x0, x1, x2, x6, x7, x14 + * ----------------------------------------------- + */ +func console_cdns_register + mov x7, x30 + mov x6, x1 + cbz x6, register_fail + str x0, [x6, #CONSOLE_T_CDNS_BASE] + + bl console_cdns_core_init + cbz x0, register_fail + + mov x0, x6 + mov x30, v7 + finish_console_register cdns + +register_fail: + ret x7 +endfunc console_cdns_register +#else + .globl console_core_init + .globl console_core_putc + .globl console_core_getc + .globl console_core_flush + .equ console_core_init,console_cdns_core_init + .equ console_core_putc,console_cdns_core_putc + .equ console_core_getc,console_cdns_core_getc +#endif /* -------------------------------------------------------- - * int console_core_putc(int c, unsigned long base_addr) + * int console_cdns_core_putc(int c, uintptr_t base_addr) * 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 @@ -57,9 +99,12 @@ endfunc console_core_init * Clobber list : x2 * -------------------------------------------------------- */ -func console_core_putc - /* Check the input parameter */ - cbz x1, putc_error +func console_cdns_core_putc +#if ENABLE_ASSERTIONS + cmp x1, #0 + ASM_ASSERT(ne) +#endif /* ENABLE_ASSERTIONS */ + /* Prepend '\r' to '\n' */ cmp w0, #0xA b.ne 2f @@ -75,36 +120,76 @@ func console_core_putc tbnz w2, #UART_SR_INTR_TFUL_BIT, 2b str w0, [x1, #R_UART_TX] ret -putc_error: - mov w0, #-1 - ret -endfunc console_core_putc +endfunc console_cdns_core_putc + + /* -------------------------------------------------------- + * int console_cdns_putc(int c, console_cdns_t *cdns) + * 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 - pointer to console_t structure + * Out : return -1 on error else return character. + * Clobber list : x2 + * -------------------------------------------------------- + */ +func console_cdns_putc +#if ENABLE_ASSERTIONS + cmp x1, #0 + ASM_ASSERT(ne) +#endif /* ENABLE_ASSERTIONS */ + ldr x1, [x1, #CONSOLE_T_CDNS_BASE] + b console_cdns_core_putc +endfunc console_cdns_putc /* --------------------------------------------- - * int console_core_getc(unsigned long base_addr) + * int console_cdns_core_getc(uintptr_t base_addr) * Function to get a character from the console. * It returns the character grabbed on success - * or -1 on error. + * or -1 if no character is available. * In : x0 - console base address + * Out: w0 - character if available, else -1 * Clobber list : x0, x1 * --------------------------------------------- */ -func console_core_getc - cbz x0, getc_error -1: +func console_cdns_core_getc +#if ENABLE_ASSERTIONS + cmp x0, #0 + ASM_ASSERT(ne) +#endif /* ENABLE_ASSERTIONS */ + /* Check if the receive FIFO is empty */ ldr w1, [x0, #R_UART_SR] - tbnz w1, #UART_SR_INTR_REMPTY_BIT, 1b + tbnz w1, #UART_SR_INTR_REMPTY_BIT, no_char ldr w1, [x0, #R_UART_RX] mov w0, w1 ret -getc_error: - mov w0, #-1 +no_char: + mov w0, #ERROR_NO_PENDING_CHAR ret -endfunc console_core_getc +endfunc console_cdns_core_getc + + /* --------------------------------------------- + * int console_cdns_getc(console_cdns_t *console) + * Function to get a character from the console. + * It returns the character grabbed on success + * or -1 if no character is available. + * In : x0 - pointer to console_t structure + * Out: w0 - character if available, else -1 + * Clobber list : x0, x1 + * --------------------------------------------- + */ +func console_cdns_getc +#if ENABLE_ASSERTIONS + cmp x0, #0 + ASM_ASSERT(ne) +#endif /* ENABLE_ASSERTIONS */ + ldr x0, [x0, #CONSOLE_T_CDNS_BASE] + b console_cdns_core_getc +endfunc console_cdns_getc /* --------------------------------------------- * int console_core_flush(uintptr_t base_addr) + * DEPRECATED: Not used with MULTI_CONSOLE_API! * Function to force a write of all buffered * data that hasn't been output. * In : x0 - console base address diff --git a/include/drivers/cadence/cdns_uart.h b/include/drivers/cadence/cdns_uart.h index 3aadde32e..7ab6df047 100644 --- a/include/drivers/cadence/cdns_uart.h +++ b/include/drivers/cadence/cdns_uart.h @@ -7,6 +7,8 @@ #ifndef __CADENCE_UART_H__ #define __CADENCE_UART_H__ +#include + /* This is very minimalistic and will only work in QEMU. */ /* CADENCE Registers */ @@ -23,4 +25,26 @@ #define R_UART_TX 0x30 #define R_UART_RX 0x30 +#define CONSOLE_T_CDNS_BASE CONSOLE_T_DRVDATA + +#ifndef __ASSEMBLY__ + +#include + +typedef struct { + console_t console; + uintptr_t base; +} console_cdns_t; + +/* + * Initialize a new Cadence console instance and register it with the console + * framework. The |console| pointer must point to storage that will be valid + * for the lifetime of the console, such as a global or static local variable. + * Its contents will be reinitialized from scratch. + */ +int console_cdns_register(uint64_t baseaddr, uint32_t clock, uint32_t baud, + console_cdns_t *console); + +#endif /*__ASSEMBLY__*/ + #endif From 3429c77ab09b69eef4ed752c2d641ed724e72110 Mon Sep 17 00:00:00 2001 From: Julius Werner Date: Fri, 9 Jun 2017 15:17:15 -0700 Subject: [PATCH 08/11] Add platform-independent coreboot support library This patch adds the foundation for a platform-independent coreboot support library that can be shared by all platforms that boot BL31 from coreboot (acting as BL2). It adds code to parse the "coreboot table", a data structure that coreboot uses to communicate different kinds of information to later-stage firmware and certain OS drivers. As a first small use case for this information, allow platforms to access the serial console configuration used by coreboot, removing the need to hardcode base address and divisors and allowing Trusted Firmware to benefit from coreboot's user configuration (e.g. which UART to pick and which baud rate to use). Change-Id: I2bfb39cd2609ce6640b844ab68df6c9ae3f28e9e Signed-off-by: Julius Werner --- include/lib/coreboot.h | 24 ++++++++++ lib/coreboot/coreboot.mk | 20 ++++++++ lib/coreboot/coreboot_table.c | 89 +++++++++++++++++++++++++++++++++++ make_helpers/defaults.mk | 4 ++ 4 files changed, 137 insertions(+) create mode 100644 include/lib/coreboot.h create mode 100644 lib/coreboot/coreboot.mk create mode 100644 lib/coreboot/coreboot_table.c diff --git a/include/lib/coreboot.h b/include/lib/coreboot.h new file mode 100644 index 000000000..4b1f200a2 --- /dev/null +++ b/include/lib/coreboot.h @@ -0,0 +1,24 @@ +/* + * Copyright (c) 2017, ARM Limited and Contributors. All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#ifndef __COREBOOT_H__ +#define __COREBOOT_H__ + +#include + +typedef struct { + uint32_t type; /* always 2 (memory-mapped) on ARM */ + uint32_t baseaddr; + uint32_t baud; + uint32_t regwidth; /* in bytes, i.e. usually 4 */ + uint32_t input_hertz; + uint32_t uart_pci_addr; /* unused on current ARM systems */ +} coreboot_serial_t; +extern coreboot_serial_t coreboot_serial; + +void coreboot_table_setup(void *base); + +#endif /* __COREBOOT_H__ */ diff --git a/lib/coreboot/coreboot.mk b/lib/coreboot/coreboot.mk new file mode 100644 index 000000000..0cd103f27 --- /dev/null +++ b/lib/coreboot/coreboot.mk @@ -0,0 +1,20 @@ +# +# Copyright (c) 2017, ARM Limited and Contributors. All rights reserved. +# +# SPDX-License-Identifier: BSD-3-Clause +# + +COREBOOT := 0 +$(eval $(call assert_boolean,COREBOOT)) +$(eval $(call add_define,COREBOOT)) + +ifeq (${COREBOOT},1) + +ifneq (${ARCH},aarch64) +$(error "coreboot only supports Trusted Firmware on AArch64.") +endif + +BL31_SOURCES += $(addprefix lib/coreboot/, \ + coreboot_table.c) + +endif # COREBOOT diff --git a/lib/coreboot/coreboot_table.c b/lib/coreboot/coreboot_table.c new file mode 100644 index 000000000..76e5d3b70 --- /dev/null +++ b/lib/coreboot/coreboot_table.c @@ -0,0 +1,89 @@ +/* + * Copyright (c) 2017, ARM Limited and Contributors. All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#include +#include +#include +#include + +/* + * Structures describing coreboot's in-memory descriptor tables. See + * /src/commonlib/include/commonlib/coreboot_tables.h for + * canonical implementation. + */ + +typedef struct { + char signature[4]; + uint32_t header_bytes; + uint32_t header_checksum; + uint32_t table_bytes; + uint32_t table_checksum; + uint32_t table_entries; +} cb_header_t; + +typedef enum { + CB_TAG_SERIAL = 0xf, +} cb_tag_t; + +typedef struct { + uint32_t tag; + uint32_t size; + union { + coreboot_serial_t serial; + }; +} cb_entry_t; + +coreboot_serial_t coreboot_serial; + +/* + * The coreboot table is parsed before the MMU is enabled (i.e. with strongly + * ordered memory), so we cannot make unaligned accesses. The table entries + * immediately follow one another without padding, so nothing after the header + * is guaranteed to be naturally aligned. Therefore, we need to define safety + * functions that can read unaligned integers. + */ +static uint32_t read_le32(uint32_t *p) +{ + uintptr_t addr = (uintptr_t)p; + return mmio_read_8(addr) | + mmio_read_8(addr + 1) << 8 | + mmio_read_8(addr + 2) << 16 | + mmio_read_8(addr + 3) << 24; +} + +void coreboot_table_setup(void *base) +{ + cb_header_t *header = base; + void *ptr; + int i; + + if (strncmp(header->signature, "LBIO", 4)) { + ERROR("coreboot table signature corrupt!\n"); + return; + } + + ptr = base + header->header_bytes; + for (i = 0; i < header->table_entries; i++) { + cb_entry_t *entry = ptr; + + if (ptr - base >= header->header_bytes + header->table_bytes) { + ERROR("coreboot table exceeds its bounds!\n"); + break; + } + + switch (read_le32(&entry->tag)) { + case CB_TAG_SERIAL: + memcpy(&coreboot_serial, &entry->serial, + sizeof(coreboot_serial)); + break; + default: + /* There are many tags TF doesn't need to care about. */ + break; + } + + ptr += read_le32(&entry->size); + } +} diff --git a/make_helpers/defaults.mk b/make_helpers/defaults.mk index 2eb922f89..eb1bb0aea 100644 --- a/make_helpers/defaults.mk +++ b/make_helpers/defaults.mk @@ -31,6 +31,10 @@ BASE_COMMIT := origin/master # The platform Makefile is free to override this value. COLD_BOOT_SINGLE_CPU := 0 +# Flag to compile in coreboot support code. Exclude by default. The coreboot +# Makefile system will set this when compiling TF as part of a coreboot image. +COREBOOT := 0 + # For Chain of Trust CREATE_KEYS := 1 From 3c250b9ab669614c8a2fcae27f598f384c6146fe Mon Sep 17 00:00:00 2001 From: Julius Werner Date: Fri, 9 Jun 2017 15:22:44 -0700 Subject: [PATCH 09/11] rockchip: Use coreboot-supplied serial console on coreboot systems This patch changes all Rockchip platforms to initialize the serial console with information supplied by coreboot rather than hardcoded base address and divisor values if BL31 is run on top of coreboot. Moving the BL2-to-BL31 parameter parsing as early as possible to ensure that the console is available for all following code. Also update the Rockchip platform to use MULTI_CONSOLE_API. Change-Id: I670d350fa2f8b8133539f91ac14977ab47db60d9 Signed-off-by: Julius Werner --- plat/rockchip/common/bl31_plat_setup.c | 13 ++++++++++--- plat/rockchip/common/include/plat_params.h | 6 ++++++ plat/rockchip/common/params_setup.c | 7 +++++++ plat/rockchip/rk3328/platform.mk | 2 ++ plat/rockchip/rk3368/platform.mk | 2 ++ plat/rockchip/rk3399/platform.mk | 2 ++ 6 files changed, 29 insertions(+), 3 deletions(-) diff --git a/plat/rockchip/common/bl31_plat_setup.c b/plat/rockchip/common/bl31_plat_setup.c index 292f0dd7d..28a83880f 100644 --- a/plat/rockchip/common/bl31_plat_setup.c +++ b/plat/rockchip/common/bl31_plat_setup.c @@ -8,12 +8,14 @@ #include #include #include +#include #include #include #include #include #include #include +#include /******************************************************************************* * Declarations of linker defined symbols which will help us find the layout @@ -69,8 +71,16 @@ void params_early_setup(void *plat_param_from_bl2) void bl31_early_platform_setup(bl31_params_t *from_bl2, void *plat_params_from_bl2) { + params_early_setup(plat_params_from_bl2); + +#if COREBOOT + if (coreboot_serial.type) + console_init(coreboot_serial.baseaddr, + coreboot_serial.input_hertz, coreboot_serial.baud); +#else console_init(PLAT_RK_UART_BASE, PLAT_RK_UART_CLOCK, PLAT_RK_UART_BAUDRATE); +#endif VERBOSE("bl31_setup\n"); @@ -82,9 +92,6 @@ void bl31_early_platform_setup(bl31_params_t *from_bl2, bl32_ep_info = *from_bl2->bl32_ep_info; bl33_ep_info = *from_bl2->bl33_ep_info; - - /* there may have some board sepcific message need to initialize */ - params_early_setup(plat_params_from_bl2); } /******************************************************************************* diff --git a/plat/rockchip/common/include/plat_params.h b/plat/rockchip/common/include/plat_params.h index aa13f878c..710990760 100644 --- a/plat/rockchip/common/include/plat_params.h +++ b/plat/rockchip/common/include/plat_params.h @@ -56,6 +56,7 @@ enum { PARAM_POWEROFF, PARAM_SUSPEND_GPIO, PARAM_SUSPEND_APIO, + PARAM_COREBOOT_TABLE, }; struct apio_info { @@ -89,4 +90,9 @@ struct bl31_apio_param { struct apio_info apio; }; +struct bl31_u64_param { + struct bl31_plat_param h; + uint64_t value; +}; + #endif /* __PLAT_PARAMS_H__ */ diff --git a/plat/rockchip/common/params_setup.c b/plat/rockchip/common/params_setup.c index b37acb76b..65afe8769 100644 --- a/plat/rockchip/common/params_setup.c +++ b/plat/rockchip/common/params_setup.c @@ -8,6 +8,7 @@ #include #include #include +#include #include #include #include @@ -84,6 +85,12 @@ void params_early_setup(void *plat_param_from_bl2) sizeof(struct bl31_apio_param)); suspend_apio = ¶m_apio.apio; break; +#if COREBOOT + case PARAM_COREBOOT_TABLE: + coreboot_table_setup((void *) + ((struct bl31_u64_param *)bl2_param)->value); + break; +#endif default: ERROR("not expected type found %ld\n", bl2_param->type); diff --git a/plat/rockchip/rk3328/platform.mk b/plat/rockchip/rk3328/platform.mk index 5de4680e0..b4b2bc45a 100644 --- a/plat/rockchip/rk3328/platform.mk +++ b/plat/rockchip/rk3328/platform.mk @@ -50,6 +50,8 @@ BL31_SOURCES += ${RK_GIC_SOURCES} \ ENABLE_PLAT_COMPAT := 0 +include lib/coreboot/coreboot.mk + $(eval $(call add_define,PLAT_EXTRA_LD_SCRIPT)) $(eval $(call add_define,PLAT_SKIP_OPTEE_S_EL1_INT_REGISTER)) diff --git a/plat/rockchip/rk3368/platform.mk b/plat/rockchip/rk3368/platform.mk index d3c6eeffb..c6e9bcd46 100644 --- a/plat/rockchip/rk3368/platform.mk +++ b/plat/rockchip/rk3368/platform.mk @@ -50,6 +50,8 @@ BL31_SOURCES += ${RK_GIC_SOURCES} \ ENABLE_PLAT_COMPAT := 0 +include lib/coreboot/coreboot.mk + $(eval $(call add_define,PLAT_EXTRA_LD_SCRIPT)) # Do not enable SVE diff --git a/plat/rockchip/rk3399/platform.mk b/plat/rockchip/rk3399/platform.mk index 33b9723d7..f9d141d4f 100644 --- a/plat/rockchip/rk3399/platform.mk +++ b/plat/rockchip/rk3399/platform.mk @@ -65,6 +65,8 @@ BL31_SOURCES += ${RK_GIC_SOURCES} \ ENABLE_PLAT_COMPAT := 0 +include lib/coreboot/coreboot.mk + $(eval $(call add_define,PLAT_EXTRA_LD_SCRIPT)) # Enable workarounds for selected Cortex-A53 erratas. From 890abc33e46349fb01aed443ad7128b82ba34f3d Mon Sep 17 00:00:00 2001 From: Julius Werner Date: Wed, 2 Aug 2017 16:31:04 -0700 Subject: [PATCH 10/11] rockchip: Move to MULTI_CONSOLE_API This patch changes all Rockchip platforms to use the new MULTI_CONSOLE_API. The platform-specific plat_crash_console implementations are removed so that the platform can use the ones from the common platform code instead. Also change the registers used in plat_crash_print_regs. The existing use of x16 and x17 has always been illegal, since those registers are reserved for use by the linker as a temporary scratch registers in intra-procedure-call veneers and can never be expected to maintain their values across a function call. Change-Id: I8249424150be8d5543ed4af93b56756795a5288f Signed-off-by: Julius Werner --- plat/rockchip/common/aarch64/plat_helpers.S | 28 --------------------- plat/rockchip/common/bl31_plat_setup.c | 12 ++++++--- plat/rockchip/common/include/plat_macros.S | 16 ++++++------ plat/rockchip/rk3328/platform.mk | 1 + plat/rockchip/rk3368/platform.mk | 1 + plat/rockchip/rk3399/platform.mk | 1 + 6 files changed, 19 insertions(+), 40 deletions(-) diff --git a/plat/rockchip/common/aarch64/plat_helpers.S b/plat/rockchip/common/aarch64/plat_helpers.S index 24cb8e45a..f415f8772 100644 --- a/plat/rockchip/common/aarch64/plat_helpers.S +++ b/plat/rockchip/common/aarch64/plat_helpers.S @@ -19,8 +19,6 @@ .globl plat_secondary_cold_boot_setup .globl plat_report_exception .globl platform_is_primary_cpu - .globl plat_crash_console_init - .globl plat_crash_console_putc .globl plat_my_core_pos .globl plat_reset_handler .globl plat_panic_handler @@ -82,32 +80,6 @@ func platform_is_primary_cpu ret endfunc platform_is_primary_cpu - /* -------------------------------------------------------------------- - * int plat_crash_console_init(void) - * Function to initialize the crash console - * without a C Runtime to print crash report. - * Clobber list : x0, x1, x2 - * -------------------------------------------------------------------- - */ -func plat_crash_console_init - mov_imm x0, PLAT_RK_UART_BASE - mov_imm x1, PLAT_RK_UART_CLOCK - mov_imm x2, PLAT_RK_UART_BAUDRATE - b console_core_init -endfunc plat_crash_console_init - - /* -------------------------------------------------------------------- - * int plat_crash_console_putc(void) - * Function to print a character on the crash - * console without a C Runtime. - * Clobber list : x1, x2 - * -------------------------------------------------------------------- - */ -func plat_crash_console_putc - mov_imm x1, PLAT_RK_UART_BASE - b console_core_putc -endfunc plat_crash_console_putc - /* -------------------------------------------------------------------- * void plat_panic_handler(void) * Call system reset function on panic. Set up an emergency stack so we diff --git a/plat/rockchip/common/bl31_plat_setup.c b/plat/rockchip/common/bl31_plat_setup.c index 28a83880f..6199edae2 100644 --- a/plat/rockchip/common/bl31_plat_setup.c +++ b/plat/rockchip/common/bl31_plat_setup.c @@ -71,15 +71,19 @@ void params_early_setup(void *plat_param_from_bl2) void bl31_early_platform_setup(bl31_params_t *from_bl2, void *plat_params_from_bl2) { + static console_16550_t console; + params_early_setup(plat_params_from_bl2); #if COREBOOT if (coreboot_serial.type) - console_init(coreboot_serial.baseaddr, - coreboot_serial.input_hertz, coreboot_serial.baud); + console_16550_register(coreboot_serial.baseaddr, + coreboot_serial.input_hertz, + coreboot_serial.baud, + &console); #else - console_init(PLAT_RK_UART_BASE, PLAT_RK_UART_CLOCK, - PLAT_RK_UART_BAUDRATE); + console_16550_register(PLAT_RK_UART_BASE, PLAT_RK_UART_CLOCK, + PLAT_RK_UART_BAUDRATE, &console); #endif VERBOSE("bl31_setup\n"); diff --git a/plat/rockchip/common/include/plat_macros.S b/plat/rockchip/common/include/plat_macros.S index be1a9fa5d..6b3cb6a72 100644 --- a/plat/rockchip/common/include/plat_macros.S +++ b/plat/rockchip/common/include/plat_macros.S @@ -38,14 +38,14 @@ cci_iface_regs: * The below utility macro prints out relevant GIC * and CCI registers whenever an unhandled * exception is taken in BL31. - * Expects: GICD base in x16, GICC base in x17 + * Expects: GICD base in x26, GICC base in x27 * Clobbers: x0 - x10, sp * --------------------------------------------- */ .macro plat_crash_print_regs - mov_imm x16, PLAT_RK_GICD_BASE - mov_imm x17, PLAT_RK_GICC_BASE + mov_imm x26, PLAT_RK_GICD_BASE + mov_imm x27, PLAT_RK_GICC_BASE /* Check for GICv3 system register access */ mrs x7, id_aa64pfr0_el1 @@ -72,19 +72,19 @@ print_gicv2: /* Load the gicc reg list to x6 */ adr x6, gicc_regs /* Load the gicc regs to gp regs used by str_in_crash_buf_print */ - ldr w8, [x17, #GICC_HPPIR] - ldr w9, [x17, #GICC_AHPPIR] - ldr w10, [x17, #GICC_CTLR] + ldr w8, [x27, #GICC_HPPIR] + ldr w9, [x27, #GICC_AHPPIR] + ldr w10, [x27, #GICC_CTLR] /* Store to the crash buf and print to console */ bl str_in_crash_buf_print print_gic_common: /* Print the GICD_ISPENDR regs */ - add x7, x16, #GICD_ISPENDR + add x7, x26, #GICD_ISPENDR adr x4, gicd_pend_reg bl asm_print_str gicd_ispendr_loop: - sub x4, x7, x16 + sub x4, x7, x26 cmp x4, #0x280 b.eq exit_print_gic_regs bl asm_print_hex diff --git a/plat/rockchip/rk3328/platform.mk b/plat/rockchip/rk3328/platform.mk index b4b2bc45a..6e4d5b4dc 100644 --- a/plat/rockchip/rk3328/platform.mk +++ b/plat/rockchip/rk3328/platform.mk @@ -49,6 +49,7 @@ BL31_SOURCES += ${RK_GIC_SOURCES} \ ${RK_PLAT_SOC}/drivers/soc/soc.c ENABLE_PLAT_COMPAT := 0 +MULTI_CONSOLE_API := 1 include lib/coreboot/coreboot.mk diff --git a/plat/rockchip/rk3368/platform.mk b/plat/rockchip/rk3368/platform.mk index c6e9bcd46..ad204e9eb 100644 --- a/plat/rockchip/rk3368/platform.mk +++ b/plat/rockchip/rk3368/platform.mk @@ -49,6 +49,7 @@ BL31_SOURCES += ${RK_GIC_SOURCES} \ ${RK_PLAT_SOC}/drivers/ddr/ddr_rk3368.c \ ENABLE_PLAT_COMPAT := 0 +MULTI_CONSOLE_API := 1 include lib/coreboot/coreboot.mk diff --git a/plat/rockchip/rk3399/platform.mk b/plat/rockchip/rk3399/platform.mk index f9d141d4f..9e369e482 100644 --- a/plat/rockchip/rk3399/platform.mk +++ b/plat/rockchip/rk3399/platform.mk @@ -64,6 +64,7 @@ BL31_SOURCES += ${RK_GIC_SOURCES} \ ${RK_PLAT_SOC}/drivers/dram/suspend.c ENABLE_PLAT_COMPAT := 0 +MULTI_CONSOLE_API := 1 include lib/coreboot/coreboot.mk From 1c5f5031f38ed77688298d419727a6f0930e0673 Mon Sep 17 00:00:00 2001 From: Julius Werner Date: Tue, 13 Jun 2017 15:53:45 -0700 Subject: [PATCH 11/11] coreboot: Add support for CBMEM console coreboot supports an in-memory console to store firmware logs even when no serial console is available. It is widely supported by coreboot-compatible bootloaders (including SeaBIOS and GRUB) and can be read by the Linux kernel. This patch allows BL31 to add its own log messages to this console. The driver will be registered automatically if coreboot support is compiled in and detects the presence of a console buffer in the coreboot tables. Change-Id: I31254dfa0c2fdeb7454634134b5707b4b4154907 Signed-off-by: Julius Werner --- .../cbmem_console/aarch64/cbmem_console.S | 101 ++++++++++++++++++ include/drivers/coreboot/cbmem_console.h | 27 +++++ lib/coreboot/coreboot.mk | 4 + lib/coreboot/coreboot_table.c | 34 ++++++ 4 files changed, 166 insertions(+) create mode 100644 drivers/coreboot/cbmem_console/aarch64/cbmem_console.S create mode 100644 include/drivers/coreboot/cbmem_console.h diff --git a/drivers/coreboot/cbmem_console/aarch64/cbmem_console.S b/drivers/coreboot/cbmem_console/aarch64/cbmem_console.S new file mode 100644 index 000000000..2fc060334 --- /dev/null +++ b/drivers/coreboot/cbmem_console/aarch64/cbmem_console.S @@ -0,0 +1,101 @@ +/* + * Copyright (c) 2017, ARM Limited and Contributors. All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#include +#include +#include + +/* + * This driver implements access to coreboot's in-memory console + * (CBMEM console). For the original implementation, see + * /src/lib/cbmem_console.c. + */ + + .globl console_cbmc_register + .globl console_cbmc_putc + .globl console_cbmc_flush + + /* ----------------------------------------------- + * int console_cbmc_register(console_cbmc_t *console, + * uintptr_t base) + * Registers a new CBMEM console instance. Reads + * the size field from the buffer header structure + * and stores it in our console_cbmc_t struct, so + * that we keep the size in secure memory where we + * can trust it. A malicious EL1 could manipulate + * the console buffer (including the header), so we + * must not trust its contents after boot. + * In: x0 - CBMEM console base address + * x1 - pointer to empty console_cbmc_t struct + * Out: x0 - 1 to indicate success + * Clobber list: x0, x1, x2, x7 + * ----------------------------------------------- + */ +func console_cbmc_register + str x0, [x1, #CONSOLE_T_CBMC_BASE] + ldr w2, [x0] + str w2, [x1, #CONSOLE_T_CBMC_SIZE] + mov x0, x1 + finish_console_register cbmc +endfunc console_cbmc_register + + /* ----------------------------------------------- + * int console_cbmc_puts(int c, console_cbmc_t *console) + * Writes a character to the CBMEM console buffer, + * including overflow handling of the cursor field. + * The character must be preserved in x0. + * In: x0 - character to be stored + * x1 - pointer to console_cbmc_t struct + * Clobber list: x1, x2, x16, x17 + * ----------------------------------------------- + */ +func console_cbmc_putc + ldr w2, [x1, #CONSOLE_T_CBMC_SIZE] + ldr x1, [x1, #CONSOLE_T_CBMC_BASE] + add x1, x1, #8 /* keep address of body in x1 */ + + ldr w16, [x1, #-4] /* load cursor (one u32 before body) */ + and w17, w16, #0xf0000000 /* keep flags part in w17 */ + and w16, w16, #0x0fffffff /* keep actual cursor part in w16 */ + + cmp w16, w2 /* sanity check that cursor < size */ + b.lo putc_within_bounds + mov w0, #-1 /* cursor >= size must be malicious */ + ret /* so return error, don't write char */ + +putc_within_bounds: + strb w0, [x1, w16, uxtw] /* body[cursor] = character */ + add w16, w16, #1 /* cursor++ */ + cmp w16, w2 /* if cursor < size... */ + b.lo putc_write_back /* ...skip overflow handling */ + + mov w16, #0 /* on overflow, set cursor back to 0 */ + orr w17, w17, #(1 << 31) /* and set overflow flag */ + +putc_write_back: + orr w16, w16, w17 /* merge cursor and flags back */ + str w16, [x1, #-4] /* write back cursor to memory */ + ret +endfunc console_cbmc_putc + + /* ----------------------------------------------- + * int console_cbmc_flush(console_cbmc_t *console) + * Flushes the CBMEM console by flushing the + * console buffer from the CPU's data cache. + * In: x0 - pointer to console_cbmc_t struct + * Out: x0 - 0 for success + * Clobber list: x0, x1, x2, x3, x5 + * ----------------------------------------------- + */ +func console_cbmc_flush + mov x5, x30 + ldr x1, [x0, #CONSOLE_T_CBMC_SIZE] + ldr x0, [x0, #CONSOLE_T_CBMC_BASE] + add x1, x1, #8 /* add size of console header */ + bl clean_dcache_range /* (clobbers x2 and x3) */ + mov x0, #0 + ret x5 +endfunc console_cbmc_flush diff --git a/include/drivers/coreboot/cbmem_console.h b/include/drivers/coreboot/cbmem_console.h new file mode 100644 index 000000000..4fca36f61 --- /dev/null +++ b/include/drivers/coreboot/cbmem_console.h @@ -0,0 +1,27 @@ +/* + * Copyright (c) 2017, ARM Limited and Contributors. All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#ifndef __CBMEM_CONSOLE_H__ +#define __CBMEM_CONSOLE_H__ + +#include + +#define CONSOLE_T_CBMC_BASE CONSOLE_T_DRVDATA +#define CONSOLE_T_CBMC_SIZE (CONSOLE_T_DRVDATA + REGSZ) + +#ifndef __ASSEMBLER__ + +typedef struct { + console_t console; + uintptr_t base; + uint32_t size; +} console_cbmc_t; + +int console_cbmc_register(uintptr_t base, console_cbmc_t *console); + +#endif /* __ASSEMBLER__ */ + +#endif /* __CBMEM_CONSOLE_H__ */ diff --git a/lib/coreboot/coreboot.mk b/lib/coreboot/coreboot.mk index 0cd103f27..bbaa33294 100644 --- a/lib/coreboot/coreboot.mk +++ b/lib/coreboot/coreboot.mk @@ -17,4 +17,8 @@ endif BL31_SOURCES += $(addprefix lib/coreboot/, \ coreboot_table.c) +BL31_SOURCES += drivers/coreboot/cbmem_console/${ARCH}/cbmem_console.S + +INCLUDES += -Iinclude/drivers/coreboot + endif # COREBOOT diff --git a/lib/coreboot/coreboot_table.c b/lib/coreboot/coreboot_table.c index 76e5d3b70..64f8879e4 100644 --- a/lib/coreboot/coreboot_table.c +++ b/lib/coreboot/coreboot_table.c @@ -4,10 +4,13 @@ * SPDX-License-Identifier: BSD-3-Clause */ +#include +#include #include #include #include #include +#include /* * Structures describing coreboot's in-memory descriptor tables. See @@ -26,6 +29,7 @@ typedef struct { typedef enum { CB_TAG_SERIAL = 0xf, + CB_TAG_CBMEM_CONSOLE = 0x17, } cb_tag_t; typedef struct { @@ -33,6 +37,7 @@ typedef struct { uint32_t size; union { coreboot_serial_t serial; + uint64_t uint64; }; } cb_entry_t; @@ -53,6 +58,32 @@ static uint32_t read_le32(uint32_t *p) mmio_read_8(addr + 2) << 16 | mmio_read_8(addr + 3) << 24; } +static uint64_t read_le64(uint64_t *p) +{ + return read_le32((void *)p) | (uint64_t)read_le32((void *)p + 4) << 32; +} + +static void expand_and_mmap(uintptr_t baseaddr, size_t size) +{ + uintptr_t pageaddr = round_down(baseaddr, PAGE_SIZE); + size_t expanded = round_up(baseaddr - pageaddr + size, PAGE_SIZE); + mmap_add_region(pageaddr, pageaddr, expanded, + MT_MEMORY | MT_RW | MT_NS | MT_EXECUTE_NEVER); +} + +static void setup_cbmem_console(uintptr_t baseaddr) +{ + static console_cbmc_t console; + assert(!console.base); /* should only have one CBMEM console */ + + /* CBMEM console structure stores its size in first header field. */ + uint32_t size = *(uint32_t *)baseaddr; + expand_and_mmap(baseaddr, size); + console_cbmc_register(baseaddr, &console); + console_set_scope(&console.console, CONSOLE_FLAG_BOOT | + CONSOLE_FLAG_RUNTIME | + CONSOLE_FLAG_CRASH); +} void coreboot_table_setup(void *base) { @@ -79,6 +110,9 @@ void coreboot_table_setup(void *base) memcpy(&coreboot_serial, &entry->serial, sizeof(coreboot_serial)); break; + case CB_TAG_CBMEM_CONSOLE: + setup_cbmem_console(read_le64(&entry->uint64)); + break; default: /* There are many tags TF doesn't need to care about. */ break;