blob: a40b300fdacba2f105942aa1c7ff93b3d3012ee4 [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 Glass99ed4a22017-05-27 07:38:30 -060015import fdt
Simon Glassbf7fd502016-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 Glassecab8972018-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 Glassbf7fd502016-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 Glassec3f3782017-05-27 07:38:29 -060048def _FindBinmanNode(dtb):
Simon Glassbf7fd502016-11-25 20:15:51 -070049 """Find the 'binman' node in the device tree
50
51 Args:
Simon Glassec3f3782017-05-27 07:38:29 -060052 dtb: Fdt object to scan
Simon Glassbf7fd502016-11-25 20:15:51 -070053 Returns:
54 Node object of /binman node, or None if not found
55 """
Simon Glassec3f3782017-05-27 07:38:29 -060056 for node in dtb.GetRoot().subnodes:
Simon Glassbf7fd502016-11-25 20:15:51 -070057 if node.name == 'binman':
58 return node
59 return None
60
Simon Glassecab8972018-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 Glassbf7fd502016-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 Glass19790632017-11-13 18:55:01 -0700115 elf.debug = options.debug
Simon Glassbf7fd502016-11-25 20:15:51 -0700116 try:
117 tools.SetInputDirs(options.indir)
118 tools.PrepareOutputDir(options.outdir, options.preserve)
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)
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 Glassec3f3782017-05-27 07:38:29 -0600132 node = _FindBinmanNode(dtb)
Simon Glassbf7fd502016-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 Glassecab8972018-07-06 10:27:40 -0600136
Simon Glassbf7fd502016-11-25 20:15:51 -0700137 images = _ReadImageDesc(node)
Simon Glassecab8972018-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():
Simon Glass078ab1a2018-07-06 10:27:41 -0600147 if options.update_fdt:
148 image.AddMissingProperties()
Simon Glassecab8972018-07-06 10:27:40 -0600149 image.ProcessFdt(dtb)
150
151 dtb.Pack()
152 dtb.Flush()
153
Simon Glassbf7fd502016-11-25 20:15:51 -0700154 for image in images.values():
155 # Perform all steps for this image, including checking and
156 # writing it. This means that errors found with a later
157 # image will be reported after earlier images are already
158 # completed and written, but that does not seem important.
159 image.GetEntryContents()
160 image.GetEntryPositions()
161 image.PackEntries()
162 image.CheckSize()
163 image.CheckEntries()
Simon Glass078ab1a2018-07-06 10:27:41 -0600164 if options.update_fdt:
165 image.SetCalculatedProperties()
Simon Glassbf7fd502016-11-25 20:15:51 -0700166 image.ProcessEntryContents()
Simon Glass19790632017-11-13 18:55:01 -0700167 image.WriteSymbols()
Simon Glassbf7fd502016-11-25 20:15:51 -0700168 image.BuildImage()
Simon Glass3b0c3822018-06-01 09:38:20 -0600169 if options.map:
170 image.WriteMap()
Simon Glass16b8d6b2018-07-06 10:27:42 -0600171 with open(fname, 'wb') as outfd:
172 outfd.write(dtb.GetContents())
Simon Glassbf7fd502016-11-25 20:15:51 -0700173 finally:
174 tools.FinaliseOutputDir()
175 finally:
176 tout.Uninit()
177
178 return 0