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 8from collections import OrderedDict 9import os 10import sys 11import tools 12 13import command 14import elf 15from image import Image 16import state 17import tout 18 19# List of images we plan to create 20# Make this global so that it can be referenced from tests 21images = OrderedDict() 22 23def _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 42def _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 55def 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 67def 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 state.use_fake_dtb = options.fake_dtb 110 try: 111 tools.SetInputDirs(options.indir) 112 tools.PrepareOutputDir(options.outdir, options.preserve) 113 state.SetEntryArgs(options.entry_arg) 114 115 # Get the device tree ready by compiling it and copying the compiled 116 # output into a file in our output directly. Then scan it for use 117 # in binman. 118 dtb_fname = fdt_util.EnsureCompiled(dtb_fname) 119 fname = tools.GetOutputFilename('u-boot.dtb.out') 120 tools.WriteFile(fname, tools.ReadFile(dtb_fname)) 121 dtb = fdt.FdtScan(fname) 122 123 node = _FindBinmanNode(dtb) 124 if not node: 125 raise ValueError("Device tree '%s' does not have a 'binman' " 126 "node" % dtb_fname) 127 128 images = _ReadImageDesc(node) 129 130 if options.image: 131 skip = [] 132 for name, image in images.iteritems(): 133 if name not in options.image: 134 del images[name] 135 skip.append(name) 136 if skip: 137 print 'Skipping images: %s\n' % ', '.join(skip) 138 139 state.Prepare(images, dtb) 140 141 # Prepare the device tree by making sure that any missing 142 # properties are added (e.g. 'pos' and 'size'). The values of these 143 # may not be correct yet, but we add placeholders so that the 144 # size of the device tree is correct. Later, in 145 # SetCalculatedProperties() we will insert the correct values 146 # without changing the device-tree size, thus ensuring that our 147 # entry offsets remain the same. 148 for image in images.values(): 149 image.ExpandEntries() 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 try: 167 image.PackEntries() 168 image.CheckSize() 169 image.CheckEntries() 170 except Exception as e: 171 if options.map: 172 fname = image.WriteMap() 173 print "Wrote map file '%s' to show errors" % fname 174 raise 175 image.SetImagePos() 176 if options.update_fdt: 177 image.SetCalculatedProperties() 178 for dtb_item in state.GetFdts(): 179 dtb_item.Sync() 180 image.ProcessEntryContents() 181 image.WriteSymbols() 182 image.BuildImage() 183 if options.map: 184 image.WriteMap() 185 186 # Write the updated FDTs to our output files 187 for dtb_item in state.GetFdts(): 188 tools.WriteFile(dtb_item._fname, dtb_item.GetContents()) 189 190 finally: 191 tools.FinaliseOutputDir() 192 finally: 193 tout.Uninit() 194 195 return 0 196