binman: Add a new 'image-pos' property

At present each entry has an offset within its parent section. This is
useful for figuring out how entries relate to one another. However it
is sometimes necessary to locate an entry within an image, regardless
of which sections it is nested inside.

Add a new 'image-pos' property to provide this information. Also add
some documentation for the -u option binman provides, which updates the
device tree with final entry information.

Since the image position is a better symbol to use for the position of
U-Boot as obtained by SPL, update the SPL symbols to use this instead of
offset, which might be incorrect if hierarchical sections are used.

Signed-off-by: Simon Glass <sjg@chromium.org>
diff --git a/tools/binman/README b/tools/binman/README
index 4b13776..df88819 100644
--- a/tools/binman/README
+++ b/tools/binman/README
@@ -324,6 +324,12 @@
 	property is present, binman will give an error if another entry does
 	not set the offset (with the GetOffsets() method).
 
+image-pos:
+	This cannot be set on entry (or at least it is ignored if it is), but
+	with the -u option, binman will set it to the absolute image position
+	for each entry. This makes it easy to find out exactly where the entry
+	ended up in the image, regardless of parent sections, etc.
+
 
 The attributes supported for images are described below. Several are similar
 to those for entries.
@@ -550,8 +556,8 @@
    # u_boot_dtsi_options_debug = $(u_boot_dtsi_options_raw)
 
 
-Access to binman entry offsets at run time
-------------------------------------------
+Access to binman entry offsets at run time (symbols)
+----------------------------------------------------
 
 Binman assembles images and determines where each entry is placed in the image.
 This information may be useful to U-Boot at run time. For example, in SPL it
@@ -577,6 +583,18 @@
 to fill in such symbols in U-Boot proper, as well.
 
 
+Access to binman entry offsets at run time (fdt)
+------------------------------------------------
+
+Binman can update the U-Boot FDT to include the final position and size of
+each entry in the images it processes. The option to enable this is -u and it
+causes binman to make sure that the 'offset', 'image-pos' and 'size' properties
+are set correctly for every entry. Since it is not necessary to specify these in
+the image definition, binman calculates the final values and writes these to
+the device tree. These can be used by U-Boot at run-time to find the location
+of each entry.
+
+
 Map files
 ---------
 
diff --git a/tools/binman/bsection.py b/tools/binman/bsection.py
index 1604b99..08c6f0c 100644
--- a/tools/binman/bsection.py
+++ b/tools/binman/bsection.py
@@ -96,7 +96,7 @@
 
     def AddMissingProperties(self):
         """Add new properties to the device tree as needed for this entry"""
-        for prop in ['offset', 'size']:
+        for prop in ['offset', 'size', 'image-pos']:
             if not prop in self._node.props:
                 self._node.AddZeroProp(prop)
         for entry in self._entries.values():
@@ -105,6 +105,7 @@
     def SetCalculatedProperties(self):
         self._node.SetInt('offset', self._offset)
         self._node.SetInt('size', self._size)
+        self._node.SetInt('image-pos', self._image_pos)
         for entry in self._entries.values():
             entry.SetCalculatedProperties()
 
@@ -260,6 +261,11 @@
             offset = entry.offset + entry.size
             prev_name = entry.GetPath()
 
