diff options
author | Tom Rini <trini@konsulko.com> | 2022-07-29 13:24:11 -0400 |
---|---|---|
committer | Tom Rini <trini@konsulko.com> | 2022-07-29 13:24:11 -0400 |
commit | 80e1491a037886ebd271ce36b9be0249e848a0c8 (patch) | |
tree | a48178d1a1c69261c93af160321036085aa7fdeb | |
parent | 12fc2c3898cbcf6713055b58bd6103a2b9fda0de (diff) | |
parent | 53d2ab9b5a0a48953fc54573d7a22724a30b512d (diff) |
Merge tag 'doc-2022-10-rc2' of https://source.denx.de/u-boot/custodians/u-boot-efi
Pull request for doc-2022-10-rc2
Documentation:
* Detail how configuration signatures are calculated
* Further expand on Image locations and provide example
* Describe system configuration
-rw-r--r-- | README | 21 | ||||
-rw-r--r-- | doc/develop/index.rst | 1 | ||||
-rw-r--r-- | doc/develop/system_configuration.rst | 132 | ||||
-rw-r--r-- | doc/uImage.FIT/signature.txt | 26 | ||||
-rw-r--r-- | doc/usage/environment.rst | 53 |
5 files changed, 212 insertions, 21 deletions
@@ -166,27 +166,6 @@ Directory Hierarchy: Software Configuration: ======================= -Configuration is usually done using C preprocessor defines; the -rationale behind that is to avoid dead code whenever possible. - -There are two classes of configuration variables: - -* Configuration _OPTIONS_: - These are selectable by the user and have names beginning with - "CONFIG_". - -* Configuration _SETTINGS_: - These depend on the hardware etc. and should not be meddled with if - you don't know what you're doing; they have names beginning with - "CONFIG_SYS_". - -Previously, all configuration was done by hand, which involved creating -symbolic links and editing configuration files manually. More recently, -U-Boot has added the Kbuild infrastructure used by the Linux kernel, -allowing you to use the "make menuconfig" command to configure your -build. - - Selection of Processor Architecture and Board Type: --------------------------------------------------- diff --git a/doc/develop/index.rst b/doc/develop/index.rst index 73741ceb6a..7c41e3f1b6 100644 --- a/doc/develop/index.rst +++ b/doc/develop/index.rst @@ -13,6 +13,7 @@ General designprinciples process release_cycle + system_configuration Implementation -------------- diff --git a/doc/develop/system_configuration.rst b/doc/develop/system_configuration.rst new file mode 100644 index 0000000000..52e4e1df15 --- /dev/null +++ b/doc/develop/system_configuration.rst @@ -0,0 +1,132 @@ +.. SPDX-License-Identifier: GPL-2.0+ + +System configuration +==================== + +There are a number of different aspects to configuring U-Boot to build and then +run on a given platform or set of platforms. Broadly speaking, some aspects of +the world can be configured at run time and others must be done at build time. +In general run time configuration is preferred over build time configuration. +But when making these decisions, we also need to consider if we're talking about +a feature that could be useful to virtually every platform or something specific +to a single hardware platform. The resulting image size is also another +important consideration. Finally, run time configuration has additional overhead +both in terms of resource requirements and wall clock time. All of this means +that care must be taken when writing new code to select the most appropriate +configuration mechanism. + +When adding new features to U-Boot, be they a new subsystem or SoC support or +new platform for an existing supported SoC, the preferred configuration order +is: + +#. Hardware based run time configuration. Examples of this include reading + processor specific registers, or a set of board specific GPIOs or an EEPROM + with a known format to it. These are the cases where we either cannot or + should not be relying on device tree checks. We use this for cases such as + optimized boot time or starting with a generic device tree and then enabling + or disabling features as we boot. + +#. Making use of our Kconfig infrastructure and C preprocessor macros that have + the prefix ``CONFIG``. This is the primary method of build time + configuration. This is generally the best fit for when we want to enable or + disable some sort of feature, such as the SoC or network support. The + ``CONFIG`` prefix for C preprocessor macros is strictly reserved for Kconfig + usage only. + +#. Making use of the :doc:`device tree <devicetree/control>` to determine at + run time how to configure a feature that we have enabled via Kconfig. For + example, we would use Kconfig to enable an I2C chip driver, but use the device + tree to know where the I2C chip resides in memory and other details we need + in order to configure the bus. + +#. Making use of C header files directly and defining C preprocessor macros that + have the ``CFG`` prefix. While the ``CFG`` prefix is reserved for this build + time configuration mechanism, the usage is ad hoc. This is to be used when the + previously mentioned mechanisms are not possible, or for legacy code that has + not been converted. + +Dynamic run time configuration methods. +--------------------------------------- + +Details of hardware specific run time configuration methods are found within the +documentation for a given processor family or board. + +Details of how to use run time configuration based on :doc:`driver model +<driver-model/index>` are covered in that documentation section. + +Static build time configuration methods +--------------------------------------- + +There are two mechanisms used to control the build time configuration of U-Boot. +One is utilizing Kconfig and ``CONFIG`` prefixed macros and the other is ad hoc +usage of ``CFG`` prefixed macros. Both of these are used when it is either not +possible or not practical to make a run time determination about some +functionality of the hardware or a required software feature or similar. Each of +these has their own places where they are better suited than the other for use. + +The `Kconfig language +<https://www.kernel.org/doc/html/latest/kbuild/kconfig-language.html>`_ is well +documented and used in a number of projects, including the Linux kernel. We +implement this with the Kconfig files found throughout our sources. This +mechanism is the preferred way of exposing new configuration options as there +are a number of ways for both users and system integrators to manage and change +these options. Some common examples here are to enable a specific command within +U-Boot or even a whole subsystem such as NAND flash or network connectivity. + +The ``CFG`` mechanism is implemented directly as C preprocessor values or +macros, depending on what they are in turn describing. While we have some +functionality that is very reasonable to expose to the end user to enable or +disable we have other places where we need to describe things such as register +locations or values, memory map ranges and so on. When practical, we should be +getting these values from the device tree. However, there are cases where this +is either not practical due to when we need the information and may not have a +device tree yet or due to legacy reasons code has not been rewritten. + +When to use each mechanism +^^^^^^^^^^^^^^^^^^^^^^^^^^ + +While there are some cases where it should be fairly obvious where to use each +mechanism, as for example a command would done via Kconfig, a new I2C driver +should use Kconfig and be configured via driver model and a header of values +generated by an external tool should be ``CFG``, there will be cases where it's +less clear and one needs to take care when implementing it. In general, +configuration *options* should be done in Kconfig and configuration *settings* +should done in driver model or ``CFG``. Let us discuss things to keep in mind +when picking the appropriate mechanism. + +A thing to keep in mind is that we have a strong preference for using Kconfig as +the primary build time configuration mechanism. Options expressed this way let +us easily express dependencies and abstractions. In addition, given that many +projects use this mechanism means it has a broad set of tooling and existing +knowledge base. + +Consider the example of a SHA256 hardware acceleration engine. This would be a +feature of the SoC and so something to not ask the user if it exists, but we +would want to have our generic framework for such engines be optionally +available and depend on knowing we have this engine on a given hardware +platform. Expressing this should be done as a hidden Kconfig symbol that is +``select``'ed by the SoC symbol which would in turn be ``select``'ed by the +board option, which is user visible. Hardware features that are either present +or not present should be expressed in Kconfig and in a similar manner, features +which will always have a constant value such as "this SoC always has 4 cores and +4 threads per core" should be as well. + +This brings us to differentiating between a configuration *setting* versus a +hardware feature. To build on the previous example, while we may know the number +of cores and threads, it's possible that within a given family of SoCs the base +addresses of peripherals has changed, but the register offsets within have not. +The preference in this case is to get our information from the device tree and +perform run time configuration. However, this is not always practical and in +those cases we instead rely on the ``CFG`` mechanism. While it would be possible +to use Kconfig in this case, it would result in using calculated rather than +constructed values, resulting in less clear code. Consider the example of a set +of register values for a memory controller. Defining this as a series of logical +ORs and shifts based on other defines is more clear than the Kconfig entry that +set the calculated value alone. + +When it has been determined that the practical solution is to utilize the +``CFG`` mechanism, the next decision is where to place these settings. It is +strongly encouraged to place these in the architecture header files, if they are +generic to a given SoC, or under the board directory if board specific. Placing +them under the board.h file in the *include/configs/* directory should be seen +as a last resort. diff --git a/doc/uImage.FIT/signature.txt b/doc/uImage.FIT/signature.txt index 61a72db3c7..c71280b63b 100644 --- a/doc/uImage.FIT/signature.txt +++ b/doc/uImage.FIT/signature.txt @@ -382,6 +382,32 @@ verified later even if the FIT has been signed with other keys in the meantime. +Details +------- +The signature node contains a property ('hashed-nodes') which lists all the +nodes that the signature was made over. The image is walked in order and each +tag processed as follows: +- DTB_BEGIN_NODE: The tag and the following name are included in the signature + if the node or its parent are present in 'hashed-nodes' +- DTB_END_NODE: The tag is included in the signature if the node or its parent + are present in 'hashed-nodes' +- DTB_PROPERTY: The tag, the length word, the offset in the string table, and + the data are all included if the current node is present in 'hashed-nodes' + and the property name is not 'data'. +- DTB_END: The tag is always included in the signature. +- DTB_NOP: The tag is included in the signature if the current node is present + in 'hashed-nodes' + +In addition, the signature contains a property 'hashed-strings' which contains +the offset and length in the string table of the strings that are to be +included in the signature (this is done last). + +IMPORTANT: To verify the signature outside u-boot, it is vital to not only +calculate the hash of the image and verify the signature with that, but also to +calculate the hashes of the kernel, fdt, and ramdisk images and check those +match the hash values in the corresponding 'hash*' subnodes. + + Verification ------------ FITs are verified when loaded. After the configuration is selected a list diff --git a/doc/usage/environment.rst b/doc/usage/environment.rst index 83543f63f6..561076bac9 100644 --- a/doc/usage/environment.rst +++ b/doc/usage/environment.rst @@ -404,6 +404,56 @@ device tree blob fdtfile fdt_addr_r fdt_addr ramdisk ramdiskfile ramdisk_addr_r ramdisk_addr ================= ============== ================ ============== +When setting the RAM addresses for `kernel_addr_r`, `fdt_addr_r` and +`ramdisk_addr_r` there are several types of constraints to keep in mind. The +one type of constraint is payload requirement. For example, a device tree MUST +be loaded at an 8-byte aligned address as that is what the specification +requires. In a similar manner, the operating system may define restrictions on +where in memory space payloads can be. This is documented for example in Linux, +with both the `Booting ARM Linux`_ and `Booting AArch64 Linux`_ documents. +Finally, there are practical constraints. We do not know the size of a given +payload a user will use but each payload must not overlap or it will corrupt +the other payload. A similar problem can happen when a payload ends up being in +the OS BSS area. For these reasons we need to ensure our default values here +are both unlikely to lead to failure to boot and sufficiently explained so that +they can be optimized for boot time or adjusted for smaller memory +configurations. + +On different architectures we will have different constraints. It is important +that we follow whatever documented requirements are available to best ensure +forward compatibility. What follows are examples to highlight how to provide +reasonable default values in different cases. + +Texas Instruments OMAP2PLUS (ARMv7) example +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +On these families of processors we are on a 32bit ARMv7 core. As booting some +form of Linux is our most common payload we will also keep in mind the +documented requirements for booting that Linux provides. These values are also +known to be fine for booting a number of other operating systems (or their +loaders). In this example we define the following variables and values:: + + loadaddr=0x82000000 + kernel_addr_r=${loadaddr} + fdt_addr_r=0x88000000 + ramdisk_addr_r=0x88080000 + bootm_size=0x10000000 + +The first thing to keep in mind is that DRAM starts at 0x80000000. We set a +32MiB buffer from the start of memory as our default load address and set +``kernel_addr_r`` to that. This is because the Linux ``zImage`` decompressor +will typically then be able to avoid doing a relocation itself. It also MUST be +within the first 128MiB of memory. The next value is we set ``fdt_addr_r`` to +be at 128MiB offset from the start of memory. This location is suggested by the +kernel documentation and is exceedingly unlikely to be overwritten by the +kernel itself given other architectural constraints. We then allow for the +device tree to be up to 512KiB in size before placing the ramdisk in memory. We +then say that everything should be within the first 256MiB of memory so that +U-Boot can relocate things as needed to ensure proper alignment. We pick 256MiB +as our value here because we know there are very few platforms on in this +family with less memory. It could be as high as 768MiB and still ensure that +everything would be visible to the kernel, but again we go with what we assume +is the safest assumption. Automatically updated variables ------------------------------- @@ -472,3 +522,6 @@ Implementation -------------- See :doc:`../develop/environment` for internal development details. + +.. _`Booting ARM Linux`: https://www.kernel.org/doc/html/latest/arm/booting.html +.. _`Booting AArch64 Linux`: https://www.kernel.org/doc/html/latest/arm64/booting.html |