diff --git a/Makefile b/Makefile index 1cd6b62..c16cad7 100644 --- a/Makefile +++ b/Makefile @@ -488,6 +488,7 @@ $(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)) @@ -530,6 +531,7 @@ $(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/bl31/aarch64/crash_reporting.S b/bl31/aarch64/crash_reporting.S index cf32b31..0986a0a 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 @@ 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 @@ /* 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 @@ 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 @@ /* 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 @@ /* 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 @@ 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/docs/porting-guide.rst b/docs/porting-guide.rst index 84bd2cd..7683ded 100644 --- a/docs/porting-guide.rst +++ b/docs/porting-guide.rst @@ -1929,12 +1929,8 @@ 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] ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ @@ -2702,14 +2698,20 @@ 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 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ @@ -2720,9 +2722,30 @@ 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 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ @@ -2736,6 +2759,12 @@ 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 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ @@ -2746,9 +2775,15 @@ 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/drivers/arm/pl011/aarch64/pl011_console.S b/drivers/arm/pl011/aarch64/pl011_console.S index 8b15d56..6f2510a 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 @@ 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 @@ * 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 @@ 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 @@ * 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 @@ 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/drivers/cadence/uart/aarch64/cdns_console.S b/drivers/cadence/uart/aarch64/cdns_console.S index f6a1532..fc357f8 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 @@ 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 @@ * 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 @@ 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/drivers/console/aarch64/console.S b/drivers/console/aarch64/console.S index 7cc04dd..f847ed5 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 0000000..c83e246 --- /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 0000000..15c3ba4 --- /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 9db6157..1b5d739 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/drivers/coreboot/cbmem_console/aarch64/cbmem_console.S b/drivers/coreboot/cbmem_console/aarch64/cbmem_console.S new file mode 100644 index 0000000..2fc0603 --- /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/drivers/ti/uart/aarch64/16550_console.S b/drivers/ti/uart/aarch64/16550_console.S index f9ccd57..b02209d 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 @@ 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 @@ * 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 @@ 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/common/aarch64/console_macros.S b/include/common/aarch64/console_macros.S new file mode 100644 index 0000000..0ebea2c --- /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/arm/pl011.h b/include/drivers/arm/pl011.h index cd259c5..06d7543 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__ */ diff --git a/include/drivers/cadence/cdns_uart.h b/include/drivers/cadence/cdns_uart.h index 3aadde3..7ab6df0 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 diff --git a/include/drivers/console.h b/include/drivers/console.h index da5cb8f..0629f57 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 0000000..cedce86 --- /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/include/drivers/coreboot/cbmem_console.h b/include/drivers/coreboot/cbmem_console.h new file mode 100644 index 0000000..4fca36f --- /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/include/drivers/ti/uart/uart_16550.h b/include/drivers/ti/uart/uart_16550.h index f258d45..9eba41a 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__ */ diff --git a/include/lib/coreboot.h b/include/lib/coreboot.h new file mode 100644 index 0000000..4b1f200 --- /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/include/lib/utils_def.h b/include/lib/utils_def.h index 185a1c1..bda3b07 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. diff --git a/lib/coreboot/coreboot.mk b/lib/coreboot/coreboot.mk new file mode 100644 index 0000000..bbaa332 --- /dev/null +++ b/lib/coreboot/coreboot.mk @@ -0,0 +1,24 @@ +# +# 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) + +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 new file mode 100644 index 0000000..64f8879 --- /dev/null +++ b/lib/coreboot/coreboot_table.c @@ -0,0 +1,123 @@ +/* + * Copyright (c) 2017, ARM Limited and Contributors. All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#include +#include +#include +#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_CBMEM_CONSOLE = 0x17, +} cb_tag_t; + +typedef struct { + uint32_t tag; + uint32_t size; + union { + coreboot_serial_t serial; + uint64_t uint64; + }; +} 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; +} +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) +{ + 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; + 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; + } + + ptr += read_le32(&entry->size); + } +} diff --git a/make_helpers/defaults.mk b/make_helpers/defaults.mk index 643890f..a80a491 100644 --- a/make_helpers/defaults.mk +++ b/make_helpers/defaults.mk @@ -34,6 +34,10 @@ # 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 @@ -94,6 +98,10 @@ # 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 a87e7c6..cfc0c4f 100644 --- a/plat/common/aarch64/plat_common.c +++ b/plat/common/aarch64/plat_common.c @@ -39,11 +39,11 @@ 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 diff --git a/plat/common/aarch64/platform_helpers.S b/plat/common/aarch64/platform_helpers.S index 797a936..8526752 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 @@ 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 @@ 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 diff --git a/plat/rockchip/common/aarch64/plat_helpers.S b/plat/rockchip/common/aarch64/plat_helpers.S index abfb5a7..f415f87 100644 --- a/plat/rockchip/common/aarch64/plat_helpers.S +++ b/plat/rockchip/common/aarch64/plat_helpers.S @@ -19,10 +19,9 @@ .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 /* * void plat_reset_handler(void); @@ -82,30 +81,17 @@ 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 + * 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_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 +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); diff --git a/plat/rockchip/common/bl31_plat_setup.c b/plat/rockchip/common/bl31_plat_setup.c index 292f0dd..6199eda 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,20 @@ void bl31_early_platform_setup(bl31_params_t *from_bl2, void *plat_params_from_bl2) { - console_init(PLAT_RK_UART_BASE, PLAT_RK_UART_CLOCK, - PLAT_RK_UART_BAUDRATE); + static console_16550_t console; + + params_early_setup(plat_params_from_bl2); + +#if COREBOOT + if (coreboot_serial.type) + console_16550_register(coreboot_serial.baseaddr, + coreboot_serial.input_hertz, + coreboot_serial.baud, + &console); +#else + console_16550_register(PLAT_RK_UART_BASE, PLAT_RK_UART_CLOCK, + PLAT_RK_UART_BAUDRATE, &console); +#endif VERBOSE("bl31_setup\n"); @@ -82,9 +96,6 @@ 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_macros.S b/plat/rockchip/common/include/plat_macros.S index be1a9fa..6b3cb6a 100644 --- a/plat/rockchip/common/include/plat_macros.S +++ b/plat/rockchip/common/include/plat_macros.S @@ -38,14 +38,14 @@ * 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 @@ /* 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/common/include/plat_params.h b/plat/rockchip/common/include/plat_params.h index aa13f87..7109907 100644 --- a/plat/rockchip/common/include/plat_params.h +++ b/plat/rockchip/common/include/plat_params.h @@ -56,6 +56,7 @@ PARAM_POWEROFF, PARAM_SUSPEND_GPIO, PARAM_SUSPEND_APIO, + PARAM_COREBOOT_TABLE, }; struct apio_info { @@ -89,4 +90,9 @@ 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 b37acb7..65afe87 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 @@ 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 5de4680..6e4d5b4 100644 --- a/plat/rockchip/rk3328/platform.mk +++ b/plat/rockchip/rk3328/platform.mk @@ -49,6 +49,9 @@ ${RK_PLAT_SOC}/drivers/soc/soc.c ENABLE_PLAT_COMPAT := 0 +MULTI_CONSOLE_API := 1 + +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 d3c6eef..ad204e9 100644 --- a/plat/rockchip/rk3368/platform.mk +++ b/plat/rockchip/rk3368/platform.mk @@ -49,6 +49,9 @@ ${RK_PLAT_SOC}/drivers/ddr/ddr_rk3368.c \ ENABLE_PLAT_COMPAT := 0 +MULTI_CONSOLE_API := 1 + +include lib/coreboot/coreboot.mk $(eval $(call add_define,PLAT_EXTRA_LD_SCRIPT)) diff --git a/plat/rockchip/rk3399/platform.mk b/plat/rockchip/rk3399/platform.mk index 33b9723..9e369e4 100644 --- a/plat/rockchip/rk3399/platform.mk +++ b/plat/rockchip/rk3399/platform.mk @@ -64,6 +64,9 @@ ${RK_PLAT_SOC}/drivers/dram/suspend.c ENABLE_PLAT_COMPAT := 0 +MULTI_CONSOLE_API := 1 + +include lib/coreboot/coreboot.mk $(eval $(call add_define,PLAT_EXTRA_LD_SCRIPT))