blob: bac90bbbcde25794ca3d75657e7a7d3100ea7f95 [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
Simon Glass53af22a2018-07-17 13:25:32 -06007from collections import namedtuple
Simon Glassb4cf5f12019-10-31 07:42:59 -06008import importlib
Simon Glassbadf0ec2018-06-01 09:38:15 -06009import os
Simon Glass790ba9f2022-01-12 13:10:36 -070010import pathlib
Simon Glassbadf0ec2018-06-01 09:38:15 -060011import sys
Simon Glassc55a50f2018-09-14 04:57:19 -060012
Simon Glass16287932020-04-17 18:09:03 -060013from dtoc import fdt_util
Simon Glassbf776672020-04-17 18:09:04 -060014from patman import tools
Simon Glass16287932020-04-17 18:09:03 -060015from patman.tools import ToHex, ToHexSize
Simon Glassbf776672020-04-17 18:09:04 -060016from patman import tout
Simon Glassbf7fd502016-11-25 20:15:51 -070017
18modules = {}
19
Simon Glass53af22a2018-07-17 13:25:32 -060020
21# An argument which can be passed to entries on the command line, in lieu of
22# device-tree properties.
23EntryArg = namedtuple('EntryArg', ['name', 'datatype'])
24
Simon Glass41b8ba02019-07-08 14:25:43 -060025# Information about an entry for use when displaying summaries
26EntryInfo = namedtuple('EntryInfo', ['indent', 'name', 'etype', 'size',
27 'image_pos', 'uncomp_size', 'offset',
28 'entry'])
Simon Glass53af22a2018-07-17 13:25:32 -060029
Simon Glassbf7fd502016-11-25 20:15:51 -070030class Entry(object):
Simon Glass25ac0e62018-06-01 09:38:14 -060031 """An Entry in the section
Simon Glassbf7fd502016-11-25 20:15:51 -070032
33 An entry corresponds to a single node in the device-tree description
Simon Glass25ac0e62018-06-01 09:38:14 -060034 of the section. Each entry ends up being a part of the final section.
Simon Glassbf7fd502016-11-25 20:15:51 -070035 Entries can be placed either right next to each other, or with padding
36 between them. The type of the entry determines the data that is in it.
37
38 This class is not used by itself. All entry objects are subclasses of
39 Entry.
40
41 Attributes:
Simon Glass8122f392018-07-17 13:25:28 -060042 section: Section object containing this entry
Simon Glassbf7fd502016-11-25 20:15:51 -070043 node: The node that created this entry
Simon Glass3ab95982018-08-01 15:22:37 -060044 offset: Offset of entry within the section, None if not known yet (in
45 which case it will be calculated by Pack())
Simon Glassbf7fd502016-11-25 20:15:51 -070046 size: Entry size in bytes, None if not known
Simon Glass9a5d3dc2019-10-31 07:43:02 -060047 pre_reset_size: size as it was before ResetForPack(). This allows us to
48 keep track of the size we started with and detect size changes
Simon Glass8287ee82019-07-08 14:25:30 -060049 uncomp_size: Size of uncompressed data in bytes, if the entry is
50 compressed, else None
Simon Glassbf7fd502016-11-25 20:15:51 -070051 contents_size: Size of contents in bytes, 0 by default
Simon Glass4eec34c2020-10-26 17:40:10 -060052 align: Entry start offset alignment relative to the start of the
53 containing section, or None
Simon Glassbf7fd502016-11-25 20:15:51 -070054 align_size: Entry size alignment, or None
Simon Glass4eec34c2020-10-26 17:40:10 -060055 align_end: Entry end offset alignment relative to the start of the
56 containing section, or None
Simon Glassf90d9062020-10-26 17:40:09 -060057 pad_before: Number of pad bytes before the contents when it is placed
58 in the containing section, 0 if none. The pad bytes become part of
59 the entry.
60 pad_after: Number of pad bytes after the contents when it is placed in
61 the containing section, 0 if none. The pad bytes become part of
62 the entry.
63 data: Contents of entry (string of bytes). This does not include
Simon Glass97c3e9a2020-10-26 17:40:15 -060064 padding created by pad_before or pad_after. If the entry is
65 compressed, this contains the compressed data.
66 uncomp_data: Original uncompressed data, if this entry is compressed,
67 else None
Simon Glass8287ee82019-07-08 14:25:30 -060068 compress: Compression algoithm used (e.g. 'lz4'), 'none' if none
Simon Glassc52c9e72019-07-08 14:25:37 -060069 orig_offset: Original offset value read from node
70 orig_size: Original size value read from node
Simon Glass87958982020-09-01 05:13:57 -060071 missing: True if this entry is missing its contents
72 allow_missing: Allow children of this entry to be missing (used by
73 subclasses such as Entry_section)
Heiko Thierya89c8f22022-01-06 11:49:41 +010074 allow_fake: Allow creating a dummy fake file if the blob file is not
75 available. This is mainly used for testing.
Simon Glass87958982020-09-01 05:13:57 -060076 external: True if this entry contains an external binary blob
Simon Glassbf7fd502016-11-25 20:15:51 -070077 """
Simon Glassc6bd6e22019-07-20 12:23:45 -060078 def __init__(self, section, etype, node, name_prefix=''):
Simon Glass8dbb7442019-08-24 07:22:44 -060079 # Put this here to allow entry-docs and help to work without libfdt
80 global state
Simon Glass16287932020-04-17 18:09:03 -060081 from binman import state
Simon Glass8dbb7442019-08-24 07:22:44 -060082
Simon Glass25ac0e62018-06-01 09:38:14 -060083 self.section = section
Simon Glassbf7fd502016-11-25 20:15:51 -070084 self.etype = etype
85 self._node = node
Simon Glassc8d48ef2018-06-01 09:38:21 -060086 self.name = node and (name_prefix + node.name) or 'none'
Simon Glass3ab95982018-08-01 15:22:37 -060087 self.offset = None
Simon Glassbf7fd502016-11-25 20:15:51 -070088 self.size = None
Simon Glass9a5d3dc2019-10-31 07:43:02 -060089 self.pre_reset_size = None
Simon Glass8287ee82019-07-08 14:25:30 -060090 self.uncomp_size = None
Simon Glass24d0d3c2018-07-17 13:25:47 -060091 self.data = None
Simon Glass97c3e9a2020-10-26 17:40:15 -060092 self.uncomp_data = None
Simon Glassbf7fd502016-11-25 20:15:51 -070093 self.contents_size = 0
94 self.align = None
95 self.align_size = None
96 self.align_end = None
97 self.pad_before = 0
98 self.pad_after = 0
Simon Glass3ab95982018-08-01 15:22:37 -060099 self.offset_unset = False
Simon Glassdbf6be92018-08-01 15:22:42 -0600100 self.image_pos = None
Simon Glassc4738312021-11-23 11:03:43 -0700101 self.expand_size = False
Simon Glass8287ee82019-07-08 14:25:30 -0600102 self.compress = 'none'
Simon Glassb1cca952020-07-09 18:39:40 -0600103 self.missing = False
Heiko Thierya89c8f22022-01-06 11:49:41 +0100104 self.faked = False
Simon Glass87958982020-09-01 05:13:57 -0600105 self.external = False
106 self.allow_missing = False
Heiko Thierya89c8f22022-01-06 11:49:41 +0100107 self.allow_fake = False
Simon Glassbf7fd502016-11-25 20:15:51 -0700108
109 @staticmethod
Simon Glass858436d2021-11-23 21:09:49 -0700110 def FindEntryClass(etype, expanded):
Simon Glassfd8d1f72018-07-17 13:25:36 -0600111 """Look up the entry class for a node.
Simon Glassbf7fd502016-11-25 20:15:51 -0700112
113 Args:
Simon Glassfd8d1f72018-07-17 13:25:36 -0600114 node_node: Path name of Node object containing information about
115 the entry to create (used for errors)
116 etype: Entry type to use
Simon Glassb35fb172021-03-18 20:25:04 +1300117 expanded: Use the expanded version of etype
Simon Glassbf7fd502016-11-25 20:15:51 -0700118
119 Returns:
Simon Glassb35fb172021-03-18 20:25:04 +1300120 The entry class object if found, else None if not found and expanded
Simon Glass858436d2021-11-23 21:09:49 -0700121 is True, else a tuple:
122 module name that could not be found
123 exception received
Simon Glassbf7fd502016-11-25 20:15:51 -0700124 """
Simon Glassdd57c132018-06-01 09:38:11 -0600125 # Convert something like 'u-boot@0' to 'u_boot' since we are only
126 # interested in the type.
Simon Glassbf7fd502016-11-25 20:15:51 -0700127 module_name = etype.replace('-', '_')
Simon Glassb35fb172021-03-18 20:25:04 +1300128
Simon Glassdd57c132018-06-01 09:38:11 -0600129 if '@' in module_name:
130 module_name = module_name.split('@')[0]
Simon Glassb35fb172021-03-18 20:25:04 +1300131 if expanded:
132 module_name += '_expanded'
Simon Glassbf7fd502016-11-25 20:15:51 -0700133 module = modules.get(module_name)
134
Simon Glassbadf0ec2018-06-01 09:38:15 -0600135 # Also allow entry-type modules to be brought in from the etype directory.
136
Simon Glassbf7fd502016-11-25 20:15:51 -0700137 # Import the module if we have not already done so.
138 if not module:
139 try:
Simon Glass16287932020-04-17 18:09:03 -0600140 module = importlib.import_module('binman.etype.' + module_name)
Simon Glassfd8d1f72018-07-17 13:25:36 -0600141 except ImportError as e:
Simon Glassb35fb172021-03-18 20:25:04 +1300142 if expanded:
143 return None
Simon Glass858436d2021-11-23 21:09:49 -0700144 return module_name, e
Simon Glassbf7fd502016-11-25 20:15:51 -0700145 modules[module_name] = module
146
Simon Glassfd8d1f72018-07-17 13:25:36 -0600147 # Look up the expected class name
148 return getattr(module, 'Entry_%s' % module_name)
149
150 @staticmethod
Simon Glass858436d2021-11-23 21:09:49 -0700151 def Lookup(node_path, etype, expanded, missing_etype=False):
152 """Look up the entry class for a node.
153
154 Args:
155 node_node (str): Path name of Node object containing information
156 about the entry to create (used for errors)
157 etype (str): Entry type to use
158 expanded (bool): Use the expanded version of etype
159 missing_etype (bool): True to default to a blob etype if the
160 requested etype is not found
161
162 Returns:
163 The entry class object if found, else None if not found and expanded
164 is True
165
166 Raise:
167 ValueError if expanded is False and the class is not found
168 """
169 # Convert something like 'u-boot@0' to 'u_boot' since we are only
170 # interested in the type.
171 cls = Entry.FindEntryClass(etype, expanded)
172 if cls is None:
173 return None
174 elif isinstance(cls, tuple):
175 if missing_etype:
176 cls = Entry.FindEntryClass('blob', False)
177 if isinstance(cls, tuple): # This should not fail
178 module_name, e = cls
179 raise ValueError(
180 "Unknown entry type '%s' in node '%s' (expected etype/%s.py, error '%s'" %
181 (etype, node_path, module_name, e))
182 return cls
183
184 @staticmethod
185 def Create(section, node, etype=None, expanded=False, missing_etype=False):
Simon Glassfd8d1f72018-07-17 13:25:36 -0600186 """Create a new entry for a node.
187
188 Args:
Simon Glass858436d2021-11-23 21:09:49 -0700189 section (entry_Section): Section object containing this node
190 node (Node): Node object containing information about the entry to
191 create
192 etype (str): Entry type to use, or None to work it out (used for
193 tests)
194 expanded (bool): Use the expanded version of etype
195 missing_etype (bool): True to default to a blob etype if the
196 requested etype is not found
Simon Glassfd8d1f72018-07-17 13:25:36 -0600197
198 Returns:
199 A new Entry object of the correct type (a subclass of Entry)
200 """
201 if not etype:
202 etype = fdt_util.GetString(node, 'type', node.name)
Simon Glass858436d2021-11-23 21:09:49 -0700203 obj = Entry.Lookup(node.path, etype, expanded, missing_etype)
Simon Glassb35fb172021-03-18 20:25:04 +1300204 if obj and expanded:
205 # Check whether to use the expanded entry
206 new_etype = etype + '-expanded'
Simon Glass3d433382021-03-21 18:24:30 +1300207 can_expand = not fdt_util.GetBool(node, 'no-expanded')
208 if can_expand and obj.UseExpanded(node, etype, new_etype):
Simon Glassb35fb172021-03-18 20:25:04 +1300209 etype = new_etype
210 else:
211 obj = None
212 if not obj:
Simon Glass858436d2021-11-23 21:09:49 -0700213 obj = Entry.Lookup(node.path, etype, False, missing_etype)
Simon Glassfd8d1f72018-07-17 13:25:36 -0600214
Simon Glassbf7fd502016-11-25 20:15:51 -0700215 # Call its constructor to get the object we want.
Simon Glass25ac0e62018-06-01 09:38:14 -0600216 return obj(section, etype, node)
Simon Glassbf7fd502016-11-25 20:15:51 -0700217
218 def ReadNode(self):
219 """Read entry information from the node
220
Simon Glassc6bd6e22019-07-20 12:23:45 -0600221 This must be called as the first thing after the Entry is created.
222
Simon Glassbf7fd502016-11-25 20:15:51 -0700223 This reads all the fields we recognise from the node, ready for use.
224 """
Simon Glass15a587c2018-07-17 13:25:51 -0600225 if 'pos' in self._node.props:
226 self.Raise("Please use 'offset' instead of 'pos'")
Simon Glass3ab95982018-08-01 15:22:37 -0600227 self.offset = fdt_util.GetInt(self._node, 'offset')
Simon Glassbf7fd502016-11-25 20:15:51 -0700228 self.size = fdt_util.GetInt(self._node, 'size')
Simon Glass12bb1a92019-07-20 12:23:51 -0600229 self.orig_offset = fdt_util.GetInt(self._node, 'orig-offset')
230 self.orig_size = fdt_util.GetInt(self._node, 'orig-size')
231 if self.GetImage().copy_to_orig:
232 self.orig_offset = self.offset
233 self.orig_size = self.size
Simon Glassc52c9e72019-07-08 14:25:37 -0600234
Simon Glassffded752019-07-08 14:25:46 -0600235 # These should not be set in input files, but are set in an FDT map,
236 # which is also read by this code.
237 self.image_pos = fdt_util.GetInt(self._node, 'image-pos')
238 self.uncomp_size = fdt_util.GetInt(self._node, 'uncomp-size')
239
Simon Glassbf7fd502016-11-25 20:15:51 -0700240 self.align = fdt_util.GetInt(self._node, 'align')
241 if tools.NotPowerOfTwo(self.align):
242 raise ValueError("Node '%s': Alignment %s must be a power of two" %
243 (self._node.path, self.align))
Simon Glass5ff9fed2021-03-21 18:24:33 +1300244 if self.section and self.align is None:
245 self.align = self.section.align_default
Simon Glassbf7fd502016-11-25 20:15:51 -0700246 self.pad_before = fdt_util.GetInt(self._node, 'pad-before', 0)
247 self.pad_after = fdt_util.GetInt(self._node, 'pad-after', 0)
248 self.align_size = fdt_util.GetInt(self._node, 'align-size')
249 if tools.NotPowerOfTwo(self.align_size):
Simon Glass8beb11e2019-07-08 14:25:47 -0600250 self.Raise("Alignment size %s must be a power of two" %
251 self.align_size)
Simon Glassbf7fd502016-11-25 20:15:51 -0700252 self.align_end = fdt_util.GetInt(self._node, 'align-end')
Simon Glass3ab95982018-08-01 15:22:37 -0600253 self.offset_unset = fdt_util.GetBool(self._node, 'offset-unset')
Simon Glassba64a0b2018-09-14 04:57:29 -0600254 self.expand_size = fdt_util.GetBool(self._node, 'expand-size')
Simon Glassb2381432020-09-06 10:39:09 -0600255 self.missing_msg = fdt_util.GetString(self._node, 'missing-msg')
Simon Glassbf7fd502016-11-25 20:15:51 -0700256
Simon Glass87c96292020-10-26 17:40:06 -0600257 # This is only supported by blobs and sections at present
258 self.compress = fdt_util.GetString(self._node, 'compress', 'none')
259
Simon Glass6c234bf2018-09-14 04:57:18 -0600260 def GetDefaultFilename(self):
261 return None
262
Simon Glassa8adb6d2019-07-20 12:23:28 -0600263 def GetFdts(self):
264 """Get the device trees used by this entry
Simon Glass539aece2018-09-14 04:57:22 -0600265
266 Returns:
Simon Glassa8adb6d2019-07-20 12:23:28 -0600267 Empty dict, if this entry is not a .dtb, otherwise:
268 Dict:
269 key: Filename from this entry (without the path)
Simon Glass4bdd3002019-07-20 12:23:31 -0600270 value: Tuple:
Simon Glassadb67bb2021-03-18 20:25:02 +1300271 Entry object for this dtb
Simon Glass4bdd3002019-07-20 12:23:31 -0600272 Filename of file containing this dtb
Simon Glass539aece2018-09-14 04:57:22 -0600273 """
Simon Glassa8adb6d2019-07-20 12:23:28 -0600274 return {}
Simon Glass539aece2018-09-14 04:57:22 -0600275
Simon Glass0a98b282018-09-14 04:57:28 -0600276 def ExpandEntries(self):
Simon Glassa01d1a22021-03-18 20:24:52 +1300277 """Expand out entries which produce other entries
278
279 Some entries generate subnodes automatically, from which sub-entries
280 are then created. This method allows those to be added to the binman
281 definition for the current image. An entry which implements this method
282 should call state.AddSubnode() to add a subnode and can add properties
283 with state.AddString(), etc.
284
285 An example is 'files', which produces a section containing a list of
286 files.
287 """
Simon Glass0a98b282018-09-14 04:57:28 -0600288 pass
289
Simon Glassa9fad072020-10-26 17:40:17 -0600290 def AddMissingProperties(self, have_image_pos):
291 """Add new properties to the device tree as needed for this entry
292
293 Args:
294 have_image_pos: True if this entry has an image position. This can
295 be False if its parent section is compressed, since compression
296 groups all entries together into a compressed block of data,
297 obscuring the start of each individual child entry
298 """
299 for prop in ['offset', 'size']:
Simon Glass078ab1a2018-07-06 10:27:41 -0600300 if not prop in self._node.props:
Simon Glassf46621d2018-09-14 04:57:21 -0600301 state.AddZeroProp(self._node, prop)
Simon Glassa9fad072020-10-26 17:40:17 -0600302 if have_image_pos and 'image-pos' not in self._node.props:
303 state.AddZeroProp(self._node, 'image-pos')
Simon Glass12bb1a92019-07-20 12:23:51 -0600304 if self.GetImage().allow_repack:
305 if self.orig_offset is not None:
306 state.AddZeroProp(self._node, 'orig-offset', True)
307 if self.orig_size is not None:
308 state.AddZeroProp(self._node, 'orig-size', True)
309
Simon Glass8287ee82019-07-08 14:25:30 -0600310 if self.compress != 'none':
311 state.AddZeroProp(self._node, 'uncomp-size')
Simon Glasse0e5df92018-09-14 04:57:31 -0600312 err = state.CheckAddHashProp(self._node)
313 if err:
314 self.Raise(err)
Simon Glass078ab1a2018-07-06 10:27:41 -0600315
316 def SetCalculatedProperties(self):
317 """Set the value of device-tree properties calculated by binman"""
Simon Glassf46621d2018-09-14 04:57:21 -0600318 state.SetInt(self._node, 'offset', self.offset)
319 state.SetInt(self._node, 'size', self.size)
Simon Glass8beb11e2019-07-08 14:25:47 -0600320 base = self.section.GetRootSkipAtStart() if self.section else 0
Simon Glassa9fad072020-10-26 17:40:17 -0600321 if self.image_pos is not None:
Simon Glass08594d42020-11-02 12:55:44 -0700322 state.SetInt(self._node, 'image-pos', self.image_pos - base)
Simon Glass12bb1a92019-07-20 12:23:51 -0600323 if self.GetImage().allow_repack:
324 if self.orig_offset is not None:
325 state.SetInt(self._node, 'orig-offset', self.orig_offset, True)
326 if self.orig_size is not None:
327 state.SetInt(self._node, 'orig-size', self.orig_size, True)
Simon Glass8287ee82019-07-08 14:25:30 -0600328 if self.uncomp_size is not None:
329 state.SetInt(self._node, 'uncomp-size', self.uncomp_size)
Simon Glasse0e5df92018-09-14 04:57:31 -0600330 state.CheckSetHashValue(self._node, self.GetData)
Simon Glass078ab1a2018-07-06 10:27:41 -0600331
Simon Glassecab8972018-07-06 10:27:40 -0600332 def ProcessFdt(self, fdt):
Simon Glass6ed45ba2018-09-14 04:57:24 -0600333 """Allow entries to adjust the device tree
334
335 Some entries need to adjust the device tree for their purposes. This
336 may involve adding or deleting properties.
337
338 Returns:
339 True if processing is complete
340 False if processing could not be completed due to a dependency.
341 This will cause the entry to be retried after others have been
342 called
343 """
Simon Glassecab8972018-07-06 10:27:40 -0600344 return True
345
Simon Glassc8d48ef2018-06-01 09:38:21 -0600346 def SetPrefix(self, prefix):
347 """Set the name prefix for a node
348
349 Args:
350 prefix: Prefix to set, or '' to not use a prefix
351 """
352 if prefix:
353 self.name = prefix + self.name
354
Simon Glass5c890232018-07-06 10:27:19 -0600355 def SetContents(self, data):
356 """Set the contents of an entry
357
358 This sets both the data and content_size properties
359
360 Args:
Simon Glass5b463fc2019-07-08 14:25:33 -0600361 data: Data to set to the contents (bytes)
Simon Glass5c890232018-07-06 10:27:19 -0600362 """
363 self.data = data
364 self.contents_size = len(self.data)
365
366 def ProcessContentsUpdate(self, data):
Simon Glass5b463fc2019-07-08 14:25:33 -0600367 """Update the contents of an entry, after the size is fixed
Simon Glass5c890232018-07-06 10:27:19 -0600368
Simon Glassa0dcaf22019-07-08 14:25:35 -0600369 This checks that the new data is the same size as the old. If the size
370 has changed, this triggers a re-run of the packing algorithm.
Simon Glass5c890232018-07-06 10:27:19 -0600371
372 Args:
Simon Glass5b463fc2019-07-08 14:25:33 -0600373 data: Data to set to the contents (bytes)
Simon Glass5c890232018-07-06 10:27:19 -0600374
375 Raises:
376 ValueError if the new data size is not the same as the old
377 """
Simon Glassa0dcaf22019-07-08 14:25:35 -0600378 size_ok = True
Simon Glassc52c9e72019-07-08 14:25:37 -0600379 new_size = len(data)
Simon Glass61ec04f2019-07-20 12:23:58 -0600380 if state.AllowEntryExpansion() and new_size > self.contents_size:
381 # self.data will indicate the new size needed
382 size_ok = False
383 elif state.AllowEntryContraction() and new_size < self.contents_size:
384 size_ok = False
385
386 # If not allowed to change, try to deal with it or give up
387 if size_ok:
Simon Glassc52c9e72019-07-08 14:25:37 -0600388 if new_size > self.contents_size:
Simon Glass61ec04f2019-07-20 12:23:58 -0600389 self.Raise('Cannot update entry size from %d to %d' %
390 (self.contents_size, new_size))
391
392 # Don't let the data shrink. Pad it if necessary
393 if size_ok and new_size < self.contents_size:
394 data += tools.GetBytes(0, self.contents_size - new_size)
395
396 if not size_ok:
397 tout.Debug("Entry '%s' size change from %s to %s" % (
398 self._node.path, ToHex(self.contents_size),
399 ToHex(new_size)))
Simon Glass5c890232018-07-06 10:27:19 -0600400 self.SetContents(data)
Simon Glassa0dcaf22019-07-08 14:25:35 -0600401 return size_ok
Simon Glass5c890232018-07-06 10:27:19 -0600402
Simon Glassbf7fd502016-11-25 20:15:51 -0700403 def ObtainContents(self):
404 """Figure out the contents of an entry.
405
406 Returns:
407 True if the contents were found, False if another call is needed
408 after the other entries are processed.
409 """
410 # No contents by default: subclasses can implement this
411 return True
412
Simon Glassc52c9e72019-07-08 14:25:37 -0600413 def ResetForPack(self):
414 """Reset offset/size fields so that packing can be done again"""
Simon Glass9f297b02019-07-20 12:23:36 -0600415 self.Detail('ResetForPack: offset %s->%s, size %s->%s' %
416 (ToHex(self.offset), ToHex(self.orig_offset),
417 ToHex(self.size), ToHex(self.orig_size)))
Simon Glass9a5d3dc2019-10-31 07:43:02 -0600418 self.pre_reset_size = self.size
Simon Glassc52c9e72019-07-08 14:25:37 -0600419 self.offset = self.orig_offset
420 self.size = self.orig_size
421
Simon Glass3ab95982018-08-01 15:22:37 -0600422 def Pack(self, offset):
Simon Glass25ac0e62018-06-01 09:38:14 -0600423 """Figure out how to pack the entry into the section
Simon Glassbf7fd502016-11-25 20:15:51 -0700424
425 Most of the time the entries are not fully specified. There may be
426 an alignment but no size. In that case we take the size from the
427 contents of the entry.
428
Simon Glass3ab95982018-08-01 15:22:37 -0600429 If an entry has no hard-coded offset, it will be placed at @offset.
Simon Glassbf7fd502016-11-25 20:15:51 -0700430
Simon Glass3ab95982018-08-01 15:22:37 -0600431 Once this function is complete, both the offset and size of the
Simon Glassbf7fd502016-11-25 20:15:51 -0700432 entry will be know.
433
434 Args:
Simon Glass3ab95982018-08-01 15:22:37 -0600435 Current section offset pointer
Simon Glassbf7fd502016-11-25 20:15:51 -0700436
437 Returns:
Simon Glass3ab95982018-08-01 15:22:37 -0600438 New section offset pointer (after this entry)
Simon Glassbf7fd502016-11-25 20:15:51 -0700439 """
Simon Glass9f297b02019-07-20 12:23:36 -0600440 self.Detail('Packing: offset=%s, size=%s, content_size=%x' %
441 (ToHex(self.offset), ToHex(self.size),
442 self.contents_size))
Simon Glass3ab95982018-08-01 15:22:37 -0600443 if self.offset is None:
444 if self.offset_unset:
445 self.Raise('No offset set with offset-unset: should another '
446 'entry provide this correct offset?')
447 self.offset = tools.Align(offset, self.align)
Simon Glassbf7fd502016-11-25 20:15:51 -0700448 needed = self.pad_before + self.contents_size + self.pad_after
449 needed = tools.Align(needed, self.align_size)
450 size = self.size
451 if not size:
452 size = needed
Simon Glass3ab95982018-08-01 15:22:37 -0600453 new_offset = self.offset + size
454 aligned_offset = tools.Align(new_offset, self.align_end)
455 if aligned_offset != new_offset:
456 size = aligned_offset - self.offset
457 new_offset = aligned_offset
Simon Glassbf7fd502016-11-25 20:15:51 -0700458
459 if not self.size:
460 self.size = size
461
462 if self.size < needed:
463 self.Raise("Entry contents size is %#x (%d) but entry size is "
464 "%#x (%d)" % (needed, needed, self.size, self.size))
465 # Check that the alignment is correct. It could be wrong if the
Simon Glass3ab95982018-08-01 15:22:37 -0600466 # and offset or size values were provided (i.e. not calculated), but
Simon Glassbf7fd502016-11-25 20:15:51 -0700467 # conflict with the provided alignment values
468 if self.size != tools.Align(self.size, self.align_size):
469 self.Raise("Size %#x (%d) does not match align-size %#x (%d)" %
470 (self.size, self.size, self.align_size, self.align_size))
Simon Glass3ab95982018-08-01 15:22:37 -0600471 if self.offset != tools.Align(self.offset, self.align):
472 self.Raise("Offset %#x (%d) does not match align %#x (%d)" %
473 (self.offset, self.offset, self.align, self.align))
Simon Glass9f297b02019-07-20 12:23:36 -0600474 self.Detail(' - packed: offset=%#x, size=%#x, content_size=%#x, next_offset=%x' %
475 (self.offset, self.size, self.contents_size, new_offset))
Simon Glassbf7fd502016-11-25 20:15:51 -0700476
Simon Glass3ab95982018-08-01 15:22:37 -0600477 return new_offset
Simon Glassbf7fd502016-11-25 20:15:51 -0700478
479 def Raise(self, msg):
480 """Convenience function to raise an error referencing a node"""
481 raise ValueError("Node '%s': %s" % (self._node.path, msg))
482
Simon Glass189f2912021-03-21 18:24:31 +1300483 def Info(self, msg):
484 """Convenience function to log info referencing a node"""
485 tag = "Info '%s'" % self._node.path
486 tout.Detail('%30s: %s' % (tag, msg))
487
Simon Glass9f297b02019-07-20 12:23:36 -0600488 def Detail(self, msg):
489 """Convenience function to log detail referencing a node"""
490 tag = "Node '%s'" % self._node.path
491 tout.Detail('%30s: %s' % (tag, msg))
492
Simon Glass53af22a2018-07-17 13:25:32 -0600493 def GetEntryArgsOrProps(self, props, required=False):
494 """Return the values of a set of properties
495
496 Args:
497 props: List of EntryArg objects
498
499 Raises:
500 ValueError if a property is not found
501 """
502 values = []
503 missing = []
504 for prop in props:
505 python_prop = prop.name.replace('-', '_')
506 if hasattr(self, python_prop):
507 value = getattr(self, python_prop)
508 else:
509 value = None
510 if value is None:
511 value = self.GetArg(prop.name, prop.datatype)
512 if value is None and required:
513 missing.append(prop.name)
514 values.append(value)
515 if missing:
Simon Glass939d1062021-01-06 21:35:16 -0700516 self.GetImage().MissingArgs(self, missing)
Simon Glass53af22a2018-07-17 13:25:32 -0600517 return values
518
Simon Glassbf7fd502016-11-25 20:15:51 -0700519 def GetPath(self):
520 """Get the path of a node
521
522 Returns:
523 Full path of the node for this entry
524 """
525 return self._node.path
526
Simon Glass631f7522021-03-21 18:24:32 +1300527 def GetData(self, required=True):
Simon Glass63e7ba62020-10-26 17:40:16 -0600528 """Get the contents of an entry
529
Simon Glass631f7522021-03-21 18:24:32 +1300530 Args:
531 required: True if the data must be present, False if it is OK to
532 return None
533
Simon Glass63e7ba62020-10-26 17:40:16 -0600534 Returns:
535 bytes content of the entry, excluding any padding. If the entry is
536 compressed, the compressed data is returned
537 """
Simon Glass9f297b02019-07-20 12:23:36 -0600538 self.Detail('GetData: size %s' % ToHexSize(self.data))
Simon Glassbf7fd502016-11-25 20:15:51 -0700539 return self.data
540
Simon Glass271a0832020-11-02 12:55:43 -0700541 def GetPaddedData(self, data=None):
542 """Get the data for an entry including any padding
543
544 Gets the entry data and uses its section's pad-byte value to add padding
545 before and after as defined by the pad-before and pad-after properties.
546
547 This does not consider alignment.
548
549 Returns:
550 Contents of the entry along with any pad bytes before and
551 after it (bytes)
552 """
553 if data is None:
554 data = self.GetData()
555 return self.section.GetPaddedDataForEntry(self, data)
556
Simon Glass3ab95982018-08-01 15:22:37 -0600557 def GetOffsets(self):
Simon Glassed7dd5e2019-07-08 13:18:30 -0600558 """Get the offsets for siblings
559
560 Some entry types can contain information about the position or size of
561 other entries. An example of this is the Intel Flash Descriptor, which
562 knows where the Intel Management Engine section should go.
563
564 If this entry knows about the position of other entries, it can specify
565 this by returning values here
566
567 Returns:
568 Dict:
569 key: Entry type
570 value: List containing position and size of the given entry
Simon Glasscf549042019-07-08 13:18:39 -0600571 type. Either can be None if not known
Simon Glassed7dd5e2019-07-08 13:18:30 -0600572 """
Simon Glassbf7fd502016-11-25 20:15:51 -0700573 return {}
574
Simon Glasscf549042019-07-08 13:18:39 -0600575 def SetOffsetSize(self, offset, size):
576 """Set the offset and/or size of an entry
577
578 Args:
579 offset: New offset, or None to leave alone
580 size: New size, or None to leave alone
581 """
582 if offset is not None:
583 self.offset = offset
584 if size is not None:
585 self.size = size
Simon Glassbf7fd502016-11-25 20:15:51 -0700586
Simon Glassdbf6be92018-08-01 15:22:42 -0600587 def SetImagePos(self, image_pos):
588 """Set the position in the image
589
590 Args:
591 image_pos: Position of this entry in the image
592 """
593 self.image_pos = image_pos + self.offset
594
Simon Glassbf7fd502016-11-25 20:15:51 -0700595 def ProcessContents(self):
Simon Glassa0dcaf22019-07-08 14:25:35 -0600596 """Do any post-packing updates of entry contents
597
598 This function should call ProcessContentsUpdate() to update the entry
599 contents, if necessary, returning its return value here.
600
601 Args:
602 data: Data to set to the contents (bytes)
603
604 Returns:
605 True if the new data size is OK, False if expansion is needed
606
607 Raises:
608 ValueError if the new data size is not the same as the old and
609 state.AllowEntryExpansion() is False
610 """
611 return True
Simon Glass19790632017-11-13 18:55:01 -0700612
Simon Glassf55382b2018-06-01 09:38:13 -0600613 def WriteSymbols(self, section):
Simon Glass19790632017-11-13 18:55:01 -0700614 """Write symbol values into binary files for access at run time
615
616 Args:
Simon Glassf55382b2018-06-01 09:38:13 -0600617 section: Section containing the entry
Simon Glass19790632017-11-13 18:55:01 -0700618 """
619 pass
Simon Glass18546952018-06-01 09:38:16 -0600620
Simon Glass6ddd6112020-10-26 17:40:18 -0600621 def CheckEntries(self):
Simon Glass3ab95982018-08-01 15:22:37 -0600622 """Check that the entry offsets are correct
Simon Glass18546952018-06-01 09:38:16 -0600623
Simon Glass3ab95982018-08-01 15:22:37 -0600624 This is used for entries which have extra offset requirements (other
Simon Glass18546952018-06-01 09:38:16 -0600625 than having to be fully inside their section). Sub-classes can implement
626 this function and raise if there is a problem.
627 """
628 pass
Simon Glass3b0c3822018-06-01 09:38:20 -0600629
Simon Glass8122f392018-07-17 13:25:28 -0600630 @staticmethod
Simon Glass163ed6c2018-09-14 04:57:36 -0600631 def GetStr(value):
632 if value is None:
633 return '<none> '
634 return '%08x' % value
635
636 @staticmethod
Simon Glass1be70d22018-07-17 13:25:49 -0600637 def WriteMapLine(fd, indent, name, offset, size, image_pos):
Simon Glass163ed6c2018-09-14 04:57:36 -0600638 print('%s %s%s %s %s' % (Entry.GetStr(image_pos), ' ' * indent,
639 Entry.GetStr(offset), Entry.GetStr(size),
640 name), file=fd)
Simon Glass8122f392018-07-17 13:25:28 -0600641
Simon Glass3b0c3822018-06-01 09:38:20 -0600642 def WriteMap(self, fd, indent):
643 """Write a map of the entry to a .map file
644
645 Args:
646 fd: File to write the map to
647 indent: Curent indent level of map (0=none, 1=one level, etc.)
648 """
Simon Glass1be70d22018-07-17 13:25:49 -0600649 self.WriteMapLine(fd, indent, self.name, self.offset, self.size,
650 self.image_pos)
Simon Glass53af22a2018-07-17 13:25:32 -0600651
Simon Glass11e36cc2018-07-17 13:25:38 -0600652 def GetEntries(self):
653 """Return a list of entries contained by this entry
654
655 Returns:
656 List of entries, or None if none. A normal entry has no entries
657 within it so will return None
658 """
659 return None
660
Simon Glass53af22a2018-07-17 13:25:32 -0600661 def GetArg(self, name, datatype=str):
662 """Get the value of an entry argument or device-tree-node property
663
664 Some node properties can be provided as arguments to binman. First check
665 the entry arguments, and fall back to the device tree if not found
666
667 Args:
668 name: Argument name
669 datatype: Data type (str or int)
670
671 Returns:
672 Value of argument as a string or int, or None if no value
673
674 Raises:
675 ValueError if the argument cannot be converted to in
676 """
Simon Glassc55a50f2018-09-14 04:57:19 -0600677 value = state.GetEntryArg(name)
Simon Glass53af22a2018-07-17 13:25:32 -0600678 if value is not None:
679 if datatype == int:
680 try:
681 value = int(value)
682 except ValueError:
683 self.Raise("Cannot convert entry arg '%s' (value '%s') to integer" %
684 (name, value))
685 elif datatype == str:
686 pass
687 else:
688 raise ValueError("GetArg() internal error: Unknown data type '%s'" %
689 datatype)
690 else:
691 value = fdt_util.GetDatatype(self._node, name, datatype)
692 return value
Simon Glassfd8d1f72018-07-17 13:25:36 -0600693
694 @staticmethod
695 def WriteDocs(modules, test_missing=None):
696 """Write out documentation about the various entry types to stdout
697
698 Args:
699 modules: List of modules to include
700 test_missing: Used for testing. This is a module to report
701 as missing
702 """
703 print('''Binman Entry Documentation
704===========================
705
706This file describes the entry types supported by binman. These entry types can
707be placed in an image one by one to build up a final firmware image. It is
708fairly easy to create new entry types. Just add a new file to the 'etype'
709directory. You can use the existing entries as examples.
710
711Note that some entries are subclasses of others, using and extending their
712features to produce new behaviours.
713
714
715''')
716 modules = sorted(modules)
717
718 # Don't show the test entry
719 if '_testing' in modules:
720 modules.remove('_testing')
721 missing = []
722 for name in modules:
Simon Glassb35fb172021-03-18 20:25:04 +1300723 module = Entry.Lookup('WriteDocs', name, False)
Simon Glassfd8d1f72018-07-17 13:25:36 -0600724 docs = getattr(module, '__doc__')
725 if test_missing == name:
726 docs = None
727 if docs:
728 lines = docs.splitlines()
729 first_line = lines[0]
730 rest = [line[4:] for line in lines[1:]]
731 hdr = 'Entry: %s: %s' % (name.replace('_', '-'), first_line)
732 print(hdr)
733 print('-' * len(hdr))
734 print('\n'.join(rest))
735 print()
736 print()
737 else:
738 missing.append(name)
739
740 if missing:
741 raise ValueError('Documentation is missing for modules: %s' %
742 ', '.join(missing))
Simon Glassa326b492018-09-14 04:57:11 -0600743
744 def GetUniqueName(self):
745 """Get a unique name for a node
746
747 Returns:
748 String containing a unique name for a node, consisting of the name
749 of all ancestors (starting from within the 'binman' node) separated
750 by a dot ('.'). This can be useful for generating unique filesnames
751 in the output directory.
752 """
753 name = self.name
754 node = self._node
755 while node.parent:
756 node = node.parent
757 if node.name == 'binman':
758 break
759 name = '%s.%s' % (node.name, name)
760 return name
Simon Glassba64a0b2018-09-14 04:57:29 -0600761
762 def ExpandToLimit(self, limit):
763 """Expand an entry so that it ends at the given offset limit"""
764 if self.offset + self.size < limit:
765 self.size = limit - self.offset
766 # Request the contents again, since changing the size requires that
767 # the data grows. This should not fail, but check it to be sure.
768 if not self.ObtainContents():
769 self.Raise('Cannot obtain contents when expanding entry')
Simon Glassfa1c9372019-07-08 13:18:38 -0600770
771 def HasSibling(self, name):
772 """Check if there is a sibling of a given name
773
774 Returns:
775 True if there is an entry with this name in the the same section,
776 else False
777 """
778 return name in self.section.GetEntries()
Simon Glasscf228942019-07-08 14:25:28 -0600779
780 def GetSiblingImagePos(self, name):
781 """Return the image position of the given sibling
782
783 Returns:
784 Image position of sibling, or None if the sibling has no position,
785 or False if there is no such sibling
786 """
787 if not self.HasSibling(name):
788 return False
789 return self.section.GetEntries()[name].image_pos
Simon Glass41b8ba02019-07-08 14:25:43 -0600790
791 @staticmethod
792 def AddEntryInfo(entries, indent, name, etype, size, image_pos,
793 uncomp_size, offset, entry):
794 """Add a new entry to the entries list
795
796 Args:
797 entries: List (of EntryInfo objects) to add to
798 indent: Current indent level to add to list
799 name: Entry name (string)
800 etype: Entry type (string)
801 size: Entry size in bytes (int)
802 image_pos: Position within image in bytes (int)
803 uncomp_size: Uncompressed size if the entry uses compression, else
804 None
805 offset: Entry offset within parent in bytes (int)
806 entry: Entry object
807 """
808 entries.append(EntryInfo(indent, name, etype, size, image_pos,
809 uncomp_size, offset, entry))
810
811 def ListEntries(self, entries, indent):
812 """Add files in this entry to the list of entries
813
814 This can be overridden by subclasses which need different behaviour.
815
816 Args:
817 entries: List (of EntryInfo objects) to add to
818 indent: Current indent level to add to list
819 """
820 self.AddEntryInfo(entries, indent, self.name, self.etype, self.size,
821 self.image_pos, self.uncomp_size, self.offset, self)
Simon Glassf667e452019-07-08 14:25:50 -0600822
Simon Glass943bf782021-11-23 21:09:50 -0700823 def ReadData(self, decomp=True, alt_format=None):
Simon Glassf667e452019-07-08 14:25:50 -0600824 """Read the data for an entry from the image
825
826 This is used when the image has been read in and we want to extract the
827 data for a particular entry from that image.
828
829 Args:
830 decomp: True to decompress any compressed data before returning it;
831 False to return the raw, uncompressed data
832
833 Returns:
834 Entry data (bytes)
835 """
836 # Use True here so that we get an uncompressed section to work from,
837 # although compressed sections are currently not supported
Simon Glass2d553c02019-09-25 08:56:21 -0600838 tout.Debug("ReadChildData section '%s', entry '%s'" %
839 (self.section.GetPath(), self.GetPath()))
Simon Glass943bf782021-11-23 21:09:50 -0700840 data = self.section.ReadChildData(self, decomp, alt_format)
Simon Glassa9cd39e2019-07-20 12:24:04 -0600841 return data
Simon Glassd5079332019-07-20 12:23:41 -0600842
Simon Glass943bf782021-11-23 21:09:50 -0700843 def ReadChildData(self, child, decomp=True, alt_format=None):
Simon Glass2d553c02019-09-25 08:56:21 -0600844 """Read the data for a particular child entry
Simon Glass4e185e82019-09-25 08:56:20 -0600845
846 This reads data from the parent and extracts the piece that relates to
847 the given child.
848
849 Args:
Simon Glass943bf782021-11-23 21:09:50 -0700850 child (Entry): Child entry to read data for (must be valid)
851 decomp (bool): True to decompress any compressed data before
852 returning it; False to return the raw, uncompressed data
853 alt_format (str): Alternative format to read in, or None
Simon Glass4e185e82019-09-25 08:56:20 -0600854
855 Returns:
856 Data for the child (bytes)
857 """
858 pass
859
Simon Glassd5079332019-07-20 12:23:41 -0600860 def LoadData(self, decomp=True):
861 data = self.ReadData(decomp)
Simon Glass10f9d002019-07-20 12:23:50 -0600862 self.contents_size = len(data)
Simon Glassd5079332019-07-20 12:23:41 -0600863 self.ProcessContentsUpdate(data)
864 self.Detail('Loaded data size %x' % len(data))
Simon Glassc5ad04b2019-07-20 12:23:46 -0600865
Simon Glass943bf782021-11-23 21:09:50 -0700866 def GetAltFormat(self, data, alt_format):
867 """Read the data for an extry in an alternative format
868
869 Supported formats are list in the documentation for each entry. An
870 example is fdtmap which provides .
871
872 Args:
873 data (bytes): Data to convert (this should have been produced by the
874 entry)
875 alt_format (str): Format to use
876
877 """
878 pass
879
Simon Glassc5ad04b2019-07-20 12:23:46 -0600880 def GetImage(self):
881 """Get the image containing this entry
882
883 Returns:
884 Image object containing this entry
885 """
886 return self.section.GetImage()
Simon Glass10f9d002019-07-20 12:23:50 -0600887
888 def WriteData(self, data, decomp=True):
889 """Write the data to an entry in the image
890
891 This is used when the image has been read in and we want to replace the
892 data for a particular entry in that image.
893
894 The image must be re-packed and written out afterwards.
895
896 Args:
897 data: Data to replace it with
898 decomp: True to compress the data if needed, False if data is
899 already compressed so should be used as is
900
901 Returns:
902 True if the data did not result in a resize of this entry, False if
903 the entry must be resized
904 """
Simon Glass9a5d3dc2019-10-31 07:43:02 -0600905 if self.size is not None:
906 self.contents_size = self.size
907 else:
908 self.contents_size = self.pre_reset_size
Simon Glass10f9d002019-07-20 12:23:50 -0600909 ok = self.ProcessContentsUpdate(data)
910 self.Detail('WriteData: size=%x, ok=%s' % (len(data), ok))
Simon Glass7210c892019-07-20 12:24:05 -0600911 section_ok = self.section.WriteChildData(self)
912 return ok and section_ok
913
914 def WriteChildData(self, child):
915 """Handle writing the data in a child entry
916
917 This should be called on the child's parent section after the child's
Simon Glass557693e2021-11-23 11:03:44 -0700918 data has been updated. It should update any data structures needed to
919 validate that the update is successful.
Simon Glass7210c892019-07-20 12:24:05 -0600920
921 This base-class implementation does nothing, since the base Entry object
922 does not have any children.
923
924 Args:
925 child: Child Entry that was written
926
927 Returns:
928 True if the section could be updated successfully, False if the
Simon Glass557693e2021-11-23 11:03:44 -0700929 data is such that the section could not update
Simon Glass7210c892019-07-20 12:24:05 -0600930 """
931 return True
Simon Glasseba1f0c2019-07-20 12:23:55 -0600932
933 def GetSiblingOrder(self):
934 """Get the relative order of an entry amoung its siblings
935
936 Returns:
937 'start' if this entry is first among siblings, 'end' if last,
938 otherwise None
939 """
940 entries = list(self.section.GetEntries().values())
941 if entries:
942 if self == entries[0]:
943 return 'start'
944 elif self == entries[-1]:
945 return 'end'
946 return 'middle'
Simon Glass4f9f1052020-07-09 18:39:38 -0600947
948 def SetAllowMissing(self, allow_missing):
949 """Set whether a section allows missing external blobs
950
951 Args:
952 allow_missing: True if allowed, False if not allowed
953 """
954 # This is meaningless for anything other than sections
955 pass
Simon Glassb1cca952020-07-09 18:39:40 -0600956
Heiko Thierya89c8f22022-01-06 11:49:41 +0100957 def SetAllowFakeBlob(self, allow_fake):
958 """Set whether a section allows to create a fake blob
959
960 Args:
961 allow_fake: True if allowed, False if not allowed
962 """
963 pass
964
Simon Glassb1cca952020-07-09 18:39:40 -0600965 def CheckMissing(self, missing_list):
966 """Check if any entries in this section have missing external blobs
967
968 If there are missing blobs, the entries are added to the list
969
970 Args:
971 missing_list: List of Entry objects to be added to
972 """
973 if self.missing:
974 missing_list.append(self)
Simon Glass87958982020-09-01 05:13:57 -0600975
Simon Glass790ba9f2022-01-12 13:10:36 -0700976 def check_fake_fname(self, fname):
977 """If the file is missing and the entry allows fake blobs, fake it
978
979 Sets self.faked to True if faked
980
981 Args:
982 fname (str): Filename to check
983
984 Returns:
985 fname (str): Filename of faked file
986 """
987 if self.allow_fake and not pathlib.Path(fname).is_file():
988 outfname = tools.GetOutputFilename(os.path.basename(fname))
989 with open(outfname, "wb") as out:
990 out.truncate(1024)
991 self.faked = True
992 return outfname
993 return fname
994
Heiko Thierya89c8f22022-01-06 11:49:41 +0100995 def CheckFakedBlobs(self, faked_blobs_list):
996 """Check if any entries in this section have faked external blobs
997
998 If there are faked blobs, the entries are added to the list
999
1000 Args:
1001 fake_blobs_list: List of Entry objects to be added to
1002 """
1003 # This is meaningless for anything other than blobs
1004 pass
1005
Simon Glass87958982020-09-01 05:13:57 -06001006 def GetAllowMissing(self):
1007 """Get whether a section allows missing external blobs
1008
1009 Returns:
1010 True if allowed, False if not allowed
1011 """
1012 return self.allow_missing
Simon Glassb2381432020-09-06 10:39:09 -06001013
1014 def GetHelpTags(self):
1015 """Get the tags use for missing-blob help
1016
1017 Returns:
1018 list of possible tags, most desirable first
1019 """
1020 return list(filter(None, [self.missing_msg, self.name, self.etype]))
Simon Glass87c96292020-10-26 17:40:06 -06001021
1022 def CompressData(self, indata):
1023 """Compress data according to the entry's compression method
1024
1025 Args:
1026 indata: Data to compress
1027
1028 Returns:
1029 Compressed data (first word is the compressed size)
1030 """
Simon Glass97c3e9a2020-10-26 17:40:15 -06001031 self.uncomp_data = indata
Simon Glass87c96292020-10-26 17:40:06 -06001032 if self.compress != 'none':
1033 self.uncomp_size = len(indata)
1034 data = tools.Compress(indata, self.compress)
1035 return data
Simon Glassb35fb172021-03-18 20:25:04 +13001036
1037 @classmethod
1038 def UseExpanded(cls, node, etype, new_etype):
1039 """Check whether to use an expanded entry type
1040
1041 This is called by Entry.Create() when it finds an expanded version of
1042 an entry type (e.g. 'u-boot-expanded'). If this method returns True then
1043 it will be used (e.g. in place of 'u-boot'). If it returns False, it is
1044 ignored.
1045
1046 Args:
1047 node: Node object containing information about the entry to
1048 create
1049 etype: Original entry type being used
1050 new_etype: New entry type proposed
1051
1052 Returns:
1053 True to use this entry type, False to use the original one
1054 """
1055 tout.Info("Node '%s': etype '%s': %s selected" %
1056 (node.path, etype, new_etype))
1057 return True
Simon Glass943bf782021-11-23 21:09:50 -07001058
1059 def CheckAltFormats(self, alt_formats):
1060 """Add any alternative formats supported by this entry type
1061
1062 Args:
1063 alt_formats (dict): Dict to add alt_formats to:
1064 key: Name of alt format
1065 value: Help text
1066 """
1067 pass