Merge pull request #1700 from jwerner-chromium/JW_crashfix

MULTI_CONSOLE_API fixes and cleanups
This commit is contained in:
Soby Mathew 2018-12-10 14:00:01 +00:00 committed by GitHub
commit 85456a9201
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
26 changed files with 311 additions and 821 deletions

View File

@ -214,6 +214,7 @@ include lib/libc/libc.mk
BL_COMMON_SOURCES += common/bl_common.c \
common/tf_log.c \
common/${ARCH}/debug.S \
drivers/console/multi_console.c \
lib/${ARCH}/cache_helpers.S \
lib/${ARCH}/misc_helpers.S \
plat/common/plat_bl_common.c \

View File

@ -2550,9 +2550,6 @@ as Group 0 secure interrupt, Group 1 secure interrupt or Group 1 NS interrupt.
Crash Reporting mechanism (in BL31)
-----------------------------------
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.
BL31 implements a crash reporting mechanism which prints the various registers
of the CPU to enable quick crash analysis and debugging. This mechanism relies
on the platform implementating ``plat_crash_console_init``,
@ -2564,15 +2561,18 @@ makefiles in order to benefit from them. By default, they 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.
NOTE: Platforms are responsible for making sure that they only mark consoles for
use in the crash scope that are able to support this, i.e. that are written in
assembly and conform with the register clobber rules for putc() (x0-x2, x16-x17)
and flush() (x0-x3, x16-x17) crash callbacks.
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.
If this behaviour is not desirable, the platform may implement functions that
redirect the prints to the console driver (``console_xxx_core_init``, etc). Most
platforms (including Arm platforms) do this and they can be used as an example.
more explicitly. These platforms may instead provide custom implementations for
these. They are executed outside of a C environment and without a stack. Many
console drivers provide functions named ``console_xxx_core_init/putc/flush``
that are designed to be used by these functions. See Arm platforms (like juno)
for an example of this.
Function : plat\_crash\_console\_init [mandatory]
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
@ -2586,28 +2586,6 @@ This API is used by the crash reporting mechanism to initialize the crash
console. It must only use the general purpose registers x0 through x7 to do the
initialization and returns 1 on success.
When using the sample implementation, 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 [mandatory]
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
@ -2621,12 +2599,6 @@ 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 sample 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 [mandatory]
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
@ -2640,12 +2612,6 @@ data on the designated crash console. It should only use general purpose
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 sample 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.
External Abort handling and RAS Support
---------------------------------------

View File

@ -10,11 +10,13 @@
#include <console_macros.S>
#include <pl011.h>
#if !MULTI_CONSOLE_API
/*
* Pull in generic functions to provide backwards compatibility for
* platform makefiles
*/
#include "../../../console/aarch32/console.S"
#endif
/*
* "core" functions are low-level implementations that don't require

View File

@ -10,11 +10,13 @@
#include <console_macros.S>
#include <pl011.h>
#if !MULTI_CONSOLE_API
/*
* Pull in generic functions to provide backwards compatibility for
* platform makefiles
*/
#include "../../../console/aarch64/console.S"
#endif
/*
* "core" functions are low-level implementations that don't require

View File

@ -5,7 +5,9 @@
*/
#if MULTI_CONSOLE_API
#include "multi_console.S"
#if ERROR_DEPRECATED
#error "console.S is deprecated, platforms should no longer link it explicitly"
#endif
#else
#include "deprecated_console.S"
#endif

View File

