summaryrefslogtreecommitdiff
path: root/tools/binman/image.py
diff options
context:
space:
mode:
authorSimon Glass <sjg@chromium.org>2018-06-01 09:38:12 -0600
committerSimon Glass <sjg@chromium.org>2018-06-07 11:25:07 -0800
commit8f1da50ccca246fe2c3e9d8ef890b48e7bc8795b (patch)
tree240e4098ca628aa9806bf6962862376a76830baf /tools/binman/image.py
parentdd57c13bbc28df6f1bc849ec55d1703f4ca0398e (diff)
binman: Refactor much of the image code into 'section'
We want to support multiple sections within a single image. To do this, move most of the Image class implementation into a new Section class. An Image contains only a single Section, but at some point we will support a new 'section' entry, thus allowing Sections within Sections. Use the name 'bsection' for the module so we can use 'section' for the etype module. Signed-off-by: Simon Glass <sjg@chromium.org>
Diffstat (limited to 'tools/binman/image.py')
-rw-r--r--tools/binman/image.py247
1 files changed, 19 insertions, 228 deletions
diff --git a/tools/binman/image.py b/tools/binman/image.py
index b10b188795..1d234965fa 100644
--- a/tools/binman/image.py
+++ b/tools/binman/image.py
@@ -13,6 +13,7 @@ import re
import sys
import fdt_util
+import bsection
import tools
class Image:
@@ -27,158 +28,31 @@ 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, test=False):
- global entry
- global Entry
- import entry
- from entry import Entry
-
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()
-
- if not test:
+ if test:
+ self._section = bsection.Section('main-section', self._node, True)
+ else:
self._ReadNode()
- self._ReadEntries()
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 GetPath(self):
- """Get the path of an image (in the FDT)
-
- Returns:
- Full path of the node for this image
- """
- return self._node.path
-
- 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
@@ -186,119 +60,36 @@ class Image:
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"""
- for entry in self._entries.values():
- entry.WriteSymbols(self)
+ 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 LookupSymbol(self, sym_name, optional, msg):
- """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 pos.
-
- 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
- _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,
- 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
-
- 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
- """
- m = re.match(r'^_binman_(\w+)_prop_(\w+)$', sym_name)
- if not m:
- raise ValueError("%s: Symbol '%s' has invalid format" %
- (msg, sym_name))
- entry_name, prop_name = m.groups()
- entry_name = entry_name.replace('_', '-')
- entry = self._entries.get(entry_name)
- if not entry:
- if entry_name.endswith('-any'):
- root = entry_name[:-4]
- for name in self._entries:
- if name.startswith(root):
- rest = name[len(root):]
- if rest in ['', '-img', '-nodtb']:
- entry = self._entries[name]
- if not entry:
- err = ("%s: Entry '%s' not found in list (%s)" %
- (msg, entry_name, ','.join(self._entries.keys())))
- if optional:
- print('Warning: %s' % err, file=sys.stderr)
- return None
- raise ValueError(err)
- if prop_name == 'pos':
- return entry.pos
- else:
- raise ValueError("%s: No such property '%s'" % (msg, prop_name))
+ def GetEntries(self):
+ return self._section.GetEntries()