blob: 9d2eec82a0aac34c23443712b272995e974a6044 [file] [log] [blame]
Simon Glass2697b7c2021-11-23 21:08:58 -07001#!/usr/bin/env python3
2# SPDX-License-Identifier: GPL-2.0+
3# Copyright 2021 Google LLC
4# Written by Simon Glass <sjg@chromium.org>
5
6"""Support for ARM's Firmware Image Package (FIP) format
7
8FIP is a format similar to FMAP[1] but with fewer features and an obscure UUID
9instead of the region name.
10
11It consists of a header and a table of entries, each pointing to a place in the
12firmware image where something can be found.
13
14[1] https://chromium.googlesource.com/chromiumos/third_party/flashmap/+/refs/heads/master/lib/fmap.h
15
16If ATF updates, run this program to update the FIT_TYPE_LIST.
17
18ARM Trusted Firmware is available at:
19
Peter Robinson32d26c72024-10-02 19:08:49 +010020https://github.com/TrustedFirmware-A/trusted-firmware-a.git
Simon Glass2697b7c2021-11-23 21:08:58 -070021"""
22
23from argparse import ArgumentParser
24import collections
25import io
26import os
27import re
28import struct
29import sys
30from uuid import UUID
31
32OUR_FILE = os.path.realpath(__file__)
33OUR_PATH = os.path.dirname(OUR_FILE)
34
35# Bring in the patman and dtoc libraries (but don't override the first path
36# in PYTHONPATH)
37sys.path.insert(2, os.path.join(OUR_PATH, '..'))
38
39# pylint: disable=C0413
Simon Glass131444f2023-02-23 18:18:04 -070040from u_boot_pylib import command
41from u_boot_pylib import tools
Simon Glass2697b7c2021-11-23 21:08:58 -070042
43# The TOC header, at the start of the FIP
44HEADER_FORMAT = '<IIQ'
45HEADER_LEN = 0x10
46HEADER_MAGIC = 0xaA640001
47HEADER_SERIAL = 0x12345678
48
49# The entry header (a table of these comes after the TOC header)
50UUID_LEN = 16
51ENTRY_FORMAT = f'<{UUID_LEN}sQQQ'
52ENTRY_SIZE = 0x28
53
54HEADER_NAMES = (
55 'name',
56 'serial',
57 'flags',
58)
59
60ENTRY_NAMES = (
61 'uuid',
62 'offset',
63 'size',
64 'flags',
65)
66
67# Set to True to enable output from running fiptool for debugging
68VERBOSE = False
69
70# Use a class so we can convert the bytes, making the table more readable
71# pylint: disable=R0903
72class FipType:
73 """A FIP entry type that we understand"""
74 def __init__(self, name, desc, uuid_bytes):
75 """Create up a new type
76
77 Args:
78 name (str): Short name for the type
79 desc (str): Longer description for the type
80 uuid_bytes (bytes): List of 16 bytes for the UUID
81 """
82 self.name = name
83 self.desc = desc
84 self.uuid = bytes(uuid_bytes)
85
86# This is taken from tbbr_config.c in ARM Trusted Firmware
87FIP_TYPE_LIST = [
88 # ToC Entry UUIDs
89 FipType('scp-fwu-cfg', 'SCP Firmware Updater Configuration FWU SCP_BL2U',
90 [0x65, 0x92, 0x27, 0x03, 0x2f, 0x74, 0xe6, 0x44,
91 0x8d, 0xff, 0x57, 0x9a, 0xc1, 0xff, 0x06, 0x10]),
92 FipType('ap-fwu-cfg', 'AP Firmware Updater Configuration BL2U',
93 [0x60, 0xb3, 0xeb, 0x37, 0xc1, 0xe5, 0xea, 0x41,
94 0x9d, 0xf3, 0x19, 0xed, 0xa1, 0x1f, 0x68, 0x01]),
95 FipType('fwu', 'Firmware Updater NS_BL2U',
96 [0x4f, 0x51, 0x1d, 0x11, 0x2b, 0xe5, 0x4e, 0x49,
97 0xb4, 0xc5, 0x83, 0xc2, 0xf7, 0x15, 0x84, 0x0a]),
98 FipType('fwu-cert', 'Non-Trusted Firmware Updater certificate',
99 [0x71, 0x40, 0x8a, 0xb2, 0x18, 0xd6, 0x87, 0x4c,
100 0x8b, 0x2e, 0xc6, 0xdc, 0xcd, 0x50, 0xf0, 0x96]),
101 FipType('tb-fw', 'Trusted Boot Firmware BL2',
102 [0x5f, 0xf9, 0xec, 0x0b, 0x4d, 0x22, 0x3e, 0x4d,
103 0xa5, 0x44, 0xc3, 0x9d, 0x81, 0xc7, 0x3f, 0x0a]),
104 FipType('scp-fw', 'SCP Firmware SCP_BL2',
105 [0x97, 0x66, 0xfd, 0x3d, 0x89, 0xbe, 0xe8, 0x49,
106 0xae, 0x5d, 0x78, 0xa1, 0x40, 0x60, 0x82, 0x13]),
107 FipType('soc-fw', 'EL3 Runtime Firmware BL31',
108 [0x47, 0xd4, 0x08, 0x6d, 0x4c, 0xfe, 0x98, 0x46,
109 0x9b, 0x95, 0x29, 0x50, 0xcb, 0xbd, 0x5a, 0x00]),
110 FipType('tos-fw', 'Secure Payload BL32 (Trusted OS)',
111 [0x05, 0xd0, 0xe1, 0x89, 0x53, 0xdc, 0x13, 0x47,
112 0x8d, 0x2b, 0x50, 0x0a, 0x4b, 0x7a, 0x3e, 0x38]),
113 FipType('tos-fw-extra1', 'Secure Payload BL32 Extra1 (Trusted OS Extra1)',
114 [0x0b, 0x70, 0xc2, 0x9b, 0x2a, 0x5a, 0x78, 0x40,
115 0x9f, 0x65, 0x0a, 0x56, 0x82, 0x73, 0x82, 0x88]),
116 FipType('tos-fw-extra2', 'Secure Payload BL32 Extra2 (Trusted OS Extra2)',
117 [0x8e, 0xa8, 0x7b, 0xb1, 0xcf, 0xa2, 0x3f, 0x4d,
118 0x85, 0xfd, 0xe7, 0xbb, 0xa5, 0x02, 0x20, 0xd9]),
119 FipType('nt-fw', 'Non-Trusted Firmware BL33',
120 [0xd6, 0xd0, 0xee, 0xa7, 0xfc, 0xea, 0xd5, 0x4b,
121 0x97, 0x82, 0x99, 0x34, 0xf2, 0x34, 0xb6, 0xe4]),
122 FipType('rmm-fw', 'Realm Monitor Management Firmware',
123 [0x6c, 0x07, 0x62, 0xa6, 0x12, 0xf2, 0x4b, 0x56,
124 0x92, 0xcb, 0xba, 0x8f, 0x63, 0x36, 0x06, 0xd9]),
125 # Key certificates
126 FipType('rot-cert', 'Root Of Trust key certificate',
127 [0x86, 0x2d, 0x1d, 0x72, 0xf8, 0x60, 0xe4, 0x11,
128 0x92, 0x0b, 0x8b, 0xe7, 0x62, 0x16, 0x0f, 0x24]),
129 FipType('trusted-key-cert', 'Trusted key certificate',
130 [0x82, 0x7e, 0xe8, 0x90, 0xf8, 0x60, 0xe4, 0x11,
131 0xa1, 0xb4, 0x77, 0x7a, 0x21, 0xb4, 0xf9, 0x4c]),
132 FipType('scp-fw-key-cert', 'SCP Firmware key certificate',
133 [0x02, 0x42, 0x21, 0xa1, 0xf8, 0x60, 0xe4, 0x11,
134 0x8d, 0x9b, 0xf3, 0x3c, 0x0e, 0x15, 0xa0, 0x14]),
135 FipType('soc-fw-key-cert', 'SoC Firmware key certificate',
136 [0x8a, 0xb8, 0xbe, 0xcc, 0xf9, 0x60, 0xe4, 0x11,
137 0x9a, 0xd0, 0xeb, 0x48, 0x22, 0xd8, 0xdc, 0xf8]),
138 FipType('tos-fw-key-cert', 'Trusted OS Firmware key certificate',
139 [0x94, 0x77, 0xd6, 0x03, 0xfb, 0x60, 0xe4, 0x11,
140 0x85, 0xdd, 0xb7, 0x10, 0x5b, 0x8c, 0xee, 0x04]),
141 FipType('nt-fw-key-cert', 'Non-Trusted Firmware key certificate',
142 [0x8a, 0xd5, 0x83, 0x2a, 0xfb, 0x60, 0xe4, 0x11,
143 0x8a, 0xaf, 0xdf, 0x30, 0xbb, 0xc4, 0x98, 0x59]),
144 # Content certificates
145 FipType('tb-fw-cert', 'Trusted Boot Firmware BL2 certificate',
146 [0xd6, 0xe2, 0x69, 0xea, 0x5d, 0x63, 0xe4, 0x11,
147 0x8d, 0x8c, 0x9f, 0xba, 0xbe, 0x99, 0x56, 0xa5]),
148 FipType('scp-fw-cert', 'SCP Firmware content certificate',
149 [0x44, 0xbe, 0x6f, 0x04, 0x5e, 0x63, 0xe4, 0x11,
150 0xb2, 0x8b, 0x73, 0xd8, 0xea, 0xae, 0x96, 0x56]),
151 FipType('soc-fw-cert', 'SoC Firmware content certificate',
152 [0xe2, 0xb2, 0x0c, 0x20, 0x5e, 0x63, 0xe4, 0x11,
153 0x9c, 0xe8, 0xab, 0xcc, 0xf9, 0x2b, 0xb6, 0x66]),
154 FipType('tos-fw-cert', 'Trusted OS Firmware content certificate',
155 [0xa4, 0x9f, 0x44, 0x11, 0x5e, 0x63, 0xe4, 0x11,
156 0x87, 0x28, 0x3f, 0x05, 0x72, 0x2a, 0xf3, 0x3d]),
157 FipType('nt-fw-cert', 'Non-Trusted Firmware content certificate',
158 [0x8e, 0xc4, 0xc1, 0xf3, 0x5d, 0x63, 0xe4, 0x11,
159 0xa7, 0xa9, 0x87, 0xee, 0x40, 0xb2, 0x3f, 0xa7]),
160 FipType('sip-sp-cert', 'SiP owned Secure Partition content certificate',
161 [0x77, 0x6d, 0xfd, 0x44, 0x86, 0x97, 0x4c, 0x3b,
162 0x91, 0xeb, 0xc1, 0x3e, 0x02, 0x5a, 0x2a, 0x6f]),
163 FipType('plat-sp-cert', 'Platform owned Secure Partition content certificate',
164 [0xdd, 0xcb, 0xbf, 0x4a, 0xca, 0xd6, 0x11, 0xea,
165 0x87, 0xd0, 0x02, 0x42, 0xac, 0x13, 0x00, 0x03]),
166 # Dynamic configs
167 FipType('hw-config', 'HW_CONFIG',
168 [0x08, 0xb8, 0xf1, 0xd9, 0xc9, 0xcf, 0x93, 0x49,
169 0xa9, 0x62, 0x6f, 0xbc, 0x6b, 0x72, 0x65, 0xcc]),
170 FipType('tb-fw-config', 'TB_FW_CONFIG',
171 [0x6c, 0x04, 0x58, 0xff, 0xaf, 0x6b, 0x7d, 0x4f,
172 0x82, 0xed, 0xaa, 0x27, 0xbc, 0x69, 0xbf, 0xd2]),
173 FipType('soc-fw-config', 'SOC_FW_CONFIG',
174 [0x99, 0x79, 0x81, 0x4b, 0x03, 0x76, 0xfb, 0x46,
175 0x8c, 0x8e, 0x8d, 0x26, 0x7f, 0x78, 0x59, 0xe0]),
176 FipType('tos-fw-config', 'TOS_FW_CONFIG',
177 [0x26, 0x25, 0x7c, 0x1a, 0xdb, 0xc6, 0x7f, 0x47,
178 0x8d, 0x96, 0xc4, 0xc4, 0xb0, 0x24, 0x80, 0x21]),
179 FipType('nt-fw-config', 'NT_FW_CONFIG',
180 [0x28, 0xda, 0x98, 0x15, 0x93, 0xe8, 0x7e, 0x44,
181 0xac, 0x66, 0x1a, 0xaf, 0x80, 0x15, 0x50, 0xf9]),
182 FipType('fw-config', 'FW_CONFIG',
183 [0x58, 0x07, 0xe1, 0x6a, 0x84, 0x59, 0x47, 0xbe,
184 0x8e, 0xd5, 0x64, 0x8e, 0x8d, 0xdd, 0xab, 0x0e]),
185 ] # end
186
187FIP_TYPES = {ftype.name: ftype for ftype in FIP_TYPE_LIST}
188
189
190def get_type_uuid(fip_type_or_uuid):
191 """get_type_uuid() - Convert a type or uuid into both
192
193 This always returns a UUID, but may not return a type since it does not do
194 the reverse lookup.
195
196 Args:
197 fip_type_or_uuid (str or bytes): Either a string containing the name of
198 an entry (e.g. 'soc-fw') or a bytes(16) containing the UUID
199
200 Returns:
201 tuple:
202 str: fip type (None if not known)
203 bytes(16): uuid
204
205 Raises:
206 ValueError: An unknown type was requested
207 """
208 if isinstance(fip_type_or_uuid, str):
209 fip_type = fip_type_or_uuid
210 lookup = FIP_TYPES.get(fip_type)
211 if not lookup:
212 raise ValueError(f"Unknown FIP entry type '{fip_type}'")
213 uuid = lookup.uuid
214 else:
215 fip_type = None
216 uuid = fip_type_or_uuid
217 return fip_type, uuid
218
219
220# pylint: disable=R0903
221class FipHeader:
222 """Class to represent a FIP header"""
223 def __init__(self, name, serial, flags):
224 """Set up a new header object
225
226 Args:
227 name (str): Name, i.e. HEADER_MAGIC
228 serial (str): Serial value, i.e. HEADER_SERIAL
229 flags (int64): Flags value
230 """
231 self.name = name
232 self.serial = serial
233 self.flags = flags
234
235
236# pylint: disable=R0903
237class FipEntry:
238 """Class to represent a single FIP entry
239
240 This is used to hold the information about an entry, including its contents.
241 Use the get_data() method to obtain the raw output for writing to the FIP
242 file.
243 """
244 def __init__(self, uuid, offset, size, flags):
245 self.uuid = uuid
246 self.offset = offset
247 self.size = size
248 self.flags = flags
249 self.fip_type = None
250 self.data = None
Simon Glass80025522022-01-29 14:14:04 -0700251 self.valid = uuid != tools.get_bytes(0, UUID_LEN)
Simon Glass2697b7c2021-11-23 21:08:58 -0700252 if self.valid:
253 # Look up the friendly name
254 matches = {val for (key, val) in FIP_TYPES.items()
255 if val.uuid == uuid}
256 if len(matches) == 1:
257 self.fip_type = matches.pop().name
258
259 @classmethod
260 def from_type(cls, fip_type_or_uuid, data, flags):
261 """Create a FipEntry from a type name
262
263 Args:
264 cls (class): This class
265 fip_type_or_uuid (str or bytes): Name of the type to create, or
266 bytes(16) uuid
267 data (bytes): Contents of entry
268 flags (int64): Flags value
269
270 Returns:
271 FipEntry: Created 241
272 """
273 fip_type, uuid = get_type_uuid(fip_type_or_uuid)
274 fent = FipEntry(uuid, None, len(data), flags)
275 fent.fip_type = fip_type
276 fent.data = data
277 return fent
278
279
280def decode_fip(data):
281 """Decode a FIP into a header and list of FIP entries
282
283 Args:
284 data (bytes): Data block containing the FMAP
285
286 Returns:
287 Tuple:
288 header: FipHeader object
289 List of FipArea objects
290 """
291 fields = list(struct.unpack(HEADER_FORMAT, data[:HEADER_LEN]))
292 header = FipHeader(*fields)
293 fents = []
294 pos = HEADER_LEN
295 while True:
296 fields = list(struct.unpack(ENTRY_FORMAT, data[pos:pos + ENTRY_SIZE]))
297 fent = FipEntry(*fields)
298 if not fent.valid:
299 break
300 fent.data = data[fent.offset:fent.offset + fent.size]
301 fents.append(fent)
302 pos += ENTRY_SIZE
303 return header, fents
304
305
306class FipWriter:
307 """Class to handle writing a ARM Trusted Firmware's Firmware Image Package
308
309 Usage is something like:
310
311 fip = FipWriter(size)
Simon Glass80025522022-01-29 14:14:04 -0700312 fip.add_entry('scp-fwu-cfg', tools.read_file('something.bin'))
Simon Glass2697b7c2021-11-23 21:08:58 -0700313 ...
314 data = cbw.get_data()
315
316 Attributes:
317 """
318 def __init__(self, flags, align):
319 self._fip_entries = []
320 self._flags = flags
321 self._align = align
322
323 def add_entry(self, fip_type, data, flags):
324 """Add a new entry to the FIP
325
326 Args:
327 fip_type (str): Type to add, e.g. 'tos-fw-config'
328 data (bytes): Contents of entry
329 flags (int64): Entry flags
330
331 Returns:
332 FipEntry: entry that was added
333 """
334 fent = FipEntry.from_type(fip_type, data, flags)
335 self._fip_entries.append(fent)
336 return fent
337
338 def get_data(self):
339 """Obtain the full contents of the FIP
340
341 Thhis builds the FIP with headers and all required FIP entries.
342
343 Returns:
344 bytes: data resulting from building the FIP
345 """
346 buf = io.BytesIO()
347 hdr = struct.pack(HEADER_FORMAT, HEADER_MAGIC, HEADER_SERIAL,
348 self._flags)
349 buf.write(hdr)
350
351 # Calculate the position fo the first entry
352 offset = len(hdr)
353 offset += len(self._fip_entries) * ENTRY_SIZE
354 offset += ENTRY_SIZE # terminating entry
355
356 for fent in self._fip_entries:
Simon Glass80025522022-01-29 14:14:04 -0700357 offset = tools.align(offset, self._align)
Simon Glass2697b7c2021-11-23 21:08:58 -0700358 fent.offset = offset
359 offset += fent.size
360
361 # Write out the TOC
362 for fent in self._fip_entries:
363 hdr = struct.pack(ENTRY_FORMAT, fent.uuid, fent.offset, fent.size,
364 fent.flags)
365 buf.write(hdr)
366
367 # Write out the entries
368 for fent in self._fip_entries:
369 buf.seek(fent.offset)
370 buf.write(fent.data)
371
372 return buf.getvalue()
373
374
375class FipReader():
376 """Class to handle reading a Firmware Image Package (FIP)
377
378 Usage is something like:
379 fip = fip_util.FipReader(data)
380 fent = fip.get_entry('fwu')
381 self.WriteFile('ufwu.bin', fent.data)
382 blob = fip.get_entry(
383 bytes([0xe3, 0xb7, 0x8d, 0x9e, 0x4a, 0x64, 0x11, 0xec,
384 0xb4, 0x5c, 0xfb, 0xa2, 0xb9, 0xb4, 0x97, 0x88]))
385 self.WriteFile('blob.bin', blob.data)
386 """
387 def __init__(self, data, read=True):
388 """Set up a new FitReader
389
390 Args:
391 data (bytes): data to read
392 read (bool): True to read the data now
393 """
394 self.fents = collections.OrderedDict()
395 self.data = data
396 if read:
397 self.read()
398
399 def read(self):
400 """Read all the files in the FIP and add them to self.files"""
401 self.header, self.fents = decode_fip(self.data)
402
403 def get_entry(self, fip_type_or_uuid):
404 """get_entry() - Find an entry by type or UUID
405
406 Args:
407 fip_type_or_uuid (str or bytes): Name of the type to create, or
408 bytes(16) uuid
409
410 Returns:
411 FipEntry: if found
412
413 Raises:
414 ValueError: entry type not found
415 """
416 fip_type, uuid = get_type_uuid(fip_type_or_uuid)
417 for fent in self.fents:
418 if fent.uuid == uuid:
419 return fent
420 label = fip_type
421 if not label:
422 label = UUID(bytes=uuid)
423 raise ValueError(f"Cannot find FIP entry '{label}'")
424
425
426def parse_macros(srcdir):
427 """parse_macros: Parse the firmware_image_package.h file
428
429 Args:
Peter Robinsonb52fd3b2024-10-04 11:40:44 +0100430 srcdir (str): 'trusted-firmware-a' source directory
Simon Glass2697b7c2021-11-23 21:08:58 -0700431
432 Returns:
433 dict:
434 key: UUID macro name, e.g. 'UUID_TRUSTED_FWU_CERT'
435 value: list:
436 file comment, e.g. 'ToC Entry UUIDs'
437 macro name, e.g. 'UUID_TRUSTED_FWU_CERT'
438 uuid as bytes(16)
439
440 Raises:
441 ValueError: a line cannot be parsed
442 """
443 re_uuid = re.compile('0x[0-9a-fA-F]{2}')
444 re_comment = re.compile(r'^/\* (.*) \*/$')
445 fname = os.path.join(srcdir, 'include/tools_share/firmware_image_package.h')
Simon Glass80025522022-01-29 14:14:04 -0700446 data = tools.read_file(fname, binary=False)
Simon Glass2697b7c2021-11-23 21:08:58 -0700447 macros = collections.OrderedDict()
448 comment = None
449 for linenum, line in enumerate(data.splitlines()):
450 if line.startswith('/*'):
451 mat = re_comment.match(line)
452 if mat:
453 comment = mat.group(1)
454 else:
455 # Example: #define UUID_TOS_FW_CONFIG \
456 if 'UUID' in line:
457 macro = line.split()[1]
458 elif '{{' in line:
459 mat = re_uuid.findall(line)
460 if not mat or len(mat) != 16:
461 raise ValueError(
462 f'{fname}: Cannot parse UUID line {linenum + 1}: Got matches: {mat}')
463
464 uuid = bytes([int(val, 16) for val in mat])
465 macros[macro] = comment, macro, uuid
466 if not macros:
467 raise ValueError(f'{fname}: Cannot parse file')
468 return macros
469
470
471def parse_names(srcdir):
472 """parse_names: Parse the tbbr_config.c file
473
474 Args:
Peter Robinsonb52fd3b2024-10-04 11:40:44 +0100475 srcdir (str): 'trusted-firmware-a' source directory
Simon Glass2697b7c2021-11-23 21:08:58 -0700476
477 Returns:
478 tuple: dict of entries:
479 key: UUID macro, e.g. 'UUID_NON_TRUSTED_FIRMWARE_BL33'
480 tuple: entry information
481 Description of entry, e.g. 'Non-Trusted Firmware BL33'
482 UUID macro, e.g. 'UUID_NON_TRUSTED_FIRMWARE_BL33'
483 Name of entry, e.g. 'nt-fw'
484
485 Raises:
486 ValueError: the file cannot be parsed
487 """
488 # Extract the .name, .uuid and .cmdline_name values
489 re_data = re.compile(r'\.name = "([^"]*)",\s*\.uuid = (UUID_\w*),\s*\.cmdline_name = "([^"]+)"',
490 re.S)
491 fname = os.path.join(srcdir, 'tools/fiptool/tbbr_config.c')
Simon Glass80025522022-01-29 14:14:04 -0700492 data = tools.read_file(fname, binary=False)
Simon Glass2697b7c2021-11-23 21:08:58 -0700493
494 # Example entry:
495 # {
496 # .name = "Secure Payload BL32 Extra2 (Trusted OS Extra2)",
497 # .uuid = UUID_SECURE_PAYLOAD_BL32_EXTRA2,
498 # .cmdline_name = "tos-fw-extra2"
499 # },
500 mat = re_data.findall(data)
501 if not mat:
502 raise ValueError(f'{fname}: Cannot parse file')
503 names = {uuid: (desc, uuid, name) for desc, uuid, name in mat}
504 return names
505
506
507def create_code_output(macros, names):
508 """create_code_output() - Create the new version of this Python file
509
510 Args:
511 macros (dict):
512 key (str): UUID macro name, e.g. 'UUID_TRUSTED_FWU_CERT'
513 value: list:
514 file comment, e.g. 'ToC Entry UUIDs'
515 macro name, e.g. 'UUID_TRUSTED_FWU_CERT'
516 uuid as bytes(16)
517
518 names (dict): list of entries, each
519 tuple: entry information
520 Description of entry, e.g. 'Non-Trusted Firmware BL33'
521 UUID macro, e.g. 'UUID_NON_TRUSTED_FIRMWARE_BL33'
522 Name of entry, e.g. 'nt-fw'
523
524 Returns:
525 str: Table of FipType() entries
526 """
527 def _to_hex_list(data):
528 """Convert bytes into C code
529
530 Args:
531 bytes to convert
532
533 Returns:
534 str: in the format '0x12, 0x34, 0x56...'
535 """
536 # Use 0x instead of %# since the latter ignores the 0 modifier in
537 # Python 3.8.10
538 return ', '.join(['0x%02x' % byte for byte in data])
539
540 out = ''
541 last_comment = None
542 for comment, macro, uuid in macros.values():
543 name_entry = names.get(macro)
544 if not name_entry:
545 print(f"Warning: UUID '{macro}' is not mentioned in tbbr_config.c file")
546 continue
547 desc, _, name = name_entry
548 if last_comment != comment:
549 out += f' # {comment}\n'
550 last_comment = comment
551 out += """ FipType('%s', '%s',
552 [%s,
553 %s]),
554""" % (name, desc, _to_hex_list(uuid[:8]), _to_hex_list(uuid[8:]))
555 return out
556
557
558def parse_atf_source(srcdir, dstfile, oldfile):
559 """parse_atf_source(): Parse the ATF source tree and update this file
560
561 Args:
Peter Robinsonb52fd3b2024-10-04 11:40:44 +0100562 srcdir (str): Path to 'trusted-firmware-a' directory. Get this from:
Peter Robinson32d26c72024-10-02 19:08:49 +0100563 https://github.com/TrustedFirmware-A/trusted-firmware-a.git
Simon Glass2697b7c2021-11-23 21:08:58 -0700564 dstfile (str): File to write new code to, if an update is needed
565 oldfile (str): Python source file to compare against
566
567 Raises:
568 ValueError: srcdir readme.rst is missing or the first line does not
569 match what is expected
570 """
571 # We expect a readme file
572 readme_fname = os.path.join(srcdir, 'readme.rst')
573 if not os.path.exists(readme_fname):
574 raise ValueError(
575 f"Expected file '{readme_fname}' - try using -s to specify the "
Peter Robinsonb52fd3b2024-10-04 11:40:44 +0100576 'trusted-firmware-a directory')
Simon Glass80025522022-01-29 14:14:04 -0700577 readme = tools.read_file(readme_fname, binary=False)
Simon Glass2697b7c2021-11-23 21:08:58 -0700578 first_line = 'Trusted Firmware-A'
579 if readme.splitlines()[0] != first_line:
580 raise ValueError(f"'{readme_fname}' does not start with '{first_line}'")
581 macros = parse_macros(srcdir)
582 names = parse_names(srcdir)
583 output = create_code_output(macros, names)
Simon Glass80025522022-01-29 14:14:04 -0700584 orig = tools.read_file(oldfile, binary=False)
Simon Glass2697b7c2021-11-23 21:08:58 -0700585 re_fip_list = re.compile(r'(.*FIP_TYPE_LIST = \[).*?( ] # end.*)', re.S)
586 mat = re_fip_list.match(orig)
587 new_code = mat.group(1) + '\n' + output + mat.group(2) if mat else output
588 if new_code == orig:
589 print(f"Existing code in '{oldfile}' is up-to-date")
590 else:
Simon Glass80025522022-01-29 14:14:04 -0700591 tools.write_file(dstfile, new_code, binary=False)
Simon Glass2697b7c2021-11-23 21:08:58 -0700592 print(f'Needs update, try:\n\tmeld {dstfile} {oldfile}')
593
594
595def main(argv, oldfile):
596 """Main program for this tool
597
598 Args:
599 argv (list): List of str command-line arguments
600 oldfile (str): Python source file to compare against
601
602 Returns:
603 int: 0 (exit code)
604 """
605 parser = ArgumentParser(epilog='''Creates an updated version of this code,
Peter Robinsonb52fd3b2024-10-04 11:40:44 +0100606with a table of FIP-entry types parsed from the trusted-firmware-a source
Simon Glass2697b7c2021-11-23 21:08:58 -0700607directory''')
608 parser.add_argument(
609 '-D', '--debug', action='store_true',
610 help='Enabling debugging (provides a full traceback on error)')
611 parser.add_argument(
612 '-o', '--outfile', type=str, default='fip_util.py.out',
613 help='Output file to write new fip_util.py file to')
614 parser.add_argument(
615 '-s', '--src', type=str, default='.',
Peter Robinsonb52fd3b2024-10-04 11:40:44 +0100616 help='Directory containing the trusted-firmware-a source')
Simon Glass2697b7c2021-11-23 21:08:58 -0700617 args = parser.parse_args(argv)
618
619 if not args.debug:
620 sys.tracebacklimit = 0
621
622 parse_atf_source(args.src, args.outfile, oldfile)
623 return 0
624
625
Simon Glass2697b7c2021-11-23 21:08:58 -0700626if __name__ == "__main__":
627 sys.exit(main(sys.argv[1:], OUR_FILE)) # pragma: no cover