@ -1,318 +0,0 @@
/*
* Copyright (c) 2015-2018, ARM Limited and Contributors. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#include <asm_macros.S>
#include <assert_macros.S>
#include <console.h>
.globl console_register
.globl console_unregister
.globl console_is_registered
.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 2
console_list: .word 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_<driver>_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 : r0 - address of console_t structure
* Out: r0 - Always 1 (for easier tail calling)
* Clobber list: r0, r1
* -----------------------------------------------
*/
func console_register
push {r6, lr}
#if ENABLE_ASSERTIONS
/* Assert that r0 isn't a NULL pointer */
cmp r0, #0
ASM_ASSERT(ne)
/* Assert that the struct isn't in the stack */
ldr r1, =__STACKS_START__
cmp r0, r1
blo not_on_stack
ldr r1, =__STACKS_END__
cmp r0, r1
ASM_ASSERT(hs)
not_on_stack:
/* Assert that this struct isn't in the list */
mov r1, r0 /* Preserve r0 and lr */
bl console_is_registered
cmp r0, #0
ASM_ASSERT(eq)
mov r0, r1
#endif /* ENABLE_ASSERTIONS */
ldr r6, =console_list
ldr r1, [r6] /* R1 = first struct in list */
str r0, [r6] /* list head = new console */
str r1, [r0, #CONSOLE_T_NEXT] /* new console next ptr = R1 */
mov r0, #1
pop {r6, pc}
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: r0 - address of console_t struct to remove
* Out: r0 - removed address, or NULL if not found
* Clobber list: r0, r1
* -----------------------------------------------
*/
func console_unregister
#if ENABLE_ASSERTIONS
/* Assert that r0 isn't a NULL pointer */
cmp r0, #0
ASM_ASSERT(ne)
#endif /* ENABLE_ASSERTIONS */
push {r6}
ldr r6, =console_list /* R6 = ptr to first struct */
ldr r1, [r6] /* R1 = first struct */
unregister_loop:
cmp r1, #0
beq unregister_not_found
cmp r0, r1
beq unregister_found
ldr r6, [r6] /* R6 = next ptr of struct */
ldr r1, [r6] /* R1 = next struct */
b unregister_loop
unregister_found:
ldr r1, [r1] /* R1 = next struct */
str r1, [r6] /* prev->next = cur->next */
pop {r6}
bx lr
unregister_not_found:
mov r0, #0 /* return NULL if not found */
pop {r6}
bx lr
endfunc console_unregister
/* -----------------------------------------------
* int console_is_registered(console_t *console)
* Function to detect if a specific console is
* registered or not.
* In: r0 - address of console_t struct to remove
* Out: r0 - 1 if it is registered, 0 if not.
* Clobber list: r0
* -----------------------------------------------
*/
func console_is_registered
#if ENABLE_ASSERTIONS
/* Assert that r0 isn't a NULL pointer */
cmp r0, #0
ASM_ASSERT(ne)
#endif /* ENABLE_ASSERTIONS */
push {r6}
ldr r6, =console_list
ldr r6, [r6] /* R6 = first console struct */
check_registered_loop:
cmp r6, #0 /* Check if end of list */
beq console_not_registered
cmp r0, r6 /* Check if the pointers are different */
beq console_registered
ldr r6, [r6, #CONSOLE_T_NEXT] /* Get pointer to next struct */
b check_registered_loop
console_not_registered:
mov r0, #0
pop {r6}
bx lr
console_registered:
mov r0, #1
pop {r6}
bx lr
endfunc console_is_registered
/* -----------------------------------------------
* 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 : r0 - global console state to move to
* Clobber list: r0, r1
* -----------------------------------------------
*/
func console_switch_state
ldr r1, =console_state
strb r0, [r1]
bx lr
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 : r0 - pointer to console_t struct
* : r1 - new active state mask
* Clobber list: r0, r1, r2
* -----------------------------------------------
*/
func console_set_scope
#if ENABLE_ASSERTIONS
ands r2, r1, #~CONSOLE_FLAG_SCOPE_MASK
ASM_ASSERT(eq)
#endif /* ENABLE_ASSERTIONS */
ldr r2, [r0, #CONSOLE_T_FLAGS]
and r2, r2, #~CONSOLE_FLAG_SCOPE_MASK
orr r2, r2, r1
str r2, [r0, #CONSOLE_T_FLAGS]
bx lr
endfunc console_set_scope
/* ---------------------------------------------
* int console_putc(int c)
* Function to output a character. Calls all
* active console's putc() handlers in succession.
* In : r0 - character to be printed
* Out: r0 - printed character on success, or < 0
if at least one console had an error
* Clobber list : r0, r1, r2
* ---------------------------------------------
*/
func console_putc
push {r4-r6, lr}
mov r5, #ERROR_NO_VALID_CONSOLE /* R5 = current return value */
mov r4, r0 /* R4 = character to print */
ldr r6, =console_list
ldr r6, [r6] /* R6 = first console struct */
putc_loop:
cmp r6, #0
beq putc_done
ldr r1, =console_state
ldrb r1, [r1]
ldr r2, [r6, #CONSOLE_T_FLAGS]
tst r1, r2
beq putc_continue
ldr r2, [r6, #CONSOLE_T_PUTC]
cmp r2, #0
beq putc_continue
mov r0, r4
mov r1, r6
blx r2
cmp r5, #ERROR_NO_VALID_CONSOLE /* update R5 if it's NOVALID */
cmpne r0, #0 /* else update it if R0 < 0 */
movlt r5, r0
putc_continue:
ldr r6, [r6] /* R6 = next struct */
b putc_loop
putc_done:
mov r0, r5
pop {r4-r6, pc}
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 : r0 - read character, or < 0 on error
* Clobber list : r0, r1
* ---------------------------------------------
*/
func console_getc
push {r5-r6, lr}
getc_try_again:
mov r5, #ERROR_NO_VALID_CONSOLE /* R5 = current return value */
ldr r6, =console_list
ldr r6, [r6] /* R6 = first console struct */
cmp r6, #0
bne getc_loop
mov r0, r5 /* If no consoles registered */
pop {r5-r6, pc} /* return immediately. */
getc_loop:
ldr r0, =console_state
ldrb r0, [r0]
ldr r1, [r6, #CONSOLE_T_FLAGS]
tst r0, r1
beq getc_continue
ldr r1, [r6, #CONSOLE_T_GETC]
cmp r1, #0
beq getc_continue
mov r0, r6
blx r1
cmp r0, #0 /* if R0 >= 0: return */
bge getc_found
cmp r5, #ERROR_NO_PENDING_CHAR /* may update R5 (NOCHAR has */
movne r5, r0 /* precedence vs real errors) */
getc_continue:
ldr r6, [r6] /* R6 = next struct */
cmp r6, #0
bne getc_loop
cmp r5, #ERROR_NO_PENDING_CHAR /* Keep scanning if at least */
beq getc_try_again /* one console returns NOCHAR */
mov r0, r5
getc_found:
pop {r5-r6, pc}
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: r0 - 0 on success, < 0 if at least one error
* Clobber list : r0, r1, r2
* ---------------------------------------------
*/
func console_flush
push {r5-r6, lr}
mov r5, #ERROR_NO_VALID_CONSOLE /* R5 = current return value */
ldr r6, =console_list
ldr r6, [r6] /* R6 = first console struct */
flush_loop:
cmp r6, #0
beq flush_done
ldr r1, =console_state
ldrb r1, [r1]
ldr r2, [r6, #CONSOLE_T_FLAGS]
tst r1, r2
beq flush_continue
ldr r1, [r6, #CONSOLE_T_FLUSH]
cmp r1, #0
beq flush_continue
mov r0, r6
blx r1
cmp r5, #ERROR_NO_VALID_CONSOLE /* update R5 if it's NOVALID */
cmpne r0, #0 /* else update it if R0 < 0 */
movlt r5, r0
flush_continue:
ldr r6, [r6] /* R6 = next struct */
b flush_loop
flush_done:
mov r0, r5
pop {r5-r6, pc}
endfunc console_flush

View File

@ -5,7 +5,9 @@
*/
#if MULTI_CONSOLE_API
#include "multi_console.S"
#if ERROR_DEPRECATED
#error "console.S is deprecated, platforms should no longer link it explicitly"
#endif
#else
#include "deprecated_console.S"
#endif

View File

@ -1,324 +0,0 @@
/*
* Copyright (c) 2015-2018, ARM Limited and Contributors. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#include <asm_macros.S>
#include <assert_macros.S>
#include <console.h>
.globl console_register
.globl console_unregister
.globl console_is_registered
.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_<driver>_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
* -----------------------------------------------
*/
func console_register
stp x21, x30, [sp, #-16]!
#if ENABLE_ASSERTIONS
/* Assert that x0 isn't a NULL pointer */
cmp x0, #0
ASM_ASSERT(ne)
/* Assert that the struct isn't in the stack */
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:
/* Assert that this struct isn't in the list */
mov x1, x0 /* Preserve x0 and x30 */
bl console_is_registered
cmp x0, #0
ASM_ASSERT(eq)
mov x0, x1
#endif /* ENABLE_ASSERTIONS */
adrp x21, console_list
ldr x1, [x21, :lo12:console_list] /* X1 = first struct in list */
str x0, [x21, :lo12:console_list] /* list head = new console */
str x1, [x0, #CONSOLE_T_NEXT] /* new console next ptr = X1 */
mov x0, #1
ldp x21, x30, [sp], #16
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
* -----------------------------------------------
*/
func console_unregister
#if ENABLE_ASSERTIONS
/* Assert that x0 isn't a NULL pointer */
cmp x0, #0
ASM_ASSERT(ne)
#endif /* ENABLE_ASSERTIONS */
stp x21, xzr, [sp, #-16]!
adrp x21, console_list
add x21, x21, :lo12:console_list /* X21 = ptr to first struct */
ldr x1, [x21] /* X1 = first struct */
unregister_loop:
cbz x1, unregister_not_found
cmp x0, x1
b.eq unregister_found
ldr x21, [x21] /* X21 = next ptr of struct */
ldr x1, [x21] /* X1 = next struct */
b unregister_loop
unregister_found:
ldr x1, [x1] /* X1 = next struct */
str x1, [x21] /* prev->next = cur->next */
ldp x21, xzr, [sp], #16
ret
unregister_not_found:
mov x0, #0 /* return NULL if not found */
ldp x21, xzr, [sp], #16
ret
endfunc console_unregister
/* -----------------------------------------------
* int console_is_registered(console_t *console)
* Function to detect if a specific console is
* registered or not.
* In: x0 - address of console_t struct to remove
* Out: x0 - 1 if it is registered, 0 if not.
* Clobber list: x0
* -----------------------------------------------
*/
func console_is_registered
#if ENABLE_ASSERTIONS
/* Assert that x0 isn't a NULL pointer */
cmp x0, #0
ASM_ASSERT(ne)
#endif /* ENABLE_ASSERTIONS */
stp x21, xzr, [sp, #-16]!
adrp x21, console_list
ldr x21, [x21, :lo12:console_list] /* X21 = first console struct */
check_registered_loop:
cbz x21, console_not_registered /* Check if end of list */
cmp x0, x21 /* Check if the pointers are different */
b.eq console_registered
ldr x21, [x21, #CONSOLE_T_NEXT] /* Get pointer to next struct */
b check_registered_loop
console_not_registered:
mov x0, #0
ldp x21, xzr, [sp], #16
ret
console_registered:
mov x0, #1
ldp x21, xzr, [sp], #16
ret
endfunc console_is_registered
/* -----------------------------------------------
* 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
* ---------------------------------------------
*/
func console_putc
stp x21, x30, [sp, #-16]!
stp x19, x20, [sp, #-16]!
mov w20, #ERROR_NO_VALID_CONSOLE /* W20 = current return value */
mov w19, w0 /* W19 = character to print */
adrp x21, console_list
ldr x21, [x21, :lo12:console_list] /* X21 = first console struct */
putc_loop:
cbz x21, putc_done
adrp x1, console_state
ldrb w1, [x1, :lo12:console_state]
ldr w2, [x21, #CONSOLE_T_FLAGS]
tst w1, w2
b.eq putc_continue
ldr x2, [x21, #CONSOLE_T_PUTC]
cbz x2, putc_continue
mov w0, w19
mov x1, x21
blr x2
cmp w20, #ERROR_NO_VALID_CONSOLE /* update W20 if it's NOVALID */
ccmp w0, #0, #0x8, ne /* else update it if W0 < 0 */
csel w20, w0, w20, lt
putc_continue:
ldr x21, [x21] /* X21 = next struct */
b putc_loop
putc_done:
mov w0, w20
ldp x19, x20, [sp], #16
ldp x21, x30, [sp], #16
ret
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
* ---------------------------------------------
*/
func console_getc
stp x30, xzr, [sp, #-16]!
stp x20, x21, [sp, #-16]!
getc_try_again:
mov w20, #ERROR_NO_VALID_CONSOLE /* W20 = current return value */
adrp x21, console_list
ldr x21, [x21, :lo12:console_list] /* X21 = first console struct */
cbnz x21, getc_loop
mov w0, w20 /* If no consoles registered */
ldp x20, x21, [sp], #16
ldp x30, xzr, [sp], #16
ret /* return immediately. */
getc_loop:
adrp x0, console_state
ldrb w0, [x0, :lo12:console_state]
ldr w1, [x21, #CONSOLE_T_FLAGS]
tst w0, w1
b.eq getc_continue
ldr x1, [x21, #CONSOLE_T_GETC]
cbz x1, getc_continue
mov x0, x21
blr x1
cmp w0, #0 /* if X0 >= 0: return */
b.ge getc_found
cmp w20, #ERROR_NO_PENDING_CHAR /* may update W20 (NOCHAR has */
csel w20, w20, w0, eq /* precedence vs real errors) */
getc_continue:
ldr x21, [x21] /* X21 = next struct */
cbnz x21, getc_loop
cmp w20, #ERROR_NO_PENDING_CHAR /* Keep scanning if at least */
b.eq getc_try_again /* one console returns NOCHAR */
mov w0, w20
getc_found:
ldp x20, x21, [sp], #16
ldp x30, xzr, [sp], #16
ret
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
* ---------------------------------------------
*/
func console_flush
stp x30, xzr, [sp, #-16]!
stp x20, x21, [sp, #-16]!
mov w20, #ERROR_NO_VALID_CONSOLE /* W20 = current return value */
adrp x21, console_list
ldr x21, [x21, :lo12:console_list] /* X21 = first console struct */
flush_loop:
cbz x21, flush_done
adrp x1, console_state
ldrb w1, [x1, :lo12:console_state]
ldr w2, [x21, #CONSOLE_T_FLAGS]
tst w1, w2
b.eq flush_continue
ldr x1, [x21, #CONSOLE_T_FLUSH]
cbz x1, flush_continue
mov x0, x21
blr x1
cmp w20, #ERROR_NO_VALID_CONSOLE /* update W20 if it's NOVALID */
ccmp w0, #0, #0x8, ne /* else update it if W0 < 0 */
csel w20, w0, w20, lt
flush_continue:
ldr x21, [x21] /* X21 = next struct */
b flush_loop
flush_done:
mov w0, w20
ldp x20, x21, [sp], #16
ldp x30, xzr, [sp], #16
ret
endfunc console_flush

View File

@ -0,0 +1,122 @@
/*
* Copyright (c) 2018, ARM Limited and Contributors. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#if MULTI_CONSOLE_API
#include <assert.h>
#include <drivers/console.h>
console_t *console_list;
uint8_t console_state = CONSOLE_FLAG_BOOT;
int console_register(console_t *console)
{
IMPORT_SYM(console_t *, __STACKS_START__, stacks_start)
IMPORT_SYM(console_t *, __STACKS_END__, stacks_end)
/* Assert that the struct is not on the stack (common mistake). */
assert((console < stacks_start) || (console >= stacks_end));
/* Assert that we won't make a circle in the list. */
assert(!console_is_registered(console));
console->next = console_list;
console_list = console;
/* Return 1 for convenient tail-calling from console_xxx_register(). */
return 1;
}
console_t *console_unregister(console_t *to_be_deleted)
{
console_t **ptr;
assert(to_be_deleted != NULL);
for (ptr = &console_list; *ptr != NULL; ptr = &(*ptr)->next)
if (*ptr == to_be_deleted) {
*ptr = (*ptr)->next;
return to_be_deleted;
}
return NULL;
}
int console_is_registered(console_t *to_find)
{
console_t *console;
assert(to_find != NULL);
for (console = console_list; console != NULL; console = console->next)
if (console == to_find)
return 1;
return 0;
}
void console_switch_state(unsigned int new_state)
{
console_state = new_state;
}
void console_set_scope(console_t *console, unsigned int scope)
{
assert(console != NULL);
console->flags = (console->flags & ~CONSOLE_FLAG_SCOPE_MASK) | scope;
}
int console_putc(int c)
{
int err = ERROR_NO_VALID_CONSOLE;
console_t *console;
for (console = console_list; console != NULL; console = console->next)
if (console->flags & console_state) {
int ret = console->putc(c, console);
if ((err == ERROR_NO_VALID_CONSOLE) || (ret < err))
err = ret;
}
return err;
}
int console_getc(void)
{
int err = ERROR_NO_VALID_CONSOLE;
console_t *console;
do { /* Keep polling while at least one console works correctly. */
for (console = console_list; console != NULL;
console = console->next)
if (console->flags & console_state) {
int ret = console->getc(console);
if (ret >= 0)
return ret;
if (err != ERROR_NO_PENDING_CHAR)
err = ret;
}
} while (err == ERROR_NO_PENDING_CHAR);
return err;
}
int console_flush(void)
{
int err = ERROR_NO_VALID_CONSOLE;
console_t *console;
for (console = console_list; console != NULL; console = console->next)
if (console->flags & console_state) {
int ret = console->flush(console);
if ((err == ERROR_NO_VALID_CONSOLE) || (ret < err))
err = ret;
}
return err;
}
#endif /* MULTI_CONSOLE_API */

View File

@ -52,8 +52,9 @@ typedef struct console {
* implementation, e.g. console_16550_register() from <uart_16550.h>. 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);
/* Remove a single console_t instance from the console list. Return a pointer to
* the console that was removed if it was found, or NULL if not. */
console_t *console_unregister(console_t *console);
/* Returns 1 if this console is already registered, 0 if not */
int console_is_registered(console_t *console);
/*

View File

@ -48,6 +48,23 @@ Arm System Guidance for Infrastructure / Mobile FVP platforms
:F: plat/arm/board/sgi575/
:F: plat/arm/board/sgm775/
Console API framework
---------------------
:M: Julius Werner <jwerner@chromium.org>
:G: `jwerner-chromium`_
:F: drivers/console/
:F: include/drivers/console.h
:F: plat/common/aarch64/crash_console_helpers.S
coreboot support libraries
--------------------------
:M: Julius Werner <jwerner@chromium.org>
:G: `jwerner-chromium`_
:F: drivers/coreboot/
:F: include/drivers/coreboot/
:F: include/lib/coreboot.h
:F: lib/coreboot/
eMMC/UFS drivers
----------------
:M: Haojian Zhuang <haojian.zhuang@linaro.org>

View File

@ -15,8 +15,7 @@ PLAT_INCLUDES := -Iinclude/plat/arm/common \
include lib/libfdt/libfdt.mk
PLAT_BL_COMMON_SOURCES := drivers/console/${ARCH}/console.S \
drivers/ti/uart/${ARCH}/16550_console.S \
PLAT_BL_COMMON_SOURCES := drivers/ti/uart/${ARCH}/16550_console.S \
${XLAT_TABLES_LIB_SRCS} \
${AW_PLAT}/common/plat_helpers.S \
${AW_PLAT}/common/sunxi_common.c

View File

@ -16,77 +16,167 @@
.globl plat_crash_console_putc
.globl plat_crash_console_flush
#if MULTI_CONSOLE_API
#if !MULTI_CONSOLE_API
#error "This crash console implementation only works with the MULTI_CONSOLE_API!"
#endif
/* -----------------------------------------------------
* 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.
* Spinlock to syncronize access to crash_console_triggered. We cannot
* acquire spinlocks when the cache is disabled, so in some cases (like
* late during CPU suspend) some risk remains.
*/
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
.section .data.crash_console_spinlock
define_asm_spinlock crash_console_spinlock
/* -----------------------------------------------------
* void plat_crash_console_putc(int character)
* Output through the normal console by default.
* -----------------------------------------------------
/*
* Flag to make sure that only one CPU can write a crash dump even if
* multiple crash at the same time. Interleaving crash dumps on the same
* console would just make the output unreadable, so it's better to only
* get a single but uncorrupted dump. This also means that we don't have
* to duplicate the reg_stash below for each CPU.
*/
func plat_crash_console_putc
b console_putc
endfunc plat_crash_console_putc
.section .data.crash_console_triggered
crash_console_triggered: .byte 0
/* -----------------------------------------------------
* void plat_crash_console_flush(void)
* Flush normal console by default.
* -----------------------------------------------------
/*
* Space to stash away some register values while we're calling into
* console drivers and don't have a real stack available. We need x14,
* x15 and x30 for bookkeeping within the plat_crash_console functions
* themselves, and some console drivers use x16 and x17 as additional
* scratch space that is not preserved by the main crash reporting
* framework. (Note that x16 and x17 should really never be expected to
* retain their values across any function call, even between carefully
* designed assembly functions, since the linker is always free to
* insert a function call veneer that uses these registers as scratch
* space at any time. The current crash reporting framework doesn't
* really respect that, but since TF is usually linked as a single
* contiguous binary of less than 128MB, it seems to work in practice.)
*/
func plat_crash_console_flush
b console_flush
endfunc plat_crash_console_flush
.section .data.crash_console_reg_stash
.align 3
crash_console_reg_stash: .quad 0, 0, 0, 0, 0
#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.
* -----------------------------------------------------
/* --------------------------------------------------------------------
* int plat_crash_console_init(void)
* Takes the crash console spinlock (if possible) and checks the trigger
* flag to make sure we're the first CPU to dump. If not, return an
* error (so crash dumping will fail but the CPU will still call
* plat_panic_handler() which may do important platform-specific tasks
* that may be needed on all crashing CPUs). In either case, the lock
* will be released so other CPUs can make forward progress on this.
* Clobbers: x0 - x4, x30
* --------------------------------------------------------------------
*/
func plat_crash_console_init
mov x0, #0
#if defined(IMAGE_BL31)
mov x4, x30 /* x3 and x4 are not clobbered by spin_lock() */
mov x3, #0 /* return value */
mrs x1, sctlr_el3
tst x1, #SCTLR_C_BIT
beq skip_spinlock /* can't synchronize when cache disabled */
adrp x0, crash_console_spinlock
add x0, x0, :lo12:crash_console_spinlock
bl spin_lock
skip_spinlock:
adrp x1, crash_console_triggered
add x1, x1, :lo12:crash_console_triggered
ldarb w2, [x1]
cmp w2, #0
bne init_error
mov x3, #1 /* set return value to success */
stlrb w3, [x1]
init_error:
bl spin_unlock /* harmless if we didn't acquire the lock */
mov x0, x3
ret x4
#else /* Only one CPU in BL1/BL2, no need to synchronize anything */
mov x0, #1
ret
#endif
endfunc plat_crash_console_init
/* --------------------------------------------------------------------
* int plat_crash_console_putc(char c)
* Prints the character on all consoles registered with the console
* framework that have CONSOLE_FLAG_CRASH set. Note that this is only
* helpful for crashes that occur after the platform intialization code
* has registered a console. Platforms using this implementation need to
* ensure that all console drivers they use that have the CRASH flag set
* support this (i.e. are written in assembly and comply to the register
* clobber requirements of plat_crash_console_putc().
* --------------------------------------------------------------------
*/
func plat_crash_console_putc
adrp x1, crash_console_reg_stash
add x1, x1, :lo12:crash_console_reg_stash
stp x14, x15, [x1]
stp x16, x17, [x1, #16]
str x30, [x1, #32]
mov w14, w0 /* W14 = character to print */
adrp x15, console_list
ldr x15, [x15, :lo12:console_list] /* X15 = first console struct */
putc_loop:
cbz x15, putc_done
ldr w1, [x15, #CONSOLE_T_FLAGS]
tst w1, #CONSOLE_FLAG_CRASH
b.eq putc_continue
ldr x2, [x15, #CONSOLE_T_PUTC]
cbz x2, putc_continue
mov x1, x15
blr x2
mov w0, w14
putc_continue:
ldr x15, [x15] /* X15 = next struct */
b putc_loop
putc_done:
adrp x1, crash_console_reg_stash
add x1, x1, :lo12:crash_console_reg_stash
ldp x14, x15, [x1]
ldp x16, x17, [x1, #16]
ldr x30, [x1, #32]
ret
endfunc plat_crash_console_putc
/* --------------------------------------------------------------------
* int plat_crash_console_flush(char c)
* Flushes all consoles registered with the console framework that have
* CONSOLE_FLAG_CRASH set. Same requirements as putc().
* --------------------------------------------------------------------
*/
func plat_crash_console_flush
adrp x1, crash_console_reg_stash
add x1, x1, :lo12:crash_console_reg_stash
stp x30, x15, [x1]
stp x16, x17, [x1, #16]
adrp x15, console_list
ldr x15, [x15, :lo12:console_list] /* X15 = first console struct */
flush_loop:
cbz x15, flush_done
ldr w1, [x15, #CONSOLE_T_FLAGS]
tst w1, #CONSOLE_FLAG_CRASH
b.eq flush_continue
ldr x2, [x15, #CONSOLE_T_FLUSH]
cbz x2, flush_continue
mov x0, x15
blr x2
flush_continue:
ldr x15, [x15] /* X15 = next struct */
b flush_loop
flush_done:
adrp x1, crash_console_reg_stash
add x1, x1, :lo12:crash_console_reg_stash
ldp x30, x15, [x1]
ldp x16, x17, [x1, #16]
ret
endfunc plat_crash_console_flush
#endif

View File

@ -40,65 +40,6 @@ func plat_report_exception
endfunc plat_report_exception
#if !ERROR_DEPRECATED
#if MULTI_CONSOLE_API
/* -----------------------------------------------------
* 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
mov x0, #0
ret
@ -111,7 +52,6 @@ endfunc plat_crash_console_putc
func plat_crash_console_flush
ret
endfunc plat_crash_console_flush
#endif
#endif /* ERROR_DEPRECATED */
/* -----------------------------------------------------

View File

@ -26,7 +26,6 @@ BL31_SOURCES += plat/imx/common/lpuart_console.S \
lib/xlat_tables/xlat_tables_common.c \
lib/cpus/aarch64/cortex_a53.S \
lib/cpus/aarch64/cortex_a72.S \
drivers/console/aarch64/console.S \
drivers/arm/cci/cci.c \
${IMX_GIC_SOURCES} \

View File

@ -25,7 +25,6 @@ BL31_SOURCES += plat/imx/common/lpuart_console.S \
lib/xlat_tables/xlat_tables_common.c \
lib/xlat_tables/aarch64/xlat_tables.c \
lib/cpus/aarch64/cortex_a35.S \
drivers/console/aarch64/console.S \
${IMX_GIC_SOURCES} \
include plat/imx/common/sci/sci_api.mk

View File

@ -28,8 +28,7 @@ PLAT_INCLUDES := -Iplat/layerscape/board/ls1043/include \
-Iinclude/drivers/io
PLAT_BL_COMMON_SOURCES := drivers/console/aarch64/console.S \
plat/layerscape/common/aarch64/ls_console.S
PLAT_BL_COMMON_SOURCES := plat/layerscape/common/aarch64/ls_console.S
LS1043_CPU_LIBS := lib/cpus/${ARCH}/aem_generic.S

View File

@ -96,7 +96,6 @@ PLAT_INCLUDES := -I$(PLAT_FAMILY_BASE)/$(PLAT) \
$(ATF_INCLUDES)
PLAT_BL_COMMON_SOURCES := $(PLAT_COMMON_BASE)/aarch64/a3700_common.c \
drivers/console/aarch64/console.S \
$(MARVELL_COMMON_BASE)/marvell_cci.c \
$(MARVELL_DRV_BASE)/uart/a3700_console.S

View File

@ -55,7 +55,6 @@ PLAT_INCLUDES := -I$(PLAT_FAMILY_BASE)/$(PLAT) \
$(ATF_INCLUDES)
PLAT_BL_COMMON_SOURCES := $(PLAT_COMMON_BASE)/aarch64/a8k_common.c \
drivers/console/aarch64/console.S \
drivers/ti/uart/aarch64/16550_console.S
BLE_PORTING_SOURCES := $(PLAT_FAMILY_BASE)/$(PLAT)/board/dram_port.c \

View File

@ -14,8 +14,7 @@ GXBB_GIC_SOURCES := drivers/arm/gic/common/gic_common.c \
drivers/arm/gic/v2/gicv2_helpers.c \
plat/common/plat_gicv2.c
PLAT_BL_COMMON_SOURCES := drivers/console/aarch64/multi_console.S \
drivers/meson/console/aarch64/meson_console.S \
PLAT_BL_COMMON_SOURCES := drivers/meson/console/aarch64/meson_console.S \
plat/meson/gxbb/gxbb_common.c \
plat/meson/gxbb/gxbb_topology.c \
${XLAT_TABLES_LIB_SRCS}

View File

@ -34,7 +34,6 @@ PLAT_BL_COMMON_SOURCES := lib/xlat_tables/aarch64/xlat_tables.c \
BL31_SOURCES += ${RK_GIC_SOURCES} \
drivers/arm/cci/cci.c \
drivers/console/aarch64/console.S \
drivers/ti/uart/aarch64/16550_console.S \
drivers/delay_timer/delay_timer.c \
drivers/delay_timer/generic_delay_timer.c \

View File

@ -31,7 +31,6 @@ PLAT_BL_COMMON_SOURCES := lib/xlat_tables/xlat_tables_common.c \
BL31_SOURCES += ${RK_GIC_SOURCES} \
drivers/arm/cci/cci.c \
drivers/console/aarch64/console.S \
drivers/ti/uart/aarch64/16550_console.S \
drivers/delay_timer/delay_timer.c \
drivers/delay_timer/generic_delay_timer.c \

View File

@ -37,7 +37,6 @@ PLAT_BL_COMMON_SOURCES := lib/xlat_tables/xlat_tables_common.c \
BL31_SOURCES += ${RK_GIC_SOURCES} \
drivers/arm/cci/cci.c \
drivers/console/aarch64/console.S \
drivers/ti/uart/aarch64/16550_console.S \
drivers/delay_timer/delay_timer.c \
drivers/delay_timer/generic_delay_timer.c \

View File

@ -10,8 +10,7 @@ include lib/xlat_tables_v2/xlat_tables.mk
PLAT_INCLUDES := -Iinclude/common/tbbr \
-Iplat/rpi3/include
PLAT_BL_COMMON_SOURCES := drivers/console/aarch64/console.S \
drivers/ti/uart/aarch64/16550_console.S \
PLAT_BL_COMMON_SOURCES := drivers/ti/uart/aarch64/16550_console.S \
plat/rpi3/rpi3_common.c \
${XLAT_TABLES_LIB_SRCS}

View File

@ -35,8 +35,7 @@ include lib/libfdt/libfdt.mk
PLAT_BL_COMMON_SOURCES := plat/st/stm32mp1/stm32mp1_common.c
PLAT_BL_COMMON_SOURCES += drivers/console/aarch32/console.S \
drivers/st/uart/aarch32/stm32_console.S
PLAT_BL_COMMON_SOURCES += drivers/st/uart/aarch32/stm32_console.S
ifneq (${ENABLE_STACK_PROTECTOR},0)
PLAT_BL_COMMON_SOURCES += plat/st/stm32mp1/stm32mp1_stack_protector.c

View File

@ -39,7 +39,6 @@ PLAT_INCLUDES += \
-I${PLAT_PATH}/common/drivers/ti_sci \
K3_CONSOLE_SOURCES += \
drivers/console/aarch64/console.S \
drivers/ti/uart/aarch64/16550_console.S \
${PLAT_PATH}/common/k3_console.c \