mirror of
https://github.com/u-boot/u-boot.git
synced 2024-12-04 01:53:27 +08:00
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:
commit
80e1491a03
21
README
21
README
@ -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:
|
||||
---------------------------------------------------
|
||||
|
||||
|
@ -13,6 +13,7 @@ General
|
||||
designprinciples
|
||||
process
|
||||
release_cycle
|
||||
system_configuration
|
||||
|
||||
Implementation
|
||||
--------------
|
||||
|
132
doc/develop/system_configuration.rst
Normal file
132
doc/develop/system_configuration.rst
Normal 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.
|
@ -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
|
||||
|
@ -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
|
||||
|
Loading…
Reference in New Issue
Block a user