aboutsummaryrefslogtreecommitdiff
path: root/tools
diff options
context:
space:
mode:
Diffstat (limited to 'tools')
-rw-r--r--tools/binman/binman.rst78
-rw-r--r--tools/binman/control.py12
-rw-r--r--tools/binman/elf.py46
-rw-r--r--tools/binman/elf_test.py10
-rw-r--r--tools/binman/entries.rst237
-rw-r--r--tools/binman/entry.py80
-rw-r--r--tools/binman/etype/_testing.py3
-rw-r--r--tools/binman/etype/blob.py8
-rw-r--r--tools/binman/etype/fit.py100
-rw-r--r--tools/binman/etype/mkimage.py28
-rw-r--r--tools/binman/etype/null.py25
-rw-r--r--tools/binman/etype/section.py93
-rw-r--r--tools/binman/etype/tee_os.py76
-rw-r--r--tools/binman/etype/u_boot.py6
-rw-r--r--tools/binman/etype/u_boot_spl.py5
-rw-r--r--tools/binman/etype/u_boot_spl_nodtb.py4
-rw-r--r--tools/binman/etype/u_boot_tpl.py4
-rw-r--r--tools/binman/etype/u_boot_tpl_nodtb.py4
-rw-r--r--tools/binman/etype/u_boot_vpl.py4
-rw-r--r--tools/binman/etype/u_boot_vpl_nodtb.py6
-rw-r--r--tools/binman/ftest.py233
-rw-r--r--tools/binman/image.py3
-rw-r--r--tools/binman/test/261_section_fname.dts29
-rw-r--r--tools/binman/test/262_absent.dts20
-rw-r--r--tools/binman/test/263_tee_os_opt.dts22
-rw-r--r--tools/binman/test/264_tee_os_opt_fit.dts33
-rw-r--r--tools/binman/test/265_tee_os_opt_fit_bad.dts40
-rw-r--r--tools/binman/test/266_blob_ext_opt.dts21
-rw-r--r--tools/binman/test/267_section_inner.dts16
-rw-r--r--tools/binman/test/268_null.dts19
-rw-r--r--tools/binman/test/269_overlap.dts21
-rw-r--r--tools/binman/test/270_overlap_null.dts24
-rw-r--r--tools/binman/test/271_overlap_bad.dts21
-rw-r--r--tools/binman/test/272_overlap_no_size.dts19
-rw-r--r--tools/binman/test/273_blob_symbol.dts24
-rw-r--r--tools/binman/test/274_offset_from_elf.dts30
-rw-r--r--tools/binman/test/Makefile9
-rw-r--r--tools/binman/test/blob_syms.c20
-rw-r--r--tools/binman/test/blob_syms.lds30
-rw-r--r--tools/dtoc/fdt_util.py28
-rw-r--r--tools/dtoc/test/dtoc_test_phandle.dts1
-rwxr-xr-xtools/dtoc/test_dtoc.py3
-rwxr-xr-xtools/dtoc/test_fdt.py11
-rw-r--r--tools/fit_image.c4
-rw-r--r--tools/image-host.c6
l---------tools/patman/.checkpatch.conf1
-rw-r--r--tools/patman/checkpatch.py2
-rw-r--r--tools/proftool.c43
48 files changed, 1396 insertions, 166 deletions
diff --git a/tools/binman/binman.rst b/tools/binman/binman.rst
index 69e4b00239..fa8abdcd86 100644
--- a/tools/binman/binman.rst
+++ b/tools/binman/binman.rst
@@ -487,6 +487,14 @@ For x86 devices (with the end-at-4gb property) this base address is not added
since it is assumed that images are XIP and the offsets already include the
address.
+While U-Boot's symbol updating is handled automatically by the u-boot-spl
+entry type (and others), it is possible to use this feature with any blob. To
+do this, add a `write-symbols` (boolean) property to the node, set the ELF
+filename using `elf-filename` and set 'elf-base-sym' to the base symbol for the
+start of the binary image (this defaults to `__image_copy_start` which is what
+U-Boot uses). See `testBlobSymbol()` for an example.
+
+.. _binman_fdt:
Access to binman entry offsets at run time (fdt)
------------------------------------------------
@@ -689,6 +697,15 @@ no-expanded:
`no-expanded` property disables this just for a single entry. Put the
`no-expanded` boolean property in the node to select this behaviour.
+optional:
+ External blobs are normally required to be present for the image to be
+ built (but see `External blobs`_). This properly allows an entry to be
+ optional, so that when it is cannot be found, this problem is ignored and
+ an empty file is used for this blob. This should be used only when the blob
+ is entirely optional and is not needed for correct operation of the image.
+ Note that missing, optional blobs do not produce a non-zero exit code from
+ binman, although it does show a warning about the missing external blob.
+
The attributes supported for images and sections are described below. Several
are similar to those for entries.
@@ -782,6 +799,37 @@ align-default:
symlink:
Adds a symlink to the image with string given in the symlink property.
+overlap:
+ Indicates that this entry overlaps with others in the same section. These
+ entries should appear at the end of the section. Overlapping entries are not
+ packed with other entries, but their contents are written over other entries
+ in the section. Overlapping entries must have an explicit offset and size.
+
+write-symbols:
+ Indicates that the blob should be updated with symbol values calculated by
+ binman. This is automatic for certain entry types, e.g. `u-boot-spl`. See
+ binman_syms_ for more information.
+
+elf-filename:
+ Sets the file name of a blob's associated ELF file. For example, if the
+ blob is `zephyr.bin` then the ELF file may be `zephyr.elf`. This allows
+ binman to locate symbols and understand the structure of the blob. See
+ binman_syms_ for more information.
+
+elf-base-sym:
+ Sets the name of the ELF symbol that points to the start of a blob. For
+ U-Boot this is `__image_copy_start` and that is the default used by binman
+ if this property is missing. For other projects, a difference symbol may be
+ needed. Add this symbol to the properties for the blob so that symbols can
+ be read correctly. See binman_syms_ for more information.
+
+offset-from-elf:
+ Sets the offset of an entry based on a symbol value in an another entry.
+ The format is <&phandle>, "sym_name", <offset> where phandle is the entry
+ containing the blob (with associated ELF file providing symbols), <sym_name>
+ is the symbol to lookup (relative to elf-base-sym) and <offset> is an offset
+ to add to that value.
+
Examples of the above options can be found in the tests. See the
tools/binman/test directory.
@@ -836,6 +884,11 @@ name-prefix:
renamed to 'ro-u-boot' and 'rw-u-boot'. This can be useful to
distinguish binaries with otherwise identical names.
+filename:
+ This allows the contents of the section to be written to a file in the
+ output directory. This can sometimes be useful to use the data in one
+ section in different image, since there is currently no way to share data
+ beteen images other than through files.
Image Properties
----------------
@@ -1007,6 +1060,28 @@ For the BSS case, a 'spl-bss-pad' entry arg controls whether it is present. All
entry args are provided by the U-Boot Makefile.
+Optional entries
+----------------
+
+Some entries need to exist only if certain conditions are met. For example, an
+entry may want to appear in the image only if a file has a particular format.
+Obviously the entry must exist in the image description for it to be processed
+at all, so a way needs to be found to have the entry remove itself.
+
+To handle this, when entry.ObtainContents() is called, the entry can call
+entry.mark_absent() to mark itself as absent, passing a suitable message as the
+reason.
+
+Any absent entries are dropped immediately after ObtainContents() has been
+called on all entries.
+
+It is not possible for an entry to mark itself absent at any other point in the
+processing. It must happen in the ObtainContents() method.
+
+The effect is as if the entry had never been present at all, since the image
+is packed without it and it disappears from the list of entries.
+
+
Compression
-----------
@@ -1683,7 +1758,8 @@ implementation of Pack() is usually sufficient.
Note: for sections, this also checks that the entries do not overlap, nor extend
outside the section. If the section does not have a defined size, the size is
-set large enough to hold all the entries.
+set large enough to hold all the entries. For entries that are explicitly marked
+as overlapping, this check is skipped.
6. SetImagePos() - sets the image position of every entry. This is the absolute
position 'image-pos', as opposed to 'offset' which is relative to the containing
diff --git a/tools/binman/control.py b/tools/binman/control.py
index 964c6984f9..e64740094f 100644
--- a/tools/binman/control.py
+++ b/tools/binman/control.py
@@ -552,6 +552,7 @@ def ProcessImage(image, update_fdt, write_map, get_contents=True,
image.SetAllowMissing(allow_missing)
image.SetAllowFakeBlob(allow_fake_blobs)
image.GetEntryContents()
+ image.drop_absent()
image.GetEntryOffsets()
# We need to pack the entries to figure out where everything
@@ -593,12 +594,14 @@ def ProcessImage(image, update_fdt, write_map, get_contents=True,
image.BuildImage()
if write_map:
image.WriteMap()
+
missing_list = []
image.CheckMissing(missing_list)
if missing_list:
tout.warning("Image '%s' is missing external blobs and is non-functional: %s" %
(image.name, ' '.join([e.name for e in missing_list])))
_ShowHelpForMissingBlobs(missing_list)
+
faked_list = []
image.CheckFakedBlobs(faked_list)
if faked_list:
@@ -606,6 +609,15 @@ def ProcessImage(image, update_fdt, write_map, get_contents=True,
"Image '%s' has faked external blobs and is non-functional: %s" %
(image.name, ' '.join([os.path.basename(e.GetDefaultFilename())
for e in faked_list])))
+
+ optional_list = []
+ image.CheckOptional(optional_list)
+ if optional_list:
+ tout.warning(
+ "Image '%s' is missing external blobs but is still functional: %s" %
+ (image.name, ' '.join([e.name for e in optional_list])))
+ _ShowHelpForMissingBlobs(optional_list)
+
missing_bintool_list = []
image.check_missing_bintools(missing_bintool_list)
if missing_bintool_list:
diff --git a/tools/binman/elf.py b/tools/binman/elf.py
index fe50bf542c..3cc8a38449 100644
--- a/tools/binman/elf.py
+++ b/tools/binman/elf.py
@@ -210,7 +210,31 @@ def GetPackString(sym, msg):
raise ValueError('%s has size %d: only 4 and 8 are supported' %
(msg, sym.size))
-def LookupAndWriteSymbols(elf_fname, entry, section, is_elf=False):
+def GetSymbolOffset(elf_fname, sym_name, base_sym=None):
+ """Read the offset of a symbol compared to base symbol
+
+ This is useful for obtaining the value of a single symbol relative to the
+ base of a binary blob.
+
+ Args:
+ elf_fname: Filename of the ELF file to read
+ sym_name (str): Name of symbol to read
+ base_sym (str): Base symbol to sue to calculate the offset (or None to
+ use '__image_copy_start'
+
+ Returns:
+ int: Offset of the symbol relative to the base symbol
+ """
+ if not base_sym:
+ base_sym = '__image_copy_start'
+ fname = tools.get_input_filename(elf_fname)
+ syms = GetSymbols(fname, [base_sym, sym_name])
+ base = syms[base_sym].address
+ val = syms[sym_name].address
+ return val - base
+
+def LookupAndWriteSymbols(elf_fname, entry, section, is_elf=False,
+ base_sym=None):
"""Replace all symbols in an entry with their correct values
The entry contents is updated so that values for referenced symbols will be
@@ -223,7 +247,10 @@ def LookupAndWriteSymbols(elf_fname, entry, section, is_elf=False):
entry
entry: Entry to process
section: Section which can be used to lookup symbol values
+ base_sym: Base symbol marking the start of the image
"""
+ if not base_sym:
+ base_sym = '__image_copy_start'
fname = tools.get_input_filename(elf_fname)
syms = GetSymbols(fname, ['image', 'binman'])
if is_elf:
@@ -243,7 +270,7 @@ def LookupAndWriteSymbols(elf_fname, entry, section, is_elf=False):
if not syms:
tout.debug('LookupAndWriteSymbols: no syms')
return
- base = syms.get('__image_copy_start')
+ base = syms.get(base_sym)
if not base and not is_elf:
tout.debug('LookupAndWriteSymbols: no base')
return
@@ -518,3 +545,18 @@ def read_loadable_segments(data):
rend = start + segment['p_filesz']
segments.append((i, segment['p_paddr'], data[start:rend]))
return segments, entry
+
+def is_valid(data):
+ """Check if some binary data is a valid ELF file
+
+ Args:
+ data (bytes): Bytes to check
+
+ Returns:
+ bool: True if a valid Elf file, False if not
+ """
+ try:
+ DecodeElf(data, 0)
+ return True
+ except ELFError:
+ return False
diff --git a/tools/binman/elf_test.py b/tools/binman/elf_test.py
index 75b867c2be..082a3e1d28 100644
--- a/tools/binman/elf_test.py
+++ b/tools/binman/elf_test.py
@@ -348,6 +348,16 @@ class TestElf(unittest.TestCase):
finally:
elf.ELF_TOOLS = old_val
+ def test_is_valid(self):
+ """Test is_valid()"""
+ self.assertEqual(False, elf.is_valid(b''))
+ self.assertEqual(False, elf.is_valid(b'1234'))
+
+ fname = self.ElfTestFile('elf_sections')
+ data = tools.read_file(fname)
+ self.assertEqual(True, elf.is_valid(data))
+ self.assertEqual(False, elf.is_valid(data[4:]))
+
if __name__ == '__main__':
unittest.main()
diff --git a/tools/binman/entries.rst b/tools/binman/entries.rst
index 3dc32db8a5..2b32c131ed 100644
--- a/tools/binman/entries.rst
+++ b/tools/binman/entries.rst
@@ -216,9 +216,9 @@ This is a blob containing a device tree. The contents of the blob are
obtained from the list of available device-tree files, managed by the
'state' module.
-Additional Properties / Entry arguments:
- - prepend: Header type to use:
- length: 32-bit length header
+Additional attributes:
+ prepend: Header used (e.g. 'length')
+
.. _etype_blob_ext:
@@ -1178,11 +1178,13 @@ Properties / Entry arguments:
- multiple-data-files: boolean to tell binman to pass all files as
datafiles to mkimage instead of creating a temporary file the result
of datafiles concatenation
+ - filename: filename of output binary generated by mkimage
The data passed to mkimage via the -d flag is collected from subnodes of the
mkimage node, e.g.::
mkimage {
+ filename = "imximage.bin";
args = "-n test -T imximage";
u-boot-spl {
@@ -1190,13 +1192,14 @@ mkimage node, e.g.::
};
This calls mkimage to create an imximage with `u-boot-spl.bin` as the data
-file, which mkimage being called like this::
+file, with mkimage being called like this::
mkimage -d <data_file> -n test -T imximage <output_file>
The output from mkimage then becomes part of the image produced by
-binman. If you need to put mulitple things in the data file, you can use
-a section, or just multiple subnodes like this::
+binman but also is written into `imximage.bin` file. If you need to put
+multiple things in the data file, you can use a section, or just multiple
+subnodes like this::
mkimage {
args = "-n test -T imximage";
@@ -1208,17 +1211,20 @@ a section, or just multiple subnodes like this::
};
};
+Note that binman places the contents (here SPL and TPL) into a single file
+and passes that to mkimage using the -d option.
+
To pass all datafiles untouched to mkimage::
mkimage {
- args = "-n rk3399 -T rkspi";
- multiple-data-files;
+ args = "-n rk3399 -T rkspi";
+ multiple-data-files;
- u-boot-tpl {
- };
+ u-boot-tpl {
+ };
- u-boot-spl {
- };
+ u-boot-spl {
+ };
};
This calls mkimage to create a Rockchip RK3399-specific first stage
@@ -1242,17 +1248,17 @@ the 'data-to-imagename' property::
mkimage {
args = "-T imximage";
- data-to-imagename';
+ data-to-imagename;
u-boot-spl {
};
};
That will pass the data to mkimage both as the data file (with -d) and as
-the image name (with -n).
+the image name (with -n). In both cases, a filename is passed as the
+argument, with the actual data being in that file.
-
-If need to pass different data in with -n, then use an imagename subnode::
+If need to pass different data in with -n, then use an `imagename` subnode::
mkimage {
args = "-T imximage";
@@ -1271,6 +1277,20 @@ This will pass in u-boot-spl as the input data and the .cfgout file as the
-n data.
+
+.. _etype_null:
+
+Entry: null: An entry which has no contents of its own
+------------------------------------------------------
+
+Note that the size property must be set since otherwise this entry does not
+know how large it should be.
+
+The contents are set by the containing section, e.g. the section's pad
+byte.
+
+
+
.. _etype_opensbi:
Entry: opensbi: RISC-V OpenSBI fw_dynamic blob
@@ -1478,6 +1498,10 @@ skip-at-start
be written at offset 4 in the image file, since the first 16 bytes are
skipped when writing.
+filename
+ filename to write the unpadded section contents to within the output
+ directory (None to skip this).
+
Since a section is also an entry, it inherits all the properies of entries
too.
@@ -1497,12 +1521,47 @@ Entry: tee-os: Entry containing an OP-TEE Trusted OS (TEE) blob
Properties / Entry arguments:
- tee-os-path: Filename of file to read into entry. This is typically
- called tee-pager.bin
+ called tee.bin or tee.elf
This entry holds the run-time firmware, typically started by U-Boot SPL.
See the U-Boot README for your architecture or board for how to use it. See
https://github.com/OP-TEE/optee_os for more information about OP-TEE.
+Note that if the file is in ELF format, it must go in a FIT. In that case,
+this entry will mark itself as absent, providing the data only through the
+read_elf_segments() method.
+
+Marking this entry as absent means that it if is used in the wrong context
+it can be automatically dropped. Thus it is possible to add an OP-TEE entry
+like this::
+
+ binman {
+ tee-os {
+ };
+ };
+
+and pass either an ELF or plain binary in with -a tee-os-path <filename>
+and have binman do the right thing:
+
+ - include the entry if tee.bin is provided and it does NOT have the v1
+ header
+ - drop it otherwise
+
+When used within a FIT, we can do::
+
+ binman {
+ fit {
+ tee-os {
+ };
+ };
+ };
+
+which will split the ELF into separate nodes for each segment, if an ELF
+file is provided (see :ref:`etype_fit`), or produce a single node if the
+OP-TEE binary v1 format is provided (see optee_doc_) .
+
+.. _optee_doc: https://optee.readthedocs.io/en/latest/architecture/core.html#partitioning-of-the-binary
+
.. _etype_text:
@@ -1567,11 +1626,7 @@ This is the U-Boot binary, containing relocation information to allow it
to relocate itself at runtime. The binary typically includes a device tree
blob at the end of it.
-U-Boot can access binman symbols at runtime. See:
-
- 'Access to binman entry offsets at run time (fdt)'
-
-in the binman README for more information.
+U-Boot can access binman symbols at runtime. See :ref:`binman_fdt`.
Note that this entry is automatically replaced with u-boot-expanded unless
--no-expanded is used or the node has a 'no-expanded' property.
@@ -1701,9 +1756,7 @@ not relocatable so must be loaded to the correct address in SRAM, or written
to run from the correct address if direct flash execution is possible (e.g.
on x86 devices).
-SPL can access binman symbols at runtime. See:
-
- 'Access to binman entry offsets at run time (symbols)'
+SPL can access binman symbols at runtime. See :ref:`binman_fdt`.
in the binman README for more information.
@@ -1806,9 +1859,7 @@ entry after this one, or use a u-boot-spl entry instead' which normally
expands to a section containing u-boot-spl-dtb, u-boot-spl-bss-pad and
u-boot-spl-dtb
-SPL can access binman symbols at runtime. See:
-
- 'Access to binman entry offsets at run time (symbols)'
+SPL can access binman symbols at runtime. See :ref:`binman_fdt`.
in the binman README for more information.
@@ -1844,9 +1895,7 @@ loader. Note that SPL is not relocatable so must be loaded to the correct
address in SRAM, or written to run from the correct address if direct
flash execution is possible (e.g. on x86 devices).
-SPL can access binman symbols at runtime. See:
-
- 'Access to binman entry offsets at run time (symbols)'
+SPL can access binman symbols at runtime. See :ref:`binman_fdt`.
in the binman README for more information.
@@ -1961,9 +2010,7 @@ entry after this one, or use a u-boot-tpl entry instead, which normally
expands to a section containing u-boot-tpl-dtb, u-boot-tpl-bss-pad and
u-boot-tpl-dtb
-TPL can access binman symbols at runtime. See:
-
- 'Access to binman entry offsets at run time (symbols)'
+TPL can access binman symbols at runtime. See :ref:`binman_fdt`.
in the binman README for more information.
@@ -2034,6 +2081,128 @@ Entry types that have a part to play in handling microcode:
+.. _etype_u_boot_vpl:
+
+Entry: u-boot-vpl: U-Boot VPL binary
+------------------------------------
+
+Properties / Entry arguments:
+ - filename: Filename of u-boot-vpl.bin (default 'vpl/u-boot-vpl.bin')
+
+This is the U-Boot VPL (Verifying Program Loader) binary. This is a small
+binary which loads before SPL, typically into on-chip SRAM. It is
+responsible for locating, loading and jumping to SPL, the next-stage
+loader. Note that VPL is not relocatable so must be loaded to the correct
+address in SRAM, or written to run from the correct address if direct
+flash execution is possible (e.g. on x86 devices).
+
+SPL can access binman symbols at runtime. See :ref:`binman_fdt`.
+
+in the binman README for more information.
+
+The ELF file 'vpl/u-boot-vpl' must also be available for this to work, since
+binman uses that to look up symbols to write into the VPL binary.
+
+
+
+.. _etype_u_boot_vpl_bss_pad:
+
+Entry: u-boot-vpl-bss-pad: U-Boot VPL binary padded with a BSS region
+---------------------------------------------------------------------
+
+Properties / Entry arguments:
+ None
+
+This holds the padding added after the VPL binary to cover the BSS (Block
+Started by Symbol) region. This region holds the various variables used by
+VPL. It is set to 0 by VPL when it starts up. If you want to append data to
+the VPL image (such as a device tree file), you must pad out the BSS region
+to avoid the data overlapping with U-Boot variables. This entry is useful in
+that case. It automatically pads out the entry size to cover both the code,
+data and BSS.
+
+The contents of this entry will a certain number of zero bytes, determined
+by __bss_size
+
+The ELF file 'vpl/u-boot-vpl' must also be available for this to work, since
+binman uses that to look up the BSS address.
+
+
+
+.. _etype_u_boot_vpl_dtb:
+
+Entry: u-boot-vpl-dtb: U-Boot VPL device tree
+---------------------------------------------
+
+Properties / Entry arguments:
+ - filename: Filename of u-boot.dtb (default 'vpl/u-boot-vpl.dtb')
+
+This is the VPL device tree, containing configuration information for
+VPL. VPL needs this to know what devices are present and which drivers
+to activate.
+
+
+
+.. _etype_u_boot_vpl_elf:
+
+Entry: u-boot-vpl-elf: U-Boot VPL ELF image
+-------------------------------------------
+
+Properties / Entry arguments:
+ - filename: Filename of VPL u-boot (default 'vpl/u-boot-vpl')
+
+This is the U-Boot VPL ELF image. It does not include a device tree but can
+be relocated to any address for execution.
+
+
+
+.. _etype_u_boot_vpl_expanded:
+
+Entry: u-boot-vpl-expanded: U-Boot VPL flat binary broken out into its component parts
+--------------------------------------------------------------------------------------
+
+Properties / Entry arguments:
+ - vpl-dtb: Controls whether this entry is selected (set to 'y' or '1' to
+ select)
+
+This is a section containing the U-Boot binary, BSS padding if needed and a
+devicetree. Using this entry type automatically creates this section, with
+the following entries in it:
+
+ u-boot-vpl-nodtb
+ u-boot-vpl-bss-pad
+ u-boot-dtb
+
+Having the devicetree separate allows binman to update it in the final
+image, so that the entries positions are provided to the running U-Boot.
+
+This entry is selected based on the value of the 'vpl-dtb' entryarg. If
+this is non-empty (and not 'n' or '0') then this expanded entry is selected.
+
+
+
+.. _etype_u_boot_vpl_nodtb:
+
+Entry: u-boot-vpl-nodtb: VPL binary without device tree appended
+----------------------------------------------------------------
+
+Properties / Entry arguments:
+ - filename: Filename to include (default 'vpl/u-boot-vpl-nodtb.bin')
+
+This is the U-Boot VPL binary, It does not include a device tree blob at
+the end of it so may not be able to work without it, assuming VPL needs
+a device tree to operate on your platform. You can add a u_boot_vpl_dtb
+entry after this one, or use a u_boot_vpl entry instead, which normally
+expands to a section containing u-boot-vpl-dtb, u-boot-vpl-bss-pad and
+u-boot-vpl-dtb
+
+VPL can access binman symbols at runtime. See :ref:`binman_fdt`.
+
+The ELF file 'vpl/u-boot-vpl' must also be available for this to work, since
+binman uses that to look up symbols to write into the VPL binary.
+
+
+
.. _etype_u_boot_with_ucode_ptr:
Entry: u-boot-with-ucode-ptr: U-Boot with embedded microcode pointer
diff --git a/tools/binman/entry.py b/tools/binman/entry.py
index 1be31a05e0..5d8696e32a 100644
--- a/tools/binman/entry.py
+++ b/tools/binman/entry.py
@@ -73,7 +73,9 @@ class Entry(object):
compress: Compression algoithm used (e.g. 'lz4'), 'none' if none
orig_offset: Original offset value read from node
orig_size: Original size value read from node
- missing: True if this entry is missing its contents
+ missing: True if this entry is missing its contents. Note that if it is
+ optional, this entry will not appear in the list generated by
+ entry.CheckMissing() since it is considered OK for it to be missing.
allow_missing: Allow children of this entry to be missing (used by
subclasses such as Entry_section)
allow_fake: Allow creating a dummy fake file if the blob file is not
@@ -91,6 +93,12 @@ class Entry(object):
file, or is a binary file produced from an ELF file
auto_write_symbols (bool): True to write ELF symbols into this entry's
contents
+ absent (bool): True if this entry is absent. This can be controlled by
+ the entry itself, allowing it to vanish in certain circumstances.
+ An absent entry is removed during processing so that it does not
+ appear in the map
+ optional (bool): True if this entry contains an optional external blob
+ overlap (bool): True if this entry overlaps with others
"""
fake_dir = None
@@ -133,6 +141,11 @@ class Entry(object):
self.comp_bintool = None
self.elf_fname = None
self.auto_write_symbols = auto_write_symbols
+ self.absent = False
+ self.optional = False
+ self.overlap = False
+ self.elf_base_sym = None
+ self.offset_from_elf = None
@staticmethod
def FindEntryClass(etype, expanded):
@@ -284,9 +297,15 @@ class Entry(object):
self.offset_unset = fdt_util.GetBool(self._node, 'offset-unset')
self.extend_size = fdt_util.GetBool(self._node, 'extend-size')
self.missing_msg = fdt_util.GetString(self._node, 'missing-msg')
+ self.optional = fdt_util.GetBool(self._node, 'optional')
+ self.overlap = fdt_util.GetBool(self._node, 'overlap')
+ if self.overlap:
+ self.required_props += ['offset', 'size']
# This is only supported by blobs and sections at present
self.compress = fdt_util.GetString(self._node, 'compress', 'none')
+ self.offset_from_elf = fdt_util.GetPhandleNameOffset(self._node,
+ 'offset-from-elf')
def GetDefaultFilename(self):
return None
@@ -444,7 +463,7 @@ class Entry(object):
Returns:
True if the contents were found, False if another call is needed
- after the other entries are processed.
+ after the other entries are processed, None if there is no contents
"""
# No contents by default: subclasses can implement this
return True
@@ -483,7 +502,10 @@ class Entry(object):
if self.offset_unset:
self.Raise('No offset set with offset-unset: should another '
'entry provide this correct offset?')
- self.offset = tools.align(offset, self.align)
+ elif self.offset_from_elf:
+ self.offset = self.lookup_offset()
+ else:
+ self.offset = tools.align(offset, self.align)
needed = self.pad_before + self.contents_size + self.pad_after
needed = tools.align(needed, self.align_size)
size = self.size
@@ -572,7 +594,9 @@ class Entry(object):
Returns:
bytes content of the entry, excluding any padding. If the entry is
- compressed, the compressed data is returned
+ compressed, the compressed data is returned. If the entry data
+ is not yet available, False can be returned. If the entry data
+ is null, then None is returned.
"""
self.Detail('GetData: size %s' % to_hex_size(self.data))
return self.data
@@ -659,7 +683,7 @@ class Entry(object):
# Check if we are writing symbols into an ELF file
is_elf = self.GetDefaultFilename() == self.elf_fname
elf.LookupAndWriteSymbols(self.elf_fname, self, section.GetImage(),
- is_elf)
+ is_elf, self.elf_base_sym)
def CheckEntries(self):
"""Check that the entry offsets are correct
@@ -1034,14 +1058,15 @@ features to produce new behaviours.
self.allow_fake = allow_fake
def CheckMissing(self, missing_list):
- """Check if any entries in this section have missing external blobs
+ """Check if the entry has missing external blobs
- If there are missing blobs, the entries are added to the list
+ If there are missing (non-optional) blobs, the entries are added to the
+ list
Args:
missing_list: List of Entry objects to be added to
"""
- if self.missing:
+ if self.missing and not self.optional:
missing_list.append(self)
def check_fake_fname(self, fname, size=0):
@@ -1080,6 +1105,17 @@ features to produce new behaviours.
# This is meaningless for anything other than blobs
pass
+ def CheckOptional(self, optional_list):
+ """Check if the entry has missing but optional external blobs
+
+ If there are missing (optional) blobs, the entries are added to the list
+
+ Args:
+ optional_list (list): List of Entry objects to be added to
+ """
+ if self.missing and self.optional:
+ optional_list.append(self)
+
def GetAllowMissing(self):
"""Get whether a section allows missing external blobs
@@ -1281,3 +1317,31 @@ features to produce new behaviours.
not_present.append(prop)
if not_present:
self.Raise(f"'{self.etype}' entry is missing properties: {' '.join(not_present)}")
+
+ def mark_absent(self, msg):
+ tout.info("Entry '%s' marked absent: %s" % (self._node.path, msg))
+ self.absent = True
+
+ def read_elf_segments(self):
+ """Read segments from an entry that can generate an ELF file
+
+ Returns:
+ tuple:
+ list of segments, each:
+ int: Segment number (0 = first)
+ int: Start address of segment in memory
+ bytes: Contents of segment
+ int: entry address of ELF file
+ """
+ return None
+
+ def lookup_offset(self):
+ node, sym_name, offset = self.offset_from_elf
+ entry = self.section.FindEntryByNode(node)
+ if not entry:
+ self.Raise("Cannot find entry for node '%s'" % node.name)
+ if not entry.elf_fname:
+ entry.Raise("Need elf-fname property '%s'" % node.name)
+ val = elf.GetSymbolOffset(entry.elf_fname, sym_name,
+ entry.elf_base_sym)
+ return val + offset
diff --git a/tools/binman/etype/_testing.py b/tools/binman/etype/_testing.py
index 6960048781..1c1efb21a4 100644
--- a/tools/binman/etype/_testing.py
+++ b/tools/binman/etype/_testing.py
@@ -63,6 +63,7 @@ class Entry__testing(Entry):
'bad-update-contents-twice')
self.return_contents_later = fdt_util.GetBool(self._node,
'return-contents-later')
+ self.set_to_absent = fdt_util.GetBool(self._node, 'set-to-absent')
# Set to True when the entry is ready to process the FDT.
self.process_fdt_ready = False
@@ -119,6 +120,8 @@ class Entry__testing(Entry):
if self.require_bintool_for_contents:
if self.bintool_for_contents is None:
self.Raise("Required bintool unusable in ObtainContents()")
+ if self.set_to_absent:
+ self.mark_absent('for testing purposes')
return True
def GetOffsets(self):
diff --git a/tools/binman/etype/blob.py b/tools/binman/etype/blob.py
index a50a806890..c7ddcedffb 100644
--- a/tools/binman/etype/blob.py
+++ b/tools/binman/etype/blob.py
@@ -35,11 +35,17 @@ class Entry_blob(Entry):
super().__init__(section, etype, node,
auto_write_symbols=auto_write_symbols)
self._filename = fdt_util.GetString(self._node, 'filename', self.etype)
+ self.elf_fname = fdt_util.GetString(self._node, 'elf-filename',
+ self.elf_fname)
+ self.elf_base_sym = fdt_util.GetString(self._node, 'elf-base-sym')
+ if not self.auto_write_symbols:
+ if fdt_util.GetBool(self._node, 'write-symbols'):
+ self.auto_write_symbols = True
def ObtainContents(self, fake_size=0):
self._filename = self.GetDefaultFilename()
self._pathname = tools.get_input_filename(self._filename,
- self.external and self.section.GetAllowMissing())
+ self.external and (self.optional or self.section.GetAllowMissing()))
# Allow the file to be missing
if not self._pathname:
self._pathname, faked = self.check_fake_fname(self._filename,
diff --git a/tools/binman/etype/fit.py b/tools/binman/etype/fit.py
index 7860e2aeea..0e9d81b9e8 100644
--- a/tools/binman/etype/fit.py
+++ b/tools/binman/etype/fit.py
@@ -392,8 +392,8 @@ class Entry_fit(Entry_section):
_add_entries(self._node, 0, self._node)
- # Keep a copy of all entries, including generator entries, since these
- # removed from self._entries later.
+ # Keep a copy of all entries, including generator entries, since those
+ # are removed from self._entries later.
self._priv_entries = dict(self._entries)
def BuildSectionData(self, required):
@@ -540,50 +540,50 @@ class Entry_fit(Entry_section):
else:
self.Raise("Generator node requires 'fit,fdt-list' property")
- def _gen_split_elf(base_node, node, elf_data, missing):
+ def _gen_split_elf(base_node, node, segments, entry_addr):
"""Add nodes for the ELF file, one per group of contiguous segments
Args:
base_node (Node): Template node from the binman definition
node (Node): Node to replace (in the FIT being built)
- data (bytes): ELF-format data to process (may be empty)
- missing (bool): True if any of the data is missing
-
+ segments (list): list of segments, each:
+ int: Segment number (0 = first)
+ int: Start address of segment in memory
+ bytes: Contents of segment
+ entry_addr (int): entry address of ELF file
"""
- # If any pieces are missing, skip this. The missing entries will
- # show an error
- if not missing:
- try:
- segments, entry = elf.read_loadable_segments(elf_data)
- except ValueError as exc:
- self._raise_subnode(node,
- f'Failed to read ELF file: {str(exc)}')
- for (seq, start, data) in segments:
- node_name = node.name[1:].replace('SEQ', str(seq + 1))
- with fsw.add_node(node_name):
- loadables.append(node_name)
- for pname, prop in node.props.items():
- if not pname.startswith('fit,'):
- fsw.property(pname, prop.bytes)
- elif pname == 'fit,load':
- fsw.property_u32('load', start)
- elif pname == 'fit,entry':
- if seq == 0:
- fsw.property_u32('entry', entry)
- elif pname == 'fit,data':
- fsw.property('data', bytes(data))
- elif pname != 'fit,operation':
- self._raise_subnode(
- node, f"Unknown directive '{pname}'")
+ for (seq, start, data) in segments:
+ node_name = node.name[1:].replace('SEQ', str(seq + 1))
+ with fsw.add_node(node_name):
+ loadables.append(node_name)
+ for pname, prop in node.props.items():
+ if not pname.startswith('fit,'):
+ fsw.property(pname, prop.bytes)
+ elif pname == 'fit,load':
+ fsw.property_u32('load', start)
+ elif pname == 'fit,entry':
+ if seq == 0:
+ fsw.property_u32('entry', entry_addr)
+ elif pname == 'fit,data':
+ fsw.property('data', bytes(data))
+ elif pname != 'fit,operation':
+ self._raise_subnode(
+ node, f"Unknown directive '{pname}'")
def _gen_node(base_node, node, depth, in_images, entry):
"""Generate nodes from a template
- This creates one node for each member of self._fdts using the
- provided template. If a property value contains 'NAME' it is
- replaced with the filename of the FDT. If a property value contains
- SEQ it is replaced with the node sequence number, where 1 is the
- first.
+ This creates one or more nodes depending on the fit,operation being
+ used.
+
+ For OP_GEN_FDT_NODES it creates one node for each member of
+ self._fdts using the provided template. If a property value contains
+ 'NAME' it is replaced with the filename of the FDT. If a property
+ value contains SEQ it is replaced with the node sequence number,
+ where 1 is the first.
+
+ For OP_SPLIT_ELF it emits one node for each section in the ELF file.
+ If the file is missing, nothing is generated.
Args:
base_node (Node): Base Node of the FIT (with 'description'
@@ -592,6 +592,8 @@ class Entry_fit(Entry_section):
depth (int): Current node depth (0 is the base 'fit' node)
in_images (bool): True if this is inside the 'images' node, so
that 'data' properties should be generated
+ entry (entry_Section): Entry for the section containing the
+ contents of this node
"""
oper = self._get_operation(base_node, node)
if oper == OP_GEN_FDT_NODES:
@@ -600,13 +602,28 @@ class Entry_fit(Entry_section):
# Entry_section.ObtainContents() either returns True or
# raises an exception.
data = None
- missing_list = []
+ missing_opt_list = []
entry.ObtainContents()
entry.Pack(0)
- data = entry.GetData()
- entry.CheckMissing(missing_list)
+ entry.CheckMissing(missing_opt_list)
+ entry.CheckOptional(missing_opt_list)
+
+ # If any pieces are missing, skip this. The missing entries will
+ # show an error
+ if not missing_opt_list:
+ segs = entry.read_elf_segments()
+ if segs:
+ segments, entry_addr = segs
+ else:
+ elf_data = entry.GetData()
+ try:
+ segments, entry_addr = (
+ elf.read_loadable_segments(elf_data))
+ except ValueError as exc:
+ self._raise_subnode(
+ node, f'Failed to read ELF file: {str(exc)}')
- _gen_split_elf(base_node, node, data, bool(missing_list))
+ _gen_split_elf(base_node, node, segments, entry_addr)
def _add_node(base_node, depth, node):
"""Add nodes to the output FIT
@@ -638,8 +655,7 @@ class Entry_fit(Entry_section):
for subnode in node.subnodes:
subnode_path = f'{rel_path}/{subnode.name}'
- if has_images and not (subnode.name.startswith('hash') or
- subnode.name.startswith('signature')):
+ if has_images and not self.IsSpecialSubnode(subnode):
# This subnode is a content node not meant to appear in
# the FIT (e.g. "/images/kernel/u-boot"), so don't call
# fsw.add_node() or _add_node() for it.
diff --git a/tools/binman/etype/mkimage.py b/tools/binman/etype/mkimage.py
index c2288c48ee..cb264c3cad 100644
--- a/tools/binman/etype/mkimage.py
+++ b/tools/binman/etype/mkimage.py
@@ -57,24 +57,24 @@ class Entry_mkimage(Entry):
Note that binman places the contents (here SPL and TPL) into a single file
and passes that to mkimage using the -d option.
- To pass all datafiles untouched to mkimage::
+ To pass all datafiles untouched to mkimage::
- mkimage {
- args = "-n rk3399 -T rkspi";
- multiple-data-files;
+ mkimage {
+ args = "-n rk3399 -T rkspi";
+ multiple-data-files;
- u-boot-tpl {
- };
+ u-boot-tpl {
+ };
- u-boot-spl {
- };
- };
+ u-boot-spl {
+ };
+ };
- This calls mkimage to create a Rockchip RK3399-specific first stage
- bootloader, made of TPL+SPL. Since this first stage bootloader requires to
- align the TPL and SPL but also some weird hacks that is handled by mkimage
- directly, binman is told to not perform the concatenation of datafiles prior
- to passing the data to mkimage.
+ This calls mkimage to create a Rockchip RK3399-specific first stage
+ bootloader, made of TPL+SPL. Since this first stage bootloader requires to
+ align the TPL and SPL but also some weird hacks that is handled by mkimage
+ directly, binman is told to not perform the concatenation of datafiles prior
+ to passing the data to mkimage.
To use CONFIG options in the arguments, use a string list instead, as in
this example which also produces four arguments::
diff --git a/tools/binman/etype/null.py b/tools/binman/etype/null.py
new file mode 100644
index 0000000000..c10d482447
--- /dev/null
+++ b/tools/binman/etype/null.py
@@ -0,0 +1,25 @@
+# SPDX-License-Identifier: GPL-2.0+
+# Copyright 2023 Google LLC
+# Written by Simon Glass <sjg@chromium.org>
+#
+
+from binman.entry import Entry
+from dtoc import fdt_util
+from patman import tools
+
+class Entry_null(Entry):
+ """An entry which has no contents of its own
+
+ Note that the size property must be set since otherwise this entry does not
+ know how large it should be.
+
+ The contents are set by the containing section, e.g. the section's pad
+ byte.
+ """
+ def __init__(self, section, etype, node):
+ super().__init__(section, etype, node)
+ self.required_props = ['size']
+
+ def ObtainContents(self):
+ # null contents
+ return None
diff --git a/tools/binman/etype/section.py b/tools/binman/etype/section.py
index da561e2bcc..57b91ff726 100644
--- a/tools/binman/etype/section.py
+++ b/tools/binman/etype/section.py
@@ -144,6 +144,10 @@ class Entry_section(Entry):
be written at offset 4 in the image file, since the first 16 bytes are
skipped when writing.
+ filename
+ filename to write the unpadded section contents to within the output
+ directory (None to skip this).
+
Since a section is also an entry, it inherits all the properies of entries
too.
@@ -163,6 +167,18 @@ class Entry_section(Entry):
self._skip_at_start = None
self._end_4gb = False
self._ignore_missing = False
+ self._filename = None
+
+ def IsSpecialSubnode(self, node):
+ """Check if a node is a special one used by the section itself
+
+ Some notes are used for hashing / signatures and do not add entries to
+ the actual section.
+
+ Returns:
+ bool: True if the node is a special one, else False
+ """
+ return node.name.startswith('hash') or node.name.startswith('signature')
def ReadNode(self):
"""Read properties from the section node"""
@@ -183,12 +199,14 @@ class Entry_section(Entry):
self._skip_at_start = 0
self._name_prefix = fdt_util.GetString(self._node, 'name-prefix')
self.align_default = fdt_util.GetInt(self._node, 'align-default', 0)
+ self._filename = fdt_util.GetString(self._node, 'filename',
+ self._filename)
self.ReadEntries()
def ReadEntries(self):
for node in self._node.subnodes:
- if node.name.startswith('hash') or node.name.startswith('signature'):
+ if self.IsSpecialSubnode(node):
continue
entry = Entry.Create(self, node,
expanded=self.GetImage().use_expanded,
@@ -258,6 +276,7 @@ class Entry_section(Entry):
Args:
entry: Entry to check
+ entry_data: Data for the entry, False if is null
Returns:
Contents of the entry along with any pad bytes before and
@@ -312,14 +331,32 @@ class Entry_section(Entry):
# earlier in the image description. See testCollectionSection().
if not required and entry_data is None:
return None
- data = self.GetPaddedDataForEntry(entry, entry_data)
+
+ entry_data_final = entry_data
+ if entry_data is None:
+ pad_byte = (entry._pad_byte if isinstance(entry, Entry_section)
+ else self._pad_byte)
+ entry_data_final = tools.get_bytes(self._pad_byte, entry.size)
+
+ data = self.GetPaddedDataForEntry(entry, entry_data_final)
# Handle empty space before the entry
pad = (entry.offset or 0) - self._skip_at_start - len(section_data)
if pad > 0:
section_data += tools.get_bytes(self._pad_byte, pad)
# Add in the actual entry data
- section_data += data
+ if entry.overlap:
+ end_offset = entry.offset + entry.size
+ if end_offset > len(section_data):
+ entry.Raise("Offset %#x (%d) ending at %#x (%d) must overlap with existing entries" %
+ (entry.offset, entry.offset, end_offset,
+ end_offset))
+ # Don't write anything for null entries'
+ if entry_data is not None:
+ section_data = (section_data[:entry.offset] + data +
+ section_data[entry.offset + entry.size:])
+ else:
+ section_data += data
self.Detail('GetData: %d entries, total size %#x' %
(len(self._entries), len(section_data)))
@@ -348,7 +385,8 @@ class Entry_section(Entry):
"""Get the contents of an entry
This builds the contents of the section, stores this as the contents of
- the section and returns it
+ the section and returns it. If the section has a filename, the data is
+ written there also.
Args:
required: True if the data must be present, False if it is OK to
@@ -363,6 +401,8 @@ class Entry_section(Entry):
if data is None:
return None
self.SetContents(data)
+ if self._filename:
+ tools.write_file(tools.get_output_filename(self._filename), data)
return data
def GetOffsets(self):
@@ -439,12 +479,13 @@ class Entry_section(Entry):
(entry.offset, entry.offset, entry.size, entry.size,
self._node.path, self._skip_at_start,
self._skip_at_start, max_size, max_size))
- if entry.offset < offset and entry.size:
- entry.Raise("Offset %#x (%d) overlaps with previous entry '%s' "
- "ending at %#x (%d)" %
- (entry.offset, entry.offset, prev_name, offset, offset))
- offset = entry.offset + entry.size
- prev_name = entry.GetPath()
+ if not entry.overlap:
+ if entry.offset < offset and entry.size:
+ entry.Raise("Offset %#x (%d) overlaps with previous entry '%s' ending at %#x (%d)" %
+ (entry.offset, entry.offset, prev_name, offset,
+ offset))
+ offset = entry.offset + entry.size
+ prev_name = entry.GetPath()
def WriteSymbols(self, section):
"""Write symbol values into binary files for access at run time"""
@@ -662,10 +703,13 @@ class Entry_section(Entry):
def GetEntryContents(self, skip_entry=None):
"""Call ObtainContents() for each entry in the section
+
+ Note that this may set entry.absent to True if the entry is not
+ actually needed
"""
def _CheckDone(entry):
if entry != skip_entry:
- if not entry.ObtainContents():
+ if entry.ObtainContents() is False:
next_todo.append(entry)
return entry
@@ -706,6 +750,10 @@ class Entry_section(Entry):
todo)
return True
+ def drop_absent(self):
+ """Drop entries which are absent"""
+ self._entries = {n: e for n, e in self._entries.items() if not e.absent}
+
def _SetEntryOffsetSize(self, name, offset, size):
"""Set the offset and size of an entry
@@ -846,7 +894,8 @@ class Entry_section(Entry):
def CheckMissing(self, missing_list):
"""Check if any entries in this section have missing external blobs
- If there are missing blobs, the entries are added to the list
+ If there are missing (non-optional) blobs, the entries are added to the
+ list
Args:
missing_list: List of Entry objects to be added to
@@ -865,6 +914,17 @@ class Entry_section(Entry):
for entry in self._entries.values():
entry.CheckFakedBlobs(faked_blobs_list)
+ def CheckOptional(self, optional_list):
+ """Check the section for missing but optional external blobs
+
+ If there are missing (optional) blobs, the entries are added to the list
+
+ Args:
+ optional_list (list): List of Entry objects to be added to
+ """
+ for entry in self._entries.values():
+ entry.CheckOptional(optional_list)
+
def check_missing_bintools(self, missing_list):
"""Check if any entries in this section have missing bintools
@@ -931,3 +991,12 @@ class Entry_section(Entry):
super().AddBintools(btools)
for entry in self._entries.values():
entry.AddBintools(btools)
+
+ def read_elf_segments(self):
+ entries = self.GetEntries()
+
+ # If the section only has one entry, see if it can provide ELF segments
+ if len(entries) == 1:
+ for entry in entries.values():
+ return entry.read_elf_segments()
+ return None
diff --git a/tools/binman/etype/tee_os.py b/tools/binman/etype/tee_os.py
index 6ce4b672de..5529727e83 100644
--- a/tools/binman/etype/tee_os.py
+++ b/tools/binman/etype/tee_os.py
@@ -4,19 +4,93 @@
# Entry-type module for OP-TEE Trusted OS firmware blob
#
+import struct
+
from binman.etype.blob_named_by_arg import Entry_blob_named_by_arg
+from binman import elf
class Entry_tee_os(Entry_blob_named_by_arg):
"""Entry containing an OP-TEE Trusted OS (TEE) blob
Properties / Entry arguments:
- tee-os-path: Filename of file to read into entry. This is typically
- called tee-pager.bin
+ called tee.bin or tee.elf
This entry holds the run-time firmware, typically started by U-Boot SPL.
See the U-Boot README for your architecture or board for how to use it. See
https://github.com/OP-TEE/optee_os for more information about OP-TEE.
+
+ Note that if the file is in ELF format, it must go in a FIT. In that case,
+ this entry will mark itself as absent, providing the data only through the
+ read_elf_segments() method.
+
+ Marking this entry as absent means that it if is used in the wrong context
+ it can be automatically dropped. Thus it is possible to add an OP-TEE entry
+ like this::
+
+ binman {
+ tee-os {
+ };
+ };
+
+ and pass either an ELF or plain binary in with -a tee-os-path <filename>
+ and have binman do the right thing:
+
+ - include the entry if tee.bin is provided and it does NOT have the v1
+ header
+ - drop it otherwise
+
+ When used within a FIT, we can do::
+
+ binman {
+ fit {
+ tee-os {
+ };
+ };
+ };
+
+ which will split the ELF into separate nodes for each segment, if an ELF
+ file is provided (see :ref:`etype_fit`), or produce a single node if the
+ OP-TEE binary v1 format is provided (see optee_doc_) .
+
+ .. _optee_doc: https://optee.readthedocs.io/en/latest/architecture/core.html#partitioning-of-the-binary
"""
def __init__(self, section, etype, node):
super().__init__(section, etype, node, 'tee-os')
self.external = True
+
+ @staticmethod
+ def is_optee_bin_v1(data):
+ return len(data) >= 8 and data[0:5] == b'OPTE\x01'
+
+ def ObtainContents(self, fake_size=0):
+ result = super().ObtainContents(fake_size)
+ if not self.missing:
+ # If using the flat binary (without the OP-TEE header), then it is
+ # just included as a blob. But if it is an ELF or usees the v1
+ # binary header, then the FIT implementation will call
+ # read_elf_segments() to get the segment information
+ if elf.is_valid(self.data):
+ self.mark_absent('uses Elf format which must be in a FIT')
+ elif self.is_optee_bin_v1(self.data):
+ # The FIT implementation will call read_elf_segments() to get
+ # the segment information
+ self.mark_absent('uses v1 format which must be in a FIT')
+ return result
+
+ def read_elf_segments(self):
+ data = self.GetData()
+ if self.is_optee_bin_v1(data):
+ # OP-TEE v1 format (tee.bin)
+ init_sz, start_hi, start_lo, _, paged_sz = (
+ struct.unpack_from('<5I', data, 0x8))
+ if paged_sz != 0:
+ self.Raise("OP-TEE paged mode not supported")
+ e_entry = (start_hi << 32) + start_lo
+ p_addr = e_entry
+ p_data = data[0x1c:]
+ if len(p_data) != init_sz:
+ self.Raise("Invalid OP-TEE file: size mismatch (expected %#x, have %#x)" %
+ (init_sz, len(p_data)))
+ return [[0, p_addr, p_data]], e_entry
+ return None
diff --git a/tools/binman/etype/u_boot.py b/tools/binman/etype/u_boot.py
index e8d180a46d..d5639eef2e 100644
--- a/tools/binman/etype/u_boot.py
+++ b/tools/binman/etype/u_boot.py
@@ -18,11 +18,7 @@ class Entry_u_boot(Entry_blob):
to relocate itself at runtime. The binary typically includes a device tree
blob at the end of it.
- U-Boot can access binman symbols at runtime. See:
-
- 'Access to binman entry offsets at run time (fdt)'
-
- in the binman README for more information.
+ U-Boot can access binman symbols at runtime. See :ref:`binman_fdt`.
Note that this entry is automatically replaced with u-boot-expanded unless
--no-expanded is used or the node has a 'no-expanded' property.
diff --git a/tools/binman/etype/u_boot_spl.py b/tools/binman/etype/u_boot_spl.py
index d1aa3b4fda..7f710c857d 100644
--- a/tools/binman/etype/u_boot_spl.py
+++ b/tools/binman/etype/u_boot_spl.py
@@ -21,9 +21,7 @@ class Entry_u_boot_spl(Entry_blob):
to run from the correct address if direct flash execution is possible (e.g.
on x86 devices).
- SPL can access binman symbols at runtime. See:
-
- 'Access to binman entry offsets at run time (symbols)'
+ SPL can access binman symbols at runtime. See :ref:`binman_fdt`.
in the binman README for more information.
@@ -36,7 +34,6 @@ class Entry_u_boot_spl(Entry_blob):
def __init__(self, section, etype, node):
super().__init__(section, etype, node, auto_write_symbols=True)
self.elf_fname = 'spl/u-boot-spl'
- self.auto_write_symbols = True
def GetDefaultFilename(self):
return 'spl/u-boot-spl.bin'
diff --git a/tools/binman/etype/u_boot_spl_nodtb.py b/tools/binman/etype/u_boot_spl_nodtb.py
index 50a126dc7e..e7ec329c90 100644
--- a/tools/binman/etype/u_boot_spl_nodtb.py
+++ b/tools/binman/etype/u_boot_spl_nodtb.py
@@ -21,9 +21,7 @@ class Entry_u_boot_spl_nodtb(Entry_blob):
expands to a section containing u-boot-spl-dtb, u-boot-spl-bss-pad and
u-boot-spl-dtb
- SPL can access binman symbols at runtime. See:
-
- 'Access to binman entry offsets at run time (symbols)'
+ SPL can access binman symbols at runtime. See :ref:`binman_fdt`.
in the binman README for more information.
diff --git a/tools/binman/etype/u_boot_tpl.py b/tools/binman/etype/u_boot_tpl.py
index 1883a2bd5f..397b9f8953 100644
--- a/tools/binman/etype/u_boot_tpl.py
+++ b/tools/binman/etype/u_boot_tpl.py
@@ -21,9 +21,7 @@ class Entry_u_boot_tpl(Entry_blob):
address in SRAM, or written to run from the correct address if direct
flash execution is possible (e.g. on x86 devices).
- SPL can access binman symbols at runtime. See:
-
- 'Access to binman entry offsets at run time (symbols)'
+ SPL can access binman symbols at runtime. See :ref:`binman_fdt`.
in the binman README for more information.
diff --git a/tools/binman/etype/u_boot_tpl_nodtb.py b/tools/binman/etype/u_boot_tpl_nodtb.py
index 7e08e58f1e..9bb2b5dda3 100644
--- a/tools/binman/etype/u_boot_tpl_nodtb.py
+++ b/tools/binman/etype/u_boot_tpl_nodtb.py
@@ -21,9 +21,7 @@ class Entry_u_boot_tpl_nodtb(Entry_blob):
expands to a section containing u-boot-tpl-dtb, u-boot-tpl-bss-pad and
u-boot-tpl-dtb
- TPL can access binman symbols at runtime. See:
-
- 'Access to binman entry offsets at run time (symbols)'
+ TPL can access binman symbols at runtime. See :ref:`binman_fdt`.
in the binman README for more information.
diff --git a/tools/binman/etype/u_boot_vpl.py b/tools/binman/etype/u_boot_vpl.py
index 62e5969c6e..31d7e8374e 100644
--- a/tools/binman/etype/u_boot_vpl.py
+++ b/tools/binman/etype/u_boot_vpl.py
@@ -21,9 +21,7 @@ class Entry_u_boot_vpl(Entry_blob):
address in SRAM, or written to run from the correct address if direct
flash execution is possible (e.g. on x86 devices).
- SPL can access binman symbols at runtime. See:
-
- 'Access to binman entry offsets at run time (symbols)'
+ SPL can access binman symbols at runtime. See :ref:`binman_fdt`.
in the binman README for more information.
diff --git a/tools/binman/etype/u_boot_vpl_nodtb.py b/tools/binman/etype/u_boot_vpl_nodtb.py
index db3d8a91c9..64c2767488 100644
--- a/tools/binman/etype/u_boot_vpl_nodtb.py
+++ b/tools/binman/etype/u_boot_vpl_nodtb.py
@@ -21,11 +21,7 @@ class Entry_u_boot_vpl_nodtb(Entry_blob):
expands to a section containing u-boot-vpl-dtb, u-boot-vpl-bss-pad and
u-boot-vpl-dtb
- VPL can access binman symbols at runtime. See:
-
- 'Access to binman entry offsets at run time (symbols)'
-
- in the binman README for more information.
+ VPL can access binman symbols at runtime. See :ref:`binman_fdt`.
The ELF file 'vpl/u-boot-vpl' must also be available for this to work, since
binman uses that to look up symbols to write into the VPL binary.
diff --git a/tools/binman/ftest.py b/tools/binman/ftest.py
index 62ee86b9b7..be0aea49ce 100644
--- a/tools/binman/ftest.py
+++ b/tools/binman/ftest.py
@@ -112,6 +112,8 @@ REPACK_DTB_PROPS = ['orig-offset', 'orig-size']
# Supported compression bintools
COMP_BINTOOLS = ['bzip2', 'gzip', 'lz4', 'lzma_alone', 'lzop', 'xz', 'zstd']
+TEE_ADDR = 0x5678
+
class TestFunctional(unittest.TestCase):
"""Functional tests for binman
@@ -219,6 +221,9 @@ class TestFunctional(unittest.TestCase):
TestFunctional._MakeInputFile('tee.elf',
tools.read_file(cls.ElfTestFile('elf_sections')))
+ # Newer OP_TEE file in v1 binary format
+ cls.make_tee_bin('tee.bin')
+
cls.comp_bintools = {}
for name in COMP_BINTOOLS:
cls.comp_bintools[name] = bintool.Bintool.create(name)
@@ -644,6 +649,14 @@ class TestFunctional(unittest.TestCase):
def ElfTestFile(cls, fname):
return os.path.join(cls._elf_testdir, fname)
+ @classmethod
+ def make_tee_bin(cls, fname, paged_sz=0, extra_data=b''):
+ init_sz, start_hi, start_lo, dummy = (len(U_BOOT_DATA), 0, TEE_ADDR, 0)
+ data = b'OPTE\x01xxx' + struct.pack('<5I', init_sz, start_hi, start_lo,
+ dummy, paged_sz) + U_BOOT_DATA
+ data += extra_data
+ TestFunctional._MakeInputFile(fname, data)
+
def AssertInList(self, grep_list, target):
"""Assert that at least one of a list of things is in a target
@@ -6077,5 +6090,225 @@ fdt fdtmap Extract the devicetree blob from the fdtmap
'Cannot write symbols to an ELF file without Python elftools',
str(exc.exception))
+ def testSectionFilename(self):
+ """Check writing of section contents to a file"""
+ data = self._DoReadFile('261_section_fname.dts')
+ expected = (b'&&' + U_BOOT_DATA + b'&&&' +
+ tools.get_bytes(ord('!'), 7) +
+ U_BOOT_DATA + tools.get_bytes(ord('&'), 12))
+ self.assertEqual(expected, data)
+
+ sect_fname = tools.get_output_filename('outfile.bin')
+ self.assertTrue(os.path.exists(sect_fname))
+ sect_data = tools.read_file(sect_fname)
+ self.assertEqual(U_BOOT_DATA, sect_data)
+
+ def testAbsent(self):
+ """Check handling of absent entries"""
+ data = self._DoReadFile('262_absent.dts')
+ self.assertEqual(U_BOOT_DATA + U_BOOT_IMG_DATA, data)
+
+ def testPackTeeOsOptional(self):
+ """Test that an image with an optional TEE binary can be created"""
+ entry_args = {
+ 'tee-os-path': 'tee.elf',
+ }
+ data = self._DoReadFileDtb('263_tee_os_opt.dts',
+ entry_args=entry_args)[0]
+ self.assertEqual(U_BOOT_DATA + U_BOOT_IMG_DATA, data)
+
+ def checkFitTee(self, dts, tee_fname):
+ """Check that a tee-os entry works and returns data
+
+ Args:
+ dts (str): Device tree filename to use
+ tee_fname (str): filename containing tee-os
+
+ Returns:
+ bytes: Image contents
+ """
+ if not elf.ELF_TOOLS:
+ self.skipTest('Python elftools not available')
+ entry_args = {
+ 'of-list': 'test-fdt1 test-fdt2',
+ 'default-dt': 'test-fdt2',
+ 'tee-os-path': tee_fname,
+ }
+ test_subdir = os.path.join(self._indir, TEST_FDT_SUBDIR)
+ data = self._DoReadFileDtb(dts, entry_args=entry_args,
+ extra_indirs=[test_subdir])[0]
+ return data
+
+ def testFitTeeOsOptionalFit(self):
+ """Test an image with a FIT with an optional OP-TEE binary"""
+ data = self.checkFitTee('264_tee_os_opt_fit.dts', 'tee.bin')
+
+ # There should be only one node, holding the data set up in SetUpClass()
+ # for tee.bin
+ dtb = fdt.Fdt.FromData(data)
+ dtb.Scan()
+ node = dtb.GetNode('/images/tee-1')
+ self.assertEqual(TEE_ADDR,
+ fdt_util.fdt32_to_cpu(node.props['load'].value))
+ self.assertEqual(TEE_ADDR,
+ fdt_util.fdt32_to_cpu(node.props['entry'].value))
+ self.assertEqual(U_BOOT_DATA, node.props['data'].bytes)
+
+ def testFitTeeOsOptionalFitBad(self):
+ """Test an image with a FIT with an optional OP-TEE binary"""
+ with self.assertRaises(ValueError) as exc:
+ self.checkFitTee('265_tee_os_opt_fit_bad.dts', 'tee.bin')
+ self.assertIn(
+ "Node '/binman/fit': subnode 'images/@tee-SEQ': Failed to read ELF file: Magic number does not match",
+ str(exc.exception))
+
+ def testFitTeeOsBad(self):
+ """Test an OP-TEE binary with wrong formats"""
+ self.make_tee_bin('tee.bad1', 123)
+ with self.assertRaises(ValueError) as exc:
+ self.checkFitTee('264_tee_os_opt_fit.dts', 'tee.bad1')
+ self.assertIn(
+ "Node '/binman/fit/images/@tee-SEQ/tee-os': OP-TEE paged mode not supported",
+ str(exc.exception))
+
+ self.make_tee_bin('tee.bad2', 0, b'extra data')
+ with self.assertRaises(ValueError) as exc:
+ self.checkFitTee('264_tee_os_opt_fit.dts', 'tee.bad2')
+ self.assertIn(
+ "Node '/binman/fit/images/@tee-SEQ/tee-os': Invalid OP-TEE file: size mismatch (expected 0x4, have 0xe)",
+ str(exc.exception))
+
+ def testExtblobOptional(self):
+ """Test an image with an external blob that is optional"""
+ with test_util.capture_sys_output() as (stdout, stderr):
+ data = self._DoReadFile('266_blob_ext_opt.dts')
+ self.assertEqual(REFCODE_DATA, data)
+ err = stderr.getvalue()
+ self.assertRegex(
+ err,
+ "Image '.*' is missing external blobs but is still functional: missing")
+
+ def testSectionInner(self):
+ """Test an inner section with a size"""
+ data = self._DoReadFile('267_section_inner.dts')
+ expected = U_BOOT_DATA + tools.get_bytes(0, 12)
+ self.assertEqual(expected, data)
+
+ def testNull(self):
+ """Test an image with a null entry"""
+ data = self._DoReadFile('268_null.dts')
+ self.assertEqual(U_BOOT_DATA + b'\xff\xff\xff\xff' + U_BOOT_IMG_DATA, data)
+
+ def testOverlap(self):
+ """Test an image with a overlapping entry"""
+ data = self._DoReadFile('269_overlap.dts')
+ self.assertEqual(U_BOOT_DATA[:1] + b'aa' + U_BOOT_DATA[3:], data)
+
+ image = control.images['image']
+ entries = image.GetEntries()
+
+ self.assertIn('inset', entries)
+ inset = entries['inset']
+ self.assertEqual(1, inset.offset);
+ self.assertEqual(1, inset.image_pos);
+ self.assertEqual(2, inset.size);
+
+ def testOverlapNull(self):
+ """Test an image with a null overlap"""
+ data = self._DoReadFile('270_overlap_null.dts')
+ self.assertEqual(U_BOOT_DATA, data[:len(U_BOOT_DATA)])
+
+ # Check the FMAP
+ fhdr, fentries = fmap_util.DecodeFmap(data[len(U_BOOT_DATA):])
+ self.assertEqual(4, fhdr.nareas)
+ fiter = iter(fentries)
+
+ fentry = next(fiter)
+ self.assertEqual(b'SECTION', fentry.name)
+ self.assertEqual(0, fentry.offset)
+ self.assertEqual(len(U_BOOT_DATA), fentry.size)
+ self.assertEqual(0, fentry.flags)
+
+ fentry = next(fiter)
+ self.assertEqual(b'U_BOOT', fentry.name)
+ self.assertEqual(0, fentry.offset)
+ self.assertEqual(len(U_BOOT_DATA), fentry.size)
+ self.assertEqual(0, fentry.flags)
+
+ # Make sure that the NULL entry appears in the FMAP
+ fentry = next(fiter)
+ self.assertEqual(b'NULL', fentry.name)
+ self.assertEqual(1, fentry.offset)
+ self.assertEqual(2, fentry.size)
+ self.assertEqual(0, fentry.flags)
+
+ fentry = next(fiter)
+ self.assertEqual(b'FMAP', fentry.name)
+ self.assertEqual(len(U_BOOT_DATA), fentry.offset)
+
+ def testOverlapBad(self):
+ """Test an image with a bad overlapping entry"""
+ with self.assertRaises(ValueError) as exc:
+ self._DoReadFile('271_overlap_bad.dts')
+ self.assertIn(
+ "Node '/binman/inset': Offset 0x10 (16) ending at 0x12 (18) must overlap with existing entries",
+ str(exc.exception))
+
+ def testOverlapNoOffset(self):
+ """Test an image with a bad overlapping entry"""
+ with self.assertRaises(ValueError) as exc:
+ self._DoReadFile('272_overlap_no_size.dts')
+ self.assertIn(
+ "Node '/binman/inset': 'fill' entry is missing properties: size",
+ str(exc.exception))
+
+ def testBlobSymbol(self):
+ """Test a blob with symbols read from an ELF file"""
+ elf_fname = self.ElfTestFile('blob_syms')
+ TestFunctional._MakeInputFile('blob_syms', tools.read_file(elf_fname))
+ TestFunctional._MakeInputFile('blob_syms.bin',
+ tools.read_file(self.ElfTestFile('blob_syms.bin')))
+
+ data = self._DoReadFile('273_blob_symbol.dts')
+
+ syms = elf.GetSymbols(elf_fname, ['binman', 'image'])
+ addr = elf.GetSymbolAddress(elf_fname, '__my_start_sym')
+ self.assertEqual(syms['_binman_sym_magic'].address, addr)
+ self.assertEqual(syms['_binman_inset_prop_offset'].address, addr + 4)
+ self.assertEqual(syms['_binman_inset_prop_size'].address, addr + 8)
+
+ sym_values = struct.pack('<LLL', elf.BINMAN_SYM_MAGIC_VALUE, 4, 8)
+ expected = sym_values
+ self.assertEqual(expected, data[:len(expected)])
+
+ def testOffsetFromElf(self):
+ """Test a blob with symbols read from an ELF file"""
+ elf_fname = self.ElfTestFile('blob_syms')
+ TestFunctional._MakeInputFile('blob_syms', tools.read_file(elf_fname))
+ TestFunctional._MakeInputFile('blob_syms.bin',
+ tools.read_file(self.ElfTestFile('blob_syms.bin')))
+
+ data = self._DoReadFile('274_offset_from_elf.dts')
+
+ syms = elf.GetSymbols(elf_fname, ['binman', 'image'])
+ base = elf.GetSymbolAddress(elf_fname, '__my_start_sym')
+
+ image = control.images['image']
+ entries = image.GetEntries()
+
+ self.assertIn('inset', entries)
+ inset = entries['inset']
+
+ self.assertEqual(base + 4, inset.offset);
+ self.assertEqual(base + 4, inset.image_pos);
+ self.assertEqual(4, inset.size);
+
+ self.assertIn('inset2', entries)
+ inset = entries['inset2']
+ self.assertEqual(base + 8, inset.offset);
+ self.assertEqual(base + 8, inset.image_pos);
+ self.assertEqual(4, inset.size);
+
+
if __name__ == "__main__":
unittest.main()
diff --git a/tools/binman/image.py b/tools/binman/image.py
index 6d4bff5843..b84dd21e22 100644
--- a/tools/binman/image.py
+++ b/tools/binman/image.py
@@ -94,9 +94,6 @@ class Image(section.Entry_section):
def ReadNode(self):
super().ReadNode()
- filename = fdt_util.GetString(self._node, 'filename')
- if filename:
- self._filename = filename
self.allow_repack = fdt_util.GetBool(self._node, 'allow-repack')
self._symlink = fdt_util.GetString(self._node, 'symlink')
diff --git a/tools/binman/test/261_section_fname.dts b/tools/binman/test/261_section_fname.dts
new file mode 100644
index 0000000000..790381e730
--- /dev/null
+++ b/tools/binman/test/261_section_fname.dts
@@ -0,0 +1,29 @@
+// SPDX-License-Identifier: GPL-2.0+
+
+/dts-v1/;
+
+/ {
+ #address-cells = <1>;
+ #size-cells = <1>;
+
+ binman {
+ pad-byte = <0x26>;
+ size = <0x20>;
+ section@0 {
+ size = <0x10>;
+ pad-byte = <0x21>;
+ pad-before = <2>;
+ pad-after = <3>;
+
+ section {
+ filename = "outfile.bin";
+ u-boot {
+ };
+ };
+ };
+ section@1 {
+ u-boot {
+ };
+ };
+ };
+};
diff --git a/tools/binman/test/262_absent.dts b/tools/binman/test/262_absent.dts
new file mode 100644
index 0000000000..2ab8766c87
--- /dev/null
+++ b/tools/binman/test/262_absent.dts
@@ -0,0 +1,20 @@
+// SPDX-License-Identifier: GPL-2.0+
+
+/dts-v1/;
+
+/ {
+ #address-cells = <1>;
+ #size-cells = <1>;
+
+ binman {
+ u-boot {
+ };
+
+ _testing {
+ set-to-absent;
+ };
+
+ u-boot-img {
+ };
+ };
+};
diff --git a/tools/binman/test/263_tee_os_opt.dts b/tools/binman/test/263_tee_os_opt.dts
new file mode 100644
index 0000000000..2e4ec24ac2
--- /dev/null
+++ b/tools/binman/test/263_tee_os_opt.dts
@@ -0,0 +1,22 @@
+// SPDX-License-Identifier: GPL-2.0+
+
+/dts-v1/;
+
+/ {
+ #address-cells = <1>;
+ #size-cells = <1>;
+
+ binman {
+ u-boot {
+ };
+ tee-os {
+ /*
+ * this results in nothing being added since only the
+ * .bin format is supported by this etype, unless it is
+ * part of a FIT
+ */
+ };
+ u-boot-img {
+ };
+ };
+};
diff --git a/tools/binman/test/264_tee_os_opt_fit.dts b/tools/binman/test/264_tee_os_opt_fit.dts
new file mode 100644
index 0000000000..ae44b433ed
--- /dev/null
+++ b/tools/binman/test/264_tee_os_opt_fit.dts
@@ -0,0 +1,33 @@
+// SPDX-License-Identifier: GPL-2.0+
+
+/dts-v1/;
+
+/ {
+ #address-cells = <1>;
+ #size-cells = <1>;
+
+ binman {
+ fit {
+ description = "test-desc";
+ #address-cells = <1>;
+ fit,fdt-list = "of-list";
+
+ images {
+ @tee-SEQ {
+ fit,operation = "split-elf";
+ description = "TEE";
+ type = "tee";
+ arch = "arm64";
+ os = "tee";
+ compression = "none";
+ fit,load;
+ fit,entry;
+ fit,data;
+
+ tee-os {
+ };
+ };
+ };
+ };
+ };
+};
diff --git a/tools/binman/test/265_tee_os_opt_fit_bad.dts b/tools/binman/test/265_tee_os_opt_fit_bad.dts
new file mode 100644
index 0000000000..7fa363cc19
--- /dev/null
+++ b/tools/binman/test/265_tee_os_opt_fit_bad.dts
@@ -0,0 +1,40 @@
+// SPDX-License-Identifier: GPL-2.0+
+
+/dts-v1/;
+
+/ {
+ #address-cells = <1>;
+ #size-cells = <1>;
+
+ binman {
+ fit {
+ description = "test-desc";
+ #address-cells = <1>;
+ fit,fdt-list = "of-list";
+
+ images {
+ @tee-SEQ {
+ fit,operation = "split-elf";
+ description = "TEE";
+ type = "tee";
+ arch = "arm64";
+ os = "tee";
+ compression = "none";
+ fit,load;
+ fit,entry;
+ fit,data;
+
+ tee-os {
+ };
+
+ /*
+ * mess up the ELF data by adding
+ * another bit of data at the end
+ */
+ u-boot {
+ };
+ };
+ };
+ };
+ };
+};
diff --git a/tools/binman/test/266_blob_ext_opt.dts b/tools/binman/test/266_blob_ext_opt.dts
new file mode 100644
index 0000000000..717153152c
--- /dev/null
+++ b/tools/binman/test/266_blob_ext_opt.dts
@@ -0,0 +1,21 @@
+// SPDX-License-Identifier: GPL-2.0+
+
+/dts-v1/;
+
+/ {
+ #address-cells = <1>;
+ #size-cells = <1>;
+
+ binman {
+ ok {
+ type = "blob-ext";
+ filename = "refcode.bin";
+ };
+
+ missing {
+ type = "blob-ext";
+ filename = "missing.bin";
+ optional;
+ };
+ };
+};
diff --git a/tools/binman/test/267_section_inner.dts b/tools/binman/test/267_section_inner.dts
new file mode 100644
index 0000000000..f6faab3d2f
--- /dev/null
+++ b/tools/binman/test/267_section_inner.dts
@@ -0,0 +1,16 @@
+// SPDX-License-Identifier: GPL-2.0+
+
+/dts-v1/;
+
+/ {
+ #address-cells = <1>;
+ #size-cells = <1>;
+
+ binman {
+ section {
+ size = <0x10>;
+ u-boot {
+ };
+ };
+ };
+};
diff --git a/tools/binman/test/268_null.dts b/tools/binman/test/268_null.dts
new file mode 100644
index 0000000000..3824ba8509
--- /dev/null
+++ b/tools/binman/test/268_null.dts
@@ -0,0 +1,19 @@
+// SPDX-License-Identifier: GPL-2.0+
+
+/dts-v1/;
+
+/ {
+ #address-cells = <1>;
+ #size-cells = <1>;
+
+ binman {
+ pad-byte = <0xff>;
+ u-boot {
+ };
+ null {
+ size = <4>;
+ };
+ u-boot-img {
+ };
+ };
+};
diff --git a/tools/binman/test/269_overlap.dts b/tools/binman/test/269_overlap.dts
new file mode 100644
index 0000000000..f949b8b359
--- /dev/null
+++ b/tools/binman/test/269_overlap.dts
@@ -0,0 +1,21 @@
+// SPDX-License-Identifier: GPL-2.0+
+
+/dts-v1/;
+
+/ {
+ #address-cells = <1>;
+ #size-cells = <1>;
+
+ binman {
+ u-boot {
+ };
+
+ inset {
+ type = "fill";
+ fill-byte = [61];
+ offset = <1>;
+ size = <2>;
+ overlap;
+ };
+ };
+};
diff --git a/tools/binman/test/270_overlap_null.dts b/tools/binman/test/270_overlap_null.dts
new file mode 100644
index 0000000000..feed9ec892
--- /dev/null
+++ b/tools/binman/test/270_overlap_null.dts
@@ -0,0 +1,24 @@
+// SPDX-License-Identifier: GPL-2.0+
+
+/dts-v1/;
+
+/ {
+ #address-cells = <1>;
+ #size-cells = <1>;
+
+ binman {
+ section {
+ u-boot {
+ };
+
+ null {
+ offset = <1>;
+ size = <2>;
+ overlap;
+ };
+ };
+
+ fmap {
+ };
+ };
+};
diff --git a/tools/binman/test/271_overlap_bad.dts b/tools/binman/test/271_overlap_bad.dts
new file mode 100644
index 0000000000..f281802114
--- /dev/null
+++ b/tools/binman/test/271_overlap_bad.dts
@@ -0,0 +1,21 @@
+// SPDX-License-Identifier: GPL-2.0+
+
+/dts-v1/;
+
+/ {
+ #address-cells = <1>;
+ #size-cells = <1>;
+
+ binman {
+ u-boot {
+ };
+
+ inset {
+ type = "fill";
+ fill-byte = [61];
+ offset = <0x10>;
+ size = <2>;
+ overlap;
+ };
+ };
+};
diff --git a/tools/binman/test/272_overlap_no_size.dts b/tools/binman/test/272_overlap_no_size.dts
new file mode 100644
index 0000000000..4517536f2e
--- /dev/null
+++ b/tools/binman/test/272_overlap_no_size.dts
@@ -0,0 +1,19 @@
+// SPDX-License-Identifier: GPL-2.0+
+
+/dts-v1/;
+
+/ {
+ #address-cells = <1>;
+ #size-cells = <1>;
+
+ binman {
+ u-boot {
+ };
+
+ inset {
+ type = "fill";
+ fill-byte = [61];
+ overlap;
+ };
+ };
+};
diff --git a/tools/binman/test/273_blob_symbol.dts b/tools/binman/test/273_blob_symbol.dts
new file mode 100644
index 0000000000..87b0aba212
--- /dev/null
+++ b/tools/binman/test/273_blob_symbol.dts
@@ -0,0 +1,24 @@
+// SPDX-License-Identifier: GPL-2.0+
+
+/dts-v1/;
+
+/ {
+ #address-cells = <1>;
+ #size-cells = <1>;
+
+ binman {
+ blob {
+ filename = "blob_syms.bin";
+ write-symbols;
+ elf-filename = "blob_syms";
+ elf-base-sym = "__my_start_sym";
+ };
+
+ inset {
+ type = "null";
+ offset = <4>;
+ size = <8>;
+ overlap;
+ };
+ };
+};
diff --git a/tools/binman/test/274_offset_from_elf.dts b/tools/binman/test/274_offset_from_elf.dts
new file mode 100644
index 0000000000..e3372fc7c3
--- /dev/null
+++ b/tools/binman/test/274_offset_from_elf.dts
@@ -0,0 +1,30 @@
+// SPDX-License-Identifier: GPL-2.0+
+
+/dts-v1/;
+
+/ {
+ #address-cells = <1>;
+ #size-cells = <1>;
+
+ binman {
+ blob: blob {
+ filename = "blob_syms.bin";
+ elf-filename = "blob_syms";
+ elf-base-sym = "__my_start_sym";
+ };
+
+ inset {
+ type = "null";
+ offset-from-elf = <&blob>, "val3", <0>;
+ size = <4>;
+ overlap;
+ };
+
+ inset2 {
+ type = "null";
+ offset-from-elf = <&blob>, "val3", <4>;
+ size = <4>;
+ overlap;
+ };
+ };
+};
diff --git a/tools/binman/test/Makefile b/tools/binman/test/Makefile
index bea8567c9b..cd66a3038b 100644
--- a/tools/binman/test/Makefile
+++ b/tools/binman/test/Makefile
@@ -30,11 +30,12 @@ LDS_BINMAN_BAD := -T $(SRC)u_boot_binman_syms_bad.lds
LDS_BINMAN_X86 := -T $(SRC)u_boot_binman_syms_x86.lds
LDS_BINMAN_EMBED := -T $(SRC)u_boot_binman_embed.lds
LDS_EFL_SECTIONS := -T $(SRC)elf_sections.lds
+LDS_BLOB := -T $(SRC)blob_syms.lds
TARGETS = u_boot_ucode_ptr u_boot_no_ucode_ptr bss_data \
u_boot_binman_syms u_boot_binman_syms.bin u_boot_binman_syms_bad \
u_boot_binman_syms_size u_boot_binman_syms_x86 embed_data \
- u_boot_binman_embed u_boot_binman_embed_sm elf_sections
+ u_boot_binman_embed u_boot_binman_embed_sm elf_sections blob_syms.bin
all: $(TARGETS)
@@ -71,6 +72,12 @@ u_boot_binman_embed: u_boot_binman_embed.c
u_boot_binman_embed_sm: CFLAGS += $(LDS_BINMAN_EMBED)
u_boot_binman_embed_sm: u_boot_binman_embed_sm.c
+blob_syms.bin: blob_syms
+ $(OBJCOPY) -O binary $< -R .note.gnu.build-id $@
+
+blob_syms: CFLAGS += $(LDS_BLOB)
+blob_syms: blob_syms.c
+
elf_sections: CFLAGS += $(LDS_EFL_SECTIONS)
elf_sections: elf_sections.c
diff --git a/tools/binman/test/blob_syms.c b/tools/binman/test/blob_syms.c
new file mode 100644
index 0000000000..d652c79aa9
--- /dev/null
+++ b/tools/binman/test/blob_syms.c
@@ -0,0 +1,20 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright (c) 2017 Google, Inc
+ *
+ * Simple program to create some binman symbols. This is used by binman tests.
+ */
+
+typedef unsigned long ulong;
+
+#include <linux/kconfig.h>
+#include <binman_sym.h>
+
+DECLARE_BINMAN_MAGIC_SYM;
+
+unsigned long val1 = 123;
+unsigned long val2 = 456;
+binman_sym_declare(unsigned long, inset, offset);
+unsigned long val3 = 789;
+unsigned long val4 = 999;
+binman_sym_declare(unsigned long, inset, size);
diff --git a/tools/binman/test/blob_syms.lds b/tools/binman/test/blob_syms.lds
new file mode 100644
index 0000000000..787e38dd85
--- /dev/null
+++ b/tools/binman/test/blob_syms.lds
@@ -0,0 +1,30 @@
+/* SPDX-License-Identifier: GPL-2.0+ */
+/*
+ * Copyright (c) 2016 Google, Inc
+ */
+
+OUTPUT_FORMAT("elf32-i386", "elf32-i386", "elf32-i386")
+OUTPUT_ARCH(i386)
+ENTRY(_start)
+
+SECTIONS
+{
+ . = 0x00000010;
+ _start = .;
+
+ . = ALIGN(4);
+ .text :
+ {
+ __my_start_sym = .;
+ *(.text*)
+ }
+
+ . = ALIGN(4);
+ .binman_sym_table : {
+ __binman_sym_start = .;
+ KEEP(*(SORT(.binman_sym*)));
+ __binman_sym_end = .;
+ }
+ .interp : { *(.interp*) }
+
+}
diff --git a/tools/dtoc/fdt_util.py b/tools/dtoc/fdt_util.py
index d7c38ad1e0..f34316632a 100644
--- a/tools/dtoc/fdt_util.py
+++ b/tools/dtoc/fdt_util.py
@@ -281,6 +281,34 @@ def GetPhandleList(node, propname):
value = [value]
return [fdt32_to_cpu(v) for v in value]
+def GetPhandleNameOffset(node, propname):
+ """Get a <&phandle>, "string", <offset> value from a property
+
+ Args:
+ node: Node object to read from
+ propname: property name to read
+
+ Returns:
+ tuple:
+ Node object
+ str
+ int
+ or None if the property does not exist
+ """
+ prop = node.props.get(propname)
+ if not prop:
+ return None
+ value = prop.bytes
+ phandle = fdt32_to_cpu(value[:4])
+ node = node.GetFdt().LookupPhandle(phandle)
+ name = ''
+ for byte in value[4:]:
+ if not byte:
+ break
+ name += chr(byte)
+ val = fdt32_to_cpu(value[4 + len(name) + 1:])
+ return node, name, val
+
def GetDatatype(node, propname, datatype):
"""Get a value of a given type from a property
diff --git a/tools/dtoc/test/dtoc_test_phandle.dts b/tools/dtoc/test/dtoc_test_phandle.dts
index a71acffc69..d9aa433503 100644
--- a/tools/dtoc/test/dtoc_test_phandle.dts
+++ b/tools/dtoc/test/dtoc_test_phandle.dts
@@ -32,6 +32,7 @@
u-boot,dm-pre-reloc;
compatible = "source";
clocks = <&phandle &phandle_1 11 &phandle_2 12 13 &phandle>;
+ phandle-name-offset = <&phandle_2>, "fred", <123>;
};
phandle-source2 {
diff --git a/tools/dtoc/test_dtoc.py b/tools/dtoc/test_dtoc.py
index 879ca2ab2b..c62fcbac83 100755
--- a/tools/dtoc/test_dtoc.py
+++ b/tools/dtoc/test_dtoc.py
@@ -929,6 +929,7 @@ U_BOOT_DRVINFO(spl_test) = {
self._check_strings(HEADER + '''
struct dtd_source {
\tstruct phandle_2_arg clocks[4];
+\tunsigned char phandle_name_offset[13];
};
struct dtd_target {
\tfdt32_t\t\tintval;
@@ -981,6 +982,8 @@ static struct dtd_source dtv_phandle_source = {
\t\t\t{0, {11}},
\t\t\t{1, {12, 13}},
\t\t\t{4, {}},},
+\t.phandle_name_offset = {0x0, 0x0, 0x0, 0x3, 0x66, 0x72, 0x65, 0x64,
+\t\t0x0, 0x0, 0x0, 0x0, 0x7b},
};
U_BOOT_DRVINFO(phandle_source) = {
\t.name\t\t= "source",
diff --git a/tools/dtoc/test_fdt.py b/tools/dtoc/test_fdt.py
index a3e36ea363..3b8ee00d4e 100755
--- a/tools/dtoc/test_fdt.py
+++ b/tools/dtoc/test_fdt.py
@@ -795,6 +795,17 @@ class TestFdtUtil(unittest.TestCase):
finally:
tools.outdir= old_outdir
+ def test_get_phandle_name_offset(self):
+ val = fdt_util.GetPhandleNameOffset(self.node, 'missing')
+ self.assertIsNone(val)
+
+ dtb = fdt.FdtScan(find_dtb_file('dtoc_test_phandle.dts'))
+ node = dtb.GetNode('/phandle-source')
+ node, name, offset = fdt_util.GetPhandleNameOffset(node,
+ 'phandle-name-offset')
+ self.assertEqual('phandle3-target', node.name)
+ self.assertEqual('fred', name)
+ self.assertEqual(123, offset)
def run_test_coverage(build_dir):
"""Run the tests and check that we get 100% coverage
diff --git a/tools/fit_image.c b/tools/fit_image.c
index 923a9755b7..8a18b1b0ba 100644
--- a/tools/fit_image.c
+++ b/tools/fit_image.c
@@ -36,8 +36,10 @@ static int fit_add_file_data(struct image_tool_params *params, size_t size_inc,
tfd = mmap_fdt(params->cmdname, tmpfile, size_inc, &ptr, &sbuf, true,
false);
- if (tfd < 0)
+ if (tfd < 0) {
+ fprintf(stderr, "Cannot map FDT file '%s'\n", tmpfile);
return -EIO;
+ }
if (params->keydest) {
struct stat dest_sbuf;
diff --git a/tools/image-host.c b/tools/image-host.c
index 4e0512be63..4a24dee815 100644
--- a/tools/image-host.c
+++ b/tools/image-host.c
@@ -1292,8 +1292,12 @@ int fit_add_verification_data(const char *keydir, const char *keyfile,
ret = fit_image_add_verification_data(keydir, keyfile, keydest,
fit, noffset, comment, require_keys, engine_id,
cmdname, algo_name);
- if (ret)
+ if (ret) {
+ printf("Can't add verification data for node '%s' (%s)\n",
+ fdt_get_name(fit, noffset, NULL),
+ fdt_strerror(ret));
return ret;
+ }
}
/* If there are no keys, we can't sign configurations */
diff --git a/tools/patman/.checkpatch.conf b/tools/patman/.checkpatch.conf
new file mode 120000
index 0000000000..c0e2020afe
--- /dev/null
+++ b/tools/patman/.checkpatch.conf
@@ -0,0 +1 @@
+../../.checkpatch.conf \ No newline at end of file
diff --git a/tools/patman/checkpatch.py b/tools/patman/checkpatch.py
index 012c0d895c..d1b902dd96 100644
--- a/tools/patman/checkpatch.py
+++ b/tools/patman/checkpatch.py
@@ -211,7 +211,7 @@ def check_patch(fname, verbose=False, show_types=False, use_tree=False):
stdout: Full output of checkpatch
"""
chk = find_check_patch()
- args = [chk, '--u-boot', '--strict']
+ args = [chk]
if not use_tree:
args.append('--no-tree')
if show_types:
diff --git a/tools/proftool.c b/tools/proftool.c
index ea7d07a277..b66ea55648 100644
--- a/tools/proftool.c
+++ b/tools/proftool.c
@@ -81,14 +81,15 @@ static void outf(int level, const char *fmt, ...)
static void usage(void)
{
fprintf(stderr,
- "Usage: proftool -cds -v3 <cmd> <profdata>\n"
+ "Usage: proftool [-cmtv] <cmd> <profdata>\n"
"\n"
"Commands\n"
" dump-ftrace\t\tDump out textual data in ftrace format\n"
"\n"
"Options:\n"
+ " -c <cfg>\tSpecific config file\n"
" -m <map>\tSpecify Systen.map file\n"
- " -t <trace>\tSpecific trace data file (from U-Boot)\n"
+ " -t <fname>\tSpecify trace data file (from U-Boot 'trace calls')\n"
" -v <0-4>\tSpecify verbosity\n");
exit(EXIT_FAILURE);
}
@@ -162,7 +163,7 @@ static int read_data(FILE *fin, void *buff, int size)
if (!err)
return 1;
if (err != size) {
- error("Cannot read profile file at pos %ld\n", ftell(fin));
+ error("Cannot read profile file at pos %lx\n", ftell(fin));
return -1;
}
return 0;
@@ -495,10 +496,17 @@ static int make_ftrace(void)
int missing_count = 0, skip_count = 0;
int i;
- printf("# tracer: ftrace\n"
- "#\n"
- "# TASK-PID CPU# TIMESTAMP FUNCTION\n"
- "# | | | | |\n");
+ printf("# tracer: function\n"
+ "#\n"
+ "# entries-in-buffer/entries-written: 140080/250280 #P:4\n"
+ "#\n"
+ "# _-----=> irqs-off\n"
+ "# / _----=> need-resched\n"
+ "# | / _---=> hardirq/softirq\n"
+ "# || / _--=> preempt-depth\n"
+ "# ||| / delay\n"
+ "# TASK-PID CPU# |||| TIMESTAMP FUNCTION\n"
+ "# | | | |||| | |\n");
for (i = 0, call = call_list; i < call_count; i++, call++) {
struct func_info *func = find_func_by_offset(call->func);
ulong time = call->flags & FUNCF_TIMESTAMP_MASK;
@@ -520,7 +528,7 @@ static int make_ftrace(void)
continue;
}
- printf("%16s-%-5d [01] %lu.%06lu: ", "uboot", 1,
+ printf("%16s-%-5d [000] .... %lu.%06lu: ", "uboot", 1,
time / 1000000, time % 1000000);
out_func(call->func, 0, " <- ");
@@ -562,23 +570,23 @@ static int prof_tool(int argc, char *const argv[],
int main(int argc, char *argv[])
{
const char *map_fname = "System.map";
- const char *prof_fname = NULL;
- const char *trace_config_fname = NULL;
+ const char *trace_fname = NULL;
+ const char *config_fname = NULL;
int opt;
verbose = 2;
- while ((opt = getopt(argc, argv, "m:p:t:v:")) != -1) {
+ while ((opt = getopt(argc, argv, "c:m:t:v:")) != -1) {
switch (opt) {
- case 'm':
- map_fname = optarg;
+ case 'c':
+ config_fname = optarg;
break;
- case 'p':
- prof_fname = optarg;
+ case 'm':
+ map_fname = optarg;
break;
case 't':
- trace_config_fname = optarg;
+ trace_fname = optarg;
break;
case 'v':
@@ -594,6 +602,5 @@ int main(int argc, char *argv[])
usage();
debug("Debug enabled\n");
- return prof_tool(argc, argv, prof_fname, map_fname,
- trace_config_fname);
+ return prof_tool(argc, argv, trace_fname, map_fname, config_fname);
}