binman: add support for creating dummy files for external blobs

While converting to binman for an imx8mq board, it has been found that
building in the u-boot CI fails. This is because an imx8mq requires an
external binary (signed_hdmi_imx8m.bin). If this file cannot be found
mkimage fails.
To be able to build this board in the u-boot CI a binman option
(--fake-ext-blobs) is introduced that can be switched on via the u-boot
makefile option BINMAN_FAKE_EXT_BLOBS. With that the needed dummy files are
created.

Signed-off-by: Heiko Thiery <heiko.thiery@gmail.com>
Reviewed-by: Simon Glass <sjg@chromium.org>
This commit is contained in:
Heiko Thiery 2022-01-06 11:49:41 +01:00 committed by Tom Rini
parent a14af7216a
commit a89c8f2111
10 changed files with 139 additions and 8 deletions

View File

@ -1315,6 +1315,7 @@ cmd_binman = $(srctree)/tools/binman/binman $(if $(BINMAN_DEBUG),-D) \
-a tpl-bss-pad=$(if $(CONFIG_TPL_SEPARATE_BSS),,1) \
-a spl-dtb=$(CONFIG_SPL_OF_REAL) \
-a tpl-dtb=$(CONFIG_TPL_OF_REAL) \
$(if $(BINMAN_FAKE_EXT_BLOBS),--fake-ext-blobs) \
$(BINMAN_$(@F))
OBJCOPYFLAGS_u-boot.ldr.hex := -I binary -O ihex

View File

