From 189f291914cb867f8782d7224a1073d6e17fc800 Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Sun, 21 Mar 2021 18:24:31 +1300 Subject: [PATCH] binman: Add support for a collection of entries The vblock entry type includes code to collect the data from a number of other entries (not necessarily subentries) and concatenating it. This is a useful feature for other entry types. Make it a base class, so that vblock can use it, along with other entry types. Signed-off-by: Simon Glass --- tools/binman/entries.rst | 13 ++++++ tools/binman/entry.py | 5 +++ tools/binman/etype/collection.py | 61 ++++++++++++++++++++++++++++ tools/binman/etype/vblock.py | 26 ++++++------ tools/binman/ftest.py | 10 ++++- tools/binman/test/198_collection.dts | 27 ++++++++++++ 6 files changed, 128 insertions(+), 14 deletions(-) create mode 100644 tools/binman/etype/collection.py create mode 100644 tools/binman/test/198_collection.dts diff --git a/tools/binman/entries.rst b/tools/binman/entries.rst index 1a71413f94..d5f8d95dc1 100644 --- a/tools/binman/entries.rst +++ b/tools/binman/entries.rst @@ -248,6 +248,19 @@ both of size 1MB. +Entry: collection: An entry which contains a collection of other entries +------------------------------------------------------------------------ + +Properties / Entry arguments: + - content: List of phandles to entries to include + +This allows reusing the contents of other entries. The contents of the +listed entries are combined to form this entry. This serves as a useful +base class for entry types which need to process data from elsewhere in +the image, not necessarily child entries. + + + Entry: cros-ec-rw: A blob entry which contains a Chromium OS read-write EC image -------------------------------------------------------------------------------- diff --git a/tools/binman/entry.py b/tools/binman/entry.py index ac25986ee6..a157038d4e 100644 --- a/tools/binman/entry.py +++ b/tools/binman/entry.py @@ -438,6 +438,11 @@ class Entry(object): """Convenience function to raise an error referencing a node""" raise ValueError("Node '%s': %s" % (self._node.path, msg)) + def Info(self, msg): + """Convenience function to log info referencing a node""" + tag = "Info '%s'" % self._node.path + tout.Detail('%30s: %s' % (tag, msg)) + def Detail(self, msg): """Convenience function to log detail referencing a node""" tag = "Node '%s'" % self._node.path diff --git a/tools/binman/etype/collection.py b/tools/binman/etype/collection.py new file mode 100644 index 0000000000..c0c552ac4f --- /dev/null +++ b/tools/binman/etype/collection.py @@ -0,0 +1,61 @@ +# SPDX-License-Identifier: GPL-2.0+ +# Copyright 2021 Google LLC +# Written by Simon Glass +# + +# Support for a collection of entries from other parts of an image + +from collections import OrderedDict +import os + +from binman.entry import Entry +from dtoc import fdt_util + +class Entry_collection(Entry): + """An entry which contains a collection of other entries + + Properties / Entry arguments: + - content: List of phandles to entries to include + + This allows reusing the contents of other entries. The contents of the + listed entries are combined to form this entry. This serves as a useful + base class for entry types which need to process data from elsewhere in + the image, not necessarily child entries. + """ + def __init__(self, section, etype, node): + super().__init__(section, etype, node) + self.content = fdt_util.GetPhandleList(self._node, 'content') + if not self.content: + self.Raise("Collection must have a 'content' property") + + def GetContents(self): + """Get the contents of this entry + + Returns: + bytes content of the entry + """ + # Join up all the data + self.Info('Getting content') + data = b'' + for entry_phandle in self.content: + entry_data = self.section.GetContentsByPhandle(entry_phandle, self) + if entry_data is None: + # Data not available yet + return None + data += entry_data + + self.Info('Returning contents size %x' % len(data)) + + return data + + def ObtainContents(self): + data = self.GetContents() + if data is None: + return False + self.SetContents(data) + return True + + def ProcessContents(self): + # The blob may have changed due to WriteSymbols() + data = self.GetContents() + return self.ProcessContentsUpdate(data) diff --git a/tools/binman/etype/vblock.py b/tools/binman/etype/vblock.py index eba5351dd5..d473083cab 100644 --- a/tools/binman/etype/vblock.py +++ b/tools/binman/etype/vblock.py @@ -9,12 +9,13 @@ from collections import OrderedDict import os -from binman.entry import Entry, EntryArg +from binman.entry import EntryArg +from binman.etype.collection import Entry_collection from dtoc import fdt_util from patman import tools -class Entry_vblock(Entry): +class Entry_vblock(Entry_collection): """An entry which contains a Chromium OS verified boot block Properties / Entry arguments: @@ -37,9 +38,6 @@ class Entry_vblock(Entry): """ def __init__(self, section, etype, node): super().__init__(section, etype, node) - self.content = fdt_util.GetPhandleList(self._node, 'content') - if not self.content: - self.Raise("Vblock must have a 'content' property") (self.keydir, self.keyblock, self.signprivate, self.version, self.kernelkey, self.preamble_flags) = self.GetEntryArgsOrProps([ EntryArg('keydir', str), @@ -50,14 +48,16 @@ class Entry_vblock(Entry): EntryArg('preamble-flags', int)]) def GetVblock(self): + """Get the contents of this entry + + Returns: + bytes content of the entry, which is the signed vblock for the + provided data + """ # Join up the data files to be signed - input_data = b'' - for entry_phandle in self.content: - data = self.section.GetContentsByPhandle(entry_phandle, self) - if data is None: - # Data not available yet - return False - input_data += data + input_data = self.GetContents() + if input_data is None: + return None uniq = self.GetUniqueName() output_fname = tools.GetOutputFilename('vblock.%s' % uniq) @@ -80,7 +80,7 @@ class Entry_vblock(Entry): def ObtainContents(self): data = self.GetVblock() - if data is False: + if data is None: return False self.SetContents(data) return True diff --git a/tools/binman/ftest.py b/tools/binman/ftest.py index cd93dc153a..fdd4f4d2fa 100644 --- a/tools/binman/ftest.py +++ b/tools/binman/ftest.py @@ -1718,7 +1718,7 @@ class TestFunctional(unittest.TestCase): """Test we detect a vblock which has no content to sign""" with self.assertRaises(ValueError) as e: self._DoReadFile('075_vblock_no_content.dts') - self.assertIn("Node '/binman/vblock': Vblock must have a 'content' " + self.assertIn("Node '/binman/vblock': Collection must have a 'content' " 'property', str(e.exception)) def testVblockBadPhandle(self): @@ -4476,5 +4476,13 @@ class TestFunctional(unittest.TestCase): U_BOOT_SPL_DTB_DATA, 0x38, entry_args=entry_args, use_expanded=True) + def testCollection(self): + """Test a collection""" + data = self._DoReadFile('198_collection.dts') + self.assertEqual(U_BOOT_NODTB_DATA + U_BOOT_DTB_DATA + + tools.GetBytes(0xff, 2) + U_BOOT_NODTB_DATA + + tools.GetBytes(0xfe, 3) + U_BOOT_DTB_DATA, + data) + if __name__ == "__main__": unittest.main() diff --git a/tools/binman/test/198_collection.dts b/tools/binman/test/198_collection.dts new file mode 100644 index 0000000000..484a1b0050 --- /dev/null +++ b/tools/binman/test/198_collection.dts @@ -0,0 +1,27 @@ +// SPDX-License-Identifier: GPL-2.0+ + +/dts-v1/; + +/ { + #address-cells = <1>; + #size-cells = <1>; + + binman { + collection { + content = <&u_boot_nodtb &dtb>; + }; + fill { + size = <2>; + fill-byte = [ff]; + }; + u_boot_nodtb: u-boot-nodtb { + }; + fill2 { + type = "fill"; + size = <3>; + fill-byte = [fe]; + }; + dtb: u-boot-dtb { + }; + }; +}; -- 2.39.5