binman: rework dropping absent entries from packaged image
When blobs are absent and are marked as optional, they can be safely
dropped from the binman tree. Use the drop_absent function for that.
Rename drop_absent to drop_absent_optional as we do not want to drop any
entries that are absent; they should be reported by binman as errors
when they are missing.
We also reorder the processing of the image the following:
- We call the CheckForProblems function before the image is built.
- We drop entries after we checked for problems with the image.
This is okay because CheckForProblems does not look at the file we have
written but rather queries the data structure (image) built with binman.
This also allows us to get all error and warning messages that we want
to report while avoiding putting missing optional entries in the final
image.
As only the blobs are dropped, the sections still remain in the
assembled image. Thus add them to the expected test case checks where
necessary.
In addition, a rework of testPackTeeOsOptional test case is necessary.
The test did not really do what it was supposed to. The description said
that optional binary is tested, but the binary is not marked as
optional. Further, the tee.elf file, when included in the image
properly, also shows up in the image data. This must be added as well.
As there is no global variable for the elf data, set the pathname to the
elf file that was created when setting up the test suite.
For the test case get the filename and read the contents, comparing them
to the contents of the created binman image.
Signed-off-by: Yannic Moog <y.moog@phytec.de>
Reviewed-by: Bryan Brattlof <bb@ti.com>
diff --git a/tools/binman/control.py b/tools/binman/control.py
index 1946656..5a66c06 100644
--- a/tools/binman/control.py
+++ b/tools/binman/control.py
@@ -697,7 +697,6 @@
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
@@ -736,12 +735,12 @@
image.Raise('Entries changed size after packing (tried %s passes)' %
passes)
+ has_problems = CheckForProblems(image)
+
image.BuildImage()
if write_map:
image.WriteMap()
- has_problems = CheckForProblems(image)
-
image.WriteAlternates()
return has_problems
diff --git a/tools/binman/entry.py b/tools/binman/entry.py
index 6390917..ce7ef28 100644
--- a/tools/binman/entry.py
+++ b/tools/binman/entry.py
@@ -760,7 +760,7 @@
self.image_pos)
# pylint: disable=assignment-from-none
- def GetEntries(self):
+ def GetEntries(self) -> None:
"""Return a list of entries contained by this entry
Returns:
@@ -1351,6 +1351,10 @@
os.mkdir(cls.fake_dir)
tout.notice(f"Fake-blob dir is '{cls.fake_dir}'")
+ def drop_absent_optional(self) -> None:
+ """Entries don't have any entries, do nothing"""
+ pass
+
def ensure_props(self):
"""Raise an exception if properties are missing
diff --git a/tools/binman/etype/cbfs.py b/tools/binman/etype/cbfs.py
index 124fa1e..5879f37 100644
--- a/tools/binman/etype/cbfs.py
+++ b/tools/binman/etype/cbfs.py
@@ -276,7 +276,8 @@
for entry in self._entries.values():
entry.ListEntries(entries, indent + 1)
- def GetEntries(self):
+ def GetEntries(self) -> dict[str, Entry]:
+ """Returns the entries (tree children) of this section"""
return self._entries
def ReadData(self, decomp=True, alt_format=None):
diff --git a/tools/binman/etype/mkimage.py b/tools/binman/etype/mkimage.py
index 6ae5d0c..75e59c3 100644
--- a/tools/binman/etype/mkimage.py
+++ b/tools/binman/etype/mkimage.py
@@ -205,7 +205,7 @@
self.record_missing_bintool(self.mkimage)
return data
- def GetEntries(self):
+ def GetEntries(self) -> dict[str, Entry]:
# Make a copy so we don't change the original
entries = OrderedDict(self._entries)
if self._imagename:
diff --git a/tools/binman/etype/section.py b/tools/binman/etype/section.py
index 1d50bb4..03c4f7c 100644
--- a/tools/binman/etype/section.py
+++ b/tools/binman/etype/section.py
@@ -537,7 +537,7 @@
for entry in self._entries.values():
entry.WriteMap(fd, indent + 1)
- def GetEntries(self):
+ def GetEntries(self) -> dict[str, Entry]:
return self._entries
def GetContentsByPhandle(self, phandle, source_entry, required):
@@ -772,9 +772,17 @@
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 drop_absent_optional(self) -> None:
+ """Drop entries which are absent.
+ Call for all nodes in the tree. Leaf nodes will do nothing per
+ definition. Sections however have _entries and should drop all children
+ which are absent.
+ """
+ self._entries = {n: e for n, e in self._entries.items() if not (e.absent and e.optional)}
+ # Drop nodes first before traversing children to avoid superfluous calls
+ # to children of absent nodes.
+ for e in self.GetEntries().values():
+ e.drop_absent_optional()
def _SetEntryOffsetSize(self, name, offset, size):
"""Set the offset and size of an entry
diff --git a/tools/binman/ftest.py b/tools/binman/ftest.py
index 4a8d330..d707e2a 100644
--- a/tools/binman/ftest.py
+++ b/tools/binman/ftest.py
@@ -251,7 +251,7 @@
# ATF and OP_TEE
TestFunctional._MakeInputFile('bl31.elf',
tools.read_file(cls.ElfTestFile('elf_sections')))
- TestFunctional._MakeInputFile('tee.elf',
+ TestFunctional.tee_elf_path = TestFunctional._MakeInputFile('tee.elf',
tools.read_file(cls.ElfTestFile('elf_sections')))
# Newer OP_TEE file in v1 binary format
@@ -6459,16 +6459,18 @@
def testAbsent(self):
"""Check handling of absent entries"""
data = self._DoReadFile('262_absent.dts')
- self.assertEqual(U_BOOT_DATA + U_BOOT_IMG_DATA, data)
+ self.assertEqual(U_BOOT_DATA + b'aa' + U_BOOT_IMG_DATA, data)
- def testPackTeeOsOptional(self):
- """Test that an image with an optional TEE binary can be created"""
+ def testPackTeeOsElf(self):
+ """Test that an image with a TEE elf binary can be created"""
entry_args = {
'tee-os-path': 'tee.elf',
}
+ tee_path = self.tee_elf_path
data = self._DoReadFileDtb('263_tee_os_opt.dts',
entry_args=entry_args)[0]
- self.assertEqual(U_BOOT_DATA + U_BOOT_IMG_DATA, data)
+ self.assertEqual(U_BOOT_DATA + tools.read_file(tee_path) +
+ U_BOOT_IMG_DATA, data)
def checkFitTee(self, dts, tee_fname):
"""Check that a tee-os entry works and returns data
@@ -6724,7 +6726,7 @@
node = dtb.GetNode('/configurations/conf-missing-tee-1')
self.assertEqual('atf-1', node.props['firmware'].value)
- self.assertEqual(['u-boot', 'atf-2'],
+ self.assertEqual(['u-boot', 'tee', 'atf-2'],
fdt_util.GetStringList(node, 'loadables'))
def testTooldir(self):
diff --git a/tools/binman/image.py b/tools/binman/image.py
index 24ce0af..698cfa4 100644
--- a/tools/binman/image.py
+++ b/tools/binman/image.py
@@ -183,6 +183,8 @@
fname = tools.get_output_filename(self._filename)
tout.info("Writing image to '%s'" % fname)
with open(fname, 'wb') as fd:
+ # For final image, don't write absent blobs to file
+ self.drop_absent_optional()
data = self.GetPaddedData()
fd.write(data)
tout.info("Wrote %#x bytes" % len(data))