+# SPDX-License-Identifier: GPL-2.0+
# Copyright (c) 2016 Google, Inc
# Written by Simon Glass <sjg@chromium.org>
#
-# SPDX-License-Identifier: GPL-2.0+
-#
# Class for an image, the output of binman
#
+from __future__ import print_function
+
from collections import OrderedDict
from operator import attrgetter
+import re
+import sys
-import entry
-from entry import Entry
import fdt_util
+import bsection
import tools
class Image:
_node: Node object that contains the image definition in device tree
_name: Image name
_size: Image size in bytes, or None if not known yet
- _align_size: Image size alignment, or None
- _pad_before: Number of bytes before the first entry starts. This
- effectively changes the place where entry position 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 image where there is no entry
_filename: Output filename for image
- _sort: True if entries should be sorted by position, False if they
- must be in-order in the device tree description
- _skip_at_start: Number of bytes before the first entry starts. These
- effecively adjust the starting position 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
- in the image file.
- _end_4gb: Indicates that the image 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.
- _entries: OrderedDict() of entries
+ _sections: Sections present in this image (may be one or more)
"""
- def __init__(self, name, node):
+ def __init__(self, name, node, test=False):
self._node = node
self._name = name
self._size = None
- self._align_size = None
- self._pad_before = 0
- self._pad_after = 0
- self._pad_byte = 0
self._filename = '%s.bin' % self._name
- self._sort = False
- self._skip_at_start = 0
- self._end_4gb = False
- self._entries = OrderedDict()
-
- self._ReadNode()
- self._ReadEntries()
+ if test:
+ self._section = bsection.Section('main-section', self._node, True)
+ else:
+ self._ReadNode()
def _ReadNode(self):
"""Read properties from the image node"""
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._Raise("Alignment size %s must be a power of two" %
- 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)
filename = fdt_util.GetString(self._node, 'filename')
if filename:
self._filename = filename
- self._sort = fdt_util.GetBool(self._node, 'sort-by-pos')
- self._end_4gb = fdt_util.GetBool(self._node, 'end-at-4gb')
- if self._end_4gb and not self._size:
- self._Raise("Image size must be provided when using end-at-4gb")
- if self._end_4gb:
- self._skip_at_start = 0x100000000 - self._size
-
- 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.pos + entry.size)
-
- contents_size -= self._skip_at_start
-
- size = self._size
- if not size:
- size = self._pad_before + contents_size + self._pad_after
- size = tools.Align(size, self._align_size)
-
- if self._size and contents_size > self._size:
- self._Raise("contents size %#x (%d) exceeds image size %#x (%d)" %
- (contents_size, contents_size, self._size, self._size))
- if not self._size:
- self._size = size
- if self._size != tools.Align(self._size, self._align_size):
- self._Raise("Size %#x (%d) does not match align-size %#x (%d)" %
- (self._size, self._size, self._align_size, self._align_size))
-
- def _Raise(self, msg):
- """Raises an error for this image
-
- Args:
- msg: Error message to use in the raise string
- Raises:
- ValueError()
- """
- raise ValueError("Image '%s': %s" % (self._node.path, msg))
-
- def _ReadEntries(self):
- for node in self._node.subnodes:
- self._entries[node.name] = Entry.Create(self, node)
-
- def FindEntryType(self, etype):
- """Find an entry type in the image
-
- Args:
- etype: Entry type to find
- Returns:
- entry matching that type, or None if not found
- """
- for entry in self._entries.values():
- if entry.etype == etype:
- return entry
- return None
+ self._section = bsection.Section('main-section', self._node)
def GetEntryContents(self):
- """Call ObtainContents() for each entry
-
- This calls each entry's ObtainContents() a few times until they all
- return True. We stop calling an entry's function once it returns
- True. This allows the contents of one entry to depend on another.
-
- After 3 rounds we give up since it's likely an error.
+ """Call ObtainContents() for the section
"""
- todo = self._entries.values()
- for passnum in range(3):
- next_todo = []
- for entry in todo:
- if not entry.ObtainContents():
- next_todo.append(entry)
- todo = next_todo
- if not todo:
- break
-
- def _SetEntryPosSize(self, name, pos, size):
- """Set the position and size of an entry
-
- Args:
- name: Entry name to update
- pos: New position
- 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._section.GetEntryContents()
def GetEntryPositions(self):
"""Handle entries that want to set the position/size of other entries
This calls each entry's GetPositions() 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)
+ self._section.GetEntryPositions()
def PackEntries(self):
"""Pack all entries into the image"""
- pos = self._skip_at_start
- for entry in self._entries.values():
- pos = entry.Pack(pos)
+ self._section.PackEntries()
- def _SortEntries(self):
- """Sort entries by position"""
- entries = sorted(self._entries.values(), key=lambda entry: entry.pos)
- self._entries.clear()
- for entry in entries:
- self._entries[entry._node.name] = entry
+ def CheckSize(self):
+ """Check that the image contents does not exceed its size, etc."""
+ self._size = self._section.CheckSize()
def CheckEntries(self):
"""Check that entries do not overlap or extend outside the image"""
- if self._sort:
- self._SortEntries()
- pos = 0
- prev_name = 'None'
- for entry in self._entries.values():
- if (entry.pos < self._skip_at_start or
- entry.pos >= self._skip_at_start + self._size):
- entry.Raise("Position %#x (%d) is outside the image starting "
- "at %#x (%d)" %
- (entry.pos, entry.pos, self._skip_at_start,
- self._skip_at_start))
- if entry.pos < pos:
- entry.Raise("Position %#x (%d) overlaps with previous entry '%s' "
- "ending at %#x (%d)" %
- (entry.pos, entry.pos, prev_name, pos, pos))
- pos = entry.pos + entry.size
- prev_name = entry.GetPath()
+ self._section.CheckEntries()
def ProcessEntryContents(self):
"""Call the ProcessContents() method for each entry
This is intended to adjust the contents as needed by the entry type.
"""
- for entry in self._entries.values():
- entry.ProcessContents()
+ self._section.ProcessEntryContents()
+
+ def WriteSymbols(self):
+ """Write symbol values into binary files for access at run time"""
+ self._section.WriteSymbols()
def BuildImage(self):
"""Write the image to a file"""
fname = tools.GetOutputFilename(self._filename)
with open(fname, 'wb') as fd:
- fd.write(chr(self._pad_byte) * self._size)
+ self._section.BuildSection(fd, 0)
- for entry in self._entries.values():
- data = entry.GetData()
- fd.seek(self._pad_before + entry.pos - self._skip_at_start)
- fd.write(data)
+ def GetEntries(self):
+ return self._section.GetEntries()