import fdt_util
import re
+import state
import tools
class Section(object):
Attributes:
_node: Node object that contains the section definition in device tree
+ _parent_section: Parent Section object which created this Section
_size: Section size in bytes, or None if not known yet
_align_size: Section size alignment, or None
_pad_before: Number of bytes before the first entry starts. This
- effectively changes the place where entry position 0 starts
+ effectively changes the place where entry offset 0 starts
_pad_after: Number of bytes after the last entry ends. The last
entry will finish on or before this boundary
_pad_byte: Byte to use to pad the section where there is no entry
- _sort: True if entries should be sorted by position, False if they
+ _sort: True if entries should be sorted by offset, False if they
must be in-order in the device tree description
_skip_at_start: Number of bytes before the first entry starts. These
- effectively adjust the starting position of entries. For example,
+ effectively adjust the starting offset of entries. For example,
if _pad_before is 16, then the first entry would start at 16.
- An entry with pos = 20 would in fact be written at position 4
+ An entry with offset = 20 would in fact be written at offset 4
in the image file.
_end_4gb: Indicates that the section ends at the 4GB boundary. This is
- used for x86 images, which want to use positions such that a
- memory address (like 0xff800000) is the first entry position.
- This causes _skip_at_start to be set to the starting memory
- address.
+ used for x86 images, which want to use offsets such that a memory
+ address (like 0xff800000) is the first entry offset. This causes
+ _skip_at_start to be set to the starting memory address.
_name_prefix: Prefix to add to the name of all entries within this
section
_entries: OrderedDict() of entries
"""
- def __init__(self, name, node, test=False):
+ def __init__(self, name, parent_section, node, image, test=False):
global entry
global Entry
import entry
from entry import Entry
+ self._parent_section = parent_section
+ self._name = name
self._node = node
+ self._image = image
+ self._offset = None
self._size = None
self._align_size = None
self._pad_before = 0
self._pad_after = 0
self._pad_byte = 0
self._sort = False
- self._skip_at_start = 0
+ self._skip_at_start = None
self._end_4gb = False
self._name_prefix = ''
self._entries = OrderedDict()
+ self._image_pos = None
if not test:
self._ReadNode()
self._ReadEntries()
def _ReadNode(self):
"""Read properties from the section node"""
+ self._offset = fdt_util.GetInt(self._node, 'offset')
self._size = fdt_util.GetInt(self._node, 'size')
self._align_size = fdt_util.GetInt(self._node, 'align-size')
if tools.NotPowerOfTwo(self._align_size):
self._pad_before = fdt_util.GetInt(self._node, 'pad-before', 0)
self._pad_after = fdt_util.GetInt(self._node, 'pad-after', 0)
self._pad_byte = fdt_util.GetInt(self._node, 'pad-byte', 0)
- self._sort = fdt_util.GetBool(self._node, 'sort-by-pos')
+ self._sort = fdt_util.GetBool(self._node, 'sort-by-offset')
self._end_4gb = fdt_util.GetBool(self._node, 'end-at-4gb')
- if self._end_4gb and not self._size:
- self._Raise("Section size must be provided when using end-at-4gb")
+ self._skip_at_start = fdt_util.GetInt(self._node, 'skip-at-start')
if self._end_4gb:
- self._skip_at_start = 0x100000000 - self._size
+ if not self._size:
+ self._Raise("Section size must be provided when using end-at-4gb")
+ if self._skip_at_start is not None:
+ self._Raise("Provide either 'end-at-4gb' or 'skip-at-start'")
+ else:
+ self._skip_at_start = 0x100000000 - self._size
+ else:
+ if self._skip_at_start is None:
+ self._skip_at_start = 0
self._name_prefix = fdt_util.GetString(self._node, 'name-prefix')
def _ReadEntries(self):
for node in self._node.subnodes:
+ if node.name == 'hash':
+ continue
entry = Entry.Create(self, node)
entry.SetPrefix(self._name_prefix)
self._entries[node.name] = entry
+ def GetFdtSet(self):
+ """Get the set of device tree files used by this image"""
+ fdt_set = set()
+ for entry in self._entries.values():
+ fdt_set.update(entry.GetFdtSet())
+ return fdt_set
+
+ def SetOffset(self, offset):
+ self._offset = offset
+
+ def ExpandEntries(self):
+ for entry in self._entries.values():
+ entry.ExpandEntries()
+
+ def AddMissingProperties(self):
+ """Add new properties to the device tree as needed for this entry"""
+ for prop in ['offset', 'size', 'image-pos']:
+ if not prop in self._node.props:
+ state.AddZeroProp(self._node, prop)
+ state.CheckAddHashProp(self._node)
+ for entry in self._entries.values():
+ entry.AddMissingProperties()
+
+ def SetCalculatedProperties(self):
+ state.SetInt(self._node, 'offset', self._offset or 0)
+ state.SetInt(self._node, 'size', self._size)
+ image_pos = self._image_pos
+ if self._parent_section:
+ image_pos -= self._parent_section.GetRootSkipAtStart()
+ state.SetInt(self._node, 'image-pos', image_pos)
+ for entry in self._entries.values():
+ entry.SetCalculatedProperties()
+
+ def ProcessFdt(self, fdt):
+ todo = self._entries.values()
+ for passnum in range(3):
+ next_todo = []
+ for entry in todo:
+ if not entry.ProcessFdt(fdt):
+ next_todo.append(entry)
+ todo = next_todo
+ if not todo:
+ break
+ if todo:
+ self._Raise('Internal error: Could not complete processing of Fdt: '
+ 'remaining %s' % todo)
+ return True
+
def CheckSize(self):
"""Check that the section contents does not exceed its size, etc."""
contents_size = 0
for entry in self._entries.values():
- contents_size = max(contents_size, entry.pos + entry.size)
+ contents_size = max(contents_size, entry.offset + entry.size)
contents_size -= self._skip_at_start
todo = next_todo
if not todo:
break
+ if todo:
+ self._Raise('Internal error: Could not complete processing of '
+ 'contents: remaining %s' % todo)
+ return True
- def _SetEntryPosSize(self, name, pos, size):
- """Set the position and size of an entry
+ def _SetEntryOffsetSize(self, name, offset, size):
+ """Set the offset and size of an entry
Args:
name: Entry name to update
- pos: New position
+ offset: New offset
size: New size
"""
entry = self._entries.get(name)
if not entry:
- self._Raise("Unable to set pos/size for unknown entry '%s'" % name)
- entry.SetPositionSize(self._skip_at_start + pos, size)
+ self._Raise("Unable to set offset/size for unknown entry '%s'" %
+ name)
+ entry.SetOffsetSize(self._skip_at_start + offset, size)
- def GetEntryPositions(self):
- """Handle entries that want to set the position/size of other entries
+ def GetEntryOffsets(self):
+ """Handle entries that want to set the offset/size of other entries
- This calls each entry's GetPositions() method. If it returns a list
+ This calls each entry's GetOffsets() method. If it returns a list
of entries to update, it updates them.
"""
for entry in self._entries.values():
- pos_dict = entry.GetPositions()
- for name, info in pos_dict.iteritems():
- self._SetEntryPosSize(name, *info)
+ offset_dict = entry.GetOffsets()
+ for name, info in offset_dict.items():
+ self._SetEntryOffsetSize(name, *info)
def PackEntries(self):
"""Pack all entries into the section"""
- pos = self._skip_at_start
+ offset = self._skip_at_start
for entry in self._entries.values():
- pos = entry.Pack(pos)
+ offset = entry.Pack(offset)
+ self._size = self.CheckSize()
def _SortEntries(self):
- """Sort entries by position"""
- entries = sorted(self._entries.values(), key=lambda entry: entry.pos)
+ """Sort entries by offset"""
+ entries = sorted(self._entries.values(), key=lambda entry: entry.offset)
self._entries.clear()
for entry in entries:
self._entries[entry._node.name] = entry
+ def _ExpandEntries(self):
+ """Expand any entries that are permitted to"""
+ exp_entry = None
+ for entry in self._entries.values():
+ if exp_entry:
+ exp_entry.ExpandToLimit(entry.offset)
+ exp_entry = None
+ if entry.expand_size:
+ exp_entry = entry
+ if exp_entry:
+ exp_entry.ExpandToLimit(self._size)
+
def CheckEntries(self):
- """Check that entries do not overlap or extend outside the section"""
+ """Check that entries do not overlap or extend outside the section
+
+ This also sorts entries, if needed and expands
+ """
if self._sort:
self._SortEntries()
- pos = 0
+ self._ExpandEntries()
+ offset = 0
prev_name = 'None'
for entry in self._entries.values():
- entry.CheckPosition()
- if (entry.pos < self._skip_at_start or
- entry.pos >= self._skip_at_start + self._size):
- entry.Raise("Position %#x (%d) is outside the section starting "
+ entry.CheckOffset()
+ 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.pos, entry.pos, self._skip_at_start,
+ (entry.offset, entry.offset, self._skip_at_start,
self._skip_at_start))
- if entry.pos < pos:
- entry.Raise("Position %#x (%d) overlaps with previous entry '%s' "
+ if entry.offset < offset:
+ entry.Raise("Offset %#x (%d) overlaps with previous entry '%s' "
"ending at %#x (%d)" %
- (entry.pos, entry.pos, prev_name, pos, pos))
- pos = entry.pos + entry.size
+ (entry.offset, entry.offset, prev_name, offset, offset))
+ offset = entry.offset + entry.size
prev_name = entry.GetPath()
+ def SetImagePos(self, image_pos):
+ self._image_pos = image_pos
+ for entry in self._entries.values():
+ entry.SetImagePos(image_pos)
+
def ProcessEntryContents(self):
"""Call the ProcessContents() method for each entry
for entry in self._entries.values():
entry.WriteSymbols(self)
- def BuildSection(self, fd, base_pos):
+ def BuildSection(self, fd, base_offset):
"""Write the section to a file"""
- fd.seek(base_pos)
+ fd.seek(base_offset)
fd.write(self.GetData())
def GetData(self):
- """Write the section to a file"""
- section_data = chr(self._pad_byte) * self._size
+ """Get the contents of the section"""
+ section_data = tools.GetBytes(self._pad_byte, self._size)
for entry in self._entries.values():
data = entry.GetData()
- base = self._pad_before + entry.pos - self._skip_at_start
+ base = self._pad_before + entry.offset - self._skip_at_start
section_data = (section_data[:base] + data +
section_data[base + len(data):])
return section_data
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 pos.
+ At present the only entry property supported is offset.
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_pos). As a special case, you can append
+ _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_pos will match entries called u-boot,
+ _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
print('Warning: %s' % err, file=sys.stderr)
return None
raise ValueError(err)
- if prop_name == 'pos':
- return entry.pos
+ if prop_name == 'offset':
+ return entry.offset
+ elif prop_name == 'image_pos':
+ return entry.image_pos
else:
raise ValueError("%s: No such property '%s'" % (msg, prop_name))
def GetEntries(self):
+ """Get the number of entries in a section
+
+ Returns:
+ Number of entries in a section
+ """
return self._entries
+ def GetSize(self):
+ """Get the size of a section in bytes
+
+ This is only meaningful if the section has a pre-defined size, or the
+ entries within it have been packed, so that the size has been
+ calculated.
+
+ Returns:
+ Entry size in bytes
+ """
+ return self._size
+
def WriteMap(self, fd, indent):
"""Write a map of the section to a .map file
Args:
fd: File to write the map to
"""
+ Entry.WriteMapLine(fd, indent, self._name, self._offset or 0,
+ self._size, self._image_pos)
+ for entry in self._entries.values():
+ entry.WriteMap(fd, indent + 1)
+
+ def GetContentsByPhandle(self, phandle, source_entry):
+ """Get the data contents of an entry specified by a phandle
+
+ This uses a phandle to look up a node and and find the entry
+ associated with it. Then it returnst he contents of that entry.
+
+ Args:
+ phandle: Phandle to look up (integer)
+ source_entry: Entry containing that phandle (used for error
+ reporting)
+
+ Returns:
+ data from associated entry (as a string), or None if not found
+ """
+ node = self._node.GetFdt().LookupPhandle(phandle)
+ if not node:
+ source_entry.Raise("Cannot find node for phandle %d" % phandle)
for entry in self._entries.values():
- entry.WriteMap(fd, indent)
+ if entry._node == node:
+ return entry.GetData()
+ source_entry.Raise("Cannot find entry for node '%s'" % node.name)
+
+ def ExpandSize(self, size):
+ if size != self._size:
+ self._size = size
+
+ def GetRootSkipAtStart(self):
+ if self._parent_section:
+ return self._parent_section.GetRootSkipAtStart()
+ return self._skip_at_start
+
+ def GetImageSize(self):
+ return self._image._size