blob: 5374178542ed1bde020d326bf48e9a6d88a5599f [file] [log] [blame]
Tom Rini83d290c2018-05-06 17:58:06 -04001# SPDX-License-Identifier: GPL-2.0+
Simon Glassbf7fd502016-11-25 20:15:51 -07002# Copyright (c) 2016 Google, Inc
3#
Simon Glassbf7fd502016-11-25 20:15:51 -07004# Base class for all entries
5#
6
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
10try:
11 import importlib
12 have_importlib = True
13except:
14 have_importlib = False
15
16import fdt_util
Simon Glassbadf0ec2018-06-01 09:38:15 -060017import os
18import sys
Simon Glassbf7fd502016-11-25 20:15:51 -070019import tools
20
21modules = {}
22
Simon Glassbadf0ec2018-06-01 09:38:15 -060023our_path = os.path.dirname(os.path.realpath(__file__))
24
Simon Glassbf7fd502016-11-25 20:15:51 -070025class Entry(object):
Simon Glass25ac0e62018-06-01 09:38:14 -060026 """An Entry in the section
Simon Glassbf7fd502016-11-25 20:15:51 -070027
28 An entry corresponds to a single node in the device-tree description
Simon Glass25ac0e62018-06-01 09:38:14 -060029 of the section. Each entry ends up being a part of the final section.
Simon Glassbf7fd502016-11-25 20:15:51 -070030 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.
32
33 This class is not used by itself. All entry objects are subclasses of
34 Entry.
35
36 Attributes:
Simon Glass25ac0e62018-06-01 09:38:14 -060037 section: The section containing this entry
Simon Glassbf7fd502016-11-25 20:15:51 -070038 node: The node that created this entry
Simon Glass25ac0e62018-06-01 09:38:14 -060039 pos: Absolute position of entry within the section, None if not known
Simon Glassbf7fd502016-11-25 20:15:51 -070040 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)
48 """
Simon Glass25ac0e62018-06-01 09:38:14 -060049 def __init__(self, section, etype, node, read_node=True):
50 self.section = section
Simon Glassbf7fd502016-11-25 20:15:51 -070051 self.etype = etype
52 self._node = node
53 self.pos = None
54 self.size = None
55 self.contents_size = 0
56 self.align = None
57 self.align_size = None
58 self.align_end = None
59 self.pad_before = 0
60 self.pad_after = 0
61 self.pos_unset = False
62 if read_node:
63 self.ReadNode()
64
65 @staticmethod
Simon Glass25ac0e62018-06-01 09:38:14 -060066 def Create(section, node, etype=None):
Simon Glassbf7fd502016-11-25 20:15:51 -070067 """Create a new entry for a node.
68
69 Args:
Simon Glass25ac0e62018-06-01 09:38:14 -060070 section: Image object containing this node
Simon Glassbf7fd502016-11-25 20:15:51 -070071 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)
73
74 Returns:
75 A new Entry object of the correct type (a subclass of Entry)
76 """
77 if not etype:
78 etype = fdt_util.GetString(node, 'type', node.name)
Simon Glassdd57c132018-06-01 09:38:11 -060079
80 # Convert something like 'u-boot@0' to 'u_boot' since we are only
81 # interested in the type.
Simon Glassbf7fd502016-11-25 20:15:51 -070082 module_name = etype.replace('-', '_')
Simon Glassdd57c132018-06-01 09:38:11 -060083 if '@' in module_name:
84 module_name = module_name.split('@')[0]
Simon Glassbf7fd502016-11-25 20:15:51 -070085 module = modules.get(module_name)
86
Simon Glassbadf0ec2018-06-01 09:38:15 -060087 # Also allow entry-type modules to be brought in from the etype directory.
88
Simon Glassbf7fd502016-11-25 20:15:51 -070089 # Import the module if we have not already done so.
90 if not module:
Simon Glassbadf0ec2018-06-01 09:38:15 -060091 old_path = sys.path
92 sys.path.insert(0, os.path.join(our_path, 'etype'))
Simon Glassbf7fd502016-11-25 20:15:51 -070093 try:
94 if have_importlib:
95 module = importlib.import_module(module_name)
96 else:
97 module = __import__(module_name)
98 except ImportError:
99 raise ValueError("Unknown entry type '%s' in node '%s'" %
100 (etype, node.path))
Simon Glassbadf0ec2018-06-01 09:38:15 -0600101 finally:
102 sys.path = old_path
Simon Glassbf7fd502016-11-25 20:15:51 -0700103 modules[module_name] = module
104
105 # Call its constructor to get the object we want.
106 obj = getattr(module, 'Entry_%s' % module_name)
Simon Glass25ac0e62018-06-01 09:38:14 -0600107 return obj(section, etype, node)
Simon Glassbf7fd502016-11-25 20:15:51 -0700108
109 def ReadNode(self):
110 """Read entry information from the node
111
112 This reads all the fields we recognise from the node, ready for use.
113 """
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')
128
129 def ObtainContents(self):
130 """Figure out the contents of an entry.
131
132 Returns:
133 True if the contents were found, False if another call is needed
134 after the other entries are processed.
135 """
136 # No contents by default: subclasses can implement this
137 return True
138
139 def Pack(self, pos):
Simon Glass25ac0e62018-06-01 09:38:14 -0600140 """Figure out how to pack the entry into the section
Simon Glassbf7fd502016-11-25 20:15:51 -0700141
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.
145
146 If an entry has no hard-coded position, it will be placed at @pos.
147
148 Once this function is complete, both the position and size of the
149 entry will be know.
150
151 Args:
Simon Glass25ac0e62018-06-01 09:38:14 -0600152 Current section position pointer
Simon Glassbf7fd502016-11-25 20:15:51 -0700153
154 Returns:
Simon Glass25ac0e62018-06-01 09:38:14 -0600155 New section position pointer (after this entry)
Simon Glassbf7fd502016-11-25 20:15:51 -0700156 """
157 if self.pos is None:
158 if self.pos_unset:
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)
164 size = self.size
165 if not size:
166 size = needed
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
172
173 if not self.size:
174 self.size = size
175
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))
188
189 return new_pos
190
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))
194
195 def GetPath(self):
196 """Get the path of a node
197
198 Returns:
199 Full path of the node for this entry
200 """
201 return self._node.path
202
203 def GetData(self):
204 return self.data
205
206 def GetPositions(self):
207 return {}
208
209 def SetPositionSize(self, pos, size):
210 self.pos = pos
211 self.size = size
212
213 def ProcessContents(self):
214 pass
Simon Glass19790632017-11-13 18:55:01 -0700215
Simon Glassf55382b2018-06-01 09:38:13 -0600216 def WriteSymbols(self, section):
Simon Glass19790632017-11-13 18:55:01 -0700217 """Write symbol values into binary files for access at run time
218
219 Args:
Simon Glassf55382b2018-06-01 09:38:13 -0600220 section: Section containing the entry
Simon Glass19790632017-11-13 18:55:01 -0700221 """
222 pass