blob: 1952b2abf48fb697f38029eecc40b772604cafc4 [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')
Simon Glass5b378e42021-01-06 21:35:13 -0700247 tout.Notice("Write entry '%s' size %x to '%s'" %
248 (entry.GetPath(), len(data), fname))
Simon Glass71ce0ba2019-07-08 14:25:52 -0600249 tools.WriteFile(fname, data)
250 return einfos
251
252
Simon Glassd7fa4e42019-07-20 12:24:13 -0600253def BeforeReplace(image, allow_resize):
254 """Handle getting an image ready for replacing entries in it
255
256 Args:
257 image: Image to prepare
258 """
259 state.PrepareFromLoadedData(image)
260 image.LoadData()
261
262 # If repacking, drop the old offset/size values except for the original
263 # ones, so we are only left with the constraints.
264 if allow_resize:
265 image.ResetForPack()
266
267
268def ReplaceOneEntry(image, entry, data, do_compress, allow_resize):
269 """Handle replacing a single entry an an image
270
271 Args:
272 image: Image to update
273 entry: Entry to write
274 data: Data to replace with
275 do_compress: True to compress the data if needed, False if data is
276 already compressed so should be used as is
277 allow_resize: True to allow entries to change size (this does a re-pack
278 of the entries), False to raise an exception
279 """
280 if not entry.WriteData(data, do_compress):
281 if not image.allow_repack:
282 entry.Raise('Entry data size does not match, but allow-repack is not present for this image')
283 if not allow_resize:
284 entry.Raise('Entry data size does not match, but resize is disabled')
285
286
287def AfterReplace(image, allow_resize, write_map):
288 """Handle write out an image after replacing entries in it
289
290 Args:
291 image: Image to write
292 allow_resize: True to allow entries to change size (this does a re-pack
293 of the entries), False to raise an exception
294 write_map: True to write a map file
295 """
296 tout.Info('Processing image')
297 ProcessImage(image, update_fdt=True, write_map=write_map,
298 get_contents=False, allow_resize=allow_resize)
299
300
301def WriteEntryToImage(image, entry, data, do_compress=True, allow_resize=True,
302 write_map=False):
303 BeforeReplace(image, allow_resize)
304 tout.Info('Writing data to %s' % entry.GetPath())
305 ReplaceOneEntry(image, entry, data, do_compress, allow_resize)
306 AfterReplace(image, allow_resize=allow_resize, write_map=write_map)
307
308
Simon Glass3ad804e2019-07-20 12:24:12 -0600309def WriteEntry(image_fname, entry_path, data, do_compress=True,
310 allow_resize=True, write_map=False):
Simon Glass22a76b72019-07-20 12:24:11 -0600311 """Replace an entry in an image
312
313 This replaces the data in a particular entry in an image. This size of the
314 new data must match the size of the old data unless allow_resize is True.
315
316 Args:
317 image_fname: Image filename to process
318 entry_path: Path to entry to extract
319 data: Data to replace with
Simon Glass3ad804e2019-07-20 12:24:12 -0600320 do_compress: True to compress the data if needed, False if data is
Simon Glass22a76b72019-07-20 12:24:11 -0600321 already compressed so should be used as is
322 allow_resize: True to allow entries to change size (this does a re-pack
323 of the entries), False to raise an exception
Simon Glass3ad804e2019-07-20 12:24:12 -0600324 write_map: True to write a map file
Simon Glass22a76b72019-07-20 12:24:11 -0600325
326 Returns:
327 Image object that was updated
328 """
Simon Glassd7fa4e42019-07-20 12:24:13 -0600329 tout.Info("Write entry '%s', file '%s'" % (entry_path, image_fname))
Simon Glass22a76b72019-07-20 12:24:11 -0600330 image = Image.FromFile(image_fname)
331 entry = image.FindEntryPath(entry_path)
Simon Glassd7fa4e42019-07-20 12:24:13 -0600332 WriteEntryToImage(image, entry, data, do_compress=do_compress,
333 allow_resize=allow_resize, write_map=write_map)
Simon Glass22a76b72019-07-20 12:24:11 -0600334
Simon Glass22a76b72019-07-20 12:24:11 -0600335 return image
336
Simon Glassa6cb9952019-07-20 12:24:15 -0600337
338def ReplaceEntries(image_fname, input_fname, indir, entry_paths,
339 do_compress=True, allow_resize=True, write_map=False):
340 """Replace the data from one or more entries from input files
341
342 Args:
343 image_fname: Image filename to process
344 input_fname: Single input ilename to use if replacing one file, None
345 otherwise
346 indir: Input directory to use (for any number of files), else None
347 entry_paths: List of entry paths to extract
348 do_compress: True if the input data is uncompressed and may need to be
349 compressed if the entry requires it, False if the data is already
350 compressed.
351 write_map: True to write a map file
352
353 Returns:
354 List of EntryInfo records that were written
355 """
356 image = Image.FromFile(image_fname)
357
358 # Replace an entry from a single file, as a special case
359 if input_fname:
360 if not entry_paths:
361 raise ValueError('Must specify an entry path to read with -f')
362 if len(entry_paths) != 1:
363 raise ValueError('Must specify exactly one entry path to write with -f')
364 entry = image.FindEntryPath(entry_paths[0])
365 data = tools.ReadFile(input_fname)
366 tout.Notice("Read %#x bytes from file '%s'" % (len(data), input_fname))
367 WriteEntryToImage(image, entry, data, do_compress=do_compress,
368 allow_resize=allow_resize, write_map=write_map)
369 return
370
371 # Otherwise we will input from a path given by the entry path of each entry.
372 # This means that files must appear in subdirectories if they are part of
373 # a sub-section.
374 einfos = image.GetListEntries(entry_paths)[0]
375 tout.Notice("Replacing %d matching entries in image '%s'" %
376 (len(einfos), image_fname))
377
378 BeforeReplace(image, allow_resize)
379
380 for einfo in einfos:
381 entry = einfo.entry
382 if entry.GetEntries():
383 tout.Info("Skipping section entry '%s'" % entry.GetPath())
384 continue
385
386 path = entry.GetPath()[1:]
387 fname = os.path.join(indir, path)
388
389 if os.path.exists(fname):
390 tout.Notice("Write entry '%s' from file '%s'" %
391 (entry.GetPath(), fname))
392 data = tools.ReadFile(fname)
393 ReplaceOneEntry(image, entry, data, do_compress, allow_resize)
394 else:
395 tout.Warning("Skipping entry '%s' from missing file '%s'" %
396 (entry.GetPath(), fname))
397
398 AfterReplace(image, allow_resize=allow_resize, write_map=write_map)
399 return image
400
401
Simon Glassa8573c42019-07-20 12:23:27 -0600402def PrepareImagesAndDtbs(dtb_fname, select_images, update_fdt):
403 """Prepare the images to be processed and select the device tree
404
405 This function:
406 - reads in the device tree
407 - finds and scans the binman node to create all entries
408 - selects which images to build
409 - Updates the device tress with placeholder properties for offset,
410 image-pos, etc.
411
412 Args:
413 dtb_fname: Filename of the device tree file to use (.dts or .dtb)
414 selected_images: List of images to output, or None for all
415 update_fdt: True to update the FDT wth entry offsets, etc.
Simon Glasse9d336d2020-09-01 05:13:55 -0600416
417 Returns:
418 OrderedDict of images:
419 key: Image name (str)
420 value: Image object
Simon Glassa8573c42019-07-20 12:23:27 -0600421 """
422 # Import these here in case libfdt.py is not available, in which case
423 # the above help option still works.
Simon Glass16287932020-04-17 18:09:03 -0600424 from dtoc import fdt
425 from dtoc import fdt_util
Simon Glassa8573c42019-07-20 12:23:27 -0600426 global images
427
428 # Get the device tree ready by compiling it and copying the compiled
429 # output into a file in our output directly. Then scan it for use
430 # in binman.
431 dtb_fname = fdt_util.EnsureCompiled(dtb_fname)
432 fname = tools.GetOutputFilename('u-boot.dtb.out')
433 tools.WriteFile(fname, tools.ReadFile(dtb_fname))
434 dtb = fdt.FdtScan(fname)
435
436 node = _FindBinmanNode(dtb)
437 if not node:
438 raise ValueError("Device tree '%s' does not have a 'binman' "
439 "node" % dtb_fname)
440
441 images = _ReadImageDesc(node)
442
443 if select_images:
444 skip = []
445 new_images = OrderedDict()
446 for name, image in images.items():
447 if name in select_images:
448 new_images[name] = image
449 else:
450 skip.append(name)
451 images = new_images
452 tout.Notice('Skipping images: %s' % ', '.join(skip))
453
454 state.Prepare(images, dtb)
455
456 # Prepare the device tree by making sure that any missing
457 # properties are added (e.g. 'pos' and 'size'). The values of these
458 # may not be correct yet, but we add placeholders so that the
459 # size of the device tree is correct. Later, in
460 # SetCalculatedProperties() we will insert the correct values
461 # without changing the device-tree size, thus ensuring that our
462 # entry offsets remain the same.
463 for image in images.values():
464 image.ExpandEntries()
465 if update_fdt:
Simon Glassa9fad072020-10-26 17:40:17 -0600466 image.AddMissingProperties(True)
Simon Glassa8573c42019-07-20 12:23:27 -0600467 image.ProcessFdt(dtb)
468
Simon Glass4bdd1152019-07-20 12:23:29 -0600469 for dtb_item in state.GetAllFdts():
Simon Glassa8573c42019-07-20 12:23:27 -0600470 dtb_item.Sync(auto_resize=True)
471 dtb_item.Pack()
472 dtb_item.Flush()
473 return images
474
475
Simon Glass51014aa2019-07-20 12:23:56 -0600476def ProcessImage(image, update_fdt, write_map, get_contents=True,
Simon Glass4f9f1052020-07-09 18:39:38 -0600477 allow_resize=True, allow_missing=False):
Simon Glassb88e81c2019-07-20 12:23:24 -0600478 """Perform all steps for this image, including checking and # writing it.
479
480 This means that errors found with a later image will be reported after
481 earlier images are already completed and written, but that does not seem
482 important.
483
484 Args:
485 image: Image to process
486 update_fdt: True to update the FDT wth entry offsets, etc.
487 write_map: True to write a map file
Simon Glass10f9d002019-07-20 12:23:50 -0600488 get_contents: True to get the image contents from files, etc., False if
489 the contents is already present
Simon Glass51014aa2019-07-20 12:23:56 -0600490 allow_resize: True to allow entries to change size (this does a re-pack
491 of the entries), False to raise an exception
Simon Glass4f9f1052020-07-09 18:39:38 -0600492 allow_missing: Allow blob_ext objects to be missing
Simon Glassb1cca952020-07-09 18:39:40 -0600493
494 Returns:
495 True if one or more external blobs are missing, False if all are present
Simon Glassb88e81c2019-07-20 12:23:24 -0600496 """
Simon Glass10f9d002019-07-20 12:23:50 -0600497 if get_contents:
Simon Glass4f9f1052020-07-09 18:39:38 -0600498 image.SetAllowMissing(allow_missing)
Simon Glass10f9d002019-07-20 12:23:50 -0600499 image.GetEntryContents()
Simon Glassb88e81c2019-07-20 12:23:24 -0600500 image.GetEntryOffsets()
501
502 # We need to pack the entries to figure out where everything
503 # should be placed. This sets the offset/size of each entry.
504 # However, after packing we call ProcessEntryContents() which
505 # may result in an entry changing size. In that case we need to
506 # do another pass. Since the device tree often contains the
507 # final offset/size information we try to make space for this in
508 # AddMissingProperties() above. However, if the device is
509 # compressed we cannot know this compressed size in advance,
510 # since changing an offset from 0x100 to 0x104 (for example) can
511 # alter the compressed size of the device tree. So we need a
512 # third pass for this.
Simon Glasseb0f4a42019-07-20 12:24:06 -0600513 passes = 5
Simon Glassb88e81c2019-07-20 12:23:24 -0600514 for pack_pass in range(passes):
515 try:
516 image.PackEntries()
Simon Glassb88e81c2019-07-20 12:23:24 -0600517 except Exception as e:
518 if write_map:
519 fname = image.WriteMap()
520 print("Wrote map file '%s' to show errors" % fname)
521 raise
522 image.SetImagePos()
523 if update_fdt:
524 image.SetCalculatedProperties()
Simon Glass4bdd1152019-07-20 12:23:29 -0600525 for dtb_item in state.GetAllFdts():
Simon Glassb88e81c2019-07-20 12:23:24 -0600526 dtb_item.Sync()
Simon Glass51014aa2019-07-20 12:23:56 -0600527 dtb_item.Flush()
Simon Glass261cbe02019-08-24 07:23:12 -0600528 image.WriteSymbols()
Simon Glassb88e81c2019-07-20 12:23:24 -0600529 sizes_ok = image.ProcessEntryContents()
530 if sizes_ok:
531 break
532 image.ResetForPack()
Simon Glassaed6c0b2019-08-24 07:23:13 -0600533 tout.Info('Pack completed after %d pass(es)' % (pack_pass + 1))
Simon Glassb88e81c2019-07-20 12:23:24 -0600534 if not sizes_ok:
Simon Glass61ec04f2019-07-20 12:23:58 -0600535 image.Raise('Entries changed size after packing (tried %s passes)' %
Simon Glassb88e81c2019-07-20 12:23:24 -0600536 passes)
537
Simon Glassb88e81c2019-07-20 12:23:24 -0600538 image.BuildImage()
539 if write_map:
540 image.WriteMap()
Simon Glassb1cca952020-07-09 18:39:40 -0600541 missing_list = []
542 image.CheckMissing(missing_list)
543 if missing_list:
544 tout.Warning("Image '%s' is missing external blobs and is non-functional: %s" %
545 (image.name, ' '.join([e.name for e in missing_list])))
Simon Glassb2381432020-09-06 10:39:09 -0600546 _ShowHelpForMissingBlobs(missing_list)
Simon Glassb1cca952020-07-09 18:39:40 -0600547 return bool(missing_list)
Simon Glassb88e81c2019-07-20 12:23:24 -0600548
549
Simon Glass53cd5d92019-07-08 14:25:29 -0600550def Binman(args):
Simon Glassbf7fd502016-11-25 20:15:51 -0700551 """The main control code for binman
552
553 This assumes that help and test options have already been dealt with. It
554 deals with the core task of building images.
555
556 Args:
Simon Glass53cd5d92019-07-08 14:25:29 -0600557 args: Command line arguments Namespace object
Simon Glassbf7fd502016-11-25 20:15:51 -0700558 """
Simon Glass8dbb7442019-08-24 07:22:44 -0600559 global Image
560 global state
561
Simon Glass53cd5d92019-07-08 14:25:29 -0600562 if args.full_help:
Simon Glassbf7fd502016-11-25 20:15:51 -0700563 pager = os.getenv('PAGER')
564 if not pager:
565 pager = 'more'
566 fname = os.path.join(os.path.dirname(os.path.realpath(sys.argv[0])),
567 'README')
568 command.Run(pager, fname)
569 return 0
570
Simon Glass8dbb7442019-08-24 07:22:44 -0600571 # Put these here so that we can import this module without libfdt
Simon Glass07237982020-08-05 13:27:47 -0600572 from binman.image import Image
Simon Glass16287932020-04-17 18:09:03 -0600573 from binman import state
Simon Glass8dbb7442019-08-24 07:22:44 -0600574
Simon Glass7bc4f0f2019-09-15 18:10:36 -0600575 if args.cmd in ['ls', 'extract', 'replace']:
Simon Glass96b6c502019-07-20 12:23:53 -0600576 try:
Simon Glass7bc4f0f2019-09-15 18:10:36 -0600577 tout.Init(args.verbosity)
Simon Glass96b6c502019-07-20 12:23:53 -0600578 tools.PrepareOutputDir(None)
Simon Glass7bc4f0f2019-09-15 18:10:36 -0600579 if args.cmd == 'ls':
580 ListEntries(args.image, args.paths)
Simon Glass61f564d2019-07-08 14:25:48 -0600581
Simon Glass7bc4f0f2019-09-15 18:10:36 -0600582 if args.cmd == 'extract':
583 ExtractEntries(args.image, args.filename, args.outdir, args.paths,
584 not args.uncompressed)
Simon Glass71ce0ba2019-07-08 14:25:52 -0600585
Simon Glass7bc4f0f2019-09-15 18:10:36 -0600586 if args.cmd == 'replace':
587 ReplaceEntries(args.image, args.filename, args.indir, args.paths,
588 do_compress=not args.compressed,
589 allow_resize=not args.fix_size, write_map=args.map)
590 except:
591 raise
Simon Glassa6cb9952019-07-20 12:24:15 -0600592 finally:
593 tools.FinaliseOutputDir()
594 return 0
595
Simon Glassbf7fd502016-11-25 20:15:51 -0700596 # Try to figure out which device tree contains our image description
Simon Glass53cd5d92019-07-08 14:25:29 -0600597 if args.dt:
598 dtb_fname = args.dt
Simon Glassbf7fd502016-11-25 20:15:51 -0700599 else:
Simon Glass53cd5d92019-07-08 14:25:29 -0600600 board = args.board
Simon Glassbf7fd502016-11-25 20:15:51 -0700601 if not board:
602 raise ValueError('Must provide a board to process (use -b <board>)')
Simon Glass53cd5d92019-07-08 14:25:29 -0600603 board_pathname = os.path.join(args.build_dir, board)
Simon Glassbf7fd502016-11-25 20:15:51 -0700604 dtb_fname = os.path.join(board_pathname, 'u-boot.dtb')
Simon Glass53cd5d92019-07-08 14:25:29 -0600605 if not args.indir:
606 args.indir = ['.']
607 args.indir.append(board_pathname)
Simon Glassbf7fd502016-11-25 20:15:51 -0700608
609 try:
Simon Glass53cd5d92019-07-08 14:25:29 -0600610 tout.Init(args.verbosity)
611 elf.debug = args.debug
612 cbfs_util.VERBOSE = args.verbosity > 2
613 state.use_fake_dtb = args.fake_dtb
Simon Glassbf7fd502016-11-25 20:15:51 -0700614 try:
Simon Glass53cd5d92019-07-08 14:25:29 -0600615 tools.SetInputDirs(args.indir)
616 tools.PrepareOutputDir(args.outdir, args.preserve)
617 tools.SetToolPaths(args.toolpath)
618 state.SetEntryArgs(args.entry_arg)
Simon Glassecab8972018-07-06 10:27:40 -0600619
Simon Glassa8573c42019-07-20 12:23:27 -0600620 images = PrepareImagesAndDtbs(dtb_fname, args.image,
621 args.update_fdt)
Simon Glassb1cca952020-07-09 18:39:40 -0600622 missing = False
Simon Glassbf7fd502016-11-25 20:15:51 -0700623 for image in images.values():
Simon Glassb1cca952020-07-09 18:39:40 -0600624 missing |= ProcessImage(image, args.update_fdt, args.map,
625 allow_missing=args.allow_missing)
Simon Glass2a72cc72018-09-14 04:57:20 -0600626
627 # Write the updated FDTs to our output files
Simon Glass4bdd1152019-07-20 12:23:29 -0600628 for dtb_item in state.GetAllFdts():
Simon Glass2a72cc72018-09-14 04:57:20 -0600629 tools.WriteFile(dtb_item._fname, dtb_item.GetContents())
630
Simon Glassb1cca952020-07-09 18:39:40 -0600631 if missing:
Simon Glassb2381432020-09-06 10:39:09 -0600632 tout.Warning("\nSome images are invalid")
Simon Glassbf7fd502016-11-25 20:15:51 -0700633 finally:
634 tools.FinaliseOutputDir()
635 finally:
636 tout.Uninit()
637
638 return 0