diff --git a/tools/binman/README.entries b/tools/binman/README.entries
index 46f6ab1899..f45f51428a 100644
--- a/tools/binman/README.entries
+++ b/tools/binman/README.entries
@@ -48,6 +48,9 @@ Entry: blob-ext: Entry containing an externally built binary blob
 Note: This should not be used by itself. It is normally used as a parent
 class by other entry types.
 
+If the file providing this blob is missing, binman can optionally ignore it
+and produce a broken image with a warning.
+
 See 'blob' for Properties / Entry arguments.
 
 
diff --git a/tools/binman/cmdline.py b/tools/binman/cmdline.py
index 1e38593579..bb4d9d1288 100644
--- a/tools/binman/cmdline.py
+++ b/tools/binman/cmdline.py
@@ -53,6 +53,8 @@ controlled by a description in the board device tree.'''
             help='Add a path to the list of directories to use for input files')
     build_parser.add_argument('-m', '--map', action='store_true',
         default=False, help='Output a map file for each image')
+    build_parser.add_argument('-M', '--allow-missing', action='store_true',
+        default=False, help='Allow external blobs to be missing')
     build_parser.add_argument('-O', '--outdir', type=str,
         action='store', help='Path to directory to use for intermediate and '
         'output files')
diff --git a/tools/binman/control.py b/tools/binman/control.py
index dc1dd2a7dc..8c6eae83f1 100644
--- a/tools/binman/control.py
+++ b/tools/binman/control.py
@@ -387,7 +387,7 @@ def PrepareImagesAndDtbs(dtb_fname, select_images, update_fdt):
 
 
 def ProcessImage(image, update_fdt, write_map, get_contents=True,
-                 allow_resize=True):
+                 allow_resize=True, allow_missing=False):
     """Perform all steps for this image, including checking and # writing it.
 
     This means that errors found with a later image will be reported after
@@ -402,8 +402,10 @@ def ProcessImage(image, update_fdt, write_map, get_contents=True,
             the contents is already present
         allow_resize: True to allow entries to change size (this does a re-pack
             of the entries), False to raise an exception
+        allow_missing: Allow blob_ext objects to be missing
     """
     if get_contents:
+        image.SetAllowMissing(allow_missing)
         image.GetEntryContents()
     image.GetEntryOffsets()
 
@@ -523,7 +525,8 @@ def Binman(args):
             images = PrepareImagesAndDtbs(dtb_fname, args.image,
                                           args.update_fdt)
             for image in images.values():
-                ProcessImage(image, args.update_fdt, args.map)
+                ProcessImage(image, args.update_fdt, args.map,
+                             allow_missing=args.allow_missing)
 
             # Write the updated FDTs to our output files
             for dtb_item in state.GetAllFdts():
diff --git a/tools/binman/entry.py b/tools/binman/entry.py
index 90ffd27617..9388586e7c 100644
--- a/tools/binman/entry.py
+++ b/tools/binman/entry.py
@@ -794,3 +794,12 @@ features to produce new behaviours.
             elif self == entries[-1]:
                 return 'end'
         return 'middle'
+
+    def SetAllowMissing(self, allow_missing):
+        """Set whether a section allows missing external blobs
+
+        Args:
+            allow_missing: True if allowed, False if not allowed
+        """
+        # This is meaningless for anything other than sections
+        pass
diff --git a/tools/binman/etype/blob_ext.py b/tools/binman/etype/blob_ext.py
index cc8d91bb59..51779c88c9 100644
--- a/tools/binman/etype/blob_ext.py
+++ b/tools/binman/etype/blob_ext.py
@@ -18,6 +18,9 @@ class Entry_blob_ext(Entry_blob):
     Note: This should not be used by itself. It is normally used as a parent
     class by other entry types.
 
+    If the file providing this blob is missing, binman can optionally ignore it
+    and produce a broken image with a warning.
+
     See 'blob' for Properties / Entry arguments.
     """
     def __init__(self, section, etype, node):
@@ -26,6 +29,10 @@ class Entry_blob_ext(Entry_blob):
 
     def ObtainContents(self):
         self._filename = self.GetDefaultFilename()
-        self._pathname = tools.GetInputFilename(self._filename)
-        self.ReadBlobContents()
-        return True
+        self._pathname = tools.GetInputFilename(self._filename,
+                                                self.section.GetAllowMissing())
+        # Allow the file to be missing
+        if not self._pathname:
+            self.SetContents(b'')
+            return True
+        return super().ObtainContents()
diff --git a/tools/binman/etype/section.py b/tools/binman/etype/section.py
index f108121c3a..9b718f1fa7 100644
--- a/tools/binman/etype/section.py
+++ b/tools/binman/etype/section.py
@@ -34,6 +34,11 @@ class Entry_section(Entry):
         name-prefix: Adds a prefix to the name of every entry in the section
             when writing out the map
 
+    Properties:
+        _allow_missing: True if this section permits external blobs to be
+            missing their contents. The second will produce an image but of
+            course it will not work.
+
     Since a section is also an entry, it inherits all the properies of entries
     too.
 
@@ -49,6 +54,7 @@ class Entry_section(Entry):
         self._sort = False
         self._skip_at_start = None
         self._end_4gb = False
+        self._allow_missing = False
 
     def ReadNode(self):
         """Read properties from the image node"""
@@ -535,3 +541,21 @@ class Entry_section(Entry):
 
     def WriteChildData(self, child):
         return True
+
+    def SetAllowMissing(self, allow_missing):
+        """Set whether a section allows missing external blobs
+
+        Args:
+            allow_missing: True if allowed, False if not allowed
+        """
+        self._allow_missing = allow_missing
+        for entry in self._entries.values():
+            entry.SetAllowMissing(allow_missing)
+
+    def GetAllowMissing(self):
+        """Get whether a section allows missing external blobs
+
+        Returns:
+            True if allowed, False if not allowed
+        """
+        return self._allow_missing
diff --git a/tools/binman/ftest.py b/tools/binman/ftest.py
index f8d5191672..7c8b3eb3a0 100644
--- a/tools/binman/ftest.py
+++ b/tools/binman/ftest.py
@@ -285,7 +285,7 @@ class TestFunctional(unittest.TestCase):
 
     def _DoTestFile(self, fname, debug=False, map=False, update_dtb=False,
                     entry_args=None, images=None, use_real_dtb=False,
-                    verbosity=None):
+                    verbosity=None, allow_missing=False):
         """Run binman with a given test file
 
         Args:
@@ -319,6 +319,8 @@ class TestFunctional(unittest.TestCase):
         if entry_args:
             for arg, value in entry_args.items():
                 args.append('-a%s=%s' % (arg, value))
+        if allow_missing:
+            args.append('-M')
         if images:
             for image in images:
                 args += ['-i', image]
@@ -3376,6 +3378,10 @@ class TestFunctional(unittest.TestCase):
         self.assertIn("Filename 'missing-file' not found in input path",
                       str(e.exception))
 
+    def testExtblobMissingOk(self):
+        """Test an image with an missing external blob that is allowed"""
+        self._DoTestFile('158_blob_ext_missing.dts', allow_missing=True)
+
 
 if __name__ == "__main__":
     unittest.main()
diff --git a/tools/patman/tools.py b/tools/patman/tools.py
index b50370dfe8..7d92e20afa 100644
--- a/tools/patman/tools.py
+++ b/tools/patman/tools.py
@@ -114,14 +114,16 @@ def SetInputDirs(dirname):
     indir = dirname
     tout.Debug("Using input directories %s" % indir)
 
-def GetInputFilename(fname):
+def GetInputFilename(fname, allow_missing=False):
     """Return a filename for use as input.
 
     Args:
         fname: Filename to use for new file
+        allow_missing: True if the filename can be missing
 
     Returns:
-        The full path of the filename, within the input directory
+        The full path of the filename, within the input directory, or
+        None on error
     """
     if not indir or fname[:1] == '/':
         return fname
@@ -130,6 +132,8 @@ def GetInputFilename(fname):
         if os.path.exists(pathname):
             return pathname
 
+    if allow_missing:
+        return None
     raise ValueError("Filename '%s' not found in input path (%s) (cwd='%s')" %
                      (fname, ','.join(indir), os.getcwd()))
 
