[U-Boot] [PATCH 08/31] dtoc: Allow syncing of the device tree back to a file

Simon Glass sjg at chromium.org
Fri Sep 14 10:57:13 UTC 2018


At present we require the caller to manually update the device tree using
individual calls to libfdt functions. This is not ideal. It would be
better if we could make changes using the Python structure and then call a
Sync() function to write them back.

Add this feature to the Fdt class. Update binman and the tests to match.

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

 tools/binman/control.py |  2 +
 tools/dtoc/fdt.py       | 91 +++++++++++++++++++++++++++++++++++++----
 tools/dtoc/test_fdt.py  |  8 +++-
 3 files changed, 91 insertions(+), 10 deletions(-)

diff --git a/tools/binman/control.py b/tools/binman/control.py
index 8c48008fc75..ded1b71109b 100644
--- a/tools/binman/control.py
+++ b/tools/binman/control.py
@@ -183,6 +183,7 @@ def Binman(options, args):
                     image.AddMissingProperties()
                 image.ProcessFdt(dtb)
 
+            dtb.Sync(auto_resize=True)
             dtb.Pack()
             dtb.Flush()
 
@@ -199,6 +200,7 @@ def Binman(options, args):
                 image.SetImagePos()
                 if options.update_fdt:
                     image.SetCalculatedProperties()
+                    dtb.Sync()
                 image.ProcessEntryContents()
                 image.WriteSymbols()
                 image.BuildImage()
diff --git a/tools/dtoc/fdt.py b/tools/dtoc/fdt.py
index 55baa3857f7..76cd66fbf95 100644
--- a/tools/dtoc/fdt.py
+++ b/tools/dtoc/fdt.py
@@ -43,6 +43,7 @@ class Prop:
         self.name = name
         self.value = None
         self.bytes = str(bytes)
+        self.dirty = False
         if not bytes:
             self.type = TYPE_BOOL
             self.value = True
@@ -160,6 +161,45 @@ class Prop:
         self._node._fdt.CheckCache()
         return self._node._fdt.GetStructOffset(self._offset)
 
+    def SetInt(self, val):
+        """Set the integer value of the property
+
+        The device tree is marked dirty so that the value will be written to
+        the block on the next sync.
+
+        Args:
+            val: Integer value (32-bit, single cell)
+        """
+        self.bytes = struct.pack('>I', val);
+        self.value = val
+        self.type = TYPE_INT
+        self.dirty = True
+
+    def Sync(self, auto_resize=False):
+        """Sync property changes back to the device tree
+
+        This updates the device tree blob with any changes to this property
+        since the last sync.
+
+        Args:
+            auto_resize: Resize the device tree automatically if it does not
+                have enough space for the update
+
+        Raises:
+            FdtException if auto_resize is False and there is not enough space
+        """
+        if self._offset is None or self.dirty:
+            node = self._node
+            fdt_obj = node._fdt._fdt_obj
+            if auto_resize:
+                while fdt_obj.setprop(node.Offset(), self.name, self.bytes,
+                                    (libfdt.NOSPACE,)) == -libfdt.NOSPACE:
+                    fdt_obj.resize(fdt_obj.totalsize() + 1024)
+                    fdt_obj.setprop(node.Offset(), self.name, self.bytes)
+            else:
+                fdt_obj.setprop(node.Offset(), self.name, self.bytes)
+
+
 class Node:
     """A device tree node
 
@@ -284,13 +324,7 @@ class Node:
         Args:
             prop_name: Name of property
         """
-        fdt_obj = self._fdt._fdt_obj
-        if fdt_obj.setprop_u32(self.Offset(), prop_name, 0,
-                               (libfdt.NOSPACE,)) == -libfdt.NOSPACE:
-            fdt_obj.resize(fdt_obj.totalsize() + 1024)
-            fdt_obj.setprop_u32(self.Offset(), prop_name, 0)
-        self.props[prop_name] = Prop(self, -1, prop_name, '\0' * 4)
-        self._fdt.Invalidate()
+        self.props[prop_name] = Prop(self, None, prop_name, '\0' * 4)
 
     def SetInt(self, prop_name, val):
         """Update an integer property int the device tree.
@@ -301,8 +335,34 @@ class Node:
             prop_name: Name of property
             val: Value to set
         """
-        fdt_obj = self._fdt._fdt_obj
-        fdt_obj.setprop_u32(self.Offset(), prop_name, val)
+        self.props[prop_name].SetInt(val)
+
+    def Sync(self, auto_resize=False):
+        """Sync node changes back to the device tree
+
+        This updates the device tree blob with any changes to this node and its
+        subnodes since the last sync.
+
+        Args:
+            auto_resize: Resize the device tree automatically if it does not
+                have enough space for the update
+
+        Raises:
+            FdtException if auto_resize is False and there is not enough space
+        """
+        # Sync subnodes in reverse so that we don't disturb node offsets for
+        # nodes that are earlier in the DT. This avoids an O(n^2) rescan of
+        # node offsets.
+        for node in reversed(self.subnodes):
+            node.Sync(auto_resize)
+
+        # Sync properties now, whose offsets should not have been disturbed.
+        # We do this after subnodes, since this disturbs the offsets of these
+        # properties.
+        prop_list = sorted(self.props.values(), key=lambda prop: prop._offset,
+                           reverse=True)
+        for prop in prop_list:
+            prop.Sync(auto_resize)
 
 
 class Fdt:
@@ -381,6 +441,19 @@ class Fdt:
         with open(self._fname, 'wb') as fd:
             fd.write(self._fdt_obj.as_bytearray())
 
+    def Sync(self, auto_resize=False):
+        """Make sure any DT changes are written to the blob
+
+        Args:
+            auto_resize: Resize the device tree automatically if it does not
+                have enough space for the update
+
+        Raises:
+            FdtException if auto_resize is False and there is not enough space
+        """
+        self._root.Sync(auto_resize)
+        self.Invalidate()
+
     def Pack(self):
         """Pack the device tree down to its minimum size
 
diff --git a/tools/dtoc/test_fdt.py b/tools/dtoc/test_fdt.py
index e88d19f80ef..4a67f8949df 100755
--- a/tools/dtoc/test_fdt.py
+++ b/tools/dtoc/test_fdt.py
@@ -337,6 +337,7 @@ class TestProp(unittest.TestCase):
         self.node.AddZeroProp('one')
         self.node.AddZeroProp('two')
         self.node.AddZeroProp('three')
+        self.dtb.Sync(auto_resize=True)
 
         # Updating existing properties should be OK, since the device-tree size
         # does not change
@@ -344,12 +345,17 @@ class TestProp(unittest.TestCase):
         self.node.SetInt('one', 1)
         self.node.SetInt('two', 2)
         self.node.SetInt('three', 3)
+        self.dtb.Sync(auto_resize=False)
 
         # This should fail since it would need to increase the device-tree size
+        self.node.AddZeroProp('four')
         with self.assertRaises(libfdt.FdtException) as e:
-            self.node.SetInt('four', 4)
+            self.dtb.Sync(auto_resize=False)
         self.assertIn('FDT_ERR_NOSPACE', str(e.exception))
 
+    def testAddNode(self):
+        self.fdt.pack()
+
 
 class TestFdtUtil(unittest.TestCase):
     """Tests for the fdt_util module
-- 
2.19.0.397.gdd90340f6a-goog



More information about the U-Boot mailing list