binman: Allow missing Intel blobs

Update the Intel blob entries to support missing binaries.

Signed-off-by: Simon Glass <sjg@chromium.org>
Reviewed-by: Bin Meng <bmeng.cn@gmail.com>
diff --git a/tools/binman/etype/intel_descriptor.py b/tools/binman/etype/intel_descriptor.py
index 5b18893..7fe88a9 100644
--- a/tools/binman/etype/intel_descriptor.py
+++ b/tools/binman/etype/intel_descriptor.py
@@ -55,6 +55,12 @@
         return super().Pack(offset)
 
     def GetOffsets(self):
+        info = {}
+        if self.missing:
+            # Return zero offsets so that these entries get placed somewhere
+            if self.HasSibling('intel-me'):
+                info['intel-me'] = [0, None]
+            return info
         offset = self.data.find(FD_SIGNATURE)
         if offset == -1:
             self.Raise('Cannot find Intel Flash Descriptor (FD) signature')
@@ -66,7 +72,6 @@
 
         # Set the offset for ME (Management Engine) and IFWI (Integrated
         # Firmware Image), for now, since the others are not used.
-        info = {}
         if self.HasSibling('intel-me'):
             info['intel-me'] = [self._regions[REGION_ME].base,
                                 self._regions[REGION_ME].size]
diff --git a/tools/binman/etype/intel_ifwi.py b/tools/binman/etype/intel_ifwi.py
index b0c2b1a..76b3357 100644
--- a/tools/binman/etype/intel_ifwi.py
+++ b/tools/binman/etype/intel_ifwi.py
@@ -84,7 +84,7 @@
         return True
 
     def ObtainContents(self):
-        """Get the contects for the IFWI
+        """Get the contents for the IFWI
 
         Unfortunately we cannot create anything from scratch here, as Intel has
         tools which create precursor binaries with lots of data and settings,
@@ -97,13 +97,21 @@
         After that we delete the OBBP sub-partition and add each of the files
         that we want in the IFWI file, one for each sub-entry of the IWFI node.
         """
-        self._pathname = tools.GetInputFilename(self._filename)
+        self._pathname = tools.GetInputFilename(self._filename,
+                                                self.section.GetAllowMissing())
+        # Allow the file to be missing
+        if not self._pathname:
+            self.SetContents(b'')
+            self.missing = True
+            return True
         for entry in self._ifwi_entries.values():
             if not entry.ObtainContents():
                 return False
         return self._BuildIfwi()
 
     def ProcessContents(self):
+        if self.missing:
+            return True
         orig_data = self.data
         self._BuildIfwi()
         same = orig_data == self.data
@@ -121,5 +129,6 @@
 
     def WriteSymbols(self, section):
         """Write symbol values into binary files for access at run time"""
-        for entry in self._ifwi_entries.values():
-            entry.WriteSymbols(self)
+        if not self.missing:
+            for entry in self._ifwi_entries.values():
+                entry.WriteSymbols(self)
diff --git a/tools/binman/etype/section.py b/tools/binman/etype/section.py
index dd7f1cc..7cd12c0 100644
--- a/tools/binman/etype/section.py
+++ b/tools/binman/etype/section.py
@@ -442,8 +442,8 @@
         if not entry:
             self._Raise("Unable to set offset/size for unknown entry '%s'" %
                         name)
-        entry.SetOffsetSize(self._skip_at_start + offset if offset else None,
-                            size)
+        entry.SetOffsetSize(self._skip_at_start + offset if offset is not None
+                            else None, size)
 
     def GetEntryOffsets(self):
         """Handle entries that want to set the offset/size of other entries
diff --git a/tools/binman/ftest.py b/tools/binman/ftest.py
index cc551c9..146d4c5 100644
--- a/tools/binman/ftest.py
+++ b/tools/binman/ftest.py
@@ -160,8 +160,7 @@
             tools.ReadFile(cls.ElfTestFile('u_boot_ucode_ptr')))
 
         # Intel flash descriptor file
-        with open(cls.TestFile('descriptor.bin'), 'rb') as fd:
-            TestFunctional._MakeInputFile('descriptor.bin', fd.read())
+        cls._SetupDescriptor()
 
         shutil.copytree(cls.TestFile('files'),
                         os.path.join(cls._indir, 'files'))
@@ -508,6 +507,11 @@
             tools.ReadFile(cls.ElfTestFile(src_fname)))
 
     @classmethod
+    def _SetupDescriptor(cls):
+        with open(cls.TestFile('descriptor.bin'), 'rb') as fd:
+            TestFunctional._MakeInputFile('descriptor.bin', fd.read())
+
+    @classmethod
     def TestFile(cls, fname):
         return os.path.join(cls._binman_dir, 'test', fname)
 
@@ -933,11 +937,14 @@
 
     def testPackX86RomMeNoDesc(self):
         """Test that an invalid Intel descriptor entry is detected"""
-        TestFunctional._MakeInputFile('descriptor.bin', b'')
-        with self.assertRaises(ValueError) as e:
-            self._DoTestFile('031_x86_rom_me.dts')
-        self.assertIn("Node '/binman/intel-descriptor': Cannot find Intel Flash Descriptor (FD) signature",
-                      str(e.exception))
+        try:
+            TestFunctional._MakeInputFile('descriptor.bin', b'')
+            with self.assertRaises(ValueError) as e:
+                self._DoTestFile('031_x86_rom_me.dts')
+            self.assertIn("Node '/binman/intel-descriptor': Cannot find Intel Flash Descriptor (FD) signature",
+                          str(e.exception))
+        finally:
+            self._SetupDescriptor()
 
     def testPackX86RomBadDesc(self):
         """Test that the Intel requires a descriptor entry"""
@@ -3394,6 +3401,26 @@
         self.assertRegex(err, "Image 'main-section'.*missing.*: "
                          "blob-ext blob-ext2")
 
+    def testPackX86RomMeMissingDesc(self):
+        """Test that an missing Intel descriptor entry is allowed"""
+        pathname = os.path.join(self._indir, 'descriptor.bin')
+        os.remove(pathname)
+        with test_util.capture_sys_output() as (stdout, stderr):
+            self._DoTestFile('031_x86_rom_me.dts', allow_missing=True)
+        err = stderr.getvalue()
+        self.assertRegex(err,
+                         "Image 'main-section'.*missing.*: intel-descriptor")
+
+    def testPackX86RomMissingIfwi(self):
+        """Test that an x86 ROM with Integrated Firmware Image can be created"""
+        self._SetupIfwi('fitimage.bin')
+        pathname = os.path.join(self._indir, 'fitimage.bin')
+        os.remove(pathname)
+        with test_util.capture_sys_output() as (stdout, stderr):
+            self._DoTestFile('111_x86_rom_ifwi.dts', allow_missing=True)
+        err = stderr.getvalue()
+        self.assertRegex(err, "Image 'main-section'.*missing.*: intel-ifwi")
+
 
 if __name__ == "__main__":
     unittest.main()