From 79d7b11102e31f3b92afff1c94dd9fe1a8b9a9e4 Mon Sep 17 00:00:00 2001 From: Paul HENRYS Date: Mon, 25 Nov 2024 18:47:15 +0100 Subject: aes: Allow to store randomly generated IV in the FIT When the initialisation vector is randomly generated, its value shall be stored in the FIT together with the encrypted data. The changes allow to store the IV in the FIT also in the case where the key is not stored in the DTB but retrieved somewhere else at runtime. Signed-off-by: Paul HENRYS Reviewed-by: Simon Glass --- include/image.h | 15 +++++++++++++++ lib/aes/aes-encrypt.c | 7 +++++++ tools/image-host.c | 2 +- 3 files changed, 23 insertions(+), 1 deletion(-) diff --git a/include/image.h b/include/image.h index 9be5acd8158..cfe3c971a36 100644 --- a/include/image.h +++ b/include/image.h @@ -1788,6 +1788,21 @@ struct cipher_algo { const unsigned char *data, int data_len, unsigned char **cipher, int *cipher_len); + /** + * add_cipher_data() - Add cipher data to the FIT and device tree + * + * This is used to add the ciphered data to the FIT and other cipher + * related information (key and initialization vector) to a device tree. + * + * @info: Pointer to image cipher information. + * @keydest: Pointer to a device tree where the key and IV can be + * stored. keydest can be NULL when the key is retrieved at + * runtime by another mean. + * @fit: Pointer to the FIT image. + * @node_noffset: Offset where the cipher information are stored in the + * FIT. + * return: 0 on success, a negative error code otherwise. + */ int (*add_cipher_data)(struct image_cipher_info *info, void *keydest, void *fit, int node_noffset); diff --git a/lib/aes/aes-encrypt.c b/lib/aes/aes-encrypt.c index e74e35eaa28..90e1407b4f0 100644 --- a/lib/aes/aes-encrypt.c +++ b/lib/aes/aes-encrypt.c @@ -84,6 +84,13 @@ int image_aes_add_cipher_data(struct image_cipher_info *info, void *keydest, char name[128]; int ret = 0; + if (!keydest && !info->ivname) { + /* At least, store the IV in the FIT image */ + ret = fdt_setprop(fit, node_noffset, "iv", + info->iv, info->cipher->iv_len); + goto done; + } + /* Either create or overwrite the named cipher node */ parent = fdt_subnode_offset(keydest, 0, FIT_CIPHER_NODENAME); if (parent == -FDT_ERR_NOTFOUND) { diff --git a/tools/image-host.c b/tools/image-host.c index 5e01b853c50..16389bd4880 100644 --- a/tools/image-host.c +++ b/tools/image-host.c @@ -535,7 +535,7 @@ fit_image_process_cipher(const char *keydir, void *keydest, void *fit, * size values * And, if needed, write the iv in the FIT file */ - if (keydest) { + if (keydest || (!keydest && !info.ivname)) { ret = info.cipher->add_cipher_data(&info, keydest, fit, node_noffset); if (ret) { fprintf(stderr, -- cgit v1.3.1 From e2cc9b4fc10f521fac098ab5e324446125e6a85d Mon Sep 17 00:00:00 2001 From: Paul HENRYS Date: Mon, 25 Nov 2024 18:47:16 +0100 Subject: tools: binman: add 'fit, encrypt' property to pass keys directory to mkimage mkimage can be used for both signing the FIT or encrypt its content and the option '-k' can be used to pass a directory where both signing and encryption keys can be retrieved. Adding 'fit,encrypt' property to the 'fit' node, leads to try to find keys directory among binman include directories. _get_priv_keys_dir() is renamed as _get_keys_dir() and adapted to support both signing and encryption nodes in the FIT. Signed-off-by: Paul HENRYS Reviewed-by: Simon Glass --- tools/binman/btool/mkimage.py | 8 ++++---- tools/binman/entries.rst | 7 +++++++ tools/binman/etype/fit.py | 25 ++++++++++++++++++------- 3 files changed, 29 insertions(+), 11 deletions(-) diff --git a/tools/binman/btool/mkimage.py b/tools/binman/btool/mkimage.py index 78d3301bc10..3f84220fb1a 100644 --- a/tools/binman/btool/mkimage.py +++ b/tools/binman/btool/mkimage.py @@ -22,7 +22,7 @@ class Bintoolmkimage(bintool.Bintool): # pylint: disable=R0913 def run(self, reset_timestamp=False, output_fname=None, external=False, - pad=None, align=None, priv_keys_dir=None): + pad=None, align=None, keys_dir=None): """Run mkimage Args: @@ -34,7 +34,7 @@ class Bintoolmkimage(bintool.Bintool): other things to be easily added later, if required, such as signatures align: Bytes to use for alignment of the FIT and its external data - priv_keys_dir: Path to directory containing private keys + keys_dir: Path to directory containing private and encryption keys version: True to get the mkimage version """ args = [] @@ -46,8 +46,8 @@ class Bintoolmkimage(bintool.Bintool): args += ['-B', f'{align:x}'] if reset_timestamp: args.append('-t') - if priv_keys_dir: - args += ['-k', f'{priv_keys_dir}'] + if keys_dir: + args += ['-k', f'{keys_dir}'] if output_fname: args += ['-F', output_fname] return self.run_cmd(*args) diff --git a/tools/binman/entries.rst b/tools/binman/entries.rst index e918162fb48..53024acad4a 100644 --- a/tools/binman/entries.rst +++ b/tools/binman/entries.rst @@ -871,6 +871,13 @@ The top-level 'fit' node supports the following special properties: -k flag. All the keys required for signing FIT must be available at time of signing and must be located in single include directory. + fit,encrypt + Enable data encryption in FIT images via mkimage. If the property + is found, the keys path is detected among binman include + directories and passed to mkimage via -k flag. All the keys + required for encrypting the FIT must be available at the time of + encrypting and must be located in a single include directory. + Substitutions ~~~~~~~~~~~~~ diff --git a/tools/binman/etype/fit.py b/tools/binman/etype/fit.py index b5afbda41b5..70be9bea479 100644 --- a/tools/binman/etype/fit.py +++ b/tools/binman/etype/fit.py @@ -110,6 +110,13 @@ class Entry_fit(Entry_section): available at time of signing and must be located in single include directory. + fit,encrypt + Enable data encryption in FIT images via mkimage. If the property + is found, the keys path is detected among binman include + directories and passed to mkimage via -k flag. All the keys + required for encrypting the FIT must be available at the time of + encrypting and must be located in a single include directory. + Substitutions ~~~~~~~~~~~~~ @@ -518,14 +525,14 @@ class Entry_fit(Entry_section): # are removed from self._entries later. self._priv_entries = dict(self._entries) - def _get_priv_keys_dir(self, data): - """Detect private keys path among binman include directories + def _get_keys_dir(self, data): + """Detect private and encryption keys path among binman include directories Args: data: FIT image in binary format Returns: - str: Single path containing all private keys found or None + str: Single path containing all keys found or None Raises: ValueError: Filename 'rsa2048.key' not found in input path @@ -533,11 +540,14 @@ class Entry_fit(Entry_section): """ def _find_keys_dir(node): for subnode in node.subnodes: - if subnode.name.startswith('signature'): + if (subnode.name.startswith('signature') or + subnode.name.startswith('cipher')): if subnode.props.get('key-name-hint') is None: continue hint = subnode.props['key-name-hint'].value - name = tools.get_input_filename(f"{hint}.key") + name = tools.get_input_filename( + f"{hint}.key" if subnode.name.startswith('signature') + else f"{hint}.bin") path = os.path.dirname(name) if path not in paths: paths.append(path) @@ -587,8 +597,9 @@ class Entry_fit(Entry_section): align = self._fit_props.get('fit,align') if align is not None: args.update({'align': fdt_util.fdt32_to_cpu(align.value)}) - if self._fit_props.get('fit,sign') is not None: - args.update({'priv_keys_dir': self._get_priv_keys_dir(data)}) + if (self._fit_props.get('fit,sign') is not None or + self._fit_props.get('fit,encrypt') is not None): + args.update({'keys_dir': self._get_keys_dir(data)}) if self.mkimage.run(reset_timestamp=True, output_fname=output_fname, **args) is None: if not self.GetAllowMissing(): -- cgit v1.3.1 From 1a957ff5d47a1f7e45c30c92da03972ea11409a7 Mon Sep 17 00:00:00 2001 From: Paul HENRYS Date: Mon, 25 Nov 2024 18:47:17 +0100 Subject: tools: binman: Add tests for FIT with data encrypted by mkimage Test the property 'fit,encrypt' to encrypt FIT data. Signed-off-by: Paul HENRYS --- tools/binman/ftest.py | 45 +++++++++++++++++++ tools/binman/test/343_fit_encrypt_data.dts | 53 +++++++++++++++++++++++ tools/binman/test/344_fit_encrypt_data_no_key.dts | 53 +++++++++++++++++++++++ tools/binman/test/aes256.bin | 1 + 4 files changed, 152 insertions(+) create mode 100644 tools/binman/test/343_fit_encrypt_data.dts create mode 100644 tools/binman/test/344_fit_encrypt_data_no_key.dts create mode 100644 tools/binman/test/aes256.bin diff --git a/tools/binman/ftest.py b/tools/binman/ftest.py index 156567ace77..92c6e592856 100644 --- a/tools/binman/ftest.py +++ b/tools/binman/ftest.py @@ -7900,5 +7900,50 @@ fdt fdtmap Extract the devicetree blob from the fdtmap extra_indirs=[test_subdir])[0] + def testSimpleFitEncryptedData(self): + """Test an image with a FIT containing data to be encrypted""" + data = tools.read_file(self.TestFile("aes256.bin")) + self._MakeInputFile("keys/aes256.bin", data) + + keys_subdir = os.path.join(self._indir, "keys") + data = self._DoReadFileDtb( + '343_fit_encrypt_data.dts', + extra_indirs=[keys_subdir])[0] + + fit = fdt.Fdt.FromData(data) + fit.Scan() + + # Extract the encrypted data and the Initialization Vector from the FIT + node = fit.GetNode('/images/u-boot') + subnode = fit.GetNode('/images/u-boot/cipher') + data_size_unciphered = int.from_bytes(fit.GetProps(node)['data-size-unciphered'].bytes, + byteorder='big') + self.assertEqual(data_size_unciphered, len(U_BOOT_NODTB_DATA)) + + # Retrieve the key name from the FIT removing any null byte + key_name = fit.GetProps(subnode)['key-name-hint'].bytes.replace(b'\x00', b'') + with open(self.TestFile(key_name.decode('ascii') + '.bin'), 'rb') as file: + key = file.read() + iv = fit.GetProps(subnode)['iv'].bytes.hex() + enc_data = fit.GetProps(node)['data'].bytes + outdir = tools.get_output_dir() + enc_data_file = os.path.join(outdir, 'encrypted_data.bin') + tools.write_file(enc_data_file, enc_data) + data_file = os.path.join(outdir, 'data.bin') + + # Decrypt the encrypted data from the FIT and compare the data + tools.run('openssl', 'enc', '-aes-256-cbc', '-nosalt', '-d', '-in', + enc_data_file, '-out', data_file, '-K', key.hex(), '-iv', iv) + with open(data_file, 'r') as file: + dec_data = file.read() + self.assertEqual(U_BOOT_NODTB_DATA, dec_data.encode('ascii')) + + def testSimpleFitEncryptedDataMissingKey(self): + """Test an image with a FIT containing data to be encrypted but with a missing key""" + with self.assertRaises(ValueError) as e: + self._DoReadFile('344_fit_encrypt_data_no_key.dts') + + self.assertIn("Filename 'aes256.bin' not found in input path", str(e.exception)) + if __name__ == "__main__": unittest.main() diff --git a/tools/binman/test/343_fit_encrypt_data.dts b/tools/binman/test/343_fit_encrypt_data.dts new file mode 100644 index 00000000000..d70de3426cf --- /dev/null +++ b/tools/binman/test/343_fit_encrypt_data.dts @@ -0,0 +1,53 @@ +// SPDX-License-Identifier: GPL-2.0+ + +/dts-v1/; + +/ { + #address-cells = <1>; + #size-cells = <1>; + + binman { + fit { + fit,encrypt; + description = "Test a FIT with encrypted data"; + #address-cells = <1>; + + images { + u-boot { + description = "U-Boot"; + type = "firmware"; + arch = "arm64"; + os = "U-Boot"; + compression = "none"; + load = <00000000>; + entry = <00000000>; + cipher { + algo = "aes256"; + key-name-hint = "aes256"; + }; + u-boot-nodtb { + }; + }; + fdt-1 { + description = "Flattened Device Tree blob"; + type = "flat_dt"; + arch = "arm64"; + compression = "none"; + cipher { + algo = "aes256"; + key-name-hint = "aes256"; + }; + }; + }; + + configurations { + default = "conf-1"; + conf-1 { + description = "Boot U-Boot with FDT blob"; + firmware = "u-boot"; + fdt = "fdt-1"; + }; + }; + }; + }; +}; diff --git a/tools/binman/test/344_fit_encrypt_data_no_key.dts b/tools/binman/test/344_fit_encrypt_data_no_key.dts new file mode 100644 index 00000000000..d70de3426cf --- /dev/null +++ b/tools/binman/test/344_fit_encrypt_data_no_key.dts @@ -0,0 +1,53 @@ +// SPDX-License-Identifier: GPL-2.0+ + +/dts-v1/; + +/ { + #address-cells = <1>; + #size-cells = <1>; + + binman { + fit { + fit,encrypt; + description = "Test a FIT with encrypted data"; + #address-cells = <1>; + + images { + u-boot { + description = "U-Boot"; + type = "firmware"; + arch = "arm64"; + os = "U-Boot"; + compression = "none"; + load = <00000000>; + entry = <00000000>; + cipher { + algo = "aes256"; + key-name-hint = "aes256"; + }; + u-boot-nodtb { + }; + }; + fdt-1 { + description = "Flattened Device Tree blob"; + type = "flat_dt"; + arch = "arm64"; + compression = "none"; + cipher { + algo = "aes256"; + key-name-hint = "aes256"; + }; + }; + }; + + configurations { + default = "conf-1"; + conf-1 { + description = "Boot U-Boot with FDT blob"; + firmware = "u-boot"; + fdt = "fdt-1"; + }; + }; + }; + }; +}; diff --git a/tools/binman/test/aes256.bin b/tools/binman/test/aes256.bin new file mode 100644 index 00000000000..09b8bf6254a --- /dev/null +++ b/tools/binman/test/aes256.bin @@ -0,0 +1 @@ +1234567890abcdefghijklmnopqrstuv \ No newline at end of file -- cgit v1.3.1 From 9cc36d654c4d25a128a4df310c8176acd1b7db0f Mon Sep 17 00:00:00 2001 From: Paul HENRYS Date: Mon, 25 Nov 2024 18:51:10 +0100 Subject: tools: dtoc: Allow passing optional input directories An optional list of input directories can be passed to EnsureCompiled() which allows to pass a list of directories where input files can be searched. Signed-off-by: Paul HENRYS Reviewed-by: Simon Glass --- tools/dtoc/fdt_util.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/tools/dtoc/fdt_util.py b/tools/dtoc/fdt_util.py index f1f70568cfe..d5ecc4207d8 100644 --- a/tools/dtoc/fdt_util.py +++ b/tools/dtoc/fdt_util.py @@ -55,7 +55,7 @@ def fdt_cells_to_cpu(val, cells): out = out << 32 | fdt32_to_cpu(val[1]) return out -def EnsureCompiled(fname, tmpdir=None, capture_stderr=False): +def EnsureCompiled(fname, tmpdir=None, capture_stderr=False, indir=None): """Compile an fdt .dts source file into a .dtb binary blob if needed. Args: @@ -63,6 +63,7 @@ def EnsureCompiled(fname, tmpdir=None, capture_stderr=False): left alone tmpdir: Temporary directory for output files, or None to use the tools-module output directory + indir: List of directories where input files can be found Returns: Filename of resulting .dtb file @@ -79,6 +80,8 @@ def EnsureCompiled(fname, tmpdir=None, capture_stderr=False): dtb_output = tools.get_output_filename('source.dtb') search_paths = [os.path.join(os.getcwd(), 'include')] + if indir is not None: + search_paths += indir root, _ = os.path.splitext(fname) cc, args = tools.get_target_compile_tool('cc') args += ['-E', '-P', '-x', 'assembler-with-cpp', '-D__ASSEMBLY__'] -- cgit v1.3.1 From f5c1b12267a9f7ed07d71affb8ff2059338ef6ff Mon Sep 17 00:00:00 2001 From: Paul HENRYS Date: Mon, 25 Nov 2024 18:51:11 +0100 Subject: tools: binman: Pass a list of input directory to EnsureCompiled() Input directories can be passed to binman using the '-I' option and those input directories are now also passed to 'dtc' when run by binman. Signed-off-by: Paul HENRYS Reviewed-by: Simon Glass --- tools/binman/control.py | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/tools/binman/control.py b/tools/binman/control.py index 542c2b45644..e73c598298c 100644 --- a/tools/binman/control.py +++ b/tools/binman/control.py @@ -526,7 +526,7 @@ def _RemoveTemplates(parent): if node.name.startswith('template'): node.Delete() -def PrepareImagesAndDtbs(dtb_fname, select_images, update_fdt, use_expanded): +def PrepareImagesAndDtbs(dtb_fname, select_images, update_fdt, use_expanded, indir): """Prepare the images to be processed and select the device tree This function: @@ -543,6 +543,7 @@ def PrepareImagesAndDtbs(dtb_fname, select_images, update_fdt, use_expanded): use_expanded: True to use expanded versions of entries, if available. So if 'u-boot' is called for, we use 'u-boot-expanded' instead. This is needed if update_fdt is True (although tests may disable it) + indir: List of directories where input files can be found Returns: OrderedDict of images: @@ -558,7 +559,9 @@ def PrepareImagesAndDtbs(dtb_fname, select_images, update_fdt, use_expanded): # Get the device tree ready by compiling it and copying the compiled # output into a file in our output directly. Then scan it for use # in binman. - dtb_fname = fdt_util.EnsureCompiled(dtb_fname) + if indir is None: + indir = [] + dtb_fname = fdt_util.EnsureCompiled(dtb_fname, indir=indir) fname = tools.get_output_filename('u-boot.dtb.out') tools.write_file(fname, tools.read_file(dtb_fname)) dtb = fdt.FdtScan(fname) @@ -846,7 +849,7 @@ def Binman(args): state.SetThreads(args.threads) images = PrepareImagesAndDtbs(dtb_fname, args.image, - args.update_fdt, use_expanded) + args.update_fdt, use_expanded, args.indir) if args.test_section_timeout: # Set the first image to timeout, used in testThreadTimeout() -- cgit v1.3.1 From a4345b19347915adeb2de9e94ed747c8c038029c Mon Sep 17 00:00:00 2001 From: Paul HENRYS Date: Mon, 25 Nov 2024 18:54:21 +0100 Subject: tools: binman: etype: Allow to replace 'NAME' in node names This change allows to replace both 'SEQ' and 'NAME' keywords by respectively a sequence number and the name of the FDT to provide more flexibility in the node name for the device trees included in the FIT. Signed-off-by: Paul HENRYS Reviewed-by: Simon Glass --- tools/binman/entries.rst | 18 ++++++++++ tools/binman/etype/fit.py | 20 +++++++++++ tools/binman/ftest.py | 61 +++++++++++++++++++++++----------- tools/binman/test/345_fit_fdt_name.dts | 58 ++++++++++++++++++++++++++++++++ 4 files changed, 138 insertions(+), 19 deletions(-) create mode 100644 tools/binman/test/345_fit_fdt_name.dts diff --git a/tools/binman/entries.rst b/tools/binman/entries.rst index 53024acad4a..83068ba6d39 100644 --- a/tools/binman/entries.rst +++ b/tools/binman/entries.rst @@ -899,6 +899,9 @@ DEFAULT-SEQ: Sequence number of the default fdt, as provided by the 'default-dt' entry argument +DEFAULT-NAME: + Name of the default fdt, as provided by the 'default-dt' entry argument + Available operations ~~~~~~~~~~~~~~~~~~~~ @@ -960,6 +963,21 @@ You can create config nodes in a similar way:: This tells binman to create nodes `config-1` and `config-2`, i.e. a config for each of your two files. +It is also possible to use NAME in the node names so that the FDT files name +will be used instead of the sequence number. This can be useful to identify +easily at runtime in U-Boot, the config to be used:: + + configurations { + default = "@config-DEFAULT-NAME"; + @config-NAME { + description = "NAME"; + firmware = "atf"; + loadables = "uboot"; + fdt = "fdt-NAME"; + fit,compatible; // optional + }; + }; + Note that if no devicetree files are provided (with '-a of-list' as above) then no nodes will be generated. diff --git a/tools/binman/etype/fit.py b/tools/binman/etype/fit.py index 70be9bea479..343094a16e5 100644 --- a/tools/binman/etype/fit.py +++ b/tools/binman/etype/fit.py @@ -138,6 +138,9 @@ class Entry_fit(Entry_section): Sequence number of the default fdt, as provided by the 'default-dt' entry argument + DEFAULT-NAME: + Name of the default fdt, as provided by the 'default-dt' entry argument + Available operations ~~~~~~~~~~~~~~~~~~~~ @@ -199,6 +202,21 @@ class Entry_fit(Entry_section): This tells binman to create nodes `config-1` and `config-2`, i.e. a config for each of your two files. + It is also possible to use NAME in the node names so that the FDT files name + will be used instead of the sequence number. This can be useful to identify + easily at runtime in U-Boot, the config to be used:: + + configurations { + default = "@config-DEFAULT-NAME"; + @config-NAME { + description = "NAME"; + firmware = "atf"; + loadables = "uboot"; + fdt = "fdt-NAME"; + fit,compatible; // optional + }; + }; + Note that if no devicetree files are provided (with '-a of-list' as above) then no nodes will be generated. @@ -674,6 +692,7 @@ class Entry_fit(Entry_section): f"not found in fdt list: {', '.join(self._fdts)}") seq = self._fdts.index(default_dt) val = val[1:].replace('DEFAULT-SEQ', str(seq + 1)) + val = val.replace('DEFAULT-NAME', self._fit_default_dt) fsw.property_string(pname, val) return elif pname.startswith('fit,'): @@ -740,6 +759,7 @@ class Entry_fit(Entry_section): # Generate nodes for each FDT for seq, fdt_fname in enumerate(self._fdts): node_name = node.name[1:].replace('SEQ', str(seq + 1)) + node_name = node_name.replace('NAME', fdt_fname) if self._fdt_dir: fname = os.path.join(self._fdt_dir, fdt_fname + '.dtb') else: diff --git a/tools/binman/ftest.py b/tools/binman/ftest.py index 92c6e592856..4a2a9f22885 100644 --- a/tools/binman/ftest.py +++ b/tools/binman/ftest.py @@ -4233,44 +4233,54 @@ class TestFunctional(unittest.TestCase): self.assertEqual(SCP_DATA, data[:len(SCP_DATA)]) def CheckFitFdt(self, dts='170_fit_fdt.dts', use_fdt_list=True, - default_dt=None): + default_dt=None, use_seq_num=True): """Check an image with an FIT with multiple FDT images""" - def _CheckFdt(seq, expected_data): + def _CheckFdt(val, expected_data): """Check the FDT nodes Args: - seq: Sequence number to check (0 or 1) + val: Sequence number to check (0 or 1) or fdt name expected_data: Expected contents of 'data' property """ - name = 'fdt-%d' % seq + name = 'fdt-%s' % val fnode = dtb.GetNode('/images/%s' % name) self.assertIsNotNone(fnode) self.assertEqual({'description','type', 'compression', 'data'}, set(fnode.props.keys())) self.assertEqual(expected_data, fnode.props['data'].bytes) - self.assertEqual('fdt-test-fdt%d.dtb' % seq, - fnode.props['description'].value) + description = ( + 'fdt-test-fdt%s.dtb' % val if len(val) == 1 else + 'fdt-%s.dtb' % val + ) + self.assertEqual(description, fnode.props['description'].value) self.assertEqual(fnode.subnodes[0].name, 'hash') - def _CheckConfig(seq, expected_data): + def _CheckConfig(val, expected_data): """Check the configuration nodes Args: - seq: Sequence number to check (0 or 1) + val: Sequence number to check (0 or 1) or fdt name expected_data: Expected contents of 'data' property """ cnode = dtb.GetNode('/configurations') self.assertIn('default', cnode.props) - self.assertEqual('config-2', cnode.props['default'].value) + default = ( + 'config-2' if len(val) == 1 else + 'config-test-fdt2' + ) + self.assertEqual(default, cnode.props['default'].value) - name = 'config-%d' % seq + name = 'config-%s' % val fnode = dtb.GetNode('/configurations/%s' % name) self.assertIsNotNone(fnode) self.assertEqual({'description','firmware', 'loadables', 'fdt'}, set(fnode.props.keys())) - self.assertEqual('conf-test-fdt%d.dtb' % seq, - fnode.props['description'].value) - self.assertEqual('fdt-%d' % seq, fnode.props['fdt'].value) + description = ( + 'conf-test-fdt%s.dtb' % val if len(val) == 1 else + 'conf-%s.dtb' % val + ) + self.assertEqual(description, fnode.props['description'].value) + self.assertEqual('fdt-%s' % val, fnode.props['fdt'].value) entry_args = { 'default-dt': 'test-fdt2', @@ -4291,13 +4301,22 @@ class TestFunctional(unittest.TestCase): fnode = dtb.GetNode('/images/kernel') self.assertIn('data', fnode.props) - # Check all the properties in fdt-1 and fdt-2 - _CheckFdt(1, TEST_FDT1_DATA) - _CheckFdt(2, TEST_FDT2_DATA) + if use_seq_num == True: + # Check all the properties in fdt-1 and fdt-2 + _CheckFdt('1', TEST_FDT1_DATA) + _CheckFdt('2', TEST_FDT2_DATA) - # Check configurations - _CheckConfig(1, TEST_FDT1_DATA) - _CheckConfig(2, TEST_FDT2_DATA) + # Check configurations + _CheckConfig('1', TEST_FDT1_DATA) + _CheckConfig('2', TEST_FDT2_DATA) + else: + # Check all the properties in fdt-1 and fdt-2 + _CheckFdt('test-fdt1', TEST_FDT1_DATA) + _CheckFdt('test-fdt2', TEST_FDT2_DATA) + + # Check configurations + _CheckConfig('test-fdt1', TEST_FDT1_DATA) + _CheckConfig('test-fdt2', TEST_FDT2_DATA) def testFitFdt(self): """Test an image with an FIT with multiple FDT images""" @@ -7945,5 +7964,9 @@ fdt fdtmap Extract the devicetree blob from the fdtmap self.assertIn("Filename 'aes256.bin' not found in input path", str(e.exception)) + def testFitFdtName(self): + """Test an image with an FIT with multiple FDT images using NAME""" + self.CheckFitFdt('345_fit_fdt_name.dts', use_seq_num=False) + if __name__ == "__main__": unittest.main() diff --git a/tools/binman/test/345_fit_fdt_name.dts b/tools/binman/test/345_fit_fdt_name.dts new file mode 100644 index 00000000000..631a8e5f59b --- /dev/null +++ b/tools/binman/test/345_fit_fdt_name.dts @@ -0,0 +1,58 @@ +// SPDX-License-Identifier: GPL-2.0+ + +/dts-v1/; + +/ { + #address-cells = <1>; + #size-cells = <1>; + + binman { + u-boot { + }; + fit { + description = "test-desc"; + #address-cells = <1>; + fit,fdt-list = "of-list"; + + images { + kernel { + description = "Vanilla Linux kernel"; + type = "kernel"; + arch = "ppc"; + os = "linux"; + compression = "gzip"; + load = <00000000>; + entry = <00000000>; + hash-1 { + algo = "crc32"; + }; + hash-2 { + algo = "sha1"; + }; + u-boot { + }; + }; + @fdt-NAME { + description = "fdt-NAME.dtb"; + type = "flat_dt"; + compression = "none"; + hash { + algo = "sha256"; + }; + }; + }; + + configurations { + default = "@config-DEFAULT-NAME"; + @config-NAME { + description = "conf-NAME.dtb"; + firmware = "uboot"; + loadables = "atf"; + fdt = "fdt-NAME"; + }; + }; + }; + u-boot-nodtb { + }; + }; +}; -- cgit v1.3.1 From c7896b3e4892c9b5b5fb723c7f042b9b28e73af0 Mon Sep 17 00:00:00 2001 From: Paul HENRYS Date: Mon, 25 Nov 2024 19:16:53 +0100 Subject: tools: u_boot_pylib: Allow to append input directories to indir append_input_dirs() can be used to append a list of input directories to indir global list. Signed-off-by: Paul HENRYS Reviewed-by: Simon Glass --- tools/u_boot_pylib/tools.py | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/tools/u_boot_pylib/tools.py b/tools/u_boot_pylib/tools.py index 187725b5015..0499a75526f 100644 --- a/tools/u_boot_pylib/tools.py +++ b/tools/u_boot_pylib/tools.py @@ -123,6 +123,22 @@ def set_input_dirs(dirname): indir = dirname tout.debug("Using input directories %s" % indir) +def append_input_dirs(dirname): + """Append a list of input directories to the current list of input + directories + + Args: + dirname: a list of paths to input directories to use for obtaining + files needed by binman to place in the image. + """ + global indir + + for dir in dirname: + if dirname not in indir: + indir.append(dirname) + + tout.debug("Updated input directories %s" % indir) + def get_input_filename(fname, allow_missing=False): """Return a filename for use as input. -- cgit v1.3.1 From e7d7d3307c6109f2bec5dd5ba779996dd891348d Mon Sep 17 00:00:00 2001 From: Paul HENRYS Date: Mon, 25 Nov 2024 19:16:54 +0100 Subject: tools: binman: etype: fit: Append DTB directory to the list of input directories When specifying a directory containing DTBs with 'fit,fdt-list-dir', it can be handy not to have to also specify this directory to the input directories of binman with '-I' option and use the method tools.append_input_dirs() append it. This avoids to have to specify the DTB directory in both the device tree provided to binman and through '-I' option to binman. Signed-off-by: Paul HENRYS Reviewed-by: Simon Glass --- tools/binman/etype/fit.py | 2 ++ tools/binman/ftest.py | 5 ++++- 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/tools/binman/etype/fit.py b/tools/binman/etype/fit.py index 343094a16e5..803fb66ea83 100644 --- a/tools/binman/etype/fit.py +++ b/tools/binman/etype/fit.py @@ -477,6 +477,8 @@ class Entry_fit(Entry_section): self._fdt_dir = fdt_util.GetString(self._node, 'fit,fdt-list-dir') if self._fdt_dir: indir = tools.get_input_filename(self._fdt_dir) + if indir: + tools.append_input_dirs(indir) fdts = glob.glob('*.dtb', root_dir=indir) self._fdts = [os.path.splitext(f)[0] for f in sorted(fdts)] else: diff --git a/tools/binman/ftest.py b/tools/binman/ftest.py index 4a2a9f22885..a553ca9e564 100644 --- a/tools/binman/ftest.py +++ b/tools/binman/ftest.py @@ -4285,14 +4285,17 @@ class TestFunctional(unittest.TestCase): entry_args = { 'default-dt': 'test-fdt2', } + extra_indirs = None if use_fdt_list: entry_args['of-list'] = 'test-fdt1 test-fdt2' if default_dt: entry_args['default-dt'] = default_dt + if use_fdt_list: + extra_indirs = [os.path.join(self._indir, TEST_FDT_SUBDIR)] data = self._DoReadFileDtb( dts, entry_args=entry_args, - extra_indirs=[os.path.join(self._indir, TEST_FDT_SUBDIR)])[0] + extra_indirs=extra_indirs)[0] self.assertEqual(U_BOOT_NODTB_DATA, data[-len(U_BOOT_NODTB_DATA):]) fit_data = data[len(U_BOOT_DATA):-len(U_BOOT_NODTB_DATA)] -- cgit v1.3.1