| 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. |
| |
| .. Registering a console: |
| |
| 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. |
| |
| 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. |
| |
| 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(...). |
| |
| 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. |
| |
| 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. |
| |
| 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``. |
| |
| 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). |
| |
| 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. |
| |
| 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``. |
| |
| 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. |
| |
| 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. |
| |
| 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. |
| |
| 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. |
| |
| 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. |
| |
| 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. |
| |
| 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.* |