]> git.dujemihanovic.xyz Git - u-boot.git/commitdiff
binman: Support overlapping entries
authorSimon Glass <sjg@chromium.org>
Wed, 11 Jan 2023 23:10:16 +0000 (16:10 -0700)
committerSimon Glass <sjg@chromium.org>
Wed, 18 Jan 2023 21:55:41 +0000 (14:55 -0700)
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@chromium.org>
tools/binman/binman.rst
tools/binman/entry.py
tools/binman/etype/section.py
tools/binman/ftest.py
tools/binman/test/269_overlap.dts [new file with mode: 0644]
tools/binman/test/270_overlap_null.dts [new file with mode: 0644]
tools/binman/test/271_overlap_bad.dts [new file with mode: 0644]
tools/binman/test/272_overlap_no_size.dts [new file with mode: 0644]

index bfe300a39c19215ecc73259530d9ceda4c5071c9..97e2d4e55d556357acafe585874a857de4a444bc 100644 (file)
@@ -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
index e6ff026ddb84a74c8ec9c010ebd3236d545996f9..0c94665f7a8c9fbc0ac7663f203bd6a441ee10b9 100644 (file)
@@ -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')
index a22be7ec774109230e073e382b6d6311e6ae934d..57b91ff726c0eba0cb5e90f4e135eb48fe87173a 100644 (file)
@@ -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"""
index ac9b050fb6caa474fa3c2384fd2e749952ba4aa1..aea8a5f758925d8cb199e02af11a9a72dff2ce1b 100644 (file)
@@ -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 (file)
index 0000000..f949b8b
--- /dev/null
@@ -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 (file)
index 0000000..feed9ec
--- /dev/null
@@ -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 (file)
index 0000000..f281802
--- /dev/null
@@ -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 (file)
index 0000000..4517536
--- /dev/null
@@ -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;
+               };
+       };
+};