+    def SetImagePos(self, image_pos):
+        self._image_pos = image_pos
+        for entry in self._entries.values():
+            entry.SetImagePos(image_pos)
+
     def ProcessEntryContents(self):
         """Call the ProcessContents() method for each entry
 
@@ -341,6 +347,8 @@
             raise ValueError(err)
         if prop_name == 'offset':
             return entry.offset
+        elif prop_name == 'image_pos':
+            return entry.image_pos
         else:
             raise ValueError("%s: No such property '%s'" % (msg, prop_name))
 
diff --git a/tools/binman/control.py b/tools/binman/control.py
index 17c6d7a..9ac392b 100644
--- a/tools/binman/control.py
+++ b/tools/binman/control.py
@@ -161,6 +161,7 @@
                 image.PackEntries()
                 image.CheckSize()
                 image.CheckEntries()
+                image.SetImagePos()
                 if options.update_fdt:
                     image.SetCalculatedProperties()
                 image.ProcessEntryContents()
diff --git a/tools/binman/entry.py b/tools/binman/entry.py
index cb693c9..8004918 100644
--- a/tools/binman/entry.py
+++ b/tools/binman/entry.py
@@ -64,6 +64,7 @@
         self.pad_before = 0
         self.pad_after = 0
         self.offset_unset = False
+        self.image_pos = None
         if read_node:
             self.ReadNode()
 
@@ -133,7 +134,7 @@
 
     def AddMissingProperties(self):
         """Add new properties to the device tree as needed for this entry"""
-        for prop in ['offset', 'size']:
+        for prop in ['offset', 'size', 'image-pos']:
             if not prop in self._node.props:
                 self._node.AddZeroProp(prop)
 
@@ -141,6 +142,7 @@
         """Set the value of device-tree properties calculated by binman"""
         self._node.SetInt('offset', self.offset)
         self._node.SetInt('size', self.size)
+        self._node.SetInt('image-pos', self.image_pos)
 
     def ProcessFdt(self, fdt):
         return True
@@ -265,6 +267,14 @@
         self.offset = pos
         self.size = size
 
+    def SetImagePos(self, image_pos):
+        """Set the position in the image
+
+        Args:
+            image_pos: Position of this entry in the image
+        """
+        self.image_pos = image_pos + self.offset
+
     def ProcessContents(self):
         pass
 
diff --git a/tools/binman/etype/section.py b/tools/binman/etype/section.py
index 1d27301..b90b80e 100644
--- a/tools/binman/etype/section.py
+++ b/tools/binman/etype/section.py
@@ -46,6 +46,10 @@
         self.size = self._section.GetSize()
         return super(Entry_section, self).Pack(offset)
 
+    def SetImagePos(self, image_pos):
+        Entry.SetImagePos(self, image_pos)
+        self._section.SetImagePos(image_pos + self.offset)
+
     def WriteSymbols(self, section):
         """Write symbol values into binary files for access at run time"""
         self._section.WriteSymbols()
diff --git a/tools/binman/ftest.py b/tools/binman/ftest.py
index 94e48f3..94a50aa 100644
--- a/tools/binman/ftest.py
+++ b/tools/binman/ftest.py
@@ -1051,23 +1051,30 @@
         """Test that we can update the device tree with offset/size info"""
         _, _, _, out_dtb_fname = self._DoReadFileDtb('60_fdt_update.dts',
                                                      update_dtb=True)
-        props = self._GetPropTree(out_dtb_fname, ['offset', 'size'])
+        props = self._GetPropTree(out_dtb_fname, ['offset', 'size',
+                                                  'image-pos'])
         with open('/tmp/x.dtb', 'wb') as outf:
             with open(out_dtb_fname) as inf:
                 outf.write(inf.read())
         self.assertEqual({
+            'image-pos': 0,
             'offset': 0,
             '_testing:offset': 32,
             '_testing:size': 1,
+            '_testing:image-pos': 32,
             'section@0/u-boot:offset': 0,
             'section@0/u-boot:size': len(U_BOOT_DATA),
+            'section@0/u-boot:image-pos': 0,
             'section@0:offset': 0,
             'section@0:size': 16,
+            'section@0:image-pos': 0,
 
             'section@1/u-boot:offset': 0,
             'section@1/u-boot:size': len(U_BOOT_DATA),
+            'section@1/u-boot:image-pos': 16,
             'section@1:offset': 16,
             'section@1:size': 16,
+            'section@1:image-pos': 16,
             'size': 40
         }, props)
 
diff --git a/tools/binman/image.py b/tools/binman/image.py
index ed8261a..4debc73 100644
--- a/tools/binman/image.py
+++ b/tools/binman/image.py
@@ -96,6 +96,9 @@
     def SetCalculatedProperties(self):
         self._section.SetCalculatedProperties()
 
+    def SetImagePos(self):
+        self._section.SetImagePos(0)
+
     def ProcessEntryContents(self):
         """Call the ProcessContents() method for each entry
 
diff --git a/tools/binman/test/u_boot_binman_syms b/tools/binman/test/u_boot_binman_syms
index f2dcb88..126a1a6 100755
--- a/tools/binman/test/u_boot_binman_syms
+++ b/tools/binman/test/u_boot_binman_syms
Binary files differ
diff --git a/tools/binman/test/u_boot_binman_syms.c b/tools/binman/test/u_boot_binman_syms.c
index cbb2f3f..4898f98 100644
--- a/tools/binman/test/u_boot_binman_syms.c
+++ b/tools/binman/test/u_boot_binman_syms.c
@@ -10,4 +10,4 @@
 
 binman_sym_declare(unsigned long, u_boot_spl, offset);
 binman_sym_declare(unsigned long long, u_boot_spl2, offset);
-binman_sym_declare(unsigned long, u_boot_any, offset);
+binman_sym_declare(unsigned long, u_boot_any, image_pos);