xref: /openbmc/u-boot/tools/binman/control.py (revision d24c1d0f4da3b081a4fedf7ae2a08790871f08d0)
183d290c5STom Rini# SPDX-License-Identifier: GPL-2.0+
2bf7fd50bSSimon Glass# Copyright (c) 2016 Google, Inc
3bf7fd50bSSimon Glass# Written by Simon Glass <sjg@chromium.org>
4bf7fd50bSSimon Glass#
5bf7fd50bSSimon Glass# Creates binary images from input files controlled by a description
6bf7fd50bSSimon Glass#
7bf7fd50bSSimon Glass
8bf7fd50bSSimon Glassfrom collections import OrderedDict
9bf7fd50bSSimon Glassimport os
10bf7fd50bSSimon Glassimport sys
11bf7fd50bSSimon Glassimport tools
12bf7fd50bSSimon Glass
13bf7fd50bSSimon Glassimport command
147fe9173bSSimon Glassimport elf
15bf7fd50bSSimon Glassfrom image import Image
16c55a50f5SSimon Glassimport state
17bf7fd50bSSimon Glassimport tout
18bf7fd50bSSimon Glass
19bf7fd50bSSimon Glass# List of images we plan to create
20bf7fd50bSSimon Glass# Make this global so that it can be referenced from tests
21bf7fd50bSSimon Glassimages = OrderedDict()
22bf7fd50bSSimon Glass
23bf7fd50bSSimon Glassdef _ReadImageDesc(binman_node):
24bf7fd50bSSimon Glass    """Read the image descriptions from the /binman node
25bf7fd50bSSimon Glass
26bf7fd50bSSimon Glass    This normally produces a single Image object called 'image'. But if
27bf7fd50bSSimon Glass    multiple images are present, they will all be returned.
28bf7fd50bSSimon Glass
29bf7fd50bSSimon Glass    Args:
30bf7fd50bSSimon Glass        binman_node: Node object of the /binman node
31bf7fd50bSSimon Glass    Returns:
32bf7fd50bSSimon Glass        OrderedDict of Image objects, each of which describes an image
33bf7fd50bSSimon Glass    """
34bf7fd50bSSimon Glass    images = OrderedDict()
35bf7fd50bSSimon Glass    if 'multiple-images' in binman_node.props:
36bf7fd50bSSimon Glass        for node in binman_node.subnodes:
37bf7fd50bSSimon Glass            images[node.name] = Image(node.name, node)
38bf7fd50bSSimon Glass    else:
39bf7fd50bSSimon Glass        images['image'] = Image('image', binman_node)
40bf7fd50bSSimon Glass    return images
41bf7fd50bSSimon Glass
42ec3f378aSSimon Glassdef _FindBinmanNode(dtb):
43bf7fd50bSSimon Glass    """Find the 'binman' node in the device tree
44bf7fd50bSSimon Glass
45bf7fd50bSSimon Glass    Args:
46ec3f378aSSimon Glass        dtb: Fdt object to scan
47bf7fd50bSSimon Glass    Returns:
48bf7fd50bSSimon Glass        Node object of /binman node, or None if not found
49bf7fd50bSSimon Glass    """
50ec3f378aSSimon Glass    for node in dtb.GetRoot().subnodes:
51bf7fd50bSSimon Glass        if node.name == 'binman':
52bf7fd50bSSimon Glass            return node
53bf7fd50bSSimon Glass    return None
54bf7fd50bSSimon Glass
55c55a50f5SSimon Glassdef WriteEntryDocs(modules, test_missing=None):
56c55a50f5SSimon Glass    """Write out documentation for all entries
57ecab8973SSimon Glass
58ecab8973SSimon Glass    Args:
59c55a50f5SSimon Glass        modules: List of Module objects to get docs for
60c55a50f5SSimon Glass        test_missing: Used for testing only, to force an entry's documeentation
61c55a50f5SSimon Glass            to show as missing even if it is present. Should be set to None in
62c55a50f5SSimon Glass            normal use.
63ecab8973SSimon Glass    """
64fd8d1f79SSimon Glass    from entry import Entry
65fd8d1f79SSimon Glass    Entry.WriteDocs(modules, test_missing)
66fd8d1f79SSimon Glass
67bf7fd50bSSimon Glassdef Binman(options, args):
68bf7fd50bSSimon Glass    """The main control code for binman
69bf7fd50bSSimon Glass
70bf7fd50bSSimon Glass    This assumes that help and test options have already been dealt with. It
71bf7fd50bSSimon Glass    deals with the core task of building images.
72bf7fd50bSSimon Glass
73bf7fd50bSSimon Glass    Args:
74bf7fd50bSSimon Glass        options: Command line options object
75bf7fd50bSSimon Glass        args: Command line arguments (list of strings)
76bf7fd50bSSimon Glass    """
77bf7fd50bSSimon Glass    global images
78bf7fd50bSSimon Glass
79bf7fd50bSSimon Glass    if options.full_help:
80bf7fd50bSSimon Glass        pager = os.getenv('PAGER')
81bf7fd50bSSimon Glass        if not pager:
82bf7fd50bSSimon Glass            pager = 'more'
83bf7fd50bSSimon Glass        fname = os.path.join(os.path.dirname(os.path.realpath(sys.argv[0])),
84bf7fd50bSSimon Glass                            'README')
85bf7fd50bSSimon Glass        command.Run(pager, fname)
86bf7fd50bSSimon Glass        return 0
87bf7fd50bSSimon Glass
88bf7fd50bSSimon Glass    # Try to figure out which device tree contains our image description
89bf7fd50bSSimon Glass    if options.dt:
90bf7fd50bSSimon Glass        dtb_fname = options.dt
91bf7fd50bSSimon Glass    else:
92bf7fd50bSSimon Glass        board = options.board
93bf7fd50bSSimon Glass        if not board:
94bf7fd50bSSimon Glass            raise ValueError('Must provide a board to process (use -b <board>)')
95bf7fd50bSSimon Glass        board_pathname = os.path.join(options.build_dir, board)
96bf7fd50bSSimon Glass        dtb_fname = os.path.join(board_pathname, 'u-boot.dtb')
97bf7fd50bSSimon Glass        if not options.indir:
98bf7fd50bSSimon Glass            options.indir = ['.']
99bf7fd50bSSimon Glass        options.indir.append(board_pathname)
100bf7fd50bSSimon Glass
101bf7fd50bSSimon Glass    try:
1029b1a804dSSimon Glass        # Import these here in case libfdt.py is not available, in which case
1039b1a804dSSimon Glass        # the above help option still works.
1049b1a804dSSimon Glass        import fdt
1059b1a804dSSimon Glass        import fdt_util
1069b1a804dSSimon Glass
107bf7fd50bSSimon Glass        tout.Init(options.verbosity)
10819790632SSimon Glass        elf.debug = options.debug
10993d17413SSimon Glass        state.use_fake_dtb = options.fake_dtb
110bf7fd50bSSimon Glass        try:
111bf7fd50bSSimon Glass            tools.SetInputDirs(options.indir)
112bf7fd50bSSimon Glass            tools.PrepareOutputDir(options.outdir, options.preserve)
113c55a50f5SSimon Glass            state.SetEntryArgs(options.entry_arg)
114ecab8973SSimon Glass
115ecab8973SSimon Glass            # Get the device tree ready by compiling it and copying the compiled
116ecab8973SSimon Glass            # output into a file in our output directly. Then scan it for use
117ecab8973SSimon Glass            # in binman.
118ecab8973SSimon Glass            dtb_fname = fdt_util.EnsureCompiled(dtb_fname)
1196ed45ba0SSimon Glass            fname = tools.GetOutputFilename('u-boot.dtb.out')
1206ed45ba0SSimon Glass            tools.WriteFile(fname, tools.ReadFile(dtb_fname))
121ecab8973SSimon Glass            dtb = fdt.FdtScan(fname)
122ecab8973SSimon Glass
123ec3f378aSSimon Glass            node = _FindBinmanNode(dtb)
124bf7fd50bSSimon Glass            if not node:
125bf7fd50bSSimon Glass                raise ValueError("Device tree '%s' does not have a 'binman' "
126bf7fd50bSSimon Glass                                 "node" % dtb_fname)
127ecab8973SSimon Glass
128bf7fd50bSSimon Glass            images = _ReadImageDesc(node)
129ecab8973SSimon Glass
1300bfa7b09SSimon Glass            if options.image:
1310bfa7b09SSimon Glass                skip = []
1320bfa7b09SSimon Glass                for name, image in images.iteritems():
1330bfa7b09SSimon Glass                    if name not in options.image:
1340bfa7b09SSimon Glass                        del images[name]
1350bfa7b09SSimon Glass                        skip.append(name)
1360bfa7b09SSimon Glass                if skip:
1370bfa7b09SSimon Glass                    print 'Skipping images: %s\n' % ', '.join(skip)
1380bfa7b09SSimon Glass
139539aece5SSimon Glass            state.Prepare(images, dtb)
1402a72cc72SSimon Glass
141ecab8973SSimon Glass            # Prepare the device tree by making sure that any missing
142ecab8973SSimon Glass            # properties are added (e.g. 'pos' and 'size'). The values of these
143ecab8973SSimon Glass            # may not be correct yet, but we add placeholders so that the
144ecab8973SSimon Glass            # size of the device tree is correct. Later, in
145ecab8973SSimon Glass            # SetCalculatedProperties() we will insert the correct values
146ecab8973SSimon Glass            # without changing the device-tree size, thus ensuring that our
1473ab9598dSSimon Glass            # entry offsets remain the same.
148ecab8973SSimon Glass            for image in images.values():
1490a98b28bSSimon Glass                image.ExpandEntries()
150078ab1a2SSimon Glass                if options.update_fdt:
151078ab1a2SSimon Glass                    image.AddMissingProperties()
152ecab8973SSimon Glass                image.ProcessFdt(dtb)
153ecab8973SSimon Glass
1542a72cc72SSimon Glass            for dtb_item in state.GetFdts():
1552a72cc72SSimon Glass                dtb_item.Sync(auto_resize=True)
1562a72cc72SSimon Glass                dtb_item.Pack()
1572a72cc72SSimon Glass                dtb_item.Flush()
158ecab8973SSimon Glass
159bf7fd50bSSimon Glass            for image in images.values():
160bf7fd50bSSimon Glass                # Perform all steps for this image, including checking and
161bf7fd50bSSimon Glass                # writing it. This means that errors found with a later
162bf7fd50bSSimon Glass                # image will be reported after earlier images are already
163bf7fd50bSSimon Glass                # completed and written, but that does not seem important.
164bf7fd50bSSimon Glass                image.GetEntryContents()
1653ab9598dSSimon Glass                image.GetEntryOffsets()
166*163ed6c3SSimon Glass                try:
167bf7fd50bSSimon Glass                    image.PackEntries()
168bf7fd50bSSimon Glass                    image.CheckSize()
169bf7fd50bSSimon Glass                    image.CheckEntries()
170*163ed6c3SSimon Glass                except Exception as e:
171*163ed6c3SSimon Glass                    if options.map:
172*163ed6c3SSimon Glass                        fname = image.WriteMap()
173*163ed6c3SSimon Glass                        print "Wrote map file '%s' to show errors"  % fname
174*163ed6c3SSimon Glass                    raise
175dbf6be9fSSimon Glass                image.SetImagePos()
176078ab1a2SSimon Glass                if options.update_fdt:
177078ab1a2SSimon Glass                    image.SetCalculatedProperties()
1782a72cc72SSimon Glass                    for dtb_item in state.GetFdts():
1792a72cc72SSimon Glass                        dtb_item.Sync()
180bf7fd50bSSimon Glass                image.ProcessEntryContents()
18119790632SSimon Glass                image.WriteSymbols()
182bf7fd50bSSimon Glass                image.BuildImage()
1833b0c3821SSimon Glass                if options.map:
1843b0c3821SSimon Glass                    image.WriteMap()
1852a72cc72SSimon Glass
1862a72cc72SSimon Glass            # Write the updated FDTs to our output files
1872a72cc72SSimon Glass            for dtb_item in state.GetFdts():
1882a72cc72SSimon Glass                tools.WriteFile(dtb_item._fname, dtb_item.GetContents())
1892a72cc72SSimon Glass
190bf7fd50bSSimon Glass        finally:
191bf7fd50bSSimon Glass            tools.FinaliseOutputDir()
192bf7fd50bSSimon Glass    finally:
193bf7fd50bSSimon Glass        tout.Uninit()
194bf7fd50bSSimon Glass
195bf7fd50bSSimon Glass    return 0
196