blob: 4a94afc8640745dabd6954497c286b2bc3443ee9 [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
Simon Glass2ca84682019-05-14 15:53:37 -06008from __future__ import print_function
9
Simon Glassbf7fd502016-11-25 20:15:51 -070010from collections import OrderedDict
11import os
12import sys
13import tools
14
Simon Glassac62fba2019-07-08 13:18:53 -060015import cbfs_util
Simon Glassbf7fd502016-11-25 20:15:51 -070016import command
Simon Glass7fe91732017-11-13 18:55:00 -070017import elf
Simon Glassbf7fd502016-11-25 20:15:51 -070018from image import Image
Simon Glassc55a50f2018-09-14 04:57:19 -060019import state
Simon Glassbf7fd502016-11-25 20:15:51 -070020import tout
21
22# List of images we plan to create
23# Make this global so that it can be referenced from tests
24images = OrderedDict()
25
26def _ReadImageDesc(binman_node):
27 """Read the image descriptions from the /binman node
28
29 This normally produces a single Image object called 'image'. But if
30 multiple images are present, they will all be returned.
31
32 Args:
33 binman_node: Node object of the /binman node
34 Returns:
35 OrderedDict of Image objects, each of which describes an image
36 """
37 images = OrderedDict()
38 if 'multiple-images' in binman_node.props:
39 for node in binman_node.subnodes:
40 images[node.name] = Image(node.name, node)
41 else:
42 images['image'] = Image('image', binman_node)
43 return images
44
Simon Glassec3f3782017-05-27 07:38:29 -060045def _FindBinmanNode(dtb):
Simon Glassbf7fd502016-11-25 20:15:51 -070046 """Find the 'binman' node in the device tree
47
48 Args:
Simon Glassec3f3782017-05-27 07:38:29 -060049 dtb: Fdt object to scan
Simon Glassbf7fd502016-11-25 20:15:51 -070050 Returns:
51 Node object of /binman node, or None if not found
52 """
Simon Glassec3f3782017-05-27 07:38:29 -060053 for node in dtb.GetRoot().subnodes:
Simon Glassbf7fd502016-11-25 20:15:51 -070054 if node.name == 'binman':
55 return node
56 return None
57
Simon Glassc55a50f2018-09-14 04:57:19 -060058def WriteEntryDocs(modules, test_missing=None):
59 """Write out documentation for all entries
Simon Glassecab8972018-07-06 10:27:40 -060060
61 Args:
Simon Glassc55a50f2018-09-14 04:57:19 -060062 modules: List of Module objects to get docs for
63 test_missing: Used for testing only, to force an entry's documeentation
64 to show as missing even if it is present. Should be set to None in
65 normal use.
Simon Glassecab8972018-07-06 10:27:40 -060066 """
Simon Glassfd8d1f72018-07-17 13:25:36 -060067 from entry import Entry
68 Entry.WriteDocs(modules, test_missing)
69
Simon Glassbf7fd502016-11-25 20:15:51 -070070def Binman(options, args):
71 """The main control code for binman
72
73 This assumes that help and test options have already been dealt with. It
74 deals with the core task of building images.
75
76 Args:
77 options: Command line options object
78 args: Command line arguments (list of strings)
79 """
80 global images
81
82 if options.full_help:
83 pager = os.getenv('PAGER')
84 if not pager:
85 pager = 'more'
86 fname = os.path.join(os.path.dirname(os.path.realpath(sys.argv[0])),
87 'README')
88 command.Run(pager, fname)
89 return 0
90
91 # Try to figure out which device tree contains our image description
92 if options.dt:
93 dtb_fname = options.dt
94 else:
95 board = options.board
96 if not board:
97 raise ValueError('Must provide a board to process (use -b <board>)')
98 board_pathname = os.path.join(options.build_dir, board)
99 dtb_fname = os.path.join(board_pathname, 'u-boot.dtb')
100 if not options.indir:
101 options.indir = ['.']
102 options.indir.append(board_pathname)
103
104 try:
Simon Glass9b1a8042018-07-17 13:25:34 -0600105 # Import these here in case libfdt.py is not available, in which case
106 # the above help option still works.
107 import fdt
108 import fdt_util
109
Simon Glassbf7fd502016-11-25 20:15:51 -0700110 tout.Init(options.verbosity)
Simon Glass19790632017-11-13 18:55:01 -0700111 elf.debug = options.debug
Simon Glassac62fba2019-07-08 13:18:53 -0600112 cbfs_util.VERBOSE = options.verbosity > 2
Simon Glass93d17412018-09-14 04:57:23 -0600113 state.use_fake_dtb = options.fake_dtb
Simon Glassbf7fd502016-11-25 20:15:51 -0700114 try:
115 tools.SetInputDirs(options.indir)
116 tools.PrepareOutputDir(options.outdir, options.preserve)
Simon Glassc7d80352019-07-08 13:18:28 -0600117 tools.SetToolPaths(options.toolpath)
Simon Glassc55a50f2018-09-14 04:57:19 -0600118 state.SetEntryArgs(options.entry_arg)
Simon Glassecab8972018-07-06 10:27:40 -0600119
120 # Get the device tree ready by compiling it and copying the compiled
121 # output into a file in our output directly. Then scan it for use
122 # in binman.
123 dtb_fname = fdt_util.EnsureCompiled(dtb_fname)
Simon Glass6ed45ba2018-09-14 04:57:24 -0600124 fname = tools.GetOutputFilename('u-boot.dtb.out')
125 tools.WriteFile(fname, tools.ReadFile(dtb_fname))
Simon Glassecab8972018-07-06 10:27:40 -0600126 dtb = fdt.FdtScan(fname)
127
Simon Glassec3f3782017-05-27 07:38:29 -0600128 node = _FindBinmanNode(dtb)
Simon Glassbf7fd502016-11-25 20:15:51 -0700129 if not node:
130 raise ValueError("Device tree '%s' does not have a 'binman' "
131 "node" % dtb_fname)
Simon Glassecab8972018-07-06 10:27:40 -0600132
Simon Glassbf7fd502016-11-25 20:15:51 -0700133 images = _ReadImageDesc(node)
Simon Glassecab8972018-07-06 10:27:40 -0600134
Simon Glass0bfa7b02018-09-14 04:57:12 -0600135 if options.image:
136 skip = []
Simon Glass58632a72019-05-17 22:00:45 -0600137 new_images = OrderedDict()
Simon Glass50979152019-05-14 15:53:41 -0600138 for name, image in images.items():
Simon Glass58632a72019-05-17 22:00:45 -0600139 if name in options.image:
140 new_images[name] = image
141 else:
Simon Glass0bfa7b02018-09-14 04:57:12 -0600142 skip.append(name)
Simon Glass58632a72019-05-17 22:00:45 -0600143 images = new_images
Simon Glasseb833d82019-04-25 21:58:34 -0600144 if skip and options.verbosity >= 2:
Simon Glass2ca84682019-05-14 15:53:37 -0600145 print('Skipping images: %s' % ', '.join(skip))
Simon Glass0bfa7b02018-09-14 04:57:12 -0600146
Simon Glass539aece2018-09-14 04:57:22 -0600147 state.Prepare(images, dtb)
Simon Glass2a72cc72018-09-14 04:57:20 -0600148
Simon Glassecab8972018-07-06 10:27:40 -0600149 # Prepare the device tree by making sure that any missing
150 # properties are added (e.g. 'pos' and 'size'). The values of these
151 # may not be correct yet, but we add placeholders so that the
152 # size of the device tree is correct. Later, in
153 # SetCalculatedProperties() we will insert the correct values
154 # without changing the device-tree size, thus ensuring that our
Simon Glass3ab95982018-08-01 15:22:37 -0600155 # entry offsets remain the same.
Simon Glassecab8972018-07-06 10:27:40 -0600156 for image in images.values():
Simon Glass0a98b282018-09-14 04:57:28 -0600157 image.ExpandEntries()
Simon Glass078ab1a2018-07-06 10:27:41 -0600158 if options.update_fdt:
159 image.AddMissingProperties()
Simon Glassecab8972018-07-06 10:27:40 -0600160 image.ProcessFdt(dtb)
161
Simon Glass2a72cc72018-09-14 04:57:20 -0600162 for dtb_item in state.GetFdts():
163 dtb_item.Sync(auto_resize=True)
164 dtb_item.Pack()
165 dtb_item.Flush()
Simon Glassecab8972018-07-06 10:27:40 -0600166
Simon Glassbf7fd502016-11-25 20:15:51 -0700167 for image in images.values():
168 # Perform all steps for this image, including checking and
169 # writing it. This means that errors found with a later
170 # image will be reported after earlier images are already
171 # completed and written, but that does not seem important.
172 image.GetEntryContents()
Simon Glass3ab95982018-08-01 15:22:37 -0600173 image.GetEntryOffsets()
Simon Glass163ed6c2018-09-14 04:57:36 -0600174 try:
175 image.PackEntries()
176 image.CheckSize()
177 image.CheckEntries()
178 except Exception as e:
179 if options.map:
180 fname = image.WriteMap()
Simon Glass2ca84682019-05-14 15:53:37 -0600181 print("Wrote map file '%s' to show errors" % fname)
Simon Glass163ed6c2018-09-14 04:57:36 -0600182 raise
Simon Glassdbf6be92018-08-01 15:22:42 -0600183 image.SetImagePos()
Simon Glass078ab1a2018-07-06 10:27:41 -0600184 if options.update_fdt:
185 image.SetCalculatedProperties()
Simon Glass2a72cc72018-09-14 04:57:20 -0600186 for dtb_item in state.GetFdts():
187 dtb_item.Sync()
Simon Glassbf7fd502016-11-25 20:15:51 -0700188 image.ProcessEntryContents()
Simon Glass19790632017-11-13 18:55:01 -0700189 image.WriteSymbols()
Simon Glassbf7fd502016-11-25 20:15:51 -0700190 image.BuildImage()
Simon Glass3b0c3822018-06-01 09:38:20 -0600191 if options.map:
192 image.WriteMap()
Simon Glass2a72cc72018-09-14 04:57:20 -0600193
194 # Write the updated FDTs to our output files
195 for dtb_item in state.GetFdts():
196 tools.WriteFile(dtb_item._fname, dtb_item.GetContents())
197
Simon Glassbf7fd502016-11-25 20:15:51 -0700198 finally:
199 tools.FinaliseOutputDir()
200 finally:
201 tout.Uninit()
202
203 return 0