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
23 our_path = os.path.dirname(os.path.realpath(__file__))
26 """An Entry in the section
28 An entry corresponds to a single node in the device-tree description
29 of the section. Each entry ends up being a part of the final section.
30 Entries can be placed either right next to each other, or with padding
31 between them. The type of the entry determines the data that is in it.
33 This class is not used by itself. All entry objects are subclasses of
37 section: The section containing this entry
38 node: The node that created this entry
39 pos: Absolute position of entry within the section, None if not known
40 size: Entry size in bytes, None if not known
41 contents_size: Size of contents in bytes, 0 by default
42 align: Entry start position alignment, or None
43 align_size: Entry size alignment, or None
44 align_end: Entry end position alignment, or None
45 pad_before: Number of pad bytes before the contents, 0 if none
46 pad_after: Number of pad bytes after the contents, 0 if none
47 data: Contents of entry (string of bytes)
49 def __init__(self, section, etype, node, read_node=True):
50 self.section = section
55 self.contents_size = 0
57 self.align_size = None
61 self.pos_unset = False
66 def Create(section, node, etype=None):
67 """Create a new entry for a node.
70 section: Image object containing this node
71 node: Node object containing information about the entry to create
72 etype: Entry type to use, or None to work it out (used for tests)
75 A new Entry object of the correct type (a subclass of Entry)
78 etype = fdt_util.GetString(node, 'type', node.name)
80 # Convert something like 'u-boot@0' to 'u_boot' since we are only
81 # interested in the type.
82 module_name = etype.replace('-', '_')
83 if '@' in module_name:
84 module_name = module_name.split('@')[0]
85 module = modules.get(module_name)
87 # Also allow entry-type modules to be brought in from the etype directory.
89 # Import the module if we have not already done so.
92 sys.path.insert(0, os.path.join(our_path, 'etype'))
95 module = importlib.import_module(module_name)
97 module = __import__(module_name)
99 raise ValueError("Unknown entry type '%s' in node '%s'" %
103 modules[module_name] = module
105 # Call its constructor to get the object we want.
106 obj = getattr(module, 'Entry_%s' % module_name)
107 return obj(section, etype, node)
110 """Read entry information from the node
112 This reads all the fields we recognise from the node, ready for use.
114 self.pos = fdt_util.GetInt(self._node, 'pos')
115 self.size = fdt_util.GetInt(self._node, 'size')
116 self.align = fdt_util.GetInt(self._node, 'align')
117 if tools.NotPowerOfTwo(self.align):
118 raise ValueError("Node '%s': Alignment %s must be a power of two" %
119 (self._node.path, self.align))
120 self.pad_before = fdt_util.GetInt(self._node, 'pad-before', 0)
121 self.pad_after = fdt_util.GetInt(self._node, 'pad-after', 0)
122 self.align_size = fdt_util.GetInt(self._node, 'align-size')
123 if tools.NotPowerOfTwo(self.align_size):
124 raise ValueError("Node '%s': Alignment size %s must be a power "
125 "of two" % (self._node.path, self.align_size))
126 self.align_end = fdt_util.GetInt(self._node, 'align-end')
127 self.pos_unset = fdt_util.GetBool(self._node, 'pos-unset')
129 def ObtainContents(self):
130 """Figure out the contents of an entry.
133 True if the contents were found, False if another call is needed
134 after the other entries are processed.
136 # No contents by default: subclasses can implement this
140 """Figure out how to pack the entry into the section
142 Most of the time the entries are not fully specified. There may be
143 an alignment but no size. In that case we take the size from the
144 contents of the entry.
146 If an entry has no hard-coded position, it will be placed at @pos.
148 Once this function is complete, both the position and size of the
152 Current section position pointer
155 New section position pointer (after this entry)
159 self.Raise('No position set with pos-unset: should another '
160 'entry provide this correct position?')
161 self.pos = tools.Align(pos, self.align)
162 needed = self.pad_before + self.contents_size + self.pad_after
163 needed = tools.Align(needed, self.align_size)
167 new_pos = self.pos + size
168 aligned_pos = tools.Align(new_pos, self.align_end)
169 if aligned_pos != new_pos:
170 size = aligned_pos - self.pos
171 new_pos = aligned_pos
176 if self.size < needed:
177 self.Raise("Entry contents size is %#x (%d) but entry size is "
178 "%#x (%d)" % (needed, needed, self.size, self.size))
179 # Check that the alignment is correct. It could be wrong if the
180 # and pos or size values were provided (i.e. not calculated), but
181 # conflict with the provided alignment values
182 if self.size != tools.Align(self.size, self.align_size):
183 self.Raise("Size %#x (%d) does not match align-size %#x (%d)" %
184 (self.size, self.size, self.align_size, self.align_size))
185 if self.pos != tools.Align(self.pos, self.align):
186 self.Raise("Position %#x (%d) does not match align %#x (%d)" %
187 (self.pos, self.pos, self.align, self.align))
191 def Raise(self, msg):
192 """Convenience function to raise an error referencing a node"""
193 raise ValueError("Node '%s': %s" % (self._node.path, msg))
196 """Get the path of a node
199 Full path of the node for this entry
201 return self._node.path
206 def GetPositions(self):
209 def SetPositionSize(self, pos, size):
213 def ProcessContents(self):
216 def WriteSymbols(self, section):
217 """Write symbol values into binary files for access at run time
220 section: Section containing the entry