summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSimon Glass <sjg@chromium.org>2018-09-14 04:57:13 -0600
committerSimon Glass <sjg@chromium.org>2018-09-28 11:09:01 -0600
commitfa80c25c09a6c59be4df9c42b4a02538d8a07382 (patch)
tree63d4ca476dd70999fbbe25d749d2e5165ff4b919
parent0bfa7b09ba16f4ffaf0cfc9315336aaa708dcd26 (diff)
downloadu-boot-fa80c25c09a6c59be4df9c42b4a02538d8a07382.tar.gz
dtoc: Allow syncing of the device tree back to a file
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@chromium.org>
-rw-r--r--tools/binman/control.py2
-rw-r--r--tools/dtoc/fdt.py91
-rwxr-xr-xtools/dtoc/test_fdt.py8
3 files changed, 91 insertions, 10 deletions
diff --git a/tools/binman/control.py b/tools/binman/control.py
index 8c48008fc7..ded1b71109 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 55baa3857f..76cd66fbf9 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 e88d19f80e..4a67f8949d 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