From 9766f69c98c2aa056d0518a9545f9e89484e9172 Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Wed, 11 Jan 2023 16:10:16 -0700 Subject: [PATCH] binman: Support overlapping entries In some cases it is useful to have an entry overlap with another in a section, either to update the contents within a blob, or to add an entry to the fdtmap that covers only part of the blob. Add support for this. Signed-off-by: Simon Glass --- tools/binman/binman.rst | 9 +++- tools/binman/entry.py | 5 ++ tools/binman/etype/section.py | 31 +++++++---- tools/binman/ftest.py | 63 +++++++++++++++++++++++ tools/binman/test/269_overlap.dts | 21 ++++++++ tools/binman/test/270_overlap_null.dts | 24 +++++++++ tools/binman/test/271_overlap_bad.dts | 21 ++++++++ tools/binman/test/272_overlap_no_size.dts | 19 +++++++ 8 files changed, 183 insertions(+), 10 deletions(-) create mode 100644 tools/binman/test/269_overlap.dts create mode 100644 tools/binman/test/270_overlap_null.dts create mode 100644 tools/binman/test/271_overlap_bad.dts create mode 100644 tools/binman/test/272_overlap_no_size.dts diff --git a/tools/binman/binman.rst b/tools/binman/binman.rst index bfe300a39c..97e2d4e55d 100644 --- a/tools/binman/binman.rst +++ b/tools/binman/binman.rst @@ -792,6 +792,12 @@ align-default: symlink: Adds a symlink to the image with string given in the symlink property. +overlap: + Indicates that this entry overlaps with others in the same section. These + entries should appear at the end of the section. Overlapping entries are not + packed with other entries, but their contents are written over other entries + in the section. Overlapping entries must have an explicit offset and size. + Examples of the above options can be found in the tests. See the tools/binman/test directory. @@ -1720,7 +1726,8 @@ implementation of Pack() is usually sufficient. Note: for sections, this also checks that the entries do not overlap, nor extend outside the section. If the section does not have a defined size, the size is -set large enough to hold all the entries. +set large enough to hold all the entries. For entries that are explicitly marked +as overlapping, this check is skipped. 6. SetImagePos() - sets the image position of every entry. This is the absolute position 'image-pos', as opposed to 'offset' which is relative to the containing diff --git a/tools/binman/entry.py b/tools/binman/entry.py index e6ff026ddb..0c94665f7a 100644 --- a/tools/binman/entry.py +++ b/tools/binman/entry.py @@ -98,6 +98,7 @@ class Entry(object): An absent entry is removed during processing so that it does not appear in the map optional (bool): True if this entry contains an optional external blob + overlap (bool): True if this entry overlaps with others """ fake_dir = None @@ -142,6 +143,7 @@ class Entry(object): self.auto_write_symbols = auto_write_symbols self.absent = False self.optional = False + self.overlap = False @staticmethod def FindEntryClass(etype, expanded): @@ -294,6 +296,9 @@ class Entry(object): self.extend_size = fdt_util.GetBool(self._node, 'extend-size') self.missing_msg = fdt_util.GetString(self._node, 'missing-msg') self.optional = fdt_util.GetBool(self._node, 'optional') + self.overlap = fdt_util.GetBool(self._node, 'overlap') + if self.overlap: + self.required_props += ['offset', 'size'] # This is only supported by blobs and sections at present self.compress = fdt_util.GetString(self._node, 'compress', 'none') diff --git a/tools/binman/etype/section.py b/tools/binman/etype/section.py index a22be7ec77..57b91ff726 100644 --- a/tools/binman/etype/section.py +++ b/tools/binman/etype/section.py @@ -332,19 +332,31 @@ class Entry_section(Entry): if not required and entry_data is None: return None + entry_data_final = entry_data if entry_data is None: pad_byte = (entry._pad_byte if isinstance(entry, Entry_section) else self._pad_byte) - entry_data = tools.get_bytes(self._pad_byte, entry.size) + entry_data_final = tools.get_bytes(self._pad_byte, entry.size) - data = self.GetPaddedDataForEntry(entry, entry_data) + data = self.GetPaddedDataForEntry(entry, entry_data_final) # Handle empty space before the entry pad = (entry.offset or 0) - self._skip_at_start - len(section_data) if pad > 0: section_data += tools.get_bytes(self._pad_byte, pad) # Add in the actual entry data - section_data += data + if entry.overlap: + end_offset = entry.offset + entry.size + if end_offset > len(section_data): + entry.Raise("Offset %#x (%d) ending at %#x (%d) must overlap with existing entries" % + (entry.offset, entry.offset, end_offset, + end_offset)) + # Don't write anything for null entries' + if entry_data is not None: + section_data = (section_data[:entry.offset] + data + + section_data[entry.offset + entry.size:]) + else: + section_data += data self.Detail('GetData: %d entries, total size %#x' % (len(self._entries), len(section_data))) @@ -467,12 +479,13 @@ class Entry_section(Entry): (entry.offset, entry.offset, entry.size, entry.size, self._node.path, self._skip_at_start, self._skip_at_start, max_size, max_size)) - if entry.offset < offset and entry.size: - entry.Raise("Offset %#x (%d) overlaps with previous entry '%s' " - "ending at %#x (%d)" % - (entry.offset, entry.offset, prev_name, offset, offset)) - offset = entry.offset + entry.size - prev_name = entry.GetPath() + if not entry.overlap: + if entry.offset < offset and entry.size: + entry.Raise("Offset %#x (%d) overlaps with previous entry '%s' ending at %#x (%d)" % + (entry.offset, entry.offset, prev_name, offset, + offset)) + offset = entry.offset + entry.size + prev_name = entry.GetPath() def WriteSymbols(self, section): """Write symbol values into binary files for access at run time""" diff --git a/tools/binman/ftest.py b/tools/binman/ftest.py index ac9b050fb6..aea8a5f758 100644 --- a/tools/binman/ftest.py +++ b/tools/binman/ftest.py @@ -6199,6 +6199,69 @@ fdt fdtmap Extract the devicetree blob from the fdtmap data = self._DoReadFile('268_null.dts') self.assertEqual(U_BOOT_DATA + b'\xff\xff\xff\xff' + U_BOOT_IMG_DATA, data) + def testOverlap(self): + """Test an image with a overlapping entry""" + data = self._DoReadFile('269_overlap.dts') + self.assertEqual(U_BOOT_DATA[:1] + b'aa' + U_BOOT_DATA[3:], data) + + image = control.images['image'] + entries = image.GetEntries() + + self.assertIn('inset', entries) + inset = entries['inset'] + self.assertEqual(1, inset.offset); + self.assertEqual(1, inset.image_pos); + self.assertEqual(2, inset.size); + + def testOverlapNull(self): + """Test an image with a null overlap""" + data = self._DoReadFile('270_overlap_null.dts') + self.assertEqual(U_BOOT_DATA, data[:len(U_BOOT_DATA)]) + + # Check the FMAP + fhdr, fentries = fmap_util.DecodeFmap(data[len(U_BOOT_DATA):]) + self.assertEqual(4, fhdr.nareas) + fiter = iter(fentries) + + fentry = next(fiter) + self.assertEqual(b'SECTION', fentry.name) + self.assertEqual(0, fentry.offset) + self.assertEqual(len(U_BOOT_DATA), fentry.size) + self.assertEqual(0, fentry.flags) + + fentry = next(fiter) + self.assertEqual(b'U_BOOT', fentry.name) + self.assertEqual(0, fentry.offset) + self.assertEqual(len(U_BOOT_DATA), fentry.size) + self.assertEqual(0, fentry.flags) + + # Make sure that the NULL entry appears in the FMAP + fentry = next(fiter) + self.assertEqual(b'NULL', fentry.name) + self.assertEqual(1, fentry.offset) + self.assertEqual(2, fentry.size) + self.assertEqual(0, fentry.flags) + + fentry = next(fiter) + self.assertEqual(b'FMAP', fentry.name) + self.assertEqual(len(U_BOOT_DATA), fentry.offset) + + def testOverlapBad(self): + """Test an image with a bad overlapping entry""" + with self.assertRaises(ValueError) as exc: + self._DoReadFile('271_overlap_bad.dts') + self.assertIn( + "Node '/binman/inset': Offset 0x10 (16) ending at 0x12 (18) must overlap with existing entries", + str(exc.exception)) + + def testOverlapNoOffset(self): + """Test an image with a bad overlapping entry""" + with self.assertRaises(ValueError) as exc: + self._DoReadFile('272_overlap_no_size.dts') + self.assertIn( + "Node '/binman/inset': 'fill' entry is missing properties: size", + str(exc.exception)) + if __name__ == "__main__": unittest.main() diff --git a/tools/binman/test/269_overlap.dts b/tools/binman/test/269_overlap.dts new file mode 100644 index 0000000000..f949b8b359 --- /dev/null +++ b/tools/binman/test/269_overlap.dts @@ -0,0 +1,21 @@ +// SPDX-License-Identifier: GPL-2.0+ + +/dts-v1/; + +/ { + #address-cells = <1>; + #size-cells = <1>; + + binman { + u-boot { + }; + + inset { + type = "fill"; + fill-byte = [61]; + offset = <1>; + size = <2>; + overlap; + }; + }; +}; diff --git a/tools/binman/test/270_overlap_null.dts b/tools/binman/test/270_overlap_null.dts new file mode 100644 index 0000000000..feed9ec892 --- /dev/null +++ b/tools/binman/test/270_overlap_null.dts @@ -0,0 +1,24 @@ +// SPDX-License-Identifier: GPL-2.0+ + +/dts-v1/; + +/ { + #address-cells = <1>; + #size-cells = <1>; + + binman { + section { + u-boot { + }; + + null { + offset = <1>; + size = <2>; + overlap; + }; + }; + + fmap { + }; + }; +}; diff --git a/tools/binman/test/271_overlap_bad.dts b/tools/binman/test/271_overlap_bad.dts new file mode 100644 index 0000000000..f281802114 --- /dev/null +++ b/tools/binman/test/271_overlap_bad.dts @@ -0,0 +1,21 @@ +// SPDX-License-Identifier: GPL-2.0+ + +/dts-v1/; + +/ { + #address-cells = <1>; + #size-cells = <1>; + + binman { + u-boot { + }; + + inset { + type = "fill"; + fill-byte = [61]; + offset = <0x10>; + size = <2>; + overlap; + }; + }; +}; diff --git a/tools/binman/test/272_overlap_no_size.dts b/tools/binman/test/272_overlap_no_size.dts new file mode 100644 index 0000000000..4517536f2e --- /dev/null +++ b/tools/binman/test/272_overlap_no_size.dts @@ -0,0 +1,19 @@ +// SPDX-License-Identifier: GPL-2.0+ + +/dts-v1/; + +/ { + #address-cells = <1>; + #size-cells = <1>; + + binman { + u-boot { + }; + + inset { + type = "fill"; + fill-byte = [61]; + overlap; + }; + }; +}; -- 2.39.5