| Logging in U-Boot | 
| ================= | 
|   | 
| Introduction | 
| ------------ | 
|   | 
| U-Boot's internal operation involves many different steps and actions. From | 
| setting up the board to displaying a start-up screen to loading an Operating | 
| System, there are many component parts each with many actions. | 
|   | 
| Most of the time this internal detail is not useful. Displaying it on the | 
| console would delay booting (U-Boot's primary purpose) and confuse users. | 
|   | 
| But for digging into what is happening in a particular area, or for debugging | 
| a problem it is often useful to see what U-Boot is doing in more detail than | 
| is visible from the basic console output. | 
|   | 
| U-Boot's logging feature aims to satisfy this goal for both users and | 
| developers. | 
|   | 
|   | 
| Logging levels | 
| -------------- | 
|   | 
| There are a number logging levels available, in increasing order of verbosity: | 
|   | 
|    LOGL_EMERG    - Printed before U-Boot halts | 
|    LOGL_ALERT    - Indicates action must be taken immediate or U-Boot will crash | 
|    LOGL_CRIT    - Indicates a critical error that will cause boot failure | 
|    LOGL_ERR    - Indicates an error that may cause boot failure | 
|    LOGL_WARNING    - Warning about an unexpected condition | 
|    LOGL_NOTE    - Important information about progress | 
|    LOGL_INFO    - Information about normal boot progress | 
|    LOGL_DEBUG    - Debug information (useful for debugging a driver or subsystem) | 
|    LOGL_DEBUG_CONTENT    - Debug message showing full message content | 
|    LOGL_DEBUG_IO    - Debug message showing hardware I/O access | 
|   | 
|   | 
| Logging category | 
| ---------------- | 
|   | 
| Logging can come from a wide variety of places within U-Boot. Each log message | 
| has a category which is intended to allow messages to be filtered according to | 
| their source. | 
|   | 
| The following main categories are defined: | 
|   | 
|    LOGC_NONE    - Unknown category (e.g. a debug() statement) | 
|    UCLASS_...    - Related to a particular uclass (e.g. UCLASS_USB) | 
|    LOGC_ARCH    - Related to architecture-specific code | 
|    LOGC_BOARD    - Related to board-specific code | 
|    LOGC_CORE    - Related to core driver-model support | 
|    LOGC_DT    - Related to device tree control | 
|   | 
|   | 
| Enabling logging | 
| ---------------- | 
|   | 
| The following options are used to enable logging at compile time: | 
|   | 
|    CONFIG_LOG        - Enables the logging system | 
|    CONFIG_MAX_LOG_LEVEL - Max log level to build (anything higher is compiled | 
|                 out) | 
|    CONFIG_LOG_CONSOLE    - Enable writing log records to the console | 
|   | 
| If CONFIG_LOG is not set, then no logging will be available. | 
|   | 
| The above have SPL versions also, e.g. CONFIG_SPL_MAX_LOG_LEVEL. | 
|   | 
|   | 
| Using DEBUG | 
| ----------- | 
|   | 
| U-Boot has traditionally used a #define called DEBUG to enable debugging on a | 
| file-by-file basis. The debug() macro compiles to a printf() statement if | 
| DEBUG is enabled, and an empty statement if not. | 
|   | 
| With logging enabled, debug() statements are interpreted as logging output | 
| with a level of LOGL_DEBUG and a category of LOGC_NONE. | 
|   | 
| The logging facilities are intended to replace DEBUG, but if DEBUG is defined | 
| at the top of a file, then it takes precedence. This means that debug() | 
| statements will result in output to the console and this output will not be | 
| logged. | 
|   | 
|   | 
| Logging destinations | 
| -------------------- | 
|   | 
| If logging information goes nowhere then it serves no purpose. U-Boot provides | 
| several possible determinations for logging information, all of which can be | 
| enabled or disabled independently: | 
|   | 
|    console - goes to stdout | 
|   | 
|   | 
| Filters | 
| ------- | 
|   | 
| Filters are attached to log drivers to control what those drivers emit. Only | 
| records that pass through the filter make it to the driver. | 
|   | 
| Filters can be based on several criteria: | 
|   | 
|    - maximum log level | 
|    - in a set of categories | 
|    - in a set of files | 
|   | 
| If no filters are attached to a driver then a default filter is used, which | 
| limits output to records with a level less than CONFIG_LOG_MAX_LEVEL. | 
|   | 
|   | 
| Logging statements | 
| ------------------ | 
|   | 
| The main logging function is: | 
|   | 
|    log(category, level, format_string, ...) | 
|   | 
| Also debug() and error() will generate log records  - these use LOG_CATEGORY | 
| as the category, so you should #define this right at the top of the source | 
| file to ensure the category is correct. | 
|   | 
|   | 
| Code size | 
| --------- | 
|   | 
| Code size impact depends largely on what is enabled. The following numbers are | 
| for snow, which is a Thumb-2 board: | 
|   | 
| This series: adds bss +20.0 data +4.0 rodata +4.0 text +44.0 | 
| CONFIG_LOG: bss -52.0 data +92.0 rodata -635.0 text +1048.0 | 
| CONFIG_LOG_MAX_LEVEL=7: bss +188.0 data +4.0 rodata +49183.0 text +98124.0 | 
|   | 
| The last option turns every debug() statement into a logging call, which | 
| bloats the code hugely. The advantage is that it is then possible to enable | 
| all logging within U-Boot. | 
|   | 
|   | 
| To Do | 
| ----- | 
|   | 
| There are lots of useful additions that could be made. None of the below is | 
| implemented! If you do one, please add a test in test/py/tests/test_log.py | 
|   | 
| Convenience functions to support setting the category: | 
|   | 
|    log_arch(level, format_string, ...) - category LOGC_ARCH | 
|    log_board(level, format_string, ...) - category LOGC_BOARD | 
|    log_core(level, format_string, ...) - category LOGC_CORE | 
|    log_dt(level, format_string, ...) - category LOGC_DT | 
|   | 
| Convenience functions to support a category defined for a single file, for | 
| example: | 
|   | 
|    #define LOG_CATEGORY   UCLASS_USB | 
|   | 
| all of these can use LOG_CATEGORY as the category, and a log level | 
| corresponding to the function name: | 
|   | 
|    logc(level, format_string, ...) | 
|   | 
| More logging destinations: | 
|   | 
|    device - goes to a device (e.g. serial) | 
|    buffer - recorded in a memory buffer | 
|   | 
| Convert debug() statements in the code to log() statements | 
|   | 
| Support making printf() emit log statements a L_INFO level | 
|   | 
| Convert error() statements in the code to log() statements | 
|   | 
| Figure out what to do with BUG(), BUG_ON() and warn_non_spl() | 
|   | 
| Figure out what to do with assert() | 
|   | 
| Add a way to browse log records | 
|   | 
| Add a way to record log records for browsing using an external tool | 
|   | 
| Add commands to add and remove filters | 
|   | 
| Add commands to add and remove log devices | 
|   | 
| Allow sharing of printf format strings in log records to reduce storage size | 
| for large numbers of log records | 
|   | 
| Add a command-line option to sandbox to set the default logging level | 
|   | 
| Convert core driver model code to use logging | 
|   | 
| Convert uclasses to use logging with the correct category | 
|   | 
| Consider making log() calls emit an automatic newline, perhaps with a logn() | 
|    function to avoid that | 
|   | 
| Passing log records through to linux (e.g. via device tree /chosen) | 
|   | 
| Provide a command to access the number of log records generated, and the | 
| number dropped due to them being generated before the log system was ready. | 
|   | 
| Add a printf() format string pragma so that log statements are checked properly | 
|   | 
| Enhance the log console driver to show level / category / file / line | 
| information | 
|   | 
| Add a command to add new log records and delete existing records. | 
|   | 
| Provide additional log() functions - e.g. logc() to specify the category | 
|   | 
| -- | 
| Simon Glass <sjg@chromium.org> | 
| 15-Sep-17 |