blob: 3446e2e79c5b278c7d8895f2d6395321bab3d582 [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
9import os
10import sys
11import tools
12
13import command
Simon Glass7fe91732017-11-13 18:55:00 -070014import elf
Simon Glassbf7fd502016-11-25 20:15:51 -070015from image import Image
Simon Glassc55a50f2018-09-14 04:57:19 -060016import state
Simon Glassbf7fd502016-11-25 20:15:51 -070017import tout
18
19# List of images we plan to create
20# Make this global so that it can be referenced from tests
21images = OrderedDict()
22
23def _ReadImageDesc(binman_node):
24 """Read the image descriptions from the /binman node
25
26 This normally produces a single Image object called 'image'. But if
27 multiple images are present, they will all be returned.
28
29 Args:
30 binman_node: Node object of the /binman node
31 Returns:
32 OrderedDict of Image objects, each of which describes an image
33 """
34 images = OrderedDict()
35 if 'multiple-images' in binman_node.props:
36 for node in binman_node.subnodes:
37 images[node.name] = Image(node.name, node)
38 else:
39 images['image'] = Image('image', binman_node)
40 return images
41
Simon Glassec3f3782017-05-27 07:38:29 -060042def _FindBinmanNode(dtb):
Simon Glassbf7fd502016-11-25 20:15:51 -070043 """Find the 'binman' node in the device tree
44
45 Args:
Simon Glassec3f3782017-05-27 07:38:29 -060046 dtb: Fdt object to scan
Simon Glassbf7fd502016-11-25 20:15:51 -070047 Returns:
48 Node object of /binman node, or None if not found
49 """
Simon Glassec3f3782017-05-27 07:38:29 -060050 for node in dtb.GetRoot().subnodes:
Simon Glassbf7fd502016-11-25 20:15:51 -070051 if node.name == 'binman':
52 return node
53 return None
54
Simon Glassc55a50f2018-09-14 04:57:19 -060055def WriteEntryDocs(modules, test_missing=None):
56 """Write out documentation for all entries
Simon Glassecab8972018-07-06 10:27:40 -060057
58 Args:
Simon Glassc55a50f2018-09-14 04:57:19 -060059 modules: List of Module objects to get docs for
60 test_missing: Used for testing only, to force an entry's documeentation
61 to show as missing even if it is present. Should be set to None in
62 normal use.
Simon Glassecab8972018-07-06 10:27:40 -060063 """
Simon Glassfd8d1f72018-07-17 13:25:36 -060064 from entry import Entry
65 Entry.WriteDocs(modules, test_missing)
66
Simon Glassbf7fd502016-11-25 20:15:51 -070067def Binman(options, args):
68 """The main control code for binman
69
70 This assumes that help and test options have already been dealt with. It
71 deals with the core task of building images.
72
73 Args:
74 options: Command line options object
75 args: Command line arguments (list of strings)
76 """
77 global images
78
79 if options.full_help:
80 pager = os.getenv('PAGER')
81 if not pager:
82 pager = 'more'
83 fname = os.path.join(os.path.dirname(os.path.realpath(sys.argv[0])),
84 'README')
85 command.Run(pager, fname)
86 return 0
87
88 # Try to figure out which device tree contains our image description
89 if options.dt:
90 dtb_fname = options.dt
91 else:
92 board = options.board
93 if not board:
94 raise ValueError('Must provide a board to process (use -b <board>)')
95 board_pathname = os.path.join(options.build_dir, board)
96 dtb_fname = os.path.join(board_pathname, 'u-boot.dtb')
97 if not options.indir:
98 options.indir = ['.']
99 options.indir.append(board_pathname)
100
101 try:
Simon Glass9b1a8042018-07-17 13:25:34 -0600102 # Import these here in case libfdt.py is not available, in which case
103 # the above help option still works.
104 import fdt
105 import fdt_util
106
Simon Glassbf7fd502016-11-25 20:15:51 -0700107 tout.Init(options.verbosity)
Simon Glass19790632017-11-13 18:55:01 -0700108 elf.debug = options.debug
Simon Glass93d17412018-09-14 04:57:23 -0600109 state.use_fake_dtb = options.fake_dtb
Simon Glassbf7fd502016-11-25 20:15:51 -0700110 try:
111 tools.SetInputDirs(options.indir)
112 tools.PrepareOutputDir(options.outdir, options.preserve)
Simon Glassc55a50f2018-09-14 04:57:19 -0600113 state.SetEntryArgs(options.entry_arg)
Simon Glassecab8972018-07-06 10:27:40 -0600114
115 # Get the device tree ready by compiling it and copying the compiled
116 # output into a file in our output directly. Then scan it for use
117 # in binman.
118 dtb_fname = fdt_util.EnsureCompiled(dtb_fname)
Simon Glass6ed45ba2018-09-14 04:57:24 -0600119 fname = tools.GetOutputFilename('u-boot.dtb.out')
120 tools.WriteFile(fname, tools.ReadFile(dtb_fname))
Simon Glassecab8972018-07-06 10:27:40 -0600121 dtb = fdt.FdtScan(fname)
122
Simon Glassec3f3782017-05-27 07:38:29 -0600123 node = _FindBinmanNode(dtb)
Simon Glassbf7fd502016-11-25 20:15:51 -0700124 if not node:
125 raise ValueError("Device tree '%s' does not have a 'binman' "
126 "node" % dtb_fname)
Simon Glassecab8972018-07-06 10:27:40 -0600127
Simon Glassbf7fd502016-11-25 20:15:51 -0700128 images = _ReadImageDesc(node)
Simon Glassecab8972018-07-06 10:27:40 -0600129
Simon Glass0bfa7b02018-09-14 04:57:12 -0600130 if options.image:
131 skip = []
132 for name, image in images.iteritems():
133 if name not in options.image:
134 del images[name]
135 skip.append(name)
136 if skip:
137 print 'Skipping images: %s\n' % ', '.join(skip)
138
Simon Glass539aece2018-09-14 04:57:22 -0600139 state.Prepare(images, dtb)
Simon Glass2a72cc72018-09-14 04:57:20 -0600140
Simon Glassecab8972018-07-06 10:27:40 -0600141 # Prepare the device tree by making sure that any missing
142 # properties are added (e.g. 'pos' and 'size'). The values of these
143 # may not be correct yet, but we add placeholders so that the
144 # size of the device tree is correct. Later, in
145 # SetCalculatedProperties() we will insert the correct values
146 # without changing the device-tree size, thus ensuring that our
Simon Glass3ab95982018-08-01 15:22:37 -0600147 # entry offsets remain the same.
Simon Glassecab8972018-07-06 10:27:40 -0600148 for image in images.values():
Simon Glass0a98b282018-09-14 04:57:28 -0600149 image.ExpandEntries()
Simon Glass078ab1a2018-07-06 10:27:41 -0600150 if options.update_fdt:
151 image.AddMissingProperties()
Simon Glassecab8972018-07-06 10:27:40 -0600152 image.ProcessFdt(dtb)
153
Simon Glass2a72cc72018-09-14 04:57:20 -0600154 for dtb_item in state.GetFdts():
155 dtb_item.Sync(auto_resize=True)
156 dtb_item.Pack()
157 dtb_item.Flush()
Simon Glassecab8972018-07-06 10:27:40 -0600158
Simon Glassbf7fd502016-11-25 20:15:51 -0700159 for image in images.values():
160 # Perform all steps for this image, including checking and
161 # writing it. This means that errors found with a later
162 # image will be reported after earlier images are already
163 # completed and written, but that does not seem important.
164 image.GetEntryContents()
Simon Glass3ab95982018-08-01 15:22:37 -0600165 image.GetEntryOffsets()
Simon Glass163ed6c2018-09-14 04:57:36 -0600166 try:
167 image.PackEntries()
168 image.CheckSize()
169 image.CheckEntries()
170 except Exception as e:
171 if options.map:
172 fname = image.WriteMap()
173 print "Wrote map file '%s' to show errors" % fname
174 raise
Simon Glassdbf6be92018-08-01 15:22:42 -0600175 image.SetImagePos()
Simon Glass078ab1a2018-07-06 10:27:41 -0600176 if options.update_fdt:
177 image.SetCalculatedProperties()
Simon Glass2a72cc72018-09-14 04:57:20 -0600178 for dtb_item in state.GetFdts():
179 dtb_item.Sync()
Simon Glassbf7fd502016-11-25 20:15:51 -0700180 image.ProcessEntryContents()
Simon Glass19790632017-11-13 18:55:01 -0700181 image.WriteSymbols()
Simon Glassbf7fd502016-11-25 20:15:51 -0700182 image.BuildImage()
Simon Glass3b0c3822018-06-01 09:38:20 -0600183 if options.map:
184 image.WriteMap()
Simon Glass2a72cc72018-09-14 04:57:20 -0600185
186 # Write the updated FDTs to our output files
187 for dtb_item in state.GetFdts():
188 tools.WriteFile(dtb_item._fname, dtb_item.GetContents())
189
Simon Glassbf7fd502016-11-25 20:15:51 -0700190 finally:
191 tools.FinaliseOutputDir()
192 finally:
193 tout.Uninit()
194
195 return 0