binman: Obtain the list of device trees from the config
[oweals/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 collections import OrderedDict
9 import os
10 import sys
11 import tools
12
13 import command
14 import elf
15 from image import Image
16 import state
17 import tout
18
19 # List of images we plan to create
20 # Make this global so that it can be referenced from tests
21 images = OrderedDict()
22
23 def _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
42 def _FindBinmanNode(dtb):
43     """Find the 'binman' node in the device tree
44
45     Args:
46         dtb: Fdt object to scan
47     Returns:
48         Node object of /binman node, or None if not found
49     """
50     for node in dtb.GetRoot().subnodes:
51         if node.name == 'binman':
52             return node
53     return None
54
55 def WriteEntryDocs(modules, test_missing=None):
56     """Write out documentation for all entries
57
58     Args:
59         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.
63     """
64     from entry import Entry
65     Entry.WriteDocs(modules, test_missing)
66
67 def 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:
102         # 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
107         tout.Init(options.verbosity)
108         elf.debug = options.debug
109         try:
110             tools.SetInputDirs(options.indir)
111             tools.PrepareOutputDir(options.outdir, options.preserve)
112             state.SetEntryArgs(options.entry_arg)
113
114             # Get the device tree ready by compiling it and copying the compiled
115             # output into a file in our output directly. Then scan it for use
116             # in binman.
117             dtb_fname = fdt_util.EnsureCompiled(dtb_fname)
118             fname = tools.GetOutputFilename('u-boot-out.dtb')
119             with open(dtb_fname) as infd:
120                 with open(fname, 'wb') as outfd:
121                     outfd.write(infd.read())
122             dtb = fdt.FdtScan(fname)
123
124             node = _FindBinmanNode(dtb)
125             if not node:
126                 raise ValueError("Device tree '%s' does not have a 'binman' "
127                                  "node" % dtb_fname)
128
129             images = _ReadImageDesc(node)
130
131             if options.image:
132                 skip = []
133                 for name, image in images.iteritems():
134                     if name not in options.image:
135                         del images[name]
136                         skip.append(name)
137                 if skip:
138                     print 'Skipping images: %s\n' % ', '.join(skip)
139
140             state.Prepare(images, dtb)
141
142             # Prepare the device tree by making sure that any missing
143             # properties are added (e.g. 'pos' and 'size'). The values of these
144             # may not be correct yet, but we add placeholders so that the
145             # size of the device tree is correct. Later, in
146             # SetCalculatedProperties() we will insert the correct values
147             # without changing the device-tree size, thus ensuring that our
148             # entry offsets remain the same.
149             for image in images.values():
150                 if options.update_fdt:
151                     image.AddMissingProperties()
152                 image.ProcessFdt(dtb)
153
154             for dtb_item in state.GetFdts():
155                 dtb_item.Sync(auto_resize=True)
156                 dtb_item.Pack()
157                 dtb_item.Flush()
158
159             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()
165                 image.GetEntryOffsets()
166                 image.PackEntries()
167                 image.CheckSize()
168                 image.CheckEntries()
169                 image.SetImagePos()
170                 if options.update_fdt:
171                     image.SetCalculatedProperties()
172                     for dtb_item in state.GetFdts():
173                         dtb_item.Sync()
174                 image.ProcessEntryContents()
175                 image.WriteSymbols()
176                 image.BuildImage()
177                 if options.map:
178                     image.WriteMap()
179
180             # Write the updated FDTs to our output files
181             for dtb_item in state.GetFdts():
182                 tools.WriteFile(dtb_item._fname, dtb_item.GetContents())
183
184         finally:
185             tools.FinaliseOutputDir()
186     finally:
187         tout.Uninit()
188
189     return 0