summaryrefslogtreecommitdiff
path: root/tools
diff options
context:
space:
mode:
Diffstat (limited to 'tools')
-rw-r--r--tools/binman/README32
-rwxr-xr-xtools/binman/binman.py11
-rw-r--r--tools/binman/control.py3
-rw-r--r--tools/binman/elf.py129
-rw-r--r--tools/binman/elf_test.py122
-rw-r--r--tools/binman/etype/entry.py8
-rw-r--r--tools/binman/etype/u_boot_spl.py6
-rw-r--r--tools/binman/etype/u_boot_spl_bss_pad.py7
-rw-r--r--tools/binman/etype/u_boot_spl_dtb.py17
-rw-r--r--tools/binman/etype/u_boot_spl_nodtb.py17
-rw-r--r--tools/binman/etype/u_boot_with_ucode_ptr.py9
-rw-r--r--tools/binman/ftest.py68
-rw-r--r--tools/binman/image.py79
-rw-r--r--tools/binman/image_test.py46
-rw-r--r--tools/binman/test/21_image_pad.dts2
-rw-r--r--tools/binman/test/24_sorted.dts4
-rw-r--r--tools/binman/test/28_pack_4gb_outside.dts4
-rw-r--r--tools/binman/test/29_x86-rom.dts6
-rw-r--r--tools/binman/test/51_u_boot_spl_dtb.dts13
-rw-r--r--tools/binman/test/52_u_boot_spl_nodtb.dts11
-rw-r--r--tools/binman/test/53_symbols.dts20
-rw-r--r--tools/binman/test/Makefile18
-rw-r--r--tools/binman/test/bss_data.c2
-rwxr-xr-xtools/binman/test/u_boot_binman_symsbin0 -> 4921 bytes
-rw-r--r--tools/binman/test/u_boot_binman_syms.c14
-rw-r--r--tools/binman/test/u_boot_binman_syms.lds30
-rwxr-xr-xtools/binman/test/u_boot_binman_syms_badbin0 -> 4890 bytes
l---------tools/binman/test/u_boot_binman_syms_bad.c1
-rw-r--r--tools/binman/test/u_boot_binman_syms_bad.lds29
-rwxr-xr-xtools/binman/test/u_boot_binman_syms_sizebin0 -> 4825 bytes
-rw-r--r--tools/binman/test/u_boot_binman_syms_size.c12
-rw-r--r--tools/binman/test/u_boot_ucode_ptr.c2
32 files changed, 685 insertions, 37 deletions
diff --git a/tools/binman/README b/tools/binman/README
index 4ef76c8f08..08c3e56bde 100644
--- a/tools/binman/README
+++ b/tools/binman/README
@@ -439,6 +439,8 @@ contents of an entry in some way. For example, it would be possible to create
an entry containing a hash of the contents of some other entries. At this
stage the position and size of entries should not be adjusted.
+6. WriteEntryInfo()
+
7. BuildImage() - builds the image and writes it to a file. This is the final
step.
@@ -471,6 +473,33 @@ the 'warning' line in scripts/Makefile.lib to see what it has found:
# u_boot_dtsi_options_debug = $(u_boot_dtsi_options_raw)
+Access to binman entry positions at run time
+--------------------------------------------
+
+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
+is useful to be able to find the location of U-Boot so that it can be executed
+when SPL is finished.
+
+Binman allows you to declare symbols in the SPL image which are filled in
+with their correct values during the build. For example:
+
+ binman_sym_declare(ulong, u_boot_any, pos);
+
+declares a ulong value which will be assigned to the position of any U-Boot
+image (u-boot.bin, u-boot.img, u-boot-nodtb.bin) that is present in the image.
+You can access this value with something like:
+
+ ulong u_boot_pos = binman_sym(ulong, u_boot_any, pos);
+
+Thus u_boot_pos will be set to the position of U-Boot in memory, assuming that
+the whole image has been loaded, or is available in flash. You can then jump to
+that address to start U-Boot.
+
+At present this feature is only supported in SPL. In principle it is possible
+to fill in such symbols in U-Boot proper, as well.
+
+
Code coverage
-------------
@@ -543,7 +572,8 @@ To do
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)
+ 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)
- Write an image map to a text file
diff --git a/tools/binman/binman.py b/tools/binman/binman.py
index 3ccf25f1f8..1c8e8dbff6 100755
--- a/tools/binman/binman.py
+++ b/tools/binman/binman.py
@@ -31,11 +31,13 @@ import cmdline
import command
import control
-def RunTests():
+def RunTests(debug):
"""Run the functional tests and any embedded doctests"""
+ import elf_test
import entry_test
import fdt_test
import ftest
+ import image_test
import test
import doctest
@@ -45,12 +47,15 @@ def RunTests():
suite.run(result)
sys.argv = [sys.argv[0]]
+ if debug:
+ sys.argv.append('-D')
# Run the entry tests first ,since these need to be the first to import the
# 'entry' module.
suite = unittest.TestLoader().loadTestsFromTestCase(entry_test.TestEntry)
suite.run(result)
- for module in (ftest.TestFunctional, fdt_test.TestFdt):
+ for module in (ftest.TestFunctional, fdt_test.TestFdt, elf_test.TestElf,
+ image_test.TestImage):
suite = unittest.TestLoader().loadTestsFromTestCase(module)
suite.run(result)
@@ -110,7 +115,7 @@ def RunBinman(options, args):
sys.tracebacklimit = 0
if options.test:
- ret_code = RunTests()
+ ret_code = RunTests(options.debug)
elif options.test_coverage:
RunTestCoverage()
diff --git a/tools/binman/control.py b/tools/binman/control.py
index e9d48df030..ffa2bbd80f 100644
--- a/tools/binman/control.py
+++ b/tools/binman/control.py
@@ -12,6 +12,7 @@ import sys
import tools
import command
+import elf
import fdt
import fdt_util
from image import Image
@@ -89,6 +90,7 @@ def Binman(options, args):
try:
tout.Init(options.verbosity)
+ elf.debug = options.debug
try:
tools.SetInputDirs(options.indir)
tools.PrepareOutputDir(options.outdir, options.preserve)
@@ -109,6 +111,7 @@ def Binman(options, args):
image.CheckSize()
image.CheckEntries()
image.ProcessEntryContents()
+ image.WriteSymbols()
image.BuildImage()
finally:
tools.FinaliseOutputDir()
diff --git a/tools/binman/elf.py b/tools/binman/elf.py
new file mode 100644
index 0000000000..80ff2253f0
--- /dev/null
+++ b/tools/binman/elf.py
@@ -0,0 +1,129 @@
+# Copyright (c) 2016 Google, Inc
+# Written by Simon Glass <sjg@chromium.org>
+#
+# SPDX-License-Identifier: GPL-2.0+
+#
+# Handle various things related to ELF images
+#
+
+from collections import namedtuple, OrderedDict
+import command
+import os
+import re
+import struct
+
+import tools
+
+# This is enabled from control.py
+debug = False
+
+Symbol = namedtuple('Symbol', ['section', 'address', 'size', 'weak'])
+
+
+def GetSymbols(fname, patterns):
+ """Get the symbols from an ELF file
+
+ Args:
+ fname: Filename of the ELF file to read
+ patterns: List of regex patterns to search for, each a string
+
+ Returns:
+ None, if the file does not exist, or Dict:
+ key: Name of symbol
+ value: Hex value of symbol
+ """
+ stdout = command.Output('objdump', '-t', fname, raise_on_error=False)
+ lines = stdout.splitlines()
+ if patterns:
+ re_syms = re.compile('|'.join(patterns))
+ else:
+ re_syms = None
+ syms = {}
+ syms_started = False
+ for line in lines:
+ if not line or not syms_started:
+ if 'SYMBOL TABLE' in line:
+ syms_started = True
+ line = None # Otherwise code coverage complains about 'continue'
+ continue
+ if re_syms and not re_syms.search(line):
+ continue
+
+ space_pos = line.find(' ')
+ value, rest = line[:space_pos], line[space_pos + 1:]
+ flags = rest[:7]
+ parts = rest[7:].split()
+ section, size = parts[:2]
+ if len(parts) > 2:
+ name = parts[2]
+ syms[name] = Symbol(section, int(value, 16), int(size,16),
+ flags[1] == 'w')
+ return syms
+
+def GetSymbolAddress(fname, sym_name):
+ """Get a value of a symbol from an ELF file
+
+ Args:
+ fname: Filename of the ELF file to read
+ patterns: List of regex patterns to search for, each a string
+
+ Returns:
+ Symbol value (as an integer) or None if not found
+ """
+ syms = GetSymbols(fname, [sym_name])
+ sym = syms.get(sym_name)
+ if not sym:
+ return None
+ return sym.address
+
+def LookupAndWriteSymbols(elf_fname, entry, image):
+ """Replace all symbols in an entry with their correct values
+
+ The entry contents is updated so that values for referenced symbols will be
+ visible at run time. This is done by finding out the symbols positions in
+ the entry (using the ELF file) and replacing them with values from binman's
+ data structures.
+
+ Args:
+ elf_fname: Filename of ELF image containing the symbol information for
+ entry
+ entry: Entry to process
+ image: Image which can be used to lookup symbol values
+ """
+ fname = tools.GetInputFilename(elf_fname)
+ syms = GetSymbols(fname, ['image', 'binman'])
+ if not syms:
+ return
+ base = syms.get('__image_copy_start')
+ if not base:
+ return
+ for name, sym in syms.iteritems():
+ if name.startswith('_binman'):
+ msg = ("Image '%s': Symbol '%s'\n in entry '%s'" %
+ (image.GetPath(), name, entry.GetPath()))
+ offset = sym.address - base.address
+ if offset < 0 or offset + sym.size > entry.contents_size:
+ raise ValueError('%s has offset %x (size %x) but the contents '
+ 'size is %x' % (entry.GetPath(), offset,
+ sym.size, entry.contents_size))
+ if sym.size == 4:
+ pack_string = '<I'
+ elif sym.size == 8:
+ pack_string = '<Q'
+ else:
+ raise ValueError('%s has size %d: only 4 and 8 are supported' %
+ (msg, sym.size))
+
+ # Look up the symbol in our entry tables.
+ value = image.LookupSymbol(name, sym.weak, msg)
+ if value is not None:
+ value += base.address
+ else:
+ value = -1
+ pack_string = pack_string.lower()
+ value_bytes = struct.pack(pack_string, value)
+ if debug:
+ print('%s:\n insert %s, offset %x, value %x, length %d' %
+ (msg, name, offset, value, len(value_bytes)))
+ entry.data = (entry.data[:offset] + value_bytes +
+ entry.data[offset + sym.size:])
diff --git a/tools/binman/elf_test.py b/tools/binman/elf_test.py
new file mode 100644
index 0000000000..e5fc28258d
--- /dev/null
+++ b/tools/binman/elf_test.py
@@ -0,0 +1,122 @@
+#
+# Copyright (c) 2017 Google, Inc
+# Written by Simon Glass <sjg@chromium.org>
+#
+# SPDX-License-Identifier: GPL-2.0+
+#
+# Test for the elf module
+
+from contextlib import contextmanager
+import os
+import sys
+import unittest
+
+try:
+ from StringIO import StringIO
+except ImportError:
+ from io import StringIO
+
+import elf
+
+binman_dir = os.path.dirname(os.path.realpath(sys.argv[0]))
+
+# Use this to suppress stdout/stderr output:
+# with capture_sys_output() as (stdout, stderr)
+# ...do something...
+@contextmanager
+def capture_sys_output():
+ capture_out, capture_err = StringIO(), StringIO()
+ old_out, old_err = sys.stdout, sys.stderr
+ try:
+ sys.stdout, sys.stderr = capture_out, capture_err
+ yield capture_out, capture_err
+ finally:
+ sys.stdout, sys.stderr = old_out, old_err
+
+
+class FakeEntry:
+ def __init__(self, contents_size):
+ self.contents_size = contents_size
+ self.data = 'a' * contents_size
+
+ def GetPath(self):
+ return 'entry_path'
+
+class FakeImage:
+ def __init__(self, sym_value=1):
+ self.sym_value = sym_value
+
+ def GetPath(self):
+ return 'image_path'
+
+ def LookupSymbol(self, name, weak, msg):
+ return self.sym_value
+
+class TestElf(unittest.TestCase):
+ def testAllSymbols(self):
+ fname = os.path.join(binman_dir, 'test', 'u_boot_ucode_ptr')
+ syms = elf.GetSymbols(fname, [])
+ self.assertIn('.ucode', syms)
+
+ def testRegexSymbols(self):
+ fname = os.path.join(binman_dir, 'test', 'u_boot_ucode_ptr')
+ syms = elf.GetSymbols(fname, ['ucode'])
+ self.assertIn('.ucode', syms)
+ syms = elf.GetSymbols(fname, ['missing'])
+ self.assertNotIn('.ucode', syms)
+ syms = elf.GetSymbols(fname, ['missing', 'ucode'])
+ self.assertIn('.ucode', syms)
+
+ def testMissingFile(self):
+ entry = FakeEntry(10)
+ image = FakeImage()
+ with self.assertRaises(ValueError) as e:
+ syms = elf.LookupAndWriteSymbols('missing-file', entry, image)
+ self.assertIn("Filename 'missing-file' not found in input path",
+ str(e.exception))
+
+ def testOutsideFile(self):
+ entry = FakeEntry(10)
+ image = FakeImage()
+ elf_fname = os.path.join(binman_dir, 'test', 'u_boot_binman_syms')
+ with self.assertRaises(ValueError) as e:
+ syms = elf.LookupAndWriteSymbols(elf_fname, entry, image)
+ self.assertIn('entry_path has offset 4 (size 8) but the contents size '
+ 'is a', str(e.exception))
+
+ def testMissingImageStart(self):
+ entry = FakeEntry(10)
+ image = FakeImage()
+ elf_fname = os.path.join(binman_dir, 'test', 'u_boot_binman_syms_bad')
+ self.assertEqual(elf.LookupAndWriteSymbols(elf_fname, entry, image),
+ None)
+
+ def testBadSymbolSize(self):
+ entry = FakeEntry(10)
+ image = FakeImage()
+ elf_fname = os.path.join(binman_dir, 'test', 'u_boot_binman_syms_size')
+ with self.assertRaises(ValueError) as e:
+ syms = elf.LookupAndWriteSymbols(elf_fname, entry, image)
+ self.assertIn('has size 1: only 4 and 8 are supported',
+ str(e.exception))
+
+ def testNoValue(self):
+ entry = FakeEntry(20)
+ image = FakeImage(sym_value=None)
+ elf_fname = os.path.join(binman_dir, 'test', 'u_boot_binman_syms')
+ syms = elf.LookupAndWriteSymbols(elf_fname, entry, image)
+ self.assertEqual(chr(255) * 16 + 'a' * 4, entry.data)
+
+ def testDebug(self):
+ elf.debug = True
+ entry = FakeEntry(20)
+ image = FakeImage()
+ elf_fname = os.path.join(binman_dir, 'test', 'u_boot_binman_syms')
+ with capture_sys_output() as (stdout, stderr):
+ syms = elf.LookupAndWriteSymbols(elf_fname, entry, image)
+ elf.debug = False
+ self.assertTrue(len(stdout.getvalue()) > 0)
+
+
+if __name__ == '__main__':
+ unittest.main()
diff --git a/tools/binman/etype/entry.py b/tools/binman/etype/entry.py
index 67c57341ca..5541887d47 100644
--- a/tools/binman/etype/entry.py
+++ b/tools/binman/etype/entry.py
@@ -198,3 +198,11 @@ class Entry(object):
def ProcessContents(self):
pass
+
+ def WriteSymbols(self, image):
+ """Write symbol values into binary files for access at run time
+
+ Args:
+ image: Image containing the entry
+ """
+ pass
diff --git a/tools/binman/etype/u_boot_spl.py b/tools/binman/etype/u_boot_spl.py
index 68b0148427..3720b47fef 100644
--- a/tools/binman/etype/u_boot_spl.py
+++ b/tools/binman/etype/u_boot_spl.py
@@ -6,12 +6,18 @@
# Entry-type module for spl/u-boot-spl.bin
#
+import elf
+
from entry import Entry
from blob import Entry_blob
class Entry_u_boot_spl(Entry_blob):
def __init__(self, image, etype, node):
Entry_blob.__init__(self, image, etype, node)
+ self.elf_fname = 'spl/u-boot-spl'
def GetDefaultFilename(self):
return 'spl/u-boot-spl.bin'
+
+ def WriteSymbols(self, image):
+ elf.LookupAndWriteSymbols(self.elf_fname, self, image)
diff --git a/tools/binman/etype/u_boot_spl_bss_pad.py b/tools/binman/etype/u_boot_spl_bss_pad.py
index c005f28191..c37f61db23 100644
--- a/tools/binman/etype/u_boot_spl_bss_pad.py
+++ b/tools/binman/etype/u_boot_spl_bss_pad.py
@@ -9,6 +9,7 @@
#
import command
+import elf
from entry import Entry
from blob import Entry_blob
import tools
@@ -19,8 +20,8 @@ class Entry_u_boot_spl_bss_pad(Entry_blob):
def ObtainContents(self):
fname = tools.GetInputFilename('spl/u-boot-spl')
- args = [['nm', fname], ['grep', '__bss_size']]
- out = command.RunPipe(args, capture=True).stdout.splitlines()
- bss_size = int(out[0].split()[0], 16)
+ bss_size = elf.GetSymbolAddress(fname, '__bss_size')
+ if not bss_size:
+ self.Raise('Expected __bss_size symbol in spl/u-boot-spl')
self.data = chr(0) * bss_size
self.contents_size = bss_size
diff --git a/tools/binman/etype/u_boot_spl_dtb.py b/tools/binman/etype/u_boot_spl_dtb.py
new file mode 100644
index 0000000000..6c5ce1e996
--- /dev/null
+++ b/tools/binman/etype/u_boot_spl_dtb.py
@@ -0,0 +1,17 @@
+# Copyright (c) 2016 Google, Inc
+# Written by Simon Glass <sjg@chromium.org>
+#
+# SPDX-License-Identifier: GPL-2.0+
+#
+# Entry-type module for U-Boot device tree
+#
+
+from entry import Entry
+from blob import Entry_blob
+
+class Entry_u_boot_spl_dtb(Entry_blob):
+ def __init__(self, image, etype, node):
+ Entry_blob.__init__(self, image, etype, node)
+
+ def GetDefaultFilename(self):
+ return 'spl/u-boot-spl.dtb'
diff --git a/tools/binman/etype/u_boot_spl_nodtb.py b/tools/binman/etype/u_boot_spl_nodtb.py
new file mode 100644
index 0000000000..880e0c78fb
--- /dev/null
+++ b/tools/binman/etype/u_boot_spl_nodtb.py
@@ -0,0 +1,17 @@
+# Copyright (c) 2016 Google, Inc
+# Written by Simon Glass <sjg@chromium.org>
+#
+# SPDX-License-Identifier: GPL-2.0+
+#
+# Entry-type module for 'u-boot-nodtb.bin'
+#
+
+from entry import Entry
+from blob import Entry_blob
+
+class Entry_u_boot_spl_nodtb(Entry_blob):
+ def __init__(self, image, etype, node):
+ Entry_blob.__init__(self, image, etype, node)
+
+ def GetDefaultFilename(self):
+ return 'spl/u-boot-spl-nodtb.bin'
diff --git a/tools/binman/etype/u_boot_with_ucode_ptr.py b/tools/binman/etype/u_boot_with_ucode_ptr.py
index 6f01adb970..99b437130d 100644
--- a/tools/binman/etype/u_boot_with_ucode_ptr.py
+++ b/tools/binman/etype/u_boot_with_ucode_ptr.py
@@ -9,6 +9,7 @@
import struct
import command
+import elf
from entry import Entry
from blob import Entry_blob
import fdt_util
@@ -31,11 +32,9 @@ class Entry_u_boot_with_ucode_ptr(Entry_blob):
def ObtainContents(self):
# Figure out where to put the microcode pointer
fname = tools.GetInputFilename(self.elf_fname)
- args = [['nm', fname], ['grep', '-w', '_dt_ucode_base_size']]
- out = (command.RunPipe(args, capture=True, raise_on_error=False).
- stdout.splitlines())
- if len(out) == 1:
- self.target_pos = int(out[0].split()[0], 16)
+ sym = elf.GetSymbolAddress(fname, '_dt_ucode_base_size')
+ if sym:
+ self.target_pos = sym
elif not fdt_util.GetBool(self._node, 'optional-ucode'):
self.Raise('Cannot locate _dt_ucode_base_size symbol in u-boot')
diff --git a/tools/binman/ftest.py b/tools/binman/ftest.py
index 9083143894..5812ab397c 100644
--- a/tools/binman/ftest.py
+++ b/tools/binman/ftest.py
@@ -20,6 +20,7 @@ import binman
import cmdline
import command
import control
+import elf
import fdt
import fdt_util
import tools
@@ -28,11 +29,12 @@ import tout
# Contents of test files, corresponding to different entry types
U_BOOT_DATA = '1234'
U_BOOT_IMG_DATA = 'img'
-U_BOOT_SPL_DATA = '567'
+U_BOOT_SPL_DATA = '56780123456789abcde'
BLOB_DATA = '89'
ME_DATA = '0abcd'
VGA_DATA = 'vga'
U_BOOT_DTB_DATA = 'udtb'
+U_BOOT_SPL_DTB_DATA = 'spldtb'
X86_START16_DATA = 'start16'
X86_START16_SPL_DATA = 'start16spl'
U_BOOT_NODTB_DATA = 'nodtb with microcode pointer somewhere in here'
@@ -76,6 +78,7 @@ class TestFunctional(unittest.TestCase):
TestFunctional._MakeInputFile('me.bin', ME_DATA)
TestFunctional._MakeInputFile('vga.bin', VGA_DATA)
TestFunctional._MakeInputFile('u-boot.dtb', U_BOOT_DTB_DATA)
+ TestFunctional._MakeInputFile('spl/u-boot-spl.dtb', U_BOOT_SPL_DTB_DATA)
TestFunctional._MakeInputFile('u-boot-x86-16bit.bin', X86_START16_DATA)
TestFunctional._MakeInputFile('spl/u-boot-x86-16bit-spl.bin',
X86_START16_SPL_DATA)
@@ -134,7 +137,10 @@ class TestFunctional(unittest.TestCase):
Returns:
Return value (0 for success)
"""
- (options, args) = cmdline.ParseArgs(list(args))
+ args = list(args)
+ if '-D' in sys.argv:
+ args = args + ['-D']
+ (options, args) = cmdline.ParseArgs(args)
options.pager = 'binman-invalid-pager'
options.build_dir = self._indir
@@ -142,14 +148,16 @@ class TestFunctional(unittest.TestCase):
# options.verbosity = tout.DEBUG
return control.Binman(options, args)
- def _DoTestFile(self, fname):
+ def _DoTestFile(self, fname, debug=False):
"""Run binman with a given test file
Args:
fname: Device tree source filename to use (e.g. 05_simple.dts)
"""
- return self._DoBinman('-p', '-I', self._indir,
- '-d', self.TestFile(fname))
+ args = ['-p', '-I', self._indir, '-d', self.TestFile(fname)]
+ if debug:
+ args.append('-D')
+ return self._DoBinman(*args)
def _SetupDtb(self, fname, outfile='u-boot.dtb'):
"""Set up a new test device-tree file
@@ -302,7 +310,6 @@ class TestFunctional(unittest.TestCase):
self.assertEqual(0, len(result.stderr))
self.assertEqual(0, result.return_code)
- # Not yet available.
def testBoard(self):
"""Test that we can run it with a specific board"""
self._SetupDtb('05_simple.dts', 'sandbox/u-boot.dtb')
@@ -362,6 +369,10 @@ class TestFunctional(unittest.TestCase):
data = self._DoReadFile('05_simple.dts')
self.assertEqual(U_BOOT_DATA, data)
+ def testSimpleDebug(self):
+ """Test a simple binman run with debugging enabled"""
+ data = self._DoTestFile('05_simple.dts', debug=True)
+
def testDual(self):
"""Test that we can handle creating two images
@@ -563,8 +574,10 @@ class TestFunctional(unittest.TestCase):
def testImagePadByte(self):
"""Test that the image pad byte can be specified"""
+ with open(self.TestFile('bss_data')) as fd:
+ TestFunctional._MakeInputFile('spl/u-boot-spl', fd.read())
data = self._DoReadFile('21_image_pad.dts')
- self.assertEqual(U_BOOT_SPL_DATA + (chr(0xff) * 9) + U_BOOT_DATA, data)
+ self.assertEqual(U_BOOT_SPL_DATA + (chr(0xff) * 1) + U_BOOT_DATA, data)
def testImageName(self):
"""Test that image files can be named"""
@@ -586,7 +599,7 @@ class TestFunctional(unittest.TestCase):
def testPackSorted(self):
"""Test that entries can be sorted"""
data = self._DoReadFile('24_sorted.dts')
- self.assertEqual(chr(0) * 5 + U_BOOT_SPL_DATA + chr(0) * 2 +
+ self.assertEqual(chr(0) * 1 + U_BOOT_SPL_DATA + chr(0) * 2 +
U_BOOT_DATA, data)
def testPackZeroPosition(self):
@@ -614,14 +627,14 @@ class TestFunctional(unittest.TestCase):
with self.assertRaises(ValueError) as e:
self._DoTestFile('28_pack_4gb_outside.dts')
self.assertIn("Node '/binman/u-boot': Position 0x0 (0) is outside "
- "the image starting at 0xfffffff0 (4294967280)",
+ "the image starting at 0xffffffe0 (4294967264)",
str(e.exception))
def testPackX86Rom(self):
"""Test that a basic x86 ROM can be created"""
data = self._DoReadFile('29_x86-rom.dts')
- self.assertEqual(U_BOOT_DATA + chr(0) * 3 + U_BOOT_SPL_DATA +
- chr(0) * 6, data)
+ self.assertEqual(U_BOOT_DATA + chr(0) * 7 + U_BOOT_SPL_DATA +
+ chr(0) * 2, data)
def testPackX86RomMeNoDesc(self):
"""Test that an invalid Intel descriptor entry is detected"""
@@ -835,6 +848,13 @@ class TestFunctional(unittest.TestCase):
data = self._DoReadFile('47_spl_bss_pad.dts')
self.assertEqual(U_BOOT_SPL_DATA + (chr(0) * 10) + U_BOOT_DATA, data)
+ with open(self.TestFile('u_boot_ucode_ptr')) as fd:
+ TestFunctional._MakeInputFile('spl/u-boot-spl', fd.read())
+ with self.assertRaises(ValueError) as e:
+ data = self._DoReadFile('47_spl_bss_pad.dts')
+ self.assertIn('Expected __bss_size symbol in spl/u-boot-spl',
+ str(e.exception))
+
def testPackStart16Spl(self):
"""Test that an image with an x86 start16 region can be created"""
data = self._DoReadFile('48_x86-start16-spl.dts')
@@ -862,6 +882,32 @@ class TestFunctional(unittest.TestCase):
data = self._DoReadFile('50_intel_mrc.dts')
self.assertEqual(MRC_DATA, data[:len(MRC_DATA)])
+ def testSplDtb(self):
+ """Test that an image with spl/u-boot-spl.dtb can be created"""
+ data = self._DoReadFile('51_u_boot_spl_dtb.dts')
+ self.assertEqual(U_BOOT_SPL_DTB_DATA, data[:len(U_BOOT_SPL_DTB_DATA)])
+
+ def testSplNoDtb(self):
+ """Test that an image with spl/u-boot-spl-nodtb.bin can be created"""
+ data = self._DoReadFile('52_u_boot_spl_nodtb.dts')
+ self.assertEqual(U_BOOT_SPL_NODTB_DATA, data[:len(U_BOOT_SPL_NODTB_DATA)])
+
+ def testSymbols(self):
+ """Test binman can assign symbols embedded in U-Boot"""
+ elf_fname = self.TestFile('u_boot_binman_syms')
+ syms = elf.GetSymbols(elf_fname, ['binman', 'image'])
+ addr = elf.GetSymbolAddress(elf_fname, '__image_copy_start')
+ self.assertEqual(syms['_binman_u_boot_spl_prop_pos'].address, addr)
+
+ with open(self.TestFile('u_boot_binman_syms')) as fd:
+ TestFunctional._MakeInputFile('spl/u-boot-spl', fd.read())
+ data = self._DoReadFile('53_symbols.dts')
+ sym_values = struct.pack('<LQL', 0x24 + 0, 0x24 + 24, 0x24 + 20)
+ expected = (sym_values + U_BOOT_SPL_DATA[16:] + chr(0xff) +
+ U_BOOT_DATA +
+ sym_values + U_BOOT_SPL_DATA[16:])
+ self.assertEqual(expected, data)
+
if __name__ == "__main__":
unittest.main()
diff --git a/tools/binman/image.py b/tools/binman/image.py
index 24c4f6f578..741630f091 100644
--- a/tools/binman/image.py
+++ b/tools/binman/image.py
@@ -6,8 +6,12 @@
# Class for an image, the output of binman
#
+from __future__ import print_function
+
from collections import OrderedDict
from operator import attrgetter
+import re
+import sys
import fdt_util
import tools
@@ -45,7 +49,7 @@ class Image:
address.
_entries: OrderedDict() of entries
"""
- def __init__(self, name, node):
+ def __init__(self, name, node, test=False):
global entry
global Entry
import entry
@@ -64,8 +68,9 @@ class Image:
self._end_4gb = False
self._entries = OrderedDict()
- self._ReadNode()
- self._ReadEntries()
+ if not test:
+ self._ReadNode()
+ self._ReadEntries()
def _ReadNode(self):
"""Read properties from the image node"""
@@ -119,6 +124,14 @@ class Image:
"""
raise ValueError("Image '%s': %s" % (self._node.path, msg))
+ def GetPath(self):
+ """Get the path of an image (in the FDT)
+
+ Returns:
+ Full path of the node for this image
+ """
+ return self._node.path
+
def _ReadEntries(self):
for node in self._node.subnodes:
self._entries[node.name] = Entry.Create(self, node)
@@ -220,6 +233,11 @@ class Image:
for entry in self._entries.values():
entry.ProcessContents()
+ def WriteSymbols(self):
+ """Write symbol values into binary files for access at run time"""
+ for entry in self._entries.values():
+ entry.WriteSymbols(self)
+
def BuildImage(self):
"""Write the image to a file"""
fname = tools.GetOutputFilename(self._filename)
@@ -230,3 +248,58 @@ class Image:
data = entry.GetData()
fd.seek(self._pad_before + entry.pos - self._skip_at_start)
fd.write(data)
+
+ def LookupSymbol(self, sym_name, optional, msg):
+ """Look up a symbol in an ELF file
+
+ Looks up a symbol in an ELF file. Only entry types which come from an
+ ELF image can be used by this function.
+
+ At present the only entry property supported is pos.
+
+ Args:
+ sym_name: Symbol name in the ELF file to look up in the format
+ _binman_<entry>_prop_<property> where <entry> is the name of
+ the entry and <property> is the property to find (e.g.
+ _binman_u_boot_prop_pos). As a special case, you can append
+ _any to <entry> to have it search for any matching entry. E.g.
+ _binman_u_boot_any_prop_pos will match entries called u-boot,
+ u-boot-img and u-boot-nodtb)
+ optional: True if the symbol is optional. If False this function
+ will raise if the symbol is not found
+ msg: Message to display if an error occurs
+
+ Returns:
+ Value that should be assigned to that symbol, or None if it was
+ optional and not found
+
+ Raises:
+ ValueError if the symbol is invalid or not found, or references a
+ property which is not supported
+ """
+ m = re.match(r'^_binman_(\w+)_prop_(\w+)$', sym_name)
+ if not m:
+ raise ValueError("%s: Symbol '%s' has invalid format" %
+ (msg, sym_name))
+ entry_name, prop_name = m.groups()
+ entry_name = entry_name.replace('_', '-')
+ entry = self._entries.get(entry_name)
+ if not entry:
+ if entry_name.endswith('-any'):
+ root = entry_name[:-4]
+ for name in self._entries:
+ if name.startswith(root):
+ rest = name[len(root):]
+ if rest in ['', '-img', '-nodtb']:
+ entry = self._entries[name]
+ if not entry:
+ err = ("%s: Entry '%s' not found in list (%s)" %
+ (msg, entry_name, ','.join(self._entries.keys())))
+ if optional:
+ print('Warning: %s' % err, file=sys.stderr)
+ return None
+ raise ValueError(err)
+ if prop_name == 'pos':
+ return entry.pos
+ else:
+ raise ValueError("%s: No such property '%s'" % (msg, prop_name))
diff --git a/tools/binman/image_test.py b/tools/binman/image_test.py
new file mode 100644
index 0000000000..1b50dda4dc
--- /dev/null
+++ b/tools/binman/image_test.py
@@ -0,0 +1,46 @@
+#
+# Copyright (c) 2017 Google, Inc
+# Written by Simon Glass <sjg@chromium.org>
+#
+# SPDX-License-Identifier: GPL-2.0+
+#
+# Test for the image module
+
+import unittest
+
+from image import Image
+from elf_test import capture_sys_output
+
+class TestImage(unittest.TestCase):
+ def testInvalidFormat(self):
+ image = Image('name', 'node', test=True)
+ with self.assertRaises(ValueError) as e:
+ image.LookupSymbol('_binman_something_prop_', False, 'msg')
+ self.assertIn(
+ "msg: Symbol '_binman_something_prop_' has invalid format",
+ str(e.exception))
+
+ def testMissingSymbol(self):
+ image = Image('name', 'node', test=True)
+ image._entries = {}
+ with self.assertRaises(ValueError) as e:
+ image.LookupSymbol('_binman_type_prop_pname', False, 'msg')
+ self.assertIn("msg: Entry 'type' not found in list ()",
+ str(e.exception))
+
+ def testMissingSymbolOptional(self):
+ image = Image('name', 'node', test=True)
+ image._entries = {}
+ with capture_sys_output() as (stdout, stderr):
+ val = image.LookupSymbol('_binman_type_prop_pname', True, 'msg')
+ self.assertEqual(val, None)
+ self.assertEqual("Warning: msg: Entry 'type' not found in list ()\n",
+ stderr.getvalue())
+ self.assertEqual('', stdout.getvalue())
+
+ def testBadProperty(self):
+ image = Image('name', 'node', test=True)
+ image._entries = {'u-boot': 1}
+ with self.assertRaises(ValueError) as e:
+ image.LookupSymbol('_binman_u_boot_prop_bad', False, 'msg')
+ self.assertIn("msg: No such property 'bad", str(e.exception))
diff --git a/tools/binman/test/21_image_pad.dts b/tools/binman/test/21_image_pad.dts
index daf8385f6d..bf39dc1b6f 100644
--- a/tools/binman/test/21_image_pad.dts
+++ b/tools/binman/test/21_image_pad.dts
@@ -10,7 +10,7 @@
};
u-boot {
- pos = <12>;
+ pos = <20>;
};
};
};
diff --git a/tools/binman/test/24_sorted.dts b/tools/binman/test/24_sorted.dts
index 9f4151c932..43a7831341 100644
--- a/tools/binman/test/24_sorted.dts
+++ b/tools/binman/test/24_sorted.dts
@@ -7,11 +7,11 @@
binman {
sort-by-pos;
u-boot {
- pos = <10>;
+ pos = <22>;
};
u-boot-spl {
- pos = <5>;
+ pos = <1>;
};
};
};
diff --git a/tools/binman/test/28_pack_4gb_outside.dts b/tools/binman/test/28_pack_4gb_outside.dts
index ff468c7d41..18d6bb5b8a 100644
--- a/tools/binman/test/28_pack_4gb_outside.dts
+++ b/tools/binman/test/28_pack_4gb_outside.dts
@@ -7,13 +7,13 @@
binman {
sort-by-pos;
end-at-4gb;
- size = <16>;
+ size = <32>;
u-boot {
pos = <0>;
};
u-boot-spl {
- pos = <0xfffffff7>;
+ pos = <0xffffffeb>;
};
};
};
diff --git a/tools/binman/test/29_x86-rom.dts b/tools/binman/test/29_x86-rom.dts
index 075ede36ab..d49078e19e 100644
--- a/tools/binman/test/29_x86-rom.dts
+++ b/tools/binman/test/29_x86-rom.dts
@@ -7,13 +7,13 @@
binman {
sort-by-pos;
end-at-4gb;
- size = <16>;
+ size = <32>;
u-boot {
- pos = <0xfffffff0>;
+ pos = <0xffffffe0>;
};
u-boot-spl {
- pos = <0xfffffff7>;
+ pos = <0xffffffeb>;
};
};
};
diff --git a/tools/binman/test/51_u_boot_spl_dtb.dts b/tools/binman/test/51_u_boot_spl_dtb.dts
new file mode 100644
index 0000000000..3912f86b4c
--- /dev/null
+++ b/tools/binman/test/51_u_boot_spl_dtb.dts
@@ -0,0 +1,13 @@
+/dts-v1/;
+
+/ {
+ #address-cells = <1>;
+ #size-cells = <1>;
+
+ binman {
+ size = <16>;
+
+ u-boot-spl-dtb {
+ };
+ };
+};
diff --git a/tools/binman/test/52_u_boot_spl_nodtb.dts b/tools/binman/test/52_u_boot_spl_nodtb.dts
new file mode 100644
index 0000000000..7f4e27780f
--- /dev/null
+++ b/tools/binman/test/52_u_boot_spl_nodtb.dts
@@ -0,0 +1,11 @@
+/dts-v1/;
+
+/ {
+ #address-cells = <1>;
+ #size-cells = <1>;
+
+ binman {
+ u-boot-spl-nodtb {
+ };
+ };
+};
diff --git a/tools/binman/test/53_symbols.dts b/tools/binman/test/53_symbols.dts
new file mode 100644
index 0000000000..980b066eb2
--- /dev/null
+++ b/tools/binman/test/53_symbols.dts
@@ -0,0 +1,20 @@
+/dts-v1/;
+
+/ {
+ #address-cells = <1>;
+ #size-cells = <1>;
+
+ binman {
+ pad-byte = <0xff>;
+ u-boot-spl {
+ };
+
+ u-boot {
+ pos = <20>;
+ };
+
+ u-boot-spl2 {
+ type = "u-boot-spl";
+ };
+ };
+};
diff --git a/tools/binman/test/Makefile b/tools/binman/test/Makefile
index 217d13c666..e58fc80775 100644
--- a/tools/binman/test/Makefile
+++ b/tools/binman/test/Makefile
@@ -10,8 +10,12 @@
CFLAGS := -march=i386 -m32 -nostdlib -I ../../../include
LDS_UCODE := -T u_boot_ucode_ptr.lds
+LDS_BINMAN := -T u_boot_binman_syms.lds
+LDS_BINMAN_BAD := -T u_boot_binman_syms_bad.lds
-TARGETS = u_boot_ucode_ptr u_boot_no_ucode_ptr bss_data
+TARGETS = u_boot_ucode_ptr u_boot_no_ucode_ptr bss_data \
+ u_boot_binman_syms u_boot_binman_syms.bin u_boot_binman_syms_bad \
+ u_boot_binman_syms_size
all: $(TARGETS)
@@ -24,6 +28,18 @@ u_boot_ucode_ptr: u_boot_ucode_ptr.c
bss_data: CFLAGS += bss_data.lds
bss_data: bss_data.c
+u_boot_binman_syms.bin: u_boot_binman_syms
+ objcopy -O binary $< -R .note.gnu.build-id $@
+
+u_boot_binman_syms: CFLAGS += $(LDS_BINMAN)
+u_boot_binman_syms: u_boot_binman_syms.c
+
+u_boot_binman_syms_bad: CFLAGS += $(LDS_BINMAN_BAD)
+u_boot_binman_syms_bad: u_boot_binman_syms_bad.c
+
+u_boot_binman_syms_size: CFLAGS += $(LDS_BINMAN)
+u_boot_binman_syms_size: u_boot_binman_syms_size.c
+
clean:
rm -f $(TARGETS)
diff --git a/tools/binman/test/bss_data.c b/tools/binman/test/bss_data.c
index f865a9d9f6..e0305c382c 100644
--- a/tools/binman/test/bss_data.c
+++ b/tools/binman/test/bss_data.c
@@ -4,7 +4,7 @@
* SPDX-License-Identifier: GPL-2.0+
*
* Simple program to create a _dt_ucode_base_size symbol which can be read
- * by 'nm'. This is used by binman tests.
+ * by binutils. This is used by binman tests.
*/
int bss_data[10];
diff --git a/tools/binman/test/u_boot_binman_syms b/tools/binman/test/u_boot_binman_syms
new file mode 100755
index 0000000000..2e02dc0ca9
--- /dev/null
+++ 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
new file mode 100644
index 0000000000..a975476944
--- /dev/null
+++ b/tools/binman/test/u_boot_binman_syms.c
@@ -0,0 +1,14 @@
+/*
+ * Copyright (c) 2017 Google, Inc
+ *
+ * SPDX-License-Identifier: GPL-2.0+
+ *
+ * Simple program to create some binman symbols. This is used by binman tests.
+ */
+
+#define CONFIG_BINMAN
+#include <binman_sym.h>
+
+binman_sym_declare(unsigned long, u_boot_spl, pos);
+binman_sym_declare(unsigned long long, u_boot_spl2, pos);
+binman_sym_declare(unsigned long, u_boot_any, pos);
diff --git a/tools/binman/test/u_boot_binman_syms.lds b/tools/binman/test/u_boot_binman_syms.lds
new file mode 100644
index 0000000000..d3130cdeb3
--- /dev/null
+++ b/tools/binman/test/u_boot_binman_syms.lds
@@ -0,0 +1,30 @@
+/*
+ * Copyright (c) 2016 Google, Inc
+ *
+ * SPDX-License-Identifier: GPL-2.0+
+ */
+
+OUTPUT_FORMAT("elf32-i386", "elf32-i386", "elf32-i386")
+OUTPUT_ARCH(i386)
+ENTRY(_start)
+
+SECTIONS
+{
+ . = 0x00000000;
+ _start = .;
+
+ . = ALIGN(4);
+ .text :
+ {
+ __image_copy_start = .;
+ *(.text*)
+ }
+
+ . = ALIGN(4);
+ .binman_sym_table : {
+ __binman_sym_start = .;
+ KEEP(*(SORT(.binman_sym*)));
+ __binman_sym_end = .;
+ }
+
+}
diff --git a/tools/binman/test/u_boot_binman_syms_bad b/tools/binman/test/u_boot_binman_syms_bad
new file mode 100755
index 0000000000..8da3d9d48f
--- /dev/null
+++ b/tools/binman/test/u_boot_binman_syms_bad
Binary files differ
diff --git a/tools/binman/test/u_boot_binman_syms_bad.c b/tools/binman/test/u_boot_binman_syms_bad.c
new file mode 120000
index 0000000000..939b2e965f
--- /dev/null
+++ b/tools/binman/test/u_boot_binman_syms_bad.c
@@ -0,0 +1 @@
+u_boot_binman_syms.c \ No newline at end of file
diff --git a/tools/binman/test/u_boot_binman_syms_bad.lds b/tools/binman/test/u_boot_binman_syms_bad.lds
new file mode 100644
index 0000000000..0b474b5374
--- /dev/null
+++ b/tools/binman/test/u_boot_binman_syms_bad.lds
@@ -0,0 +1,29 @@
+/*
+ * Copyright (c) 2016 Google, Inc
+ *
+ * SPDX-License-Identifier: GPL-2.0+
+ */
+
+OUTPUT_FORMAT("elf32-i386", "elf32-i386", "elf32-i386")
+OUTPUT_ARCH(i386)
+ENTRY(_start)
+
+SECTIONS
+{
+ . = 0x00000000;
+ _start = .;
+
+ . = ALIGN(4);
+ .text :
+ {
+ *(.text*)
+ }
+
+ . = ALIGN(4);
+ .binman_sym_table : {
+ __binman_sym_start = .;
+ KEEP(*(SORT(.binman_sym*)));
+ __binman_sym_end = .;
+ }
+
+}
diff --git a/tools/binman/test/u_boot_binman_syms_size b/tools/binman/test/u_boot_binman_syms_size
new file mode 100755
index 0000000000..d691e897c0
--- /dev/null
+++ b/tools/binman/test/u_boot_binman_syms_size
Binary files differ
diff --git a/tools/binman/test/u_boot_binman_syms_size.c b/tools/binman/test/u_boot_binman_syms_size.c
new file mode 100644
index 0000000000..ee4c048b28
--- /dev/null
+++ b/tools/binman/test/u_boot_binman_syms_size.c
@@ -0,0 +1,12 @@
+/*
+ * Copyright (c) 2017 Google, Inc
+ *
+ * SPDX-License-Identifier: GPL-2.0+
+ *
+ * Simple program to create some binman symbols. This is used by binman tests.
+ */
+
+#define CONFIG_BINMAN
+#include <binman_sym.h>
+
+binman_sym_declare(char, u_boot_spl, pos);
diff --git a/tools/binman/test/u_boot_ucode_ptr.c b/tools/binman/test/u_boot_ucode_ptr.c
index 24f349fb9e..734d54f0d4 100644
--- a/tools/binman/test/u_boot_ucode_ptr.c
+++ b/tools/binman/test/u_boot_ucode_ptr.c
@@ -4,7 +4,7 @@
* SPDX-License-Identifier: GPL-2.0+
*
* Simple program to create a _dt_ucode_base_size symbol which can be read
- * by 'nm'. This is used by binman tests.
+ * by binutils. This is used by binman tests.
*/
static unsigned long _dt_ucode_base_size[2]