A common way to detect problems in firmware is to collect logs from the firmware, then pass them to the OS for storage and analysis. Logs can take the form of simple text output, or structured logs where the filename and line number, etc. are provided. Timestamps can sometimes be useful, too. Ideally the log can be displayed as simple ASCII without always needing a special program to read it. The firmware consists of various boot phases, any of which can contribute log information. It is assumed that these logs are not interleaved, i.e. that the phases run one after the other. The final boot phase (before the OS) is responsible for collecting the logs, e.g. from a Transfer List, and placing them in the devicetree. This binding collects the logs as individual log@n subnodes within a /chosen/logs node. If firmware phases use the devicetree to pass logs between each other, then the /chosen node should still be used. The /options node is not supported. Subsequent phases must be sure to use the next numbered log@n node. If the log data is sitting in memory somewhere, it is possible to point to it, rather than copying the data into a property. For large logs this may be more efficient. It must end with a NUL character, so the total space for actual log data is one byte less than the allocated size. If something goes wrong and an incomplete log record is emitted, then the next record may appear to be part of it, since there is no LF or ETX character at the end of the previous record. The intent with this binding is to provide a Linux driver which can provide access to the log data after booting is complete. Other things not considered: - signalling overflow of a log buffer - circular log buffers - a single unified log buffer with inline ASCII characters to indicate the phase and project - log records that contain multiple lines of text Signed-off-by: Simon Glass <sjg@xxxxxxxxxxxx> --- dtschema/schemas/chosen.yaml | 3 + dtschema/schemas/log.yaml | 176 +++++++++++++++++++++++++++++++++++ dtschema/schemas/logs.yaml | 30 ++++++ test/logs.dts | 47 ++++++++++ 4 files changed, 256 insertions(+) create mode 100644 dtschema/schemas/log.yaml create mode 100644 dtschema/schemas/logs.yaml create mode 100644 test/logs.dts diff --git a/dtschema/schemas/chosen.yaml b/dtschema/schemas/chosen.yaml index 86194dd..46cc9fb 100644 --- a/dtschema/schemas/chosen.yaml +++ b/dtschema/schemas/chosen.yaml @@ -236,6 +236,9 @@ properties: system. patternProperties: + '^logs$': + $ref: logs.yaml# + "^framebuffer": true additionalProperties: false diff --git a/dtschema/schemas/log.yaml b/dtschema/schemas/log.yaml new file mode 100644 index 0000000..5218234 --- /dev/null +++ b/dtschema/schemas/log.yaml @@ -0,0 +1,176 @@ +# SPDX-License-Identifier: BSD-2-Clause +# Copyright 2023 Google LLC +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/log.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Log-output binding + +maintainers: + - Simon Glass <sjg@xxxxxxxxxxxx> + +description: + This holds a log file or console dump created by a single phase of the boot. + It typically consists of plain ASCII text, but it is also possible to + add metadata like files and line numbers. + + Each log node has a hex unit address which indicates the order of progress + through the boot phases. The first node must be log@0, followed by + log@1, etc. + +select: false + +properties: + reg: + description: + Defines a unique log ID for the log represented by the log node. + + boot-phase: + $ref: types.yaml#/definitions/string + description: | + Indicates the phase of boot which produced this log: + + - pre-sram: Before SRAM is available + - verify: Verification step, which decides which of the available images + should be run next + - pre-ram: Sets up SDRAM + - some-ram: After SDRAM is working but before all of it is available. + Some RAM is available but it is limited (e.g. it may be split into + two pieces by the location of the running program) because the + program code is not yet relocated out of the way. + - loader: OS loader, typically the final firmware step + + pattern: "^pre-sram|verify|pre-ram|some-ram|loader$" + + project: + $ref: types.yaml#/definitions/string + description: + Indicates the name of the project which produced this log + + pattern: "^U-Boot|TF-A" + + time-format: + $ref: types.yaml#/definitions/string + description: | + Indicates the time format used by the log. Options are: + + usec - a integer number of microseconds since reset was released, + expressed in ASCII, e.g. "123" + + pattern: "^usec$" + + text-start: + oneOf: + - $ref: types.yaml#/definitions/uint32 + - $ref: types.yaml#/definitions/uint64 + description: + These properties hold the physical start and end address of the log text + if the 'text' property is not used. + + Note that text-start is inclusive, but text-end is exclusive. + + The text must be terminated with a NUL character. + + text-end: + oneOf: + - $ref: types.yaml#/definitions/uint32 + - $ref: types.yaml#/definitions/uint64 + description: + These properties hold the physical start and end address of the log text + if the 'text' property is not used. + + Note that text-start is inclusive, but text-end is exclusive. + + The text must be terminated with a NUL character. + + text: + $ref: types.yaml#/definitions/string + description: | + Contains the log text, if it is not referred to by text-start / text-end. + + The format is ASCII with US and SOT used to indicate optional fields: + + [timestamp<US>][level[:category[:filename[:line[:function]]]]]<SOT>]message[<LF>|<ETX>] + + where: + + timestamp is the timestamp, according to time-format + + level is the single-digit log level: + 0 - emergency (program is unstable) + 1 - alert (action must be taken immediately) + 2 - crit (critical conditions) + 3 - err (error that prevents something from working + 4 - warning (may prevent optimal operation) + 5 - notice (normal but significant condition, printf()) + 6 - info (general information message) + 7 - debug (basic debug-level message) + 8 - debug content (debug message showing full message content) + 9 - debug I/O (debug message showing hardware I/O access) + + category is the category name which is project-dependent + + filename is the relative filename (__FILE__ in C) + + line is the line number starting from 1 (__LINE__ in C) + + function is the function name (__func__ in C) + + message is the message string, which may not contain control + characters (beyond those listed above) except for HT and LF. DEL and CR + are not permitted. + + The timestamp is present only if US is in the string. + + The fields before <SOT> are all optional, but must be listed in order. + To omit a field in the middle, use an empty string between two colons. + To omit a field at the end, just leave it out along with the colon before + it. + + Typically LF is used as a line delimiter, but if a record does not + end with a newline, ETX can be used. This indicates that it is a new + log record but without a newline between them. Often (but not always) + the 'continuation' does not include the US and SOT information. + + A log record without a LF or ETX terminator is considered invalid, even + if it is the final record. + + Examples: + + 123<US>5:tpm:lib/tpm.c:334:tpm_init<SOT>TPM starting...<LF> + 23<US>Hello<LF> + 2:boot:lib/panic.c:84:panic<SOT>Memory training failed<LF> + 7:mmc:::mmc_bind<SOT>Cannot create block device<LF> + Net: eth0: host_lo, eth1: host_enp1s0<ETX> + + ASCII characters: + + SOT - 0x2 - indicates the start of the message. This is optional if + the record has nothing but a message + ETX - 0x3 - indicates the end of a log record (without new line) + LF - 0xa - indicates the end of a log record (and new line) + US - 0x1f - indicates the end of the timestamp (and that it is present + in the record) + + The above format is intended to be unambiguous, while still being fairly + readable it just shown on a terminal with all control characters except + LF dropped. The CR character is not permitted since it is not needed to + signal an end of line and it avoids worrying about what <CR><LF> actually + means. + + The text size is determined by the property size. The last byte must be + a NUL character. + +required: + - boot-phase + - project + +anyOf: + - required: + - text + - required: + - text-start + - text-end + +additionalProperties: false diff --git a/dtschema/schemas/logs.yaml b/dtschema/schemas/logs.yaml new file mode 100644 index 0000000..76ba2b0 --- /dev/null +++ b/dtschema/schemas/logs.yaml @@ -0,0 +1,30 @@ +# SPDX-License-Identifier: BSD-2-Clause +# Copyright 2023 Google LLC +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/logs.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Log information collected during firmware execution + +maintainers: + - Simon Glass <sjg@xxxxxxxxxxxx> + +description: + This holds a set of logs build up during booting of the machine. The + collection of logs is described in the "/logs" node. This node in turn + contains a number of subnodes representing individual log output from + different boot phases. + +properties: + '#address-cells': + const: 1 + + '#size-cells': + const: 0 + +patternProperties: + '^log@[0-9a-f]+$': + $ref: log.yaml# + +additionalProperties: false diff --git a/test/logs.dts b/test/logs.dts new file mode 100644 index 0000000..7d044df --- /dev/null +++ b/test/logs.dts @@ -0,0 +1,47 @@ +// SPDX-License-Identifier: BSD-2-Clause +// Copyright 2023 Google LLC + +// Used to validate the "logs" node and its child "log" nodes + +// dtc -O dtb -o test.dtb test/bootphases.dts && tools/dt-validate -s test/schemas -m test.dtb + + +/dts-v1/; + +/ { + model = "none"; + compatible = "foo"; + + #address-cells = <1>; + #size-cells = <1>; + + chosen { + logs { + #address-cells = <1>; + #size-cells = <0>; + + log@0 { + reg = <0>; + boot-phase = "pre-ram"; + project = "U-Boot"; + text = "\nU-Boot SPL 2023.01 (Feb 03 2023 - 14:45:39 -0700)\nTrying to boot from sandbox_image\nTrying to boot from sandbox_file\n"; + }; + + log@1 { + reg = <1>; + boot-phase = "loader"; + project = "U-Boot"; + time-format = "usec"; + text = "\n\n123\x1f2:boot:lib/display_options.c:43:display_options\x02U-Boot 2023.01 (Feb 03 2023 - 14:45:39 -0700)\n\nReset Status: COLD\nModel: sandbox\nDRAM: 256 MiB\n"; + }; + + log@2 { + reg = <2>; + boot-phase = "pre-ram"; + project = "TF-A"; + text-start = <0x103000>; + text-end = <0x107000>; + }; + }; + }; +}; -- 2.39.1.519.gcb327c4b5f-goog