From ba64a0bbb7b7128479a97fdf58baa9ddfbfe4db6 Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Fri, 14 Sep 2018 04:57:29 -0600 Subject: [PATCH] binman: Support expanding entries It is useful to have entries which can grow automatically to fill available space. Add support for this. Signed-off-by: Simon Glass --- tools/binman/README | 4 +++ tools/binman/bsection.py | 22 +++++++++++++++- tools/binman/entry.py | 11 ++++++++ tools/binman/etype/_testing.py | 7 +++++- tools/binman/etype/section.py | 8 ++++++ tools/binman/ftest.py | 29 +++++++++++++++++++++ tools/binman/test/88_expand_size.dts | 43 ++++++++++++++++++++++++++++++++ tools/binman/test/89_expand_size_bad.dts | 14 +++++++++++ 8 files changed, 136 insertions(+), 2 deletions(-) create mode 100644 tools/binman/test/88_expand_size.dts create mode 100644 tools/binman/test/89_expand_size_bad.dts diff --git a/tools/binman/README b/tools/binman/README index d687194..6aa5b38 100644 --- a/tools/binman/README +++ b/tools/binman/README @@ -330,6 +330,10 @@ image-pos: for each entry. This makes it easy to find out exactly where the entry ended up in the image, regardless of parent sections, etc. +expand-size: + Expand the size of this entry to fit available space. This space is only + limited by the size of the image/section and the position of the next + entry. The attributes supported for images are described below. Several are similar to those for entries. diff --git a/tools/binman/bsection.py b/tools/binman/bsection.py index 4bf2068..52ac31a 100644 --- a/tools/binman/bsection.py +++ b/tools/binman/bsection.py @@ -253,10 +253,26 @@ class Section(object): for entry in entries: self._entries[entry._node.name] = entry + def _ExpandEntries(self): + """Expand any entries that are permitted to""" + exp_entry = None + for entry in self._entries.values(): + if exp_entry: + exp_entry.ExpandToLimit(entry.offset) + exp_entry = None + if entry.expand_size: + exp_entry = entry + if exp_entry: + exp_entry.ExpandToLimit(self._size) + def CheckEntries(self): - """Check that entries do not overlap or extend outside the section""" + """Check that entries do not overlap or extend outside the section + + This also sorts entries, if needed and expands + """ if self._sort: self._SortEntries() + self._ExpandEntries() offset = 0 prev_name = 'None' for entry in self._entries.values(): @@ -419,3 +435,7 @@ class Section(object): return None return entry.data source_entry.Raise("Cannot find entry for node '%s'" % node.name) + + def ExpandSize(self, size): + if size != self._size: + self._size = size diff --git a/tools/binman/entry.py b/tools/binman/entry.py index 7316ad4..0915b47 100644 --- a/tools/binman/entry.py +++ b/tools/binman/entry.py @@ -76,6 +76,7 @@ class Entry(object): self.pad_after = 0 self.offset_unset = False self.image_pos = None + self._expand_size = False if read_node: self.ReadNode() @@ -161,6 +162,7 @@ class Entry(object): "of two" % (self._node.path, self.align_size)) self.align_end = fdt_util.GetInt(self._node, 'align-end') self.offset_unset = fdt_util.GetBool(self._node, 'offset-unset') + self.expand_size = fdt_util.GetBool(self._node, 'expand-size') def GetDefaultFilename(self): return None @@ -507,3 +509,12 @@ features to produce new behaviours. break name = '%s.%s' % (node.name, name) return name + + def ExpandToLimit(self, limit): + """Expand an entry so that it ends at the given offset limit""" + if self.offset + self.size < limit: + self.size = limit - self.offset + # Request the contents again, since changing the size requires that + # the data grows. This should not fail, but check it to be sure. + if not self.ObtainContents(): + self.Raise('Cannot obtain contents when expanding entry') diff --git a/tools/binman/etype/_testing.py b/tools/binman/etype/_testing.py index 02c165c..3e345bd 100644 --- a/tools/binman/etype/_testing.py +++ b/tools/binman/etype/_testing.py @@ -48,6 +48,8 @@ class Entry__testing(Entry): 'return-unknown-contents') self.bad_update_contents = fdt_util.GetBool(self._node, 'bad-update-contents') + self.return_contents_once = fdt_util.GetBool(self._node, + 'return-contents-once') # Set to True when the entry is ready to process the FDT. self.process_fdt_ready = False @@ -68,12 +70,15 @@ class Entry__testing(Entry): EntryArg('test-existing-prop', str)], self.require_args) if self.force_bad_datatype: self.GetEntryArgsOrProps([EntryArg('test-bad-datatype-arg', bool)]) + self.return_contents = True def ObtainContents(self): - if self.return_unknown_contents: + if self.return_unknown_contents or not self.return_contents: return False self.data = 'a' self.contents_size = len(self.data) + if self.return_contents_once: + self.return_contents = False return True def GetOffsets(self): diff --git a/tools/binman/etype/section.py b/tools/binman/etype/section.py index a30cc91..005a9f9 100644 --- a/tools/binman/etype/section.py +++ b/tools/binman/etype/section.py @@ -40,6 +40,10 @@ class Entry_section(Entry): def ProcessFdt(self, fdt): return self._section.ProcessFdt(fdt) + def ExpandEntries(self): + Entry.ExpandEntries(self) + self._section.ExpandEntries() + def AddMissingProperties(self): Entry.AddMissingProperties(self) self._section.AddMissingProperties() @@ -95,3 +99,7 @@ class Entry_section(Entry): def GetEntries(self): return self._section.GetEntries() + + def ExpandToLimit(self, limit): + super(Entry_section, self).ExpandToLimit(limit) + self._section.ExpandSize(self.size) diff --git a/tools/binman/ftest.py b/tools/binman/ftest.py index e919e70..b156943 100644 --- a/tools/binman/ftest.py +++ b/tools/binman/ftest.py @@ -1579,6 +1579,35 @@ class TestFunctional(unittest.TestCase): self.assertIn("Node '/binman/files': Missing 'pattern' property", str(e.exception)) + def testExpandSize(self): + """Test an expanding entry""" + data, _, map_data, _ = self._DoReadFileDtb('88_expand_size.dts', + map=True) + expect = ('a' * 8 + U_BOOT_DATA + + MRC_DATA + 'b' * 1 + U_BOOT_DATA + + 'c' * 8 + U_BOOT_DATA + + 'd' * 8) + self.assertEqual(expect, data) + self.assertEqual('''ImagePos Offset Size Name +00000000 00000000 00000028 main-section +00000000 00000000 00000008 fill +00000008 00000008 00000004 u-boot +0000000c 0000000c 00000004 section +0000000c 00000000 00000003 intel-mrc +00000010 00000010 00000004 u-boot2 +00000014 00000014 0000000c section2 +00000014 00000000 00000008 fill +0000001c 00000008 00000004 u-boot +00000020 00000020 00000008 fill2 +''', map_data) + + def testExpandSizeBad(self): + """Test an expanding entry which fails to provide contents""" + with self.assertRaises(ValueError) as e: + self._DoReadFileDtb('89_expand_size_bad.dts', map=True) + self.assertIn("Node '/binman/_testing': Cannot obtain contents when " + 'expanding entry', str(e.exception)) + if __name__ == "__main__": unittest.main() diff --git a/tools/binman/test/88_expand_size.dts b/tools/binman/test/88_expand_size.dts new file mode 100644 index 0000000..c8a0130 --- /dev/null +++ b/tools/binman/test/88_expand_size.dts @@ -0,0 +1,43 @@ +// SPDX-License-Identifier: GPL-2.0+ +/dts-v1/; + +/ { + binman { + size = <40>; + fill { + expand-size; + fill-byte = [61]; + size = <0>; + }; + u-boot { + offset = <8>; + }; + section { + expand-size; + pad-byte = <0x62>; + intel-mrc { + }; + }; + u-boot2 { + type = "u-boot"; + offset = <16>; + }; + section2 { + type = "section"; + fill { + expand-size; + fill-byte = [63]; + size = <0>; + }; + u-boot { + offset = <8>; + }; + }; + fill2 { + type = "fill"; + expand-size; + fill-byte = [64]; + size = <0>; + }; + }; +}; diff --git a/tools/binman/test/89_expand_size_bad.dts b/tools/binman/test/89_expand_size_bad.dts new file mode 100644 index 0000000..edc0e5c --- /dev/null +++ b/tools/binman/test/89_expand_size_bad.dts @@ -0,0 +1,14 @@ +// SPDX-License-Identifier: GPL-2.0+ +/dts-v1/; + +/ { + binman { + _testing { + expand-size; + return-contents-once; + }; + u-boot { + offset = <8>; + }; + }; +};