binman: Plumb in support for missing bintools

Bintools can be missing, in which case binman continues operation but
reports an invalid image. Plumb in support for this and add tests for
entry types which use bintools.

Signed-off-by: Simon Glass <sjg@chromium.org>
This commit is contained in:
Simon Glass 2022-01-09 20:14:09 -07:00
parent 359e431cbc
commit 4f9ee83ba9
5 changed files with 103 additions and 2 deletions

View file

@ -105,6 +105,8 @@ controlled by a description in the board device tree.'''
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('--force-missing-bintools', type=str,
help='Comma-separated list of bintools to consider missing (for testing)')
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

@ -583,7 +583,14 @@ 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])))
return bool(missing_list) or bool(faked_list)
missing_bintool_list = []
image.check_missing_bintools(missing_bintool_list)
if missing_bintool_list:
tout.Warning(
"Image '%s' has missing bintools and is non-functional: %s" %
(image.name, ' '.join([os.path.basename(bintool.name)
for bintool in missing_bintool_list])))
return any([missing_list, faked_list, missing_bintool_list])
def Binman(args):
@ -688,6 +695,9 @@ def Binman(args):
# Set the first image to timeout, used in testThreadTimeout()
images[list(images.keys())[0]].test_section_timeout = True
invalid = False
bintool.Bintool.set_missing_list(
args.force_missing_bintools.split(',') if
args.force_missing_bintools else None)
for image in images.values():
invalid |= ProcessImage(image, args.update_fdt, args.map,
allow_missing=args.allow_missing,

View file

@ -77,6 +77,7 @@ class Entry(object):
available. This is mainly used for testing.
external: True if this entry contains an external binary blob
bintools: Bintools used by this entry (only populated for Image)
missing_bintools: List of missing bintools for this entry
"""
def __init__(self, section, etype, node, name_prefix=''):
# Put this here to allow entry-docs and help to work without libfdt
@ -109,6 +110,7 @@ class Entry(object):
self.allow_missing = False
self.allow_fake = False
self.bintools = {}
self.missing_bintools = []
@staticmethod
def FindEntryClass(etype, expanded):
@ -1015,6 +1017,24 @@ features to produce new behaviours.
"""
return self.allow_missing
def record_missing_bintool(self, bintool):
"""Record a missing bintool that was needed to produce this entry
Args:
bintool (Bintool): Bintool that was missing
"""
self.missing_bintools.append(bintool)
def check_missing_bintools(self, missing_list):
"""Check if any entries in this section have missing bintools
If there are missing bintools, these are added to the list
Args:
missing_list: List of Bintool objects to be added to
"""
missing_list += self.missing_bintools
def GetHelpTags(self):
"""Get the tags use for missing-blob help

View file

@ -832,6 +832,17 @@ class Entry_section(Entry):
for entry in self._entries.values():
entry.CheckFakedBlobs(faked_blobs_list)
def check_missing_bintools(self, missing_list):
"""Check if any entries in this section have missing bintools
If there are missing bintools, these are added to the list
Args:
missing_list: List of Bintool objects to be added to
"""
for entry in self._entries.values():
entry.check_missing_bintools(missing_list)
def _CollectEntries(self, entries, entries_by_name, add_entry):
"""Collect all the entries in an section

View file

@ -310,7 +310,8 @@ class TestFunctional(unittest.TestCase):
entry_args=None, images=None, use_real_dtb=False,
use_expanded=False, verbosity=None, allow_missing=False,
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,
force_missing_bintools=''):
"""Run binman with a given test file
Args:
@ -339,6 +340,8 @@ class TestFunctional(unittest.TestCase):
test_section_timeout: True to force the first time to timeout, as
used in testThreadTimeout()
update_fdt_in_elf: Value to pass with --update-fdt-in-elf=xxx
force_missing_tools (str): comma-separated list of bintools to
regard as missing
Returns:
int return code, 0 on success
@ -373,6 +376,8 @@ class TestFunctional(unittest.TestCase):
args.append('-M')
if allow_fake_blobs:
args.append('--fake-ext-blobs')
if force_missing_bintools:
args += ['--force-missing-bintools', force_missing_bintools]
if update_fdt_in_elf:
args += ['--update-fdt-in-elf', update_fdt_in_elf]
if images:
@ -1713,6 +1718,18 @@ class TestFunctional(unittest.TestCase):
self.assertIn("Node '/binman/gbb': GBB must have a fixed size",
str(e.exception))
def testGbbMissing(self):
"""Test that binman still produces an image if futility is missing"""
entry_args = {
'keydir': 'devkeys',
}
with test_util.capture_sys_output() as (_, stderr):
self._DoTestFile('071_gbb.dts', force_missing_bintools='futility',
entry_args=entry_args)
err = stderr.getvalue()
self.assertRegex(err,
"Image 'main-section'.*missing bintools.*: futility")
def _HandleVblockCommand(self, pipe_list):
"""Fake calls to the futility utility
@ -1798,6 +1815,19 @@ class TestFunctional(unittest.TestCase):
expected_hashval = m.digest()
self.assertEqual(expected_hashval, hashval)
def testVblockMissing(self):
"""Test that binman still produces an image if futility is missing"""
entry_args = {
'keydir': 'devkeys',
}
with test_util.capture_sys_output() as (_, stderr):
self._DoTestFile('074_vblock.dts',
force_missing_bintools='futility',
entry_args=entry_args)
err = stderr.getvalue()
self.assertRegex(err,
"Image 'main-section'.*missing bintools.*: futility")
def testTpl(self):
"""Test that an image with TPL and its device tree can be created"""
# ELF file with a '__bss_size' symbol
@ -2335,6 +2365,16 @@ class TestFunctional(unittest.TestCase):
self.assertIn('Could not complete processing of contents',
str(e.exception))
def testIfwiMissing(self):
"""Test that binman still produces an image if ifwitool is missing"""
self._SetupIfwi('fitimage.bin')
with test_util.capture_sys_output() as (_, stderr):
self._DoTestFile('111_x86_rom_ifwi.dts',
force_missing_bintools='ifwitool')
err = stderr.getvalue()
self.assertRegex(err,
"Image 'main-section'.*missing bintools.*: ifwitool")
def testCbfsOffset(self):
"""Test a CBFS with files at particular offsets
@ -3614,6 +3654,15 @@ class TestFunctional(unittest.TestCase):
# Just check that the data appears in the file somewhere
self.assertIn(U_BOOT_SPL_DATA, data)
def testMkimageMissing(self):
"""Test that binman still produces an image if mkimage is missing"""
with test_util.capture_sys_output() as (_, stderr):
self._DoTestFile('156_mkimage.dts',
force_missing_bintools='mkimage')
err = stderr.getvalue()
self.assertRegex(err,
"Image 'main-section'.*missing bintools.*: mkimage")
def testExtblob(self):
"""Test an image with an external blob"""
data = self._DoReadFile('157_blob_ext.dts')
@ -3734,6 +3783,15 @@ class TestFunctional(unittest.TestCase):
self.assertEqual(U_BOOT_DATA + b'aa',
data[actual_pos:actual_pos + external_data_size])
def testFitMissing(self):
"""Test that binman still produces a FIT image if mkimage is missing"""
with test_util.capture_sys_output() as (_, stderr):
self._DoTestFile('162_fit_external.dts',
force_missing_bintools='mkimage')
err = stderr.getvalue()
self.assertRegex(err,
"Image 'main-section'.*missing bintools.*: mkimage")
def testSectionIgnoreHashSignature(self):
"""Test that sections ignore hash, signature nodes for its data"""
data = self._DoReadFile('165_section_ignore_hash_signature.dts')