]> git.ipfire.org Git - thirdparty/u-boot.git/blame - tools/binman/control.py
binman: Support listing an image
[thirdparty/u-boot.git] / tools / binman / control.py
CommitLineData
83d290c5 1# SPDX-License-Identifier: GPL-2.0+
bf7fd50b
SG
2# Copyright (c) 2016 Google, Inc
3# Written by Simon Glass <sjg@chromium.org>
4#
bf7fd50b
SG
5# Creates binary images from input files controlled by a description
6#
7
2ca84680
SG
8from __future__ import print_function
9
bf7fd50b
SG
10from collections import OrderedDict
11import os
12import sys
13import tools
14
ac62fba4 15import cbfs_util
bf7fd50b 16import command
7fe9173b 17import elf
bf7fd50b 18from image import Image
c55a50f5 19import state
bf7fd50b
SG
20import 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
ec3f378a 45def _FindBinmanNode(dtb):
bf7fd50b
SG
46 """Find the 'binman' node in the device tree
47
48 Args:
ec3f378a 49 dtb: Fdt object to scan
bf7fd50b
SG
50 Returns:
51 Node object of /binman node, or None if not found
52 """
ec3f378a 53 for node in dtb.GetRoot().subnodes:
bf7fd50b
SG
54 if node.name == 'binman':
55 return node
56 return None
57
c55a50f5
SG
58def WriteEntryDocs(modules, test_missing=None):
59 """Write out documentation for all entries
ecab8973
SG
60
61 Args:
c55a50f5
SG
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.
ecab8973 66 """
fd8d1f79
SG
67 from entry import Entry
68 Entry.WriteDocs(modules, test_missing)
69
61f564d1
SG
70
71def ListEntries(image_fname, entry_paths):
72 """List the entries in an image
73
74 This decodes the supplied image and displays a table of entries from that
75 image, preceded by a header.
76
77 Args:
78 image_fname: Image filename to process
79 entry_paths: List of wildcarded paths (e.g. ['*dtb*', 'u-boot*',
80 'section/u-boot'])
81 """
82 image = Image.FromFile(image_fname)
83
84 entries, lines, widths = image.GetListEntries(entry_paths)
85
86 num_columns = len(widths)
87 for linenum, line in enumerate(lines):
88 if linenum == 1:
89 # Print header line
90 print('-' * (sum(widths) + num_columns * 2))
91 out = ''
92 for i, item in enumerate(line):
93 width = -widths[i]
94 if item.startswith('>'):
95 width = -width
96 item = item[1:]
97 txt = '%*s ' % (width, item)
98 out += txt
99 print(out.rstrip())
100
53cd5d92 101def Binman(args):
bf7fd50b
SG
102 """The main control code for binman
103
104 This assumes that help and test options have already been dealt with. It
105 deals with the core task of building images.
106
107 Args:
53cd5d92 108 args: Command line arguments Namespace object
bf7fd50b
SG
109 """
110 global images
111
53cd5d92 112 if args.full_help:
bf7fd50b
SG
113 pager = os.getenv('PAGER')
114 if not pager:
115 pager = 'more'
116 fname = os.path.join(os.path.dirname(os.path.realpath(sys.argv[0])),
117 'README')
118 command.Run(pager, fname)
119 return 0
120
61f564d1
SG
121 if args.cmd == 'ls':
122 ListEntries(args.image, args.paths)
123 return 0
124
bf7fd50b 125 # Try to figure out which device tree contains our image description
53cd5d92
SG
126 if args.dt:
127 dtb_fname = args.dt
bf7fd50b 128 else:
53cd5d92 129 board = args.board
bf7fd50b
SG
130 if not board:
131 raise ValueError('Must provide a board to process (use -b <board>)')
53cd5d92 132 board_pathname = os.path.join(args.build_dir, board)
bf7fd50b 133 dtb_fname = os.path.join(board_pathname, 'u-boot.dtb')
53cd5d92
SG
134 if not args.indir:
135 args.indir = ['.']
136 args.indir.append(board_pathname)
bf7fd50b
SG
137
138 try:
9b1a804d
SG
139 # Import these here in case libfdt.py is not available, in which case
140 # the above help option still works.
141 import fdt
142 import fdt_util
143
53cd5d92
SG
144 tout.Init(args.verbosity)
145 elf.debug = args.debug
146 cbfs_util.VERBOSE = args.verbosity > 2
147 state.use_fake_dtb = args.fake_dtb
bf7fd50b 148 try:
53cd5d92
SG
149 tools.SetInputDirs(args.indir)
150 tools.PrepareOutputDir(args.outdir, args.preserve)
151 tools.SetToolPaths(args.toolpath)
152 state.SetEntryArgs(args.entry_arg)
ecab8973
SG
153
154 # Get the device tree ready by compiling it and copying the compiled
155 # output into a file in our output directly. Then scan it for use
156 # in binman.
157 dtb_fname = fdt_util.EnsureCompiled(dtb_fname)
6ed45ba0
SG
158 fname = tools.GetOutputFilename('u-boot.dtb.out')
159 tools.WriteFile(fname, tools.ReadFile(dtb_fname))
ecab8973
SG
160 dtb = fdt.FdtScan(fname)
161
ec3f378a 162 node = _FindBinmanNode(dtb)
bf7fd50b
SG
163 if not node:
164 raise ValueError("Device tree '%s' does not have a 'binman' "
165 "node" % dtb_fname)
ecab8973 166
bf7fd50b 167 images = _ReadImageDesc(node)
ecab8973 168
53cd5d92 169 if args.image:
0bfa7b09 170 skip = []
58632a7f 171 new_images = OrderedDict()
50979154 172 for name, image in images.items():
53cd5d92 173 if name in args.image:
58632a7f
SG
174 new_images[name] = image
175 else:
0bfa7b09 176 skip.append(name)
58632a7f 177 images = new_images
53cd5d92 178 if skip and args.verbosity >= 2:
2ca84680 179 print('Skipping images: %s' % ', '.join(skip))
0bfa7b09 180
539aece5 181 state.Prepare(images, dtb)
2a72cc72 182
ecab8973
SG
183 # Prepare the device tree by making sure that any missing
184 # properties are added (e.g. 'pos' and 'size'). The values of these
185 # may not be correct yet, but we add placeholders so that the
186 # size of the device tree is correct. Later, in
187 # SetCalculatedProperties() we will insert the correct values
188 # without changing the device-tree size, thus ensuring that our
3ab9598d 189 # entry offsets remain the same.
ecab8973 190 for image in images.values():
0a98b28b 191 image.ExpandEntries()
53cd5d92 192 if args.update_fdt:
078ab1a2 193 image.AddMissingProperties()
ecab8973
SG
194 image.ProcessFdt(dtb)
195
2a72cc72
SG
196 for dtb_item in state.GetFdts():
197 dtb_item.Sync(auto_resize=True)
198 dtb_item.Pack()
199 dtb_item.Flush()
ecab8973 200
bf7fd50b
SG
201 for image in images.values():
202 # Perform all steps for this image, including checking and
203 # writing it. This means that errors found with a later
204 # image will be reported after earlier images are already
205 # completed and written, but that does not seem important.
206 image.GetEntryContents()
3ab9598d 207 image.GetEntryOffsets()
c52c9e7d
SG
208
209 # We need to pack the entries to figure out where everything
210 # should be placed. This sets the offset/size of each entry.
211 # However, after packing we call ProcessEntryContents() which
212 # may result in an entry changing size. In that case we need to
213 # do another pass. Since the device tree often contains the
214 # final offset/size information we try to make space for this in
215 # AddMissingProperties() above. However, if the device is
216 # compressed we cannot know this compressed size in advance,
217 # since changing an offset from 0x100 to 0x104 (for example) can
218 # alter the compressed size of the device tree. So we need a
219 # third pass for this.
220 passes = 3
221 for pack_pass in range(passes):
222 try:
223 image.PackEntries()
224 image.CheckSize()
225 image.CheckEntries()
226 except Exception as e:
227 if args.map:
228 fname = image.WriteMap()
229 print("Wrote map file '%s' to show errors" % fname)
230 raise
231 image.SetImagePos()
232 if args.update_fdt:
233 image.SetCalculatedProperties()
234 for dtb_item in state.GetFdts():
235 dtb_item.Sync()
236 sizes_ok = image.ProcessEntryContents()
237 if sizes_ok:
238 break
239 image.ResetForPack()
240 if not sizes_ok:
241 image.Raise('Entries expanded after packing (tried %s passes)' %
242 passes)
243
19790632 244 image.WriteSymbols()
bf7fd50b 245 image.BuildImage()
53cd5d92 246 if args.map:
3b0c3821 247 image.WriteMap()
2a72cc72
SG
248
249 # Write the updated FDTs to our output files
250 for dtb_item in state.GetFdts():
251 tools.WriteFile(dtb_item._fname, dtb_item.GetContents())
252
bf7fd50b
SG
253 finally:
254 tools.FinaliseOutputDir()
255 finally:
256 tout.Uninit()
257
258 return 0