blob: 5325a6a00669d2c40d159d5770f853f3c5c0ab92 [file] [log] [blame]
Tom Rini10e47792018-05-06 17:58:06 -04001# SPDX-License-Identifier: GPL-2.0+
Simon Glass2574ef62016-11-25 20:15:51 -07002# Copyright (c) 2016 Google, Inc
3# Written by Simon Glass <sjg@chromium.org>
4#
Simon Glass2574ef62016-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 Glass075a45c2017-11-13 18:55:00 -070014import elf
Simon Glassa9440932017-05-27 07:38:30 -060015import fdt
Simon Glass2574ef62016-11-25 20:15:51 -070016import fdt_util
17from image import Image
18import tout
19
20# List of images we plan to create
21# Make this global so that it can be referenced from tests
22images = OrderedDict()
23
Simon Glass92307732018-07-06 10:27:40 -060024# Records the device-tree files known to binman, keyed by filename (e.g.
25# 'u-boot-spl.dtb')
26fdt_files = {}
27
28
Simon Glass2574ef62016-11-25 20:15:51 -070029def _ReadImageDesc(binman_node):
30 """Read the image descriptions from the /binman node
31
32 This normally produces a single Image object called 'image'. But if
33 multiple images are present, they will all be returned.
34
35 Args:
36 binman_node: Node object of the /binman node
37 Returns:
38 OrderedDict of Image objects, each of which describes an image
39 """
40 images = OrderedDict()
41 if 'multiple-images' in binman_node.props:
42 for node in binman_node.subnodes:
43 images[node.name] = Image(node.name, node)
44 else:
45 images['image'] = Image('image', binman_node)
46 return images
47
Simon Glass22c92ca2017-05-27 07:38:29 -060048def _FindBinmanNode(dtb):
Simon Glass2574ef62016-11-25 20:15:51 -070049 """Find the 'binman' node in the device tree
50
51 Args:
Simon Glass22c92ca2017-05-27 07:38:29 -060052 dtb: Fdt object to scan
Simon Glass2574ef62016-11-25 20:15:51 -070053 Returns:
54 Node object of /binman node, or None if not found
55 """
Simon Glass22c92ca2017-05-27 07:38:29 -060056 for node in dtb.GetRoot().subnodes:
Simon Glass2574ef62016-11-25 20:15:51 -070057 if node.name == 'binman':
58 return node
59 return None
60
Simon Glass92307732018-07-06 10:27:40 -060061def GetFdt(fname):
62 """Get the Fdt object for a particular device-tree filename
63
64 Binman keeps track of at least one device-tree file called u-boot.dtb but
65 can also have others (e.g. for SPL). This function looks up the given
66 filename and returns the associated Fdt object.
67
68 Args:
69 fname: Filename to look up (e.g. 'u-boot.dtb').
70
71 Returns:
72 Fdt object associated with the filename
73 """
74 return fdt_files[fname]
75
76def GetFdtPath(fname):
77 return fdt_files[fname]._fname
78
Simon Glass2574ef62016-11-25 20:15:51 -070079def Binman(options, args):
80 """The main control code for binman
81
82 This assumes that help and test options have already been dealt with. It
83 deals with the core task of building images.
84
85 Args:
86 options: Command line options object
87 args: Command line arguments (list of strings)
88 """
89 global images
90
91 if options.full_help:
92 pager = os.getenv('PAGER')
93 if not pager:
94 pager = 'more'
95 fname = os.path.join(os.path.dirname(os.path.realpath(sys.argv[0])),
96 'README')
97 command.Run(pager, fname)
98 return 0
99
100 # Try to figure out which device tree contains our image description
101 if options.dt:
102 dtb_fname = options.dt
103 else:
104 board = options.board
105 if not board:
106 raise ValueError('Must provide a board to process (use -b <board>)')
107 board_pathname = os.path.join(options.build_dir, board)
108 dtb_fname = os.path.join(board_pathname, 'u-boot.dtb')
109 if not options.indir:
110 options.indir = ['.']
111 options.indir.append(board_pathname)
112
113 try:
114 tout.Init(options.verbosity)
Simon Glass4ca8e042017-11-13 18:55:01 -0700115 elf.debug = options.debug
Simon Glass2574ef62016-11-25 20:15:51 -0700116 try:
117 tools.SetInputDirs(options.indir)
118 tools.PrepareOutputDir(options.outdir, options.preserve)
Simon Glass92307732018-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)
124 fname = tools.GetOutputFilename('u-boot-out.dtb')
125 with open(dtb_fname) as infd:
126 with open(fname, 'wb') as outfd:
127 outfd.write(infd.read())
128 dtb = fdt.FdtScan(fname)
129
130 # Note the file so that GetFdt() can find it
131 fdt_files['u-boot.dtb'] = dtb
Simon Glass22c92ca2017-05-27 07:38:29 -0600132 node = _FindBinmanNode(dtb)
Simon Glass2574ef62016-11-25 20:15:51 -0700133 if not node:
134 raise ValueError("Device tree '%s' does not have a 'binman' "
135 "node" % dtb_fname)
Simon Glass92307732018-07-06 10:27:40 -0600136
Simon Glass2574ef62016-11-25 20:15:51 -0700137 images = _ReadImageDesc(node)
Simon Glass92307732018-07-06 10:27:40 -0600138
139 # Prepare the device tree by making sure that any missing
140 # properties are added (e.g. 'pos' and 'size'). The values of these
141 # may not be correct yet, but we add placeholders so that the
142 # size of the device tree is correct. Later, in
143 # SetCalculatedProperties() we will insert the correct values
144 # without changing the device-tree size, thus ensuring that our
145 # entry positions remain the same.
146 for image in images.values():
147 image.ProcessFdt(dtb)
148
149 dtb.Pack()
150 dtb.Flush()
151
Simon Glass2574ef62016-11-25 20:15:51 -0700152 for image in images.values():
153 # Perform all steps for this image, including checking and
154 # writing it. This means that errors found with a later
155 # image will be reported after earlier images are already
156 # completed and written, but that does not seem important.
157 image.GetEntryContents()
158 image.GetEntryPositions()
159 image.PackEntries()
160 image.CheckSize()
161 image.CheckEntries()
162 image.ProcessEntryContents()
Simon Glass4ca8e042017-11-13 18:55:01 -0700163 image.WriteSymbols()
Simon Glass2574ef62016-11-25 20:15:51 -0700164 image.BuildImage()
Simon Glass30732662018-06-01 09:38:20 -0600165 if options.map:
166 image.WriteMap()
Simon Glass2574ef62016-11-25 20:15:51 -0700167 finally:
168 tools.FinaliseOutputDir()
169 finally:
170 tout.Uninit()
171
172 return 0