]> git.ipfire.org Git - thirdparty/u-boot.git/blob - tools/binman/etype/entry.py
SPDX: Convert all of our single license tags to Linux Kernel style
[thirdparty/u-boot.git] / tools / binman / etype / entry.py
1 # SPDX-License-Identifier: GPL-2.0+
2 # Copyright (c) 2016 Google, Inc
3 #
4 # 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
10 try:
11 import importlib
12 have_importlib = True
13 except:
14 have_importlib = False
15
16 import fdt_util
17 import tools
18
19 modules = {}
20
21 class Entry(object):
22 """An Entry in the image
23
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.
28
29 This class is not used by itself. All entry objects are subclasses of
30 Entry.
31
32 Attributes:
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)
44 """
45 def __init__(self, image, etype, node, read_node=True):
46 self.image = image
47 self.etype = etype
48 self._node = node
49 self.pos = None
50 self.size = None
51 self.contents_size = 0
52 self.align = None
53 self.align_size = None
54 self.align_end = None
55 self.pad_before = 0
56 self.pad_after = 0
57 self.pos_unset = False
58 if read_node:
59 self.ReadNode()
60
61 @staticmethod
62 def Create(image, node, etype=None):
63 """Create a new entry for a node.
64
65 Args:
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)
69
70 Returns:
71 A new Entry object of the correct type (a subclass of Entry)
72 """
73 if not etype:
74 etype = fdt_util.GetString(node, 'type', node.name)
75 module_name = etype.replace('-', '_')
76 module = modules.get(module_name)
77
78 # Import the module if we have not already done so.
79 if not module:
80 try:
81 if have_importlib:
82 module = importlib.import_module(module_name)
83 else:
84 module = __import__(module_name)
85 except ImportError:
86 raise ValueError("Unknown entry type '%s' in node '%s'" %
87 (etype, node.path))
88 modules[module_name] = module
89
90 # Call its constructor to get the object we want.
91 obj = getattr(module, 'Entry_%s' % module_name)
92 return obj(image, etype, node)
93
94 def ReadNode(self):
95 """Read entry information from the node
96
97 This reads all the fields we recognise from the node, ready for use.
98 """
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')
113
114 def ObtainContents(self):
115 """Figure out the contents of an entry.
116
117 Returns:
118 True if the contents were found, False if another call is needed
119 after the other entries are processed.
120 """
121 # No contents by default: subclasses can implement this
122 return True
123
124 def Pack(self, pos):
125 """Figure out how to pack the entry into the image
126
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.
130
131 If an entry has no hard-coded position, it will be placed at @pos.
132
133 Once this function is complete, both the position and size of the
134 entry will be know.
135
136 Args:
137 Current image position pointer
138
139 Returns:
140 New image position pointer (after this entry)
141 """
142 if self.pos is None:
143 if self.pos_unset:
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)
149 size = self.size
150 if not size:
151 size = needed
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
157
158 if not self.size:
159 self.size = size
160
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))
173
174 return new_pos
175
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))
179
180 def GetPath(self):
181 """Get the path of a node
182
183 Returns:
184 Full path of the node for this entry
185 """
186 return self._node.path
187
188 def GetData(self):
189 return self.data
190
191 def GetPositions(self):
192 return {}
193
194 def SetPositionSize(self, pos, size):
195 self.pos = pos
196 self.size = size
197
198 def ProcessContents(self):
199 pass
200
201 def WriteSymbols(self, image):
202 """Write symbol values into binary files for access at run time
203
204 Args:
205 image: Image containing the entry
206 """
207 pass