196 lines
6.6 KiB
Python
196 lines
6.6 KiB
Python
|
# SPDX-License-Identifier: GPL-2.0+
|
||
|
# Copyright (c) 2016 Google, Inc
|
||
|
# Written by Simon Glass <sjg@chromium.org>
|
||
|
#
|
||
|
# Creates binary images from input files controlled by a description
|
||
|
#
|
||
|
|
||
|
from collections import OrderedDict
|
||
|
import os
|
||
|
import sys
|
||
|
import tools
|
||
|
|
||
|
import command
|
||
|
import elf
|
||
|
from image import Image
|
||
|
import state
|
||
|
import tout
|
||
|
|
||
|
# List of images we plan to create
|
||
|
# Make this global so that it can be referenced from tests
|
||
|
images = OrderedDict()
|
||
|
|
||
|
def _ReadImageDesc(binman_node):
|
||
|
"""Read the image descriptions from the /binman node
|
||
|
|
||
|
This normally produces a single Image object called 'image'. But if
|
||
|
multiple images are present, they will all be returned.
|
||
|
|
||
|
Args:
|
||
|
binman_node: Node object of the /binman node
|
||
|
Returns:
|
||
|
OrderedDict of Image objects, each of which describes an image
|
||
|
"""
|
||
|
images = OrderedDict()
|
||
|
if 'multiple-images' in binman_node.props:
|
||
|
for node in binman_node.subnodes:
|
||
|
images[node.name] = Image(node.name, node)
|
||
|
else:
|
||
|
images['image'] = Image('image', binman_node)
|
||
|
return images
|
||
|
|
||
|
def _FindBinmanNode(dtb):
|
||
|
"""Find the 'binman' node in the device tree
|
||
|
|
||
|
Args:
|
||
|
dtb: Fdt object to scan
|
||
|
Returns:
|
||
|
Node object of /binman node, or None if not found
|
||
|
"""
|
||
|
for node in dtb.GetRoot().subnodes:
|
||
|
if node.name == 'binman':
|
||
|
return node
|
||
|
return None
|
||
|
|
||
|
def WriteEntryDocs(modules, test_missing=None):
|
||
|
"""Write out documentation for all entries
|
||
|
|
||
|
Args:
|
||
|
modules: List of Module objects to get docs for
|
||
|
test_missing: Used for testing only, to force an entry's documeentation
|
||
|
to show as missing even if it is present. Should be set to None in
|
||
|
normal use.
|
||
|
"""
|
||
|
from entry import Entry
|
||
|
Entry.WriteDocs(modules, test_missing)
|
||
|
|
||
|
def Binman(options, args):
|
||
|
"""The main control code for binman
|
||
|
|
||
|
This assumes that help and test options have already been dealt with. It
|
||
|
deals with the core task of building images.
|
||
|
|
||
|
Args:
|
||
|
options: Command line options object
|
||
|
args: Command line arguments (list of strings)
|
||
|
"""
|
||
|
global images
|
||
|
|
||
|
if options.full_help:
|
||
|
pager = os.getenv('PAGER')
|
||
|
if not pager:
|
||
|
pager = 'more'
|
||
|
fname = os.path.join(os.path.dirname(os.path.realpath(sys.argv[0])),
|
||
|
'README')
|
||
|
command.Run(pager, fname)
|
||
|
return 0
|
||
|
|
||
|
# Try to figure out which device tree contains our image description
|
||
|
if options.dt:
|
||
|
dtb_fname = options.dt
|
||
|
else:
|
||
|
board = options.board
|
||
|
if not board:
|
||
|
raise ValueError('Must provide a board to process (use -b <board>)')
|
||
|
board_pathname = os.path.join(options.build_dir, board)
|
||
|
dtb_fname = os.path.join(board_pathname, 'u-boot.dtb')
|
||
|
if not options.indir:
|
||
|
options.indir = ['.']
|
||
|
options.indir.append(board_pathname)
|
||
|
|
||
|
try:
|
||
|
# Import these here in case libfdt.py is not available, in which case
|
||
|
# the above help option still works.
|
||
|
import fdt
|
||
|
import fdt_util
|
||
|
|
||
|
tout.Init(options.verbosity)
|
||
|
elf.debug = options.debug
|
||
|
state.use_fake_dtb = options.fake_dtb
|
||
|
try:
|
||
|
tools.SetInputDirs(options.indir)
|
||
|
tools.PrepareOutputDir(options.outdir, options.preserve)
|
||
|
state.SetEntryArgs(options.entry_arg)
|
||
|
|
||
|
# Get the device tree ready by compiling it and copying the compiled
|
||
|
# output into a file in our output directly. Then scan it for use
|
||
|
# in binman.
|
||
|
dtb_fname = fdt_util.EnsureCompiled(dtb_fname)
|
||
|
fname = tools.GetOutputFilename('u-boot.dtb.out')
|
||
|
tools.WriteFile(fname, tools.ReadFile(dtb_fname))
|
||
|
dtb = fdt.FdtScan(fname)
|
||
|
|
||
|
node = _FindBinmanNode(dtb)
|
||
|
if not node:
|
||
|
raise ValueError("Device tree '%s' does not have a 'binman' "
|
||
|
"node" % dtb_fname)
|
||
|
|
||
|
images = _ReadImageDesc(node)
|
||
|
|
||
|
if options.image:
|
||
|
skip = []
|
||
|
for name, image in images.iteritems():
|
||
|
if name not in options.image:
|
||
|
del images[name]
|
||
|
skip.append(name)
|
||
|
if skip:
|
||
|
print 'Skipping images: %s\n' % ', '.join(skip)
|
||
|
|
||
|
state.Prepare(images, dtb)
|
||
|
|
||
|
# Prepare the device tree by making sure that any missing
|
||
|
# properties are added (e.g. 'pos' and 'size'). The values of these
|
||
|
# may not be correct yet, but we add placeholders so that the
|
||
|
# size of the device tree is correct. Later, in
|
||
|
# SetCalculatedProperties() we will insert the correct values
|
||
|
# without changing the device-tree size, thus ensuring that our
|
||
|
# entry offsets remain the same.
|
||
|
for image in images.values():
|
||
|
image.ExpandEntries()
|
||
|
if options.update_fdt:
|
||
|
image.AddMissingProperties()
|
||
|
image.ProcessFdt(dtb)
|
||
|
|
||
|
for dtb_item in state.GetFdts():
|
||
|
dtb_item.Sync(auto_resize=True)
|
||
|
dtb_item.Pack()
|
||
|
dtb_item.Flush()
|
||
|
|
||
|
for image in images.values():
|
||
|
# Perform all steps for this image, including checking and
|
||
|
# writing it. This means that errors found with a later
|
||
|
# image will be reported after earlier images are already
|
||
|
# completed and written, but that does not seem important.
|
||
|
image.GetEntryContents()
|
||
|
image.GetEntryOffsets()
|
||
|
try:
|
||
|
image.PackEntries()
|
||
|
image.CheckSize()
|
||
|
image.CheckEntries()
|
||
|
except Exception as e:
|
||
|
if options.map:
|
||
|
fname = image.WriteMap()
|
||
|
print "Wrote map file '%s' to show errors" % fname
|
||
|
raise
|
||
|
image.SetImagePos()
|
||
|
if options.update_fdt:
|
||
|
image.SetCalculatedProperties()
|
||
|
for dtb_item in state.GetFdts():
|
||
|
dtb_item.Sync()
|
||
|
image.ProcessEntryContents()
|
||
|
image.WriteSymbols()
|
||
|
image.BuildImage()
|
||
|
if options.map:
|
||
|
image.WriteMap()
|
||
|
|
||
|
# Write the updated FDTs to our output files
|
||
|
for dtb_item in state.GetFdts():
|
||
|
tools.WriteFile(dtb_item._fname, dtb_item.GetContents())
|
||
|
|
||
|
finally:
|
||
|
tools.FinaliseOutputDir()
|
||
|
finally:
|
||
|
tout.Uninit()
|
||
|
|
||
|
return 0
|