@ -52,6 +52,8 @@ controlled by a description in the board device tree.'''
help='Configuration file (.dtb) to use')
build_parser.add_argument('--fake-dtb', action='store_true',
help='Use fake device tree contents (for testing only)')
build_parser.add_argument('--fake-ext-blobs', action='store_true',
help='Create fake ext blobs with dummy content (for testing only)')
build_parser.add_argument('-i', '--image', type=str, action='append',
help='Image filename to build (if not specified, build all)')
build_parser.add_argument('-I', '--indir', action='append',

View File

@ -479,7 +479,8 @@ def PrepareImagesAndDtbs(dtb_fname, select_images, update_fdt, use_expanded):
def ProcessImage(image, update_fdt, write_map, get_contents=True,
allow_resize=True, allow_missing=False):
allow_resize=True, allow_missing=False,
allow_fake_blobs=False):
"""Perform all steps for this image, including checking and # writing it.
This means that errors found with a later image will be reported after
@ -495,12 +496,15 @@ def ProcessImage(image, update_fdt, write_map, get_contents=True,
allow_resize: True to allow entries to change size (this does a re-pack
of the entries), False to raise an exception
allow_missing: Allow blob_ext objects to be missing
allow_fake_blobs: Allow blob_ext objects to be faked with dummy files
Returns:
True if one or more external blobs are missing, False if all are present
True if one or more external blobs are missing or faked,
False if all are present
"""
if get_contents:
image.SetAllowMissing(allow_missing)
image.SetAllowFakeBlob(allow_fake_blobs)
image.GetEntryContents()
image.GetEntryOffsets()
@ -549,7 +553,13 @@ def ProcessImage(image, update_fdt, write_map, get_contents=True,
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)
return bool(missing_list)
faked_list = []
image.CheckFakedBlobs(faked_list)
if faked_list:
tout.Warning("Image '%s:%s' has faked external blobs and is non-functional: %s" %
(image.name, image.image_name,
' '.join([e.GetDefaultFilename() for e in faked_list])))
return bool(missing_list) or bool(faked_list)
def Binman(args):
@ -636,13 +646,15 @@ def Binman(args):
images = PrepareImagesAndDtbs(dtb_fname, args.image,
args.update_fdt, use_expanded)
if args.test_section_timeout:
# Set the first image to timeout, used in testThreadTimeout()
images[list(images.keys())[0]].test_section_timeout = True
missing = False
invalid = False
for image in images.values():
missing |= ProcessImage(image, args.update_fdt, args.map,
allow_missing=args.allow_missing)
invalid |= ProcessImage(image, args.update_fdt, args.map,
allow_missing=args.allow_missing,
allow_fake_blobs=args.fake_ext_blobs)
# Write the updated FDTs to our output files
for dtb_item in state.GetAllFdts():
@ -652,7 +664,7 @@ def Binman(args):
data = state.GetFdtForEtype('u-boot-dtb').GetContents()
elf.UpdateFile(*elf_params, data)
if missing:
if invalid:
tout.Warning("\nSome images are invalid")
# Use this to debug the time take to pack the image

View File

@ -70,6 +70,8 @@ class Entry(object):
missing: True if this entry is missing its contents
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
available. This is mainly used for testing.
external: True if this entry contains an external binary blob
"""
def __init__(self, section, etype, node, name_prefix=''):
@ -98,8 +100,10 @@ class Entry(object):
self._expand_size = False
self.compress = 'none'
self.missing = False
self.faked = False
self.external = False
self.allow_missing = False
self.allow_fake = False
@staticmethod
def Lookup(node_path, etype, expanded):
@ -898,6 +902,14 @@ features to produce new behaviours.
# This is meaningless for anything other than sections
pass
def SetAllowFakeBlob(self, allow_fake):
"""Set whether a section allows to create a fake blob
Args:
allow_fake: True if allowed, False if not allowed
"""
pass
def CheckMissing(self, missing_list):
"""Check if any entries in this section have missing external blobs
@ -909,6 +921,17 @@ features to produce new behaviours.
if self.missing:
missing_list.append(self)
def CheckFakedBlobs(self, faked_blobs_list):
"""Check if any entries in this section have faked external blobs
If there are faked blobs, the entries are added to the list
Args:
fake_blobs_list: List of Entry objects to be added to
"""
# This is meaningless for anything other than blobs
pass
def GetAllowMissing(self):
"""Get whether a section allows missing external blobs

View File

@ -5,6 +5,8 @@
# Entry-type module for blobs, which are binary objects read from files
#
import pathlib
from binman.entry import Entry
from binman import state
from dtoc import fdt_util
@ -36,6 +38,11 @@ class Entry_blob(Entry):
self._filename = fdt_util.GetString(self._node, 'filename', self.etype)
def ObtainContents(self):
if self.allow_fake and not pathlib.Path(self._filename).is_file():
with open(self._filename, "wb") as out:
out.truncate(1024)
self.faked = True
self._filename = self.GetDefaultFilename()
self._pathname = tools.GetInputFilename(self._filename,
self.external and self.section.GetAllowMissing())
@ -75,3 +82,14 @@ class Entry_blob(Entry):
def ProcessContents(self):
# The blob may have changed due to WriteSymbols()
return self.ProcessContentsUpdate(self.data)
def CheckFakedBlobs(self, faked_blobs_list):
"""Check if any entries in this section have faked external blobs
If there are faked blobs, the entries are added to the list
Args:
fake_blobs_list: List of Entry objects to be added to
"""
if self.faked:
faked_blobs_list.append(self)

View File

@ -26,3 +26,11 @@ class Entry_blob_ext(Entry_blob):
def __init__(self, section, etype, node):
Entry_blob.__init__(self, section, etype, node)
self.external = True
def SetAllowFakeBlob(self, allow_fake):
"""Set whether the entry allows to create a fake blob
Args:
allow_fake_blob: True if allowed, False if not allowed
"""
self.allow_fake = allow_fake

View File

@ -61,3 +61,23 @@ class Entry_mkimage(Entry):
entry = Entry.Create(self, node)
entry.ReadNode()
self._mkimage_entries[entry.name] = entry
def SetAllowFakeBlob(self, allow_fake):
"""Set whether the sub nodes allows to create a fake blob
Args:
allow_fake: True if allowed, False if not allowed
"""
for entry in self._mkimage_entries.values():
entry.SetAllowFakeBlob(allow_fake)
def CheckFakedBlobs(self, faked_blobs_list):
"""Check if any entries in this section have faked external blobs
If there are faked blobs, the entries are added to the list
Args:
faked_blobs_list: List of Entry objects to be added to
"""
for entry in self._mkimage_entries.values():
entry.CheckFakedBlobs(faked_blobs_list)

View File

@ -689,6 +689,15 @@ class Entry_section(Entry):
for entry in self._entries.values():
entry.SetAllowMissing(allow_missing)
def SetAllowFakeBlob(self, allow_fake):
"""Set whether a section allows to create a fake blob
Args:
allow_fake_blob: True if allowed, False if not allowed
"""
for entry in self._entries.values():
entry.SetAllowFakeBlob(allow_fake)
def CheckMissing(self, missing_list):
"""Check if any entries in this section have missing external blobs
@ -700,6 +709,17 @@ class Entry_section(Entry):
for entry in self._entries.values():
entry.CheckMissing(missing_list)
def CheckFakedBlobs(self, faked_blobs_list):
"""Check if any entries in this section have faked external blobs
If there are faked blobs, the entries are added to the list
Args:
fake_blobs_list: List of Entry objects to be added to
"""
for entry in self._entries.values():
entry.CheckFakedBlobs(faked_blobs_list)
def _CollectEntries(self, entries, entries_by_name, add_entry):
"""Collect all the entries in an section

View File

@ -308,7 +308,7 @@ class TestFunctional(unittest.TestCase):
def _DoTestFile(self, fname, debug=False, map=False, update_dtb=False,
entry_args=None, images=None, use_real_dtb=False,
use_expanded=False, verbosity=None, allow_missing=False,
extra_indirs=None, threads=None,
allow_fake_blobs=False, extra_indirs=None, threads=None,
test_section_timeout=False, update_fdt_in_elf=None):
"""Run binman with a given test file
@ -331,6 +331,7 @@ class TestFunctional(unittest.TestCase):
verbosity: Verbosity level to use (0-3, None=don't set it)
allow_missing: Set the '--allow-missing' flag so that missing
external binaries just produce a warning instead of an error
allow_fake_blobs: Set the '--fake-ext-blobs' flag
extra_indirs: Extra input directories to add using -I
threads: Number of threads to use (None for default, 0 for
single-threaded)
@ -369,6 +370,8 @@ class TestFunctional(unittest.TestCase):
args.append('-a%s=%s' % (arg, value))
if allow_missing:
args.append('-M')
if allow_fake_blobs:
args.append('--fake-ext-blobs')
if update_fdt_in_elf:
args += ['--update-fdt-in-elf', update_fdt_in_elf]
if images:
@ -4661,6 +4664,16 @@ class TestFunctional(unittest.TestCase):
str(e.exception),
"Not enough space in '.*u_boot_binman_embed_sm' for data length.*")
def testFakeBlob(self):
"""Test handling of faking an external blob"""
with test_util.capture_sys_output() as (stdout, stderr):
self._DoTestFile('203_fake_blob.dts', allow_missing=True,
allow_fake_blobs=True)
err = stderr.getvalue()
self.assertRegex(err,
"Image '.*' has faked external blobs and is non-functional: .*")
os.remove('binman_faking_test_blob')
if __name__ == "__main__":
unittest.main()

View File

@ -0,0 +1,14 @@
// SPDX-License-Identifier: GPL-2.0+
/dts-v1/;
/ {
#address-cells = <1>;
#size-cells = <1>;
binman {
blob-ext {
filename = "binman_faking_test_blob";
};
};
};