except:
have_importlib = False
-import fdt_util
-import control
import os
+from sets import Set
import sys
+
+import fdt_util
+import state
import tools
modules = {}
self.name = node and (name_prefix + node.name) or 'none'
self.offset = None
self.size = None
- self.data = ''
+ self.data = None
self.contents_size = 0
self.align = None
self.align_size = None
self.pad_after = 0
self.offset_unset = False
self.image_pos = None
+ self._expand_size = False
if read_node:
self.ReadNode()
@staticmethod
- def Create(section, node, etype=None):
- """Create a new entry for a node.
+ def Lookup(section, node_path, etype):
+ """Look up the entry class for a node.
Args:
- section: Section object containing this node
- node: Node object containing information about the entry to create
- etype: Entry type to use, or None to work it out (used for tests)
+ section: Section object containing this node
+ node_node: Path name of Node object containing information about
+ the entry to create (used for errors)
+ etype: Entry type to use
Returns:
- A new Entry object of the correct type (a subclass of Entry)
+ The entry class object if found, else None
"""
- if not etype:
- etype = fdt_util.GetString(node, 'type', node.name)
-
# Convert something like 'u-boot@0' to 'u_boot' since we are only
# interested in the type.
module_name = etype.replace('-', '_')
module = importlib.import_module(module_name)
else:
module = __import__(module_name)
- except ImportError:
- raise ValueError("Unknown entry type '%s' in node '%s'" %
- (etype, node.path))
+ except ImportError as e:
+ raise ValueError("Unknown entry type '%s' in node '%s' (expected etype/%s.py, error '%s'" %
+ (etype, node_path, module_name, e))
finally:
sys.path = old_path
modules[module_name] = module
+ # Look up the expected class name
+ return getattr(module, 'Entry_%s' % module_name)
+
+ @staticmethod
+ def Create(section, node, etype=None):
+ """Create a new entry for a node.
+
+ Args:
+ section: Section object containing this node
+ node: Node object containing information about the entry to
+ create
+ etype: Entry type to use, or None to work it out (used for tests)
+
+ Returns:
+ A new Entry object of the correct type (a subclass of Entry)
+ """
+ if not etype:
+ etype = fdt_util.GetString(node, 'type', node.name)
+ obj = Entry.Lookup(section, node.path, etype)
+
# Call its constructor to get the object we want.
- obj = getattr(module, 'Entry_%s' % module_name)
return obj(section, etype, node)
def ReadNode(self):
This reads all the fields we recognise from the node, ready for use.
"""
+ if 'pos' in self._node.props:
+ self.Raise("Please use 'offset' instead of 'pos'")
self.offset = fdt_util.GetInt(self._node, 'offset')
self.size = fdt_util.GetInt(self._node, 'size')
self.align = fdt_util.GetInt(self._node, 'align')
"of two" % (self._node.path, self.align_size))
self.align_end = fdt_util.GetInt(self._node, 'align-end')
self.offset_unset = fdt_util.GetBool(self._node, 'offset-unset')
+ self.expand_size = fdt_util.GetBool(self._node, 'expand-size')
+
+ def GetDefaultFilename(self):
+ return None
+
+ def GetFdtSet(self):
+ """Get the set of device trees used by this entry
+
+ Returns:
+ Set containing the filename from this entry, if it is a .dtb, else
+ an empty set
+ """
+ fname = self.GetDefaultFilename()
+ # It would be better to use isinstance(self, Entry_blob_dtb) here but
+ # we cannot access Entry_blob_dtb
+ if fname and fname.endswith('.dtb'):
+ return Set([fname])
+ return Set()
+
+ def ExpandEntries(self):
+ pass
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:
- self._node.AddZeroProp(prop)
+ state.AddZeroProp(self._node, prop)
+ err = state.CheckAddHashProp(self._node)
+ if err:
+ self.Raise(err)
def SetCalculatedProperties(self):
"""Set the value of device-tree properties calculated by binman"""
- self._node.SetInt('offset', self.offset)
- self._node.SetInt('size', self.size)
- self._node.SetInt('image-pos', self.image_pos)
+ state.SetInt(self._node, 'offset', self.offset)
+ state.SetInt(self._node, 'size', self.size)
+ state.SetInt(self._node, 'image-pos',
+ self.image_pos - self.section.GetRootSkipAtStart())
+ state.CheckSetHashValue(self._node, self.GetData)
def ProcessFdt(self, fdt):
+ """Allow entries to adjust the device tree
+
+ Some entries need to adjust the device tree for their purposes. This
+ may involve adding or deleting properties.
+
+ Returns:
+ True if processing is complete
+ False if processing could not be completed due to a dependency.
+ This will cause the entry to be retried after others have been
+ called
+ """
return True
def SetPrefix(self, prefix):
pass
@staticmethod
- def WriteMapLine(fd, indent, name, offset, size):
- print('%s%08x %08x %s' % (' ' * indent, offset, size, name), file=fd)
+ def GetStr(value):
+ if value is None:
+ return '<none> '
+ return '%08x' % value
+
+ @staticmethod
+ def WriteMapLine(fd, indent, name, offset, size, image_pos):
+ print('%s %s%s %s %s' % (Entry.GetStr(image_pos), ' ' * indent,
+ Entry.GetStr(offset), Entry.GetStr(size),
+ name), file=fd)
def WriteMap(self, fd, indent):
"""Write a map of the entry to a .map file
fd: File to write the map to
indent: Curent indent level of map (0=none, 1=one level, etc.)
"""
- self.WriteMapLine(fd, indent, self.name, self.offset, self.size)
+ self.WriteMapLine(fd, indent, self.name, self.offset, self.size,
+ self.image_pos)
+
+ def GetEntries(self):
+ """Return a list of entries contained by this entry
+
+ Returns:
+ List of entries, or None if none. A normal entry has no entries
+ within it so will return None
+ """
+ return None
def GetArg(self, name, datatype=str):
"""Get the value of an entry argument or device-tree-node property
Raises:
ValueError if the argument cannot be converted to in
"""
- value = control.GetEntryArg(name)
+ value = state.GetEntryArg(name)
if value is not None:
if datatype == int:
try:
else:
value = fdt_util.GetDatatype(self._node, name, datatype)
return value
+
+ @staticmethod
+ def WriteDocs(modules, test_missing=None):
+ """Write out documentation about the various entry types to stdout
+
+ Args:
+ modules: List of modules to include
+ test_missing: Used for testing. This is a module to report
+ as missing
+ """
+ print('''Binman Entry Documentation
+===========================
+
+This file describes the entry types supported by binman. These entry types can
+be placed in an image one by one to build up a final firmware image. It is
+fairly easy to create new entry types. Just add a new file to the 'etype'
+directory. You can use the existing entries as examples.
+
+Note that some entries are subclasses of others, using and extending their
+features to produce new behaviours.
+
+
+''')
+ modules = sorted(modules)
+
+ # Don't show the test entry
+ if '_testing' in modules:
+ modules.remove('_testing')
+ missing = []
+ for name in modules:
+ module = Entry.Lookup(name, name, name)
+ docs = getattr(module, '__doc__')
+ if test_missing == name:
+ docs = None
+ if docs:
+ lines = docs.splitlines()
+ first_line = lines[0]
+ rest = [line[4:] for line in lines[1:]]
+ hdr = 'Entry: %s: %s' % (name.replace('_', '-'), first_line)
+ print(hdr)
+ print('-' * len(hdr))
+ print('\n'.join(rest))
+ print()
+ print()
+ else:
+ missing.append(name)
+
+ if missing:
+ raise ValueError('Documentation is missing for modules: %s' %
+ ', '.join(missing))
+
+ def GetUniqueName(self):
+ """Get a unique name for a node
+
+ Returns:
+ String containing a unique name for a node, consisting of the name
+ of all ancestors (starting from within the 'binman' node) separated
+ by a dot ('.'). This can be useful for generating unique filesnames
+ in the output directory.
+ """
+ name = self.name
+ node = self._node
+ while node.parent:
+ node = node.parent
+ if node.name == 'binman':
+ break
+ name = '%s.%s' % (node.name, name)
+ return name
+
+ def ExpandToLimit(self, limit):
+ """Expand an entry so that it ends at the given offset limit"""
+ if self.offset + self.size < limit:
+ self.size = limit - self.offset
+ # Request the contents again, since changing the size requires that
+ # the data grows. This should not fail, but check it to be sure.
+ if not self.ObtainContents():
+ self.Raise('Cannot obtain contents when expanding entry')