781 lines
29 KiB
Text
781 lines
29 KiB
Text
|
# SPDX-License-Identifier: GPL-2.0+
|
||
|
# Copyright (c) 2016 Google, Inc
|
||
|
|
||
|
Introduction
|
||
|
------------
|
||
|
|
||
|
Firmware often consists of several components which must be packaged together.
|
||
|
For example, we may have SPL, U-Boot, a device tree and an environment area
|
||
|
grouped together and placed in MMC flash. When the system starts, it must be
|
||
|
able to find these pieces.
|
||
|
|
||
|
So far U-Boot has not provided a way to handle creating such images in a
|
||
|
general way. Each SoC does what it needs to build an image, often packing or
|
||
|
concatenating images in the U-Boot build system.
|
||
|
|
||
|
Binman aims to provide a mechanism for building images, from simple
|
||
|
SPL + U-Boot combinations, to more complex arrangements with many parts.
|
||
|
|
||
|
|
||
|
What it does
|
||
|
------------
|
||
|
|
||
|
Binman reads your board's device tree and finds a node which describes the
|
||
|
required image layout. It uses this to work out what to place where. The
|
||
|
output file normally contains the device tree, so it is in principle possible
|
||
|
to read an image and extract its constituent parts.
|
||
|
|
||
|
|
||
|
Features
|
||
|
--------
|
||
|
|
||
|
So far binman is pretty simple. It supports binary blobs, such as 'u-boot',
|
||
|
'spl' and 'fdt'. It supports empty entries (such as setting to 0xff). It can
|
||
|
place entries at a fixed location in the image, or fit them together with
|
||
|
suitable padding and alignment. It provides a way to process binaries before
|
||
|
they are included, by adding a Python plug-in. The device tree is available
|
||
|
to U-Boot at run-time so that the images can be interpreted.
|
||
|
|
||
|
Binman does not yet update the device tree with the final location of
|
||
|
everything when it is done. A simple C structure could be generated for
|
||
|
constrained environments like SPL (using dtoc) but this is also not
|
||
|
implemented.
|
||
|
|
||
|
Binman can also support incorporating filesystems in the image if required.
|
||
|
For example x86 platforms may use CBFS in some cases.
|
||
|
|
||
|
Binman is intended for use with U-Boot but is designed to be general enough
|
||
|
to be useful in other image-packaging situations.
|
||
|
|
||
|
|
||
|
Motivation
|
||
|
----------
|
||
|
|
||
|
Packaging of firmware is quite a different task from building the various
|
||
|
parts. In many cases the various binaries which go into the image come from
|
||
|
separate build systems. For example, ARM Trusted Firmware is used on ARMv8
|
||
|
devices but is not built in the U-Boot tree. If a Linux kernel is included
|
||
|
in the firmware image, it is built elsewhere.
|
||
|
|
||
|
It is of course possible to add more and more build rules to the U-Boot
|
||
|
build system to cover these cases. It can shell out to other Makefiles and
|
||
|
build scripts. But it seems better to create a clear divide between building
|
||
|
software and packaging it.
|
||
|
|
||
|
At present this is handled by manual instructions, different for each board,
|
||
|
on how to create images that will boot. By turning these instructions into a
|
||
|
standard format, we can support making valid images for any board without
|
||
|
manual effort, lots of READMEs, etc.
|
||
|
|
||
|
Benefits:
|
||
|
- Each binary can have its own build system and tool chain without creating
|
||
|
any dependencies between them
|
||
|
- Avoids the need for a single-shot build: individual parts can be updated
|
||
|
and brought in as needed
|
||
|
- Provides for a standard image description available in the build and at
|
||
|
run-time
|
||
|
- SoC-specific image-signing tools can be accomodated
|
||
|
- Avoids cluttering the U-Boot build system with image-building code
|
||
|
- The image description is automatically available at run-time in U-Boot,
|
||
|
SPL. It can be made available to other software also
|
||
|
- The image description is easily readable (it's a text file in device-tree
|
||
|
format) and permits flexible packing of binaries
|
||
|
|
||
|
|
||
|
Terminology
|
||
|
-----------
|
||
|
|
||
|
Binman uses the following terms:
|
||
|
|
||
|
- image - an output file containing a firmware image
|
||
|
- binary - an input binary that goes into the image
|
||
|
|
||
|
|
||
|
Relationship to FIT
|
||
|
-------------------
|
||
|
|
||
|
FIT is U-Boot's official image format. It supports multiple binaries with
|
||
|
load / execution addresses, compression. It also supports verification
|
||
|
through hashing and RSA signatures.
|
||
|
|
||
|
FIT was originally designed to support booting a Linux kernel (with an
|
||
|
optional ramdisk) and device tree chosen from various options in the FIT.
|
||
|
Now that U-Boot supports configuration via device tree, it is possible to
|
||
|
load U-Boot from a FIT, with the device tree chosen by SPL.
|
||
|
|
||
|
Binman considers FIT to be one of the binaries it can place in the image.
|
||
|
|
||
|
Where possible it is best to put as much as possible in the FIT, with binman
|
||
|
used to deal with cases not covered by FIT. Examples include initial
|
||
|
execution (since FIT itself does not have an executable header) and dealing
|
||
|
with device boundaries, such as the read-only/read-write separation in SPI
|
||
|
flash.
|
||
|
|
||
|
For U-Boot, binman should not be used to create ad-hoc images in place of
|
||
|
FIT.
|
||
|
|
||
|
|
||
|
Relationship to mkimage
|
||
|
-----------------------
|
||
|
|
||
|
The mkimage tool provides a means to create a FIT. Traditionally it has
|
||
|
needed an image description file: a device tree, like binman, but in a
|
||
|
different format. More recently it has started to support a '-f auto' mode
|
||
|
which can generate that automatically.
|
||
|
|
||
|
More relevant to binman, mkimage also permits creation of many SoC-specific
|
||
|
image types. These can be listed by running 'mkimage -T list'. Examples
|
||
|
include 'rksd', the Rockchip SD/MMC boot format. The mkimage tool is often
|
||
|
called from the U-Boot build system for this reason.
|
||
|
|
||
|
Binman considers the output files created by mkimage to be binary blobs
|
||
|
which it can place in an image. Binman does not replace the mkimage tool or
|
||
|
this purpose. It would be possible in some situations to create a new entry
|
||
|
type for the images in mkimage, but this would not add functionality. It
|
||
|
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).
|
||
|
|
||
|
|
||
|
Example use of binman in U-Boot
|
||
|
-------------------------------
|
||
|
|
||
|
Binman aims to replace some of the ad-hoc image creation in the U-Boot
|
||
|
build system.
|
||
|
|
||
|
Consider sunxi. It has the following steps:
|
||
|
|
||
|
1. It uses a custom mksunxiboot tool to build an SPL image called
|
||
|
sunxi-spl.bin. This should probably move into mkimage.
|
||
|
|
||
|
2. It uses mkimage to package U-Boot into a legacy image file (so that it can
|
||
|
hold the load and execution address) called u-boot.img.
|
||
|
|
||
|
3. It builds a final output image called u-boot-sunxi-with-spl.bin which
|
||
|
consists of sunxi-spl.bin, some padding and u-boot.img.
|
||
|
|
||
|
Binman is intended to replace the last step. The U-Boot build system builds
|
||
|
u-boot.bin and sunxi-spl.bin. Binman can then take over creation of
|
||
|
sunxi-spl.bin (by calling mksunxiboot, or hopefully one day mkimage). In any
|
||
|
case, it would then create the image from the component parts.
|
||
|
|
||
|
This simplifies the U-Boot Makefile somewhat, since various pieces of logic
|
||
|
can be replaced by a call to binman.
|
||
|
|
||
|
|
||
|
Example use of binman for x86
|
||
|
-----------------------------
|
||
|
|
||
|
In most cases x86 images have a lot of binary blobs, 'black-box' code
|
||
|
provided by Intel which must be run for the platform to work. Typically
|
||
|
these blobs are not relocatable and must be placed at fixed areas in the
|
||
|
firmware image.
|
||
|
|
||
|
Currently this is handled by ifdtool, which places microcode, FSP, MRC, VGA
|
||
|
BIOS, reference code and Intel ME binaries into a u-boot.rom file.
|
||
|
|
||
|
Binman is intended to replace all of this, with ifdtool left to handle only
|
||
|
the configuration of the Intel-format descriptor.
|
||
|
|
||
|
|
||
|
Running binman
|
||
|
--------------
|
||
|
|
||
|
Type:
|
||
|
|
||
|
binman -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:
|
||
|
|
||
|
binman -I <build_path>
|
||
|
|
||
|
where <build_path> is the build directory containing the output of the U-Boot
|
||
|
build.
|
||
|
|
||
|
(Future work will make this more configurable)
|
||
|
|
||
|
In either case, binman picks up the device tree file (u-boot.dtb) and looks
|
||
|
for its instructions in the 'binman' node.
|
||
|
|
||
|
Binman has a few other options which you can see by running 'binman -h'.
|
||
|
|
||
|
|
||
|
Enabling binman for a board
|
||
|
---------------------------
|
||
|
|
||
|
At present binman is invoked from a rule in the main Makefile. Typically you
|
||
|
will have a rule like:
|
||
|
|
||
|
ifneq ($(CONFIG_ARCH_<something>),)
|
||
|
u-boot-<your_suffix>.bin: <input_file_1> <input_file_2> checkbinman FORCE
|
||
|
$(call if_changed,binman)
|
||
|
endif
|
||
|
|
||
|
This assumes that u-boot-<your_suffix>.bin is a target, and is the final file
|
||
|
that you need to produce. You can make it a target by adding it to ALL-y
|
||
|
either in the main Makefile or in a config.mk file in your arch subdirectory.
|
||
|
|
||
|
Once binman is executed it will pick up its instructions from a device-tree
|
||
|
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.
|
||
|
|
||
|
|
||
|
Image description format
|
||
|
------------------------
|
||
|
|
||
|
The binman node is called 'binman'. An example image description is shown
|
||
|
below:
|
||
|
|
||
|
binman {
|
||
|
filename = "u-boot-sunxi-with-spl.bin";
|
||
|
pad-byte = <0xff>;
|
||
|
blob {
|
||
|
filename = "spl/sunxi-spl.bin";
|
||
|
};
|
||
|
u-boot {
|
||
|
offset = <CONFIG_SPL_PAD_TO>;
|
||
|
};
|
||
|
};
|
||
|
|
||
|
|
||
|
This requests binman to create an image file called u-boot-sunxi-with-spl.bin
|
||
|
consisting of a specially formatted SPL (spl/sunxi-spl.bin, built by the
|
||
|
normal U-Boot Makefile), some 0xff padding, and a U-Boot legacy image. The
|
||
|
padding comes from the fact that the second binary is placed at
|
||
|
CONFIG_SPL_PAD_TO. If that line were omitted then the U-Boot binary would
|
||
|
immediately follow the SPL binary.
|
||
|
|
||
|
The binman node describes an image. The sub-nodes describe entries in the
|
||
|
image. Each entry represents a region within the overall image. The name of
|
||
|
the entry (blob, u-boot) tells binman what to put there. For 'blob' we must
|
||
|
provide a filename. For 'u-boot', binman knows that this means 'u-boot.bin'.
|
||
|
|
||
|
Entries are normally placed into the image sequentially, one after the other.
|
||
|
The image size is the total size of all entries. As you can see, you can
|
||
|
specify the start offset of an entry using the 'offset' property.
|
||
|
|
||
|
Note that due to a device tree requirement, all entries must have a unique
|
||
|
name. If you want to put the same binary in the image multiple times, you can
|
||
|
use any unique name, with the 'type' property providing the type.
|
||
|
|
||
|
The attributes supported for entries are described below.
|
||
|
|
||
|
offset:
|
||
|
This sets the offset of an entry within the image or section containing
|
||
|
it. The first byte of the image is normally at offset 0. If 'offset' is
|
||
|
not provided, binman sets it to the end of the previous region, or the
|
||
|
start of the image's entry area (normally 0) if there is no previous
|
||
|
region.
|
||
|
|
||
|
align:
|
||
|
This sets the alignment of the entry. The entry offset is adjusted
|
||
|
so that the entry starts on an aligned boundary within the image. For
|
||
|
example 'align = <16>' means that the entry will start on a 16-byte
|
||
|
boundary. Alignment shold be a power of 2. If 'align' is not
|
||
|
provided, no alignment is performed.
|
||
|
|
||
|
size:
|
||
|
This sets the size of the entry. The contents will be padded out to
|
||
|
this size. If this is not provided, it will be set to the size of the
|
||
|
contents.
|
||
|
|
||
|
pad-before:
|
||
|
Padding before the contents of the entry. Normally this is 0, meaning
|
||
|
that the contents start at the beginning of the entry. This can be
|
||
|
offset the entry contents a little. Defaults to 0.
|
||
|
|
||
|
pad-after:
|
||
|
Padding after the contents of the entry. Normally this is 0, meaning
|
||
|
that the entry ends at the last byte of content (unless adjusted by
|
||
|
other properties). This allows room to be created in the image for
|
||
|
this entry to expand later. Defaults to 0.
|
||
|
|
||
|
align-size:
|
||
|
This sets the alignment of the entry size. For example, to ensure
|
||
|
that the size of an entry is a multiple of 64 bytes, set this to 64.
|
||
|
If 'align-size' is not provided, no alignment is performed.
|
||
|
|
||
|
align-end:
|
||
|
This sets the alignment of the end of an entry. Some entries require
|
||
|
that they end on an alignment boundary, regardless of where they
|
||
|
start. This does not move the start of the entry, so the contents of
|
||
|
the entry will still start at the beginning. But there may be padding
|
||
|
at the end. If 'align-end' is not provided, no alignment is performed.
|
||
|
|
||
|
filename:
|
||
|
For 'blob' types this provides the filename containing the binary to
|
||
|
put into the entry. If binman knows about the entry type (like
|
||
|
u-boot-bin), then there is no need to specify this.
|
||
|
|
||
|
type:
|
||
|
Sets the type of an entry. This defaults to the entry name, but it is
|
||
|
possible to use any name, and then add (for example) 'type = "u-boot"'
|
||
|
to specify the type.
|
||
|
|
||
|
offset-unset:
|
||
|
Indicates that the offset of this entry should not be set by placing
|
||
|
it immediately after the entry before. Instead, is set by another
|
||
|
entry which knows where this entry should go. When this boolean
|
||
|
property is present, binman will give an error if another entry does
|
||
|
not set the offset (with the GetOffsets() method).
|
||
|
|
||
|
image-pos:
|
||
|
This cannot be set on entry (or at least it is ignored if it is), but
|
||
|
with the -u option, binman will set it to the absolute image position
|
||
|
for each entry. This makes it easy to find out exactly where the entry
|
||
|
ended up in the image, regardless of parent sections, etc.
|
||
|
|
||
|
expand-size:
|
||
|
Expand the size of this entry to fit available space. This space is only
|
||
|
limited by the size of the image/section and the position of the next
|
||
|
entry.
|
||
|
|
||
|
The attributes supported for images and sections are described below. Several
|
||
|
are similar to those for entries.
|
||
|
|
||
|
size:
|
||
|
Sets the image size in bytes, for example 'size = <0x100000>' for a
|
||
|
1MB image.
|
||
|
|
||
|
align-size:
|
||
|
This sets the alignment of the image size. For example, to ensure
|
||
|
that the image ends on a 512-byte boundary, use 'align-size = <512>'.
|
||
|
If 'align-size' is not provided, no alignment is performed.
|
||
|
|
||
|
pad-before:
|
||
|
This sets the padding before the image entries. The first entry will
|
||
|
be positioned after the padding. This defaults to 0.
|
||
|
|
||
|
pad-after:
|
||
|
This sets the padding after the image entries. The padding will be
|
||
|
placed after the last entry. This defaults to 0.
|
||
|
|
||
|
pad-byte:
|
||
|
This specifies the pad byte to use when padding in the image. It
|
||
|
defaults to 0. To use 0xff, you would add 'pad-byte = <0xff>'.
|
||
|
|
||
|
filename:
|
||
|
This specifies the image filename. It defaults to 'image.bin'.
|
||
|
|
||
|
sort-by-offset:
|
||
|
This causes binman to reorder the entries as needed to make sure they
|
||
|
are in increasing positional order. This can be used when your entry
|
||
|
order may not match the positional order. A common situation is where
|
||
|
the 'offset' properties are set by CONFIG options, so their ordering is
|
||
|
not known a priori.
|
||
|
|
||
|
This is a boolean property so needs no value. To enable it, add a
|
||
|
line 'sort-by-offset;' to your description.
|
||
|
|
||
|
multiple-images:
|
||
|
Normally only a single image is generated. To create more than one
|
||
|
image, put this property in the binman node. For example, this will
|
||
|
create image1.bin containing u-boot.bin, and image2.bin containing
|
||
|
both spl/u-boot-spl.bin and u-boot.bin:
|
||
|
|
||
|
binman {
|
||
|
multiple-images;
|
||
|
image1 {
|
||
|
u-boot {
|
||
|
};
|
||
|
};
|
||
|
|
||
|
image2 {
|
||
|
spl {
|
||
|
};
|
||
|
u-boot {
|
||
|
};
|
||
|
};
|
||
|
};
|
||
|
|
||
|
end-at-4gb:
|
||
|
For x86 machines the ROM offsets start just before 4GB and extend
|
||
|
up so that the image finished at the 4GB boundary. This boolean
|
||
|
option can be enabled to support this. The image size must be
|
||
|
provided so that binman knows when the image should start. For an
|
||
|
8MB ROM, the offset of the first entry would be 0xfff80000 with
|
||
|
this option, instead of 0 without this option.
|
||
|
|
||
|
skip-at-start:
|
||
|
This property specifies the entry offset of the first entry.
|
||
|
|
||
|
For PowerPC mpc85xx based CPU, CONFIG_SYS_TEXT_BASE is the entry
|
||
|
offset of the first entry. It can be 0xeff40000 or 0xfff40000 for
|
||
|
nor flash boot, 0x201000 for sd boot etc.
|
||
|
|
||
|
'end-at-4gb' property is not applicable where CONFIG_SYS_TEXT_BASE +
|
||
|
Image size != 4gb.
|
||
|
|
||
|
Examples of the above options can be found in the tests. See the
|
||
|
tools/binman/test directory.
|
||
|
|
||
|
It is possible to have the same binary appear multiple times in the image,
|
||
|
either by using a unit number suffix (u-boot@0, u-boot@1) or by using a
|
||
|
different name for each and specifying the type with the 'type' attribute.
|
||
|
|
||
|
|
||
|
Sections and hierachical images
|
||
|
-------------------------------
|
||
|
|
||
|
Sometimes it is convenient to split an image into several pieces, each of which
|
||
|
contains its own set of binaries. An example is a flash device where part of
|
||
|
the image is read-only and part is read-write. We can set up sections for each
|
||
|
of these, and place binaries in them independently. The image is still produced
|
||
|
as a single output file.
|
||
|
|
||
|
This feature provides a way of creating hierarchical images. For example here
|
||
|
is an example image with two copies of U-Boot. One is read-only (ro), intended
|
||
|
to be written only in the factory. Another is read-write (rw), so that it can be
|
||
|
upgraded in the field. The sizes are fixed so that the ro/rw boundary is known
|
||
|
and can be programmed:
|
||
|
|
||
|
binman {
|
||
|
section@0 {
|
||
|
read-only;
|
||
|
name-prefix = "ro-";
|
||
|
size = <0x100000>;
|
||
|
u-boot {
|
||
|
};
|
||
|
};
|
||
|
section@1 {
|
||
|
name-prefix = "rw-";
|
||
|
size = <0x100000>;
|
||
|
u-boot {
|
||
|
};
|
||
|
};
|
||
|
};
|
||
|
|
||
|
This image could be placed into a SPI flash chip, with the protection boundary
|
||
|
set at 1MB.
|
||
|
|
||
|
A few special properties are provided for sections:
|
||
|
|
||
|
read-only:
|
||
|
Indicates that this section is read-only. This has no impact on binman's
|
||
|
operation, but his property can be read at run time.
|
||
|
|
||
|
name-prefix:
|
||
|
This string is prepended to all the names of the binaries in the
|
||
|
section. In the example above, the 'u-boot' binaries which actually be
|
||
|
renamed to 'ro-u-boot' and 'rw-u-boot'. This can be useful to
|
||
|
distinguish binaries with otherwise identical names.
|
||
|
|
||
|
|
||
|
Entry Documentation
|
||
|
-------------------
|
||
|
|
||
|
For details on the various entry types supported by binman and how to use them,
|
||
|
see README.entries. This is generated from the source code using:
|
||
|
|
||
|
binman -E >tools/binman/README.entries
|
||
|
|
||
|
|
||
|
Hashing Entries
|
||
|
---------------
|
||
|
|
||
|
It is possible to ask binman to hash the contents of an entry and write that
|
||
|
value back to the device-tree node. For example:
|
||
|
|
||
|
binman {
|
||
|
u-boot {
|
||
|
hash {
|
||
|
algo = "sha256";
|
||
|
};
|
||
|
};
|
||
|
};
|
||
|
|
||
|
Here, a new 'value' property will be written to the 'hash' node containing
|
||
|
the hash of the 'u-boot' entry. Only SHA256 is supported at present. Whole
|
||
|
sections can be hased if desired, by adding the 'hash' node to the section.
|
||
|
|
||
|
The has value can be chcked at runtime by hashing the data actually read and
|
||
|
comparing this has to the value in the device tree.
|
||
|
|
||
|
|
||
|
Order of image creation
|
||
|
-----------------------
|
||
|
|
||
|
Image creation proceeds in the following order, for each entry in the image.
|
||
|
|
||
|
1. AddMissingProperties() - binman can add calculated values to the device
|
||
|
tree as part of its processing, for example the offset and size of each
|
||
|
entry. This method adds any properties associated with this, expanding the
|
||
|
device tree as needed. These properties can have placeholder values which are
|
||
|
set later by SetCalculatedProperties(). By that stage the size of sections
|
||
|
cannot be changed (since it would cause the images to need to be repacked),
|
||
|
but the correct values can be inserted.
|
||
|
|
||
|
2. ProcessFdt() - process the device tree information as required by the
|
||
|
particular entry. This may involve adding or deleting properties. If the
|
||
|
processing is complete, this method should return True. If the processing
|
||
|
cannot complete because it needs the ProcessFdt() method of another entry to
|
||
|
run first, this method should return False, in which case it will be called
|
||
|
again later.
|
||
|
|
||
|
3. GetEntryContents() - the contents of each entry are obtained, normally by
|
||
|
reading from a file. This calls the Entry.ObtainContents() to read the
|
||
|
contents. The default version of Entry.ObtainContents() calls
|
||
|
Entry.GetDefaultFilename() and then reads that file. So a common mechanism
|
||
|
to select a file to read is to override that function in the subclass. The
|
||
|
functions must return True when they have read the contents. Binman will
|
||
|
retry calling the functions a few times if False is returned, allowing
|
||
|
dependencies between the contents of different entries.
|
||
|
|
||
|
4. GetEntryOffsets() - calls Entry.GetOffsets() for each entry. This can
|
||
|
return a dict containing entries that need updating. The key should be the
|
||
|
entry name and the value is a tuple (offset, size). This allows an entry to
|
||
|
provide the offset and size for other entries. The default implementation
|
||
|
of GetEntryOffsets() returns {}.
|
||
|
|
||
|
5. PackEntries() - calls Entry.Pack() which figures out the offset and
|
||
|
size of an entry. The 'current' image offset is passed in, and the function
|
||
|
returns the offset immediately after the entry being packed. The default
|
||
|
implementation of Pack() is usually sufficient.
|
||
|
|
||
|
6. CheckSize() - checks that the contents of all the entries fits within
|
||
|
the image size. If the image does not have a defined size, the size is set
|
||
|
large enough to hold all the entries.
|
||
|
|
||
|
7. CheckEntries() - checks that the entries do not overlap, nor extend
|
||
|
outside the image.
|
||
|
|
||
|
8. SetCalculatedProperties() - update any calculated properties in the device
|
||
|
tree. This sets the correct 'offset' and 'size' vaues, for example.
|
||
|
|
||
|
9. ProcessEntryContents() - this calls Entry.ProcessContents() on each entry.
|
||
|
The default implementatoin does nothing. This can be overriden to adjust the
|
||
|
contents of an entry in some way. For example, it would be possible to create
|
||
|
an entry containing a hash of the contents of some other entries. At this
|
||
|
stage the offset and size of entries should not be adjusted.
|
||
|
|
||
|
10. WriteSymbols() - write the value of symbols into the U-Boot SPL binary.
|
||
|
See 'Access to binman entry offsets at run time' below for a description of
|
||
|
what happens in this stage.
|
||
|
|
||
|
11. BuildImage() - builds the image and writes it to a file. This is the final
|
||
|
step.
|
||
|
|
||
|
|
||
|
Automatic .dtsi inclusion
|
||
|
-------------------------
|
||
|
|
||
|
It is sometimes inconvenient to add a 'binman' node to the .dts file for each
|
||
|
board. This can be done by using #include to bring in a common file. Another
|
||
|
approach supported by the U-Boot build system is to automatically include
|
||
|
a common header. You can then put the binman node (and anything else that is
|
||
|
specific to U-Boot, such as u-boot,dm-pre-reloc properies) in that header
|
||
|
file.
|
||
|
|
||
|
Binman will search for the following files in arch/<arch>/dts:
|
||
|
|
||
|
<dts>-u-boot.dtsi where <dts> is the base name of the .dts file
|
||
|
<CONFIG_SYS_SOC>-u-boot.dtsi
|
||
|
<CONFIG_SYS_CPU>-u-boot.dtsi
|
||
|
<CONFIG_SYS_VENDOR>-u-boot.dtsi
|
||
|
u-boot.dtsi
|
||
|
|
||
|
U-Boot will only use the first one that it finds. If you need to include a
|
||
|
more general file you can do that from the more specific file using #include.
|
||
|
If you are having trouble figuring out what is going on, you can uncomment
|
||
|
the 'warning' line in scripts/Makefile.lib to see what it has found:
|
||
|
|
||
|
# Uncomment for debugging
|
||
|
# This shows all the files that were considered and the one that we chose.
|
||
|
# u_boot_dtsi_options_debug = $(u_boot_dtsi_options_raw)
|
||
|
|
||
|
|
||
|
Access to binman entry offsets at run time (symbols)
|
||
|
----------------------------------------------------
|
||
|
|
||
|
Binman assembles images and determines where each entry is placed in the image.
|
||
|
This information may be useful to U-Boot at run time. For example, in SPL it
|
||
|
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:
|
||
|
|
||
|
binman_sym_declare(ulong, u_boot_any, offset);
|
||
|
|
||
|
declares a ulong value which will be assigned to the offset 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:
|
||
|
|
||
|
ulong u_boot_offset = binman_sym(ulong, u_boot_any, offset);
|
||
|
|
||
|
Thus u_boot_offset will be set to the offset of U-Boot in memory, assuming that
|
||
|
the whole image has been loaded, or is available in flash. You can then jump to
|
||
|
that address to start U-Boot.
|
||
|
|
||
|
At present this feature is only supported in SPL. In principle it is possible
|
||
|
to fill in such symbols in U-Boot proper, as well.
|
||
|
|
||
|
|
||
|
Access to binman entry offsets at run time (fdt)
|
||
|
------------------------------------------------
|
||
|
|
||
|
Binman can update the U-Boot FDT to include the final position and size of
|
||
|
each entry in the images it processes. The option to enable this is -u and it
|
||
|
causes binman to make sure that the 'offset', 'image-pos' and 'size' properties
|
||
|
are set correctly for every entry. Since it is not necessary to specify these in
|
||
|
the image definition, binman calculates the final values and writes these to
|
||
|
the device tree. These can be used by U-Boot at run-time to find the location
|
||
|
of each entry.
|
||
|
|
||
|
|
||
|
Compression
|
||
|
-----------
|
||
|
|
||
|
Binman support compression for 'blob' entries (those of type 'blob' and
|
||
|
derivatives). To enable this for an entry, add a 'compression' property:
|
||
|
|
||
|
blob {
|
||
|
filename = "datafile";
|
||
|
compression = "lz4";
|
||
|
};
|
||
|
|
||
|
The entry will then contain the compressed data, using the 'lz4' compression
|
||
|
algorithm. Currently this is the only one that is supported.
|
||
|
|
||
|
|
||
|
|
||
|
Map files
|
||
|
---------
|
||
|
|
||
|
The -m option causes binman to output a .map file for each image that it
|
||
|
generates. This shows the offset and size of each entry. For example:
|
||
|
|
||
|
Offset Size Name
|
||
|
00000000 00000028 main-section
|
||
|
00000000 00000010 section@0
|
||
|
00000000 00000004 u-boot
|
||
|
00000010 00000010 section@1
|
||
|
00000000 00000004 u-boot
|
||
|
|
||
|
This shows a hierarchical image with two sections, each with a single entry. The
|
||
|
offsets of the sections are absolute hex byte offsets within the image. The
|
||
|
offsets of the entries are relative to their respective sections. The size of
|
||
|
each entry is also shown, in bytes (hex). The indentation shows the entries
|
||
|
nested inside their sections.
|
||
|
|
||
|
|
||
|
Passing command-line arguments to entries
|
||
|
-----------------------------------------
|
||
|
|
||
|
Sometimes it is useful to pass binman the value of an entry property from the
|
||
|
command line. For example some entries need access to files and it is not
|
||
|
always convenient to put these filenames in the image definition (device tree).
|
||
|
|
||
|
The-a option supports this:
|
||
|
|
||
|
-a<prop>=<value>
|
||
|
|
||
|
where
|
||
|
|
||
|
<prop> is the property to set
|
||
|
<value> is the value to set it to
|
||
|
|
||
|
Not all properties can be provided this way. Only some entries support it,
|
||
|
typically for filenames.
|
||
|
|
||
|
|
||
|
Code coverage
|
||
|
-------------
|
||
|
|
||
|
Binman is a critical tool and is designed to be very testable. Entry
|
||
|
implementations target 100% test coverage. Run 'binman -T' to check this.
|
||
|
|
||
|
To enable Python test coverage on Debian-type distributions (e.g. Ubuntu):
|
||
|
|
||
|
$ sudo apt-get install python-coverage python-pytest
|
||
|
|
||
|
|
||
|
Advanced Features / Technical docs
|
||
|
----------------------------------
|
||
|
|
||
|
The behaviour of entries is defined by the Entry class. All other entries are
|
||
|
a subclass of this. An important subclass is Entry_blob which takes binary
|
||
|
data from a file and places it in the entry. In fact most entry types are
|
||
|
subclasses of Entry_blob.
|
||
|
|
||
|
Each entry type is a separate file in the tools/binman/etype directory. Each
|
||
|
file contains a class called Entry_<type> where <type> is the entry type.
|
||
|
New entry types can be supported by adding new files in that directory.
|
||
|
These will automatically be detected by binman when needed.
|
||
|
|
||
|
Entry properties are documented in entry.py. The entry subclasses are free
|
||
|
to change the values of properties to support special behaviour. For example,
|
||
|
when Entry_blob loads a file, it sets content_size to the size of the file.
|
||
|
Entry classes can adjust other entries. For example, an entry that knows
|
||
|
where other entries should be positioned can set up those entries' offsets
|
||
|
so they don't need to be set in the binman decription. It can also adjust
|
||
|
entry contents.
|
||
|
|
||
|
Most of the time such essoteric behaviour is not needed, but it can be
|
||
|
essential for complex images.
|
||
|
|
||
|
If you need to specify a particular device-tree compiler to use, you can define
|
||
|
the DTC environment variable. This can be useful when the system dtc is too
|
||
|
old.
|
||
|
|
||
|
To enable a full backtrace and other debugging features in binman, pass
|
||
|
BINMAN_DEBUG=1 to your build:
|
||
|
|
||
|
make sandbox_defconfig
|
||
|
make BINMAN_DEBUG=1
|
||
|
|
||
|
|
||
|
History / Credits
|
||
|
-----------------
|
||
|
|
||
|
Binman takes a lot of inspiration from a Chrome OS tool called
|
||
|
'cros_bundle_firmware', which I wrote some years ago. That tool was based on
|
||
|
a reasonably simple and sound design but has expanded greatly over the
|
||
|
years. In particular its handling of x86 images is convoluted.
|
||
|
|
||
|
Quite a few lessons have been learned which are hopefully applied here.
|
||
|
|
||
|
|
||
|
Design notes
|
||
|
------------
|
||
|
|
||
|
On the face of it, a tool to create firmware images should be fairly simple:
|
||
|
just find all the input binaries and place them at the right place in the
|
||
|
image. The difficulty comes from the wide variety of input types (simple
|
||
|
flat binaries containing code, packaged data with various headers), packing
|
||
|
requirments (alignment, spacing, device boundaries) and other required
|
||
|
features such as hierarchical images.
|
||
|
|
||
|
The design challenge is to make it easy to create simple images, while
|
||
|
allowing the more complex cases to be supported. For example, for most
|
||
|
images we don't much care exactly where each binary ends up, so we should
|
||
|
not have to specify that unnecessarily.
|
||
|
|
||
|
New entry types should aim to provide simple usage where possible. If new
|
||
|
core features are needed, they can be added in the Entry base class.
|
||
|
|
||
|
|
||
|
To do
|
||
|
-----
|
||
|
|
||
|
Some ideas:
|
||
|
- Use of-platdata to make the information available to code that is unable
|
||
|
to use device tree (such as a very small SPL image)
|
||
|
- Allow easy building of images by specifying just the board name
|
||
|
- Produce a full Python binding for libfdt (for upstream). This is nearing
|
||
|
completion but some work remains
|
||
|
- Add an option to decode an image into the constituent binaries
|
||
|
- Support building an image for a board (-b) more completely, with a
|
||
|
configurable build directory
|
||
|
- Consider making binman work with buildman, although if it is used in the
|
||
|
Makefile, this will be automatic
|
||
|
|
||
|
--
|
||
|
Simon Glass <sjg@chromium.org>
|
||
|
7/7/2016
|