Unverified Commit 040f1e69 authored by davidcunado-arm's avatar davidcunado-arm Committed by GitHub
Browse files

Merge pull request #1193 from jwerner-chromium/JW_coreboot

New console API and coreboot support [v4]
parents d2184052 1c5f5031
......@@ -488,6 +488,7 @@ $(eval $(call assert_boolean,GENERATE_COT))
$(eval $(call assert_boolean,GICV2_G0_FOR_EL3))
$(eval $(call assert_boolean,HW_ASSISTED_COHERENCY))
$(eval $(call assert_boolean,LOAD_IMAGE_V2))
$(eval $(call assert_boolean,MULTI_CONSOLE_API))
$(eval $(call assert_boolean,NS_TIMER_SWITCH))
$(eval $(call assert_boolean,PL011_GENERIC_UART))
$(eval $(call assert_boolean,PROGRAMMABLE_RESET_ADDRESS))
......@@ -530,6 +531,7 @@ $(eval $(call add_define,GICV2_G0_FOR_EL3))
$(eval $(call add_define,HW_ASSISTED_COHERENCY))
$(eval $(call add_define,LOAD_IMAGE_V2))
$(eval $(call add_define,LOG_LEVEL))
$(eval $(call add_define,MULTI_CONSOLE_API))
$(eval $(call add_define,NS_TIMER_SWITCH))
$(eval $(call add_define,PL011_GENERIC_UART))
$(eval $(call add_define,PLAT_${PLAT}))
......
......@@ -9,13 +9,13 @@
#include <cpu_data.h>
#include <plat_macros.S>
#include <platform_def.h>
#include <utils_def.h>
.globl report_unhandled_exception
.globl report_unhandled_interrupt
.globl el3_panic
#if CRASH_REPORTING
#define REG_SIZE 0x8
/* ------------------------------------------------------
* The below section deals with dumping the system state
......@@ -92,7 +92,7 @@ test_size_list:
mov x6, x4
adr x4, print_spacer
bl asm_print_str
ldr x4, [x7], #REG_SIZE
ldr x4, [x7], #REGSZ
bl asm_print_hex
bl print_newline
b test_size_list
......@@ -114,9 +114,9 @@ func str_in_crash_buf_print
/* restore the crash buf address in x0 */
mrs x0, tpidr_el3
stp x8, x9, [x0]
stp x10, x11, [x0, #REG_SIZE * 2]
stp x12, x13, [x0, #REG_SIZE * 4]
stp x14, x15, [x0, #REG_SIZE * 6]
stp x10, x11, [x0, #REGSZ * 2]
stp x12, x13, [x0, #REGSZ * 4]
stp x14, x15, [x0, #REGSZ * 6]
b size_controlled_print
endfunc str_in_crash_buf_print
......@@ -136,7 +136,7 @@ endfunc str_in_crash_buf_print
add x0, x0, #CPU_DATA_CRASH_BUF_OFFSET
/* Store crash buffer address in tpidr_el3 */
msr tpidr_el3, x0
str x1, [x0, #REG_SIZE]
str x1, [x0, #REGSZ]
mov x1, sp
str x1, [x0]
.endm
......@@ -214,9 +214,9 @@ func do_crash_reporting
/* Retrieve the crash buf from tpidr_el3 */
mrs x0, tpidr_el3
/* Store x2 - x6, x30 in the crash buffer */
stp x2, x3, [x0, #REG_SIZE * 2]
stp x4, x5, [x0, #REG_SIZE * 4]
stp x6, x30, [x0, #REG_SIZE * 6]
stp x2, x3, [x0, #REGSZ * 2]
stp x4, x5, [x0, #REGSZ * 4]
stp x6, x30, [x0, #REGSZ * 6]
/* Initialize the crash console */
bl plat_crash_console_init
/* Verify the console is initialized */
......@@ -227,13 +227,13 @@ func do_crash_reporting
/* load the crash buf address */
mrs x0, tpidr_el3
/* report x30 first from the crash buf */
ldr x4, [x0, #REG_SIZE * 7]
ldr x4, [x0, #REGSZ * 7]
bl asm_print_hex
bl print_newline
/* Load the crash buf address */
mrs x0, tpidr_el3
/* Now mov x7 into crash buf */
str x7, [x0, #REG_SIZE * 7]
str x7, [x0, #REGSZ * 7]
/* Report x0 - x29 values stored in crash buf*/
/* Store the ascii list pointer in x6 */
......@@ -246,15 +246,15 @@ func do_crash_reporting
mrs x0, tpidr_el3
/* Store the rest of gp regs and print */
stp x16, x17, [x0]
stp x18, x19, [x0, #REG_SIZE * 2]
stp x20, x21, [x0, #REG_SIZE * 4]
stp x22, x23, [x0, #REG_SIZE * 6]
stp x18, x19, [x0, #REGSZ * 2]
stp x20, x21, [x0, #REGSZ * 4]
stp x22, x23, [x0, #REGSZ * 6]
bl size_controlled_print
/* Load the crash buf address */
mrs x0, tpidr_el3
stp x24, x25, [x0]
stp x26, x27, [x0, #REG_SIZE * 2]
stp x28, x29, [x0, #REG_SIZE * 4]
stp x26, x27, [x0, #REGSZ * 2]
stp x28, x29, [x0, #REGSZ * 4]
bl size_controlled_print
/* Print the el3 sys registers */
......
......@@ -1929,12 +1929,8 @@ Function : bl31\_plat\_runtime\_setup() [optional]
The purpose of this function is allow the platform to perform any BL31 runtime
setup just prior to BL31 exit during cold boot. The default weak
implementation of this function will invoke ``console_uninit()`` which will
suppress any BL31 runtime logs.
In ARM Standard platforms, this function will initialize the BL31 runtime
console which will cause all further BL31 logs to be output to the
runtime console.
implementation of this function will invoke ``console_switch_state()`` to switch
console output to consoles marked for use in the ``runtime`` state.
Function : bl31\_get\_next\_image\_info() [mandatory]
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
......@@ -2702,14 +2698,20 @@ 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. It requires that a
console is designated as the crash console by the platform which will be used to
print the register dump.
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.
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.
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 @@ Function : plat\_crash\_console\_init
Return : int
This API is used by the crash reporting mechanism to initialize the crash
console. It must only use the general purpose registers x0 to x4 to do the
console. It must only use the general purpose registers x0 through x7 to do the
initialization and returns 1 on success.
If you are trying to debug crashes before the console driver would normally get
registered, you can use this to register a driver from assembly with hardcoded
parameters. For example, you could register the 16550 driver like this:
::
.section .data.crash_console /* Reserve space for console structure */
crash_console:
.zero 6 * 8 /* console_16550_t has 6 8-byte words */
func plat_crash_console_init
ldr x0, =YOUR_16550_BASE_ADDR
ldr x1, =YOUR_16550_SRCCLK_IN_HZ
ldr x2, =YOUR_16550_TARGET_BAUD_RATE
adrp x3, crash_console
add x3, x3, :lo12:crash_console
b console_16550_register /* tail call, returns 1 on success */
endfunc plat_crash_console_init
If you're trying to debug crashes in BL1, you can call the console_xxx_core_init
function exported by some console drivers from here.
Function : plat\_crash\_console\_putc
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
......@@ -2736,6 +2759,12 @@ designated crash console. It must only use general purpose registers x1 and
x2 to do its work. The parameter and the return value are in general purpose
register x0.
If you have registered a normal console driver in ``plat_crash_console_init``,
you can keep the default implementation here (which calls ``console_putc()``).
If you're trying to debug crashes in BL1, you can call the console_xxx_core_putc
function exported by some console drivers from here.
Function : plat\_crash\_console\_flush
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
......@@ -2746,9 +2775,15 @@ Function : plat\_crash\_console\_flush
This API is used by the crash reporting mechanism to force write of all buffered
data on the designated crash console. It should only use general purpose
registers x0 and x1 to do its work. The return value is 0 on successful
registers x0 through x5 to do its work. The return value is 0 on successful
completion; otherwise the return value is -1.
If you have registered a normal console driver in ``plat_crash_console_init``,
you can keep the default implementation here (which calls ``console_flush()``).
If you're trying to debug crashes in BL1, you can call the console_xx_core_flush
function exported by some console drivers from here.
Build flags
-----------
......
......@@ -5,6 +5,7 @@
*/
#include <arch.h>
#include <asm_macros.S>
#include <assert_macros.S>
#include <pl011.h>
/*
......@@ -13,15 +14,21 @@
*/
#include "../../../console/aarch64/console.S"
/*
* "core" functions are low-level implementations that don't require
* writable memory and are thus safe to call in BL1 crash context.
*/
.globl console_pl011_core_init
.globl console_pl011_core_putc
.globl console_pl011_core_getc
.globl console_pl011_core_flush
.globl console_core_init
.globl console_core_putc
.globl console_core_getc
.globl console_core_flush
.globl console_pl011_putc
.globl console_pl011_getc
.globl console_pl011_flush
/* -----------------------------------------------
* int console_core_init(uintptr_t base_addr,
* int console_pl011_core_init(uintptr_t base_addr,
* unsigned int uart_clk, unsigned int baud_rate)
* Function to initialize the console without a
* C Runtime to print debug information. This
......@@ -34,7 +41,7 @@
* Clobber list : x1, x2, x3, x4
* -----------------------------------------------
*/
func console_core_init
func console_pl011_core_init
/* Check the input base address */
cbz x0, core_init_fail
#if !PL011_GENERIC_UART
......@@ -71,10 +78,54 @@ func console_core_init
core_init_fail:
mov w0, wzr
ret
endfunc console_core_init
endfunc console_pl011_core_init
#if MULTI_CONSOLE_API
.globl console_pl011_register
/* -----------------------------------------------
* int console_pl011_register(console_pl011_t *console,
uintptr_t base, uint32_t clk, uint32_t baud)
* Function to initialize and register a new PL011
* console. Storage passed in for the console struct
* *must* be persistent (i.e. not from the stack).
* In: x0 - UART register base address
* w1 - UART clock in Hz
* w2 - Baud rate
* x3 - pointer to empty console_pl011_t struct
* Out: return 1 on success, 0 on error
* Clobber list : x0, x1, x2, x6, x7, x14
* -----------------------------------------------
*/
func console_pl011_register
mov x7, x30
mov x6, x3
cbz x6, register_fail
str x0, [x6, #CONSOLE_T_PL011_BASE]
bl console_pl011_core_init
cbz x0, register_fail
mov x0, x6
mov x30, x7
finish_console_register pl011
register_fail:
ret x7
endfunc console_pl011_register
#else
.globl console_core_init
.globl console_core_putc
.globl console_core_getc
.globl console_core_flush
.equ console_core_init,console_pl011_core_init
.equ console_core_putc,console_pl011_core_putc
.equ console_core_getc,console_pl011_core_getc
.equ console_core_flush,console_pl011_core_flush
#endif
/* --------------------------------------------------------
* int console_core_putc(int c, uintptr_t base_addr)
* int console_pl011_core_putc(int c, uintptr_t base_addr)
* Function to output a character over the console. It
* returns the character printed on success or -1 on error.
* In : w0 - character to be printed
......@@ -83,9 +134,12 @@ endfunc console_core_init
* Clobber list : x2
* --------------------------------------------------------
*/
func console_core_putc
/* Check the input parameter */
cbz x1, putc_error
func console_pl011_core_putc
#if ENABLE_ASSERTIONS
cmp x1, #0
ASM_ASSERT(ne)
#endif /* ENABLE_ASSERTIONS */
/* Prepend '\r' to '\n' */
cmp w0, #0xA
b.ne 2f
......@@ -101,36 +155,75 @@ func console_core_putc
tbnz w2, #PL011_UARTFR_TXFF_BIT, 2b
str w0, [x1, #UARTDR]
ret
putc_error:
mov w0, #-1
ret
endfunc console_core_putc
endfunc console_pl011_core_putc
/* --------------------------------------------------------
* int console_pl011_putc(int c, console_pl011_t *console)
* Function to output a character over the console. It
* returns the character printed on success or -1 on error.
* In : w0 - character to be printed
* x1 - pointer to console_t structure
* Out : return -1 on error else return character.
* Clobber list : x2
* --------------------------------------------------------
*/
func console_pl011_putc
#if ENABLE_ASSERTIONS
cmp x1, #0
ASM_ASSERT(ne)
#endif /* ENABLE_ASSERTIONS */
ldr x1, [x1, #CONSOLE_T_PL011_BASE]
b console_pl011_core_putc
endfunc console_pl011_putc
/* ---------------------------------------------
* int console_core_getc(uintptr_t base_addr)
* int console_pl011_core_getc(uintptr_t base_addr)
* Function to get a character from the console.
* It returns the character grabbed on success
* or -1 on error.
* or -1 if no character is available.
* In : x0 - console base address
* Out: w0 - character if available, else -1
* Clobber list : x0, x1
* ---------------------------------------------
*/
func console_core_getc
cbz x0, getc_error
1:
func console_pl011_core_getc
#if ENABLE_ASSERTIONS
cmp x0, #0
ASM_ASSERT(ne)
#endif /* ENABLE_ASSERTIONS */
/* Check if the receive FIFO is empty */
ldr w1, [x0, #UARTFR]
tbnz w1, #PL011_UARTFR_RXFE_BIT, 1b
tbnz w1, #PL011_UARTFR_RXFE_BIT, no_char
ldr w1, [x0, #UARTDR]
mov w0, w1
ret
getc_error:
mov w0, #-1
no_char:
mov w0, #ERROR_NO_PENDING_CHAR
ret
endfunc console_core_getc
endfunc console_pl011_core_getc
/* ---------------------------------------------
* int console_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_core_flush(uintptr_t base_addr)
* int console_pl011_core_flush(uintptr_t base_addr)
* Function to force a write of all buffered
* data that hasn't been output.
* In : x0 - console base address
......@@ -138,9 +231,11 @@ endfunc console_core_getc
* Clobber list : x0, x1
* ---------------------------------------------
*/
func console_core_flush
cbz x0, flush_error
func console_pl011_core_flush
#if ENABLE_ASSERTIONS
cmp x0, #0
ASM_ASSERT(ne)
#endif /* ENABLE_ASSERTIONS */
1:
/* Loop until the transmit FIFO is empty */
ldr w1, [x0, #UARTFR]
......@@ -148,7 +243,22 @@ func console_core_flush
mov w0, #0
ret
flush_error:
mov w0, #-1
ret
endfunc console_core_flush
endfunc console_pl011_core_flush
/* ---------------------------------------------
* int console_pl011_flush(console_pl011_t *console)
* Function to force a write of all buffered
* data that hasn't been output.
* In : x0 - pointer to console_t structure
* Out : return -1 on error else return 0.
* Clobber list : x0, x1
* ---------------------------------------------
*/
func console_pl011_flush
#if ENABLE_ASSERTIONS
cmp x0, #0
ASM_ASSERT(ne)
#endif /* ENABLE_ASSERTIONS */
ldr x0, [x0, #CONSOLE_T_PL011_BASE]
b console_pl011_core_flush
endfunc console_pl011_flush
......@@ -5,16 +5,22 @@
*/
#include <arch.h>
#include <asm_macros.S>
#include <assert_macros.S>
#include <cadence/cdns_uart.h>
.globl console_core_init
.globl console_core_putc
.globl console_core_getc
.globl console_core_flush
/*
* "core" functions are low-level implementations that don't require
* writable memory and are thus safe to call in BL1 crash context.
*/
.globl console_cdns_core_init
.globl console_cdns_core_putc
.globl console_cdns_core_getc
.globl console_cdns_putc
.globl console_cdns_getc
/* -----------------------------------------------
* int console_core_init(unsigned long base_addr,
* unsigned int uart_clk, unsigned int baud_rate)
* int console_cdns_core_init(uintptr_t base_addr)
* Function to initialize the console without a
* C Runtime to print debug information. This
* function will be accessed by console_init and
......@@ -23,18 +29,13 @@
* the HW (baud, ...) and only enable the trans-
* mitter and receiver here.
* In: x0 - console base address
* w1 - Uart clock in Hz
* w2 - Baud rate
* Out: return 1 on success else 0 on error
* Clobber list : x1, x2, x3
* -----------------------------------------------
*/
func console_core_init
func console_cdns_core_init
/* Check the input base address */
cbz x0, core_init_fail
/* Check baud rate and uart clock for sanity */
cbz w1, core_init_fail
cbz w2, core_init_fail
/* RX/TX enabled & reset */
mov w3, #(R_UART_CR_TX_EN | R_UART_CR_RX_EN | R_UART_CR_TXRST | R_UART_CR_RXRST)
......@@ -45,10 +46,51 @@ func console_core_init
core_init_fail:
mov w0, wzr
ret
endfunc console_core_init
endfunc console_cdns_core_init
#if MULTI_CONSOLE_API
.globl console_cdns_register
/* -----------------------------------------------
* int console_cdns_register(console_cdns_t *console,
uintptr_t base, uint32_t clk, uint32_t baud)
* Function to initialize and register a new CDNS
* console. Storage passed in for the console struct
* *must* be persistent (i.e. not from the stack).
* In: x0 - UART register base address
* x1 - pointer to empty console_cdns_t struct
* Out: return 1 on success, 0 on error
* Clobber list : x0, x1, x2, x6, x7, x14
* -----------------------------------------------
*/
func console_cdns_register
mov x7, x30
mov x6, x1
cbz x6, register_fail
str x0, [x6, #CONSOLE_T_CDNS_BASE]
bl console_cdns_core_init
cbz x0, register_fail
mov x0, x6
mov x30, v7
finish_console_register cdns
register_fail:
ret x7
endfunc console_cdns_register
#else
.globl console_core_init
.globl console_core_putc
.globl console_core_getc
.globl console_core_flush
.equ console_core_init,console_cdns_core_init
.equ console_core_putc,console_cdns_core_putc
.equ console_core_getc,console_cdns_core_getc
#endif
/* --------------------------------------------------------
* int console_core_putc(int c, unsigned long base_addr)
* int console_cdns_core_putc(int c, uintptr_t base_addr)
* Function to output a character over the console. It
* returns the character printed on success or -1 on error.
* In : w0 - character to be printed
......@@ -57,9 +99,12 @@ endfunc console_core_init
* Clobber list : x2
* --------------------------------------------------------
*/
func console_core_putc
/* Check the input parameter */
cbz x1, putc_error
func console_cdns_core_putc
#if ENABLE_ASSERTIONS
cmp x1, #0
ASM_ASSERT(ne)
#endif /* ENABLE_ASSERTIONS */
/* Prepend '\r' to '\n' */
cmp w0, #0xA
b.ne 2f
......@@ -75,36 +120,76 @@ func console_core_putc
tbnz w2, #UART_SR_INTR_TFUL_BIT, 2b
str w0, [x1, #R_UART_TX]
ret
putc_error:
mov w0, #-1
ret
endfunc console_core_putc
endfunc console_cdns_core_putc
/* --------------------------------------------------------
* int console_cdns_putc(int c, console_cdns_t *cdns)
* Function to output a character over the console. It
* returns the character printed on success or -1 on error.
* In : w0 - character to be printed
* x1 - pointer to console_t structure
* Out : return -1 on error else return character.
* Clobber list : x2
* --------------------------------------------------------
*/
func console_cdns_putc
#if ENABLE_ASSERTIONS
cmp x1, #0
ASM_ASSERT(ne)
#endif /* ENABLE_ASSERTIONS */
ldr x1, [x1, #CONSOLE_T_CDNS_BASE]
b console_cdns_core_putc
endfunc console_cdns_putc
/* ---------------------------------------------
* int console_core_getc(unsigned long base_addr)
* int console_cdns_core_getc(uintptr_t base_addr)
* Function to get a character from the console.
* It returns the character grabbed on success
* or -1 on error.
* or -1 if no character is available.
* In : x0 - console base address
* Out: w0 - character if available, else -1
* Clobber list : x0, x1
* ---------------------------------------------
*/
func console_core_getc
cbz x0, getc_error
1:
func console_cdns_core_getc
#if ENABLE_ASSERTIONS
cmp x0, #0
ASM_ASSERT(ne)
#endif /* ENABLE_ASSERTIONS */
/* Check if the receive FIFO is empty */
ldr w1, [x0, #R_UART_SR]
tbnz w1, #UART_SR_INTR_REMPTY_BIT, 1b
tbnz w1, #UART_SR_INTR_REMPTY_BIT, no_char
ldr w1, [x0, #R_UART_RX]
mov w0, w1
ret
getc_error:
mov w0, #-1
no_char:
mov w0, #ERROR_NO_PENDING_CHAR
ret
endfunc console_core_getc
endfunc console_cdns_core_getc
/* ---------------------------------------------
* int console_cdns_getc(console_cdns_t *console)
* Function to get a character from the console.
* It returns the character grabbed on success
* or -1 if no character is available.
* In : x0 - pointer to console_t structure
* Out: w0 - character if available, else -1
* Clobber list : x0, x1
* ---------------------------------------------
*/
func console_cdns_getc
#if ENABLE_ASSERTIONS
cmp x0, #0
ASM_ASSERT(ne)
#endif /* ENABLE_ASSERTIONS */
ldr x0, [x0, #CONSOLE_T_CDNS_BASE]
b console_cdns_core_getc
endfunc console_cdns_getc
/* ---------------------------------------------
* int console_core_flush(uintptr_t base_addr)
* DEPRECATED: Not used with MULTI_CONSOLE_API!
* Function to force a write of all buffered
* data that hasn't been output.
* In : x0 - console base address
......
/*
* 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 <asm_macros.S>
.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
/*
* Copyright (c) 2015-2017, ARM Limited and Contributors. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#include <asm_macros.S>
/*
* 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
/*
* Copyright (c) 2015-2017, 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_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, 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
......@@ -4,99 +4,171 @@
* SPDX-License-Identifier: BSD-3-Clause
*/
#include <asm_macros.S>
#include <console_macros.S>
/*
* This file contains a skeleton console implementation that can
* be used as basis for a real console implementation by platforms
* that do not contain PL011 hardware.
* This file contains a skeleton console driver that can be used as
* basis for a real console driver. Console drivers in Trusted Firmware
* can be instantiated multiple times. Each instance is described by a
* separate console_t structure which must be registered with the common
* console framework via console_register(). Console drivers should
* define a console_xxx_register() function that initializes a new
* console_t structure passed in from the caller and registers it after
* initializing the console hardware. Drivers may define their own
* structures extending console_t to store private driver information.
* Console drivers *MUST* take care that the console callbacks they
* implement only change registers allowed in the clobber lists defined
* in this file. (Note that in addition to the explicit clobber lists,
* any function may always clobber the intra-procedure-call registers
* X16 and X17, but may never depend on them retaining their values
* across any function call.)
* Platforms using drivers based on this template need to enable
* MULTI_CONSOLE_API := 1 in their platform.mk.
*/
.globl console_core_init
.globl console_core_putc
.globl console_core_getc
.globl console_core_flush
.globl console_xxx_register
.globl console_xxx_putc
.globl console_xxx_getc
.globl console_xxx_flush
/* -----------------------------------------------
* int console_core_init(uintptr_t base_addr,
* unsigned int uart_clk, unsigned int baud_rate)
* Function to initialize the console without a
* C Runtime to print debug information. This
* function will be accessed by console_init and
* crash reporting.
* In: x0 - console base address
* w1 - Uart clock in Hz
* w2 - Baud rate
* Out: return 1 on success else 0 on error
* Clobber list : x1, x2
* int console_xxx_register(console_xxx_t *console,
* ...additional parameters as desired...)
* Function to initialize and register the console.
* The caller needs to pass an empty console_xxx_t
* structure in which *MUST* be allocated in
* persistent memory (e.g. a global or static local
* variable, *NOT* on the stack).
* In : x0 - pointer to empty console_t structure
* x1 through x7: additional parameters as desired
* Out: x0 - 1 on success, 0 on error
* Clobber list : x0 - x7
* -----------------------------------------------
*/
func console_core_init
/* Check the input base address */
cbz x0, core_init_fail
/* Check baud rate and uart clock for sanity */
cbz w1, core_init_fail
cbz w2, core_init_fail
/* Insert implementation here */
mov w0, #1
ret
core_init_fail:
mov w0, wzr
func console_xxx_register
/*
* Store parameters (e.g. hardware base address) in driver-specific
* console_xxx_t structure field if they will need to be retrieved
* by later console callback (e.g. putc).
* Example:
*/
str x1, [x0, #CONSOLE_T_XXX_BASE]
str x2, [x0, #CONSOLE_T_XXX_SOME_OTHER_VALUE]
/*
* Initialize console hardware, using x1 - x7 parameters as needed.
* Keep console_t pointer in x0 for later.
*/
/* Macro to finish up registration and return (needs valid x0 + x30). */
finish_console_register xxx
/* Jump here if hardware init fails or parameters are invalid. */
register_fail:
mov w0, #0
ret
endfunc console_core_init
endfunc console_xxx_register
/* --------------------------------------------------------
* int console_core_putc(int c, uintptr_t base_addr)
* int console_xxx_putc(int c, console_xxx_t *console)
* Function to output a character over the console. It
* returns the character printed on success or -1 on error.
* In : w0 - character to be printed
* x1 - console base address
* Out : return -1 on error else return character.
* Clobber list : x2
* x1 - pointer to console_t struct
* Out: w0 - printed character on success, < 0 on error.
* Clobber list : x0, x1, x2
* --------------------------------------------------------
*/
func console_core_putc
/* Check the input parameter */
cbz x1, putc_error
/* Insert implementation here */
func console_xxx_putc
/*
* Retrieve values we need (e.g. hardware base address) from
* console_xxx_t structure pointed to by x1.
* Example:
*/
ldr x1, [x1, #CONSOLE_T_XXX_BASE]
/*
* Write w0 to hardware.
*/
ret
/* Jump here if output fails for any reason. */
putc_error:
mov w0, #-1
ret
endfunc console_core_putc
endfunc console_xxx_putc
/* ---------------------------------------------
* int console_core_getc(uintptr_t base_addr)
* int console_xxx_getc(console_xxx_t *console)
* Function to get a character from the console.
* It returns the character grabbed on success
* or -1 on error.
* In : x0 - console base address
* Even though console_getc() is blocking, this
* callback has to be non-blocking and always
* return immediately to allow polling multiple
* drivers concurrently.
* Returns the character grabbed on success,
* ERROR_NO_PENDING_CHAR if no character was
* available at this time, or any value
* between -2 and -127 if there was an error.
* In : x0 - pointer to console_t struct
* Out: w0 - character on success,
* ERROR_NO_PENDING_CHAR if no char,
* < -1 on error
* Clobber list : x0, x1
* ---------------------------------------------
*/
func console_core_getc
cbz x0, getc_error
/* Insert implementation here */
func console_xxx_getc
/*
* Retrieve values we need (e.g. hardware base address) from
* console_xxx_t structure pointed to by x0.
* Example:
*/
ldr x1, [x0, #CONSOLE_T_XXX_BASE]
/*
* Try to read character into w0 from hardware.
*/
ret
/* Jump here if there is no character available at this time. */
getc_no_char:
mov w0, #ERROR_NO_PENDING_CHAR
ret
/* Jump here if there was any hardware error. */
getc_error:
mov w0, #-1
mov w0, #-2 /* may pick error codes between -2 and -127 */
ret
endfunc console_core_getc
endfunc console_xxx_getc
/* ---------------------------------------------
* int console_core_flush(uintptr_t base_addr)
* int console_xxx_flush(console_xxx_t *console)
* Function to force a write of all buffered
* data that hasn't been output.
* In : x0 - console base address
* Out : return -1 on error else return 0.
* Clobber list : x0, x1
* In : x0 - pointer to console_xxx_t struct
* Out: w0 - 0 on success, < 0 on error
* Clobber list : x0, x1, x2, x3, x4, x5
* ---------------------------------------------
*/
func console_core_flush
cbz x0, flush_error
/* Insert implementation here */
func console_xxx_flush
/*
* Retrieve values we need (e.g. hardware base address) from
* console_xxx_t structure pointed to by x0.
* Example:
*/
ldr x1, [x0, #CONSOLE_T_XXX_BASE]
/*
* Flush all remaining output from hardware FIFOs. Do not return until
* all data has been flushed or there was an unrecoverable error.
*/
mov w0, #0
ret
/* Jump here if an unrecoverable error has been encountered. */
flush_error:
mov w0, #-1
ret
endfunc console_core_flush
endfunc console_xxx_flush
/*
* Copyright (c) 2017, ARM Limited and Contributors. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#include <asm_macros.S>
#include <cbmem_console.h>
#include <console_macros.S>
/*
* This driver implements access to coreboot's in-memory console
* (CBMEM console). For the original implementation, see
* <coreboot>/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
......@@ -6,15 +6,24 @@
#include <arch.h>
#include <asm_macros.S>
#include <assert_macros.S>
#include <console_macros.S>
#include <uart_16550.h>
.globl console_core_init
.globl console_core_putc
.globl console_core_getc
.globl console_core_flush
/*
* "core" functions are low-level implementations that don't require
* writable memory and are thus safe to call in BL1 crash context.
*/
.globl console_16550_core_init
.globl console_16550_core_putc
.globl console_16550_core_getc
.globl console_16550_putc
.globl console_16550_getc
/* -----------------------------------------------
* int console_core_init(unsigned long base_addr,
* int console_16550_core_init(uintptr_t base_addr,
* unsigned int uart_clk, unsigned int baud_rate)
* Function to initialize the console without a
* C Runtime to print debug information. This
......@@ -23,11 +32,11 @@
* In: x0 - console base address
* w1 - Uart clock in Hz
* w2 - Baud rate
* Out: return 1 on success
* Out: return 1 on success, 0 on error
* Clobber list : x1, x2, x3
* -----------------------------------------------
*/
func console_core_init
func console_16550_core_init
/* Check the input base address */
cbz x0, init_fail
/* Check baud rate and uart clock for sanity */
......@@ -63,12 +72,57 @@ func console_core_init
mov w3, #3
str w3, [x0, #UARTMCR]
mov w0, #1
ret
init_fail:
mov w0, #0
ret
endfunc console_core_init
endfunc console_16550_core_init
#if MULTI_CONSOLE_API
.globl console_16550_register
/* -----------------------------------------------
* int console_16550_register(console_16550_t *console,
uintptr_t base, uint32_t clk, uint32_t baud)
* Function to initialize and register a new 16550
* console. Storage passed in for the console struct
* *must* be persistent (i.e. not from the stack).
* In: x0 - UART register base address
* w1 - UART clock in Hz
* w2 - Baud rate
* x3 - pointer to empty console_16550_t struct
* Out: return 1 on success, 0 on error
* Clobber list : x0, x1, x2, x6, x7, x14
* -----------------------------------------------
*/
func console_16550_register
mov x7, x30
mov x6, x3
cbz x6, register_fail
str x0, [x6, #CONSOLE_T_16550_BASE]
bl console_16550_core_init
cbz x0, register_fail
mov x0, x6
mov x30, x7
finish_console_register 16550
register_fail:
ret x7
endfunc console_16550_register
#else
.globl console_core_init
.globl console_core_putc
.globl console_core_getc
.globl console_core_flush
.equ console_core_init,console_16550_core_init
.equ console_core_putc,console_16550_core_putc
.equ console_core_getc,console_16550_core_getc
#endif
/* --------------------------------------------------------
* int console_core_putc(int c, unsigned int base_addr)
* int console_16550_core_putc(int c, uintptr_t base_addr)
* Function to output a character over the console. It
* returns the character printed on success or -1 on error.
* In : w0 - character to be printed
......@@ -77,9 +131,11 @@ endfunc console_core_init
* Clobber list : x2
* --------------------------------------------------------
*/
func console_core_putc
/* Check the input parameter */
cbz x1, putc_error
func console_16550_core_putc
#if ENABLE_ASSERTIONS
cmp x1, #0
ASM_ASSERT(ne)
#endif /* ENABLE_ASSERTIONS */
/* Prepend '\r' to '\n' */
cmp w0, #0xA
......@@ -99,34 +155,75 @@ func console_core_putc
b.ne 2b
str w0, [x1, #UARTTX]
ret
putc_error:
mov w0, #-1
ret
endfunc console_core_putc
endfunc console_16550_core_putc
/* --------------------------------------------------------
* int console_16550_putc(int c, console_16550_t *console)
* Function to output a character over the console. It
* returns the character printed on success or -1 on error.
* In : w0 - character to be printed
* x1 - pointer to console_t structure
* Out : return -1 on error else return character.
* Clobber list : x2
* --------------------------------------------------------
*/
func console_16550_putc
#if ENABLE_ASSERTIONS
cmp x1, #0
ASM_ASSERT(ne)
#endif /* ENABLE_ASSERTIONS */
ldr x1, [x1, #CONSOLE_T_16550_BASE]
b console_16550_core_putc
endfunc console_16550_putc
/* ---------------------------------------------
* int console_core_getc(void)
* int console_16550_core_getc(uintptr_t base_addr)
* Function to get a character from the console.
* It returns the character grabbed on success
* or -1 on error.
* In : w0 - console base address
* Out : return -1 on error else return character.
* or -1 on if no character is available.
* In : x0 - console base address
* Out : w0 - character if available, else -1
* Clobber list : x0, x1
* ---------------------------------------------
*/
func console_core_getc
func console_16550_core_getc
#if ENABLE_ASSERTIONS
cmp x0, #0
ASM_ASSERT(ne)
#endif /* ENABLE_ASSERTIONS */
/* Check if the receive FIFO is empty */
1: ldr w1, [x0, #UARTLSR]
tbz w1, #UARTLSR_RDR_BIT, 1b
tbz w1, #UARTLSR_RDR_BIT, no_char
ldr w0, [x0, #UARTRX]
ret
getc_error:
mov w0, #-1
no_char:
mov w0, #ERROR_NO_PENDING_CHAR
ret
endfunc console_core_getc
endfunc console_16550_core_getc
/* ---------------------------------------------
* int console_16550_getc(console_16550_t *console)
* Function to get a character from the console.
* It returns the character grabbed on success
* or -1 on if no character is available.
* In : x0 - pointer to console_t stucture
* Out : w0 - character if available, else -1
* Clobber list : x0, x1
* ---------------------------------------------
*/
func console_16550_getc
#if ENABLE_ASSERTIONS
cmp x1, #0
ASM_ASSERT(ne)
#endif /* ENABLE_ASSERTIONS */
ldr x0, [x0, #CONSOLE_T_16550_BASE]
b console_16550_core_getc
endfunc console_16550_getc
/* ---------------------------------------------
* int console_core_flush(uintptr_t base_addr)
* DEPRECATED: Not used with MULTI_CONSOLE_API!
* Function to force a write of all buffered
* data that hasn't been output.
* In : x0 - console base address
......
/*
* 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 <console.h>
/*
* 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__ */
......@@ -7,6 +7,8 @@
#ifndef __PL011_H__
#define __PL011_H__
#include <console.h>
/* 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 <types.h>
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__ */
......@@ -7,6 +7,8 @@
#ifndef __CADENCE_UART_H__
#define __CADENCE_UART_H__
#include <console.h>
/* 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 <types.h>
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
......@@ -7,14 +7,69 @@
#ifndef __CONSOLE_H__
#define __CONSOLE_H__
#include <stdint.h>
#include <utils_def.h>
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 <types.h>
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 <console_assertions.h> /* 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 <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);
/* 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_<driver>_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__ */
/*
* 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 <cassert.h>
/*
* This file contains some separate assertions about console_t, moved here to
* keep them out of the way. Should only be included from <console.h>.
*/
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__ */
/*
* 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 <console.h>
#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__ */
......@@ -7,6 +7,8 @@
#ifndef __UART_16550_H__
#define __UART_16550_H__
#include <console.h>
/* 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 <types.h>
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__ */
/*
* Copyright (c) 2017, ARM Limited and Contributors. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#ifndef __COREBOOT_H__
#define __COREBOOT_H__
#include <types.h>
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__ */
......@@ -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.
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment