[PATCH 5/8] binman: Support overlapping entries

Simon Glass sjg at chromium.org
Thu Jan 12 00:10:16 CET 2023


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 <sjg at chromium.org>
---

 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 bfe300a39c1..97e2d4e55d5 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 e6ff026ddb8..0c94665f7a8 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 a22be7ec774..57b91ff726c 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 ac9b050fb6c..aea8a5f7589 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 00000000000..f949b8b359f
--- /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 00000000000..feed9ec8920
--- /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 00000000000..f2818021144
--- /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 00000000000..4517536f2e6
--- /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.0.314.g84b9a713c41-goog



More information about the U-Boot mailing list