blob: 26f1cf462ecd611395527b94407fc24c4ac867f8 [file] [log] [blame]
Tom Rini83d290c2018-05-06 17:58:06 -04001# SPDX-License-Identifier: GPL-2.0+
Simon Glassbf7fd502016-11-25 20:15:51 -07002# Copyright (c) 2016 Google, Inc
3# Written by Simon Glass <sjg@chromium.org>
4#
Simon Glassbf7fd502016-11-25 20:15:51 -07005# Creates binary images from input files controlled by a description
6#
7
8from collections import OrderedDict
Simon Glass87d43322020-08-05 13:27:46 -06009import glob
Simon Glassbf7fd502016-11-25 20:15:51 -070010import os
Simon Glass9fbfaba2020-08-29 11:36:14 -060011import pkg_resources
Simon Glassb2381432020-09-06 10:39:09 -060012import re
Simon Glass9fbfaba2020-08-29 11:36:14 -060013
Simon Glassbf7fd502016-11-25 20:15:51 -070014import sys
Simon Glassbf776672020-04-17 18:09:04 -060015from patman import tools
Simon Glassbf7fd502016-11-25 20:15:51 -070016
Simon Glass16287932020-04-17 18:09:03 -060017from binman import cbfs_util
18from binman import elf
Simon Glassbf776672020-04-17 18:09:04 -060019from patman import command
20from patman import tout
Simon Glassbf7fd502016-11-25 20:15:51 -070021
22# List of images we plan to create
23# Make this global so that it can be referenced from tests
24images = OrderedDict()
25
Simon Glassb2381432020-09-06 10:39:09 -060026# Help text for each type of missing blob, dict:
27# key: Value of the entry's 'missing-msg' or entry name
28# value: Text for the help
29missing_blob_help = {}
30
Simon Glassbf7fd502016-11-25 20:15:51 -070031def _ReadImageDesc(binman_node):
32 """Read the image descriptions from the /binman node
33
34 This normally produces a single Image object called 'image'. But if
35 multiple images are present, they will all be returned.
36
37 Args:
38 binman_node: Node object of the /binman node
39 Returns:
40 OrderedDict of Image objects, each of which describes an image
41 """
42 images = OrderedDict()
43 if 'multiple-images' in binman_node.props:
44 for node in binman_node.subnodes:
45 images[node.name] = Image(node.name, node)
46 else:
47 images['image'] = Image('image', binman_node)
48 return images
49
Simon Glassec3f3782017-05-27 07:38:29 -060050def _FindBinmanNode(dtb):
Simon Glassbf7fd502016-11-25 20:15:51 -070051 """Find the 'binman' node in the device tree
52
53 Args:
Simon Glassec3f3782017-05-27 07:38:29 -060054 dtb: Fdt object to scan
Simon Glassbf7fd502016-11-25 20:15:51 -070055 Returns:
56 Node object of /binman node, or None if not found
57 """
Simon Glassec3f3782017-05-27 07:38:29 -060058 for node in dtb.GetRoot().subnodes:
Simon Glassbf7fd502016-11-25 20:15:51 -070059 if node.name == 'binman':
60 return node
61 return None
62
Simon Glassb2381432020-09-06 10:39:09 -060063def _ReadMissingBlobHelp():
64 """Read the missing-blob-help file
65
66 This file containins help messages explaining what to do when external blobs
67 are missing.
68
69 Returns:
70 Dict:
71 key: Message tag (str)
72 value: Message text (str)
73 """
74
75 def _FinishTag(tag, msg, result):
76 if tag:
77 result[tag] = msg.rstrip()
78 tag = None
79 msg = ''
80 return tag, msg
81
82 my_data = pkg_resources.resource_string(__name__, 'missing-blob-help')
83 re_tag = re.compile('^([-a-z0-9]+):$')
84 result = {}
85 tag = None
86 msg = ''
87 for line in my_data.decode('utf-8').splitlines():
88 if not line.startswith('#'):
89 m_tag = re_tag.match(line)
90 if m_tag:
91 _, msg = _FinishTag(tag, msg, result)
92 tag = m_tag.group(1)
93 elif tag:
94 msg += line + '\n'
95 _FinishTag(tag, msg, result)
96 return result
97
98def _ShowBlobHelp(path, text):
99 tout.Warning('\n%s:' % path)
100 for line in text.splitlines():
101 tout.Warning(' %s' % line)
102
103def _ShowHelpForMissingBlobs(missing_list):
104 """Show help for each missing blob to help the user take action
105
106 Args:
107 missing_list: List of Entry objects to show help for
108 """
109 global missing_blob_help
110
111 if not missing_blob_help:
112 missing_blob_help = _ReadMissingBlobHelp()
113
114 for entry in missing_list:
115 tags = entry.GetHelpTags()
116
117 # Show the first match help message
118 for tag in tags:
119 if tag in missing_blob_help:
120 _ShowBlobHelp(entry._node.path, missing_blob_help[tag])
121 break
122
Simon Glass87d43322020-08-05 13:27:46 -0600123def GetEntryModules(include_testing=True):
124 """Get a set of entry class implementations
125
126 Returns:
127 Set of paths to entry class filenames
128 """
Simon Glass9fbfaba2020-08-29 11:36:14 -0600129 glob_list = pkg_resources.resource_listdir(__name__, 'etype')
130 glob_list = [fname for fname in glob_list if fname.endswith('.py')]
Simon Glass87d43322020-08-05 13:27:46 -0600131 return set([os.path.splitext(os.path.basename(item))[0]
132 for item in glob_list
133 if include_testing or '_testing' not in item])
134
Simon Glassc55a50f2018-09-14 04:57:19 -0600135def WriteEntryDocs(modules, test_missing=None):
136 """Write out documentation for all entries
Simon Glassecab8972018-07-06 10:27:40 -0600137
138 Args:
Simon Glassc55a50f2018-09-14 04:57:19 -0600139 modules: List of Module objects to get docs for
140 test_missing: Used for testing only, to force an entry's documeentation
141 to show as missing even if it is present. Should be set to None in
142 normal use.
Simon Glassecab8972018-07-06 10:27:40 -0600143 """
Simon Glass16287932020-04-17 18:09:03 -0600144 from binman.entry import Entry
Simon Glassfd8d1f72018-07-17 13:25:36 -0600145 Entry.WriteDocs(modules, test_missing)
146
Simon Glass61f564d2019-07-08 14:25:48 -0600147
148def ListEntries(image_fname, entry_paths):
149 """List the entries in an image
150
151 This decodes the supplied image and displays a table of entries from that
152 image, preceded by a header.
153
154 Args:
155 image_fname: Image filename to process
156 entry_paths: List of wildcarded paths (e.g. ['*dtb*', 'u-boot*',
157 'section/u-boot'])
158 """
159 image = Image.FromFile(image_fname)
160
161 entries, lines, widths = image.GetListEntries(entry_paths)
162
163 num_columns = len(widths)
164 for linenum, line in enumerate(lines):
165 if linenum == 1:
166 # Print header line
167 print('-' * (sum(widths) + num_columns * 2))
168 out = ''
169 for i, item in enumerate(line):
170 width = -widths[i]
171 if item.startswith('>'):
172 width = -width
173 item = item[1:]
174 txt = '%*s ' % (width, item)
175 out += txt
176 print(out.rstrip())
177
Simon Glassf667e452019-07-08 14:25:50 -0600178
179def ReadEntry(image_fname, entry_path, decomp=True):
180 """Extract an entry from an image
181
182 This extracts the data from a particular entry in an image
183
184 Args:
185 image_fname: Image filename to process
186 entry_path: Path to entry to extract
187 decomp: True to return uncompressed data, if the data is compress
188 False to return the raw data
189
190 Returns:
191 data extracted from the entry
192 """
Simon Glass8dbb7442019-08-24 07:22:44 -0600193 global Image
Simon Glass07237982020-08-05 13:27:47 -0600194 from binman.image import Image
Simon Glass8dbb7442019-08-24 07:22:44 -0600195
Simon Glassf667e452019-07-08 14:25:50 -0600196 image = Image.FromFile(image_fname)
197 entry = image.FindEntryPath(entry_path)
198 return entry.ReadData(decomp)
199
200
Simon Glass71ce0ba2019-07-08 14:25:52 -0600201def ExtractEntries(image_fname, output_fname, outdir, entry_paths,
202 decomp=True):
203 """Extract the data from one or more entries and write it to files
204
205 Args:
206 image_fname: Image filename to process
207 output_fname: Single output filename to use if extracting one file, None
208 otherwise
209 outdir: Output directory to use (for any number of files), else None
210 entry_paths: List of entry paths to extract
Simon Glass3ad804e2019-07-20 12:24:12 -0600211 decomp: True to decompress the entry data
Simon Glass71ce0ba2019-07-08 14:25:52 -0600212
213 Returns:
214 List of EntryInfo records that were written
215 """
216 image = Image.FromFile(image_fname)
217
218 # Output an entry to a single file, as a special case
219 if output_fname:
220 if not entry_paths:
Simon Glassbb5edc12019-07-20 12:24:14 -0600221 raise ValueError('Must specify an entry path to write with -f')
Simon Glass71ce0ba2019-07-08 14:25:52 -0600222 if len(entry_paths) != 1:
Simon Glassbb5edc12019-07-20 12:24:14 -0600223 raise ValueError('Must specify exactly one entry path to write with -f')
Simon Glass71ce0ba2019-07-08 14:25:52 -0600224 entry = image.FindEntryPath(entry_paths[0])
225 data = entry.ReadData(decomp)
226 tools.WriteFile(output_fname, data)
227 tout.Notice("Wrote %#x bytes to file '%s'" % (len(data), output_fname))
228 return
229
230 # Otherwise we will output to a path given by the entry path of each entry.
231 # This means that entries will appear in subdirectories if they are part of
232 # a sub-section.
233 einfos = image.GetListEntries(entry_paths)[0]
234 tout.Notice('%d entries match and will be written' % len(einfos))
235 for einfo in einfos:
236 entry = einfo.entry
237 data = entry.ReadData(decomp)
238 path = entry.GetPath()[1:]
239 fname = os.path.join(outdir, path)
240
241 # If this entry has children, create a directory for it and put its
242 # data in a file called 'root' in that directory
243 if entry.GetEntries():
244 if not os.path.exists(fname):
245 os.makedirs(fname)
246 fname = os.path.join(fname, 'root')
247 tout.Notice("Write entry '%s' to '%s'" % (entry.GetPath(), fname))
248 tools.WriteFile(fname, data)
249 return einfos
250
251
Simon Glassd7fa4e42019-07-20 12:24:13 -0600252def BeforeReplace(image, allow_resize):
253 """Handle getting an image ready for replacing entries in it
254
255 Args:
256 image: Image to prepare
257 """
258 state.PrepareFromLoadedData(image)
259 image.LoadData()
260
261 # If repacking, drop the old offset/size values except for the original
262 # ones, so we are only left with the constraints.
263 if allow_resize:
264 image.ResetForPack()
265
266
267def ReplaceOneEntry(image, entry, data, do_compress, allow_resize):
268 """Handle replacing a single entry an an image
269
270 Args:
271 image: Image to update
272 entry: Entry to write
273 data: Data to replace with
274 do_compress: True to compress the data if needed, False if data is
275 already compressed so should be used as is
276 allow_resize: True to allow entries to change size (this does a re-pack
277 of the entries), False to raise an exception
278 """
279 if not entry.WriteData(data, do_compress):
280 if not image.allow_repack:
281 entry.Raise('Entry data size does not match, but allow-repack is not present for this image')
282 if not allow_resize:
283 entry.Raise('Entry data size does not match, but resize is disabled')
284
285
286def AfterReplace(image, allow_resize, write_map):
287 """Handle write out an image after replacing entries in it
288
289 Args:
290 image: Image to write
291 allow_resize: True to allow entries to change size (this does a re-pack
292 of the entries), False to raise an exception
293 write_map: True to write a map file
294 """
295 tout.Info('Processing image')
296 ProcessImage(image, update_fdt=True, write_map=write_map,
297 get_contents=False, allow_resize=allow_resize)
298
299
300def WriteEntryToImage(image, entry, data, do_compress=True, allow_resize=True,
301 write_map=False):
302 BeforeReplace(image, allow_resize)
303 tout.Info('Writing data to %s' % entry.GetPath())
304 ReplaceOneEntry(image, entry, data, do_compress, allow_resize)
305 AfterReplace(image, allow_resize=allow_resize, write_map=write_map)
306
307
Simon Glass3ad804e2019-07-20 12:24:12 -0600308def WriteEntry(image_fname, entry_path, data, do_compress=True,
309 allow_resize=True, write_map=False):
Simon Glass22a76b72019-07-20 12:24:11 -0600310 """Replace an entry in an image
311
312 This replaces the data in a particular entry in an image. This size of the
313 new data must match the size of the old data unless allow_resize is True.
314
315 Args:
316 image_fname: Image filename to process
317 entry_path: Path to entry to extract
318 data: Data to replace with
Simon Glass3ad804e2019-07-20 12:24:12 -0600319 do_compress: True to compress the data if needed, False if data is
Simon Glass22a76b72019-07-20 12:24:11 -0600320 already compressed so should be used as is
321 allow_resize: True to allow entries to change size (this does a re-pack
322 of the entries), False to raise an exception
Simon Glass3ad804e2019-07-20 12:24:12 -0600323 write_map: True to write a map file
Simon Glass22a76b72019-07-20 12:24:11 -0600324
325 Returns:
326 Image object that was updated
327 """
Simon Glassd7fa4e42019-07-20 12:24:13 -0600328 tout.Info("Write entry '%s', file '%s'" % (entry_path, image_fname))
Simon Glass22a76b72019-07-20 12:24:11 -0600329 image = Image.FromFile(image_fname)
330 entry = image.FindEntryPath(entry_path)
Simon Glassd7fa4e42019-07-20 12:24:13 -0600331 WriteEntryToImage(image, entry, data, do_compress=do_compress,
332 allow_resize=allow_resize, write_map=write_map)
Simon Glass22a76b72019-07-20 12:24:11 -0600333
Simon Glass22a76b72019-07-20 12:24:11 -0600334 return image
335
Simon Glassa6cb9952019-07-20 12:24:15 -0600336
337def ReplaceEntries(image_fname, input_fname, indir, entry_paths,
338 do_compress=True, allow_resize=True, write_map=False):
339 """Replace the data from one or more entries from input files
340
341 Args:
342 image_fname: Image filename to process
343 input_fname: Single input ilename to use if replacing one file, None
344 otherwise
345 indir: Input directory to use (for any number of files), else None
346 entry_paths: List of entry paths to extract
347 do_compress: True if the input data is uncompressed and may need to be
348 compressed if the entry requires it, False if the data is already
349 compressed.
350 write_map: True to write a map file
351
352 Returns:
353 List of EntryInfo records that were written
354 """
355 image = Image.FromFile(image_fname)
356
357 # Replace an entry from a single file, as a special case
358 if input_fname:
359 if not entry_paths:
360 raise ValueError('Must specify an entry path to read with -f')
361 if len(entry_paths) != 1:
362 raise ValueError('Must specify exactly one entry path to write with -f')
363 entry = image.FindEntryPath(entry_paths[0])
364 data = tools.ReadFile(input_fname)
365 tout.Notice("Read %#x bytes from file '%s'" % (len(data), input_fname))
366 WriteEntryToImage(image, entry, data, do_compress=do_compress,
367 allow_resize=allow_resize, write_map=write_map)
368 return
369
370 # Otherwise we will input from a path given by the entry path of each entry.
371 # This means that files must appear in subdirectories if they are part of
372 # a sub-section.
373 einfos = image.GetListEntries(entry_paths)[0]
374 tout.Notice("Replacing %d matching entries in image '%s'" %
375 (len(einfos), image_fname))
376
377 BeforeReplace(image, allow_resize)
378
379 for einfo in einfos:
380 entry = einfo.entry
381 if entry.GetEntries():
382 tout.Info("Skipping section entry '%s'" % entry.GetPath())
383 continue
384
385 path = entry.GetPath()[1:]
386 fname = os.path.join(indir, path)
387
388 if os.path.exists(fname):
389 tout.Notice("Write entry '%s' from file '%s'" %
390 (entry.GetPath(), fname))
391 data = tools.ReadFile(fname)
392 ReplaceOneEntry(image, entry, data, do_compress, allow_resize)
393 else:
394 tout.Warning("Skipping entry '%s' from missing file '%s'" %
395 (entry.GetPath(), fname))
396
397 AfterReplace(image, allow_resize=allow_resize, write_map=write_map)
398 return image
399
400
Simon Glassa8573c42019-07-20 12:23:27 -0600401def PrepareImagesAndDtbs(dtb_fname, select_images, update_fdt):
402 """Prepare the images to be processed and select the device tree
403
404 This function:
405 - reads in the device tree
406 - finds and scans the binman node to create all entries
407 - selects which images to build
408 - Updates the device tress with placeholder properties for offset,
409 image-pos, etc.
410
411 Args:
412 dtb_fname: Filename of the device tree file to use (.dts or .dtb)
413 selected_images: List of images to output, or None for all
414 update_fdt: True to update the FDT wth entry offsets, etc.
Simon Glasse9d336d2020-09-01 05:13:55 -0600415
416 Returns:
417 OrderedDict of images:
418 key: Image name (str)
419 value: Image object
Simon Glassa8573c42019-07-20 12:23:27 -0600420 """
421 # Import these here in case libfdt.py is not available, in which case
422 # the above help option still works.
Simon Glass16287932020-04-17 18:09:03 -0600423 from dtoc import fdt
424 from dtoc import fdt_util
Simon Glassa8573c42019-07-20 12:23:27 -0600425 global images
426
427 # Get the device tree ready by compiling it and copying the compiled
428 # output into a file in our output directly. Then scan it for use
429 # in binman.
430 dtb_fname = fdt_util.EnsureCompiled(dtb_fname)
431 fname = tools.GetOutputFilename('u-boot.dtb.out')
432 tools.WriteFile(fname, tools.ReadFile(dtb_fname))
433 dtb = fdt.FdtScan(fname)
434
435 node = _FindBinmanNode(dtb)
436 if not node:
437 raise ValueError("Device tree '%s' does not have a 'binman' "
438 "node" % dtb_fname)
439
440 images = _ReadImageDesc(node)
441
442 if select_images:
443 skip = []
444 new_images = OrderedDict()
445 for name, image in images.items():
446 if name in select_images:
447 new_images[name] = image
448 else:
449 skip.append(name)
450 images = new_images
451 tout.Notice('Skipping images: %s' % ', '.join(skip))
452
453 state.Prepare(images, dtb)
454
455 # Prepare the device tree by making sure that any missing
456 # properties are added (e.g. 'pos' and 'size'). The values of these
457 # may not be correct yet, but we add placeholders so that the
458 # size of the device tree is correct. Later, in
459 # SetCalculatedProperties() we will insert the correct values
460 # without changing the device-tree size, thus ensuring that our
461 # entry offsets remain the same.
462 for image in images.values():
463 image.ExpandEntries()
464 if update_fdt:
Simon Glassa9fad072020-10-26 17:40:17 -0600465 image.AddMissingProperties(True)
Simon Glassa8573c42019-07-20 12:23:27 -0600466 image.ProcessFdt(dtb)
467
Simon Glass4bdd1152019-07-20 12:23:29 -0600468 for dtb_item in state.GetAllFdts():
Simon Glassa8573c42019-07-20 12:23:27 -0600469 dtb_item.Sync(auto_resize=True)
470 dtb_item.Pack()
471 dtb_item.Flush()
472 return images
473
474
Simon Glass51014aa2019-07-20 12:23:56 -0600475def ProcessImage(image, update_fdt, write_map, get_contents=True,
Simon Glass4f9f1052020-07-09 18:39:38 -0600476 allow_resize=True, allow_missing=False):
Simon Glassb88e81c2019-07-20 12:23:24 -0600477 """Perform all steps for this image, including checking and # writing it.
478
479 This means that errors found with a later image will be reported after
480 earlier images are already completed and written, but that does not seem
481 important.
482
483 Args:
484 image: Image to process
485 update_fdt: True to update the FDT wth entry offsets, etc.
486 write_map: True to write a map file
Simon Glass10f9d002019-07-20 12:23:50 -0600487 get_contents: True to get the image contents from files, etc., False if
488 the contents is already present
Simon Glass51014aa2019-07-20 12:23:56 -0600489 allow_resize: True to allow entries to change size (this does a re-pack
490 of the entries), False to raise an exception
Simon Glass4f9f1052020-07-09 18:39:38 -0600491 allow_missing: Allow blob_ext objects to be missing
Simon Glassb1cca952020-07-09 18:39:40 -0600492
493 Returns:
494 True if one or more external blobs are missing, False if all are present
Simon Glassb88e81c2019-07-20 12:23:24 -0600495 """
Simon Glass10f9d002019-07-20 12:23:50 -0600496 if get_contents:
Simon Glass4f9f1052020-07-09 18:39:38 -0600497 image.SetAllowMissing(allow_missing)
Simon Glass10f9d002019-07-20 12:23:50 -0600498 image.GetEntryContents()
Simon Glassb88e81c2019-07-20 12:23:24 -0600499 image.GetEntryOffsets()
500
501 # We need to pack the entries to figure out where everything
502 # should be placed. This sets the offset/size of each entry.
503 # However, after packing we call ProcessEntryContents() which
504 # may result in an entry changing size. In that case we need to
505 # do another pass. Since the device tree often contains the
506 # final offset/size information we try to make space for this in
507 # AddMissingProperties() above. However, if the device is
508 # compressed we cannot know this compressed size in advance,
509 # since changing an offset from 0x100 to 0x104 (for example) can
510 # alter the compressed size of the device tree. So we need a
511 # third pass for this.
Simon Glasseb0f4a42019-07-20 12:24:06 -0600512 passes = 5
Simon Glassb88e81c2019-07-20 12:23:24 -0600513 for pack_pass in range(passes):
514 try:
515 image.PackEntries()
516 image.CheckSize()
517 image.CheckEntries()
518 except Exception as e:
519 if write_map:
520 fname = image.WriteMap()
521 print("Wrote map file '%s' to show errors" % fname)
522 raise
523 image.SetImagePos()
524 if update_fdt:
525 image.SetCalculatedProperties()
Simon Glass4bdd1152019-07-20 12:23:29 -0600526 for dtb_item in state.GetAllFdts():
Simon Glassb88e81c2019-07-20 12:23:24 -0600527 dtb_item.Sync()
Simon Glass51014aa2019-07-20 12:23:56 -0600528 dtb_item.Flush()
Simon Glass261cbe02019-08-24 07:23:12 -0600529 image.WriteSymbols()
Simon Glassb88e81c2019-07-20 12:23:24 -0600530 sizes_ok = image.ProcessEntryContents()
531 if sizes_ok:
532 break
533 image.ResetForPack()
Simon Glassaed6c0b2019-08-24 07:23:13 -0600534 tout.Info('Pack completed after %d pass(es)' % (pack_pass + 1))
Simon Glassb88e81c2019-07-20 12:23:24 -0600535 if not sizes_ok:
Simon Glass61ec04f2019-07-20 12:23:58 -0600536 image.Raise('Entries changed size after packing (tried %s passes)' %
Simon Glassb88e81c2019-07-20 12:23:24 -0600537 passes)
538
Simon Glassb88e81c2019-07-20 12:23:24 -0600539 image.BuildImage()
540 if write_map:
541 image.WriteMap()
Simon Glassb1cca952020-07-09 18:39:40 -0600542 missing_list = []
543 image.CheckMissing(missing_list)
544 if missing_list:
545 tout.Warning("Image '%s' is missing external blobs and is non-functional: %s" %
546 (image.name, ' '.join([e.name for e in missing_list])))
Simon Glassb2381432020-09-06 10:39:09 -0600547 _ShowHelpForMissingBlobs(missing_list)
Simon Glassb1cca952020-07-09 18:39:40 -0600548 return bool(missing_list)
Simon Glassb88e81c2019-07-20 12:23:24 -0600549
550
Simon Glass53cd5d92019-07-08 14:25:29 -0600551def Binman(args):
Simon Glassbf7fd502016-11-25 20:15:51 -0700552 """The main control code for binman
553
554 This assumes that help and test options have already been dealt with. It
555 deals with the core task of building images.
556
557 Args:
Simon Glass53cd5d92019-07-08 14:25:29 -0600558 args: Command line arguments Namespace object
Simon Glassbf7fd502016-11-25 20:15:51 -0700559 """
Simon Glass8dbb7442019-08-24 07:22:44 -0600560 global Image
561 global state
562
Simon Glass53cd5d92019-07-08 14:25:29 -0600563 if args.full_help:
Simon Glassbf7fd502016-11-25 20:15:51 -0700564 pager = os.getenv('PAGER')
565 if not pager:
566 pager = 'more'
567 fname = os.path.join(os.path.dirname(os.path.realpath(sys.argv[0])),
568 'README')
569 command.Run(pager, fname)
570 return 0
571
Simon Glass8dbb7442019-08-24 07:22:44 -0600572 # Put these here so that we can import this module without libfdt
Simon Glass07237982020-08-05 13:27:47 -0600573 from binman.image import Image
Simon Glass16287932020-04-17 18:09:03 -0600574 from binman import state
Simon Glass8dbb7442019-08-24 07:22:44 -0600575
Simon Glass7bc4f0f2019-09-15 18:10:36 -0600576 if args.cmd in ['ls', 'extract', 'replace']:
Simon Glass96b6c502019-07-20 12:23:53 -0600577 try:
Simon Glass7bc4f0f2019-09-15 18:10:36 -0600578 tout.Init(args.verbosity)
Simon Glass96b6c502019-07-20 12:23:53 -0600579 tools.PrepareOutputDir(None)
Simon Glass7bc4f0f2019-09-15 18:10:36 -0600580 if args.cmd == 'ls':
581 ListEntries(args.image, args.paths)
Simon Glass61f564d2019-07-08 14:25:48 -0600582
Simon Glass7bc4f0f2019-09-15 18:10:36 -0600583 if args.cmd == 'extract':
584 ExtractEntries(args.image, args.filename, args.outdir, args.paths,
585 not args.uncompressed)
Simon Glass71ce0ba2019-07-08 14:25:52 -0600586
Simon Glass7bc4f0f2019-09-15 18:10:36 -0600587 if args.cmd == 'replace':
588 ReplaceEntries(args.image, args.filename, args.indir, args.paths,
589 do_compress=not args.compressed,
590 allow_resize=not args.fix_size, write_map=args.map)
591 except:
592 raise
Simon Glassa6cb9952019-07-20 12:24:15 -0600593 finally:
594 tools.FinaliseOutputDir()
595 return 0
596
Simon Glassbf7fd502016-11-25 20:15:51 -0700597 # Try to figure out which device tree contains our image description
Simon Glass53cd5d92019-07-08 14:25:29 -0600598 if args.dt:
599 dtb_fname = args.dt
Simon Glassbf7fd502016-11-25 20:15:51 -0700600 else:
Simon Glass53cd5d92019-07-08 14:25:29 -0600601 board = args.board
Simon Glassbf7fd502016-11-25 20:15:51 -0700602 if not board:
603 raise ValueError('Must provide a board to process (use -b <board>)')
Simon Glass53cd5d92019-07-08 14:25:29 -0600604 board_pathname = os.path.join(args.build_dir, board)
Simon Glassbf7fd502016-11-25 20:15:51 -0700605 dtb_fname = os.path.join(board_pathname, 'u-boot.dtb')
Simon Glass53cd5d92019-07-08 14:25:29 -0600606 if not args.indir:
607 args.indir = ['.']
608 args.indir.append(board_pathname)
Simon Glassbf7fd502016-11-25 20:15:51 -0700609
610 try:
Simon Glass53cd5d92019-07-08 14:25:29 -0600611 tout.Init(args.verbosity)
612 elf.debug = args.debug
613 cbfs_util.VERBOSE = args.verbosity > 2
614 state.use_fake_dtb = args.fake_dtb
Simon Glassbf7fd502016-11-25 20:15:51 -0700615 try:
Simon Glass53cd5d92019-07-08 14:25:29 -0600616 tools.SetInputDirs(args.indir)
617 tools.PrepareOutputDir(args.outdir, args.preserve)
618 tools.SetToolPaths(args.toolpath)
619 state.SetEntryArgs(args.entry_arg)
Simon Glassecab8972018-07-06 10:27:40 -0600620
Simon Glassa8573c42019-07-20 12:23:27 -0600621 images = PrepareImagesAndDtbs(dtb_fname, args.image,
622 args.update_fdt)
Simon Glassb1cca952020-07-09 18:39:40 -0600623 missing = False
Simon Glassbf7fd502016-11-25 20:15:51 -0700624 for image in images.values():
Simon Glassb1cca952020-07-09 18:39:40 -0600625 missing |= ProcessImage(image, args.update_fdt, args.map,
626 allow_missing=args.allow_missing)
Simon Glass2a72cc72018-09-14 04:57:20 -0600627
628 # Write the updated FDTs to our output files
Simon Glass4bdd1152019-07-20 12:23:29 -0600629 for dtb_item in state.GetAllFdts():
Simon Glass2a72cc72018-09-14 04:57:20 -0600630 tools.WriteFile(dtb_item._fname, dtb_item.GetContents())
631
Simon Glassb1cca952020-07-09 18:39:40 -0600632 if missing:
Simon Glassb2381432020-09-06 10:39:09 -0600633 tout.Warning("\nSome images are invalid")
Simon Glassbf7fd502016-11-25 20:15:51 -0700634 finally:
635 tools.FinaliseOutputDir()
636 finally:
637 tout.Uninit()
638
639 return 0