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
 -----BEGIN PGP SIGNATURE-----
 
 iQIzBAABCAAdFiEEbcT5xx8ppvoGt20zxIHbvCwFGsQFAmLkE0AACgkQxIHbvCwF
 GsSmqQ/+N6b9ABQaWBbLIR0PLAVN6K8gY8HU/CNs+lM2AYcp75890J4/KsB3oueG
 7/thHuv72R9aGVn9JvQKVjz6UfG47g6IyOeV3oRQJfY1vHw1aUd/WXXZFeCnAPVl
 hlxYy+r6pe9rgssoktzp7Ruh8Lgce1tEJNmK978aMp3gnPxl553WwNyi/8mDezDO
 ogt8AqxK3TiLTVpq3Lq1dnInaSWTVObCfdazD2JqY9pydvPOAoRDZsJRbr0RQBU+
 25vvRWKB84y7saHi0g+wjLHk+8rDxhIGh7wHwWszEqb5fhY2cbwyPS8pdVYbr+p0
 yMjFCyhO9bJ5FGQgPtVGHdKtcsI0hQt18kYCutXQ/ujATUjFrHXvlE1yx9RneDmv
 sDMnWGGA2N9PLg/jaa8TNjZ5eSji0jq5PEPeD4Yvj2cmmZacA6sCkbURE0Ngv36R
 m9nfXRj6y+DQJ1Wg2fDzp+PtQmHcXyJnNsNuMD9U0g0EHtc7FhHJJDRW06YukCxD
 x8hGXxnePJq4A/7Zu+wHY3rT6XhQ51SWtiTHY04lRbDnV+hxtrKLAvDepAky78Gl
 EuTqg3vVllAxEUJLX5kWFZlEhyjOCfqUirSoUVoc6nsLcHY81xxZFGroXm/EQFxz
 ecMRYwAUXKhZTrUy5AtnB0NQ4rxnf2PWXo+98Ok79ZLwMSf6Aj4=
 =EHQo
 -----END PGP SIGNATURE-----

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
This commit is contained in:
Tom Rini 2022-07-29 13:24:11 -04:00
commit 80e1491a03
5 changed files with 212 additions and 21 deletions

21
README
View File

@ -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:
---------------------------------------------------

View File

@ -13,6 +13,7 @@ General
designprinciples
process
release_cycle
system_configuration
Implementation
--------------

View File

@ -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.

View File

@ -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

View File

@ -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