# Class for an image, the output of binman
#
-from __future__ import print_function
-
from collections import OrderedDict
import fnmatch
from operator import attrgetter
+import os
import re
import sys
-from entry import Entry
-from etype import fdtmap
-from etype import image_header
-from etype import section
-import fdt
-import fdt_util
-import tools
-import tout
+from binman.entry import Entry
+from binman.etype import fdtmap
+from binman.etype import image_header
+from binman.etype import section
+from dtoc import fdt
+from dtoc import fdt_util
+from patman import tools
+from patman import tout
class Image(section.Entry_section):
"""A Image, representing an output from binman
image_node: Name of node containing the description for this image
fdtmap_dtb: Fdt object for the fdtmap when loading from a file
fdtmap_data: Contents of the fdtmap when loading from a file
+ allow_repack: True to add properties to allow the image to be safely
+ repacked later
+ test_section_timeout: Use a zero timeout for section multi-threading
+ (for testing)
Args:
+ copy_to_orig: Copy offset/size to orig_offset/orig_size after reading
+ from the device tree
test: True if this is being called from a test of Images. This this case
there is no device tree defining the structure of the section, so
we create a section manually.
+ ignore_missing: Ignore any missing entry arguments (i.e. don't raise an
+ exception). This should be used if the Image is being loaded from
+ a file rather than generated. In that case we obviously don't need
+ the entry arguments since the contents already exists.
+ use_expanded: True if we are updating the FDT wth entry offsets, etc.
+ and should use the expanded versions of the U-Boot entries.
+ Any entry type that includes a devicetree must put it in a
+ separate entry so that it will be updated. For example. 'u-boot'
+ normally just picks up 'u-boot.bin' which includes the
+ devicetree, but this is not updateable, since it comes into
+ binman as one piece and binman doesn't know that it is actually
+ an executable followed by a devicetree. Of course it could be
+ taught this, but then when reading an image (e.g. 'binman ls')
+ it may need to be able to split the devicetree out of the image
+ in order to determine the location of things. Instead we choose
+ to ignore 'u-boot-bin' in this case, and build it ourselves in
+ binman with 'u-boot-dtb.bin' and 'u-boot.dtb'. See
+ Entry_u_boot_expanded and Entry_blob_phase for details.
"""
- def __init__(self, name, node, test=False):
- section.Entry_section.__init__(self, None, 'section', node, test)
+ def __init__(self, name, node, copy_to_orig=True, test=False,
+ ignore_missing=False, use_expanded=False):
+ super().__init__(None, 'section', node, test=test)
+ self.copy_to_orig = copy_to_orig
self.name = 'main-section'
self.image_name = name
self._filename = '%s.bin' % self.image_name
self.fdtmap_dtb = None
self.fdtmap_data = None
+ self.allow_repack = False
+ self._ignore_missing = ignore_missing
+ self.use_expanded = use_expanded
+ self.test_section_timeout = False
if not test:
self.ReadNode()
def ReadNode(self):
- section.Entry_section.ReadNode(self)
+ super().ReadNode()
filename = fdt_util.GetString(self._node, 'filename')
if filename:
self._filename = filename
+ self.allow_repack = fdt_util.GetBool(self._node, 'allow-repack')
@classmethod
def FromFile(cls, fname):
data[pos + fdtmap.FDTMAP_HDR_LEN:pos + 256])
dtb_size = probe_dtb.GetFdtObj().totalsize()
fdtmap_data = data[pos:pos + dtb_size + fdtmap.FDTMAP_HDR_LEN]
- dtb = fdt.Fdt.FromData(fdtmap_data[fdtmap.FDTMAP_HDR_LEN:])
+ fdt_data = fdtmap_data[fdtmap.FDTMAP_HDR_LEN:]
+ out_fname = tools.GetOutputFilename('fdtmap.in.dtb')
+ tools.WriteFile(out_fname, fdt_data)
+ dtb = fdt.Fdt(out_fname)
dtb.Scan()
# Return an Image with the associated nodes
root = dtb.GetRoot()
- image = Image('image', root)
+ image = Image('image', root, copy_to_orig=False, ignore_missing=True)
+
image.image_node = fdt_util.GetString(root, 'image-node', 'image')
image.fdtmap_dtb = dtb
image.fdtmap_data = fdtmap_data
image._data = data
+ image._filename = fname
+ image.image_name, _ = os.path.splitext(fname)
return image
def Raise(self, msg):
def PackEntries(self):
"""Pack all entries into the image"""
- section.Entry_section.Pack(self, 0)
+ super().Pack(0)
def SetImagePos(self):
# This first section in the image so it starts at 0
- section.Entry_section.SetImagePos(self, 0)
+ super().SetImagePos(0)
def ProcessEntryContents(self):
"""Call the ProcessContents() method for each entry
Returns:
True if the new data size is OK, False if expansion is needed
"""
- sizes_ok = True
- for entry in self._entries.values():
- if not entry.ProcessContents():
- sizes_ok = False
- tout.Debug("Entry '%s' size change" % self._node.path)
- return sizes_ok
+ return super().ProcessContents()
def WriteSymbols(self):
"""Write symbol values into binary files for access at run time"""
- section.Entry_section.WriteSymbols(self, self)
-
- def BuildSection(self, fd, base_offset):
- """Write the section to a file"""
- fd.seek(base_offset)
- fd.write(self.GetData())
+ super().WriteSymbols(self)
def BuildImage(self):
"""Write the image to a file"""
fname = tools.GetOutputFilename(self._filename)
+ tout.Info("Writing image to '%s'" % fname)
with open(fname, 'wb') as fd:
- self.BuildSection(fd, 0)
+ data = self.GetPaddedData()
+ fd.write(data)
+ tout.Info("Wrote %#x bytes" % len(data))
def WriteMap(self):
"""Write a map of the image to a .map file
with open(fname, 'w') as fd:
print('%8s %8s %8s %s' % ('ImagePos', 'Offset', 'Size', 'Name'),
file=fd)
- section.Entry_section.WriteMap(self, fd, 0)
+ super().WriteMap(fd, 0)
return fname
def BuildEntryList(self):
return entry
def ReadData(self, decomp=True):
+ tout.Debug("Image '%s' ReadData(), size=%#x" %
+ (self.GetPath(), len(self._data)))
return self._data
def GetListEntries(self, entry_paths):
_DoLine(lines, _EntryToStrings(entry))
selected_entries.append(entry)
return selected_entries, lines, widths
+
+ def LookupImageSymbol(self, sym_name, optional, msg, base_addr):
+ """Look up a symbol in an ELF file
+
+ Looks up a symbol in an ELF file. Only entry types which come from an
+ ELF image can be used by this function.
+
+ This searches through this image including all of its subsections.
+
+ At present the only entry properties supported are:
+ offset
+ image_pos - 'base_addr' is added if this is not an end-at-4gb image
+ size
+
+ Args:
+ sym_name: Symbol name in the ELF file to look up in the format
+ _binman_<entry>_prop_<property> where <entry> is the name of
+ the entry and <property> is the property to find (e.g.
+ _binman_u_boot_prop_offset). As a special case, you can append
+ _any to <entry> to have it search for any matching entry. E.g.
+ _binman_u_boot_any_prop_offset will match entries called u-boot,
+ u-boot-img and u-boot-nodtb)
+ optional: True if the symbol is optional. If False this function
+ will raise if the symbol is not found
+ msg: Message to display if an error occurs
+ base_addr: Base address of image. This is added to the returned
+ image_pos in most cases so that the returned position indicates
+ where the targeted entry/binary has actually been loaded. But
+ if end-at-4gb is used, this is not done, since the binary is
+ already assumed to be linked to the ROM position and using
+ execute-in-place (XIP).
+
+ Returns:
+ Value that should be assigned to that symbol, or None if it was
+ optional and not found
+
+ Raises:
+ ValueError if the symbol is invalid or not found, or references a
+ property which is not supported
+ """
+ entries = OrderedDict()
+ entries_by_name = {}
+ self._CollectEntries(entries, entries_by_name, self)
+ return self.LookupSymbol(sym_name, optional, msg, base_addr,
+ entries_by_name)