binman: Support updating the device tree with calc'd info
It is useful to write the position and size of each entry back to the
device tree so that U-Boot can access this at runtime. Add a feature to
support this, along with associated tests.
Signed-off-by: Simon Glass <sjg@chromium.org>
diff --git a/tools/binman/README b/tools/binman/README
index 8b598a7..207928a 100644
--- a/tools/binman/README
+++ b/tools/binman/README
@@ -669,13 +669,11 @@
-----
Some ideas:
-- Fill out the device tree to include the final position and size of each
- entry (since the input file may not always specify these). See also
- 'Access to binman entry positions at run time' above
- Use of-platdata to make the information available to code that is unable
to use device tree (such as a very small SPL image)
- Allow easy building of images by specifying just the board name
-- Produce a full Python binding for libfdt (for upstream)
+- Produce a full Python binding for libfdt (for upstream). This is nearing
+ completion but some work remains
- Add an option to decode an image into the constituent binaries
- Support building an image for a board (-b) more completely, with a
configurable build directory
diff --git a/tools/binman/control.py b/tools/binman/control.py
index eafabf0..a40b300 100644
--- a/tools/binman/control.py
+++ b/tools/binman/control.py
@@ -168,6 +168,8 @@
image.BuildImage()
if options.map:
image.WriteMap()
+ with open(fname, 'wb') as outfd:
+ outfd.write(dtb.GetContents())
finally:
tools.FinaliseOutputDir()
finally:
diff --git a/tools/binman/etype/_testing.py b/tools/binman/etype/_testing.py
index 04bdc6c..6a1af57 100644
--- a/tools/binman/etype/_testing.py
+++ b/tools/binman/etype/_testing.py
@@ -24,6 +24,9 @@
'return-unknown-contents')
self.bad_update_contents = fdt_util.GetBool(self._node,
'bad-update-contents')
+ self.process_fdt_ready = False
+ self.never_complete_process_fdt = fdt_util.GetBool(self._node,
+ 'never-complete-process-fdt')
def ObtainContents(self):
if self.return_unknown_contents:
@@ -42,3 +45,10 @@
# Request to update the conents with something larger, to cause a
# failure.
self.ProcessContentsUpdate('aa')
+
+ def ProcessFdt(self, fdt):
+ """Force reprocessing the first time"""
+ ready = self.process_fdt_ready
+ if not self.never_complete_process_fdt:
+ self.process_fdt_ready = True
+ return ready
diff --git a/tools/binman/ftest.py b/tools/binman/ftest.py
index af3b4dc..12164a8 100644
--- a/tools/binman/ftest.py
+++ b/tools/binman/ftest.py
@@ -146,19 +146,23 @@
# options.verbosity = tout.DEBUG
return control.Binman(options, args)
- def _DoTestFile(self, fname, debug=False, map=False):
+ def _DoTestFile(self, fname, debug=False, map=False, update_dtb=False):
"""Run binman with a given test file
Args:
fname: Device-tree source filename to use (e.g. 05_simple.dts)
debug: True to enable debugging output
map: True to output map files for the images
+ update_dtb: Update the position and size of each entry in the device
+ tree before packing it into the image
"""
args = ['-p', '-I', self._indir, '-d', self.TestFile(fname)]
if debug:
args.append('-D')
if map:
args.append('-m')
+ if update_dtb:
+ args.append('-up')
return self._DoBinman(*args)
def _SetupDtb(self, fname, outfile='u-boot.dtb'):
@@ -183,7 +187,8 @@
TestFunctional._MakeInputFile(outfile, data)
return data
- def _DoReadFileDtb(self, fname, use_real_dtb=False, map=False):
+ def _DoReadFileDtb(self, fname, use_real_dtb=False, map=False,
+ update_dtb=False):
"""Run binman and return the resulting image
This runs binman with a given test file and then reads the resulting
@@ -199,6 +204,8 @@
test contents (the U_BOOT_DTB_DATA string) can be used.
But in some test we need the real contents.
map: True to output map files for the images
+ update_dtb: Update the position and size of each entry in the device
+ tree before packing it into the image
Returns:
Tuple:
@@ -212,21 +219,22 @@
dtb_data = self._SetupDtb(fname)
try:
- retcode = self._DoTestFile(fname, map=map)
+ retcode = self._DoTestFile(fname, map=map, update_dtb=update_dtb)
self.assertEqual(0, retcode)
+ out_dtb_fname = control.GetFdtPath('u-boot.dtb')
# Find the (only) image, read it and return its contents
image = control.images['image']
- fname = tools.GetOutputFilename('image.bin')
- self.assertTrue(os.path.exists(fname))
+ image_fname = tools.GetOutputFilename('image.bin')
+ self.assertTrue(os.path.exists(image_fname))
if map:
map_fname = tools.GetOutputFilename('image.map')
with open(map_fname) as fd:
map_data = fd.read()
else:
map_data = None
- with open(fname) as fd:
- return fd.read(), dtb_data, map_data
+ with open(image_fname) as fd:
+ return fd.read(), dtb_data, map_data, out_dtb_fname
finally:
# Put the test file back
if use_real_dtb:
@@ -300,6 +308,26 @@
"""
return struct.unpack('>L', dtb[4:8])[0]
+ def _GetPropTree(self, dtb_data, node_names):
+ def AddNode(node, path):
+ if node.name != '/':
+ path += '/' + node.name
+ #print 'path', path
+ for subnode in node.subnodes:
+ for prop in subnode.props.values():
+ if prop.name in node_names:
+ prop_path = path + '/' + subnode.name + ':' + prop.name
+ tree[prop_path[len('/binman/'):]] = fdt_util.fdt32_to_cpu(
+ prop.value)
+ #print ' ', prop.name
+ AddNode(subnode, path)
+
+ tree = {}
+ dtb = fdt.Fdt(dtb_data)
+ dtb.Scan()
+ AddNode(dtb.GetRoot(), '')
+ return tree
+
def testRun(self):
"""Test a basic run with valid args"""
result = self._RunBinman('-h')
@@ -845,7 +873,7 @@
"""Test that we can cope with an image without microcode (e.g. qemu)"""
with open(self.TestFile('u_boot_no_ucode_ptr')) as fd:
TestFunctional._MakeInputFile('u-boot', fd.read())
- data, dtb, _ = self._DoReadFileDtb('44_x86_optional_ucode.dts', True)
+ data, dtb, _, _ = self._DoReadFileDtb('44_x86_optional_ucode.dts', True)
# Now check the device tree has no microcode
self.assertEqual(U_BOOT_NODTB_DATA, data[:len(U_BOOT_NODTB_DATA)])
@@ -980,7 +1008,7 @@
def testMap(self):
"""Tests outputting a map of the images"""
- _, _, map_data = self._DoReadFileDtb('55_sections.dts', map=True)
+ _, _, map_data, _ = self._DoReadFileDtb('55_sections.dts', map=True)
self.assertEqual('''Position Size Name
00000000 00000010 section@0
00000000 00000004 u-boot
@@ -990,7 +1018,7 @@
def testNamePrefix(self):
"""Tests that name prefixes are used"""
- _, _, map_data = self._DoReadFileDtb('56_name_prefix.dts', map=True)
+ _, _, map_data, _ = self._DoReadFileDtb('56_name_prefix.dts', map=True)
self.assertEqual('''Position Size Name
00000000 00000010 section@0
00000000 00000004 ro-u-boot
@@ -1013,6 +1041,35 @@
self.assertIn("Node '/binman/_testing': Cannot update entry size from "
'2 to 1', str(e.exception))
+ def testUpdateFdt(self):
+ """Test that we can update the device tree with pos/size info"""
+ _, _, _, out_dtb_fname = self._DoReadFileDtb('60_fdt_update.dts',
+ update_dtb=True)
+ props = self._GetPropTree(out_dtb_fname, ['pos', 'size'])
+ with open('/tmp/x.dtb', 'wb') as outf:
+ with open(out_dtb_fname) as inf:
+ outf.write(inf.read())
+ self.assertEqual({
+ '_testing:pos': 32,
+ '_testing:size': 1,
+ 'section@0/u-boot:pos': 0,
+ 'section@0/u-boot:size': len(U_BOOT_DATA),
+ 'section@0:pos': 0,
+ 'section@0:size': 16,
+
+ 'section@1/u-boot:pos': 0,
+ 'section@1/u-boot:size': len(U_BOOT_DATA),
+ 'section@1:pos': 16,
+ 'section@1:size': 16,
+ 'size': 40
+ }, props)
+
+ def testUpdateFdtBad(self):
+ """Test that we detect when ProcessFdt never completes"""
+ with self.assertRaises(ValueError) as e:
+ self._DoReadFileDtb('61_fdt_update_bad.dts', update_dtb=True)
+ self.assertIn('Could not complete processing of Fdt: remaining '
+ '[<_testing.Entry__testing', str(e.exception))
if __name__ == "__main__":
unittest.main()
diff --git a/tools/binman/test/60_fdt_update.dts b/tools/binman/test/60_fdt_update.dts
new file mode 100644
index 0000000..f53c8a5
--- /dev/null
+++ b/tools/binman/test/60_fdt_update.dts
@@ -0,0 +1,31 @@
+// SPDX-License-Identifier: GPL-2.0+
+/dts-v1/;
+
+/ {
+ #address-cells = <1>;
+ #size-cells = <1>;
+
+ binman {
+ pad-byte = <0x26>;
+ size = <0x28>;
+ section@0 {
+ read-only;
+ name-prefix = "ro-";
+ size = <0x10>;
+ pad-byte = <0x21>;
+
+ u-boot {
+ };
+ };
+ section@1 {
+ name-prefix = "rw-";
+ size = <0x10>;
+ pad-byte = <0x61>;
+
+ u-boot {
+ };
+ };
+ _testing {
+ };
+ };
+};
diff --git a/tools/binman/test/61_fdt_update_bad.dts b/tools/binman/test/61_fdt_update_bad.dts
new file mode 100644
index 0000000..e5abf31
--- /dev/null
+++ b/tools/binman/test/61_fdt_update_bad.dts
@@ -0,0 +1,32 @@
+// SPDX-License-Identifier: GPL-2.0+
+/dts-v1/;
+
+/ {
+ #address-cells = <1>;
+ #size-cells = <1>;
+
+ binman {
+ pad-byte = <0x26>;
+ size = <0x28>;
+ section@0 {
+ read-only;
+ name-prefix = "ro-";
+ size = <0x10>;
+ pad-byte = <0x21>;
+
+ u-boot {
+ };
+ };
+ section@1 {
+ name-prefix = "rw-";
+ size = <0x10>;
+ pad-byte = <0x61>;
+
+ u-boot {
+ };
+ };
+ _testing {
+ never-complete-process-fdt;
+ };
+ };
+};