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