From 7d6fadef84de958e83856efdd257ae98280dd74a Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Sun, 7 Aug 2022 16:33:26 -0600 Subject: [PATCH] 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 Acked-by: Heinrich Schuchardt --- doc/Makefile | 1 + tools/binman/binman.rst | 200 ++++++++++++++++++++++++++++++++++++++-- 2 files changed, 193 insertions(+), 8 deletions(-) diff --git a/doc/Makefile b/doc/Makefile index 050d9dd239..6081858726 100644 --- a/doc/Makefile +++ b/doc/Makefile @@ -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) \ diff --git a/tools/binman/binman.rst b/tools/binman/binman.rst index 935839c433..6e1fd3476f 100644 --- a/tools/binman/binman.rst +++ b/tools/binman/binman.rst @@ -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 = ; + ... + }; + +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 = ; + }; + #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 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/. -Or you can specify this explicitly:: +Or you can specify this explicitly: +.. code-block:: bash + + make NO_PYTHON=1 PREFIX=/ install binman build -I where is the build directory containing the output of the U-Boot @@ -254,6 +433,7 @@ file, typically -u-boot.dtsi, where 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); -- 2.39.5