]> git.dujemihanovic.xyz Git - u-boot.git/commitdiff
binman: Support optional external blobs
authorSimon Glass <sjg@chromium.org>
Sat, 7 Jan 2023 21:07:15 +0000 (14:07 -0700)
committerSimon Glass <sjg@chromium.org>
Wed, 18 Jan 2023 18:50:01 +0000 (11:50 -0700)
Some blobs are actually not necessary for the board to work correctly. Add
a property to allow this to be indicated. Missing optional blobs do not
cause a build failure.

Signed-off-by: Simon Glass <sjg@chromium.org>
tools/binman/binman.rst
tools/binman/control.py
tools/binman/entry.py
tools/binman/etype/blob.py
tools/binman/etype/fit.py
tools/binman/etype/section.py
tools/binman/ftest.py
tools/binman/test/266_blob_ext_opt.dts [new file with mode: 0644]

index 5e3961f225529fa298c8c6e4b709140d55267a2d..bfe300a39c19215ecc73259530d9ceda4c5071c9 100644 (file)
@@ -690,6 +690,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.
 
index 07225381146b36c9f9fdc6328187a0938843ee15..e64740094f60ac0118850abdd2b1a7fbca2c7693 100644 (file)
@@ -594,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:
@@ -607,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:
index de51d29589133f271fe3503357945c2223cf5aa4..d73f30134052d365b49df914909501f62b3114e6 100644 (file)
@@ -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
@@ -95,6 +97,7 @@ class Entry(object):
             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
     """
     fake_dir = None
 
@@ -138,6 +141,7 @@ class Entry(object):
         self.elf_fname = None
         self.auto_write_symbols = auto_write_symbols
         self.absent = False
+        self.optional = False
 
     @staticmethod
     def FindEntryClass(etype, expanded):
@@ -289,6 +293,7 @@ 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')
 
         # This is only supported by blobs and sections at present
         self.compress = fdt_util.GetString(self._node, 'compress', 'none')
@@ -1039,14 +1044,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):
@@ -1085,6 +1091,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
 
index a50a80689012f4ee36a4329e2734f29cd9742184..70dea7158ee09c13a29096a2e3115014ae0456b7 100644 (file)
@@ -39,7 +39,7 @@ class Entry_blob(Entry):
     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,
index fea3adcc68d717587f3a5a728debb64a67612ac8..f0e3fd1a09229bcd261030d3f025cad3c3a0d5e9 100644 (file)
@@ -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):
@@ -602,14 +602,15 @@ 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)
-                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_list:
+                if not missing_opt_list:
                     segs = entry.read_elf_segments()
                     if segs:
                         segments, entry_addr = segs
index 57bfee0b286d96977c5fb887b0f1b00103120bcc..44dafaf7262747eea76bc1e19db2d8b66c695b18 100644 (file)
@@ -863,7 +863,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
@@ -882,6 +883,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
 
index f893050e706baf2b590a7445e999bb39e352adb5..330e8e1ccb4abc71c37393fa195c8d521f42f3c4 100644 (file)
@@ -6178,6 +6178,16 @@ fdt         fdtmap                Extract the devicetree blob from the fdtmap
             "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")
+
 
 if __name__ == "__main__":
     unittest.main()
diff --git a/tools/binman/test/266_blob_ext_opt.dts b/tools/binman/test/266_blob_ext_opt.dts
new file mode 100644 (file)
index 0000000..7171531
--- /dev/null
@@ -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;
+               };
+       };
+};