diff options
Diffstat (limited to 'tools')
28 files changed, 438 insertions, 126 deletions
diff --git a/tools/binman/binman.rst b/tools/binman/binman.rst index 020988d955f..230e055667f 100644 --- a/tools/binman/binman.rst +++ b/tools/binman/binman.rst @@ -2060,7 +2060,7 @@ don't have access to the blobs. If the blobs are in a different directory, you can specify this with the `-I` option. -For U-Boot, you can use set the BINMAN_INDIRS environment variable to provide a +For U-Boot, you can set the BINMAN_INDIRS environment variable to provide a space-separated list of directories to search for binary blobs:: BINMAN_INDIRS="odroid-c4/fip/g12a \ diff --git a/tools/binman/btool/openssl.py b/tools/binman/btool/openssl.py index 7ee2683ab23..fe81a1f51b1 100644 --- a/tools/binman/btool/openssl.py +++ b/tools/binman/btool/openssl.py @@ -82,7 +82,7 @@ imageSize = INTEGER:{len(indata)} return self.run_cmd(*args) def x509_cert_sysfw(self, cert_fname, input_fname, key_fname, sw_rev, - config_fname, req_dist_name_dict): + config_fname, req_dist_name_dict, firewall_cert_data): """Create a certificate to be booted by system firmware Args: @@ -94,6 +94,13 @@ imageSize = INTEGER:{len(indata)} req_dist_name_dict (dict): Dictionary containing key-value pairs of req_distinguished_name section extensions, must contain extensions for C, ST, L, O, OU, CN and emailAddress + firewall_cert_data (dict): + - auth_in_place (int): The Priv ID for copying as the + specific host in firewall protected region + - num_firewalls (int): The number of firewalls in the + extended certificate + - certificate (str): Extended firewall certificate with + the information for the firewall configurations. Returns: str: Tool output @@ -121,6 +128,7 @@ basicConstraints = CA:true 1.3.6.1.4.1.294.1.3 = ASN1:SEQUENCE:swrv 1.3.6.1.4.1.294.1.34 = ASN1:SEQUENCE:sysfw_image_integrity 1.3.6.1.4.1.294.1.35 = ASN1:SEQUENCE:sysfw_image_load +1.3.6.1.4.1.294.1.37 = ASN1:SEQUENCE:firewall [ swrv ] swrv = INTEGER:{sw_rev} @@ -132,7 +140,11 @@ imageSize = INTEGER:{len(indata)} [ sysfw_image_load ] destAddr = FORMAT:HEX,OCT:00000000 -authInPlace = INTEGER:2 +authInPlace = INTEGER:{hex(firewall_cert_data['auth_in_place'])} + +[ firewall ] +numFirewallRegions = INTEGER:{firewall_cert_data['num_firewalls']} +{firewall_cert_data['certificate']} ''', file=outf) args = ['req', '-new', '-x509', '-key', key_fname, '-nodes', '-outform', 'DER', '-out', cert_fname, '-config', config_fname, diff --git a/tools/binman/elf_test.py b/tools/binman/elf_test.py index e3dee79d065..b64134123c1 100644 --- a/tools/binman/elf_test.py +++ b/tools/binman/elf_test.py @@ -249,8 +249,8 @@ class TestElf(unittest.TestCase): def testEmbedFail(self): """Test calling GetSymbolFileOffset() without elftools""" + old_val = elf.ELF_TOOLS try: - old_val = elf.ELF_TOOLS elf.ELF_TOOLS = False fname = self.ElfTestFile('embed_data') with self.assertRaises(ValueError) as e: @@ -290,8 +290,8 @@ class TestElf(unittest.TestCase): def test_read_segments_fail(self): """Test for read_loadable_segments() without elftools""" + old_val = elf.ELF_TOOLS try: - old_val = elf.ELF_TOOLS elf.ELF_TOOLS = False fname = self.ElfTestFile('embed_data') with self.assertRaises(ValueError) as e: @@ -327,8 +327,8 @@ class TestElf(unittest.TestCase): def test_get_file_offset_fail(self): """Test calling GetFileOffset() without elftools""" + old_val = elf.ELF_TOOLS try: - old_val = elf.ELF_TOOLS elf.ELF_TOOLS = False fname = self.ElfTestFile('embed_data') with self.assertRaises(ValueError) as e: @@ -351,8 +351,8 @@ class TestElf(unittest.TestCase): def test_get_symbol_from_address_fail(self): """Test calling GetSymbolFromAddress() without elftools""" + old_val = elf.ELF_TOOLS try: - old_val = elf.ELF_TOOLS elf.ELF_TOOLS = False fname = self.ElfTestFile('embed_data') with self.assertRaises(ValueError) as e: diff --git a/tools/binman/entries.rst b/tools/binman/entries.rst index 61de7f1f4a8..254afe76074 100644 --- a/tools/binman/entries.rst +++ b/tools/binman/entries.rst @@ -1906,6 +1906,20 @@ the included board config binaries. Example:: +.. _etype_ti_dm: + +Entry: ti-dm: TI Device Manager (DM) blob +----------------------------------------- + +Properties / Entry arguments: + - ti-dm-path: Filename of file to read into the entry, typically ti-dm.bin + +This entry holds the device manager responsible for resource and power management +in K3 devices. See https://software-dl.ti.com/tisci/esd/latest/ for more information +about TI DM. + + + .. _etype_ti_secure: Entry: ti-secure: Entry containing a TI x509 certificate binary diff --git a/tools/binman/etype/ti_dm.py b/tools/binman/etype/ti_dm.py new file mode 100644 index 00000000000..0faa0bf0ca7 --- /dev/null +++ b/tools/binman/etype/ti_dm.py @@ -0,0 +1,22 @@ +# SPDX-License-Identifier: GPL-2.0+ +# Copyright (C) 2023 Texas Instruments Incorporated - https://www.ti.com/ +# Written by Neha Malcom Francis <n-francis@ti.com> +# +# Entry-type module for TI Device Manager (DM) +# + +from binman.etype.blob_named_by_arg import Entry_blob_named_by_arg + +class Entry_ti_dm(Entry_blob_named_by_arg): + """TI Device Manager (DM) blob + + Properties / Entry arguments: + - ti-dm-path: Filename of file to read into the entry, typically ti-dm.bin + + This entry holds the device manager responsible for resource and power management + in K3 devices. See https://software-dl.ti.com/tisci/esd/latest/ for more information + about TI DM. + """ + def __init__(self, section, etype, node): + super().__init__(section, etype, node, 'ti-dm') + self.external = True diff --git a/tools/binman/etype/ti_secure.py b/tools/binman/etype/ti_secure.py index d939dce5713..704dcf8a381 100644 --- a/tools/binman/etype/ti_secure.py +++ b/tools/binman/etype/ti_secure.py @@ -7,9 +7,44 @@ from binman.entry import EntryArg from binman.etype.x509_cert import Entry_x509_cert +from dataclasses import dataclass from dtoc import fdt_util +@dataclass +class Firewall(): + id: int + region: int + control : int + permissions: list + start_address: str + end_address: str + + def ensure_props(self, etype, name): + missing_props = [] + for key, val in self.__dict__.items(): + if val is None: + missing_props += [key] + + if len(missing_props): + etype.Raise(f"Subnode '{name}' is missing properties: {','.join(missing_props)}") + + def get_certificate(self) -> str: + unique_identifier = f"{self.id}{self.region}" + cert = f""" +firewallID{unique_identifier} = INTEGER:{self.id} +region{unique_identifier} = INTEGER:{self.region} +control{unique_identifier} = INTEGER:{hex(self.control)} +nPermissionRegs{unique_identifier} = INTEGER:{len(self.permissions)} +""" + for index, permission in enumerate(self.permissions): + cert += f"""permissions{unique_identifier}{index} = INTEGER:{hex(permission)} +""" + cert += f"""startAddress{unique_identifier} = FORMAT:HEX,OCT:{self.start_address:02x} +endAddress{unique_identifier} = FORMAT:HEX,OCT:{self.end_address:02x} +""" + return cert + class Entry_ti_secure(Entry_x509_cert): """Entry containing a TI x509 certificate binary @@ -17,6 +52,11 @@ class Entry_ti_secure(Entry_x509_cert): - content: List of phandles to entries to sign - keyfile: Filename of file containing key to sign binary with - sha: Hash function to be used for signing + - auth-in-place: This is an integer field that contains two pieces + of information + Lower Byte - Remains 0x02 as per our use case + ( 0x02: Move the authenticated binary back to the header ) + Upper Byte - The Host ID of the core owning the firewall Output files: - input.<unique_name> - input file passed to openssl @@ -25,6 +65,35 @@ class Entry_ti_secure(Entry_x509_cert): - cert.<unique_name> - output file generated by openssl (which is used as the entry contents) + Depending on auth-in-place information in the inputs, we read the + firewall nodes that describe the configurations of firewall that TIFS + will be doing after reading the certificate. + + The syntax of the firewall nodes are as such: + + firewall-257-0 { + id = <257>; /* The ID of the firewall being configured */ + region = <0>; /* Region number to configure */ + + control = /* The control register */ + <(FWCTRL_EN | FWCTRL_LOCK | FWCTRL_BG | FWCTRL_CACHE)>; + + permissions = /* The permission registers */ + <((FWPRIVID_ALL << FWPRIVID_SHIFT) | + FWPERM_SECURE_PRIV_RWCD | + FWPERM_SECURE_USER_RWCD | + FWPERM_NON_SECURE_PRIV_RWCD | + FWPERM_NON_SECURE_USER_RWCD)>; + + /* More defines can be found in k3-security.h */ + + start_address = /* The Start Address of the firewall */ + <0x0 0x0>; + end_address = /* The End Address of the firewall */ + <0xff 0xffffffff>; + }; + + openssl signs the provided data, using the TI templated config file and writes the signature in this entry. This allows verification that the data is genuine. @@ -32,11 +101,20 @@ class Entry_ti_secure(Entry_x509_cert): def __init__(self, section, etype, node): super().__init__(section, etype, node) self.openssl = None + self.firewall_cert_data: dict = { + 'auth_in_place': 0x02, + 'num_firewalls': 0, + 'certificate': '', + } def ReadNode(self): super().ReadNode() self.key_fname = self.GetEntryArgsOrProps([ EntryArg('keyfile', str)], required=True)[0] + auth_in_place = fdt_util.GetInt(self._node, 'auth-in-place') + if auth_in_place: + self.firewall_cert_data['auth_in_place'] = auth_in_place + self.ReadFirewallNode() self.sha = fdt_util.GetInt(self._node, 'sha', 512) self.req_dist_name = {'C': 'US', 'ST': 'TX', @@ -46,6 +124,23 @@ class Entry_ti_secure(Entry_x509_cert): 'CN': 'TI Support', 'emailAddress': 'support@ti.com'} + def ReadFirewallNode(self): + self.firewall_cert_data['certificate'] = "" + self.firewall_cert_data['num_firewalls'] = 0 + for node in self._node.subnodes: + if 'firewall' in node.name: + firewall = Firewall( + fdt_util.GetInt(node, 'id'), + fdt_util.GetInt(node, 'region'), + fdt_util.GetInt(node, 'control'), + fdt_util.GetPhandleList(node, 'permissions'), + fdt_util.GetInt64(node, 'start_address'), + fdt_util.GetInt64(node, 'end_address'), + ) + firewall.ensure_props(self, node.name) + self.firewall_cert_data['num_firewalls'] += 1 + self.firewall_cert_data['certificate'] += firewall.get_certificate() + def GetCertificate(self, required): """Get the contents of this entry diff --git a/tools/binman/etype/x509_cert.py b/tools/binman/etype/x509_cert.py index fc0bb122786..29630d1b86c 100644 --- a/tools/binman/etype/x509_cert.py +++ b/tools/binman/etype/x509_cert.py @@ -51,6 +51,7 @@ class Entry_x509_cert(Entry_collection): self.hashval_sysfw_data = None self.sysfw_inner_cert_ext_boot_block = None self.dm_data_ext_boot_block = None + self.firewall_cert_data = None def ReadNode(self): super().ReadNode() @@ -98,7 +99,8 @@ class Entry_x509_cert(Entry_collection): key_fname=self.key_fname, config_fname=config_fname, sw_rev=self.sw_rev, - req_dist_name_dict=self.req_dist_name) + req_dist_name_dict=self.req_dist_name, + firewall_cert_data=self.firewall_cert_data) elif type == 'rom': stdout = self.openssl.x509_cert_rom( cert_fname=output_fname, diff --git a/tools/binman/ftest.py b/tools/binman/ftest.py index 5ace2a825dc..90482518f1e 100644 --- a/tools/binman/ftest.py +++ b/tools/binman/ftest.py @@ -88,6 +88,7 @@ FSP_S_DATA = b'fsp_s' FSP_T_DATA = b'fsp_t' ATF_BL31_DATA = b'bl31' TEE_OS_DATA = b'this is some tee OS data' +TI_DM_DATA = b'tidmtidm' ATF_BL2U_DATA = b'bl2u' OPENSBI_DATA = b'opensbi' SCP_DATA = b'scp' @@ -221,6 +222,7 @@ class TestFunctional(unittest.TestCase): TestFunctional._MakeInputFile('compress_big', COMPRESS_DATA_BIG) TestFunctional._MakeInputFile('bl31.bin', ATF_BL31_DATA) TestFunctional._MakeInputFile('tee-pager.bin', TEE_OS_DATA) + TestFunctional._MakeInputFile('dm.bin', TI_DM_DATA) TestFunctional._MakeInputFile('bl2u.bin', ATF_BL2U_DATA) TestFunctional._MakeInputFile('fw_dynamic.bin', OPENSBI_DATA) TestFunctional._MakeInputFile('scp.bin', SCP_DATA) @@ -2840,12 +2842,14 @@ class TestFunctional(unittest.TestCase): fdt_size = entries['section'].GetEntries()['u-boot-dtb'].size fdtmap_offset = entries['fdtmap'].offset + tmpdir = None try: tmpdir, updated_fname = self._SetupImageInTmpdir() with test_util.capture_sys_output() as (stdout, stderr): self._DoBinman('ls', '-i', updated_fname) finally: - shutil.rmtree(tmpdir) + if tmpdir: + shutil.rmtree(tmpdir) lines = stdout.getvalue().splitlines() expected = [ 'Name Image-pos Size Entry-type Offset Uncomp-size', @@ -2866,12 +2870,14 @@ class TestFunctional(unittest.TestCase): def testListCmdFail(self): """Test failing to list an image""" self._DoReadFile('005_simple.dts') + tmpdir = None try: tmpdir, updated_fname = self._SetupImageInTmpdir() with self.assertRaises(ValueError) as e: self._DoBinman('ls', '-i', updated_fname) finally: - shutil.rmtree(tmpdir) + if tmpdir: + shutil.rmtree(tmpdir) self.assertIn("Cannot find FDT map in image", str(e.exception)) def _RunListCmd(self, paths, expected): @@ -3000,13 +3006,15 @@ class TestFunctional(unittest.TestCase): self._CheckLz4() self._DoReadFileRealDtb('130_list_fdtmap.dts') fname = os.path.join(self._indir, 'output.extact') + tmpdir = None try: tmpdir, updated_fname = self._SetupImageInTmpdir() with test_util.capture_sys_output() as (stdout, stderr): self._DoBinman('extract', '-i', updated_fname, 'u-boot', '-f', fname) finally: - shutil.rmtree(tmpdir) + if tmpdir: + shutil.rmtree(tmpdir) data = tools.read_file(fname) self.assertEqual(U_BOOT_DATA, data) @@ -5183,12 +5191,14 @@ fdt fdtmap Extract the devicetree blob from the fdtmap data = self._DoReadFileRealDtb('207_fip_ls.dts') hdr, fents = fip_util.decode_fip(data) + tmpdir = None try: tmpdir, updated_fname = self._SetupImageInTmpdir() with test_util.capture_sys_output() as (stdout, stderr): self._DoBinman('ls', '-i', updated_fname) finally: - shutil.rmtree(tmpdir) + if tmpdir: + shutil.rmtree(tmpdir) lines = stdout.getvalue().splitlines() expected = [ 'Name Image-pos Size Entry-type Offset Uncomp-size', @@ -5393,12 +5403,14 @@ fdt fdtmap Extract the devicetree blob from the fdtmap use_real_dtb=True, extra_indirs=[os.path.join(self._indir, TEST_FDT_SUBDIR)]) + tmpdir = None try: tmpdir, updated_fname = self._SetupImageInTmpdir() with test_util.capture_sys_output() as (stdout, stderr): self._RunBinman('ls', '-i', updated_fname) finally: - shutil.rmtree(tmpdir) + if tmpdir: + shutil.rmtree(tmpdir) def testFitSubentryUsesBintool(self): """Test that binman FIT subentries can use bintools""" @@ -5455,6 +5467,11 @@ fdt fdtmap Extract the devicetree blob from the fdtmap data = self._DoReadFile('222_tee_os.dts') self.assertEqual(TEE_OS_DATA, data[:len(TEE_OS_DATA)]) + def testPackTiDm(self): + """Test that an image with a TI DM binary can be created""" + data = self._DoReadFile('225_ti_dm.dts') + self.assertEqual(TI_DM_DATA, data[:len(TI_DM_DATA)]) + def testFitFdtOper(self): """Check handling of a specified FIT operation""" entry_args = { @@ -7035,6 +7052,29 @@ fdt fdtmap Extract the devicetree blob from the fdtmap entry_args=entry_args)[0] self.assertGreater(len(data), len(TI_UNSECURE_DATA)) + def testPackTiSecureFirewall(self): + """Test that an image with a TI secured binary can be created""" + keyfile = self.TestFile('key.key') + entry_args = { + 'keyfile': keyfile, + } + data_no_firewall = self._DoReadFileDtb('296_ti_secure.dts', + entry_args=entry_args)[0] + data_firewall = self._DoReadFileDtb('324_ti_secure_firewall.dts', + entry_args=entry_args)[0] + self.assertGreater(len(data_firewall),len(data_no_firewall)) + + def testPackTiSecureFirewallMissingProperty(self): + """Test that an image with a TI secured binary can be created""" + keyfile = self.TestFile('key.key') + entry_args = { + 'keyfile': keyfile, + } + with self.assertRaises(ValueError) as e: + data_firewall = self._DoReadFileDtb('325_ti_secure_firewall_missing_property.dts', + entry_args=entry_args)[0] + self.assertRegex(str(e.exception), "Node '/binman/ti-secure': Subnode 'firewall-0-2' is missing properties: id,region") + def testPackTiSecureMissingTool(self): """Test that an image with a TI secured binary (non-functional) can be created when openssl is missing""" diff --git a/tools/binman/pyproject.toml b/tools/binman/pyproject.toml index b4b54fbaee6..ba34437fc53 100644 --- a/tools/binman/pyproject.toml +++ b/tools/binman/pyproject.toml @@ -4,11 +4,11 @@ build-backend = "setuptools.build_meta" [project] name = "binary-manager" -version = "0.0.2" +version = "0.0.6" authors = [ { name="Simon Glass", email="sjg@chromium.org" }, ] -dependencies = ["pylibfdt", "u_boot_pylib", "dtoc"] +dependencies = ["pylibfdt", "u_boot_pylib >= 0.0.6", "dtoc >= 0.0.6"] description = "Binman firmware-packaging tool" readme = "README.rst" requires-python = ">=3.7" @@ -19,7 +19,7 @@ classifiers = [ ] [project.urls] -"Homepage" = "https://u-boot.readthedocs.io/en/latest/develop/package/index.html" +"Homepage" = "https://docs.u-boot.org/en/latest/develop/package/index.html" "Bug Tracker" = "https://source.denx.de/groups/u-boot/-/issues" [project.scripts] diff --git a/tools/binman/test/225_ti_dm.dts b/tools/binman/test/225_ti_dm.dts new file mode 100644 index 00000000000..3ab754131e9 --- /dev/null +++ b/tools/binman/test/225_ti_dm.dts @@ -0,0 +1,13 @@ +// SPDX-License-Identifier: GPL-2.0+ + +/dts-v1/; + +/ { + #address-cells = <1>; + #size-cells = <1>; + binman { + ti-dm { + filename = "dm.bin"; + }; + }; +}; diff --git a/tools/binman/test/324_ti_secure_firewall.dts b/tools/binman/test/324_ti_secure_firewall.dts new file mode 100644 index 00000000000..7ec407fa67b --- /dev/null +++ b/tools/binman/test/324_ti_secure_firewall.dts @@ -0,0 +1,28 @@ +// SPDX-License-Identifier: GPL-2.0+ + +/dts-v1/; + +/ { + #address-cells = <1>; + #size-cells = <1>; + + binman { + ti-secure { + content = <&unsecure_binary>; + auth-in-place = <0xa02>; + + firewall-0-2 { + id = <0>; + region = <2>; + control = <0x31a>; + permissions = <0xc3ffff>; + start_address = <0x0 0x9e800000>; + end_address = <0x0 0x9fffffff>; + }; + + }; + unsecure_binary: blob-ext { + filename = "ti_unsecure.bin"; + }; + }; +}; diff --git a/tools/binman/test/325_ti_secure_firewall_missing_property.dts b/tools/binman/test/325_ti_secure_firewall_missing_property.dts new file mode 100644 index 00000000000..24a0a996250 --- /dev/null +++ b/tools/binman/test/325_ti_secure_firewall_missing_property.dts @@ -0,0 +1,28 @@ +// SPDX-License-Identifier: GPL-2.0+ + +/dts-v1/; + +/ { + #address-cells = <1>; + #size-cells = <1>; + + binman { + ti-secure { + content = <&unsecure_binary>; + auth-in-place = <0xa02>; + + firewall-0-2 { + // id = <0>; + // region = <2>; + control = <0x31a>; + permissions = <0xc3ffff>; + start_address = <0x0 0x9e800000>; + end_address = <0x0 0x9fffffff>; + }; + + }; + unsecure_binary: blob-ext { + filename = "ti_unsecure.bin"; + }; + }; +}; diff --git a/tools/buildman/boards.py b/tools/buildman/boards.py index 341a5056dfd..3c2822715f3 100644 --- a/tools/buildman/boards.py +++ b/tools/buildman/boards.py @@ -119,7 +119,7 @@ class Expr: """Set up a new Expr object. Args: - expr (str): String cotaining regular expression to store + expr (str): String containing regular expression to store """ self._expr = expr self._re = re.compile(expr) diff --git a/tools/buildman/builder.py b/tools/buildman/builder.py index 3e42c987d1c..f35175b4598 100644 --- a/tools/buildman/builder.py +++ b/tools/buildman/builder.py @@ -480,7 +480,7 @@ class Builder: Args: commit: Commit object that is being built brd: Board object that is being built - stage: Stage that we are at (mrproper, config, build) + stage: Stage that we are at (mrproper, config, oldconfig, build) cwd: Directory where make should be run args: Arguments to pass to make kwargs: Arguments to pass to command.run_pipe() diff --git a/tools/buildman/builderthread.py b/tools/buildman/builderthread.py index 6a61f64da1d..a8599c0bb2a 100644 --- a/tools/buildman/builderthread.py +++ b/tools/buildman/builderthread.py @@ -426,6 +426,12 @@ class BuilderThread(threading.Thread): # Now do the build, if everything looks OK if result.return_code == 0: + if adjust_cfg: + oldc_args = list(args) + ['oldconfig'] + oldc_result = self.make(commit, brd, 'oldconfig', cwd, + *oldc_args, env=env) + if oldc_result.return_code: + return oldc_result result = self._build(commit, brd, cwd, args, env, cmd_list, config_only) if adjust_cfg: diff --git a/tools/buildman/func_test.py b/tools/buildman/func_test.py index 55dd494fe8e..6b88ed815d6 100644 --- a/tools/buildman/func_test.py +++ b/tools/buildman/func_test.py @@ -439,6 +439,8 @@ class TestFunctional(unittest.TestCase): tools.write_file(fname, b'CONFIG_SOMETHING=1') return command.CommandResult(return_code=0, combined='Test configuration complete') + elif stage == 'oldconfig': + return command.CommandResult(return_code=0) elif stage == 'build': stderr = '' fname = os.path.join(cwd or '', out_dir, 'u-boot') @@ -461,7 +463,7 @@ Some images are invalid''' return command.CommandResult(return_code=0) # Not handled, so abort - print('make', stage) + print('_HandleMake failure: make', stage) sys.exit(1) # Example function to print output lines diff --git a/tools/buildman/pyproject.toml b/tools/buildman/pyproject.toml index 4d75e772ee1..fe0f6421b53 100644 --- a/tools/buildman/pyproject.toml +++ b/tools/buildman/pyproject.toml @@ -4,11 +4,11 @@ build-backend = "setuptools.build_meta" [project] name = "buildman" -version = "0.0.2" +version = "0.0.6" authors = [ { name="Simon Glass", email="sjg@chromium.org" }, ] -dependencies = ["u_boot_pylib", "patch-manager"] +dependencies = ["u_boot_pylib >= 0.0.6", "patch-manager >= 0.0.6"] description = "Buildman build tool for U-Boot" readme = "README.rst" requires-python = ">=3.7" @@ -19,7 +19,7 @@ classifiers = [ ] [project.urls] -"Homepage" = "https://u-boot.readthedocs.io/en/latest/build/buildman.html" +"Homepage" = "https://docs.u-boot.org/en/latest/build/buildman.html" "Bug Tracker" = "https://source.denx.de/groups/u-boot/-/issues" [project.scripts] diff --git a/tools/dtoc/fdt.py b/tools/dtoc/fdt.py index 5963925146a..991a36b9879 100644 --- a/tools/dtoc/fdt.py +++ b/tools/dtoc/fdt.py @@ -782,7 +782,7 @@ class Node: for node in parent.subnodes.__reversed__(): dst = self.copy_node(node) - tout.debug(f'merge props from {parent.path} to {dst.path}') + tout.debug(f'merge props from {parent.path} to {self.path}') self.merge_props(parent, False) diff --git a/tools/dtoc/pyproject.toml b/tools/dtoc/pyproject.toml index 77fe4da2158..9f59788e616 100644 --- a/tools/dtoc/pyproject.toml +++ b/tools/dtoc/pyproject.toml @@ -4,11 +4,11 @@ build-backend = "setuptools.build_meta" [project] name = "dtoc" -version = "0.0.2" +version = "0.0.6" authors = [ { name="Simon Glass", email="sjg@chromium.org" }, ] -dependencies = ["pylibfdt", "u_boot_pylib"] +dependencies = ["pylibfdt", "u_boot_pylib >= 0.0.6"] description = "Devicetree-to-C generator" readme = "README.rst" requires-python = ">=3.7" @@ -19,7 +19,7 @@ classifiers = [ ] [project.urls] -"Homepage" = "https://u-boot.readthedocs.io/en/latest/develop/driver-model/of-plat.html" +"Homepage" = "https://docs.u-boot.org/en/latest/develop/driver-model/of-plat.html" "Bug Tracker" = "https://source.denx.de/groups/u-boot/-/issues" [project.scripts] diff --git a/tools/env/README b/tools/env/README index 480a893202f..b8c6a7e1974 100644 --- a/tools/env/README +++ b/tools/env/README @@ -58,6 +58,9 @@ DEVICEx_ENVSECTORS defines the number of sectors that may be used for this environment instance. On NAND this is used to limit the range within which bad blocks are skipped, on NOR it is not used. +If DEVICEx_ESIZE and DEVICEx_ENVSECTORS are both zero, then a runtime +detection is attempted for NOR and NAND mtd types. + To prevent losing changes to the environment and to prevent confusing the MTD drivers, a lock file at /run/fw_printenv.lock is used to serialize access to the environment. diff --git a/tools/env/fw_env.c b/tools/env/fw_env.c index c9a8774acef..74451ecb945 100644 --- a/tools/env/fw_env.c +++ b/tools/env/fw_env.c @@ -948,29 +948,25 @@ static int flash_read_buf(int dev, int fd, void *buf, size_t count, */ lseek(fd, blockstart + block_seek, SEEK_SET); - rc = read(fd, buf + processed, readlen); - if (rc == -1) { - fprintf(stderr, "Read error on %s: %s\n", - DEVNAME(dev), strerror(errno)); - return -1; - } + while (readlen) { + rc = read(fd, buf + processed, readlen); + if (rc == -1) { + fprintf(stderr, "Read error on %s: %s\n", + DEVNAME(dev), strerror(errno)); + return -1; + } #ifdef DEBUG - fprintf(stderr, "Read 0x%x bytes at 0x%llx on %s\n", - rc, (unsigned long long)blockstart + block_seek, - DEVNAME(dev)); + fprintf(stderr, "Read 0x%x bytes at 0x%llx on %s\n", + rc, (unsigned long long)blockstart + block_seek, + DEVNAME(dev)); #endif - processed += rc; - if (rc != readlen) { - fprintf(stderr, - "Warning on %s: Attempted to read %zd bytes but got %d\n", - DEVNAME(dev), readlen, rc); + processed += rc; readlen -= rc; - block_seek += rc; - } else { - blockstart += blocklen; - readlen = min(blocklen, count - processed); - block_seek = 0; } + + blockstart += blocklen; + readlen = min(blocklen, count - processed); + block_seek = 0; } return processed; @@ -1416,11 +1412,11 @@ int fw_env_open(struct env_opts *opts) { int crc0, crc0_ok; unsigned char flag0; - void *addr0 = NULL; + void *buf0 = NULL; int crc1, crc1_ok; unsigned char flag1; - void *addr1 = NULL; + void *buf1 = NULL; int ret; @@ -1430,8 +1426,8 @@ int fw_env_open(struct env_opts *opts) if (parse_config(opts)) /* should fill envdevices */ return -EINVAL; - addr0 = calloc(1, CUR_ENVSIZE); - if (addr0 == NULL) { + buf0 = calloc(1, CUR_ENVSIZE); + if (buf0 == NULL) { fprintf(stderr, "Not enough memory for environment (%ld bytes)\n", CUR_ENVSIZE); @@ -1440,13 +1436,13 @@ int fw_env_open(struct env_opts *opts) } dev_current = 0; - if (flash_io(O_RDONLY, addr0, CUR_ENVSIZE)) { + if (flash_io(O_RDONLY, buf0, CUR_ENVSIZE)) { ret = -EIO; goto open_cleanup; } if (!have_redund_env) { - struct env_image_single *single = addr0; + struct env_image_single *single = buf0; crc0 = crc32(0, (uint8_t *)single->data, ENV_SIZE); crc0_ok = (crc0 == single->crc); @@ -1458,12 +1454,12 @@ int fw_env_open(struct env_opts *opts) environment.dirty = 1; } - environment.image = addr0; + environment.image = buf0; environment.crc = &single->crc; environment.flags = NULL; environment.data = single->data; } else { - struct env_image_redundant *redundant0 = addr0; + struct env_image_redundant *redundant0 = buf0; struct env_image_redundant *redundant1; crc0 = crc32(0, (uint8_t *)redundant0->data, ENV_SIZE); @@ -1472,17 +1468,17 @@ int fw_env_open(struct env_opts *opts) flag0 = redundant0->flags; dev_current = 1; - addr1 = calloc(1, CUR_ENVSIZE); - if (addr1 == NULL) { + buf1 = calloc(1, CUR_ENVSIZE); + if (buf1 == NULL) { fprintf(stderr, "Not enough memory for environment (%ld bytes)\n", CUR_ENVSIZE); ret = -ENOMEM; goto open_cleanup; } - redundant1 = addr1; + redundant1 = buf1; - if (flash_io(O_RDONLY, addr1, CUR_ENVSIZE)) { + if (flash_io(O_RDONLY, buf1, CUR_ENVSIZE)) { ret = -EIO; goto open_cleanup; } @@ -1571,17 +1567,17 @@ int fw_env_open(struct env_opts *opts) * flags before writing out */ if (dev_current) { - environment.image = addr1; + environment.image = buf1; environment.crc = &redundant1->crc; environment.flags = &redundant1->flags; environment.data = redundant1->data; - free(addr0); + free(buf0); } else { - environment.image = addr0; + environment.image = buf0; environment.crc = &redundant0->crc; environment.flags = &redundant0->flags; environment.data = redundant0->data; - free(addr1); + free(buf1); } #ifdef DEBUG fprintf(stderr, "Selected env in %s\n", DEVNAME(dev_current)); @@ -1590,11 +1586,8 @@ int fw_env_open(struct env_opts *opts) return 0; open_cleanup: - if (addr0) - free(addr0); - - if (addr1) - free(addr1); + free(buf0); + free(buf1); return ret; } @@ -1659,8 +1652,15 @@ static int check_device_config(int dev) } DEVTYPE(dev) = mtdinfo.type; if (DEVESIZE(dev) == 0 && ENVSECTORS(dev) == 0 && - mtdinfo.type == MTD_NORFLASH) - DEVESIZE(dev) = mtdinfo.erasesize; + mtdinfo.erasesize > 0) { + if (mtdinfo.type == MTD_NORFLASH) + DEVESIZE(dev) = mtdinfo.erasesize; + else if (mtdinfo.type == MTD_NANDFLASH) { + DEVESIZE(dev) = mtdinfo.erasesize; + ENVSECTORS(dev) = + mtdinfo.size / mtdinfo.erasesize; + } + } if (DEVESIZE(dev) == 0) /* Assume the erase size is the same as the env-size */ DEVESIZE(dev) = ENVSIZE(dev); @@ -1732,6 +1732,7 @@ static int find_nvmem_device(void) } while (!nvmem && (dent = readdir(dir))) { + struct stat s; FILE *fp; size_t size; @@ -1749,14 +1750,22 @@ static int find_nvmem_device(void) continue; } - size = fread(buf, sizeof(buf), 1, fp); + if (fstat(fileno(fp), &s)) { + fprintf(stderr, "Failed to fstat %s\n", comp); + goto next; + } + + if (s.st_size >= sizeof(buf)) { + goto next; + } + + size = fread(buf, s.st_size, 1, fp); if (size != 1) { fprintf(stderr, "read failed about %s\n", comp); - fclose(fp); - return -EIO; + goto next; } - + buf[s.st_size] = '\0'; if (!strcmp(buf, "u-boot,env")) { bytes = asprintf(&nvmem, "%s/%s/nvmem", path, dent->d_name); @@ -1765,6 +1774,7 @@ static int find_nvmem_device(void) } } +next: fclose(fp); } diff --git a/tools/fdtgrep.c b/tools/fdtgrep.c index 7eabcab4399..f1ff1946bd4 100644 --- a/tools/fdtgrep.c +++ b/tools/fdtgrep.c @@ -63,6 +63,7 @@ struct display_info { int types_inc; /* Mask of types that we include (FDT_IS...) */ int types_exc; /* Mask of types that we exclude (FDT_IS...) */ int invert; /* Invert polarity of match */ + int props_up; /* Imply properties up to supernodes */ struct value_node *value_head; /* List of values to match */ const char *output_fname; /* Output filename */ FILE *fout; /* File to write dts/dtb output */ @@ -375,8 +376,9 @@ static int display_fdt_by_regions(struct display_info *disp, const void *blob, const char *str; int str_base = fdt_off_dt_strings(blob); - for (offset = 0; offset < fdt_size_dt_strings(blob); - offset += strlen(str) + 1) { + for (offset = 0; + offset < (int)fdt_size_dt_strings(blob); + offset += strlen(str) + 1) { str = fdt_string(blob, offset); int len = strlen(str) + 1; int show; @@ -431,7 +433,7 @@ static int dump_fdt_regions(struct display_info *disp, const void *blob, { struct fdt_header *fdt; int size, struct_start; - int ptr; + unsigned int ptr; int i; /* Set up a basic header (even if we don't actually write it) */ @@ -575,15 +577,65 @@ static int check_type_include(void *priv, int type, const char *data, int size) } /** - * h_include() - Include handler function for fdt_find_regions() + * check_props() - Check if a node has properties that we want to include + * + * Calls check_type_include() for each property in the nodn, returning 1 if + * that function returns 1 for any of them + * + * @disp: Display structure, holding info about our options + * @fdt: Devicetree blob to check + * @node: Node offset to check + * @inc: Current value of the 'include' variable (see h_include()) + * Return: 0 to exclude, 1 to include, -1 if no information is available + */ +static int check_props(struct display_info *disp, const void *fdt, int node, + int inc) +{ + int offset; + + for (offset = fdt_first_property_offset(fdt, node); + offset > 0 && inc != 1; + offset = fdt_next_property_offset(fdt, offset)) { + const struct fdt_property *prop; + const char *str; + + prop = fdt_get_property_by_offset(fdt, offset, NULL); + if (!prop) + continue; + str = fdt_string(fdt, fdt32_to_cpu(prop->nameoff)); + inc = check_type_include(disp, FDT_NODE_HAS_PROP, str, + strlen(str)); + } + + /* if requested, check all subnodes for this property too */ + if (inc != 1 && disp->props_up) { + int subnode; + + for (subnode = fdt_first_subnode(fdt, node); + subnode > 0 && inc != 1; + subnode = fdt_next_subnode(fdt, subnode)) + inc = check_props(disp, fdt, subnode, inc); + } + + return inc; +} + +/** + * h_include() - Include handler function for fdt_first_region() * * This function decides whether to include or exclude a node, property or - * compatible string. The function is defined by fdt_find_regions(). + * compatible string. The function is defined by fdt_first_region(). * * The algorithm is documented in the code - disp->invert is 0 for normal * operation, and 1 to invert the sense of all matches. * - * See + * @priv: Private pointer as passed to fdtgrep_find_regions() + * @fdt: Pointer to FDT blob + * @offset: Offset of this node / property + * @type: Type of this part, FDT_IS_... + * @data: Pointer to data (node name, property name, compatible string) + * @size: Size of data, or 0 if none + * Return: 0 to exclude, 1 to include, -1 if no information is available */ static int h_include(void *priv, const void *fdt, int offset, int type, const char *data, int size) @@ -610,31 +662,13 @@ static int h_include(void *priv, const void *fdt, int offset, int type, (disp->types_inc & FDT_NODE_HAS_PROP)) { debug(" - checking node '%s'\n", fdt_get_name(fdt, offset, NULL)); - for (offset = fdt_first_property_offset(fdt, offset); - offset > 0 && inc != 1; - offset = fdt_next_property_offset(fdt, offset)) { - const struct fdt_property *prop; - const char *str; - - prop = fdt_get_property_by_offset(fdt, offset, NULL); - if (!prop) - continue; - str = fdt_string(fdt, fdt32_to_cpu(prop->nameoff)); - inc = check_type_include(priv, FDT_NODE_HAS_PROP, str, - strlen(str)); - } + inc = check_props(disp, fdt, offset, inc); if (inc == -1) inc = 0; } - switch (inc) { - case 1: - inc = !disp->invert; - break; - case 0: - inc = disp->invert; - break; - } + if (inc != -1 && disp->invert) + inc = !inc; debug(" - returning %d\n", inc); return inc; @@ -683,10 +717,10 @@ static int fdtgrep_find_regions(const void *fdt, return new_count; } else if (new_count <= max_regions) { /* - * The alias regions will now be at the end of the list. - * Sort the regions by offset to get things into the - * right order - */ + * The alias regions will now be at the end of the list. + * Sort the regions by offset to get things into the + * right order + */ count = new_count; qsort(region, count, sizeof(struct fdt_region), h_cmp_region); @@ -821,7 +855,7 @@ static int do_fdtgrep(struct display_info *disp, const char *filename) region, max_regions, path, sizeof(path), disp->flags); if (count < 0) { - report_error("fdt_find_regions", count); + report_error("fdtgrep_find_regions", count); free(region); return -1; } @@ -880,7 +914,7 @@ static int do_fdtgrep(struct display_info *disp, const char *filename) size = fdt_totalsize(fdt); } - if (size != fwrite(fdt, 1, size, disp->fout)) { + if ((size_t)size != fwrite(fdt, 1, size, disp->fout)) { fprintf(stderr, "Write failure, %d bytes\n", size); free(fdt); ret = 1; @@ -932,9 +966,9 @@ static const char usage_synopsis[] = case '?': usage("unknown option"); static const char usage_short_opts[] = - "haAc:b:C:defg:G:HIlLmn:N:o:O:p:P:rRsStTv" + "haAc:b:C:defg:G:HIlLmn:N:o:O:p:P:rRsStTuv" USAGE_COMMON_SHORT_OPTS; -static struct option const usage_long_opts[] = { +static const struct option usage_long_opts[] = { {"show-address", no_argument, NULL, 'a'}, {"colour", no_argument, NULL, 'A'}, {"include-node-with-prop", a_argument, NULL, 'b'}, @@ -952,6 +986,8 @@ static struct option const usage_long_opts[] = { {"include-mem", no_argument, NULL, 'm'}, {"include-node", a_argument, NULL, 'n'}, {"exclude-node", a_argument, NULL, 'N'}, + {"out", a_argument, NULL, 'o'}, + {"out-format", a_argument, NULL, 'O'}, {"include-prop", a_argument, NULL, 'p'}, {"exclude-prop", a_argument, NULL, 'P'}, {"remove-strings", no_argument, NULL, 'r'}, @@ -960,8 +996,7 @@ static struct option const usage_long_opts[] = { {"skip-supernodes", no_argument, NULL, 'S'}, {"show-stringtab", no_argument, NULL, 't'}, {"show-aliases", no_argument, NULL, 'T'}, - {"out", a_argument, NULL, 'o'}, - {"out-format", a_argument, NULL, 'O'}, + {"props-up-to-supernode", no_argument, NULL, 'u'}, {"invert-match", no_argument, NULL, 'v'}, USAGE_COMMON_LONG_OPTS, }; @@ -983,6 +1018,8 @@ static const char * const usage_opts_help[] = { "Include mem_rsvmap section in binary output", "Node to include in grep", "Node to exclude in grep", + "-o <output file>", + "-O <output format>", "Property to include in grep", "Property to exclude in grep", "Remove unused strings from string table", @@ -991,8 +1028,7 @@ static const char * const usage_opts_help[] = { "Don't include supernodes of matching nodes", "Include string table in binary output", "Include matching aliases in output", - "-o <output file>", - "-O <output format>", + "Add -p properties to supernodes too", "Invert the sense of matching (select non-matching lines)", USAGE_COMMON_OPTS_HELP }; @@ -1124,6 +1160,9 @@ static void scan_args(struct display_info *disp, int argc, char *argv[]) case 'H': disp->header = 1; break; + case 'I': + disp->show_dts_version = 1; + break; case 'l': disp->region_list = 1; break; @@ -1176,12 +1215,12 @@ static void scan_args(struct display_info *disp, int argc, char *argv[]) case 'T': disp->add_aliases = 1; break; + case 'u': + disp->props_up = 1; + break; case 'v': disp->invert = 1; break; - case 'I': - disp->show_dts_version = 1; - break; } if (type && value_add(disp, &disp->value_head, type, inc, diff --git a/tools/logos/stm32f469-discovery.bmp b/tools/logos/stm32f469-discovery.bmp Binary files differnew file mode 100644 index 00000000000..ecc8d984218 --- /dev/null +++ b/tools/logos/stm32f469-discovery.bmp diff --git a/tools/mkeficapsule.c b/tools/mkeficapsule.c index b8fc6069b58..6a261ff549d 100644 --- a/tools/mkeficapsule.c +++ b/tools/mkeficapsule.c @@ -16,7 +16,6 @@ #include <sys/stat.h> #include <sys/types.h> #include <uuid/uuid.h> -#include <linux/kconfig.h> #include <gnutls/gnutls.h> #include <gnutls/pkcs7.h> diff --git a/tools/mxsboot.c b/tools/mxsboot.c index 04d86f87a86..8f4018aa560 100644 --- a/tools/mxsboot.c +++ b/tools/mxsboot.c @@ -478,7 +478,7 @@ static int mx28_create_nand_image(int infd, int outfd) goto err0; } - memset(buf, 0, size); + memset(buf, 0xff, size); fcb = mx28_nand_get_fcb(MAX_BOOTSTREAM_SIZE); if (!fcb) { diff --git a/tools/patman/pyproject.toml b/tools/patman/pyproject.toml index a54211f7069..fcefcf66960 100644 --- a/tools/patman/pyproject.toml +++ b/tools/patman/pyproject.toml @@ -4,11 +4,11 @@ build-backend = "setuptools.build_meta" [project] name = "patch-manager" -version = "0.0.2" +version = "0.0.6" authors = [ { name="Simon Glass", email="sjg@chromium.org" }, ] -dependencies = ["u_boot_pylib"] +dependencies = ["u_boot_pylib >= 0.0.6"] description = "Patman patch manager" readme = "README.rst" requires-python = ">=3.7" @@ -19,11 +19,11 @@ classifiers = [ ] [project.urls] -"Homepage" = "https://u-boot.readthedocs.io/en/latest/develop/patman.html" +"Homepage" = "https://docs.u-boot.org/en/latest/develop/patman.html" "Bug Tracker" = "https://source.denx.de/groups/u-boot/-/issues" [project.scripts] -patman = "patman.__main__" +patman = "patman.__main__:run_patman" [tool.setuptools.package-data] patman = ["*.rst"] diff --git a/tools/u_boot_pylib/README.rst b/tools/u_boot_pylib/README.rst index 93858f5571d..36a18256d8b 100644 --- a/tools/u_boot_pylib/README.rst +++ b/tools/u_boot_pylib/README.rst @@ -1,7 +1,7 @@ .. SPDX-License-Identifier: GPL-2.0+ # U-Boot Python Library -===================== +======================= This is a Python library used by various U-Boot tools, including patman, buildman and binman. diff --git a/tools/u_boot_pylib/pyproject.toml b/tools/u_boot_pylib/pyproject.toml index 037c5d629ec..ce2355084ac 100644 --- a/tools/u_boot_pylib/pyproject.toml +++ b/tools/u_boot_pylib/pyproject.toml @@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta" [project] name = "u_boot_pylib" -version = "0.0.2" +version = "0.0.6" authors = [ { name="Simon Glass", email="sjg@chromium.org" }, ] @@ -18,9 +18,8 @@ classifiers = [ ] [project.urls] -"Homepage" = "https://u-boot.readthedocs.io" +"Homepage" = "https://docs.u-boot.org" "Bug Tracker" = "https://source.denx.de/groups/u-boot/-/issues" -[tool.setuptools.packages.find] -where = [".."] -include = ["u_boot_pylib*"] +[tool.setuptools.package-data] +u_boot_pylib = ["*.rst"] |