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 tpl-bss-pad=$(if $(CONFIG_TPL_SEPARATE_BSS),,1) \
-a spl-dtb=$(CONFIG_SPL_OF_REAL) \ -a spl-dtb=$(CONFIG_SPL_OF_REAL) \
-a tpl-dtb=$(CONFIG_TPL_OF_REAL) \ -a tpl-dtb=$(CONFIG_TPL_OF_REAL) \
$(if $(BINMAN_FAKE_EXT_BLOBS),--fake-ext-blobs) \
$(BINMAN_$(@F)) $(BINMAN_$(@F))
OBJCOPYFLAGS_u-boot.ldr.hex := -I binary -O ihex 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') help='Configuration file (.dtb) to use')
build_parser.add_argument('--fake-dtb', action='store_true', build_parser.add_argument('--fake-dtb', action='store_true',
help='Use fake device tree contents (for testing only)') 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', build_parser.add_argument('-i', '--image', type=str, action='append',
help='Image filename to build (if not specified, build all)') help='Image filename to build (if not specified, build all)')
build_parser.add_argument('-I', '--indir', action='append', 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, 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. """Perform all steps for this image, including checking and # writing it.
This means that errors found with a later image will be reported after 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 allow_resize: True to allow entries to change size (this does a re-pack
of the entries), False to raise an exception of the entries), False to raise an exception
allow_missing: Allow blob_ext objects to be missing allow_missing: Allow blob_ext objects to be missing
allow_fake_blobs: Allow blob_ext objects to be faked with dummy files
Returns: 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: if get_contents:
image.SetAllowMissing(allow_missing) image.SetAllowMissing(allow_missing)
image.SetAllowFakeBlob(allow_fake_blobs)
image.GetEntryContents() image.GetEntryContents()
image.GetEntryOffsets() 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" % tout.Warning("Image '%s' is missing external blobs and is non-functional: %s" %
(image.name, ' '.join([e.name for e in missing_list]))) (image.name, ' '.join([e.name for e in missing_list])))
_ShowHelpForMissingBlobs(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): def Binman(args):
@ -636,13 +646,15 @@ def Binman(args):
images = PrepareImagesAndDtbs(dtb_fname, args.image, images = PrepareImagesAndDtbs(dtb_fname, args.image,
args.update_fdt, use_expanded) args.update_fdt, use_expanded)
if args.test_section_timeout: if args.test_section_timeout:
# Set the first image to timeout, used in testThreadTimeout() # Set the first image to timeout, used in testThreadTimeout()
images[list(images.keys())[0]].test_section_timeout = True images[list(images.keys())[0]].test_section_timeout = True
missing = False invalid = False
for image in images.values(): for image in images.values():
missing |= ProcessImage(image, args.update_fdt, args.map, invalid |= ProcessImage(image, args.update_fdt, args.map,
allow_missing=args.allow_missing) allow_missing=args.allow_missing,
allow_fake_blobs=args.fake_ext_blobs)
# Write the updated FDTs to our output files # Write the updated FDTs to our output files
for dtb_item in state.GetAllFdts(): for dtb_item in state.GetAllFdts():
@ -652,7 +664,7 @@ def Binman(args):
data = state.GetFdtForEtype('u-boot-dtb').GetContents() data = state.GetFdtForEtype('u-boot-dtb').GetContents()
elf.UpdateFile(*elf_params, data) elf.UpdateFile(*elf_params, data)
if missing: if invalid:
tout.Warning("\nSome images are invalid") tout.Warning("\nSome images are invalid")
# Use this to debug the time take to pack the image # 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 missing: True if this entry is missing its contents
allow_missing: Allow children of this entry to be missing (used by allow_missing: Allow children of this entry to be missing (used by
subclasses such as Entry_section) 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 external: True if this entry contains an external binary blob
""" """
def __init__(self, section, etype, node, name_prefix=''): def __init__(self, section, etype, node, name_prefix=''):
@ -98,8 +100,10 @@ class Entry(object):
self._expand_size = False self._expand_size = False
self.compress = 'none' self.compress = 'none'
self.missing = False self.missing = False
self.faked = False
self.external = False self.external = False
self.allow_missing = False self.allow_missing = False
self.allow_fake = False
@staticmethod @staticmethod
def Lookup(node_path, etype, expanded): def Lookup(node_path, etype, expanded):
@ -898,6 +902,14 @@ features to produce new behaviours.
# This is meaningless for anything other than sections # This is meaningless for anything other than sections
pass 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): def CheckMissing(self, missing_list):
"""Check if any entries in this section have missing external blobs """Check if any entries in this section have missing external blobs
@ -909,6 +921,17 @@ features to produce new behaviours.
if self.missing: if self.missing:
missing_list.append(self) 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): def GetAllowMissing(self):
"""Get whether a section allows missing external blobs """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 # Entry-type module for blobs, which are binary objects read from files
# #
import pathlib
from binman.entry import Entry from binman.entry import Entry
from binman import state from binman import state
from dtoc import fdt_util from dtoc import fdt_util
@ -36,6 +38,11 @@ class Entry_blob(Entry):
self._filename = fdt_util.GetString(self._node, 'filename', self.etype) self._filename = fdt_util.GetString(self._node, 'filename', self.etype)
def ObtainContents(self): 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._filename = self.GetDefaultFilename()
self._pathname = tools.GetInputFilename(self._filename, self._pathname = tools.GetInputFilename(self._filename,
self.external and self.section.GetAllowMissing()) self.external and self.section.GetAllowMissing())
@ -75,3 +82,14 @@ class Entry_blob(Entry):
def ProcessContents(self): def ProcessContents(self):
# The blob may have changed due to WriteSymbols() # The blob may have changed due to WriteSymbols()
return self.ProcessContentsUpdate(self.data) 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): def __init__(self, section, etype, node):
Entry_blob.__init__(self, section, etype, node) Entry_blob.__init__(self, section, etype, node)
self.external = True 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 = Entry.Create(self, node)
entry.ReadNode() entry.ReadNode()
self._mkimage_entries[entry.name] = entry 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(): for entry in self._entries.values():
entry.SetAllowMissing(allow_missing) 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): def CheckMissing(self, missing_list):
"""Check if any entries in this section have missing external blobs """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(): for entry in self._entries.values():
entry.CheckMissing(missing_list) 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): def _CollectEntries(self, entries, entries_by_name, add_entry):
"""Collect all the entries in an section """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, def _DoTestFile(self, fname, debug=False, map=False, update_dtb=False,
entry_args=None, images=None, use_real_dtb=False, entry_args=None, images=None, use_real_dtb=False,
use_expanded=False, verbosity=None, allow_missing=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): test_section_timeout=False, update_fdt_in_elf=None):
"""Run binman with a given test file """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) verbosity: Verbosity level to use (0-3, None=don't set it)
allow_missing: Set the '--allow-missing' flag so that missing allow_missing: Set the '--allow-missing' flag so that missing
external binaries just produce a warning instead of an error 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 extra_indirs: Extra input directories to add using -I
threads: Number of threads to use (None for default, 0 for threads: Number of threads to use (None for default, 0 for
single-threaded) single-threaded)
@ -369,6 +370,8 @@ class TestFunctional(unittest.TestCase):
args.append('-a%s=%s' % (arg, value)) args.append('-a%s=%s' % (arg, value))
if allow_missing: if allow_missing:
args.append('-M') args.append('-M')
if allow_fake_blobs:
args.append('--fake-ext-blobs')
if update_fdt_in_elf: if update_fdt_in_elf:
args += ['--update-fdt-in-elf', update_fdt_in_elf] args += ['--update-fdt-in-elf', update_fdt_in_elf]
if images: if images:
@ -4661,6 +4664,16 @@ class TestFunctional(unittest.TestCase):
str(e.exception), str(e.exception),
"Not enough space in '.*u_boot_binman_embed_sm' for data length.*") "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__": if __name__ == "__main__":
unittest.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";
};
};
};