5.8. Console Framework

The TF-A console framework is used to register consoles for different boot states so that user’s output can be displayed on physical consoles throughout the different boot stages. The framework also supports debug mode for general debugging purposes.

The console framework supports a number of different UARTs, it is highly likely that the driver of the UART that is needed is already implemented. If not, a driver will need to be written for the new UART in TF-A. Current supported UARTs are:

  • Amlogic Meson

  • Arm PL011

  • Cadence CDNS

  • Coreboot CBMEM

  • Marvell A3700

  • NXP
    • i.MX LPUART

    • i.MX UART

    • Linflex

  • Nvidia SPE

  • Qualcomm UARTDM

  • Renesas RCAR

  • STMicroelectronics STM32

  • Texas Instruments 16550

    Note

    The supported UART list is non-exhaustive. Check if the UART driver has already been written before writing a new one.

Console scopes and flags

Scope   : Flag
BOOT    : CONSOLE_FLAG_BOOT
RUNTIME : CONSOLE_FLAG_RUNTIME
CRASH   : CONSOLE_FLAG_CRASH

The console framework supports multiple consoles. Multiple instances of a UART can be registered at any given moment. Any registered console can have a single scope or multiple scopes. In single scope for example, setting three different consoles with each having BOOT, RUNTIME, and CRASH states respectively, the boot console will display only boot logs, the runtime console will display only the runtime output, while the crash console will be used to print the crash log in the event of a crash. Similarly, a console with all three scopes will display any and all output destined for BOOT, RUNTIME, or CRASH consoles.

These multiple scopes can be useful in many ways, for example:

  • Having different consoles for Boot and Runtime messages

  • Having a single console for both Runtime and Boot messages

  • Having no runtime console at all and just having a single Boot console.

  • Having a separate console for crash reporting when debugging.

5.8.1. Registering a console

To register a console in TF-A check if the hardware (UART) that is going to be used is already defined, if not we will need to define it, for example, the PL011 UART driver API is defined in include/drivers/arm/pl011.h.

A skeleton console driver (assembly) is provided in TF-A drivers/console/aarch64/ skeleton_console.S, this skeleton sets the rules for writing a new console_driver. Have a look at drivers/arm/pl011/aarch64/pl011_console.S for an actual implementation using this skeleton.

5.8.1.1. Function : console_xxx_register

Argument : console_t *, ...
Return   : int

This ASM Function is used to initialize and register a console. The caller needs to pass an empty console_t struct which MUST be allocated in persistent memory (e.g. a global or static local variable, NOT on the stack).

This function takes a console_t struct placed in x0 and additional arguments placed in x1 - x7. It returns x0 with either a 0 on failure or 1 on success.

See console_pl011_register ASM function for an implementation of this function.

Note

The xxx in the function name is replaced with the console driver name, for example, console_xxx_register becomes console_pl011_register in the driver for pl011.

5.8.1.2. Function : console_xxx_putc

Argument : int, console_t *
Return   : int

This ASM function is used to send a character to the UART’s Transmit FIFO. It takes two arguments, a character as int stored in w0, and the console_t struct pointer stored in x1. It returns w0 with either the character on successs or a negative value on error. In a crash context this function must only clobber x0 - x2, x16 - x17.

See console_pl011_putc ASM function for an implementation.

Note

Avoid the direct use of this function for printing to the console, instead use the debug.h print macros, such as: VERBOSE(…), INFO(…), WARN(…), NOTICE(…) and ERROR(…).

5.8.1.3. Function : console_xxx_getc

Argument : console_t *
Return   : int

This ASM function is used to read a character from the receive FIFO. It takes a pointer to the console_struct as an argument and returns a character on success or a negative value below -2 on failure. This function is dependent on the ENABLE_CONSOLE_GETC flag, which is optional and is left to the platform because there may be security implications.

See console_pl011_getc ASM function for an implementation.

5.8.1.4. Function : console_xxx_flush

Argument : console_t *
Return   : void

This ASM function flushes any characters, that are still in the Transmit FIFO but haven’t been printed yet to the console. It takes a pointer to the console_struct but doesn’t return any value. In a crash context this function must only clobber x0 - x5, x16 - x17.

See console_pl011_flush ASM function for an implementation.

5.8.1.5. Macro : finish_console_register xxx putc=1 getc=ENABLE_CONSOLE_GETC flush=1

Callbacks
xxx      : name of the console driver
putc     : 0 for off, 1 to turn on putc function
getc     : 0 for off, ENABLE_CONSOLE_GETC to turn on the getc function
flush    : 0 for off, 1 to turn on flush function

