binman: Add more documentation about binman usage

This is an attempt to answer the comments provided by Xavier [1].

[1] https://lore.kernel.org/all/Yulcol7HpTHtjXTX@begut/

Signed-off-by: Simon Glass <sjg@chromium.org>
Acked-by: Heinrich Schuchardt <heinrich.schuchardt@canonical.com>
This commit is contained in:
Simon Glass 2022-08-07 16:33:26 -06:00 committed by Heinrich Schuchardt
parent 228c9b8629
commit 7d6fadef84
2 changed files with 193 additions and 8 deletions

View File

@ -56,6 +56,7 @@ quiet_cmd_sphinx = SPHINX $@ --> file://$(abspath $(BUILDDIR)/$3/$4)
PYTHONDONTWRITEBYTECODE=1 \
BUILDDIR=$(abspath $(BUILDDIR)) SPHINX_CONF=$(abspath $(srctree)/$(src)/$5/$(SPHINX_CONF)) \
$(SPHINXBUILD) \
-j$(shell nproc) \
-b $2 \
-c $(abspath $(srctree)/$(src)) \
-d $(abspath $(BUILDDIR)/.doctrees/$3) \

View File

@ -42,7 +42,7 @@ the devicetree description of the image.
Binman is designed primarily for use with U-Boot and associated binaries such
as ARM Trusted Firmware, but it is suitable for use with other projects, such
as Zephyr. Binman also provides facilities useful in Chromium OS, such as CBFS,
vblocks and and the like.
vblocks and the like.
Binman provides a way to process binaries before they are included, by adding a
Python plug-in.
@ -118,6 +118,10 @@ flash.
For U-Boot, binman should not be used to create ad-hoc images in place of
FIT.
Note that binman can itself create a FIT. This helps to move mkimage
invocations out of the Makefile and into binman image descriptions. It also
helps by removing the need for ad-hoc tools like `make_fit_atf.py`.
Relationship to mkimage
-----------------------
@ -140,6 +144,9 @@ seems better to use the mkimage tool to generate binaries and avoid blurring
the boundaries between building input files (mkimage) and packaging then
into a final image (binman).
Note that binman can itself invoke mkimage. This helps to move mkimage
invocations out of the Makefile and into binman image descriptions.
Using binman
============
@ -170,6 +177,164 @@ This simplifies the U-Boot Makefile somewhat, since various pieces of logic
can be replaced by a call to binman.
Invoking binman within U-Boot
-----------------------------
Within U-Boot, binman is invoked by the build system, i.e. when you type 'make'
or use buildman to build U-Boot. There is no need to run binman independently
during development. Everything happens automatically and is set up for your
SoC or board so that binman produced the right things.
The general policy is that the Makefile builds all the binaries in INPUTS-y
(the 'inputs' rule), then binman is run to produce the final images (the 'all'
rule).
There should be only one invocation of binman in Makefile, the very last step
that pulls everything together. At present there are some arch-specific
invocations as well, but these should be dropped when those architectures are
converted to use binman properly.
As above, the term 'binary' is used for something in INPUTS-y and 'image' is
used for the things that binman creates. So the binaries are inputs to the
image(s) and it is the image that is actually loaded on the board.
Again, at present, there are a number of things created in Makefile which should
be done by binman (when we get around to it), like `u-boot-ivt.img`,
`lpc32xx-spl.img`, `u-boot-with-nand-spl.imx`, `u-boot-spl-padx4.sfp` and
`u-boot-mtk.bin`, just to pick on a few. When completed this will remove about
400 lines from `Makefile`.
Since binman is invoked only once, it must of course create all the images that
are needed, in that one invocation. It does this by working through the image
descriptions one by one, collecting the input binaries, processing them as
needed and producing the final images.
The same binaries may be used by multiple images. For example binman may be used
to produce an SD-card image and a SPI-flash image. In this case the binaries
going into the process are the same, but binman produces slightly different
images in each case.
For some SoCs, U-Boot is not the only project that produces the necessary
binaries. For example, ARM Trusted Firmware (ATF) is a project that produces
binaries which must be incorporate, such as `bl31.elf` or `bl31.bin`. For this
to work you must have built ATF before you build U-Boot and you must tell U-Boot
where to find the bl31 image, using the BL31 environment variable.
How do you know how to incorporate ATF? It is handled by the atf-bl31 entry type
(etype). An etype is an implementation of reading a binary into binman, in this
case the `bl31.bin` file. When you build U-Boot but do not set the BL31
environment variable, binman provides a help message, which comes from
`missing-blob-help`::
See the documentation for your board. You may need to build ARM Trusted
Firmware and build with BL31=/path/to/bl31.bin
The mechanism by which binman is advised of this is also in the Makefile. See
the `-a atf-bl31-path=${BL31}` piece in `cmd_binman`. This tells binman to
set the EntryArg `atf-bl31-path` to the value of the `BL31` environment
variable. Within binman, this EntryArg is picked up by the `Entry_atf_bl31`
etype. An EntryArg is simply an argument to the entry. The `atf-bl31-path`
name is documented in :ref:`etype_atf_bl31`.
Invoking binman outside U-Boot
------------------------------
While binman is invoked from within the U-Boot build system, it is also possible
to invoke it separately. This is typically used in a production build system,
where signing is completed (with real keys) and any missing binaries are
provided.
For example, for build testing there is no need to provide a real signature,
nor is there any need to provide a real ATF BL31 binary (for example). These can
be added later by invoking binman again, providing all the required inputs
from the first time, plus any that were missing or placeholders.
So in practice binman is often used twice:
- once within the U-Boot build system, for development and testing
- again outside U-Boot to assembly and final production images
While the same input binaries are used in each case, you will of course you will
need to create your own binman command line, similar to that in `cmd_binman` in
the Makefile. You may find the -I and --toolpath options useful. The
device tree file is provided to binman in binary form, so there is no need to
have access to the original `.dts` sources.
Assembling the image description
--------------------------------
Since binman uses the device tree for its image description, you can use the
same files that describe your board's hardware to describe how the image is
assembled. Typically the images description is in a common file used by all
boards with a particular SoC (e.g. `imx8mp-u-boot.dtsi`).
Where a particular boards needs to make changes, it can override properties in
the SoC file, just as it would for any other device tree property. It can also
add a image that is specific to the board.
Another way to control the image description to make use of CONFIG options in
the description. For example, if the start offset of a particular entry varies
by board, you can add a Kconfig for that and reference it in the description::
u-boot-spl {
};
fit {
offset = <CONFIG_SPL_PAD_TO>;
...
};
The SoC can provide a default value but boards can override that as needed and
binman will take care of it.
It is even possible to control which entries appear in the image, by using the
C preprocessor::
#ifdef CONFIG_HAVE_MRC
intel-mrc {
offset = <CONFIG_X86_MRC_ADDR>;
};
#endif
Only boards which enable `HAVE_MRC` will include this entry.
Obviously a similar approach can be used to control which images are produced,
with a Kconfig option to enable a SPI image, for example. However there is
generally no harm in producing an image that is not used. If a board uses MMC
but not SPI, but the SoC supports booting from both, then both images can be
produced, with only on or other being used by particular boards. This can help
reduce the need for having multiple defconfig targets for a board where the
only difference is the boot media, enabling / disabling secure boot, etc.
Of course you can use the device tree itself to pass any board-specific
information that is needed by U-Boot at runtime (see binman_syms_ for how to
make binman insert these values directly into executables like SPL).
There is one more way this can be done: with individual .dtsi files for each
image supported by the SoC. Then the board `.dts` file can include the ones it
wants. This is not recommended, since it is likely to be difficult to maintain
and harder to understand the relationship between the different boards.
Producing images for multiple boards
------------------------------------
When invoked within U-Boot, binman only builds a single set of images, for
the chosen board. This is set by the `CONFIG_DEFAULT_DEVICE_TREE` option.
However, U-Boot generally builds all the device tree files associated with an
SoC. These are written to the (e.g. for ARM) `arch/arm/dts` directory. Each of
these contains the full binman description for that board. Often the best
approach is to build a single image that includes all these device tree binaries
and allow SPL to select the correct one on boot.
However, it is also possible to build separate images for each board, simply by
invoking binman multiple times, once for each device tree file, using a
different output directory. This will produce one set of images for each board.
Example use of binman for x86
-----------------------------
@ -188,19 +353,25 @@ the configuration of the Intel-format descriptor.
Installing binman
-----------------
First install prerequisites, e.g::
First install prerequisites, e.g:
.. code-block:: bash
sudo apt-get install python-pyelftools python3-pyelftools lzma-alone \
liblz4-tool
You can run binman directly if you put it on your PATH. But if you want to
install into your `~/.local` Python directory, use::
install into your `~/.local` Python directory, use:
.. code-block:: bash
pip install tools/patman tools/dtoc tools/binman
Note that binman makes use of libraries from patman and dtoc, which is why these
need to be installed. Also you need `libfdt` and `pylibfdt` which can be
installed like this::
installed like this:
.. code-block:: bash
git clone git://git.kernel.org/pub/scm/utils/dtc/dtc.git
cd dtc
@ -209,7 +380,9 @@ installed like this::
This installs the `libfdt.so` library into `~/lib` so you can use
`LD_LIBRARY_PATH=~/lib` when running binman. If you want to install it in the
system-library directory, replace the last line with::
system-library directory, replace the last line with:
.. code-block:: bash
make NO_PYTHON=1 PREFIX=/ install
@ -218,14 +391,20 @@ Running binman
Type::
.. code-block: bash
make NO_PYTHON=1 PREFIX=/ install
binman build -b <board_name>
to build an image for a board. The board name is the same name used when
configuring U-Boot (e.g. for sandbox_defconfig the board name is 'sandbox').
Binman assumes that the input files for the build are in ../b/<board_name>.
Or you can specify this explicitly::
Or you can specify this explicitly:
.. code-block:: bash
make NO_PYTHON=1 PREFIX=/ install
binman build -I <build_path>
where <build_path> is the build directory containing the output of the U-Boot
@ -254,6 +433,7 @@ file, typically <soc>-u-boot.dtsi, where <soc> is your CONFIG_SYS_SOC value.
You can use other, more specific CONFIG options - see 'Automatic .dtsi
inclusion' below.
.. _binman_syms:
Access to binman entry offsets at run time (symbols)
----------------------------------------------------
@ -264,13 +444,17 @@ is useful to be able to find the location of U-Boot so that it can be executed
when SPL is finished.
Binman allows you to declare symbols in the SPL image which are filled in
with their correct values during the build. For example::
with their correct values during the build. For example:
.. code-block:: c
binman_sym_declare(ulong, u_boot_any, image_pos);
declares a ulong value which will be assigned to the image-pos of any U-Boot
image (u-boot.bin, u-boot.img, u-boot-nodtb.bin) that is present in the image.
You can access this value with something like::
You can access this value with something like:
.. code-block:: c
ulong u_boot_offset = binman_sym(ulong, u_boot_any, image_pos);