images to be created.
"""
-from __future__ import print_function
-
from collections import OrderedDict
import re
import sys
-from entry import Entry
-import fdt_util
-import tools
-import tout
+from binman.entry import Entry
+from dtoc import fdt_util
+from patman import tools
+from patman import tout
+from patman.tools import ToHexSize
class Entry_section(Entry):
name-prefix: Adds a prefix to the name of every entry in the section
when writing out the map
+ Properties:
+ allow_missing: True if this section permits external blobs to be
+ missing their contents. The second will produce an image but of
+ course it will not work.
+
Since a section is also an entry, it inherits all the properies of entries
too.
"""
def __init__(self, section, etype, node, test=False):
if not test:
- Entry.__init__(self, section, etype, node)
+ super().__init__(section, etype, node)
self._entries = OrderedDict()
self._pad_byte = 0
self._sort = False
self._end_4gb = False
def ReadNode(self):
- """Read properties from the image node"""
- Entry.ReadNode(self)
+ """Read properties from the section node"""
+ super().ReadNode()
self._pad_byte = fdt_util.GetInt(self._node, 'pad-byte', 0)
self._sort = fdt_util.GetBool(self._node, 'sort-by-offset')
self._end_4gb = fdt_util.GetBool(self._node, 'end-at-4gb')
def _ReadEntries(self):
for node in self._node.subnodes:
- if node.name == 'hash':
+ if node.name.startswith('hash') or node.name.startswith('signature'):
continue
entry = Entry.Create(self, node)
entry.ReadNode()
a section containing a list of files. Process these entries so that
this information is added to the device tree.
"""
- Entry.ExpandEntries(self)
+ super().ExpandEntries()
for entry in self._entries.values():
entry.ExpandEntries()
- def AddMissingProperties(self):
+ def AddMissingProperties(self, have_image_pos):
"""Add new properties to the device tree as needed for this entry"""
- Entry.AddMissingProperties(self)
+ super().AddMissingProperties(have_image_pos)
+ if self.compress != 'none':
+ have_image_pos = False
for entry in self._entries.values():
- entry.AddMissingProperties()
+ entry.AddMissingProperties(have_image_pos)
def ObtainContents(self):
return self.GetEntryContents()
- def GetData(self):
- section_data = tools.GetBytes(self._pad_byte, self.size)
+ def GetPaddedDataForEntry(self, entry, entry_data):
+ """Get the data for an entry including any padding
+
+ Gets the entry data and uses the section pad-byte value to add padding
+ before and after as defined by the pad-before and pad-after properties.
+ This does not consider alignment.
+
+ Args:
+ entry: Entry to check
+
+ Returns:
+ Contents of the entry along with any pad bytes before and
+ after it (bytes)
+ """
+ pad_byte = (entry._pad_byte if isinstance(entry, Entry_section)
+ else self._pad_byte)
+
+ data = b''
+ # Handle padding before the entry
+ if entry.pad_before:
+ data += tools.GetBytes(self._pad_byte, entry.pad_before)
+
+ # Add in the actual entry data
+ data += entry_data
+
+ # Handle padding after the entry
+ if entry.pad_after:
+ data += tools.GetBytes(self._pad_byte, entry.pad_after)
+
+ if entry.size:
+ data += tools.GetBytes(pad_byte, entry.size - len(data))
+
+ self.Detail('GetPaddedDataForEntry: size %s' % ToHexSize(self.data))
+
+ return data
+
+ def _BuildSectionData(self):
+ """Build the contents of a section
+
+ This places all entries at the right place, dealing with padding before
+ and after entries. It does not do padding for the section itself (the
+ pad-before and pad-after properties in the section items) since that is
+ handled by the parent section.
+
+ Returns:
+ Contents of the section (bytes)
+ """
+ section_data = b''
for entry in self._entries.values():
- data = entry.GetData()
- base = self.pad_before + entry.offset - self._skip_at_start
- section_data = (section_data[:base] + data +
- section_data[base + len(data):])
+ data = self.GetPaddedDataForEntry(entry, entry.GetData())
+ # Handle empty space before the entry
+ pad = (entry.offset or 0) - self._skip_at_start - len(section_data)
+ if pad > 0:
+ section_data += tools.GetBytes(self._pad_byte, pad)
+
+ # Add in the actual entry data
+ section_data += data
+
self.Detail('GetData: %d entries, total size %#x' %
(len(self._entries), len(section_data)))
- return section_data
+ return self.CompressData(section_data)
+
+ def GetPaddedData(self, data=None):
+ """Get the data for a section including any padding
+
+ Gets the section data and uses the parent section's pad-byte value to
+ add padding before and after as defined by the pad-before and pad-after
+ properties. If this is a top-level section (i.e. an image), this is the
+ same as GetData(), since padding is not supported.
+
+ This does not consider alignment.
+
+ Returns:
+ Contents of the section along with any pad bytes before and
+ after it (bytes)
+ """
+ section = self.section or self
+ if data is None:
+ data = self.GetData()
+ return section.GetPaddedDataForEntry(self, data)
+
+ def GetData(self):
+ """Get the contents of an entry
+
+ This builds the contents of the section, stores this as the contents of
+ the section and returns it
+
+ Returns:
+ bytes content of the section, made up for all all of its subentries.
+ This excludes any padding. If the section is compressed, the
+ compressed data is returned
+ """
+ data = self._BuildSectionData()
+ self.SetContents(data)
+ return data
def GetOffsets(self):
"""Handle entries that want to set the offset/size of other entries
def ResetForPack(self):
"""Reset offset/size fields so that packing can be done again"""
- Entry.ResetForPack(self)
+ super().ResetForPack()
for entry in self._entries.values():
entry.ResetForPack()
def Pack(self, offset):
"""Pack all entries into the section"""
self._PackEntries()
- return Entry.Pack(self, offset)
+ if self._sort:
+ self._SortEntries()
+ self._ExpandEntries()
+
+ data = self._BuildSectionData()
+ self.SetContents(data)
+
+ self.CheckSize()
+
+ offset = super().Pack(offset)
+ self.CheckEntries()
+ return offset
def _PackEntries(self):
- """Pack all entries into the image"""
+ """Pack all entries into the section"""
offset = self._skip_at_start
for entry in self._entries.values():
offset = entry.Pack(offset)
- self.size = self.CheckSize()
+ return offset
def _ExpandEntries(self):
"""Expand any entries that are permitted to"""
self._entries[entry._node.name] = entry
def CheckEntries(self):
- """Check that entries do not overlap or extend outside the image"""
- if self._sort:
- self._SortEntries()
- self._ExpandEntries()
+ """Check that entries do not overlap or extend outside the section"""
+ max_size = self.size if self.uncomp_size is None else self.uncomp_size
+
offset = 0
prev_name = 'None'
for entry in self._entries.values():
- entry.CheckOffset()
+ entry.CheckEntries()
if (entry.offset < self._skip_at_start or
entry.offset + entry.size > self._skip_at_start +
- self.size):
- entry.Raise("Offset %#x (%d) is outside the section starting "
- "at %#x (%d)" %
- (entry.offset, entry.offset, self._skip_at_start,
- self._skip_at_start))
- if entry.offset < offset:
+ max_size):
+ entry.Raise('Offset %#x (%d) size %#x (%d) is outside the '
+ "section '%s' starting at %#x (%d) "
+ 'of size %#x (%d)' %
+ (entry.offset, entry.offset, entry.size, entry.size,
+ self._node.path, self._skip_at_start,
+ self._skip_at_start, max_size, max_size))
+ if entry.offset < offset and entry.size:
entry.Raise("Offset %#x (%d) overlaps with previous entry '%s' "
"ending at %#x (%d)" %
(entry.offset, entry.offset, prev_name, offset, offset))
entry.WriteSymbols(self)
def SetCalculatedProperties(self):
- Entry.SetCalculatedProperties(self)
+ super().SetCalculatedProperties()
for entry in self._entries.values():
entry.SetCalculatedProperties()
def SetImagePos(self, image_pos):
- Entry.SetImagePos(self, image_pos)
- for entry in self._entries.values():
- entry.SetImagePos(image_pos + self.offset)
+ super().SetImagePos(image_pos)
+ if self.compress == 'none':
+ for entry in self._entries.values():
+ entry.SetImagePos(image_pos + self.offset)
def ProcessContents(self):
sizes_ok_base = super(Entry_section, self).ProcessContents()
sizes_ok = False
return sizes_ok and sizes_ok_base
- def CheckOffset(self):
- self.CheckEntries()
-
def WriteMap(self, fd, indent):
"""Write a map of the section to a .map file
return entry.GetData()
source_entry.Raise("Cannot find entry for node '%s'" % node.name)
- def LookupSymbol(self, sym_name, optional, msg):
+ def LookupSymbol(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.
- At present the only entry property supported is offset.
+ 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
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 targetted 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
if prop_name == 'offset':
return entry.offset
elif prop_name == 'image_pos':
- return entry.image_pos
+ value = entry.image_pos
+ if not self.GetImage()._end_4gb:
+ value += base_addr
+ return value
+ if prop_name == 'size':
+ return entry.size
else:
raise ValueError("%s: No such property '%s'" % (msg, prop_name))
return None
def GetEntryContents(self):
- """Call ObtainContents() for the section
+ """Call ObtainContents() for each entry in the section
"""
todo = self._entries.values()
for passnum in range(3):
if not entry:
self._Raise("Unable to set offset/size for unknown entry '%s'" %
name)
- entry.SetOffsetSize(self._skip_at_start + offset if offset else None,
- size)
+ entry.SetOffsetSize(self._skip_at_start + offset if offset is not None
+ else None, size)
def GetEntryOffsets(self):
"""Handle entries that want to set the offset/size of other entries
for name, info in offset_dict.items():
self._SetEntryOffsetSize(name, *info)
-
def CheckSize(self):
- """Check that the image contents does not exceed its size, etc."""
- contents_size = 0
- for entry in self._entries.values():
- contents_size = max(contents_size, entry.offset + entry.size)
-
- contents_size -= self._skip_at_start
+ contents_size = len(self.data)
size = self.size
if not size:
- size = self.pad_before + contents_size + self.pad_after
+ data = self.GetPaddedData(self.data)
+ size = len(data)
size = tools.Align(size, self.align_size)
if self.size and contents_size > self.size:
return data
def ReadChildData(self, child, decomp=True):
- """Read the data for a particular child entry
-
- Args:
- child: Child entry to read data for
- decomp: True to return uncompressed data, False to leave the data
- compressed if it is compressed
-
- Returns:
- Data contents of entry
- """
+ tout.Debug("ReadChildData for child '%s'" % child.GetPath())
parent_data = self.ReadData(True)
- data = parent_data[child.offset:child.offset + child.size]
+ offset = child.offset - self._skip_at_start
+ tout.Debug("Extract for child '%s': offset %#x, skip_at_start %#x, result %#x" %
+ (child.GetPath(), child.offset, self._skip_at_start, offset))
+ data = parent_data[offset:offset + child.size]
if decomp:
indata = data
data = tools.Decompress(indata, child.compress)
def WriteChildData(self, child):
return True
+
+ def SetAllowMissing(self, allow_missing):
+ """Set whether a section allows missing external blobs
+
+ Args:
+ allow_missing: True if allowed, False if not allowed
+ """
+ self.allow_missing = allow_missing
+ for entry in self._entries.values():
+ entry.SetAllowMissing(allow_missing)
+
+ def CheckMissing(self, missing_list):
+ """Check if any entries in this section have missing external blobs
+
+ If there are missing blobs, the entries are added to the list
+
+ Args:
+ missing_list: List of Entry objects to be added to
+ """
+ for entry in self._entries.values():
+ entry.CheckMissing(missing_list)