This assembly macro function is called by the console_xxx_register to encapsulate the common setup that has to be done at the end of a console driver’s register function. It takes putc, getc and flush macro arguments. It will register all of the driver’s callbacks in the console_t struct and initialize the flags field (by default consoles are enabled for “boot” and “crash” states, this can be changed after registration using the console_set_scope function). This macro ends with a tail call that will include return to the caller.

This macro requires console_t pointer in x0 and a valid return address in x30.

See include/arch/aarch64/console_macros.S.

5.8.2. Registering a console using C

A console can be implemented in pure C, which is much easier than using assembly. Currently there is no C template for implementing a console driver in C but it can easily be implemented using existing examples. See drivers/arm/dcc/dcc_console.c for an implementation of a console driver in C.

The assembly functions in Registering a console section can be written in C when implementing a console driver using C.

Note

A crash callback needs to be able to run without a stack. If crash mode support is required then the console driver will need to be written in Assembly (only the putc and flush functions are needed in a crash context).

5.8.3. Multi Console API

TF-A uses the multi-console API to manage the registered console instances and the characters print queue. This can be found in drivers/console/multi_console.c.

The multi-console API stores all registered consoles in a struct list console_list. Consoles can be removed from the console_list if no longer needed.

Consoles are registered with BOOT and CRASH scopes by default. These scopes can be changed after registration using console_set_scope function, as per the platform requirement.

This API also helps print characters to the specified consoles, characters can also be retrieved from the receive FIFO (this implementation is disabled by default but can be enabled if there is a need for it). The API can also help flush the transmit FIFO to get rid of any lingering characters from the queue when switching from secure world to the non-secure world.

The following functions are defined in the multi_console API.

5.8.3.1. Function : console_register()

Argument : console_t*
Return   : int

This function adds a console to the console_list declared in include/drivers/console.h and makes sure that there is only one instance of a specific console in this list. This function is called by the finish_console_register asm macro function, at the end of the console registration process.

This function always return 1. If the console is already present in the console_list it will return immediately with a value of 1, otherwise it will add the console to the console_list and then return 1.

Note

The console_list is a list of type console_t, it is an extern variable declared in include/drivers/console.h.

5.8.3.2. Function : console_unregister()

Argument : console_t*
Return   : console_t* or NULL

This function removes a console from the console_list. It will return the removed console on success or a NULL character upon failure.

5.8.3.3. Function : console_set_scope()

Argument : console_t*, int
Return   : void

This function is used to set the scope of the registered console. A console can be registered with upto three states (called the scope). These states are

  • BOOT - set using the flag CONSOLE_FLAG_BOOT

  • RUNTIME - set using the flag CONSOLE_FLAG_RUNTIME

  • CRASH - set using the flag CONSOLE_FLAG_CRASH

It takes a pointer to the console and an int value (which is provided as the FLAG value) as its arguments. This function does not return anything.

5.8.3.4. Function : console_switch_state()

Argument : int
Return   : void

This function sets the console state (scope) for printing, i.e, TF-A will start sending all logs (INFO, WARNING, ERROR, NOTICE, VERBOSE) to the consoles that are registered with this new state (scope). For example, calling console_switch_state(CONSOLE_FLAG_RUNTIME), TF-A will start sending all log messages to all consoles marked with the RUNTIME flag. BOOT is the default console state.

This function takes a console state as the function’s only argument. This function does not return a value.

5.8.3.5. Function : console_putc()

Argument : int
Return   : int

Invoking this function sends a character to the console->putc (struct member) function of all consoles registered for the current scope, for example, BOOT logs will only be printed on consoles set with a BOOT scope. In the PL011 implementation console->putc call points to the console_pl011_putc() function.

This function takes the int value of a character as an argument and returns the int value of the character back on success or a negative int value on error.

Note

Do not use this function in TF-A release builds, instead use the log prefixes, for example, INFO("Print information here.") to print messages on the active console.

5.8.3.6. Function : console_getc()

Argument : void
Return   : int

This function is used to fetch a character from the receive FIFO that has not been printed to the console yet. This function is disabled by default for security reasons but can be enabled using the ENABLE_CONSOLE_GETC macro if there is a need for it.

This function doesn’t take any argument but returns a character as an int.

5.8.3.7. Function : console_flush()

Argument : void
Return   : void

This function flushes all the characters pending in the transmit FIFO of the active UART thus removing them from the print queue.

This function has no arguments and do not return a value.

5.8.3.8. Function : putchar()

Argument : int
Return   : int

This function overrides the weak implementation of the putchar library. It is used to send a character to the console_putc() function to be printed to the active console.

This function will either return the character on success or an EOF character otherwise.


Copyright (c) 2024-2025, Arm Limited and Contributors. All rights reserved.