Salman Nabi | 31edc20 | 2024-02-01 15:28:43 +0000 | [diff] [blame^] | 1 | Console Framework |
| 2 | ================= |
| 3 | |
| 4 | The TF-A console framework is used to register consoles for different boot states |
| 5 | so that user's output can be displayed on physical consoles throughout the different |
| 6 | boot stages. The framework also supports debug mode for general debugging purposes. |
| 7 | |
| 8 | The console framework supports a number of different UARTs, it is highly likely |
| 9 | that the driver of the UART that is needed is already implemented. If not, a driver |
| 10 | will 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 | |
| 40 | The console framework supports multiple consoles. Multiple instances of a UART |
| 41 | can be registered at any given moment. Any registered console can have a single |
| 42 | scope or multiple scopes. In single scope for example, setting three different |
| 43 | consoles with each having BOOT, RUNTIME, and CRASH states respectively, the boot |
| 44 | console will display only boot logs, the runtime console will display only the |
| 45 | runtime output, while the crash console will be used to print the crash log in the |
| 46 | event of a crash. Similarly, a console with all three scopes will display any and |
| 47 | all output destined for BOOT, RUNTIME, or CRASH consoles. |
| 48 | |
| 49 | These 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 | |
| 58 | Registering a console |
| 59 | --------------------- |
| 60 | To register a console in TF-A check if the hardware (UART) that is going to be used |
| 61 | is already defined, if not we will need to define it, for example, the **PL011** |
| 62 | UART driver API is defined in ``include/drivers/arm/pl011.h``. |
| 63 | |
| 64 | A skeleton console driver (assembly) is provided in TF-A ``drivers/console/aarch64/ |
| 65 | skeleton_console.S``, this skeleton sets the rules for writing a new console_driver. |
| 66 | Have a look at ``drivers/arm/pl011/aarch64/pl011_console.S`` for an actual |
| 67 | implementation using this skeleton. |
| 68 | |
| 69 | Function : console_xxx_register |
| 70 | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ |
| 71 | |
| 72 | :: |
| 73 | |
| 74 | Argument : console_t *, ... |
| 75 | Return : int |
| 76 | |
| 77 | This ASM Function is used to initialize and register a console. The caller needs |
| 78 | to pass an empty ``console_t`` struct which *MUST* be allocated in persistent |
| 79 | memory (e.g. a global or static local variable, *NOT* on the stack). |
| 80 | |
| 81 | This function takes a ``console_t`` struct placed in x0 and additional |
| 82 | arguments placed in x1 - x7. It returns x0 with either a 0 on failure or 1 |
| 83 | on success. |
| 84 | |
| 85 | See ``console_pl011_register`` ASM function for an implementation of this |
| 86 | function. |
| 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 | |
| 93 | Function : console_xxx_putc |
| 94 | ~~~~~~~~~~~~~~~~~~~~~~~~~~~ |
| 95 | |
| 96 | :: |
| 97 | |
| 98 | Argument : int, console_t * |
| 99 | Return : int |
| 100 | |
| 101 | This ASM function is used to send a character to the UART's Transmit FIFO. It takes |
| 102 | two arguments, a character as int stored in w0, and the ``console_t`` struct pointer |
| 103 | stored in x1. It returns w0 with either the character on successs or a negative |
| 104 | value on error. In a crash context this function must only clobber x0 - x2, x16 - x17. |
| 105 | |
| 106 | See ``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 | |
| 113 | Function : console_xxx_getc |
| 114 | ~~~~~~~~~~~~~~~~~~~~~~~~~~~ |
| 115 | |
| 116 | :: |
| 117 | |
| 118 | Argument : console_t * |
| 119 | Return : int |
| 120 | |
| 121 | This ASM function is used to read a character from the receive FIFO. It takes a pointer |
| 122 | to the console_struct as an argument and returns a character on success or a negative |
| 123 | value below -2 on failure. This function is dependent on the ``ENABLE_CONSOLE_GETC`` flag, |
| 124 | which is optional and is left to the platform because there may be security implications. |
| 125 | |
| 126 | See ``console_pl011_getc`` ASM function for an implementation. |
| 127 | |
| 128 | Function : console_xxx_flush |
| 129 | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~ |
| 130 | |
| 131 | :: |
| 132 | |
| 133 | Argument : console_t * |
| 134 | Return : void |
| 135 | |
| 136 | This ASM function flushes any characters, that are still in the Transmit FIFO but |
| 137 | haven't been printed yet to the console. It takes a pointer to the console_struct |
| 138 | but doesn't return any value. In a crash context this function must only clobber |
| 139 | x0 - x5, x16 - x17. |
| 140 | |
| 141 | See ``console_pl011_flush`` ASM function for an implementation. |
| 142 | |
| 143 | Macro : 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 | |
| 154 | This assembly macro function is called by the ``console_xxx_register`` to |
| 155 | encapsulate the common setup that has to be done at the end of a console |
| 156 | driver's register function. It takes ``putc``, ``getc`` and ``flush`` macro |
| 157 | arguments. It will register all of the driver's callbacks in the ``console_t`` |
| 158 | struct 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 |
| 161 | include return to the caller. |
| 162 | |
| 163 | This macro requires ``console_t`` pointer in x0 and a valid return address in x30. |
| 164 | |
| 165 | See ``include/arch/aarch64/console_macros.S``. |
| 166 | |
| 167 | Registering a console using C |
| 168 | ----------------------------- |
| 169 | |
| 170 | A console can be implemented in pure C, which is much easier than using assembly. |
| 171 | Currently there is no C template for implementing a console driver in C but it can |
| 172 | easily be implemented using existing examples. See ``drivers/arm/dcc/dcc_console.c`` |
| 173 | for an implementation of a console driver in C. |
| 174 | |
| 175 | The assembly functions in `Registering a console`_ section can be written in C when |
| 176 | implementing 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 | |
| 184 | Multi Console API |
| 185 | ----------------- |
| 186 | |
| 187 | TF-A uses the multi-console API to manage the registered console instances and the |
| 188 | characters print queue. This can be found in ``drivers/console/multi_console.c``. |
| 189 | |
| 190 | The multi-console API stores all registered consoles in a struct list ``console_list``. |
| 191 | Consoles can be removed from the console_list if no longer needed. |
| 192 | |
| 193 | Consoles are registered with BOOT and CRASH scopes by default. These scopes can be |
| 194 | changed after registration using ``console_set_scope`` function, as per the platform |
| 195 | requirement. |
| 196 | |
| 197 | This API also helps print characters to the specified consoles, characters can also |
| 198 | be retrieved from the receive FIFO (this implementation is disabled by default but can |
| 199 | be enabled if there is a need for it). The API can also help flush the transmit FIFO |
| 200 | to get rid of any lingering characters from the queue when switching from secure world |
| 201 | to the non-secure world. |
| 202 | |
| 203 | The following functions are defined in the multi_console API. |
| 204 | |
| 205 | Function : console_register() |
| 206 | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ |
| 207 | |
| 208 | :: |
| 209 | |
| 210 | Argument : console_t* |
| 211 | Return : int |
| 212 | |
| 213 | This function adds a console to the ``console_list`` declared in |
| 214 | ``include/drivers/console.h`` and makes sure that there is only one instance |
| 215 | of 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 |
| 217 | registration process. |
| 218 | |
| 219 | This 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 |
| 221 | it 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 | |
| 227 | Function : console_unregister() |
| 228 | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ |
| 229 | |
| 230 | :: |
| 231 | |
| 232 | Argument : console_t* |
| 233 | Return : console_t* or NULL |
| 234 | |
| 235 | This function removes a console from the ``console_list``. It will return the |
| 236 | removed console on success or a ``NULL`` character upon failure. |
| 237 | |
| 238 | Function : console_set_scope() |
| 239 | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ |
| 240 | |
| 241 | :: |
| 242 | |
| 243 | Argument : console_t*, int |
| 244 | Return : void |
| 245 | |
| 246 | This function is used to set the scope of the registered console. A console |
| 247 | can 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 | |
| 253 | It takes a pointer to the console and an int value (which is provided as the |
| 254 | FLAG value) as its arguments. This function does not return anything. |
| 255 | |
| 256 | Function : console_switch_state() |
| 257 | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ |
| 258 | |
| 259 | :: |
| 260 | |
| 261 | Argument : int |
| 262 | Return : void |
| 263 | |
| 264 | This function sets the console state (scope) for printing, i.e, TF-A will |
| 265 | start sending all logs (INFO, WARNING, ERROR, NOTICE, VERBOSE) to the consoles |
| 266 | that are registered with this new state (scope). For example, calling |
| 267 | ``console_switch_state(CONSOLE_FLAG_RUNTIME)``, TF-A will start sending all log |
| 268 | messages to all consoles marked with the RUNTIME flag. BOOT is the default |
| 269 | console state. |
| 270 | |
| 271 | This function takes a console state as the function's only argument. This function |
| 272 | does not return a value. |
| 273 | |
| 274 | Function : console_putc() |
| 275 | ~~~~~~~~~~~~~~~~~~~~~~~~~ |
| 276 | |
| 277 | :: |
| 278 | |
| 279 | Argument : int |
| 280 | Return : int |
| 281 | |
| 282 | Invoking this function sends a character to the ``console->putc`` (struct |
| 283 | member) function of all consoles registered for the current scope, for example, |
| 284 | BOOT logs will only be printed on consoles set with a BOOT scope. In the PL011 |
| 285 | implementation ``console->putc`` call points to the ``console_pl011_putc()`` |
| 286 | function. |
| 287 | |
| 288 | This function takes the int value of a character as an argument and returns the |
| 289 | int 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 | |
| 296 | Function : console_getc() |
| 297 | ~~~~~~~~~~~~~~~~~~~~~~~~~ |
| 298 | |
| 299 | :: |
| 300 | |
| 301 | Argument : void |
| 302 | Return : int |
| 303 | |
| 304 | This function is used to fetch a character from the receive FIFO that has |
| 305 | not been printed to the console yet. This function is disabled by default for |
| 306 | security reasons but can be enabled using the ``ENABLE_CONSOLE_GETC`` macro |
| 307 | if there is a need for it. |
| 308 | |
| 309 | This function doesn't take any argument but returns a character as an int. |
| 310 | |
| 311 | Function : console_flush() |
| 312 | ~~~~~~~~~~~~~~~~~~~~~~~~~~ |
| 313 | |
| 314 | :: |
| 315 | |
| 316 | Argument : void |
| 317 | Return : void |
| 318 | |
| 319 | This function flushes all the characters pending in the transmit FIFO of the |
| 320 | active UART thus removing them from the print queue. |
| 321 | |
| 322 | This function has no arguments and do not return a value. |
| 323 | |
| 324 | Function : putchar() |
| 325 | ~~~~~~~~~~~~~~~~~~~~ |
| 326 | |
| 327 | :: |
| 328 | |
| 329 | Argument : int |
| 330 | Return : int |
| 331 | |
| 332 | This function overrides the weak implementation of the putchar library. It is |
| 333 | used to send a character to the ``console_putc()`` function to be printed to |
| 334 | the active console. |
| 335 | |
| 336 | This function will either return the character on success or an **EOF** character |
| 337 | otherwise. |
| 338 | |
| 339 | -------------- |
| 340 | |
| 341 | *Copyright (c) 2024-2025, Arm Limited and Contributors. All rights reserved.* |