1Console Framework 2================= 3 4The TF-A console framework is used to register consoles for different boot states 5so that user's output can be displayed on physical consoles throughout the different 6boot stages. The framework also supports debug mode for general debugging purposes. 7 8The console framework supports a number of different UARTs, it is highly likely 9that the driver of the UART that is needed is already implemented. If not, a driver 10will need to be written for the new UART in TF-A. Current supported UARTs are: 11 12* Amlogic Meson 13* Arm PL011 14* Cadence CDNS 15* Coreboot CBMEM 16* Marvell A3700 17* NXP 18 * i.MX LPUART 19 * i.MX UART 20 * Linflex 21* Nvidia SPE 22* Qualcomm UARTDM 23* Renesas RCAR 24* STMicroelectronics STM32 25* Texas Instruments 16550 26 27 .. note:: 28 The supported UART list is non-exhaustive. Check if the UART driver has 29 already been written before writing a new one. 30 31:: 32 33 Console scopes and flags 34 35 Scope : Flag 36 BOOT : CONSOLE_FLAG_BOOT 37 RUNTIME : CONSOLE_FLAG_RUNTIME 38 CRASH : CONSOLE_FLAG_CRASH 39 40The console framework supports multiple consoles. Multiple instances of a UART 41can be registered at any given moment. Any registered console can have a single 42scope or multiple scopes. In single scope for example, setting three different 43consoles with each having BOOT, RUNTIME, and CRASH states respectively, the boot 44console will display only boot logs, the runtime console will display only the 45runtime output, while the crash console will be used to print the crash log in the 46event of a crash. Similarly, a console with all three scopes will display any and 47all output destined for BOOT, RUNTIME, or CRASH consoles. 48 49These multiple scopes can be useful in many ways, for example: 50 51* Having different consoles for Boot and Runtime messages 52* Having a single console for both Runtime and Boot messages 53* Having no runtime console at all and just having a single Boot console. 54* Having a separate console for crash reporting when debugging. 55 56.. Registering a console: 57 58Registering a console 59--------------------- 60To register a console in TF-A check if the hardware (UART) that is going to be used 61is already defined, if not we will need to define it, for example, the **PL011** 62UART driver API is defined in ``include/drivers/arm/pl011.h``. 63 64A skeleton console driver (assembly) is provided in TF-A ``drivers/console/aarch64/ 65skeleton_console.S``, this skeleton sets the rules for writing a new console_driver. 66Have a look at ``drivers/arm/pl011/aarch64/pl011_console.S`` for an actual 67implementation using this skeleton. 68 69Function : console_xxx_register 70~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 71 72:: 73 74 Argument : console_t *, ... 75 Return : int 76 77This ASM Function is used to initialize and register a console. The caller needs 78to pass an empty ``console_t`` struct which *MUST* be allocated in persistent 79memory (e.g. a global or static local variable, *NOT* on the stack). 80 81This function takes a ``console_t`` struct placed in x0 and additional 82arguments placed in x1 - x7. It returns x0 with either a 0 on failure or 1 83on success. 84 85See ``console_pl011_register`` ASM function for an implementation of this 86function. 87 88 .. note:: 89 The ``xxx`` in the function name is replaced with the console driver 90 name, for example, ``console_xxx_register`` becomes 91 ``console_pl011_register`` in the driver for pl011. 92 93Function : console_xxx_putc 94~~~~~~~~~~~~~~~~~~~~~~~~~~~ 95 96:: 97 98 Argument : int, console_t * 99 Return : int 100 101This ASM function is used to send a character to the UART's Transmit FIFO. It takes 102two arguments, a character as int stored in w0, and the ``console_t`` struct pointer 103stored in x1. It returns w0 with either the character on successs or a negative 104value on error. In a crash context this function must only clobber x0 - x2, x16 - x17. 105 106See ``console_pl011_putc`` ASM function for an implementation. 107 108 .. note:: 109 Avoid the direct use of this function for printing to the console, instead use 110 the ``debug.h`` print macros, such as: VERBOSE(...), INFO(...), WARN(...), 111 NOTICE(...) and ERROR(...). 112 113Function : console_xxx_getc 114~~~~~~~~~~~~~~~~~~~~~~~~~~~ 115 116:: 117 118 Argument : console_t * 119 Return : int 120 121This ASM function is used to read a character from the receive FIFO. It takes a pointer 122to the console_struct as an argument and returns a character on success or a negative 123value below -2 on failure. This function is dependent on the ``ENABLE_CONSOLE_GETC`` flag, 124which is optional and is left to the platform because there may be security implications. 125 126See ``console_pl011_getc`` ASM function for an implementation. 127 128Function : console_xxx_flush 129~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 130 131:: 132 133 Argument : console_t * 134 Return : void 135 136This ASM function flushes any characters, that are still in the Transmit FIFO but 137haven't been printed yet to the console. It takes a pointer to the console_struct 138but doesn't return any value. In a crash context this function must only clobber 139x0 - x5, x16 - x17. 140 141See ``console_pl011_flush`` ASM function for an implementation. 142 143Macro : finish_console_register xxx putc=1 getc=ENABLE_CONSOLE_GETC flush=1 144~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 145 146:: 147 148 Callbacks 149 xxx : name of the console driver 150 putc : 0 for off, 1 to turn on putc function 151 getc : 0 for off, ENABLE_CONSOLE_GETC to turn on the getc function 152 flush : 0 for off, 1 to turn on flush function 153 154This assembly macro function is called by the ``console_xxx_register`` to 155encapsulate the common setup that has to be done at the end of a console 156driver's register function. It takes ``putc``, ``getc`` and ``flush`` macro 157arguments. It will register all of the driver's callbacks in the ``console_t`` 158struct and initialize the ``flags`` field (by default consoles are enabled for 159"boot" and "crash" states, this can be changed after registration using the 160``console_set_scope`` function). This macro ends with a tail call that will 161include return to the caller. 162 163This macro requires ``console_t`` pointer in x0 and a valid return address in x30. 164 165See ``include/arch/aarch64/console_macros.S``. 166 167Registering a console using C 168----------------------------- 169 170A console can be implemented in pure C, which is much easier than using assembly. 171Currently there is no C template for implementing a console driver in C but it can 172easily be implemented using existing examples. See ``drivers/arm/dcc/dcc_console.c`` 173for an implementation of a console driver in C. 174 175The assembly functions in `Registering a console`_ section can be written in C when 176implementing a console driver using C. 177 178 .. note:: 179 A crash callback needs to be able to run without a stack. If crash mode 180 support is required then the console driver will need to be written in 181 Assembly (only the putc and flush functions are needed in a crash 182 context). 183 184Multi Console API 185----------------- 186 187TF-A uses the multi-console API to manage the registered console instances and the 188characters print queue. This can be found in ``drivers/console/multi_console.c``. 189 190The multi-console API stores all registered consoles in a struct list ``console_list``. 191Consoles can be removed from the console_list if no longer needed. 192 193Consoles are registered with BOOT and CRASH scopes by default. These scopes can be 194changed after registration using ``console_set_scope`` function, as per the platform 195requirement. 196 197This API also helps print characters to the specified consoles, characters can also 198be retrieved from the receive FIFO (this implementation is disabled by default but can 199be enabled if there is a need for it). The API can also help flush the transmit FIFO 200to get rid of any lingering characters from the queue when switching from secure world 201to the non-secure world. 202 203The following functions are defined in the multi_console API. 204 205Function : console_register() 206~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 207 208:: 209 210 Argument : console_t* 211 Return : int 212 213This function adds a console to the ``console_list`` declared in 214``include/drivers/console.h`` and makes sure that there is only one instance 215of a specific console in this list. This function is called by the 216``finish_console_register`` asm macro function, at the end of the console 217registration process. 218 219This function always return 1. If the console is already present in the 220``console_list`` it will return immediately with a value of 1, otherwise 221it will add the console to the ``console_list`` and then return 1. 222 223 .. note:: 224 The ``console_list`` is a list of type ``console_t``, it is an **extern** 225 variable declared in ``include/drivers/console.h``. 226 227Function : console_unregister() 228~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 229 230:: 231 232 Argument : console_t* 233 Return : console_t* or NULL 234 235This function removes a console from the ``console_list``. It will return the 236removed console on success or a ``NULL`` character upon failure. 237 238Function : console_set_scope() 239~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 240 241:: 242 243 Argument : console_t*, int 244 Return : void 245 246This function is used to set the scope of the registered console. A console 247can be registered with upto three states (called the scope). These states are 248 249* BOOT - set using the flag ``CONSOLE_FLAG_BOOT`` 250* RUNTIME - set using the flag ``CONSOLE_FLAG_RUNTIME`` 251* CRASH - set using the flag ``CONSOLE_FLAG_CRASH`` 252 253It takes a pointer to the console and an int value (which is provided as the 254FLAG value) as its arguments. This function does not return anything. 255 256Function : console_switch_state() 257~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 258 259:: 260 261 Argument : int 262 Return : void 263 264This function sets the console state (scope) for printing, i.e, TF-A will 265start sending all logs (INFO, WARNING, ERROR, NOTICE, VERBOSE) to the consoles 266that are registered with this new state (scope). For example, calling 267``console_switch_state(CONSOLE_FLAG_RUNTIME)``, TF-A will start sending all log 268messages to all consoles marked with the RUNTIME flag. BOOT is the default 269console state. 270 271This function takes a console state as the function's only argument. This function 272does not return a value. 273 274Function : console_putc() 275~~~~~~~~~~~~~~~~~~~~~~~~~ 276 277:: 278 279 Argument : int 280 Return : int 281 282Invoking this function sends a character to the ``console->putc`` (struct 283member) function of all consoles registered for the current scope, for example, 284BOOT logs will only be printed on consoles set with a BOOT scope. In the PL011 285implementation ``console->putc`` call points to the ``console_pl011_putc()`` 286function. 287 288This function takes the int value of a character as an argument and returns the 289int value of the character back on success or a negative int value on error. 290 291 .. note:: 292 Do not use this function in TF-A release builds, instead use the log 293 prefixes, for example, ``INFO("Print information here.")`` to print 294 messages on the active console. 295 296Function : console_getc() 297~~~~~~~~~~~~~~~~~~~~~~~~~ 298 299:: 300 301 Argument : void 302 Return : int 303 304This function is used to fetch a character from the receive FIFO that has 305not been printed to the console yet. This function is disabled by default for 306security reasons but can be enabled using the ``ENABLE_CONSOLE_GETC`` macro 307if there is a need for it. 308 309This function doesn't take any argument but returns a character as an int. 310 311Function : console_flush() 312~~~~~~~~~~~~~~~~~~~~~~~~~~ 313 314:: 315 316 Argument : void 317 Return : void 318 319This function flushes all the characters pending in the transmit FIFO of the 320active UART thus removing them from the print queue. 321 322This function has no arguments and do not return a value. 323 324Function : putchar() 325~~~~~~~~~~~~~~~~~~~~ 326 327:: 328 329 Argument : int 330 Return : int 331 332This function overrides the weak implementation of the putchar library. It is 333used to send a character to the ``console_putc()`` function to be printed to 334the active console. 335 336This function will either return the character on success or an **EOF** character 337otherwise. 338 339-------------- 340 341*Copyright (c) 2024-2025, Arm Limited and Contributors. All rights reserved.*