]> git.ipfire.org Git - thirdparty/u-boot.git/blob - tools/binman/control.py
35faf1150629e3c0bfb87969b60702937181990f
[thirdparty/u-boot.git] / tools / binman / control.py
1 # SPDX-License-Identifier: GPL-2.0+
2 # Copyright (c) 2016 Google, Inc
3 # Written by Simon Glass <sjg@chromium.org>
4 #
5 # Creates binary images from input files controlled by a description
6 #
7
8 from __future__ import print_function
9
10 from collections import OrderedDict
11 import os
12 import sys
13 import tools
14
15 import cbfs_util
16 import command
17 import elf
18 from image import Image
19 import state
20 import tout
21
22 # List of images we plan to create
23 # Make this global so that it can be referenced from tests
24 images = OrderedDict()
25
26 def _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
45 def _FindBinmanNode(dtb):
46 """Find the 'binman' node in the device tree
47
48 Args:
49 dtb: Fdt object to scan
50 Returns:
51 Node object of /binman node, or None if not found
52 """
53 for node in dtb.GetRoot().subnodes:
54 if node.name == 'binman':
55 return node
56 return None
57
58 def WriteEntryDocs(modules, test_missing=None):
59 """Write out documentation for all entries
60
61 Args:
62 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.
66 """
67 from entry import Entry
68 Entry.WriteDocs(modules, test_missing)
69
70 def Binman(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 args: Command line arguments Namespace object
78 """
79 global images
80
81 if args.full_help:
82 pager = os.getenv('PAGER')
83 if not pager:
84 pager = 'more'
85 fname = os.path.join(os.path.dirname(os.path.realpath(sys.argv[0])),
86 'README')
87 command.Run(pager, fname)
88 return 0
89
90 # Try to figure out which device tree contains our image description
91 if args.dt:
92 dtb_fname = args.dt
93 else:
94 board = args.board
95 if not board:
96 raise ValueError('Must provide a board to process (use -b <board>)')
97 board_pathname = os.path.join(args.build_dir, board)
98 dtb_fname = os.path.join(board_pathname, 'u-boot.dtb')
99 if not args.indir:
100 args.indir = ['.']
101 args.indir.append(board_pathname)
102
103 try:
104 # Import these here in case libfdt.py is not available, in which case
105 # the above help option still works.
106 import fdt
107 import fdt_util
108
109 tout.Init(args.verbosity)
110 elf.debug = args.debug
111 cbfs_util.VERBOSE = args.verbosity > 2
112 state.use_fake_dtb = args.fake_dtb
113 try:
114 tools.SetInputDirs(args.indir)
115 tools.PrepareOutputDir(args.outdir, args.preserve)
116 tools.SetToolPaths(args.toolpath)
117 state.SetEntryArgs(args.entry_arg)
118
119 # Get the device tree ready by compiling it and copying the compiled
120 # output into a file in our output directly. Then scan it for use
121 # in binman.
122 dtb_fname = fdt_util.EnsureCompiled(dtb_fname)
123 fname = tools.GetOutputFilename('u-boot.dtb.out')
124 tools.WriteFile(fname, tools.ReadFile(dtb_fname))
125 dtb = fdt.FdtScan(fname)
126
127 node = _FindBinmanNode(dtb)
128 if not node:
129 raise ValueError("Device tree '%s' does not have a 'binman' "
130 "node" % dtb_fname)
131
132 images = _ReadImageDesc(node)
133
134 if args.image:
135 skip = []
136 new_images = OrderedDict()
137 for name, image in images.items():
138 if name in args.image:
139 new_images[name] = image
140 else:
141 skip.append(name)
142 images = new_images
143 if skip and args.verbosity >= 2:
144 print('Skipping images: %s' % ', '.join(skip))
145
146 state.Prepare(images, dtb)
147
148 # Prepare the device tree by making sure that any missing
149 # properties are added (e.g. 'pos' and 'size'). The values of these
150 # may not be correct yet, but we add placeholders so that the
151 # size of the device tree is correct. Later, in
152 # SetCalculatedProperties() we will insert the correct values
153 # without changing the device-tree size, thus ensuring that our
154 # entry offsets remain the same.
155 for image in images.values():
156 image.ExpandEntries()
157 if args.update_fdt:
158 image.AddMissingProperties()
159 image.ProcessFdt(dtb)
160
161 for dtb_item in state.GetFdts():
162 dtb_item.Sync(auto_resize=True)
163 dtb_item.Pack()
164 dtb_item.Flush()
165
166 for image in images.values():
167 # Perform all steps for this image, including checking and
168 # writing it. This means that errors found with a later
169 # image will be reported after earlier images are already
170 # completed and written, but that does not seem important.
171 image.GetEntryContents()
172 image.GetEntryOffsets()
173
174 # We need to pack the entries to figure out where everything
175 # should be placed. This sets the offset/size of each entry.
176 # However, after packing we call ProcessEntryContents() which
177 # may result in an entry changing size. In that case we need to
178 # do another pass. Since the device tree often contains the
179 # final offset/size information we try to make space for this in
180 # AddMissingProperties() above. However, if the device is
181 # compressed we cannot know this compressed size in advance,
182 # since changing an offset from 0x100 to 0x104 (for example) can
183 # alter the compressed size of the device tree. So we need a
184 # third pass for this.
185 passes = 3
186 for pack_pass in range(passes):
187 try:
188 image.PackEntries()
189 image.CheckSize()
190 image.CheckEntries()
191 except Exception as e:
192 if args.map:
193 fname = image.WriteMap()
194 print("Wrote map file '%s' to show errors" % fname)
195 raise
196 image.SetImagePos()
197 if args.update_fdt:
198 image.SetCalculatedProperties()
199 for dtb_item in state.GetFdts():
200 dtb_item.Sync()
201 sizes_ok = image.ProcessEntryContents()
202 if sizes_ok:
203 break
204 image.ResetForPack()
205 if not sizes_ok:
206 image.Raise('Entries expanded after packing (tried %s passes)' %
207 passes)
208
209 image.WriteSymbols()
210 image.BuildImage()
211 if args.map:
212 image.WriteMap()
213
214 # Write the updated FDTs to our output files
215 for dtb_item in state.GetFdts():
216 tools.WriteFile(dtb_item._fname, dtb_item.GetContents())
217
218 finally:
219 tools.FinaliseOutputDir()
220 finally:
221 tout.Uninit()
222
223 return 0