diff options
| author | Tom Rini <trini@konsulko.com> | 2022-07-11 10:18:13 -0400 |
|---|---|---|
| committer | Tom Rini <trini@konsulko.com> | 2022-07-11 14:58:57 -0400 |
| commit | 36b661dc919da318c163a45f4a220d2e3d9db608 (patch) | |
| tree | 268703050f58280feb3287d48eb0cedc974730e1 /tools | |
| parent | e092e3250270a1016c877da7bdd9384f14b1321e (diff) | |
| parent | 05a4859637567b13219efd6f1707fb236648b1b7 (diff) | |
Merge branch 'next'
Diffstat (limited to 'tools')
31 files changed, 920 insertions, 184 deletions
diff --git a/tools/binman/elf.py b/tools/binman/elf.py index afa05e58fdd..6d440ddf21d 100644 --- a/tools/binman/elf.py +++ b/tools/binman/elf.py @@ -25,6 +25,9 @@ try: except: # pragma: no cover ELF_TOOLS = False +# BSYM in little endian, keep in sync with include/binman_sym.h +BINMAN_SYM_MAGIC_VALUE = 0x4d595342 + # Information about an EFL symbol: # section (str): Name of the section containing this symbol # address (int): Address of the symbol (its value) @@ -223,9 +226,12 @@ def LookupAndWriteSymbols(elf_fname, entry, section): raise ValueError('%s has size %d: only 4 and 8 are supported' % (msg, sym.size)) - # Look up the symbol in our entry tables. - value = section.GetImage().LookupImageSymbol(name, sym.weak, msg, - base.address) + if name == '_binman_sym_magic': + value = BINMAN_SYM_MAGIC_VALUE + else: + # Look up the symbol in our entry tables. + value = section.GetImage().LookupImageSymbol(name, sym.weak, + msg, base.address) if value is None: value = -1 pack_string = pack_string.lower() diff --git a/tools/binman/elf_test.py b/tools/binman/elf_test.py index 02bc1083749..5a51c64cfee 100644 --- a/tools/binman/elf_test.py +++ b/tools/binman/elf_test.py @@ -127,7 +127,7 @@ class TestElf(unittest.TestCase): elf_fname = self.ElfTestFile('u_boot_binman_syms') with self.assertRaises(ValueError) as e: elf.LookupAndWriteSymbols(elf_fname, entry, section) - self.assertIn('entry_path has offset 4 (size 8) but the contents size ' + self.assertIn('entry_path has offset 8 (size 8) but the contents size ' 'is a', str(e.exception)) def testMissingImageStart(self): @@ -161,18 +161,20 @@ class TestElf(unittest.TestCase): This should produce -1 values for all thress symbols, taking up the first 16 bytes of the image. """ - entry = FakeEntry(24) + entry = FakeEntry(28) section = FakeSection(sym_value=None) elf_fname = self.ElfTestFile('u_boot_binman_syms') elf.LookupAndWriteSymbols(elf_fname, entry, section) - self.assertEqual(tools.get_bytes(255, 20) + tools.get_bytes(ord('a'), 4), - entry.data) + expected = (struct.pack('<L', elf.BINMAN_SYM_MAGIC_VALUE) + + tools.get_bytes(255, 20) + + tools.get_bytes(ord('a'), 4)) + self.assertEqual(expected, entry.data) def testDebug(self): """Check that enabling debug in the elf module produced debug output""" try: tout.init(tout.DEBUG) - entry = FakeEntry(20) + entry = FakeEntry(24) section = FakeSection() elf_fname = self.ElfTestFile('u_boot_binman_syms') with test_util.capture_sys_output() as (stdout, stderr): diff --git a/tools/binman/ftest.py b/tools/binman/ftest.py index b5cf549703a..fa1f421c052 100644 --- a/tools/binman/ftest.py +++ b/tools/binman/ftest.py @@ -43,8 +43,8 @@ from patman import tout # Contents of test files, corresponding to different entry types U_BOOT_DATA = b'1234' U_BOOT_IMG_DATA = b'img' -U_BOOT_SPL_DATA = b'56780123456789abcdefghi' -U_BOOT_TPL_DATA = b'tpl9876543210fedcbazyw' +U_BOOT_SPL_DATA = b'56780123456789abcdefghijklm' +U_BOOT_TPL_DATA = b'tpl9876543210fedcbazywvuts' BLOB_DATA = b'89' ME_DATA = b'0abcd' VGA_DATA = b'vga' @@ -1406,8 +1406,9 @@ class TestFunctional(unittest.TestCase): elf_fname = self.ElfTestFile('u_boot_binman_syms') syms = elf.GetSymbols(elf_fname, ['binman', 'image']) addr = elf.GetSymbolAddress(elf_fname, '__image_copy_start') + self.assertEqual(syms['_binman_sym_magic'].address, addr) self.assertEqual(syms['_binman_u_boot_spl_any_prop_offset'].address, - addr) + addr + 4) self._SetupSplElf('u_boot_binman_syms') data = self._DoReadFileDtb(dts, entry_args=entry_args, @@ -1415,17 +1416,17 @@ class TestFunctional(unittest.TestCase): # The image should contain the symbols from u_boot_binman_syms.c # Note that image_pos is adjusted by the base address of the image, # which is 0x10 in our test image - sym_values = struct.pack('<LQLL', 0x00, - u_boot_offset + len(U_BOOT_DATA), + sym_values = struct.pack('<LLQLL', elf.BINMAN_SYM_MAGIC_VALUE, + 0x00, u_boot_offset + len(U_BOOT_DATA), 0x10 + u_boot_offset, 0x04) - expected = (sym_values + base_data[20:] + + expected = (sym_values + base_data[24:] + tools.get_bytes(0xff, 1) + U_BOOT_DATA + sym_values + - base_data[20:]) + base_data[24:]) self.assertEqual(expected, data) def testSymbols(self): """Test binman can assign symbols embedded in U-Boot""" - self.checkSymbols('053_symbols.dts', U_BOOT_SPL_DATA, 0x18) + self.checkSymbols('053_symbols.dts', U_BOOT_SPL_DATA, 0x1c) def testSymbolsNoDtb(self): """Test binman can assign symbols embedded in U-Boot SPL""" @@ -3610,20 +3611,20 @@ class TestFunctional(unittest.TestCase): def _CheckSymbolsTplSection(self, dts, expected_vals): data = self._DoReadFile(dts) - sym_values = struct.pack('<LQLL', *expected_vals) + sym_values = struct.pack('<LLQLL', elf.BINMAN_SYM_MAGIC_VALUE, *expected_vals) upto1 = 4 + len(U_BOOT_SPL_DATA) - expected1 = tools.get_bytes(0xff, 4) + sym_values + U_BOOT_SPL_DATA[20:] + expected1 = tools.get_bytes(0xff, 4) + sym_values + U_BOOT_SPL_DATA[24:] self.assertEqual(expected1, data[:upto1]) upto2 = upto1 + 1 + len(U_BOOT_SPL_DATA) - expected2 = tools.get_bytes(0xff, 1) + sym_values + U_BOOT_SPL_DATA[20:] + expected2 = tools.get_bytes(0xff, 1) + sym_values + U_BOOT_SPL_DATA[24:] self.assertEqual(expected2, data[upto1:upto2]) - upto3 = 0x34 + len(U_BOOT_DATA) + upto3 = 0x3c + len(U_BOOT_DATA) expected3 = tools.get_bytes(0xff, 1) + U_BOOT_DATA self.assertEqual(expected3, data[upto2:upto3]) - expected4 = sym_values + U_BOOT_TPL_DATA[20:] + expected4 = sym_values + U_BOOT_TPL_DATA[24:] self.assertEqual(expected4, data[upto3:upto3 + len(U_BOOT_TPL_DATA)]) def testSymbolsTplSection(self): @@ -3631,14 +3632,14 @@ class TestFunctional(unittest.TestCase): self._SetupSplElf('u_boot_binman_syms') self._SetupTplElf('u_boot_binman_syms') self._CheckSymbolsTplSection('149_symbols_tpl.dts', - [0x04, 0x1c, 0x10 + 0x34, 0x04]) + [0x04, 0x20, 0x10 + 0x3c, 0x04]) def testSymbolsTplSectionX86(self): """Test binman can assign symbols in a section with end-at-4gb""" self._SetupSplElf('u_boot_binman_syms_x86') self._SetupTplElf('u_boot_binman_syms_x86') self._CheckSymbolsTplSection('155_symbols_tpl_x86.dts', - [0xffffff04, 0xffffff1c, 0xffffff34, + [0xffffff04, 0xffffff20, 0xffffff3c, 0x04]) def testPackX86RomIfwiSectiom(self): @@ -4488,7 +4489,7 @@ class TestFunctional(unittest.TestCase): def testSymbolsSubsection(self): """Test binman can assign symbols from a subsection""" - self.checkSymbols('187_symbols_sub.dts', U_BOOT_SPL_DATA, 0x18) + self.checkSymbols('187_symbols_sub.dts', U_BOOT_SPL_DATA, 0x1c) def testReadImageEntryArg(self): """Test reading an image that would need an entry arg to generate""" diff --git a/tools/binman/main.py b/tools/binman/main.py index 5fb9404ef6a..14432a8d0dc 100755 --- a/tools/binman/main.py +++ b/tools/binman/main.py @@ -13,7 +13,6 @@ import os import site import sys import traceback -import unittest # Get the absolute path to this file at run-time our_path = os.path.dirname(os.path.realpath(__file__)) @@ -73,19 +72,18 @@ def RunTests(debug, verbosity, processes, test_preserve_dirs, args, toolpath): from binman import image_test import doctest - result = unittest.TestResult() test_name = args and args[0] or None # Run the entry tests first ,since these need to be the first to import the # 'entry' module. - test_util.run_test_suites( - result, debug, verbosity, test_preserve_dirs, processes, test_name, + result = test_util.run_test_suites( + 'binman', debug, verbosity, test_preserve_dirs, processes, test_name, toolpath, [bintool_test.TestBintool, entry_test.TestEntry, ftest.TestFunctional, fdt_test.TestFdt, elf_test.TestElf, image_test.TestImage, cbfs_util_test.TestCbfs, fip_util_test.TestFip]) - return test_util.report_result('binman', test_name, result) + return (0 if result.wasSuccessful() else 1) def RunTestCoverage(toolpath): """Run the tests and check that we get 100% coverage""" diff --git a/tools/binman/test/021_image_pad.dts b/tools/binman/test/021_image_pad.dts index 1ff8dab296f..c5abbbcdd6a 100644 --- a/tools/binman/test/021_image_pad.dts +++ b/tools/binman/test/021_image_pad.dts @@ -10,7 +10,7 @@ }; u-boot { - offset = <24>; + offset = <28>; }; }; }; diff --git a/tools/binman/test/024_sorted.dts b/tools/binman/test/024_sorted.dts index b79d9adf682..b54f9b14191 100644 --- a/tools/binman/test/024_sorted.dts +++ b/tools/binman/test/024_sorted.dts @@ -7,7 +7,7 @@ binman { sort-by-offset; u-boot { - offset = <26>; + offset = <30>; }; u-boot-spl { diff --git a/tools/binman/test/028_pack_4gb_outside.dts b/tools/binman/test/028_pack_4gb_outside.dts index 11a1f6059e2..b6ad7fb56a5 100644 --- a/tools/binman/test/028_pack_4gb_outside.dts +++ b/tools/binman/test/028_pack_4gb_outside.dts @@ -13,7 +13,7 @@ }; u-boot-spl { - offset = <0xffffffe7>; + offset = <0xffffffe3>; }; }; }; diff --git a/tools/binman/test/029_x86_rom.dts b/tools/binman/test/029_x86_rom.dts index 88aa007bbae..ad8f9d6e1bd 100644 --- a/tools/binman/test/029_x86_rom.dts +++ b/tools/binman/test/029_x86_rom.dts @@ -7,13 +7,13 @@ binman { sort-by-offset; end-at-4gb; - size = <32>; + size = <36>; u-boot { - offset = <0xffffffe0>; + offset = <0xffffffdc>; }; u-boot-spl { - offset = <0xffffffe7>; + offset = <0xffffffe3>; }; }; }; diff --git a/tools/binman/test/053_symbols.dts b/tools/binman/test/053_symbols.dts index 29658092764..b28f34a72fa 100644 --- a/tools/binman/test/053_symbols.dts +++ b/tools/binman/test/053_symbols.dts @@ -10,7 +10,7 @@ }; u-boot { - offset = <0x18>; + offset = <0x1c>; }; u-boot-spl2 { diff --git a/tools/binman/test/149_symbols_tpl.dts b/tools/binman/test/149_symbols_tpl.dts index 0a4ab3f1fab..4e649c45978 100644 --- a/tools/binman/test/149_symbols_tpl.dts +++ b/tools/binman/test/149_symbols_tpl.dts @@ -11,12 +11,12 @@ }; u-boot-spl2 { - offset = <0x1c>; + offset = <0x20>; type = "u-boot-spl"; }; u-boot { - offset = <0x34>; + offset = <0x3c>; }; section { diff --git a/tools/binman/test/155_symbols_tpl_x86.dts b/tools/binman/test/155_symbols_tpl_x86.dts index 9d7dc51b3d9..e1ce33e67fb 100644 --- a/tools/binman/test/155_symbols_tpl_x86.dts +++ b/tools/binman/test/155_symbols_tpl_x86.dts @@ -14,12 +14,12 @@ }; u-boot-spl2 { - offset = <0xffffff1c>; + offset = <0xffffff20>; type = "u-boot-spl"; }; u-boot { - offset = <0xffffff34>; + offset = <0xffffff3c>; }; section { diff --git a/tools/binman/test/187_symbols_sub.dts b/tools/binman/test/187_symbols_sub.dts index 54511a73711..3ab62d37215 100644 --- a/tools/binman/test/187_symbols_sub.dts +++ b/tools/binman/test/187_symbols_sub.dts @@ -11,7 +11,7 @@ }; u-boot { - offset = <24>; + offset = <28>; }; }; diff --git a/tools/binman/test/Makefile b/tools/binman/test/Makefile index 57057e2d588..bea8567c9b4 100644 --- a/tools/binman/test/Makefile +++ b/tools/binman/test/Makefile @@ -21,7 +21,7 @@ CC = $(CROSS_COMPILE)gcc OBJCOPY = $(CROSS_COMPILE)objcopy VPATH := $(SRC) -CFLAGS := -march=i386 -m32 -nostdlib -I $(SRC)../../../include \ +CFLAGS := -march=i386 -m32 -nostdlib -I $(SRC)../../../include -I $(SRC) \ -Wl,--no-dynamic-linker LDS_UCODE := -T $(SRC)u_boot_ucode_ptr.lds diff --git a/tools/binman/test/generated/autoconf.h b/tools/binman/test/generated/autoconf.h new file mode 100644 index 00000000000..6a23039f469 --- /dev/null +++ b/tools/binman/test/generated/autoconf.h @@ -0,0 +1,3 @@ +#define CONFIG_BINMAN 1 +#define CONFIG_SPL_BUILD 1 +#define CONFIG_SPL_BINMAN_SYMBOLS 1 diff --git a/tools/binman/test/u_boot_binman_syms.c b/tools/binman/test/u_boot_binman_syms.c index 37fc339ce84..ed761246aec 100644 --- a/tools/binman/test/u_boot_binman_syms.c +++ b/tools/binman/test/u_boot_binman_syms.c @@ -5,9 +5,13 @@ * Simple program to create some binman symbols. This is used by binman tests. */ -#define CONFIG_BINMAN +typedef unsigned long ulong; + +#include <linux/kconfig.h> #include <binman_sym.h> +DECLARE_BINMAN_MAGIC_SYM; + binman_sym_declare(unsigned long, u_boot_spl_any, offset); binman_sym_declare(unsigned long long, u_boot_spl2, offset); binman_sym_declare(unsigned long, u_boot_any, image_pos); diff --git a/tools/binman/test/u_boot_binman_syms_size.c b/tools/binman/test/u_boot_binman_syms_size.c index 7224bc1863c..fa41b3d9a33 100644 --- a/tools/binman/test/u_boot_binman_syms_size.c +++ b/tools/binman/test/u_boot_binman_syms_size.c @@ -5,7 +5,11 @@ * Simple program to create some binman symbols. This is used by binman tests. */ -#define CONFIG_BINMAN +typedef unsigned long ulong; + +#include <linux/kconfig.h> #include <binman_sym.h> +DECLARE_BINMAN_MAGIC_SYM; + binman_sym_declare(char, u_boot_spl, pos); diff --git a/tools/buildman/main.py b/tools/buildman/main.py index 3b6af240802..67c560c48d3 100755 --- a/tools/buildman/main.py +++ b/tools/buildman/main.py @@ -11,7 +11,6 @@ import multiprocessing import os import re import sys -import unittest # Bring in the patman libraries our_path = os.path.dirname(os.path.realpath(__file__)) @@ -34,19 +33,18 @@ def RunTests(skip_net_tests, verboose, args): from buildman import test import doctest - result = unittest.TestResult() test_name = args and args[0] or None if skip_net_tests: test.use_network = False # Run the entry tests first ,since these need to be the first to import the # 'entry' module. - test_util.run_test_suites( - result, False, verboose, False, None, test_name, [], + result = test_util.run_test_suites( + 'buildman', False, verboose, False, None, test_name, [], [test.TestBuild, func_test.TestFunctional, 'buildman.toolchain', 'patman.gitutil']) - return test_util.report_result('buildman', test_name, result) + return (0 if result.wasSuccessful() else 1) options, args = cmdline.ParseArgs() diff --git a/tools/concurrencytest/concurrencytest.py b/tools/concurrencytest/concurrencytest.py index 5e88b94f415..1c4f03f37e5 100644 --- a/tools/concurrencytest/concurrencytest.py +++ b/tools/concurrencytest/concurrencytest.py @@ -31,6 +31,7 @@ from subunit import ProtocolTestCase, TestProtocolClient from subunit.test_results import AutoTimingTestResultDecorator from testtools import ConcurrentTestSuite, iterate_tests +from testtools.content import TracebackContent, text_content _all__ = [ @@ -43,11 +44,81 @@ _all__ = [ CPU_COUNT = cpu_count() -def fork_for_tests(concurrency_num=CPU_COUNT): +class BufferingTestProtocolClient(TestProtocolClient): + """A TestProtocolClient which can buffer the test outputs + + This class captures the stdout and stderr output streams of the + tests as it runs them, and includes the output texts in the subunit + stream as additional details. + + Args: + stream: A file-like object to write a subunit stream to + buffer (bool): True to capture test stdout/stderr outputs and + include them in the test details + """ + def __init__(self, stream, buffer=True): + super().__init__(stream) + self.buffer = buffer + + def _addOutcome(self, outcome, test, error=None, details=None, + error_permitted=True): + """Report a test outcome to the subunit stream + + The parent class uses this function as a common implementation + for various methods that report successes, errors, failures, etc. + + This version automatically upgrades the error tracebacks to the + new 'details' format by wrapping them in a Content object, so + that we can include the captured test output in the test result + details. + + Args: + outcome: A string describing the outcome - used as the + event name in the subunit stream. + test: The test case whose outcome is to be reported + error: Standard unittest positional argument form - an + exc_info tuple. + details: New Testing-in-python drafted API; a dict from + string to subunit.Content objects. + error_permitted: If True then one and only one of error or + details must be supplied. If False then error must not + be supplied and details is still optional. + """ + if details is None: + details = {} + + # Parent will raise an exception if error_permitted is False but + # error is not None. We want that exception in that case, so + # don't touch error when error_permitted is explicitly False. + if error_permitted and error is not None: + # Parent class prefers error over details + details['traceback'] = TracebackContent(error, test) + error_permitted = False + error = None + + if self.buffer: + stdout = sys.stdout.getvalue() + if stdout: + details['stdout'] = text_content(stdout) + + stderr = sys.stderr.getvalue() + if stderr: + details['stderr'] = text_content(stderr) + + return super()._addOutcome(outcome, test, error=error, + details=details, error_permitted=error_permitted) + + +def fork_for_tests(concurrency_num=CPU_COUNT, buffer=False): """Implementation of `make_tests` used to construct `ConcurrentTestSuite`. :param concurrency_num: number of processes to use. """ + if buffer: + test_protocol_client_class = BufferingTestProtocolClient + else: + test_protocol_client_class = TestProtocolClient + def do_fork(suite): """Take suite and start up multiple runners by forking (Unix only). @@ -76,7 +147,7 @@ def fork_for_tests(concurrency_num=CPU_COUNT): # child actually gets keystrokes for pdb etc). sys.stdin.close() subunit_result = AutoTimingTestResultDecorator( - TestProtocolClient(stream) + test_protocol_client_class(stream) ) process_suite.run(subunit_result) except: @@ -93,7 +164,13 @@ def fork_for_tests(concurrency_num=CPU_COUNT): else: os.close(c2pwrite) stream = os.fdopen(c2pread, 'rb') - test = ProtocolTestCase(stream) + # If we don't pass the second argument here, it defaults + # to sys.stdout.buffer down the line. But if we don't + # pass it *now*, it may be resolved after sys.stdout is + # replaced with a StringIO (to capture tests' outputs) + # which doesn't have a buffer attribute and can end up + # occasionally causing a 'broken-runner' error. + test = ProtocolTestCase(stream, sys.stdout.buffer) result.append(test) return result return do_fork diff --git a/tools/dtoc/main.py b/tools/dtoc/main.py index fac9db9c786..5508759d4d5 100755 --- a/tools/dtoc/main.py +++ b/tools/dtoc/main.py @@ -24,7 +24,6 @@ see doc/driver-model/of-plat.rst from argparse import ArgumentParser import os import sys -import unittest # Bring in the patman libraries our_path = os.path.dirname(os.path.realpath(__file__)) @@ -49,18 +48,18 @@ def run_tests(processes, args): from dtoc import test_src_scan from dtoc import test_dtoc - result = unittest.TestResult() sys.argv = [sys.argv[0]] test_name = args.files and args.files[0] or None test_dtoc.setup() - test_util.run_test_suites( - result, debug=True, verbosity=1, test_preserve_dirs=False, + result = test_util.run_test_suites( + toolname='dtoc', debug=True, verbosity=1, test_preserve_dirs=False, processes=processes, test_name=test_name, toolpath=[], class_and_module_list=[test_dtoc.TestDtoc,test_src_scan.TestSrcScan]) - return test_util.report_result('binman', test_name, result) + return (0 if result.wasSuccessful() else 1) + def RunTestCoverage(): """Run the tests and check that we get 100% coverage""" diff --git a/tools/dtoc/test_dtoc.py b/tools/dtoc/test_dtoc.py index c81bcc9c32f..879ca2ab2bf 100755 --- a/tools/dtoc/test_dtoc.py +++ b/tools/dtoc/test_dtoc.py @@ -616,8 +616,11 @@ struct dm_test_pdata __attribute__ ((section (".priv_data"))) u8 _denx_u_boot_test_bus_priv_some_bus[sizeof(struct dm_test_priv)] \t__attribute__ ((section (".priv_data"))); #include <dm/test.h> -u8 _denx_u_boot_test_bus_ucplat_some_bus[sizeof(struct dm_test_uclass_priv)] +u8 _denx_u_boot_test_bus_ucplat_some_bus[sizeof(struct dm_test_uclass_plat)] \t__attribute__ ((section (".priv_data"))); +#include <dm/test.h> +u8 _denx_u_boot_test_bus_uc_priv_some_bus[sizeof(struct dm_test_uclass_priv)] + __attribute__ ((section (".priv_data"))); #include <test.h> DM_DEVICE_INST(some_bus) = { @@ -628,6 +631,7 @@ DM_DEVICE_INST(some_bus) = { \t.driver_data\t= DM_TEST_TYPE_FIRST, \t.priv_\t\t= _denx_u_boot_test_bus_priv_some_bus, \t.uclass\t\t= DM_UCLASS_REF(testbus), +\t.uclass_priv_ = _denx_u_boot_test_bus_uc_priv_some_bus, \t.uclass_node\t= { \t\t.prev = &DM_UCLASS_REF(testbus)->dev_head, \t\t.next = &DM_UCLASS_REF(testbus)->dev_head, diff --git a/tools/dtoc/test_fdt.py b/tools/dtoc/test_fdt.py index 914ed6aed59..3baf4437cdd 100755 --- a/tools/dtoc/test_fdt.py +++ b/tools/dtoc/test_fdt.py @@ -780,25 +780,17 @@ def RunTests(args): Args: args: List of positional args provided to fdt. This can hold a test name to execute (as in 'fdt -t testFdt', for example) + + Returns: + Return code, 0 on success """ - result = unittest.TestResult() - sys.argv = [sys.argv[0]] test_name = args and args[0] or None - for module in (TestFdt, TestNode, TestProp, TestFdtUtil): - if test_name: - try: - suite = unittest.TestLoader().loadTestsFromName(test_name, module) - except AttributeError: - continue - else: - suite = unittest.TestLoader().loadTestsFromTestCase(module) - suite.run(result) - - print(result) - for _, err in result.errors: - print(err) - for _, err in result.failures: - print(err) + result = test_util.run_test_suites( + 'test_fdt', False, False, False, None, test_name, None, + [TestFdt, TestNode, TestProp, TestFdtUtil]) + + return (0 if result.wasSuccessful() else 1) + if __name__ != '__main__': sys.exit(1) @@ -816,6 +808,7 @@ parser.add_option('-T', '--test-coverage', action='store_true', # Run our meagre tests if options.test: - RunTests(args) + ret_code = RunTests(args) + sys.exit(ret_code) elif options.test_coverage: RunTestCoverage() diff --git a/tools/env/fw_env.c b/tools/env/fw_env.c index 31afef6f3b1..908a162202d 100644 --- a/tools/env/fw_env.c +++ b/tools/env/fw_env.c @@ -1713,6 +1713,67 @@ static int check_device_config(int dev) return rc; } +static int find_nvmem_device(void) +{ + const char *path = "/sys/bus/nvmem/devices"; + struct dirent *dent; + char *nvmem = NULL; + char comp[256]; + char buf[32]; + int bytes; + DIR *dir; + + dir = opendir(path); + if (!dir) { + return -EIO; + } + + while (!nvmem && (dent = readdir(dir))) { + FILE *fp; + + if (!strcmp(dent->d_name, ".") || !strcmp(dent->d_name, "..")) { + continue; + } + + bytes = snprintf(comp, sizeof(comp), "%s/%s/of_node/compatible", path, dent->d_name); + if (bytes < 0 || bytes == sizeof(comp)) { + continue; + } + + fp = fopen(comp, "r"); + if (!fp) { + continue; + } + + fread(buf, sizeof(buf), 1, fp); + + if (!strcmp(buf, "u-boot,env")) { + bytes = asprintf(&nvmem, "%s/%s/nvmem", path, dent->d_name); + if (bytes < 0) { + nvmem = NULL; + } + } + + fclose(fp); + } + + closedir(dir); + + if (nvmem) { + struct stat s; + + stat(nvmem, &s); + + DEVNAME(0) = nvmem; + DEVOFFSET(0) = 0; + ENVSIZE(0) = s.st_size; + + return 0; + } + + return -ENOENT; +} + static int parse_config(struct env_opts *opts) { int rc; @@ -1723,9 +1784,12 @@ static int parse_config(struct env_opts *opts) #if defined(CONFIG_FILE) /* Fills in DEVNAME(), ENVSIZE(), DEVESIZE(). Or don't. */ if (get_config(opts->config_file)) { - fprintf(stderr, "Cannot parse config file '%s': %m\n", - opts->config_file); - return -1; + if (find_nvmem_device()) { + fprintf(stderr, "Cannot parse config file '%s': %m\n", + opts->config_file); + fprintf(stderr, "Failed to find NVMEM device\n"); + return -1; + } } #else DEVNAME(0) = DEVICE1_NAME; diff --git a/tools/fit_image.c b/tools/fit_image.c index 1884a2eb0b9..979f2411ee0 100644 --- a/tools/fit_image.c +++ b/tools/fit_image.c @@ -199,15 +199,36 @@ static void get_basename(char *str, int size, const char *fname) } /** - * add_crc_node() - Add a hash node to request a CRC checksum for an image + * add_hash_node() - Add a hash or signature node * + * @params: Image parameters * @fdt: Device tree to add to (in sequential-write mode) + * + * If there is a key name hint, try to sign the images. Otherwise, just add a + * CRC. + * + * Return: 0 on success, or -1 on failure */ -static void add_crc_node(void *fdt) +static int add_hash_node(struct image_tool_params *params, void *fdt) { - fdt_begin_node(fdt, "hash-1"); - fdt_property_string(fdt, FIT_ALGO_PROP, "crc32"); + if (params->keyname) { + if (!params->algo_name) { + fprintf(stderr, + "%s: Algorithm name must be specified\n", + params->cmdname); + return -1; + } + + fdt_begin_node(fdt, "signature-1"); + fdt_property_string(fdt, FIT_ALGO_PROP, params->algo_name); + fdt_property_string(fdt, FIT_KEY_HINT, params->keyname); + } else { + fdt_begin_node(fdt, "hash-1"); + fdt_property_string(fdt, FIT_ALGO_PROP, "crc32"); + } + fdt_end_node(fdt); + return 0; } /** @@ -248,7 +269,9 @@ static int fit_write_images(struct image_tool_params *params, char *fdt) ret = fdt_property_file(params, fdt, FIT_DATA_PROP, params->datafile); if (ret) return ret; - add_crc_node(fdt); + ret = add_hash_node(params, fdt); + if (ret) + return ret; fdt_end_node(fdt); /* Now the device tree files if available */ @@ -271,7 +294,9 @@ static int fit_write_images(struct image_tool_params *params, char *fdt) genimg_get_arch_short_name(params->arch)); fdt_property_string(fdt, FIT_COMP_PROP, genimg_get_comp_short_name(IH_COMP_NONE)); - add_crc_node(fdt); + ret = add_hash_node(params, fdt); + if (ret) + return ret; fdt_end_node(fdt); } @@ -289,7 +314,9 @@ static int fit_write_images(struct image_tool_params *params, char *fdt) params->fit_ramdisk); if (ret) return ret; - add_crc_node(fdt); + ret = add_hash_node(params, fdt); + if (ret) + return ret; fdt_end_node(fdt); } diff --git a/tools/imagetool.h b/tools/imagetool.h index 05dd94d1084..ca7c2e48ba9 100644 --- a/tools/imagetool.h +++ b/tools/imagetool.h @@ -71,6 +71,7 @@ struct image_tool_params { const char *keydir; /* Directory holding private keys */ const char *keydest; /* Destination .dtb for public key */ const char *keyfile; /* Filename of private or public key */ + const char *keyname; /* Key name "hint" */ const char *comment; /* Comment to add to signature node */ /* Algorithm name to use for hashing/signing or NULL to use the one * specified in the its */ diff --git a/tools/mips-relocs.c b/tools/mips-relocs.c index 625258085b6..5db610f5c77 100644 --- a/tools/mips-relocs.c +++ b/tools/mips-relocs.c @@ -312,7 +312,7 @@ int main(int argc, char *argv[]) goto out_free_relocs; } - rel_pfx = is_64 ? ".rela." : ".rel."; + rel_pfx = is_64 ? ".rela" : ".rel"; for (i = 0; i < ehdr_field(e_shnum); i++) { sh_type = shdr_field(i, sh_type); @@ -321,10 +321,11 @@ int main(int argc, char *argv[]) sh_name = shstr(shdr_field(i, sh_name)); if (strncmp(sh_name, rel_pfx, strlen(rel_pfx))) { - if (strcmp(sh_name, ".rel") && strcmp(sh_name, ".rel.dyn")) - fprintf(stderr, "WARNING: Unexpected reloc section name '%s'\n", sh_name); + fprintf(stderr, "WARNING: Unexpected reloc section name '%s'\n", sh_name); continue; } + if (!strcmp(sh_name, ".rel") || !strcmp(sh_name, ".rel.dyn")) + continue; /* * Skip reloc sections which either don't correspond to another @@ -334,7 +335,7 @@ int main(int argc, char *argv[]) */ skip = true; for (j = 0; j < ehdr_field(e_shnum); j++) { - if (strcmp(&sh_name[strlen(rel_pfx) - 1], shstr(shdr_field(j, sh_name)))) + if (strcmp(&sh_name[strlen(rel_pfx)], shstr(shdr_field(j, sh_name)))) continue; skip = !(shdr_field(j, sh_flags) & SHF_ALLOC); diff --git a/tools/mkimage.c b/tools/mkimage.c index 5c6a60e8513..0e1198b4113 100644 --- a/tools/mkimage.c +++ b/tools/mkimage.c @@ -119,6 +119,7 @@ static void usage(const char *msg) "Signing / verified boot options: [-k keydir] [-K dtb] [ -c <comment>] [-p addr] [-r] [-N engine]\n" " -k => set directory containing private keys\n" " -K => write public keys to this .dtb file\n" + " -g => set key name hint\n" " -G => use this signing key (in lieu of -k)\n" " -c => add comment in signature node\n" " -F => re-sign existing FIT image\n" @@ -163,7 +164,7 @@ static void process_args(int argc, char **argv) int opt; while ((opt = getopt(argc, argv, - "a:A:b:B:c:C:d:D:e:Ef:FG:k:i:K:ln:N:p:o:O:rR:qstT:vVx")) != -1) { + "a:A:b:B:c:C:d:D:e:Ef:Fg:G:k:i:K:ln:N:p:o:O:rR:qstT:vVx")) != -1) { switch (opt) { case 'a': params.addr = strtoull(optarg, &ptr, 16); @@ -239,6 +240,8 @@ static void process_args(int argc, char **argv) params.type = IH_TYPE_FLATDT; params.fflag = 1; break; + case 'g': + params.keyname = optarg; case 'G': params.keyfile = optarg; break; diff --git a/tools/patman/main.py b/tools/patman/main.py index 2a2ac457093..66d4806c8d8 100755 --- a/tools/patman/main.py +++ b/tools/patman/main.py @@ -12,7 +12,6 @@ import re import shutil import sys import traceback -import unittest if __name__ == "__main__": # Allow 'from patman import xxx to work' @@ -134,13 +133,12 @@ if args.cmd == 'test': import doctest from patman import func_test - result = unittest.TestResult() - test_util.run_test_suites( - result, False, False, False, None, None, None, + result = test_util.run_test_suites( + 'patman', False, False, False, None, None, None, [test_checkpatch.TestPatch, func_test.TestFunctional, 'gitutil', 'settings', 'terminal']) - sys.exit(test_util.report_result('patman', args.testname, result)) + sys.exit(0 if result.wasSuccessful() else 1) # Process commits, produce patches files, check them, email them elif args.cmd == 'send': diff --git a/tools/patman/settings.py b/tools/patman/settings.py index 7c2b5c196c0..4c847fe88fd 100644 --- a/tools/patman/settings.py +++ b/tools/patman/settings.py @@ -246,8 +246,10 @@ def _UpdateDefaults(main_parser, config): # Collect the defaults from each parser defaults = {} + parser_defaults = [] for parser in parsers: pdefs = parser.parse_known_args()[0] + parser_defaults.append(pdefs) defaults.update(vars(pdefs)) # Go through the settings and collect defaults @@ -264,8 +266,11 @@ def _UpdateDefaults(main_parser, config): else: print("WARNING: Unknown setting %s" % name) - # Set all the defaults (this propagates through all subparsers) + # Set all the defaults and manually propagate them to subparsers main_parser.set_defaults(**defaults) + for parser, pdefs in zip(parsers, parser_defaults): + parser.set_defaults(**{ k: v for k, v in defaults.items() + if k in pdefs }) def _ReadAliasFile(fname): """Read in the U-Boot git alias file if it exists. diff --git a/tools/patman/test_util.py b/tools/patman/test_util.py index c60eb3628e2..c27e0b39e5f 100644 --- a/tools/patman/test_util.py +++ b/tools/patman/test_util.py @@ -15,6 +15,7 @@ from patman import command from io import StringIO +buffer_outputs = True use_concurrent = True try: from concurrencytest.concurrencytest import ConcurrentTestSuite @@ -102,49 +103,85 @@ def capture_sys_output(): sys.stdout, sys.stderr = old_out, old_err -def report_result(toolname:str, test_name: str, result: unittest.TestResult): - """Report the results from a suite of tests +class FullTextTestResult(unittest.TextTestResult): + """A test result class that can print extended text results to a stream + + This is meant to be used by a TestRunner as a result class. Like + TextTestResult, this prints out the names of tests as they are run, + errors as they occur, and a summary of the results at the end of the + test run. Beyond those, this prints information about skipped tests, + expected failures and unexpected successes. Args: - toolname: Name of the tool that ran the tests - test_name: Name of test that was run, or None for all - result: A unittest.TestResult object containing the results + stream: A file-like object to write results to + descriptions (bool): True to print descriptions with test names + verbosity (int): Detail of printed output per test as they run + Test stdout and stderr always get printed when buffering + them is disabled by the test runner. In addition to that, + 0: Print nothing + 1: Print a dot per test + 2: Print test names + 3: Print test names, and buffered outputs for failing tests """ - # Remove errors which just indicate a missing test. Since Python v3.5 If an - # ImportError or AttributeError occurs while traversing name then a - # synthetic test that raises that error when run will be returned. These - # errors are included in the errors accumulated by result.errors. - if test_name: - errors = [] - - for test, err in result.errors: - if ("has no attribute '%s'" % test_name) not in err: - errors.append((test, err)) - result.testsRun -= 1 - result.errors = errors - - print(result) - for test, err in result.errors: - print(test.id(), err) - for test, err in result.failures: - print(err, result.failures) - if result.skipped: - print('%d %s test%s SKIPPED:' % (len(result.skipped), toolname, - 's' if len(result.skipped) > 1 else '')) - for skip_info in result.skipped: - print('%s: %s' % (skip_info[0], skip_info[1])) - if result.errors or result.failures: - print('%s tests FAILED' % toolname) - return 1 - return 0 - - -def run_test_suites(result, debug, verbosity, test_preserve_dirs, processes, + def __init__(self, stream, descriptions, verbosity): + self.verbosity = verbosity + super().__init__(stream, descriptions, verbosity) + + def printErrors(self): + "Called by TestRunner after test run to summarize the tests" + # The parent class doesn't keep unexpected successes in the same + # format as the rest. Adapt it to what printErrorList expects. + unexpected_successes = [ + (test, 'Test was expected to fail, but succeeded.\n') + for test in self.unexpectedSuccesses + ] + + super().printErrors() # FAIL and ERROR + self.printErrorList('SKIP', self.skipped) + self.printErrorList('XFAIL', self.expectedFailures) + self.printErrorList('XPASS', unexpected_successes) + + def addError(self, test, err): + """Called when an error has occurred.""" + super().addError(test, err) + self._mirrorOutput &= self.verbosity >= 3 + + def addFailure(self, test, err): + """Called when a test has failed.""" + super().addFailure(test, err) + self._mirrorOutput &= self.verbosity >= 3 + + def addSubTest(self, test, subtest, err): + """Called at the end of a subtest.""" + super().addSubTest(test, subtest, err) + self._mirrorOutput &= self.verbosity >= 3 + + def addSuccess(self, test): + """Called when a test has completed successfully""" + super().addSuccess(test) + # Don't print stdout/stderr for successful tests + self._mirrorOutput = False + + def addSkip(self, test, reason): + """Called when a test is skipped.""" + # Add empty line to keep spacing consistent with other results + if not reason.endswith('\n'): + reason += '\n' + super().addSkip(test, reason) + self._mirrorOutput &= self.verbosity >= 3 + + def addExpectedFailure(self, test, err): + """Called when an expected failure/error occurred.""" + super().addExpectedFailure(test, err) + self._mirrorOutput &= self.verbosity >= 3 + + +def run_test_suites(toolname, debug, verbosity, test_preserve_dirs, processes, test_name, toolpath, class_and_module_list): """Run a series of test suites and collect the results Args: - result: A unittest.TestResult object to add the results to + toolname: Name of the tool that ran the tests debug: True to enable debugging, which shows a full stack trace on error verbosity: Verbosity level to use (0-4) test_preserve_dirs: True to preserve the input directory used by tests @@ -158,11 +195,6 @@ def run_test_suites(result, debug, verbosity, test_preserve_dirs, processes, class_and_module_list: List of test classes (type class) and module names (type str) to run """ - for module in class_and_module_list: - if isinstance(module, str) and (not test_name or test_name == module): - suite = doctest.DocTestSuite(module) - suite.run(result) - sys.argv = [sys.argv[0]] if debug: sys.argv.append('-D') @@ -174,6 +206,22 @@ def run_test_suites(result, debug, verbosity, test_preserve_dirs, processes, suite = unittest.TestSuite() loader = unittest.TestLoader() + runner = unittest.TextTestRunner( + stream=sys.stdout, + verbosity=(1 if verbosity is None else verbosity), + buffer=buffer_outputs, + resultclass=FullTextTestResult, + ) + + if use_concurrent and processes != 1: + suite = ConcurrentTestSuite(suite, + fork_for_tests(processes or multiprocessing.cpu_count(), + buffer=buffer_outputs)) + + for module in class_and_module_list: + if isinstance(module, str) and (not test_name or test_name == module): + suite.addTests(doctest.DocTestSuite(module)) + for module in class_and_module_list: if isinstance(module, str): continue @@ -184,15 +232,17 @@ def run_test_suites(result, debug, verbosity, test_preserve_dirs, processes, preserve_outdirs=test_preserve_dirs and test_name is not None, toolpath=toolpath, verbosity=verbosity) if test_name: - try: + # Since Python v3.5 If an ImportError or AttributeError occurs + # while traversing a name then a synthetic test that raises that + # error when run will be returned. Check that the requested test + # exists, otherwise these errors are included in the results. + if test_name in loader.getTestCaseNames(module): suite.addTests(loader.loadTestsFromName(test_name, module)) - except AttributeError: - continue else: suite.addTests(loader.loadTestsFromTestCase(module)) - if use_concurrent and processes != 1: - concurrent_suite = ConcurrentTestSuite(suite, - fork_for_tests(processes or multiprocessing.cpu_count())) - concurrent_suite.run(result) - else: - suite.run(result) + + print(f" Running {toolname} tests ".center(70, "=")) + result = runner.run(suite) + print() + + return result diff --git a/tools/relocate-rela.c b/tools/relocate-rela.c index f0bc548617a..090fb1acb20 100644 --- a/tools/relocate-rela.c +++ b/tools/relocate-rela.c @@ -20,6 +20,10 @@ #define R_AARCH64_RELATIVE 1027 #endif +static int ei_class; + +static uint64_t rela_start, rela_end, text_base, dyn_start; + static const bool debug_en; static void debug(const char *fmt, ...) @@ -52,58 +56,310 @@ static bool supported_rela(Elf64_Rela *rela) } } -static bool read_num(const char *str, uint64_t *num) +static int decode_elf64(FILE *felf, char **argv) { - char *endptr; - *num = strtoull(str, &endptr, 16); - return str[0] && !endptr[0]; + size_t size; + Elf64_Ehdr header; + uint64_t section_header_base, section_header_size, sh_offset, sh_size; + Elf64_Shdr *sh_table; /* Elf symbol table */ + int ret, i, machine; + char *sh_str; + + debug("64bit version\n"); + + /* Make sure we are at start */ + rewind(felf); + + size = fread(&header, 1, sizeof(header), felf); + if (size != sizeof(header)) { + fclose(felf); + return 25; + } + + machine = header.e_machine; + debug("Machine\t%d\n", machine); + + if (machine != EM_AARCH64) { + fprintf(stderr, "%s: Not supported machine type\n", argv[0]); + return 30; + } + + text_base = header.e_entry; + section_header_base = header.e_shoff; + section_header_size = header.e_shentsize * header.e_shnum; + + sh_table = malloc(section_header_size); + if (!sh_table) { + fprintf(stderr, "%s: Cannot allocate space for section header\n", + argv[0]); + fclose(felf); + return 26; + } + + ret = fseek(felf, section_header_base, SEEK_SET); + if (ret) { + fprintf(stderr, "%s: Can't set pointer to section header: %x/%lx\n", + argv[0], ret, section_header_base); + free(sh_table); + fclose(felf); + return 26; + } + + size = fread(sh_table, 1, section_header_size, felf); + if (size != section_header_size) { + fprintf(stderr, "%s: Can't read section header: %lx/%lx\n", + argv[0], size, section_header_size); + free(sh_table); + fclose(felf); + return 27; + } + + sh_size = sh_table[header.e_shstrndx].sh_size; + debug("e_shstrndx\t0x%08x\n", header.e_shstrndx); + debug("sh_size\t\t0x%08lx\n", sh_size); + + sh_str = malloc(sh_size); + if (!sh_str) { + fprintf(stderr, "malloc failed\n"); + free(sh_table); + fclose(felf); + return 28; + } + + /* + * Specifies the byte offset from the beginning of the file + * to the first byte in the section. + */ + sh_offset = sh_table[header.e_shstrndx].sh_offset; + + debug("sh_offset\t0x%08x\n", header.e_shnum); + + ret = fseek(felf, sh_offset, SEEK_SET); + if (ret) { + fprintf(stderr, "Setting up sh_offset failed\n"); + free(sh_str); + free(sh_table); + fclose(felf); + return 29; + } + + size = fread(sh_str, 1, sh_size, felf); + if (size != sh_size) { + fprintf(stderr, "%s: Can't read section: %lx/%lx\n", + argv[0], size, sh_size); + free(sh_str); + free(sh_table); + fclose(felf); + return 30; + } + + for (i = 0; i < header.e_shnum; i++) { + /* fprintf(stderr, "%s\n", sh_str + sh_table[i].sh_name); Debug only */ + if (!strcmp(".rela.dyn", (sh_str + sh_table[i].sh_name))) { + debug("Found section\t\".rela_dyn\"\n"); + debug(" at addr\t0x%08x\n", + (unsigned int)sh_table[i].sh_addr); + debug(" at offset\t0x%08x\n", + (unsigned int)sh_table[i].sh_offset); + debug(" of size\t0x%08x\n", + (unsigned int)sh_table[i].sh_size); + rela_start = sh_table[i].sh_addr; + rela_end = rela_start + sh_table[i].sh_size; + break; + } + } + + /* Clean up */ + free(sh_str); + free(sh_table); + fclose(felf); + + debug("text_base\t0x%08lx\n", text_base); + debug("rela_start\t0x%08lx\n", rela_start); + debug("rela_end\t0x%08lx\n", rela_end); + + if (!rela_start) + return 1; + + return 0; } -int main(int argc, char **argv) +static int decode_elf32(FILE *felf, char **argv) { - FILE *f; - int i, num; - uint64_t rela_start, rela_end, text_base, file_size; + size_t size; + Elf32_Ehdr header; + uint64_t section_header_base, section_header_size, sh_offset, sh_size; + Elf32_Shdr *sh_table; /* Elf symbol table */ + int ret, i, machine; + char *sh_str; - if (argc != 5) { - fprintf(stderr, "Statically apply ELF rela relocations\n"); - fprintf(stderr, "Usage: %s <bin file> <text base> " \ - "<rela start> <rela end>\n", argv[0]); - fprintf(stderr, "All numbers in hex.\n"); - return 1; + debug("32bit version\n"); + + /* Make sure we are at start */ + rewind(felf); + + size = fread(&header, 1, sizeof(header), felf); + if (size != sizeof(header)) { + fclose(felf); + return 25; } - f = fopen(argv[1], "r+b"); - if (!f) { + machine = header.e_machine; + debug("Machine %d\n", machine); + + if (machine != EM_MICROBLAZE) { + fprintf(stderr, "%s: Not supported machine type\n", argv[0]); + return 30; + } + + text_base = header.e_entry; + section_header_base = header.e_shoff; + + debug("Section header base %x\n", section_header_base); + + section_header_size = header.e_shentsize * header.e_shnum; + + debug("Section header size %d\n", section_header_size); + + sh_table = malloc(section_header_size); + if (!sh_table) { + fprintf(stderr, "%s: Cannot allocate space for section header\n", + argv[0]); + fclose(felf); + return 26; + } + + ret = fseek(felf, section_header_base, SEEK_SET); + if (ret) { + fprintf(stderr, "%s: Can't set pointer to section header: %x/%lx\n", + argv[0], ret, section_header_base); + free(sh_table); + fclose(felf); + return 26; + } + + size = fread(sh_table, 1, section_header_size, felf); + if (size != section_header_size) { + fprintf(stderr, "%s: Can't read section header: %lx/%lx\n", + argv[0], size, section_header_size); + free(sh_table); + fclose(felf); + return 27; + } + + sh_size = sh_table[header.e_shstrndx].sh_size; + debug("e_shstrndx %x, sh_size %lx\n", header.e_shstrndx, sh_size); + + sh_str = malloc(sh_size); + if (!sh_str) { + fprintf(stderr, "malloc failed\n"); + free(sh_table); + fclose(felf); + return 28; + } + + /* + * Specifies the byte offset from the beginning of the file + * to the first byte in the section. + */ + sh_offset = sh_table[header.e_shstrndx].sh_offset; + + debug("sh_offset %x\n", header.e_shnum); + + ret = fseek(felf, sh_offset, SEEK_SET); + if (ret) { + fprintf(stderr, "Setting up sh_offset failed\n"); + free(sh_str); + free(sh_table); + fclose(felf); + return 29; + } + + size = fread(sh_str, 1, sh_size, felf); + if (size != sh_size) { + fprintf(stderr, "%s: Can't read section: %lx/%lx\n", + argv[0], size, sh_size); + free(sh_str); + free(sh_table); + fclose(felf); + return 30; + } + + for (i = 0; i < header.e_shnum; i++) { + debug("%s\n", sh_str + sh_table[i].sh_name); + if (!strcmp(".rela.dyn", (sh_str + sh_table[i].sh_name))) { + debug("Found section\t\".rela_dyn\"\n"); + debug(" at addr\t0x%08x\n", (unsigned int)sh_table[i].sh_addr); + debug(" at offset\t0x%08x\n", (unsigned int)sh_table[i].sh_offset); + debug(" of size\t0x%08x\n", (unsigned int)sh_table[i].sh_size); + rela_start = sh_table[i].sh_addr; + rela_end = rela_start + sh_table[i].sh_size; + } + if (!strcmp(".dynsym", (sh_str + sh_table[i].sh_name))) { + debug("Found section\t\".dynsym\"\n"); + debug(" at addr\t0x%08x\n", (unsigned int)sh_table[i].sh_addr); + debug(" at offset\t0x%08x\n", (unsigned int)sh_table[i].sh_offset); + debug(" of size\t0x%08x\n", (unsigned int)sh_table[i].sh_size); + dyn_start = sh_table[i].sh_addr; + } + } + + /* Clean up */ + free(sh_str); + free(sh_table); + fclose(felf); + + debug("text_base\t0x%08lx\n", text_base); + debug("rela_start\t0x%08lx\n", rela_start); + debug("rela_end\t0x%08lx\n", rela_end); + debug("dyn_start\t0x%08lx\n", dyn_start); + + if (!rela_start) + return 1; + + return 0; +} + +static int decode_elf(char **argv) +{ + FILE *felf; + size_t size; + unsigned char e_ident[EI_NIDENT]; + + felf = fopen(argv[2], "r+b"); + if (!felf) { fprintf(stderr, "%s: Cannot open %s: %s\n", - argv[0], argv[1], strerror(errno)); + argv[0], argv[5], strerror(errno)); return 2; } - if (!read_num(argv[2], &text_base) || - !read_num(argv[3], &rela_start) || - !read_num(argv[4], &rela_end)) { - fprintf(stderr, "%s: bad number\n", argv[0]); - return 3; + size = fread(e_ident, 1, EI_NIDENT, felf); + if (size != EI_NIDENT) { + fclose(felf); + return 25; } - if (rela_start > rela_end || rela_start < text_base) { - fprintf(stderr, "%s: bad rela bounds\n", argv[0]); - return 3; + /* Check if this is really ELF file */ + if (e_ident[0] != 0x7f && + e_ident[1] != 'E' && + e_ident[2] != 'L' && + e_ident[3] != 'F') { + fclose(felf); + return 1; } - rela_start -= text_base; - rela_end -= text_base; + ei_class = e_ident[4]; + debug("EI_CLASS(1=32bit, 2=64bit) %d\n", ei_class); - fseek(f, 0, SEEK_END); - file_size = ftell(f); - rewind(f); + if (ei_class == 2) + return decode_elf64(felf, argv); - if (rela_end > file_size) { - // Most likely compiler inserted some section that didn't get - // objcopy-ed into the final binary - rela_end = file_size; - } + return decode_elf32(felf, argv); +} + +static int rela_elf64(char **argv, FILE *f) +{ + int i, num; if ((rela_end - rela_start) % sizeof(Elf64_Rela)) { fprintf(stderr, "%s: rela size isn't a multiple of Elf64_Rela\n", argv[0]); @@ -161,11 +417,228 @@ int main(int argc, char **argv) } } + return 0; +} + +static bool supported_rela32(Elf32_Rela *rela, uint32_t *type) +{ + uint32_t mask = 0xffULL; /* would be different on 32-bit */ + *type = rela->r_info & mask; + + debug("Type:\t"); + + switch (*type) { + case R_MICROBLAZE_32: + debug("R_MICROBLAZE_32\n"); + return true; + case R_MICROBLAZE_GLOB_DAT: + debug("R_MICROBLAZE_GLOB_DAT\n"); + return true; + case R_MICROBLAZE_NONE: + debug("R_MICROBLAZE_NONE - ignoring - do nothing\n"); + return false; + case R_MICROBLAZE_REL: + debug("R_MICROBLAZE_REL\n"); + return true; + default: + fprintf(stderr, "warning: unsupported relocation type %" + PRIu32 " at %" PRIx32 "\n", *type, rela->r_offset); + + return false; + } +} + +static int rela_elf32(char **argv, FILE *f) +{ + int i, num, index; + uint32_t value, type; + + if ((rela_end - rela_start) % sizeof(Elf32_Rela)) { + fprintf(stderr, "%s: rela size isn't a multiple of Elf32_Rela\n", argv[0]); + return 3; + } + + num = (rela_end - rela_start) / sizeof(Elf32_Rela); + + debug("Number of entries: %u\n", num); + + for (i = 0; i < num; i++) { + Elf32_Rela rela, swrela; + Elf32_Sym symbols; + uint32_t pos = rela_start + sizeof(Elf32_Rela) * i; + uint32_t addr, pos_dyn; + + debug("\nPossition:\t%d/0x%x\n", i, pos); + + if (fseek(f, pos, SEEK_SET) < 0) { + fprintf(stderr, "%s: %s: seek to %" PRIx32 + " failed: %s\n", + argv[0], argv[1], pos, strerror(errno)); + } + + if (fread(&rela, sizeof(rela), 1, f) != 1) { + fprintf(stderr, "%s: %s: read rela failed at %" + PRIx32 "\n", + argv[0], argv[1], pos); + return 4; + } + + debug("Rela:\toffset:\t%" PRIx32 " r_info:\t%" + PRIu32 " r_addend:\t%" PRIx32 "\n", + rela.r_offset, rela.r_info, rela.r_addend); + + swrela.r_offset = cpu_to_le32(rela.r_offset); + swrela.r_info = cpu_to_le32(rela.r_info); + swrela.r_addend = cpu_to_le32(rela.r_addend); + + debug("SWRela:\toffset:\t%" PRIx32 " r_info:\t%" + PRIu32 " r_addend:\t%" PRIx32 "\n", + swrela.r_offset, swrela.r_info, swrela.r_addend); + + if (!supported_rela32(&swrela, &type)) + continue; + + if (swrela.r_offset < text_base) { + fprintf(stderr, "%s: %s: bad rela at %" PRIx32 "\n", + argv[0], argv[1], pos); + return 4; + } + + addr = swrela.r_offset - text_base; + + debug("Addr:\t0x%" PRIx32 "\n", addr); + + switch (type) { + case R_MICROBLAZE_REL: + if (fseek(f, addr, SEEK_SET) < 0) { + fprintf(stderr, "%s: %s: seek to %" + PRIx32 " failed: %s\n", + argv[0], argv[1], addr, strerror(errno)); + return 5; + } + + debug("Write addend\n"); + + if (fwrite(&rela.r_addend, sizeof(rela.r_addend), 1, f) != 1) { + fprintf(stderr, "%s: %s: write failed at %" PRIx32 "\n", + argv[0], argv[1], addr); + return 4; + } + break; + case R_MICROBLAZE_32: + case R_MICROBLAZE_GLOB_DAT: + /* global symbols read it and add reloc offset */ + index = swrela.r_info >> 8; + pos_dyn = dyn_start + sizeof(Elf32_Sym) * index; + + debug("Index:\t%d\n", index); + debug("Pos_dyn:\t0x%x\n", pos_dyn); + + if (fseek(f, pos_dyn, SEEK_SET) < 0) { + fprintf(stderr, "%s: %s: seek to %" + PRIx32 " failed: %s\n", + argv[0], argv[1], pos_dyn, strerror(errno)); + return 5; + } + + if (fread(&symbols, sizeof(symbols), 1, f) != 1) { + fprintf(stderr, "%s: %s: read symbols failed at %" + PRIx32 "\n", + argv[0], argv[1], pos_dyn); + return 4; + } + + debug("Symbol description:\n"); + debug(" st_name:\t0x%x\n", symbols.st_name); + debug(" st_value:\t0x%x\n", symbols.st_value); + debug(" st_size:\t0x%x\n", symbols.st_size); + + value = swrela.r_addend + symbols.st_value; + + debug("Value:\t0x%x\n", value); + + if (fseek(f, addr, SEEK_SET) < 0) { + fprintf(stderr, "%s: %s: seek to %" + PRIx32 " failed: %s\n", + argv[0], argv[1], addr, strerror(errno)); + return 5; + } + + if (fwrite(&value, sizeof(rela.r_addend), 1, f) != 1) { + fprintf(stderr, "%s: %s: write failed at %" PRIx32 "\n", + argv[0], argv[1], addr); + return 4; + } + + break; + case R_MICROBLAZE_NONE: + debug("R_MICROBLAZE_NONE - skip\n"); + break; + default: + fprintf(stderr, "warning: unsupported relocation type %" + PRIu32 " at %" PRIx32 "\n", + type, rela.r_offset); + } + } + + return 0; +} + +int main(int argc, char **argv) +{ + FILE *f; + int ret; + uint64_t file_size; + + if (argc != 3) { + fprintf(stderr, "Statically apply ELF rela relocations\n"); + fprintf(stderr, "Usage: %s <bin file> <u-boot ELF>\n", + argv[0]); + return 1; + } + + ret = decode_elf(argv); + if (ret) { + fprintf(stderr, "ELF decoding failed\n"); + return ret; + } + + if (rela_start > rela_end || rela_start < text_base) { + fprintf(stderr, "%s: bad rela bounds\n", argv[0]); + return 3; + } + + rela_start -= text_base; + rela_end -= text_base; + dyn_start -= text_base; + + f = fopen(argv[1], "r+b"); + if (!f) { + fprintf(stderr, "%s: Cannot open %s: %s\n", + argv[0], argv[1], strerror(errno)); + return 2; + } + + fseek(f, 0, SEEK_END); + file_size = ftell(f); + rewind(f); + + if (rela_end > file_size) { + // Most likely compiler inserted some section that didn't get + // objcopy-ed into the final binary + rela_end = file_size; + } + + if (ei_class == 2) + ret = rela_elf64(argv, f); + else + ret = rela_elf32(argv, f); + if (fclose(f) < 0) { fprintf(stderr, "%s: %s: close failed: %s\n", argv[0], argv[1], strerror(errno)); return 4; } - return 0; + return ret; } diff --git a/tools/zynqmp_psu_init_minimize.sh b/tools/zynqmp_psu_init_minimize.sh index 4ee418f07ea..16c622f6ce7 100755 --- a/tools/zynqmp_psu_init_minimize.sh +++ b/tools/zynqmp_psu_init_minimize.sh @@ -2,6 +2,8 @@ # SPDX-License-Identifier: GPL-2.0+ # Copyright (C) 2018 Michal Simek <michal.simek@xilinx.com> # Copyright (C) 2019 Luca Ceresoli <luca@lucaceresoli.net> +# Copyright (C) 2022 Weidmüller Interface GmbH & Co. KG +# Stefan Herbrechtsmeier <stefan.herbrechtsmeier@weidmueller.com> usage() { @@ -119,7 +121,7 @@ tr "\n" "\r" <${OUT} >${TMP} # | | ==> |while (e)| # | } | | ; | # | | -sed -i -r 's| \{\r+(\t*)\}\r\r|\n\1\t;\n|g' ${TMP} +sed -i -r 's| \{\r+(\t*)\}\r\r|\r\1\t;\r|g' ${TMP} # Remove empty line between variable declaration sed -i -r 's|\r(\r\t(unsigned )?int )|\1|g' ${TMP} @@ -141,7 +143,30 @@ sed -i -r 's| \{(\r[^\r]*;)\r\t*\}|\1|g' ${TMP} # if ((p_code >= 0x26) && ...) -> if (p_code >= 0x26 && ...) sed -i -r 's|\((._code .= [x[:xdigit:]]+)\)|\1|g' ${TMP} +# Move helper functions below header includes +TARGET="#include <xil_io.h>" +START="static int serdes_rst_seq" +END="static int serdes_enb_coarse_saturation" + +sed -i -e "s|\(${TARGET}\r\r\)\(.*\)\(${START}(.*\)\(${END}(\)|\1\3\2\4|g" \ + ${TMP} + # Convert back newlines tr "\r" "\n" <${TMP} >${OUT} +# Remove unnecessary settings +# - Low level UART +SETTINGS_TO_REMOVE="0xFF000000 +0xFF000004 +0xFF000018 +0xFF000034 +0xFF010000 +0xFF010004 +0xFF010018 +0xFF010034 +" +for i in $SETTINGS_TO_REMOVE; do +sed -i "/^\tpsu_mask_write($i,.*$/d" ${OUT} +done + rm ${TMP} |
