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)
76 # Convert something like 'u-boot@0' to 'u_boot' since we are only
77 # interested in the type.
78 module_name = etype.replace('-', '_')
79 if '@' in module_name:
80 module_name = module_name.split('@')[0]
81 module = modules.get(module_name)
83 # Import the module if we have not already done so.
87 module = importlib.import_module(module_name)
89 module = __import__(module_name)
91 raise ValueError("Unknown entry type '%s' in node '%s'" %
93 modules[module_name] = module
95 # Call its constructor to get the object we want.
96 obj = getattr(module, 'Entry_%s' % module_name)
97 return obj(image, etype, node)
100 """Read entry information from the node
102 This reads all the fields we recognise from the node, ready for use.
104 self.pos = fdt_util.GetInt(self._node, 'pos')
105 self.size = fdt_util.GetInt(self._node, 'size')
106 self.align = fdt_util.GetInt(self._node, 'align')
107 if tools.NotPowerOfTwo(self.align):
108 raise ValueError("Node '%s': Alignment %s must be a power of two" %
109 (self._node.path, self.align))
110 self.pad_before = fdt_util.GetInt(self._node, 'pad-before', 0)
111 self.pad_after = fdt_util.GetInt(self._node, 'pad-after', 0)
112 self.align_size = fdt_util.GetInt(self._node, 'align-size')
113 if tools.NotPowerOfTwo(self.align_size):
114 raise ValueError("Node '%s': Alignment size %s must be a power "
115 "of two" % (self._node.path, self.align_size))
116 self.align_end = fdt_util.GetInt(self._node, 'align-end')
117 self.pos_unset = fdt_util.GetBool(self._node, 'pos-unset')
119 def ObtainContents(self):
120 """Figure out the contents of an entry.
123 True if the contents were found, False if another call is needed
124 after the other entries are processed.
126 # No contents by default: subclasses can implement this
130 """Figure out how to pack the entry into the image
132 Most of the time the entries are not fully specified. There may be
133 an alignment but no size. In that case we take the size from the
134 contents of the entry.
136 If an entry has no hard-coded position, it will be placed at @pos.
138 Once this function is complete, both the position and size of the
142 Current image position pointer
145 New image position pointer (after this entry)
149 self.Raise('No position set with pos-unset: should another '
150 'entry provide this correct position?')
151 self.pos = tools.Align(pos, self.align)
152 needed = self.pad_before + self.contents_size + self.pad_after
153 needed = tools.Align(needed, self.align_size)
157 new_pos = self.pos + size
158 aligned_pos = tools.Align(new_pos, self.align_end)
159 if aligned_pos != new_pos:
160 size = aligned_pos - self.pos
161 new_pos = aligned_pos
166 if self.size < needed:
167 self.Raise("Entry contents size is %#x (%d) but entry size is "
168 "%#x (%d)" % (needed, needed, self.size, self.size))
169 # Check that the alignment is correct. It could be wrong if the
170 # and pos or size values were provided (i.e. not calculated), but
171 # conflict with the provided alignment values
172 if self.size != tools.Align(self.size, self.align_size):
173 self.Raise("Size %#x (%d) does not match align-size %#x (%d)" %
174 (self.size, self.size, self.align_size, self.align_size))
175 if self.pos != tools.Align(self.pos, self.align):
176 self.Raise("Position %#x (%d) does not match align %#x (%d)" %
177 (self.pos, self.pos, self.align, self.align))
181 def Raise(self, msg):
182 """Convenience function to raise an error referencing a node"""
183 raise ValueError("Node '%s': %s" % (self._node.path, msg))
186 """Get the path of a node
189 Full path of the node for this entry
191 return self._node.path
196 def GetPositions(self):
199 def SetPositionSize(self, pos, size):
203 def ProcessContents(self):
206 def WriteSymbols(self, section):
207 """Write symbol values into binary files for access at run time
210 section: Section containing the entry