From f6abd5227a13e652c6a6c25173403ae19ac9e0f0 Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Tue, 18 Jul 2023 07:24:04 -0600 Subject: [PATCH] binman: Support simple templates Collections can used to collect the contents of other entries into a single entry, but they result in a single entry, with the original entries 'left behind' in their old place. It is useful to be able to specific a set of entries ones and have it used in multiple images, or parts of an image. Implement this mechanism. Signed-off-by: Simon Glass --- tools/binman/binman.rst | 87 ++++++++++++++++++++++++++++++++++++++ tools/binman/control.py | 26 ++++++++++++ tools/binman/etype/section.py | 3 +- tools/binman/ftest.py | 8 ++++ tools/binman/test/286_template.dts | 42 ++++++++++++++++++ 5 files changed, 165 insertions(+), 1 deletion(-) create mode 100644 tools/binman/test/286_template.dts diff --git a/tools/binman/binman.rst b/tools/binman/binman.rst index a4b31fe..8f57b6c 100644 --- a/tools/binman/binman.rst +++ b/tools/binman/binman.rst @@ -727,6 +727,13 @@ optional: Note that missing, optional blobs do not produce a non-zero exit code from binman, although it does show a warning about the missing external blob. +insert-template: + This is not strictly speaking an entry property, since it is processed early + in Binman before the entries are read. It is a list of phandles of nodes to + include in the current (target) node. For each node, its subnodes and their + properties are brought into the target node. See Templates_ below for + more information. + The attributes supported for images and sections are described below. Several are similar to those for entries. @@ -1172,6 +1179,86 @@ If you are having trouble figuring out what is going on, you can use arch/arm/dts/u-boot.dtsi ... found: "arch/arm/dts/juno-r2-u-boot.dtsi" +Templates +========= + +Sometimes multiple images need to be created which have all have a common +part. For example, a board may generate SPI and eMMC images which both include +a FIT. Since the FIT includes many entries, it is tedious to repeat them twice +in the image description. + +Templates provide a simple way to handle this:: + + binman { + multiple-images; + common_part: template-1 { + some-property; + fit { + ... lots of entries in here + }; + + text { + text = "base image"; + }; + }; + + spi-image { + filename = "image-spi.bin"; + insert-template = <&fit>; + + /* things specific to SPI follow */ + footer { + ]; + + text { + text = "SPI image"; + }; + }; + + mmc-image { + filename = "image-mmc.bin"; + insert-template = <&fit>; + + /* things specific to MMC follow */ + footer { + ]; + + text { + text = "MMC image"; + }; + }; + }; + +The template node name must start with 'template', so it is not considered to be +an image itself. + +The mechanism is very simple. For each phandle in the 'insert-templates' +property, the source node is looked up. Then the subnodes of that source node +are copied into the target node, i.e. the one containing the `insert-template` +property. + +If the target node has a node with the same name as a template, its properties +override corresponding properties in the template. This allows the template to +be uses as a base, with the node providing updates to the properties as needed. +The overriding happens recursively. + +Template nodes appear first in each node that they are inserted into and +ordering of template nodes is preserved. Other nodes come afterwards. If a +template node also appears in the target node, then the template node sets the +order. Thus the template can be used to set the ordering, even if the target +node provides all the properties. In the above example, `fit` and `text` appear +first in the `spi-image` and `mmc-image` images, followed by `footer`. + +Where there are multiple template nodes, they are inserted in that order. so +the first template node appears first, then the second. + +Properties in the template node are inserted into the destination node if they +do not exist there. In the example above, `some-property` is added to each of +`spi-image` and `mmc-image`. + +Note that template nodes are not removed from the binman description at present. + + Updating an ELF file ==================== diff --git a/tools/binman/control.py b/tools/binman/control.py index 7e2dd35..e9c4a65 100644 --- a/tools/binman/control.py +++ b/tools/binman/control.py @@ -22,6 +22,7 @@ from binman import bintool from binman import cbfs_util from binman import elf from binman import entry +from dtoc import fdt_util from u_boot_pylib import command from u_boot_pylib import tools from u_boot_pylib import tout @@ -478,6 +479,29 @@ def SignEntries(image_fname, input_fname, privatekey_fname, algo, entry_paths, AfterReplace(image, allow_resize=True, write_map=write_map) +def _ProcessTemplates(parent): + """Handle any templates in the binman description + + Args: + parent: Binman node to process (typically /binman) + + Search though each target node looking for those with an 'insert-template' + property. Use that as a list of references to template nodes to use to + adjust the target node. + + Processing involves copying each subnode of the template node into the + target node. + + For now this is not done recursively, so templates must be at the top level + of the binman image. + + See 'Templates' in the Binman documnentation for details. + """ + for node in parent.subnodes: + tmpl = fdt_util.GetPhandleList(node, 'insert-template') + if tmpl: + node.copy_subnodes_from_phandles(tmpl) + def PrepareImagesAndDtbs(dtb_fname, select_images, update_fdt, use_expanded): """Prepare the images to be processed and select the device tree @@ -520,6 +544,8 @@ def PrepareImagesAndDtbs(dtb_fname, select_images, update_fdt, use_expanded): raise ValueError("Device tree '%s' does not have a 'binman' " "node" % dtb_fname) + _ProcessTemplates(node) + images = _ReadImageDesc(node, use_expanded) if select_images: diff --git a/tools/binman/etype/section.py b/tools/binman/etype/section.py index d9b9e42..7c4d312 100644 --- a/tools/binman/etype/section.py +++ b/tools/binman/etype/section.py @@ -179,7 +179,8 @@ class Entry_section(Entry): Returns: bool: True if the node is a special one, else False """ - return node.name.startswith('hash') or node.name.startswith('signature') + start_list = ('hash', 'signature', 'template') + return any(node.name.startswith(name) for name in start_list) def ReadNode(self): """Read properties from the section node""" diff --git a/tools/binman/ftest.py b/tools/binman/ftest.py index dc9a95d..fc5d8a8 100644 --- a/tools/binman/ftest.py +++ b/tools/binman/ftest.py @@ -6785,6 +6785,14 @@ fdt fdtmap Extract the devicetree blob from the fdtmap data = self._DoReadFileDtb('285_spl_expand.dts', use_expanded=True, entry_args=entry_args)[0] + def testTemplate(self): + """Test using a template""" + TestFunctional._MakeInputFile('vga2.bin', b'#' + VGA_DATA) + data = self._DoReadFile('286_template.dts') + first = U_BOOT_DATA + VGA_DATA + U_BOOT_DTB_DATA + second = U_BOOT_DATA + b'#' + VGA_DATA + U_BOOT_DTB_DATA + self.assertEqual(U_BOOT_IMG_DATA + first + second, data) + if __name__ == "__main__": unittest.main() diff --git a/tools/binman/test/286_template.dts b/tools/binman/test/286_template.dts new file mode 100644 index 0000000..6980dbf --- /dev/null +++ b/tools/binman/test/286_template.dts @@ -0,0 +1,42 @@ +// SPDX-License-Identifier: GPL-2.0+ + +/dts-v1/; + +/ { + #address-cells = <1>; + #size-cells = <1>; + + binman { + u-boot-img { + }; + + common_part: template { + u-boot { + }; + + intel-vga { + filename = "vga.bin"; + }; + }; + + first { + type = "section"; + insert-template = <&common_part>; + + u-boot-dtb { + }; + }; + + second { + type = "section"; + insert-template = <&common_part>; + + u-boot-dtb { + }; + + intel-vga { + filename = "vga2.bin"; + }; + }; + }; +}; -- 2.7.4