mirror of
				https://github.com/smaeul/u-boot.git
				synced 2025-10-31 03:58:17 +00:00 
			
		
		
		
	The TF-A URL was updated, as a result the name of the
directory changed as part of the new git URL and not
all the referenced directories were updated.
Fixes: 0ec0207fe07 ("Update the ARM trusted firmware git URL")
Signed-off-by: Peter Robinson <pbrobinson@gmail.com>
		
	
			
		
			
				
	
	
		
			628 lines
		
	
	
		
			22 KiB
		
	
	
	
		
			Python
		
	
	
		
			Executable File
		
	
	
	
	
			
		
		
	
	
			628 lines
		
	
	
		
			22 KiB
		
	
	
	
		
			Python
		
	
	
		
			Executable File
		
	
	
	
	
| #!/usr/bin/env python3
 | |
| # SPDX-License-Identifier: GPL-2.0+
 | |
| # Copyright 2021 Google LLC
 | |
| # Written by Simon Glass <sjg@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/TrustedFirmware-A/trusted-firmware-a.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 u_boot_pylib import command
 | |
| from u_boot_pylib 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.get_bytes(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.read_file('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): 'trusted-firmware-a' 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.read_file(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): 'trusted-firmware-a' 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.read_file(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 'trusted-firmware-a' directory. Get this from:
 | |
|             https://github.com/TrustedFirmware-A/trusted-firmware-a.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 "
 | |
|             'trusted-firmware-a directory')
 | |
|     readme = tools.read_file(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.read_file(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.write_file(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 trusted-firmware-a 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 trusted-firmware-a source')
 | |
|     args = parser.parse_args(argv)
 | |
| 
 | |
|     if not args.debug:
 | |
|         sys.tracebacklimit = 0
 | |
| 
 | |
|     parse_atf_source(args.src, args.outfile, oldfile)
 | |
|     return 0
 | |
| 
 | |
| 
 | |
| if __name__ == "__main__":
 | |
|     sys.exit(main(sys.argv[1:], OUR_FILE))  # pragma: no cover
 |