[PATCH 1/2] binman: Add a utility module for ATF FIP

Ilias Apalodimas ilias.apalodimas at linaro.org
Thu Nov 25 15:47:30 CET 2021


+cc Sandrine

On Wed, 24 Nov 2021 at 06:09, Simon Glass <sjg at chromium.org> wrote:
>
> Add support for this format which is used by ARM Trusted Firmware to find
> firmware binaries to load.
>
> FIP is like a simpler version of FMAP but uses a UUID instead of a name,
> for each entry.
>
> It supports reading a FIP, writing a FIP and parsing the ATF source code
> to get a list of supported UUIDs.
>
> Signed-off-by: Simon Glass <sjg at chromium.org>
> ---
>
>  scripts/pylint.base           |   8 +-
>  tools/binman/fip_util.py      | 653 ++++++++++++++++++++++++++++++++++
>  tools/binman/fip_util_test.py | 405 +++++++++++++++++++++
>  tools/binman/main.py          |   4 +-
>  4 files changed, 1066 insertions(+), 4 deletions(-)
>  create mode 100755 tools/binman/fip_util.py
>  create mode 100755 tools/binman/fip_util_test.py
>
> diff --git a/scripts/pylint.base b/scripts/pylint.base
> index 4e82dd4a616..a35dbe34d2d 100644
> --- a/scripts/pylint.base
> +++ b/scripts/pylint.base
> @@ -9,11 +9,13 @@ binman.elf_test 5.41
>  binman.entry 2.39
>  binman.entry_test 5.29
>  binman.fdt_test 3.23
> +binman.fip_util 9.86
> +binman.fip_util_test 9.75
>  binman.fmap_util 6.67
>  binman.ftest 7.38
>  binman.image 6.39
>  binman.image_test 4.48
> -binman.main 4.26
> +binman.main 4.03
>  binman.setup 5.00
>  binman.state 3.30
>  blob -1.94
> @@ -33,7 +35,7 @@ buildman.main 1.43
>  buildman.test 6.10
>  buildman.toolchain 5.81
>  capsule_defs 5.00
> -cbfs -1.52
> +cbfs -1.44
>  collection 2.33
>  concurrencytest 6.77
>  conftest -3.84
> @@ -107,7 +109,7 @@ powerpc_mpc85xx_bootpg_resetvec -10.00
>  rkmux 6.76
>  rmboard 7.76
>  scp -6.00
> -section 4.25
> +section 4.31
>  sqfs_common 8.12
>  test 8.18
>  test_000_version 7.50
> diff --git a/tools/binman/fip_util.py b/tools/binman/fip_util.py
> new file mode 100755
> index 00000000000..5f7dbc04d56
> --- /dev/null
> +++ b/tools/binman/fip_util.py
> @@ -0,0 +1,653 @@
> +#!/usr/bin/env python3
> +# SPDX-License-Identifier: GPL-2.0+
> +# Copyright 2021 Google LLC
> +# Written by Simon Glass <sjg at chromium.org>
> +
> +"""Support for ARM's Firmware Image Package (FIP) format
> +
> +FIP is a format similar to FMAP[1] but with fewer features and an obscure UUID
> +instead of the region name.
> +
> +It consists of a header and a table of entries, each pointing to a place in the
> +firmware image where something can be found.
> +
> +[1] https://chromium.googlesource.com/chromiumos/third_party/flashmap/+/refs/heads/master/lib/fmap.h
> +
> +If ATF updates, run this program to update the FIT_TYPE_LIST.
> +
> +ARM Trusted Firmware is available at:
> +
> +https://github.com/ARM-software/arm-trusted-firmware.git
> +"""
> +
> +from argparse import ArgumentParser
> +import collections
> +import io
> +import os
> +import re
> +import struct
> +import sys
> +from uuid import UUID
> +
> +OUR_FILE = os.path.realpath(__file__)
> +OUR_PATH = os.path.dirname(OUR_FILE)
> +
> +# Bring in the patman and dtoc libraries (but don't override the first path
> +# in PYTHONPATH)
> +sys.path.insert(2, os.path.join(OUR_PATH, '..'))
> +
> +# pylint: disable=C0413
> +from patman import command
> +from patman import tools
> +
> +# The TOC header, at the start of the FIP
> +HEADER_FORMAT = '<IIQ'
> +HEADER_LEN = 0x10
> +HEADER_MAGIC = 0xaA640001
> +HEADER_SERIAL = 0x12345678
> +
> +# The entry header (a table of these comes after the TOC header)
> +UUID_LEN = 16
> +ENTRY_FORMAT = f'<{UUID_LEN}sQQQ'
> +ENTRY_SIZE = 0x28
> +
> +HEADER_NAMES = (
> +    'name',
> +    'serial',
> +    'flags',
> +)
> +
> +ENTRY_NAMES = (
> +    'uuid',
> +    'offset',
> +    'size',
> +    'flags',
> +)
> +
> +# Set to True to enable output from running fiptool for debugging
> +VERBOSE = False
> +
> +# Use a class so we can convert the bytes, making the table more readable
> +# pylint: disable=R0903
> +class FipType:
> +    """A FIP entry type that we understand"""
> +    def __init__(self, name, desc, uuid_bytes):
> +        """Create up a new type
> +
> +        Args:
> +            name (str): Short name for the type
> +            desc (str): Longer description for the type
> +            uuid_bytes (bytes): List of 16 bytes for the UUID
> +        """
> +        self.name = name
> +        self.desc = desc
> +        self.uuid = bytes(uuid_bytes)
> +
> +# This is taken from tbbr_config.c in ARM Trusted Firmware
> +FIP_TYPE_LIST = [
> +    # ToC Entry UUIDs
> +    FipType('scp-fwu-cfg', 'SCP Firmware Updater Configuration FWU SCP_BL2U',
> +            [0x65, 0x92, 0x27, 0x03, 0x2f, 0x74, 0xe6, 0x44,
> +             0x8d, 0xff, 0x57, 0x9a, 0xc1, 0xff, 0x06, 0x10]),
> +    FipType('ap-fwu-cfg', 'AP Firmware Updater Configuration BL2U',
> +            [0x60, 0xb3, 0xeb, 0x37, 0xc1, 0xe5, 0xea, 0x41,
> +             0x9d, 0xf3, 0x19, 0xed, 0xa1, 0x1f, 0x68, 0x01]),
> +    FipType('fwu', 'Firmware Updater NS_BL2U',
> +            [0x4f, 0x51, 0x1d, 0x11, 0x2b, 0xe5, 0x4e, 0x49,
> +             0xb4, 0xc5, 0x83, 0xc2, 0xf7, 0x15, 0x84, 0x0a]),
> +    FipType('fwu-cert', 'Non-Trusted Firmware Updater certificate',
> +            [0x71, 0x40, 0x8a, 0xb2, 0x18, 0xd6, 0x87, 0x4c,
> +             0x8b, 0x2e, 0xc6, 0xdc, 0xcd, 0x50, 0xf0, 0x96]),
> +    FipType('tb-fw', 'Trusted Boot Firmware BL2',
> +            [0x5f, 0xf9, 0xec, 0x0b, 0x4d, 0x22, 0x3e, 0x4d,
> +             0xa5, 0x44, 0xc3, 0x9d, 0x81, 0xc7, 0x3f, 0x0a]),
> +    FipType('scp-fw', 'SCP Firmware SCP_BL2',
> +            [0x97, 0x66, 0xfd, 0x3d, 0x89, 0xbe, 0xe8, 0x49,
> +             0xae, 0x5d, 0x78, 0xa1, 0x40, 0x60, 0x82, 0x13]),
> +    FipType('soc-fw', 'EL3 Runtime Firmware BL31',
> +            [0x47, 0xd4, 0x08, 0x6d, 0x4c, 0xfe, 0x98, 0x46,
> +             0x9b, 0x95, 0x29, 0x50, 0xcb, 0xbd, 0x5a, 0x00]),
> +    FipType('tos-fw', 'Secure Payload BL32 (Trusted OS)',
> +            [0x05, 0xd0, 0xe1, 0x89, 0x53, 0xdc, 0x13, 0x47,
> +             0x8d, 0x2b, 0x50, 0x0a, 0x4b, 0x7a, 0x3e, 0x38]),
> +    FipType('tos-fw-extra1', 'Secure Payload BL32 Extra1 (Trusted OS Extra1)',
> +            [0x0b, 0x70, 0xc2, 0x9b, 0x2a, 0x5a, 0x78, 0x40,
> +             0x9f, 0x65, 0x0a, 0x56, 0x82, 0x73, 0x82, 0x88]),
> +    FipType('tos-fw-extra2', 'Secure Payload BL32 Extra2 (Trusted OS Extra2)',
> +            [0x8e, 0xa8, 0x7b, 0xb1, 0xcf, 0xa2, 0x3f, 0x4d,
> +             0x85, 0xfd, 0xe7, 0xbb, 0xa5, 0x02, 0x20, 0xd9]),
> +    FipType('nt-fw', 'Non-Trusted Firmware BL33',
> +            [0xd6, 0xd0, 0xee, 0xa7, 0xfc, 0xea, 0xd5, 0x4b,
> +             0x97, 0x82, 0x99, 0x34, 0xf2, 0x34, 0xb6, 0xe4]),
> +    FipType('rmm-fw', 'Realm Monitor Management Firmware',
> +            [0x6c, 0x07, 0x62, 0xa6, 0x12, 0xf2, 0x4b, 0x56,
> +             0x92, 0xcb, 0xba, 0x8f, 0x63, 0x36, 0x06, 0xd9]),
> +    # Key certificates
> +    FipType('rot-cert', 'Root Of Trust key certificate',
> +            [0x86, 0x2d, 0x1d, 0x72, 0xf8, 0x60, 0xe4, 0x11,
> +             0x92, 0x0b, 0x8b, 0xe7, 0x62, 0x16, 0x0f, 0x24]),
> +    FipType('trusted-key-cert', 'Trusted key certificate',
> +            [0x82, 0x7e, 0xe8, 0x90, 0xf8, 0x60, 0xe4, 0x11,
> +             0xa1, 0xb4, 0x77, 0x7a, 0x21, 0xb4, 0xf9, 0x4c]),
> +    FipType('scp-fw-key-cert', 'SCP Firmware key certificate',
> +            [0x02, 0x42, 0x21, 0xa1, 0xf8, 0x60, 0xe4, 0x11,
> +             0x8d, 0x9b, 0xf3, 0x3c, 0x0e, 0x15, 0xa0, 0x14]),
> +    FipType('soc-fw-key-cert', 'SoC Firmware key certificate',
> +            [0x8a, 0xb8, 0xbe, 0xcc, 0xf9, 0x60, 0xe4, 0x11,
> +             0x9a, 0xd0, 0xeb, 0x48, 0x22, 0xd8, 0xdc, 0xf8]),
> +    FipType('tos-fw-key-cert', 'Trusted OS Firmware key certificate',
> +            [0x94, 0x77, 0xd6, 0x03, 0xfb, 0x60, 0xe4, 0x11,
> +             0x85, 0xdd, 0xb7, 0x10, 0x5b, 0x8c, 0xee, 0x04]),
> +    FipType('nt-fw-key-cert', 'Non-Trusted Firmware key certificate',
> +            [0x8a, 0xd5, 0x83, 0x2a, 0xfb, 0x60, 0xe4, 0x11,
> +             0x8a, 0xaf, 0xdf, 0x30, 0xbb, 0xc4, 0x98, 0x59]),
> +    # Content certificates
> +    FipType('tb-fw-cert', 'Trusted Boot Firmware BL2 certificate',
> +            [0xd6, 0xe2, 0x69, 0xea, 0x5d, 0x63, 0xe4, 0x11,
> +             0x8d, 0x8c, 0x9f, 0xba, 0xbe, 0x99, 0x56, 0xa5]),
> +    FipType('scp-fw-cert', 'SCP Firmware content certificate',
> +            [0x44, 0xbe, 0x6f, 0x04, 0x5e, 0x63, 0xe4, 0x11,
> +             0xb2, 0x8b, 0x73, 0xd8, 0xea, 0xae, 0x96, 0x56]),
> +    FipType('soc-fw-cert', 'SoC Firmware content certificate',
> +            [0xe2, 0xb2, 0x0c, 0x20, 0x5e, 0x63, 0xe4, 0x11,
> +             0x9c, 0xe8, 0xab, 0xcc, 0xf9, 0x2b, 0xb6, 0x66]),
> +    FipType('tos-fw-cert', 'Trusted OS Firmware content certificate',
> +            [0xa4, 0x9f, 0x44, 0x11, 0x5e, 0x63, 0xe4, 0x11,
> +             0x87, 0x28, 0x3f, 0x05, 0x72, 0x2a, 0xf3, 0x3d]),
> +    FipType('nt-fw-cert', 'Non-Trusted Firmware content certificate',
> +            [0x8e, 0xc4, 0xc1, 0xf3, 0x5d, 0x63, 0xe4, 0x11,
> +             0xa7, 0xa9, 0x87, 0xee, 0x40, 0xb2, 0x3f, 0xa7]),
> +    FipType('sip-sp-cert', 'SiP owned Secure Partition content certificate',
> +            [0x77, 0x6d, 0xfd, 0x44, 0x86, 0x97, 0x4c, 0x3b,
> +             0x91, 0xeb, 0xc1, 0x3e, 0x02, 0x5a, 0x2a, 0x6f]),
> +    FipType('plat-sp-cert', 'Platform owned Secure Partition content certificate',
> +            [0xdd, 0xcb, 0xbf, 0x4a, 0xca, 0xd6, 0x11, 0xea,
> +             0x87, 0xd0, 0x02, 0x42, 0xac, 0x13, 0x00, 0x03]),
> +    # Dynamic configs
> +    FipType('hw-config', 'HW_CONFIG',
> +            [0x08, 0xb8, 0xf1, 0xd9, 0xc9, 0xcf, 0x93, 0x49,
> +             0xa9, 0x62, 0x6f, 0xbc, 0x6b, 0x72, 0x65, 0xcc]),
> +    FipType('tb-fw-config', 'TB_FW_CONFIG',
> +            [0x6c, 0x04, 0x58, 0xff, 0xaf, 0x6b, 0x7d, 0x4f,
> +             0x82, 0xed, 0xaa, 0x27, 0xbc, 0x69, 0xbf, 0xd2]),
> +    FipType('soc-fw-config', 'SOC_FW_CONFIG',
> +            [0x99, 0x79, 0x81, 0x4b, 0x03, 0x76, 0xfb, 0x46,
> +             0x8c, 0x8e, 0x8d, 0x26, 0x7f, 0x78, 0x59, 0xe0]),
> +    FipType('tos-fw-config', 'TOS_FW_CONFIG',
> +            [0x26, 0x25, 0x7c, 0x1a, 0xdb, 0xc6, 0x7f, 0x47,
> +             0x8d, 0x96, 0xc4, 0xc4, 0xb0, 0x24, 0x80, 0x21]),
> +    FipType('nt-fw-config', 'NT_FW_CONFIG',
> +            [0x28, 0xda, 0x98, 0x15, 0x93, 0xe8, 0x7e, 0x44,
> +             0xac, 0x66, 0x1a, 0xaf, 0x80, 0x15, 0x50, 0xf9]),
> +    FipType('fw-config', 'FW_CONFIG',
> +            [0x58, 0x07, 0xe1, 0x6a, 0x84, 0x59, 0x47, 0xbe,
> +             0x8e, 0xd5, 0x64, 0x8e, 0x8d, 0xdd, 0xab, 0x0e]),
> +    ] # end
> +
> +FIP_TYPES = {ftype.name: ftype for ftype in FIP_TYPE_LIST}
> +
> +
> +def get_type_uuid(fip_type_or_uuid):
> +    """get_type_uuid() - Convert a type or uuid into both
> +
> +    This always returns a UUID, but may not return a type since it does not do
> +    the reverse lookup.
> +
> +    Args:
> +        fip_type_or_uuid (str or bytes): Either a string containing the name of
> +            an entry (e.g. 'soc-fw') or a bytes(16) containing the UUID
> +
> +    Returns:
> +        tuple:
> +            str: fip type (None if not known)
> +            bytes(16): uuid
> +
> +    Raises:
> +        ValueError: An unknown type was requested
> +    """
> +    if isinstance(fip_type_or_uuid, str):
> +        fip_type = fip_type_or_uuid
> +        lookup = FIP_TYPES.get(fip_type)
> +        if not lookup:
> +            raise ValueError(f"Unknown FIP entry type '{fip_type}'")
> +        uuid = lookup.uuid
> +    else:
> +        fip_type = None
> +        uuid = fip_type_or_uuid
> +    return fip_type, uuid
> +
> +
> +# pylint: disable=R0903
> +class FipHeader:
> +    """Class to represent a FIP header"""
> +    def __init__(self, name, serial, flags):
> +        """Set up a new header object
> +
> +        Args:
> +            name (str): Name, i.e. HEADER_MAGIC
> +            serial (str): Serial value, i.e. HEADER_SERIAL
> +            flags (int64): Flags value
> +        """
> +        self.name = name
> +        self.serial = serial
> +        self.flags = flags
> +
> +
> +# pylint: disable=R0903
> +class FipEntry:
> +    """Class to represent a single FIP entry
> +
> +    This is used to hold the information about an entry, including its contents.
> +    Use the get_data() method to obtain the raw output for writing to the FIP
> +    file.
> +    """
> +    def __init__(self, uuid, offset, size, flags):
> +        self.uuid = uuid
> +        self.offset = offset
> +        self.size = size
> +        self.flags = flags
> +        self.fip_type = None
> +        self.data = None
> +        self.valid = uuid != tools.GetBytes(0, UUID_LEN)
> +        if self.valid:
> +            # Look up the friendly name
> +            matches = {val for (key, val) in FIP_TYPES.items()
> +                       if val.uuid == uuid}
> +            if len(matches) == 1:
> +                self.fip_type = matches.pop().name
> +
> +    @classmethod
> +    def from_type(cls, fip_type_or_uuid, data, flags):
> +        """Create a FipEntry from a type name
> +
> +        Args:
> +            cls (class): This class
> +            fip_type_or_uuid (str or bytes): Name of the type to create, or
> +                bytes(16) uuid
> +            data (bytes): Contents of entry
> +            flags (int64): Flags value
> +
> +        Returns:
> +            FipEntry: Created 241
> +        """
> +        fip_type, uuid = get_type_uuid(fip_type_or_uuid)
> +        fent = FipEntry(uuid, None, len(data), flags)
> +        fent.fip_type = fip_type
> +        fent.data = data
> +        return fent
> +
> +
> +def decode_fip(data):
> +    """Decode a FIP into a header and list of FIP entries
> +
> +    Args:
> +        data (bytes): Data block containing the FMAP
> +
> +    Returns:
> +        Tuple:
> +            header: FipHeader object
> +            List of FipArea objects
> +    """
> +    fields = list(struct.unpack(HEADER_FORMAT, data[:HEADER_LEN]))
> +    header = FipHeader(*fields)
> +    fents = []
> +    pos = HEADER_LEN
> +    while True:
> +        fields = list(struct.unpack(ENTRY_FORMAT, data[pos:pos + ENTRY_SIZE]))
> +        fent = FipEntry(*fields)
> +        if not fent.valid:
> +            break
> +        fent.data = data[fent.offset:fent.offset + fent.size]
> +        fents.append(fent)
> +        pos += ENTRY_SIZE
> +    return header, fents
> +
> +
> +class FipWriter:
> +    """Class to handle writing a ARM Trusted Firmware's Firmware Image Package
> +
> +    Usage is something like:
> +
> +        fip = FipWriter(size)
> +        fip.add_entry('scp-fwu-cfg', tools.ReadFile('something.bin'))
> +        ...
> +        data = cbw.get_data()
> +
> +    Attributes:
> +    """
> +    def __init__(self, flags, align):
> +        self._fip_entries = []
> +        self._flags = flags
> +        self._align = align
> +
> +    def add_entry(self, fip_type, data, flags):
> +        """Add a new entry to the FIP
> +
> +        Args:
> +            fip_type (str): Type to add, e.g. 'tos-fw-config'
> +            data (bytes): Contents of entry
> +            flags (int64): Entry flags
> +
> +        Returns:
> +            FipEntry: entry that was added
> +        """
> +        fent = FipEntry.from_type(fip_type, data, flags)
> +        self._fip_entries.append(fent)
> +        return fent
> +
> +    def get_data(self):
> +        """Obtain the full contents of the FIP
> +
> +        Thhis builds the FIP with headers and all required FIP entries.
> +
> +        Returns:
> +            bytes: data resulting from building the FIP
> +        """
> +        buf = io.BytesIO()
> +        hdr = struct.pack(HEADER_FORMAT, HEADER_MAGIC, HEADER_SERIAL,
> +                          self._flags)
> +        buf.write(hdr)
> +
> +        # Calculate the position fo the first entry
> +        offset = len(hdr)
> +        offset += len(self._fip_entries) * ENTRY_SIZE
> +        offset += ENTRY_SIZE   # terminating entry
> +
> +        for fent in self._fip_entries:
> +            offset = tools.Align(offset, self._align)
> +            fent.offset = offset
> +            offset += fent.size
> +
> +        # Write out the TOC
> +        for fent in self._fip_entries:
> +            hdr = struct.pack(ENTRY_FORMAT, fent.uuid, fent.offset, fent.size,
> +                              fent.flags)
> +            buf.write(hdr)
> +
> +        # Write out the entries
> +        for fent in self._fip_entries:
> +            buf.seek(fent.offset)
> +            buf.write(fent.data)
> +
> +        return buf.getvalue()
> +
> +
> +class FipReader():
> +    """Class to handle reading a Firmware Image Package (FIP)
> +
> +    Usage is something like:
> +        fip = fip_util.FipReader(data)
> +        fent = fip.get_entry('fwu')
> +        self.WriteFile('ufwu.bin', fent.data)
> +        blob = fip.get_entry(
> +            bytes([0xe3, 0xb7, 0x8d, 0x9e, 0x4a, 0x64, 0x11, 0xec,
> +                   0xb4, 0x5c, 0xfb, 0xa2, 0xb9, 0xb4, 0x97, 0x88]))
> +        self.WriteFile('blob.bin', blob.data)
> +    """
> +    def __init__(self, data, read=True):
> +        """Set up a new FitReader
> +
> +        Args:
> +            data (bytes): data to read
> +            read (bool): True to read the data now
> +        """
> +        self.fents = collections.OrderedDict()
> +        self.data = data
> +        if read:
> +            self.read()
> +
> +    def read(self):
> +        """Read all the files in the FIP and add them to self.files"""
> +        self.header, self.fents = decode_fip(self.data)
> +
> +    def get_entry(self, fip_type_or_uuid):
> +        """get_entry() - Find an entry by type or UUID
> +
> +        Args:
> +            fip_type_or_uuid (str or bytes): Name of the type to create, or
> +                    bytes(16) uuid
> +
> +        Returns:
> +            FipEntry: if found
> +
> +        Raises:
> +            ValueError: entry type not found
> +        """
> +        fip_type, uuid = get_type_uuid(fip_type_or_uuid)
> +        for fent in self.fents:
> +            if fent.uuid == uuid:
> +                return fent
> +        label = fip_type
> +        if not label:
> +            label = UUID(bytes=uuid)
> +        raise ValueError(f"Cannot find FIP entry '{label}'")
> +
> +
> +def parse_macros(srcdir):
> +    """parse_macros: Parse the firmware_image_package.h file
> +
> +    Args:
> +        srcdir (str): 'arm-trusted-firmware' source directory
> +
> +    Returns:
> +        dict:
> +            key: UUID macro name, e.g. 'UUID_TRUSTED_FWU_CERT'
> +            value: list:
> +                file comment, e.g. 'ToC Entry UUIDs'
> +                macro name, e.g. 'UUID_TRUSTED_FWU_CERT'
> +                uuid as bytes(16)
> +
> +    Raises:
> +        ValueError: a line cannot be parsed
> +    """
> +    re_uuid = re.compile('0x[0-9a-fA-F]{2}')
> +    re_comment = re.compile(r'^/\* (.*) \*/$')
> +    fname = os.path.join(srcdir, 'include/tools_share/firmware_image_package.h')
> +    data = tools.ReadFile(fname, binary=False)
> +    macros = collections.OrderedDict()
> +    comment = None
> +    for linenum, line in enumerate(data.splitlines()):
> +        if line.startswith('/*'):
> +            mat = re_comment.match(line)
> +            if mat:
> +                comment = mat.group(1)
> +        else:
> +            # Example: #define UUID_TOS_FW_CONFIG \
> +            if 'UUID' in line:
> +                macro = line.split()[1]
> +            elif '{{' in line:
> +                mat = re_uuid.findall(line)
> +                if not mat or len(mat) != 16:
> +                    raise ValueError(
> +                        f'{fname}: Cannot parse UUID line {linenum + 1}: Got matches: {mat}')
> +
> +                uuid = bytes([int(val, 16) for val in mat])
> +                macros[macro] = comment, macro, uuid
> +    if not macros:
> +        raise ValueError(f'{fname}: Cannot parse file')
> +    return macros
> +
> +
> +def parse_names(srcdir):
> +    """parse_names: Parse the tbbr_config.c file
> +
> +    Args:
> +        srcdir (str): 'arm-trusted-firmware' source directory
> +
> +    Returns:
> +        tuple: dict of entries:
> +            key: UUID macro, e.g. 'UUID_NON_TRUSTED_FIRMWARE_BL33'
> +            tuple: entry information
> +                Description of entry, e.g. 'Non-Trusted Firmware BL33'
> +                UUID macro, e.g. 'UUID_NON_TRUSTED_FIRMWARE_BL33'
> +                Name of entry, e.g. 'nt-fw'
> +
> +    Raises:
> +        ValueError: the file cannot be parsed
> +    """
> +    # Extract the .name, .uuid and .cmdline_name values
> +    re_data = re.compile(r'\.name = "([^"]*)",\s*\.uuid = (UUID_\w*),\s*\.cmdline_name = "([^"]+)"',
> +                         re.S)
> +    fname = os.path.join(srcdir, 'tools/fiptool/tbbr_config.c')
> +    data = tools.ReadFile(fname, binary=False)
> +
> +    # Example entry:
> +    #   {
> +    #       .name = "Secure Payload BL32 Extra2 (Trusted OS Extra2)",
> +    #       .uuid = UUID_SECURE_PAYLOAD_BL32_EXTRA2,
> +    #       .cmdline_name = "tos-fw-extra2"
> +    #   },
> +    mat = re_data.findall(data)
> +    if not mat:
> +        raise ValueError(f'{fname}: Cannot parse file')
> +    names = {uuid: (desc, uuid, name) for desc, uuid, name in mat}
> +    return names
> +
> +
> +def create_code_output(macros, names):
> +    """create_code_output() - Create the new version of this Python file
> +
> +    Args:
> +        macros (dict):
> +            key (str): UUID macro name, e.g. 'UUID_TRUSTED_FWU_CERT'
> +            value: list:
> +                file comment, e.g. 'ToC Entry UUIDs'
> +                macro name, e.g. 'UUID_TRUSTED_FWU_CERT'
> +                uuid as bytes(16)
> +
> +        names (dict): list of entries, each
> +            tuple: entry information
> +                Description of entry, e.g. 'Non-Trusted Firmware BL33'
> +                UUID macro, e.g. 'UUID_NON_TRUSTED_FIRMWARE_BL33'
> +                Name of entry, e.g. 'nt-fw'
> +
> +    Returns:
> +        str: Table of FipType() entries
> +    """
> +    def _to_hex_list(data):
> +        """Convert bytes into C code
> +
> +        Args:
> +            bytes to convert
> +
> +        Returns:
> +            str: in the format '0x12, 0x34, 0x56...'
> +        """
> +        # Use 0x instead of %# since the latter ignores the 0 modifier in
> +        # Python 3.8.10
> +        return ', '.join(['0x%02x' % byte for byte in data])
> +
> +    out = ''
> +    last_comment = None
> +    for comment, macro, uuid in macros.values():
> +        name_entry = names.get(macro)
> +        if not name_entry:
> +            print(f"Warning: UUID '{macro}' is not mentioned in tbbr_config.c file")
> +            continue
> +        desc, _, name = name_entry
> +        if last_comment != comment:
> +            out += f'    # {comment}\n'
> +            last_comment = comment
> +        out += """    FipType('%s', '%s',
> +            [%s,
> +             %s]),
> +""" % (name, desc, _to_hex_list(uuid[:8]), _to_hex_list(uuid[8:]))
> +    return out
> +
> +
> +def parse_atf_source(srcdir, dstfile, oldfile):
> +    """parse_atf_source(): Parse the ATF source tree and update this file
> +
> +    Args:
> +        srcdir (str): Path to 'arm-trusted-firmware' directory. Get this from:
> +            https://github.com/ARM-software/arm-trusted-firmware.git
> +        dstfile (str): File to write new code to, if an update is needed
> +        oldfile (str): Python source file to compare against
> +
> +    Raises:
> +        ValueError: srcdir readme.rst is missing or the first line does not
> +            match what is expected
> +    """
> +    # We expect a readme file
> +    readme_fname = os.path.join(srcdir, 'readme.rst')
> +    if not os.path.exists(readme_fname):
> +        raise ValueError(
> +            f"Expected file '{readme_fname}' - try using -s to specify the "
> +            'arm-trusted-firmware directory')
> +    readme = tools.ReadFile(readme_fname, binary=False)
> +    first_line = 'Trusted Firmware-A'
> +    if readme.splitlines()[0] != first_line:
> +        raise ValueError(f"'{readme_fname}' does not start with '{first_line}'")
> +    macros = parse_macros(srcdir)
> +    names = parse_names(srcdir)
> +    output = create_code_output(macros, names)
> +    orig = tools.ReadFile(oldfile, binary=False)
> +    re_fip_list = re.compile(r'(.*FIP_TYPE_LIST = \[).*?(    ] # end.*)', re.S)
> +    mat = re_fip_list.match(orig)
> +    new_code = mat.group(1) + '\n' + output + mat.group(2) if mat else output
> +    if new_code == orig:
> +        print(f"Existing code in '{oldfile}' is up-to-date")
> +    else:
> +        tools.WriteFile(dstfile, new_code, binary=False)
> +        print(f'Needs update, try:\n\tmeld {dstfile} {oldfile}')
> +
> +
> +def main(argv, oldfile):
> +    """Main program for this tool
> +
> +    Args:
> +        argv (list): List of str command-line arguments
> +        oldfile (str): Python source file to compare against
> +
> +    Returns:
> +        int: 0 (exit code)
> +    """
> +    parser = ArgumentParser(epilog='''Creates an updated version of this code,
> +with a table of FIP-entry types parsed from the arm-trusted-firmware source
> +directory''')
> +    parser.add_argument(
> +        '-D', '--debug', action='store_true',
> +        help='Enabling debugging (provides a full traceback on error)')
> +    parser.add_argument(
> +        '-o', '--outfile', type=str, default='fip_util.py.out',
> +        help='Output file to write new fip_util.py file to')
> +    parser.add_argument(
> +        '-s', '--src', type=str, default='.',
> +        help='Directory containing the arm-trusted-firmware source')
> +    args = parser.parse_args(argv)
> +
> +    if not args.debug:
> +        sys.tracebacklimit = 0
> +
> +    parse_atf_source(args.src, args.outfile, oldfile)
> +    return 0
> +
> +
> +def fiptool(fname, *fip_args):
> +    """Run fiptool with provided arguments
> +
> +    If the tool fails then this function raises an exception and prints out the
> +    output and stderr.
> +
> +    Args:
> +        fname (str): Filename of FIP
> +        *fip_args: List of arguments to pass to fiptool
> +
> +    Returns:
> +        CommandResult: object containing the results
> +
> +    Raises:
> +        ValueError: the tool failed to run
> +    """
> +    args = ['fiptool', fname] + list(fip_args)
> +    result = command.RunPipe([args], capture=not VERBOSE,
> +                             capture_stderr=not VERBOSE, raise_on_error=False)
> +    if result.return_code:
> +        print(result.stderr, file=sys.stderr)
> +        raise ValueError("Failed to run (error %d): '%s'" %
> +                         (result.return_code, ' '.join(args)))
> +    return result
> +
> +
> +if __name__ == "__main__":
> +    sys.exit(main(sys.argv[1:], OUR_FILE))  # pragma: no cover
> diff --git a/tools/binman/fip_util_test.py b/tools/binman/fip_util_test.py
> new file mode 100755
> index 00000000000..4839b298762
> --- /dev/null
> +++ b/tools/binman/fip_util_test.py
> @@ -0,0 +1,405 @@
> +#!/usr/bin/env python3
> +# SPDX-License-Identifier: GPL-2.0+
> +# Copyright 2021 Google LLC
> +# Written by Simon Glass <sjg at chromium.org>
> +
> +"""Tests for fip_util
> +
> +This tests a few features of fip_util which are not covered by binman's ftest.py
> +"""
> +
> +import os
> +import shutil
> +import sys
> +import tempfile
> +import unittest
> +
> +# Bring in the patman and dtoc libraries (but don't override the first path
> +# in PYTHONPATH)
> +OUR_PATH = os.path.dirname(os.path.realpath(__file__))
> +sys.path.insert(2, os.path.join(OUR_PATH, '..'))
> +
> +# pylint: disable=C0413
> +from patman import test_util
> +from patman import tools
> +import fip_util
> +
> +HAVE_FIPTOOL = True
> +try:
> +    tools.Run('which', 'fiptool')
> +except ValueError:
> +    HAVE_FIPTOOL = False
> +
> +# pylint: disable=R0902,R0904
> +class TestFip(unittest.TestCase):
> +    """Test of fip_util classes"""
> +    #pylint: disable=W0212
> +    def setUp(self):
> +        # Create a temporary directory for test files
> +        self._indir = tempfile.mkdtemp(prefix='fip_util.')
> +        tools.SetInputDirs([self._indir])
> +
> +        # Set up a temporary output directory, used by the tools library when
> +        # compressing files
> +        tools.PrepareOutputDir(None)
> +
> +        self.src_file = os.path.join(self._indir, 'orig.py')
> +        self.outname = tools.GetOutputFilename('out.py')
> +        self.args = ['-D', '-s', self._indir, '-o', self.outname]
> +        self.readme = os.path.join(self._indir, 'readme.rst')
> +        self.macro_dir = os.path.join(self._indir, 'include/tools_share')
> +        self.macro_fname = os.path.join(self.macro_dir,
> +                                        'firmware_image_package.h')
> +        self.name_dir = os.path.join(self._indir, 'tools/fiptool')
> +        self.name_fname = os.path.join(self.name_dir, 'tbbr_config.c')
> +
> +    macro_contents = '''
> +
> +/* ToC Entry UUIDs */
> +#define UUID_TRUSTED_UPDATE_FIRMWARE_SCP_BL2U \\
> +       {{0x65, 0x92, 0x27, 0x03}, {0x2f, 0x74}, {0xe6, 0x44}, 0x8d, 0xff, {0x57, 0x9a, 0xc1, 0xff, 0x06, 0x10} }
> +#define UUID_TRUSTED_UPDATE_FIRMWARE_BL2U \\
> +       {{0x60, 0xb3, 0xeb, 0x37}, {0xc1, 0xe5}, {0xea, 0x41}, 0x9d, 0xf3, {0x19, 0xed, 0xa1, 0x1f, 0x68, 0x01} }
> +
> +'''
> +
> +    name_contents = '''
> +
> +toc_entry_t toc_entries[] = {
> +       {
> +               .name = "SCP Firmware Updater Configuration FWU SCP_BL2U",
> +               .uuid = UUID_TRUSTED_UPDATE_FIRMWARE_SCP_BL2U,
> +               .cmdline_name = "scp-fwu-cfg"
> +       },
> +       {
> +               .name = "AP Firmware Updater Configuration BL2U",
> +               .uuid = UUID_TRUSTED_UPDATE_FIRMWARE_BL2U,
> +               .cmdline_name = "ap-fwu-cfg"
> +       },
> +'''
> +
> +    def setup_readme(self):
> +        """Set up the readme.txt file"""
> +        tools.WriteFile(self.readme, 'Trusted Firmware-A\n==================',
> +                        binary=False)
> +
> +    def setup_macro(self, data=macro_contents):
> +        """Set up the tbbr_config.c file"""
> +        os.makedirs(self.macro_dir)
> +        tools.WriteFile(self.macro_fname, data, binary=False)
> +
> +    def setup_name(self, data=name_contents):
> +        """Set up the firmware_image_package.h file"""
> +        os.makedirs(self.name_dir)
> +        tools.WriteFile(self.name_fname, data, binary=False)
> +
> +    def tearDown(self):
> +        """Remove the temporary input directory and its contents"""
> +        if self._indir:
> +            shutil.rmtree(self._indir)
> +        self._indir = None
> +        tools.FinaliseOutputDir()
> +
> +    def test_no_readme(self):
> +        """Test handling of a missing readme.rst"""
> +        with self.assertRaises(Exception) as err:
> +            fip_util.main(self.args, self.src_file)
> +        self.assertIn('Expected file', str(err.exception))
> +
> +    def test_invalid_readme(self):
> +        """Test that an invalid readme.rst is detected"""
> +        tools.WriteFile(self.readme, 'blah', binary=False)
> +        with self.assertRaises(Exception) as err:
> +            fip_util.main(self.args, self.src_file)
> +        self.assertIn('does not start with', str(err.exception))
> +
> +    def test_no_fip_h(self):
> +        """Check handling of missing firmware_image_package.h"""
> +        self.setup_readme()
> +        with self.assertRaises(Exception) as err:
> +            fip_util.main(self.args, self.src_file)
> +        self.assertIn('No such file or directory', str(err.exception))
> +
> +    def test_invalid_fip_h(self):
> +        """Check failure to parse firmware_image_package.h"""
> +        self.setup_readme()
> +        self.setup_macro('blah')
> +        with self.assertRaises(Exception) as err:
> +            fip_util.main(self.args, self.src_file)
> +        self.assertIn('Cannot parse file', str(err.exception))
> +
> +    def test_parse_fip_h(self):
> +        """Check parsing of firmware_image_package.h"""
> +        self.setup_readme()
> +        # Check parsing the header file
> +        self.setup_macro()
> +        macros = fip_util.parse_macros(self._indir)
> +        expected_macros = {
> +            'UUID_TRUSTED_UPDATE_FIRMWARE_SCP_BL2U':
> +                ('ToC Entry UUIDs', 'UUID_TRUSTED_UPDATE_FIRMWARE_SCP_BL2U',
> +                 bytes([0x65, 0x92, 0x27, 0x03, 0x2f, 0x74, 0xe6, 0x44,
> +                        0x8d, 0xff, 0x57, 0x9a, 0xc1, 0xff, 0x06, 0x10])),
> +            'UUID_TRUSTED_UPDATE_FIRMWARE_BL2U':
> +                ('ToC Entry UUIDs', 'UUID_TRUSTED_UPDATE_FIRMWARE_BL2U',
> +                 bytes([0x60, 0xb3, 0xeb, 0x37, 0xc1, 0xe5, 0xea, 0x41,
> +                        0x9d, 0xf3, 0x19, 0xed, 0xa1, 0x1f, 0x68, 0x01])),
> +            }
> +        self.assertEqual(expected_macros, macros)
> +
> +    def test_missing_tbbr_c(self):
> +        """Check handlinh of missing tbbr_config.c"""
> +        self.setup_readme()
> +        self.setup_macro()
> +
> +        # Still need the .c file
> +        with self.assertRaises(Exception) as err:
> +            fip_util.main(self.args, self.src_file)
> +        self.assertIn('tbbr_config.c', str(err.exception))
> +
> +    def test_invalid_tbbr_c(self):
> +        """Check failure to parse tbbr_config.c"""
> +        self.setup_readme()
> +        self.setup_macro()
> +        # Check invalid format for C file
> +        self.setup_name('blah')
> +        with self.assertRaises(Exception) as err:
> +            fip_util.main(self.args, self.src_file)
> +        self.assertIn('Cannot parse file', str(err.exception))
> +
> +    def test_inconsistent_tbbr_c(self):
> +        """Check tbbr_config.c in a format we don't expect"""
> +        self.setup_readme()
> +        # This is missing a hex value
> +        self.setup_macro('''
> +
> +/* ToC Entry UUIDs */
> +#define UUID_TRUSTED_UPDATE_FIRMWARE_SCP_BL2U \\
> +       {{0x65, 0x92, 0x27,}, {0x2f, 0x74}, {0xe6, 0x44}, 0x8d, 0xff, {0x57, 0x9a, 0xc1, 0xff, 0x06, 0x10} }
> +#define UUID_TRUSTED_UPDATE_FIRMWARE_BL2U \\
> +       {{0x60, 0xb3, 0xeb, 0x37}, {0xc1, 0xe5}, {0xea, 0x41}, 0x9d, 0xf3, {0x19, 0xed, 0xa1, 0x1f, 0x68, 0x01} }
> +
> +''')
> +        # Check invalid format for C file
> +        self.setup_name('blah')
> +        with self.assertRaises(Exception) as err:
> +            fip_util.main(self.args, self.src_file)
> +        self.assertIn('Cannot parse UUID line 5', str(err.exception))
> +
> +    def test_parse_tbbr_c(self):
> +        """Check parsing tbbr_config.c"""
> +        self.setup_readme()
> +        self.setup_macro()
> +        self.setup_name()
> +
> +        names = fip_util.parse_names(self._indir)
> +
> +        expected_names = {
> +            'UUID_TRUSTED_UPDATE_FIRMWARE_SCP_BL2U': (
> +                'SCP Firmware Updater Configuration FWU SCP_BL2U',
> +                'UUID_TRUSTED_UPDATE_FIRMWARE_SCP_BL2U',
> +                'scp-fwu-cfg'),
> +            'UUID_TRUSTED_UPDATE_FIRMWARE_BL2U': (
> +                'AP Firmware Updater Configuration BL2U',
> +                'UUID_TRUSTED_UPDATE_FIRMWARE_BL2U',
> +                'ap-fwu-cfg'),
> +            }
> +        self.assertEqual(expected_names, names)
> +
> +    def test_uuid_not_in_tbbr_config_c(self):
> +        """Check handling a UUID in the header file that's not in the .c file"""
> +        self.setup_readme()
> +        self.setup_macro(self.macro_contents + '''
> +#define UUID_TRUSTED_OS_FW_KEY_CERT \\
> +       {{0x94,  0x77, 0xd6, 0x03}, {0xfb, 0x60}, {0xe4, 0x11}, 0x85, 0xdd, {0xb7, 0x10, 0x5b, 0x8c, 0xee, 0x04} }
> +
> +''')
> +        self.setup_name()
> +
> +        macros = fip_util.parse_macros(self._indir)
> +        names = fip_util.parse_names(self._indir)
> +        with test_util.capture_sys_output() as (stdout, _):
> +            fip_util.create_code_output(macros, names)
> +        self.assertIn(
> +            "UUID 'UUID_TRUSTED_OS_FW_KEY_CERT' is not mentioned in tbbr_config.c file",
> +            stdout.getvalue())
> +
> +    def test_changes(self):
> +        """Check handling of a source file that does/doesn't need changes"""
> +        self.setup_readme()
> +        self.setup_macro()
> +        self.setup_name()
> +
> +        # Check generating the file when changes are needed
> +        tools.WriteFile(self.src_file, '''
> +
> +# This is taken from tbbr_config.c in ARM Trusted Firmware
> +FIP_TYPE_LIST = [
> +    # ToC Entry UUIDs
> +    FipType('scp-fwu-cfg', 'SCP Firmware Updater Configuration FWU SCP_BL2U',
> +            [0x65, 0x92, 0x27, 0x03, 0x2f, 0x74, 0xe6, 0x44,
> +             0x8d, 0xff, 0x57, 0x9a, 0xc1, 0xff, 0x06, 0x10]),
> +    ] # end
> +blah de blah
> +                        ''', binary=False)
> +        with test_util.capture_sys_output() as (stdout, _):
> +            fip_util.main(self.args, self.src_file)
> +        self.assertIn('Needs update', stdout.getvalue())
> +
> +        # Check generating the file when no changes are needed
> +        tools.WriteFile(self.src_file, '''
> +# This is taken from tbbr_config.c in ARM Trusted Firmware
> +FIP_TYPE_LIST = [
> +    # ToC Entry UUIDs
> +    FipType('scp-fwu-cfg', 'SCP Firmware Updater Configuration FWU SCP_BL2U',
> +            [0x65, 0x92, 0x27, 0x03, 0x2f, 0x74, 0xe6, 0x44,
> +             0x8d, 0xff, 0x57, 0x9a, 0xc1, 0xff, 0x06, 0x10]),
> +    FipType('ap-fwu-cfg', 'AP Firmware Updater Configuration BL2U',
> +            [0x60, 0xb3, 0xeb, 0x37, 0xc1, 0xe5, 0xea, 0x41,
> +             0x9d, 0xf3, 0x19, 0xed, 0xa1, 0x1f, 0x68, 0x01]),
> +    ] # end
> +blah blah''', binary=False)
> +        with test_util.capture_sys_output() as (stdout, _):
> +            fip_util.main(self.args, self.src_file)
> +        self.assertIn('is up-to-date', stdout.getvalue())
> +
> +    def test_no_debug(self):
> +        """Test running without the -D flag"""
> +        self.setup_readme()
> +        self.setup_macro()
> +        self.setup_name()
> +
> +        args = self.args.copy()
> +        args.remove('-D')
> +        tools.WriteFile(self.src_file, '', binary=False)
> +        with test_util.capture_sys_output():
> +            fip_util.main(args, self.src_file)
> +
> +    @unittest.skipIf(not HAVE_FIPTOOL, 'No fiptool available')
> +    def test_fiptool_list(self):
> +        """Create a FIP and check that fiptool can read it"""
> +        fwu = b'my data'
> +        tb_fw = b'some more data'
> +        fip = fip_util.FipWriter(0x123, 0x10)
> +        fip.add_entry('fwu', fwu, 0x456)
> +        fip.add_entry('tb-fw', tb_fw, 0)
> +        fip.add_entry(bytes(range(16)), tb_fw, 0)
> +        data = fip.get_data()
> +        fname = tools.GetOutputFilename('data.fip')
> +        tools.WriteFile(fname, data)
> +        result = fip_util.fiptool('info', fname)
> +        self.assertEqual(
> +            '''Firmware Updater NS_BL2U: offset=0xB0, size=0x7, cmdline="--fwu"
> +Trusted Boot Firmware BL2: offset=0xC0, size=0xE, cmdline="--tb-fw"
> +00010203-0405-0607-0809-0A0B0C0D0E0F: offset=0xD0, size=0xE, cmdline="--blob"
> +''',
> +            result.stdout)
> +
> +    fwu_data = b'my data'
> +    tb_fw_data = b'some more data'
> +    other_fw_data = b'even more'
> +
> +    def create_fiptool_image(self):
> +        """Create an image with fiptool which we can use for testing
> +
> +        Returns:
> +            FipReader: reader for the image
> +        """
> +        fwu = os.path.join(self._indir, 'fwu')
> +        tools.WriteFile(fwu, self.fwu_data)
> +
> +        tb_fw = os.path.join(self._indir, 'tb_fw')
> +        tools.WriteFile(tb_fw, self.tb_fw_data)
> +
> +        other_fw = os.path.join(self._indir, 'other_fw')
> +        tools.WriteFile(other_fw, self.other_fw_data)
> +
> +        fname = tools.GetOutputFilename('data.fip')
> +        uuid = 'e3b78d9e-4a64-11ec-b45c-fba2b9b49788'
> +        fip_util.fiptool('create', '--align', '8', '--plat-toc-flags', '0x123',
> +                         '--fwu', fwu,
> +                         '--tb-fw', tb_fw,
> +                         '--blob', f'uuid={uuid},file={other_fw}',
> +                          fname)
> +
> +        return fip_util.FipReader(tools.ReadFile(fname))
> +
> +    @unittest.skipIf(not HAVE_FIPTOOL, 'No fiptool available')
> +    def test_fiptool_create(self):
> +        """Create a FIP with fiptool and check that fip_util can read it"""
> +        reader = self.create_fiptool_image()
> +
> +        header = reader.header
> +        fents = reader.fents
> +
> +        self.assertEqual(0x123 << 32, header.flags)
> +        self.assertEqual(fip_util.HEADER_MAGIC, header.name)
> +        self.assertEqual(fip_util.HEADER_SERIAL, header.serial)
> +
> +        self.assertEqual(3, len(fents))
> +        fent = fents[0]
> +        self.assertEqual(
> +            bytes([0x4f, 0x51, 0x1d, 0x11, 0x2b, 0xe5, 0x4e, 0x49,
> +                   0xb4, 0xc5, 0x83, 0xc2, 0xf7, 0x15, 0x84, 0x0a]), fent.uuid)
> +        self.assertEqual(0xb0, fent.offset)
> +        self.assertEqual(len(self.fwu_data), fent.size)
> +        self.assertEqual(0, fent.flags)
> +        self.assertEqual(self.fwu_data, fent.data)
> +
> +        fent = fents[1]
> +        self.assertEqual(
> +            bytes([0x5f, 0xf9, 0xec, 0x0b, 0x4d, 0x22, 0x3e, 0x4d,
> +             0xa5, 0x44, 0xc3, 0x9d, 0x81, 0xc7, 0x3f, 0x0a]), fent.uuid)
> +        self.assertEqual(0xb8, fent.offset)
> +        self.assertEqual(len(self.tb_fw_data), fent.size)
> +        self.assertEqual(0, fent.flags)
> +        self.assertEqual(self.tb_fw_data, fent.data)
> +
> +        fent = fents[2]
> +        self.assertEqual(
> +            bytes([0xe3, 0xb7, 0x8d, 0x9e, 0x4a, 0x64, 0x11, 0xec,
> +                   0xb4, 0x5c, 0xfb, 0xa2, 0xb9, 0xb4, 0x97, 0x88]), fent.uuid)
> +        self.assertEqual(0xc8, fent.offset)
> +        self.assertEqual(len(self.other_fw_data), fent.size)
> +        self.assertEqual(0, fent.flags)
> +        self.assertEqual(self.other_fw_data, fent.data)
> +
> +    @unittest.skipIf(not HAVE_FIPTOOL, 'No fiptool available')
> +    def test_reader_get_entry(self):
> +        """Test get_entry() by name and UUID"""
> +        reader = self.create_fiptool_image()
> +        fents = reader.fents
> +        fent = reader.get_entry('fwu')
> +        self.assertEqual(fent, fents[0])
> +
> +        fent = reader.get_entry(
> +            bytes([0x5f, 0xf9, 0xec, 0x0b, 0x4d, 0x22, 0x3e, 0x4d,
> +                   0xa5, 0x44, 0xc3, 0x9d, 0x81, 0xc7, 0x3f, 0x0a]))
> +        self.assertEqual(fent, fents[1])
> +
> +        # Try finding entries that don't exist
> +        with self.assertRaises(Exception) as err:
> +            fent = reader.get_entry('scp-fwu-cfg')
> +        self.assertIn("Cannot find FIP entry 'scp-fwu-cfg'", str(err.exception))
> +
> +        with self.assertRaises(Exception) as err:
> +            fent = reader.get_entry(bytes(list(range(16))))
> +        self.assertIn(
> +            "Cannot find FIP entry '00010203-0405-0607-0809-0a0b0c0d0e0f'",
> +            str(err.exception))
> +
> +        with self.assertRaises(Exception) as err:
> +            fent = reader.get_entry('blah')
> +        self.assertIn("Unknown FIP entry type 'blah'", str(err.exception))
> +
> +    @unittest.skipIf(not HAVE_FIPTOOL, 'No fiptool available')
> +    def test_fiptool_errors(self):
> +        """Check some error reporting from fiptool"""
> +        with self.assertRaises(Exception) as err:
> +            with test_util.capture_sys_output():
> +                fip_util.fiptool('create', '--fred')
> +        self.assertIn("Failed to run (error 1): 'fiptool create --fred'",
> +                      str(err.exception))
> +
> +
> +if __name__ == '__main__':
> +    unittest.main()
> diff --git a/tools/binman/main.py b/tools/binman/main.py
> index 8c1e478d54c..1a639f43e9e 100755
> --- a/tools/binman/main.py
> +++ b/tools/binman/main.py
> @@ -59,6 +59,7 @@ def RunTests(debug, verbosity, processes, test_preserve_dirs, args, toolpath):
>      from binman import elf_test
>      from binman import entry_test
>      from binman import fdt_test
> +    from binman import fip_util_test
>      from binman import ftest
>      from binman import image_test
>      import doctest
> @@ -72,7 +73,8 @@ def RunTests(debug, verbosity, processes, test_preserve_dirs, args, toolpath):
>          result, debug, verbosity, test_preserve_dirs, processes, test_name,
>          toolpath,
>          [entry_test.TestEntry, ftest.TestFunctional, fdt_test.TestFdt,
> -         elf_test.TestElf, image_test.TestImage, cbfs_util_test.TestCbfs])
> +         elf_test.TestElf, image_test.TestImage, cbfs_util_test.TestCbfs,
> +         fip_util_test.TestFip])
>
>      return test_util.ReportResult('binman', test_name, result)
>
> --
> 2.34.0.rc2.393.gf8c9666880-goog
>


More information about the U-Boot mailing list