1 # SPDX-License-Identifier: GPL-2.0+
2 # Copyright (c) 2016 Google, Inc
4 # Base class for all entries
7 # importlib was introduced in Python 2.7 but there was a report of it not
8 # working in 2.7.12, so we work around this:
9 # http://lists.denx.de/pipermail/u-boot/2016-October/269729.html
14 have_importlib = False
22 """An Entry in the image
24 An entry corresponds to a single node in the device-tree description
25 of the image. Each entry ends up being a part of the final image.
26 Entries can be placed either right next to each other, or with padding
27 between them. The type of the entry determines the data that is in it.
29 This class is not used by itself. All entry objects are subclasses of
33 image: The image containing this entry
34 node: The node that created this entry
35 pos: Absolute position of entry within the image, None if not known
36 size: Entry size in bytes, None if not known
37 contents_size: Size of contents in bytes, 0 by default
38 align: Entry start position alignment, or None
39 align_size: Entry size alignment, or None
40 align_end: Entry end position alignment, or None
41 pad_before: Number of pad bytes before the contents, 0 if none
42 pad_after: Number of pad bytes after the contents, 0 if none
43 data: Contents of entry (string of bytes)
45 def __init__(self, image, etype, node, read_node=True):
51 self.contents_size = 0
53 self.align_size = None
57 self.pos_unset = False
62 def Create(image, node, etype=None):
63 """Create a new entry for a node.
66 image: Image object containing this node
67 node: Node object containing information about the entry to create
68 etype: Entry type to use, or None to work it out (used for tests)
71 A new Entry object of the correct type (a subclass of Entry)
74 etype = fdt_util.GetString(node, 'type', node.name)
75 module_name = etype.replace('-', '_')
76 module = modules.get(module_name)
78 # Import the module if we have not already done so.
82 module = importlib.import_module(module_name)
84 module = __import__(module_name)
86 raise ValueError("Unknown entry type '%s' in node '%s'" %
88 modules[module_name] = module
90 # Call its constructor to get the object we want.
91 obj = getattr(module, 'Entry_%s' % module_name)
92 return obj(image, etype, node)
95 """Read entry information from the node
97 This reads all the fields we recognise from the node, ready for use.
99 self.pos = fdt_util.GetInt(self._node, 'pos')
100 self.size = fdt_util.GetInt(self._node, 'size')
101 self.align = fdt_util.GetInt(self._node, 'align')
102 if tools.NotPowerOfTwo(self.align):
103 raise ValueError("Node '%s': Alignment %s must be a power of two" %
104 (self._node.path, self.align))
105 self.pad_before = fdt_util.GetInt(self._node, 'pad-before', 0)
106 self.pad_after = fdt_util.GetInt(self._node, 'pad-after', 0)
107 self.align_size = fdt_util.GetInt(self._node, 'align-size')
108 if tools.NotPowerOfTwo(self.align_size):
109 raise ValueError("Node '%s': Alignment size %s must be a power "
110 "of two" % (self._node.path, self.align_size))
111 self.align_end = fdt_util.GetInt(self._node, 'align-end')
112 self.pos_unset = fdt_util.GetBool(self._node, 'pos-unset')
114 def ObtainContents(self):
115 """Figure out the contents of an entry.
118 True if the contents were found, False if another call is needed
119 after the other entries are processed.
121 # No contents by default: subclasses can implement this
125 """Figure out how to pack the entry into the image
127 Most of the time the entries are not fully specified. There may be
128 an alignment but no size. In that case we take the size from the
129 contents of the entry.
131 If an entry has no hard-coded position, it will be placed at @pos.
133 Once this function is complete, both the position and size of the
137 Current image position pointer
140 New image position pointer (after this entry)
144 self.Raise('No position set with pos-unset: should another '
145 'entry provide this correct position?')
146 self.pos = tools.Align(pos, self.align)
147 needed = self.pad_before + self.contents_size + self.pad_after
148 needed = tools.Align(needed, self.align_size)
152 new_pos = self.pos + size
153 aligned_pos = tools.Align(new_pos, self.align_end)
154 if aligned_pos != new_pos:
155 size = aligned_pos - self.pos
156 new_pos = aligned_pos
161 if self.size < needed:
162 self.Raise("Entry contents size is %#x (%d) but entry size is "
163 "%#x (%d)" % (needed, needed, self.size, self.size))
164 # Check that the alignment is correct. It could be wrong if the
165 # and pos or size values were provided (i.e. not calculated), but
166 # conflict with the provided alignment values
167 if self.size != tools.Align(self.size, self.align_size):
168 self.Raise("Size %#x (%d) does not match align-size %#x (%d)" %
169 (self.size, self.size, self.align_size, self.align_size))
170 if self.pos != tools.Align(self.pos, self.align):
171 self.Raise("Position %#x (%d) does not match align %#x (%d)" %
172 (self.pos, self.pos, self.align, self.align))
176 def Raise(self, msg):
177 """Convenience function to raise an error referencing a node"""
178 raise ValueError("Node '%s': %s" % (self._node.path, msg))
181 """Get the path of a node
184 Full path of the node for this entry
186 return self._node.path
191 def GetPositions(self):
194 def SetPositionSize(self, pos, size):
198 def ProcessContents(self):
201 def WriteSymbols(self, image):
202 """Write symbol values into binary files for access at run time
205 image: Image containing the entry