From 81b71c32005475395b5b4d0945de4e6a9136d191 Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Tue, 8 Feb 2022 11:50:00 -0700 Subject: [PATCH] binman: Move entry-data collection into a Entry method Collecting the data from a list of entries and putting it in a file is a useful operation that will be needed by other entry types. Put this into a method in the Entry class. Add some documentation about how to collect data for an entry type. Signed-off-by: Simon Glass --- tools/binman/binman.rst | 86 +++++++++++++++++++++++++++++++++++ tools/binman/entry.py | 28 ++++++++++++ tools/binman/etype/mkimage.py | 14 ++---- 3 files changed, 118 insertions(+), 10 deletions(-) diff --git a/tools/binman/binman.rst b/tools/binman/binman.rst index d6b95de1f5..771645380e 100644 --- a/tools/binman/binman.rst +++ b/tools/binman/binman.rst @@ -1358,6 +1358,92 @@ development, since dealing with exceptions and problems in threads is more difficult. This avoids any use of ThreadPoolExecutor. +Collecting data for an entry type +--------------------------------- + +Some entry types deal with data obtained from others. For example, +`Entry_mkimage` calls the `mkimage` tool with data from its subnodes:: + + mkimage { + args = "-n test -T script"; + + u-boot-spl { + }; + + u-boot { + }; + }; + +This shows mkimage being passed a file consisting of SPL and U-Boot proper. It +is create by calling `Entry.collect_contents_to_file()`. Note that in this case, +the data is passed to mkimage for processing but does not appear separately in +the image. It may not appear at all, depending on what mkimage does. The +contents of the `mkimage` entry are entirely dependent on the processing done +by the entry, with the provided subnodes (`u-boot-spl` and `u-boot`) simply +providing the input data for that processing. + +Note that `Entry.collect_contents_to_file()` simply concatenates the data from +the different entries together, with no control over alignment, etc. Another +approach is to subclass `Entry_section` so that those features become available, +such as `size` and `pad-byte`. Then the contents of the entry can be obtained by +calling `BuildSectionData()`. + +There are other ways to obtain data also, depending on the situation. If the +entry type is simply signing data which exists elsewhere in the image, then +you can use `Entry_collection` as a base class. It lets you use a property +called `content` which lists the entries containing data to be processed. This +is used by `Entry_vblock`, for example:: + + u_boot: u-boot { + }; + vblock { + content = <&u_boot &dtb>; + keyblock = "firmware.keyblock"; + signprivate = "firmware_data_key.vbprivk"; + version = <1>; + kernelkey = "kernel_subkey.vbpubk"; + preamble-flags = <1>; + }; + + dtb: u-boot-dtb { + }; + +which shows an image containing `u-boot` and `u-boot-dtb`, with the `vblock` +image collecting their contents to produce input for its signing process, +without affecting those entries, which still appear in the final image +untouched. + +Another example is where an entry type needs several independent pieces of input +to function. For example, `Entry_fip` allows a number of different binary blobs +to be placed in their own individual places in a custom data structure in the +output image. To make that work you can add subnodes for each of them and call +`Entry.Create()` on each subnode, as `Entry_fip` does. Then the data for each +blob can come from any suitable place, such as an `Entry_u_boot` or an +`Entry_blob` or anything else:: + + atf-fip { + fip-hdr-flags = /bits/ 64 <0x123>; + soc-fw { + fip-flags = /bits/ 64 <0x123456789abcdef>; + filename = "bl31.bin"; + }; + + u-boot { + fip-uuid = [fc 65 13 92 4a 5b 11 ec + 94 35 ff 2d 1c fc 79 9c]; + }; + }; + +The `soc-fw` node is a `blob-ext` (i.e. it reads in a named binary file) whereas +`u-boot` is a normal entry type. This works because `Entry_fip` selects the +`blob-ext` entry type if the node name (here `soc-fw`) is recognised as being +a known blob type. + +When adding new entry types you are encouraged to use subnodes to provide the +data for processing, unless the `content` approach is more suitable. Ad-hoc +properties and other methods of obtaining data are discouraged, since it adds to +confusion for users. + History / Credits ----------------- diff --git a/tools/binman/entry.py b/tools/binman/entry.py index 631215dfc8..bf68a85b24 100644 --- a/tools/binman/entry.py +++ b/tools/binman/entry.py @@ -1123,3 +1123,31 @@ features to produce new behaviours. update_hash: True if hash should be updated, False if not """ self.update_hash = update_hash + + def collect_contents_to_file(self, entries, prefix): + """Put the contents of a list of entries into a file + + Args: + entries (list of Entry): Entries to collect + prefix (str): Filename prefix of file to write to + + If any entry does not have contents yet, this function returns False + for the data. + + Returns: + Tuple: + bytes: Concatenated data from all the entries (or False) + str: Filename of file written (or False if no data) + str: Unique portion of filename (or False if no data) + """ + data = b'' + for entry in entries: + # First get the input data and put it in a file. If not available, + # try later. + if not entry.ObtainContents(): + return False, False, False + data += entry.GetData() + uniq = self.GetUniqueName() + fname = tools.get_output_filename(f'{prefix}.{uniq}') + tools.write_file(fname, data) + return data, fname, uniq diff --git a/tools/binman/etype/mkimage.py b/tools/binman/etype/mkimage.py index ba4fb25de8..8e74ebb9c0 100644 --- a/tools/binman/etype/mkimage.py +++ b/tools/binman/etype/mkimage.py @@ -51,16 +51,10 @@ class Entry_mkimage(Entry): self.ReadEntries() def ObtainContents(self): - data = b'' - for entry in self._mkimage_entries.values(): - # First get the input data and put it in a file. If not available, - # try later. - if not entry.ObtainContents(): - return False - data += entry.GetData() - uniq = self.GetUniqueName() - input_fname = tools.get_output_filename('mkimage.%s' % uniq) - tools.write_file(input_fname, data) + data, input_fname, uniq = self.collect_contents_to_file( + self._mkimage_entries.values(), 'mkimage') + if data is False: + return False output_fname = tools.get_output_filename('mkimage-out.%s' % uniq) if self.mkimage.run_cmd('-d', input_fname, *self._args, output_fname) is not None: -- 2.39.5