[U-Boot,06/12] binman: Add support for sections

Message ID 20180516015258.187295-7-sjg@chromium.org
State Superseded
Delegated to: Simon Glass
Headers show
Series
  • binman: A few more features
Related show

Commit Message

Simon Glass May 16, 2018, 1:52 a.m.
It is useful to be able to split an image into multiple sections,
each with its own size and position, for cases where a flash device has
read-only and read-write portions.

Add support for this.

Signed-off-by: Simon Glass <sjg@chromium.org>
---

 tools/binman/README               | 41 +++++++++++++++++++++++--
 tools/binman/bsection.py          |  1 +
 tools/binman/entry.py             |  9 ++++++
 tools/binman/etype/section.py     | 51 +++++++++++++++++++++++++++++++
 tools/binman/ftest.py             |  5 +++
 tools/binman/test/55_sections.dts | 26 ++++++++++++++++
 6 files changed, 131 insertions(+), 2 deletions(-)
 create mode 100644 tools/binman/etype/section.py
 create mode 100644 tools/binman/test/55_sections.dts

Patch

diff --git a/tools/binman/README b/tools/binman/README
index 196dda1fb4c..5ef1246f296 100644
--- a/tools/binman/README
+++ b/tools/binman/README
@@ -392,6 +392,45 @@  either by using a unit number suffix (u-boot@0, u-boot@1) or by using a
 different name for each and specifying the type with the 'type' attribute.
 
 
+Sections and hiearchical images
+-------------------------------
+
+Sometimes it is convenient to split an image into several pieces, each of which
+contains its own set of binaries. An example is a flash device where part of
+the image is read-only and part is read-write. We can set up sections for each
+of these, and place binaries in them independently. The image is still produced
+as a single output file.
+
+This feature provides a way of creating hierarchical images. For example here
+is an example with two copies of U-Boot. One is read-only (ro), intended to be
+written only in the factory. Another is read-write (rw), so that it can be
+upgraded in the field. The sizes are fixed so that the ro/rw boundary is known
+and can be programmed:
+
+	binman {
+		section@0 {
+			read-only;
+			size = <0x100000>;
+			u-boot {
+			};
+		};
+		section@1 {
+			size = <0x100000>;
+			u-boot {
+			};
+		};
+	};
+
+This image could be placed into a SPI flash chip, with the protection boundary
+set at 1MB.
+
+A few special properties are provided for sections:
+
+read-only:
+	Indicates that this section is read-only. This has no impact on binman's
+	operation, but his property can be read at run time.
+
+
 Special properties
 ------------------
 
@@ -586,8 +625,6 @@  Some ideas:
 - Allow easy building of images by specifying just the board name
 - Produce a full Python binding for libfdt (for upstream)
 - Add an option to decode an image into the constituent binaries
-- Suppoort hierarchical images (packing of binaries into another binary
-  which is then placed in the image)
 - Support building an image for a board (-b) more completely, with a
   configurable build directory
 - Consider making binman work with buildman, although if it is used in the
diff --git a/tools/binman/bsection.py b/tools/binman/bsection.py
index 70da2c9ef50..9333932d41e 100644
--- a/tools/binman/bsection.py
+++ b/tools/binman/bsection.py
@@ -201,6 +201,7 @@  class Section(object):
         pos = 0
         prev_name = 'None'
         for entry in self._entries.values():
+            entry.CheckPosition()
             if (entry.pos < self._skip_at_start or
                 entry.pos >= self._skip_at_start + self._size):
                 entry.Raise("Position %#x (%d) is outside the section starting "
diff --git a/tools/binman/entry.py b/tools/binman/entry.py
index 5374178542e..8b46fbb5fa6 100644
--- a/tools/binman/entry.py
+++ b/tools/binman/entry.py
@@ -220,3 +220,12 @@  class Entry(object):
           section: Section containing the entry
         """
         pass
+
+    def CheckPosition(self):
+        """Check that the entry positions are correct
+
+        This is used for entries which have extra position requirements (other
+        than having to be fully inside their section). Sub-classes can implement
+        this function and raise if there is a problem.
+        """
+        pass
diff --git a/tools/binman/etype/section.py b/tools/binman/etype/section.py
new file mode 100644
index 00000000000..7437f91567d
--- /dev/null
+++ b/tools/binman/etype/section.py
@@ -0,0 +1,51 @@ 
+# Copyright (c) 2018 Google, Inc
+# Written by Simon Glass <sjg@chromium.org>
+#
+# SPDX-License-Identifier:      GPL-2.0+
+#
+# Entry-type module for sections, which are entries which can contain other
+# entries.
+#
+
+from entry import Entry
+import fdt_util
+import tools
+
+import bsection
+
+class Entry_section(Entry):
+    def __init__(self, image, etype, node):
+        Entry.__init__(self, image, etype, node)
+        self._section = bsection.Section(node.name, node)
+
+    def ObtainContents(self):
+        self._section.GetEntryContents()
+
+    def GetData(self):
+        return self._section.GetData()
+
+    def GetPositions(self):
+        """Handle entries that want to set the position/size of other entries
+
+        This calls each entry's GetPositions() method. If it returns a list
+        of entries to update, it updates them.
+        """
+        self._section.GetEntryPositions()
+        return {}
+
+    def Pack(self, pos):
+        """Pack all entries into the section"""
+        self._section.PackEntries()
+        self.size = self._section.CheckSize()
+        return super(Entry_section, self).Pack(pos)
+
+    def WriteSymbols(self, section):
+        """Write symbol values into binary files for access at run time"""
+        self._section.WriteSymbols()
+
+    def ProcessContents(self):
+        self._section.ProcessEntryContents()
+        super(Entry_section, self).ProcessContents()
+
+    def CheckPosition(self):
+        self._section.CheckEntries()
diff --git a/tools/binman/ftest.py b/tools/binman/ftest.py
index 96a5535626d..06b8132f01f 100644
--- a/tools/binman/ftest.py
+++ b/tools/binman/ftest.py
@@ -914,6 +914,11 @@  class TestFunctional(unittest.TestCase):
         data = self._DoReadFile('54_unit_address.dts')
         self.assertEqual(U_BOOT_DATA + U_BOOT_DATA, data)
 
+    def testSections(self):
+        """Basic test of sections"""
+        data = self._DoReadFile('55_sections.dts')
+        expected = U_BOOT_DATA + '!' * 12 + U_BOOT_DATA + 'a' * 12 + '&' * 8
+        self.assertEqual(expected, data)
 
 if __name__ == "__main__":
     unittest.main()
diff --git a/tools/binman/test/55_sections.dts b/tools/binman/test/55_sections.dts
new file mode 100644
index 00000000000..04081f78d60
--- /dev/null
+++ b/tools/binman/test/55_sections.dts
@@ -0,0 +1,26 @@ 
+/dts-v1/;
+
+/ {
+	#address-cells = <1>;
+	#size-cells = <1>;
+
+	binman {
+		pad-byte = <0x26>;
+		size = <0x28>;
+		section@0 {
+			read-only;
+			size = <0x10>;
+			pad-byte = <0x21>;
+
+			u-boot {
+			};
+		};
+		section@1 {
+			size = <0x10>;
+			pad-byte = <0x61>;
+
+			u-boot {
+			};
+		};
+	};
+};