From 9b2fd2d22852ee70c07934a78314b01ad9b96b62 Mon Sep 17 00:00:00 2001 From: Jonas Karlman Date: Sat, 21 Jan 2023 19:01:39 +0000 Subject: [PATCH 1/9] binman: Add support for align argument to mkimage tool Add support to indicate what alignment to use for the FIT and its external data. Pass the alignment to mkimage via the -B flag. Signed-off-by: Jonas Karlman Reviewed-by: Simon Glass --- tools/binman/btool/mkimage.py | 5 ++- tools/binman/entries.rst | 5 +++ tools/binman/etype/fit.py | 8 ++++ tools/binman/ftest.py | 16 ++++++++ tools/binman/test/275_fit_align.dts | 59 +++++++++++++++++++++++++++++ 5 files changed, 92 insertions(+), 1 deletion(-) create mode 100644 tools/binman/test/275_fit_align.dts diff --git a/tools/binman/btool/mkimage.py b/tools/binman/btool/mkimage.py index da5f344162..d5b407c554 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): + pad=None, align=None): """Run mkimage Args: @@ -33,6 +33,7 @@ class Bintoolmkimage(bintool.Bintool): pad: Bytes to use for padding the FIT devicetree output. This allows 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 version: True to get the mkimage version """ args = [] @@ -40,6 +41,8 @@ class Bintoolmkimage(bintool.Bintool): args.append('-E') if pad: args += ['-p', f'{pad:x}'] + if align: + args += ['-B', f'{align:x}'] if reset_timestamp: args.append('-t') if output_fname: diff --git a/tools/binman/entries.rst b/tools/binman/entries.rst index 2b32c131ed..8f11189b7b 100644 --- a/tools/binman/entries.rst +++ b/tools/binman/entries.rst @@ -604,6 +604,11 @@ The top-level 'fit' node supports the following special properties: Indicates that the contents of the FIT are external and provides the external offset. This is passed to mkimage via the -E and -p flags. + fit,align + Indicates what alignment to use for the FIT and its external data, + and provides the alignment to use. This is passed to mkimage via + the -B flag. + fit,fdt-list Indicates the entry argument which provides the list of device tree files for the gen-fdt-nodes operation (as below). This is often diff --git a/tools/binman/etype/fit.py b/tools/binman/etype/fit.py index 0e9d81b9e8..df1ce81f9c 100644 --- a/tools/binman/etype/fit.py +++ b/tools/binman/etype/fit.py @@ -70,6 +70,11 @@ class Entry_fit(Entry_section): Indicates that the contents of the FIT are external and provides the external offset. This is passed to mkimage via the -E and -p flags. + fit,align + Indicates what alignment to use for the FIT and its external data, + and provides the alignment to use. This is passed to mkimage via + the -B flag. + fit,fdt-list Indicates the entry argument which provides the list of device tree files for the gen-fdt-nodes operation (as below). This is often @@ -423,6 +428,9 @@ class Entry_fit(Entry_section): 'external': True, 'pad': fdt_util.fdt32_to_cpu(ext_offset.value) } + align = self._fit_props.get('fit,align') + if align is not None: + args.update({'align': fdt_util.fdt32_to_cpu(align.value)}) if self.mkimage.run(reset_timestamp=True, output_fname=output_fname, **args) is None: # Bintool is missing; just use empty data as the output diff --git a/tools/binman/ftest.py b/tools/binman/ftest.py index be0aea49ce..f0d0afd5b8 100644 --- a/tools/binman/ftest.py +++ b/tools/binman/ftest.py @@ -6309,6 +6309,22 @@ fdt fdtmap Extract the devicetree blob from the fdtmap self.assertEqual(base + 8, inset.image_pos); self.assertEqual(4, inset.size); + def testFitAlign(self): + """Test an image with an FIT with aligned external data""" + data = self._DoReadFile('275_fit_align.dts') + self.assertEqual(4096, len(data)) + + dtb = fdt.Fdt.FromData(data) + dtb.Scan() + + props = self._GetPropTree(dtb, ['data-position']) + expected = { + 'u-boot:data-position': 1024, + 'fdt-1:data-position': 2048, + 'fdt-2:data-position': 3072, + } + self.assertEqual(expected, props) + if __name__ == "__main__": unittest.main() diff --git a/tools/binman/test/275_fit_align.dts b/tools/binman/test/275_fit_align.dts new file mode 100644 index 0000000000..c7b06e390f --- /dev/null +++ b/tools/binman/test/275_fit_align.dts @@ -0,0 +1,59 @@ +// SPDX-License-Identifier: GPL-2.0+ + +/dts-v1/; + +/ { + #address-cells = <1>; + #size-cells = <1>; + + binman { + fit { + description = "test desc"; + #address-cells = <1>; + fit,external-offset = <1024>; + fit,align = <1024>; + + images { + u-boot { + description = "test u-boot"; + type = "standalone"; + arch = "arm64"; + os = "u-boot"; + compression = "none"; + load = <00000000>; + entry = <00000000>; + + u-boot-nodtb { + }; + }; + + fdt-1 { + description = "test fdt"; + type = "flat_dt"; + compression = "none"; + + u-boot-dtb { + }; + }; + + fdt-2 { + description = "test fdt"; + type = "flat_dt"; + compression = "none"; + + u-boot-dtb { + }; + }; + }; + + configurations { + default = "config-1"; + config-1 { + description = "test config"; + fdt = "fdt-1"; + firmware = "u-boot"; + }; + }; + }; + }; +}; From 5ad03fc77dfa055629bfbf283bdf938e6dd27d94 Mon Sep 17 00:00:00 2001 From: Jonas Karlman Date: Sat, 21 Jan 2023 19:01:39 +0000 Subject: [PATCH 2/9] rockchip: Align FIT image data to SD/MMC block length SPL load FIT images by reading the data aligned to block length. Block length aligned image data is read directly to the load address. Unaligned image data is written to an offset of the load address and then the data is memcpy to the load address. This adds a small overhead of having to memcpy unaligned data, something that normally is not an issue. However, TF-A may have a segment that should be loaded into SRAM, e.g. vendor TF-A for RK3568 has a 8KiB segment that should be loaded into the 8KiB PMU SRAM. Having the image data for such segment unaligned result in segment being written to and memcpy from beyond the SRAM boundary, in the end this results in invalid data in SRAM. Aligning the FIT and its external data to MMC block length to work around such issue. Signed-off-by: Jonas Karlman Reviewed-by: Simon Glass --- arch/arm/dts/rockchip-u-boot.dtsi | 1 + 1 file changed, 1 insertion(+) diff --git a/arch/arm/dts/rockchip-u-boot.dtsi b/arch/arm/dts/rockchip-u-boot.dtsi index 234fc5df43..63c8da456b 100644 --- a/arch/arm/dts/rockchip-u-boot.dtsi +++ b/arch/arm/dts/rockchip-u-boot.dtsi @@ -37,6 +37,7 @@ fit,fdt-list = "of-list"; filename = "u-boot.itb"; fit,external-offset = ; + fit,align = <512>; offset = ; images { u-boot { From 00b3d53f156927427b2bec95604acb6f6190c134 Mon Sep 17 00:00:00 2001 From: Jonas Karlman Date: Sat, 21 Jan 2023 19:01:48 +0000 Subject: [PATCH 3/9] binman: Add special subnodes to the nodes generated by split-elf Special nodes, hash and signature, is not being added to the nodes generated for each segment in split-elf operation. Copy the subnode logic used in _gen_fdt_nodes to _gen_split_elf to ensure special nodes are added to the generated nodes. Signed-off-by: Jonas Karlman Reviewed-by: Simon Glass --- tools/binman/entries.rst | 14 ++++++++++++++ tools/binman/etype/fit.py | 23 +++++++++++++++++++++-- tools/binman/ftest.py | 12 ++++++++++++ tools/binman/test/226_fit_split_elf.dts | 6 ++++++ 4 files changed, 53 insertions(+), 2 deletions(-) diff --git a/tools/binman/entries.rst b/tools/binman/entries.rst index 8f11189b7b..78f95dae1a 100644 --- a/tools/binman/entries.rst +++ b/tools/binman/entries.rst @@ -762,6 +762,9 @@ Here is an example showing ATF, TEE and a device tree all combined:: atf-bl31 { }; + hash { + algo = "sha256"; + }; }; @tee-SEQ { @@ -777,6 +780,9 @@ Here is an example showing ATF, TEE and a device tree all combined:: tee-os { }; + hash { + algo = "sha256"; + }; }; }; @@ -805,6 +811,10 @@ ELF file, for example:: arch = "arm64"; type = "firmware"; description = "ARM Trusted Firmware"; + hash { + algo = "sha256"; + value = <...hash of first segment...>; + }; }; atf-2 { data = <...contents of second segment...>; @@ -814,6 +824,10 @@ ELF file, for example:: arch = "arm64"; type = "firmware"; description = "ARM Trusted Firmware"; + hash { + algo = "sha256"; + value = <...hash of second segment...>; + }; }; }; diff --git a/tools/binman/etype/fit.py b/tools/binman/etype/fit.py index df1ce81f9c..bcb606f3f9 100644 --- a/tools/binman/etype/fit.py +++ b/tools/binman/etype/fit.py @@ -228,6 +228,9 @@ class Entry_fit(Entry_section): atf-bl31 { }; + hash { + algo = "sha256"; + }; }; @tee-SEQ { @@ -243,6 +246,9 @@ class Entry_fit(Entry_section): tee-os { }; + hash { + algo = "sha256"; + }; }; }; @@ -271,6 +277,10 @@ class Entry_fit(Entry_section): arch = "arm64"; type = "firmware"; description = "ARM Trusted Firmware"; + hash { + algo = "sha256"; + value = <...hash of first segment...>; + }; }; atf-2 { data = <...contents of second segment...>; @@ -280,6 +290,10 @@ class Entry_fit(Entry_section): arch = "arm64"; type = "firmware"; description = "ARM Trusted Firmware"; + hash { + algo = "sha256"; + value = <...hash of second segment...>; + }; }; }; @@ -548,12 +562,13 @@ class Entry_fit(Entry_section): else: self.Raise("Generator node requires 'fit,fdt-list' property") - def _gen_split_elf(base_node, node, segments, entry_addr): + def _gen_split_elf(base_node, node, depth, segments, entry_addr): """Add nodes for the ELF file, one per group of contiguous segments Args: base_node (Node): Template node from the binman definition node (Node): Node to replace (in the FIT being built) + depth: Current node depth (0 is the base 'fit' node) segments (list): list of segments, each: int: Segment number (0 = first) int: Start address of segment in memory @@ -578,6 +593,10 @@ class Entry_fit(Entry_section): self._raise_subnode( node, f"Unknown directive '{pname}'") + for subnode in node.subnodes: + with fsw.add_node(subnode.name): + _add_node(node, depth + 1, subnode) + def _gen_node(base_node, node, depth, in_images, entry): """Generate nodes from a template @@ -631,7 +650,7 @@ class Entry_fit(Entry_section): self._raise_subnode( node, f'Failed to read ELF file: {str(exc)}') - _gen_split_elf(base_node, node, segments, entry_addr) + _gen_split_elf(base_node, node, depth, segments, entry_addr) def _add_node(base_node, depth, node): """Add nodes to the output FIT diff --git a/tools/binman/ftest.py b/tools/binman/ftest.py index f0d0afd5b8..cd27572571 100644 --- a/tools/binman/ftest.py +++ b/tools/binman/ftest.py @@ -5439,6 +5439,10 @@ fdt fdtmap Extract the devicetree blob from the fdtmap fdt_util.fdt32_to_cpu(atf1.props['load'].value)) self.assertEqual(data, atf1.props['data'].bytes) + hash_node = atf1.FindNode('hash') + self.assertIsNotNone(hash_node) + self.assertEqual({'algo', 'value'}, hash_node.props.keys()) + atf2 = dtb.GetNode('/images/atf-2') self.assertEqual(base_keys, atf2.props.keys()) _, start, data = segments[1] @@ -5446,6 +5450,14 @@ fdt fdtmap Extract the devicetree blob from the fdtmap fdt_util.fdt32_to_cpu(atf2.props['load'].value)) self.assertEqual(data, atf2.props['data'].bytes) + hash_node = atf2.FindNode('hash') + self.assertIsNotNone(hash_node) + self.assertEqual({'algo', 'value'}, hash_node.props.keys()) + + hash_node = dtb.GetNode('/images/tee-1/hash-1') + self.assertIsNotNone(hash_node) + self.assertEqual({'algo', 'value'}, hash_node.props.keys()) + conf = dtb.GetNode('/configurations') self.assertEqual({'default'}, conf.props.keys()) diff --git a/tools/binman/test/226_fit_split_elf.dts b/tools/binman/test/226_fit_split_elf.dts index fab15338b2..22c453e603 100644 --- a/tools/binman/test/226_fit_split_elf.dts +++ b/tools/binman/test/226_fit_split_elf.dts @@ -33,6 +33,9 @@ atf-bl31 { }; + hash { + algo = "sha256"; + }; }; @tee-SEQ { @@ -48,6 +51,9 @@ tee-os { }; + hash-1 { + algo = "sha256"; + }; }; }; From 99e3a2cd4e74b8d6fd7cca3d3dc8e106170ac532 Mon Sep 17 00:00:00 2001 From: Jonas Karlman Date: Sat, 21 Jan 2023 19:01:59 +0000 Subject: [PATCH 4/9] rockchip: Add sha256 hash to FIT images Add sha256 hash to FIT images when CONFIG_SPL_FIT_SIGNATURE=y. Signed-off-by: Jonas Karlman Reviewed-by: Simon Glass --- arch/arm/dts/rockchip-u-boot.dtsi | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/arch/arm/dts/rockchip-u-boot.dtsi b/arch/arm/dts/rockchip-u-boot.dtsi index 63c8da456b..e35902bb63 100644 --- a/arch/arm/dts/rockchip-u-boot.dtsi +++ b/arch/arm/dts/rockchip-u-boot.dtsi @@ -50,6 +50,11 @@ entry = ; u-boot-nodtb { }; +#ifdef CONFIG_SPL_FIT_SIGNATURE + hash { + algo = "sha256"; + }; +#endif }; @atf-SEQ { @@ -65,6 +70,11 @@ atf-bl31 { }; +#ifdef CONFIG_SPL_FIT_SIGNATURE + hash { + algo = "sha256"; + }; +#endif }; @tee-SEQ { fit,operation = "split-elf"; @@ -80,12 +90,22 @@ tee-os { optional; }; +#ifdef CONFIG_SPL_FIT_SIGNATURE + hash { + algo = "sha256"; + }; +#endif }; @fdt-SEQ { description = "fdt-NAME"; compression = "none"; type = "flat_dt"; +#ifdef CONFIG_SPL_FIT_SIGNATURE + hash { + algo = "sha256"; + }; +#endif }; }; From f584d44c2371b9d0027ac30fe4af5475926caecc Mon Sep 17 00:00:00 2001 From: Jonas Karlman Date: Sat, 21 Jan 2023 19:02:12 +0000 Subject: [PATCH 5/9] binman: Add support for selecting firmware to use with split-elf In some cases it is desired for SPL to start TF-A instead of U-Boot proper. Add support for a new property fit,firmware that picks a valid entry and prepends the remaining valid entries to the loadables list generated by the split-elf generator. Signed-off-by: Jonas Karlman Reviewed-by: Simon Glass Reviewed-by: Simon Glass --- tools/binman/entries.rst | 16 +++- tools/binman/etype/fit.py | 62 ++++++++++-- tools/binman/ftest.py | 44 +++++++++ .../test/276_fit_firmware_loadables.dts | 96 +++++++++++++++++++ 4 files changed, 205 insertions(+), 13 deletions(-) create mode 100644 tools/binman/test/276_fit_firmware_loadables.dts diff --git a/tools/binman/entries.rst b/tools/binman/entries.rst index 78f95dae1a..7a04a61399 100644 --- a/tools/binman/entries.rst +++ b/tools/binman/entries.rst @@ -721,6 +721,12 @@ split-elf fit,data Generates a `data = <...>` property with the contents of the segment + fit,firmware + Generates a `firmware = <...>` property. Provides a list of possible + nodes to be used as the `firmware` property value. The first valid + node is picked as the firmware. Any remaining valid nodes is + prepended to the `loadable` property generated by `fit,loadables` + fit,loadables Generates a `loadable = <...>` property with a list of the generated nodes (including all nodes if this operation is used multiple times) @@ -791,7 +797,7 @@ Here is an example showing ATF, TEE and a device tree all combined:: @config-SEQ { description = "conf-NAME.dtb"; fdt = "fdt-SEQ"; - firmware = "u-boot"; + fit,firmware = "atf-1", "u-boot"; fit,loadables; }; }; @@ -846,15 +852,15 @@ is:: configurations { default = "config-1"; config-1 { - loadables = "atf-1", "atf-2", "atf-3", "tee-1", "tee-2"; + loadables = "u-boot", "atf-2", "atf-3", "tee-1", "tee-2"; description = "rk3399-firefly.dtb"; fdt = "fdt-1"; - firmware = "u-boot"; + firmware = "atf-1"; }; }; -U-Boot SPL can then load the firmware (U-Boot proper) and all the loadables -(ATF and TEE), then proceed with the boot. +U-Boot SPL can then load the firmware (ATF) and all the loadables (U-Boot +proper, ATF and TEE), then proceed with the boot. diff --git a/tools/binman/etype/fit.py b/tools/binman/etype/fit.py index bcb606f3f9..cd2943533c 100644 --- a/tools/binman/etype/fit.py +++ b/tools/binman/etype/fit.py @@ -187,6 +187,12 @@ class Entry_fit(Entry_section): fit,data Generates a `data = <...>` property with the contents of the segment + fit,firmware + Generates a `firmware = <...>` property. Provides a list of possible + nodes to be used as the `firmware` property value. The first valid + node is picked as the firmware. Any remaining valid nodes is + prepended to the `loadable` property generated by `fit,loadables` + fit,loadables Generates a `loadable = <...>` property with a list of the generated nodes (including all nodes if this operation is used multiple times) @@ -257,7 +263,7 @@ class Entry_fit(Entry_section): @config-SEQ { description = "conf-NAME.dtb"; fdt = "fdt-SEQ"; - firmware = "u-boot"; + fit,firmware = "atf-1", "u-boot"; fit,loadables; }; }; @@ -312,15 +318,15 @@ class Entry_fit(Entry_section): configurations { default = "config-1"; config-1 { - loadables = "atf-1", "atf-2", "atf-3", "tee-1", "tee-2"; + loadables = "u-boot", "atf-2", "atf-3", "tee-1", "tee-2"; description = "rk3399-firefly.dtb"; fdt = "fdt-1"; - firmware = "u-boot"; + firmware = "atf-1"; }; }; - U-Boot SPL can then load the firmware (U-Boot proper) and all the loadables - (ATF and TEE), then proceed with the boot. + U-Boot SPL can then load the firmware (ATF) and all the loadables (U-Boot + proper, ATF and TEE), then proceed with the boot. """ def __init__(self, section, etype, node): """ @@ -510,6 +516,42 @@ class Entry_fit(Entry_section): return fsw.property(pname, prop.bytes) + def _process_firmware_prop(node): + """Process optional fit,firmware property + + Picks the first valid entry for use as the firmware, remaining valid + entries is prepended to loadables + + Args: + node (Node): Generator node to process + + Returns: + firmware (str): Firmware or None + result (list): List of remaining loadables + """ + val = fdt_util.GetStringList(node, 'fit,firmware') + if val is None: + return None, self._loadables + valid_entries = list(self._loadables) + for name, entry in self.GetEntries().items(): + missing = [] + entry.CheckMissing(missing) + entry.CheckOptional(missing) + if not missing: + valid_entries.append(name) + firmware = None + result = [] + for name in val: + if name in valid_entries: + if not firmware: + firmware = name + elif name not in result: + result.append(name) + for name in self._loadables: + if name != firmware and name not in result: + result.append(name) + return firmware, result + def _gen_fdt_nodes(base_node, node, depth, in_images): """Generate FDT nodes @@ -520,20 +562,24 @@ class Entry_fit(Entry_section): first. Args: - node (None): Generator node to process + node (Node): Generator node to process depth: Current node depth (0 is the base 'fit' node) in_images: True if this is inside the 'images' node, so that 'data' properties should be generated """ if self._fdts: + firmware, fit_loadables = _process_firmware_prop(node) # Generate nodes for each FDT for seq, fdt_fname in enumerate(self._fdts): node_name = node.name[1:].replace('SEQ', str(seq + 1)) fname = tools.get_input_filename(fdt_fname + '.dtb') with fsw.add_node(node_name): for pname, prop in node.props.items(): - if pname == 'fit,loadables': - val = '\0'.join(self._loadables) + '\0' + if pname == 'fit,firmware': + if firmware: + fsw.property_string('firmware', firmware) + elif pname == 'fit,loadables': + val = '\0'.join(fit_loadables) + '\0' fsw.property('loadables', val.encode('utf-8')) elif pname == 'fit,operation': pass diff --git a/tools/binman/ftest.py b/tools/binman/ftest.py index cd27572571..0c4d34dfe4 100644 --- a/tools/binman/ftest.py +++ b/tools/binman/ftest.py @@ -6337,6 +6337,50 @@ fdt fdtmap Extract the devicetree blob from the fdtmap } self.assertEqual(expected, props) + def testFitFirmwareLoadables(self): + """Test an image with an FIT that use fit,firmware""" + if not elf.ELF_TOOLS: + self.skipTest('Python elftools not available') + entry_args = { + 'of-list': 'test-fdt1', + 'default-dt': 'test-fdt1', + 'atf-bl31-path': 'bl31.elf', + 'tee-os-path': 'missing.bin', + } + test_subdir = os.path.join(self._indir, TEST_FDT_SUBDIR) + data = self._DoReadFileDtb( + '276_fit_firmware_loadables.dts', + entry_args=entry_args, + extra_indirs=[test_subdir])[0] + + dtb = fdt.Fdt.FromData(data) + dtb.Scan() + + node = dtb.GetNode('/configurations/conf-uboot-1') + self.assertEqual('u-boot', node.props['firmware'].value) + self.assertEqual(['atf-1', 'atf-2'], + fdt_util.GetStringList(node, 'loadables')) + + node = dtb.GetNode('/configurations/conf-atf-1') + self.assertEqual('atf-1', node.props['firmware'].value) + self.assertEqual(['u-boot', 'atf-2'], + fdt_util.GetStringList(node, 'loadables')) + + node = dtb.GetNode('/configurations/conf-missing-uboot-1') + self.assertEqual('u-boot', node.props['firmware'].value) + self.assertEqual(['atf-1', 'atf-2'], + fdt_util.GetStringList(node, 'loadables')) + + node = dtb.GetNode('/configurations/conf-missing-atf-1') + self.assertEqual('atf-1', node.props['firmware'].value) + self.assertEqual(['u-boot', 'atf-2'], + fdt_util.GetStringList(node, 'loadables')) + + node = dtb.GetNode('/configurations/conf-missing-tee-1') + self.assertEqual('atf-1', node.props['firmware'].value) + self.assertEqual(['u-boot', 'atf-2'], + fdt_util.GetStringList(node, 'loadables')) + if __name__ == "__main__": unittest.main() diff --git a/tools/binman/test/276_fit_firmware_loadables.dts b/tools/binman/test/276_fit_firmware_loadables.dts new file mode 100644 index 0000000000..2f79cdc9bb --- /dev/null +++ b/tools/binman/test/276_fit_firmware_loadables.dts @@ -0,0 +1,96 @@ +// SPDX-License-Identifier: GPL-2.0+ + +/dts-v1/; + +/ { + #address-cells = <1>; + #size-cells = <1>; + + binman { + fit { + description = "test desc"; + #address-cells = <1>; + fit,fdt-list = "of-list"; + + images { + u-boot { + description = "test u-boot"; + type = "standalone"; + arch = "arm64"; + os = "u-boot"; + compression = "none"; + load = <0x00000000>; + entry = <0x00000000>; + + u-boot-nodtb { + }; + }; + tee { + description = "test tee"; + type = "tee"; + arch = "arm64"; + os = "tee"; + compression = "none"; + load = <0x00200000>; + + tee-os { + optional; + }; + }; + @atf-SEQ { + fit,operation = "split-elf"; + description = "test tf-a"; + type = "firmware"; + arch = "arm64"; + os = "arm-trusted-firmware"; + compression = "none"; + fit,load; + fit,entry; + fit,data; + + atf-bl31 { + }; + }; + @fdt-SEQ { + description = "test fdt"; + type = "flat_dt"; + compression = "none"; + }; + }; + + configurations { + default = "@conf-uboot-DEFAULT-SEQ"; + @conf-uboot-SEQ { + description = "uboot config"; + fdt = "fdt-SEQ"; + fit,firmware = "u-boot"; + fit,loadables; + }; + @conf-atf-SEQ { + description = "atf config"; + fdt = "fdt-SEQ"; + fit,firmware = "atf-1", "u-boot"; + fit,loadables; + }; + @conf-missing-uboot-SEQ { + description = "missing uboot config"; + fdt = "fdt-SEQ"; + fit,firmware = "missing-1", "u-boot"; + fit,loadables; + }; + @conf-missing-atf-SEQ { + description = "missing atf config"; + fdt = "fdt-SEQ"; + fit,firmware = "missing-1", "atf-1", "u-boot"; + fit,loadables; + }; + @conf-missing-tee-SEQ { + description = "missing tee config"; + fdt = "fdt-SEQ"; + fit,firmware = "atf-1", "u-boot", "tee"; + fit,loadables; + }; + }; + }; + }; +}; From 7e215ad05f4d9005d00e954e705fac05b86e62dd Mon Sep 17 00:00:00 2001 From: Jonas Karlman Date: Sat, 21 Jan 2023 19:02:26 +0000 Subject: [PATCH 6/9] rockchip: Use atf as firmware and move u-boot to loadables in FIT The FIT generated after the switch to using binman is using different values for firmware and loadables properties compared to the old script. With the old script: firmware = "atf-1"; loadables = "u-boot", "atf-2", ...; After switch to binman: firmware = "u-boot"; loadables = "atf-1", "atf-2", ...; This change result in SPL jumping directly into U-Boot proper instead of initializing TF-A. With this patch the properties change back to: firmware = "atf-1"; loatables = "u-boot", "atf-2", ...; Fixes: e0c0efff2a02 ("rockchip: Support building the all output files in binman") Signed-off-by: Jonas Karlman Reviewed-by: Simon Glass --- arch/arm/dts/rockchip-u-boot.dtsi | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/arm/dts/rockchip-u-boot.dtsi b/arch/arm/dts/rockchip-u-boot.dtsi index e35902bb63..f147dc2066 100644 --- a/arch/arm/dts/rockchip-u-boot.dtsi +++ b/arch/arm/dts/rockchip-u-boot.dtsi @@ -114,7 +114,7 @@ @config-SEQ { description = "NAME.dtb"; fdt = "fdt-SEQ"; - firmware = "u-boot"; + fit,firmware = "atf-1", "u-boot"; fit,loadables; }; }; From b01ae03c0bbd77f70fdbbc076415ce5273808555 Mon Sep 17 00:00:00 2001 From: Samuel Holland Date: Sat, 21 Jan 2023 17:25:16 -0600 Subject: [PATCH 7/9] binman: Add 'min-size' entry property This property sets the minimum size of an entry, including padding but not alignment. It can be used to reserve space for growth of an entry, or to enforce a minimum offset for later entries in the section. Signed-off-by: Samuel Holland Reviewed-by: Simon Glass --- tools/binman/binman.rst | 8 ++++++++ tools/binman/entry.py | 4 ++++ tools/binman/ftest.py | 21 +++++++++++++++++---- tools/binman/test/009_pack_extra.dts | 7 +++++++ 4 files changed, 36 insertions(+), 4 deletions(-) diff --git a/tools/binman/binman.rst b/tools/binman/binman.rst index fa8abdcd86..03a99a19bc 100644 --- a/tools/binman/binman.rst +++ b/tools/binman/binman.rst @@ -615,6 +615,14 @@ size: this size. If this is not provided, it will be set to the size of the contents. +min-size: + Sets the minimum size of the entry. This size includes explicit padding + ('pad-before' and 'pad-after'), but not padding added to meet alignment + requirements. While this does not affect the contents of the entry within + binman itself (the padding is performed only when its parent section is + assembled), the end result will be that the entry ends with the padding + bytes, so may grow. Defaults to 0. + pad-before: Padding before the contents of the entry. Normally this is 0, meaning that the contents start at the beginning of the entry. This can be used diff --git a/tools/binman/entry.py b/tools/binman/entry.py index 5d8696e32a..5eacc5fa6c 100644 --- a/tools/binman/entry.py +++ b/tools/binman/entry.py @@ -49,6 +49,7 @@ class Entry(object): offset: Offset of entry within the section, None if not known yet (in which case it will be calculated by Pack()) size: Entry size in bytes, None if not known + min_size: Minimum entry size in bytes pre_reset_size: size as it was before ResetForPack(). This allows us to keep track of the size we started with and detect size changes uncomp_size: Size of uncompressed data in bytes, if the entry is @@ -114,6 +115,7 @@ class Entry(object): self.name = node and (name_prefix + node.name) or 'none' self.offset = None self.size = None + self.min_size = 0 self.pre_reset_size = None self.uncomp_size = None self.data = None @@ -270,6 +272,7 @@ class Entry(object): self.Raise("Please use 'extend-size' instead of 'expand-size'") self.offset = fdt_util.GetInt(self._node, 'offset') self.size = fdt_util.GetInt(self._node, 'size') + self.min_size = fdt_util.GetInt(self._node, 'min-size', 0) self.orig_offset = fdt_util.GetInt(self._node, 'orig-offset') self.orig_size = fdt_util.GetInt(self._node, 'orig-size') if self.GetImage().copy_to_orig: @@ -507,6 +510,7 @@ class Entry(object): else: self.offset = tools.align(offset, self.align) needed = self.pad_before + self.contents_size + self.pad_after + needed = max(needed, self.min_size) needed = tools.align(needed, self.align_size) size = self.size if not size: diff --git a/tools/binman/ftest.py b/tools/binman/ftest.py index 0c4d34dfe4..6b203dfb64 100644 --- a/tools/binman/ftest.py +++ b/tools/binman/ftest.py @@ -883,9 +883,9 @@ class TestFunctional(unittest.TestCase): self.assertIn('image', control.images) image = control.images['image'] entries = image.GetEntries() - self.assertEqual(5, len(entries)) + self.assertEqual(6, len(entries)) - # First u-boot with padding before and after + # First u-boot with padding before and after (included in minimum size) self.assertIn('u-boot', entries) entry = entries['u-boot'] self.assertEqual(0, entry.offset) @@ -934,8 +934,17 @@ class TestFunctional(unittest.TestCase): self.assertEqual(U_BOOT_DATA + tools.get_bytes(0, 64 - len(U_BOOT_DATA)), data[pos:pos + entry.size]) + # Sixth u-boot with both minimum size and aligned size + self.assertIn('u-boot-min-size', entries) + entry = entries['u-boot-min-size'] + self.assertEqual(128, entry.offset) + self.assertEqual(32, entry.size) + self.assertEqual(U_BOOT_DATA, entry.data[:len(U_BOOT_DATA)]) + self.assertEqual(U_BOOT_DATA + tools.get_bytes(0, 32 - len(U_BOOT_DATA)), + data[pos:pos + entry.size]) + self.CheckNoGaps(entries) - self.assertEqual(128, image.size) + self.assertEqual(160, image.size) dtb = fdt.Fdt(out_dtb_fname) dtb.Scan() @@ -943,7 +952,7 @@ class TestFunctional(unittest.TestCase): expected = { 'image-pos': 0, 'offset': 0, - 'size': 128, + 'size': 160, 'u-boot:image-pos': 0, 'u-boot:offset': 0, @@ -964,6 +973,10 @@ class TestFunctional(unittest.TestCase): 'u-boot-align-both:image-pos': 64, 'u-boot-align-both:offset': 64, 'u-boot-align-both:size': 64, + + 'u-boot-min-size:image-pos': 128, + 'u-boot-min-size:offset': 128, + 'u-boot-min-size:size': 32, } self.assertEqual(expected, props) diff --git a/tools/binman/test/009_pack_extra.dts b/tools/binman/test/009_pack_extra.dts index 1b31555771..8d6f4910c9 100644 --- a/tools/binman/test/009_pack_extra.dts +++ b/tools/binman/test/009_pack_extra.dts @@ -6,6 +6,7 @@ binman { u-boot { + min-size = <12>; pad-before = <3>; pad-after = <5>; }; @@ -31,5 +32,11 @@ align = <64>; align-end = <128>; }; + + u-boot-min-size { + type = "u-boot"; + min-size = <24>; + align-size = <16>; + }; }; }; From c2e13aa9e1a99da9334f0a666783c8f7dd98016f Mon Sep 17 00:00:00 2001 From: Samuel Holland Date: Sat, 21 Jan 2023 17:30:12 -0600 Subject: [PATCH 8/9] dm: core: Use full printf() format when possible Use a more accurate check for determining if the full format string will be handled correctly, since SPL_USE_TINY_PRINTF can be disabled. Signed-off-by: Samuel Holland Reviewed-by: Simon Glass --- drivers/core/dump.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/core/dump.c b/drivers/core/dump.c index 0c7d2ec4d0..3e77832a3a 100644 --- a/drivers/core/dump.c +++ b/drivers/core/dump.c @@ -39,7 +39,7 @@ static void show_devices(struct udevice *dev, int depth, int last_flag, u32 flags = dev_get_flags(dev); /* print the first 20 characters to not break the tree-format. */ - printf(IS_ENABLED(CONFIG_SPL_BUILD) ? " %s %d [ %c ] %s " : + printf(CONFIG_IS_ENABLED(USE_TINY_PRINTF) ? " %s %d [ %c ] %s " : " %-10.10s %3d [ %c ] %-20.20s ", dev->uclass->uc_drv->name, dev_get_uclass_index(dev, NULL), flags & DM_FLAG_ACTIVATED ? '+' : ' ', dev->driver->name); From 060a65e899859dcbf42049a18be20ce7118e7c0e Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Mon, 23 Jan 2023 11:29:41 -0700 Subject: [PATCH 9/9] binman: Fix a test-coverage regression Unfortunately a recent patch snuck through without the require test coverage. Fix it. Signed-off-by: Simon Glass Fixes: 571bc4e67d3 ("binman: Support positioning an entry by and ELF symbol") --- tools/binman/elf_test.py | 13 ++++++++++++- tools/binman/entry_test.py | 19 +++++++++++++++++++ tools/binman/test/embed_data.c | 1 + 3 files changed, 32 insertions(+), 1 deletion(-) diff --git a/tools/binman/elf_test.py b/tools/binman/elf_test.py index 082a3e1d28..8cb55ebb81 100644 --- a/tools/binman/elf_test.py +++ b/tools/binman/elf_test.py @@ -242,7 +242,7 @@ class TestElf(unittest.TestCase): end = offset['embed_end'].offset data = tools.read_file(fname) embed_data = data[start:end] - expect = struct.pack('