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 15import fdt 16import 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 24# Records the device-tree files known to binman, keyed by filename (e.g. 25# 'u-boot-spl.dtb') 26fdt_files = {} 27 28 29def _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 48def _FindBinmanNode(dtb): 49 """Find the 'binman' node in the device tree 50 51 Args: 52 dtb: Fdt object to scan 53 Returns: 54 Node object of /binman node, or None if not found 55 """ 56 for node in dtb.GetRoot().subnodes: 57 if node.name == 'binman': 58 return node 59 return None 60 61def 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 79def 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) 115 elf.debug = options.debug 116 try: 117 tools.SetInputDirs(options.indir) 118 tools.PrepareOutputDir(options.outdir, options.preserve) 119 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 132 node = _FindBinmanNode(dtb) 133 if not node: 134 raise ValueError("Device tree '%s' does not have a 'binman' " 135 "node" % dtb_fname) 136 137 images = _ReadImageDesc(node) 138 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(): 147 if options.update_fdt: 148 image.AddMissingProperties() 149 image.ProcessFdt(dtb) 150 151 dtb.Pack() 152 dtb.Flush() 153 154 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() 164 if options.update_fdt: 165 image.SetCalculatedProperties() 166 image.ProcessEntryContents() 167 image.WriteSymbols() 168 image.BuildImage() 169 if options.map: 170 image.WriteMap() 171 with open(fname, 'wb') as outfd: 172 outfd.write(dtb.GetContents()) 173 finally: 174 tools.FinaliseOutputDir() 175 finally: 176 tout.Uninit() 177 178 return 0 179