binman: Support lists of external blobs

Sometimes it is useful to have a list of related external blobs in a
single entry. An example is the DDR binaries used by meson. There are
9 files in total. Add support for this, so we don't have to have a
separate entry for each.

Signed-off-by: Simon Glass <sjg@chromium.org>
This commit is contained in:
Simon Glass 2021-11-23 21:09:52 -07:00
parent 1b5a5331f3
commit cc2c500426
6 changed files with 133 additions and 3 deletions

View file

@ -69,6 +69,20 @@ See 'blob' for Properties / Entry arguments.
Entry: blob-ext-list: List of externally built binary blobs
-----------------------------------------------------------
This is like blob-ext except that a number of blobs can be provided,
typically with some sort of relationship, e.g. all are DDC parameters.
If any of the external files needed by this llist is missing, binman can
optionally ignore it and produce a broken image with a warning.
Args:
filenames: List of filenames to read and include
Entry: blob-named-by-arg: A blob entry which gets its filename property from its subclass
-----------------------------------------------------------------------------------------

View file

@ -48,10 +48,10 @@ class Entry_blob(Entry):
self.ReadBlobContents()
return True
def ReadBlobContents(self):
def ReadFileContents(self, pathname):
"""Read blob contents into memory
This function compresses the data before storing if needed.
This function compresses the data before returning if needed.
We assume the data is small enough to fit into memory. If this
is used for large filesystem image that might not be true.
@ -59,13 +59,23 @@ class Entry_blob(Entry):
new Entry method which can read in chunks. Then we could copy
the data in chunks and avoid reading it all at once. For now
this seems like an unnecessary complication.
Args:
pathname (str): Pathname to read from
Returns:
bytes: Data read
"""
state.TimingStart('read')
indata = tools.ReadFile(self._pathname)
indata = tools.ReadFile(pathname)
state.TimingAccum('read')
state.TimingStart('compress')
data = self.CompressData(indata)
state.TimingAccum('compress')
return data
def ReadBlobContents(self):
data = self.ReadFileContents(self._pathname)
self.SetContents(data)
return True

View file

@ -0,0 +1,58 @@
# SPDX-License-Identifier: GPL-2.0+
# Copyright (c) 2016 Google, Inc
# Written by Simon Glass <sjg@chromium.org>
#
# Entry-type module for a list of external blobs, not built by U-Boot
#
import os
from binman.etype.blob import Entry_blob
from dtoc import fdt_util
from patman import tools
from patman import tout
class Entry_blob_ext_list(Entry_blob):
"""List of externally built binary blobs
This is like blob-ext except that a number of blobs can be provided,
typically with some sort of relationship, e.g. all are DDC parameters.
If any of the external files needed by this llist is missing, binman can
optionally ignore it and produce a broken image with a warning.
Args:
filenames: List of filenames to read and include
"""
def __init__(self, section, etype, node):
Entry_blob.__init__(self, section, etype, node)
self.external = True
def ReadNode(self):
super().ReadNode()
self._filenames = fdt_util.GetStringList(self._node, 'filenames')
self._pathnames = []
def ObtainContents(self):
missing = False
pathnames = []
for fname in self._filenames:
pathname = tools.GetInputFilename(
fname, self.external and self.section.GetAllowMissing())
# Allow the file to be missing
if not pathname:
missing = True
pathnames.append(pathname)
self._pathnames = pathnames
if missing:
self.SetContents(b'')
self.missing = True
return True
data = bytearray()
for pathname in pathnames:
data += self.ReadFileContents(pathname)
self.SetContents(data)
return True

View file

@ -4715,6 +4715,26 @@ fdt fdtmap Extract the devicetree blob from the fdtmap
finally:
shutil.rmtree(tmpdir)
def testExtblobList(self):
"""Test an image with an external blob list"""
data = self._DoReadFile('215_blob_ext_list.dts')
self.assertEqual(REFCODE_DATA + FSP_M_DATA, data)
def testExtblobListMissing(self):
"""Test an image with a missing external blob"""
with self.assertRaises(ValueError) as e:
self._DoReadFile('216_blob_ext_list_missing.dts')
self.assertIn("Filename 'missing-file' not found in input path",
str(e.exception))
def testExtblobListMissingOk(self):
"""Test an image with an missing external blob that is allowed"""
with test_util.capture_sys_output() as (stdout, stderr):
self._DoTestFile('216_blob_ext_list_missing.dts',
allow_missing=True)
err = stderr.getvalue()
self.assertRegex(err, "Image 'main-section'.*missing.*: blob-ext")
if __name__ == "__main__":
unittest.main()

View file

@ -0,0 +1,14 @@
// SPDX-License-Identifier: GPL-2.0+
/dts-v1/;
/ {
#address-cells = <1>;
#size-cells = <1>;
binman {
blob-ext-list {
filenames = "refcode.bin", "fsp_m.bin";
};
};
};

View file

@ -0,0 +1,14 @@
// SPDX-License-Identifier: GPL-2.0+
/dts-v1/;
/ {
#address-cells = <1>;
#size-cells = <1>;
binman {
blob-ext-list {
filenames = "refcode.bin", "missing-file";
};
};
};