blob: 5281dcdab6aff344eb6d5759a3d2de8b885504ff [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 Glass386c63c2022-01-09 20:13:50 -070013from binman import bintool
Simon Glassad35ce52022-01-09 20:14:03 -070014from binman import comp_util
Simon Glass16287932020-04-17 18:09:03 -060015from dtoc import fdt_util
Simon Glassbf776672020-04-17 18:09:04 -060016from patman import tools
Simon Glass16287932020-04-17 18:09:03 -060017from patman.tools import ToHex, ToHexSize
Simon Glassbf776672020-04-17 18:09:04 -060018from patman import tout
Simon Glassbf7fd502016-11-25 20:15:51 -070019
20modules = {}
21
Simon Glass53af22a2018-07-17 13:25:32 -060022
23# An argument which can be passed to entries on the command line, in lieu of
24# device-tree properties.
25EntryArg = namedtuple('EntryArg', ['name', 'datatype'])
26
Simon Glass41b8ba02019-07-08 14:25:43 -060027# Information about an entry for use when displaying summaries
28EntryInfo = namedtuple('EntryInfo', ['indent', 'name', 'etype', 'size',
29 'image_pos', 'uncomp_size', 'offset',
30 'entry'])
Simon Glass53af22a2018-07-17 13:25:32 -060031
Simon Glassbf7fd502016-11-25 20:15:51 -070032class Entry(object):
Simon Glass25ac0e62018-06-01 09:38:14 -060033 """An Entry in the section
Simon Glassbf7fd502016-11-25 20:15:51 -070034
35 An entry corresponds to a single node in the device-tree description
Simon Glass25ac0e62018-06-01 09:38:14 -060036 of the section. Each entry ends up being a part of the final section.
Simon Glassbf7fd502016-11-25 20:15:51 -070037 Entries can be placed either right next to each other, or with padding
38 between them. The type of the entry determines the data that is in it.
39
40 This class is not used by itself. All entry objects are subclasses of
41 Entry.
42
43 Attributes:
Simon Glass8122f392018-07-17 13:25:28 -060044 section: Section object containing this entry
Simon Glassbf7fd502016-11-25 20:15:51 -070045 node: The node that created this entry
Simon Glass3ab95982018-08-01 15:22:37 -060046 offset: Offset of entry within the section, None if not known yet (in
47 which case it will be calculated by Pack())
Simon Glassbf7fd502016-11-25 20:15:51 -070048 size: Entry size in bytes, None if not known
Simon Glass9a5d3dc2019-10-31 07:43:02 -060049 pre_reset_size: size as it was before ResetForPack(). This allows us to
50 keep track of the size we started with and detect size changes
Simon Glass8287ee82019-07-08 14:25:30 -060051 uncomp_size: Size of uncompressed data in bytes, if the entry is
52 compressed, else None
Simon Glassbf7fd502016-11-25 20:15:51 -070053 contents_size: Size of contents in bytes, 0 by default
Simon Glass4eec34c2020-10-26 17:40:10 -060054 align: Entry start offset alignment relative to the start of the
55 containing section, or None
Simon Glassbf7fd502016-11-25 20:15:51 -070056 align_size: Entry size alignment, or None
Simon Glass4eec34c2020-10-26 17:40:10 -060057 align_end: Entry end offset alignment relative to the start of the
58 containing section, or None
Simon Glassf90d9062020-10-26 17:40:09 -060059 pad_before: Number of pad bytes before the contents when it is placed
60 in the containing section, 0 if none. The pad bytes become part of
61 the entry.
62 pad_after: Number of pad bytes after the contents when it is placed in
63 the containing section, 0 if none. The pad bytes become part of
64 the entry.
65 data: Contents of entry (string of bytes). This does not include
Simon Glass97c3e9a2020-10-26 17:40:15 -060066 padding created by pad_before or pad_after. If the entry is
67 compressed, this contains the compressed data.
68 uncomp_data: Original uncompressed data, if this entry is compressed,
69 else None
Simon Glass8287ee82019-07-08 14:25:30 -060070 compress: Compression algoithm used (e.g. 'lz4'), 'none' if none
Simon Glassc52c9e72019-07-08 14:25:37 -060071 orig_offset: Original offset value read from node
72 orig_size: Original size value read from node
Simon Glass87958982020-09-01 05:13:57 -060073 missing: True if this entry is missing its contents
74 allow_missing: Allow children of this entry to be missing (used by
75 subclasses such as Entry_section)
Heiko Thierya89c8f22022-01-06 11:49:41 +010076 allow_fake: Allow creating a dummy fake file if the blob file is not
77 available. This is mainly used for testing.
Simon Glass87958982020-09-01 05:13:57 -060078 external: True if this entry contains an external binary blob
Simon Glass386c63c2022-01-09 20:13:50 -070079 bintools: Bintools used by this entry (only populated for Image)
Simon Glassbf7fd502016-11-25 20:15:51 -070080 """
Simon Glassc6bd6e22019-07-20 12:23:45 -060081 def __init__(self, section, etype, node, name_prefix=''):
Simon Glass8dbb7442019-08-24 07:22:44 -060082 # Put this here to allow entry-docs and help to work without libfdt
83 global state
Simon Glass16287932020-04-17 18:09:03 -060084 from binman import state
Simon Glass8dbb7442019-08-24 07:22:44 -060085
Simon Glass25ac0e62018-06-01 09:38:14 -060086 self.section = section
Simon Glassbf7fd502016-11-25 20:15:51 -070087 self.etype = etype
88 self._node = node
Simon Glassc8d48ef2018-06-01 09:38:21 -060089 self.name = node and (name_prefix + node.name) or 'none'
Simon Glass3ab95982018-08-01 15:22:37 -060090 self.offset = None
Simon Glassbf7fd502016-11-25 20:15:51 -070091 self.size = None
Simon Glass9a5d3dc2019-10-31 07:43:02 -060092 self.pre_reset_size = None
Simon Glass8287ee82019-07-08 14:25:30 -060093 self.uncomp_size = None
Simon Glass24d0d3c2018-07-17 13:25:47 -060094 self.data = None
Simon Glass97c3e9a2020-10-26 17:40:15 -060095 self.uncomp_data = None
Simon Glassbf7fd502016-11-25 20:15:51 -070096 self.contents_size = 0
97 self.align = None
98 self.align_size = None
99 self.align_end = None
100 self.pad_before = 0
101 self.pad_after = 0
Simon Glass3ab95982018-08-01 15:22:37 -0600102 self.offset_unset = False
Simon Glassdbf6be92018-08-01 15:22:42 -0600103 self.image_pos = None
Simon Glassc4738312021-11-23 11:03:43 -0700104 self.expand_size = False
Simon Glass8287ee82019-07-08 14:25:30 -0600105 self.compress = 'none'
Simon Glassb1cca952020-07-09 18:39:40 -0600106 self.missing = False
Heiko Thierya89c8f22022-01-06 11:49:41 +0100107 self.faked = False
Simon Glass87958982020-09-01 05:13:57 -0600108 self.external = False
109 self.allow_missing = False
Heiko Thierya89c8f22022-01-06 11:49:41 +0100110 self.allow_fake = False
Simon Glass386c63c2022-01-09 20:13:50 -0700111 self.bintools = {}
Simon Glassbf7fd502016-11-25 20:15:51 -0700112
113 @staticmethod
Simon Glass858436d2021-11-23 21:09:49 -0700114 def FindEntryClass(etype, expanded):
Simon Glassfd8d1f72018-07-17 13:25:36 -0600115 """Look up the entry class for a node.
Simon Glassbf7fd502016-11-25 20:15:51 -0700116
117 Args:
Simon Glassfd8d1f72018-07-17 13:25:36 -0600118 node_node: Path name of Node object containing information about
119 the entry to create (used for errors)
120 etype: Entry type to use
Simon Glassb35fb172021-03-18 20:25:04 +1300121 expanded: Use the expanded version of etype
Simon Glassbf7fd502016-11-25 20:15:51 -0700122
123 Returns:
Simon Glassb35fb172021-03-18 20:25:04 +1300124 The entry class object if found, else None if not found and expanded
Simon Glass858436d2021-11-23 21:09:49 -0700125 is True, else a tuple:
126 module name that could not be found
127 exception received
Simon Glassbf7fd502016-11-25 20:15:51 -0700128 """
Simon Glassdd57c132018-06-01 09:38:11 -0600129 # Convert something like 'u-boot@0' to 'u_boot' since we are only
130 # interested in the type.
Simon Glassbf7fd502016-11-25 20:15:51 -0700131 module_name = etype.replace('-', '_')
Simon Glassb35fb172021-03-18 20:25:04 +1300132
Simon Glassdd57c132018-06-01 09:38:11 -0600133 if '@' in module_name:
134 module_name = module_name.split('@')[0]
Simon Glassb35fb172021-03-18 20:25:04 +1300135 if expanded:
136 module_name += '_expanded'
Simon Glassbf7fd502016-11-25 20:15:51 -0700137 module = modules.get(module_name)
138
Simon Glassbadf0ec2018-06-01 09:38:15 -0600139 # Also allow entry-type modules to be brought in from the etype directory.
140
Simon Glassbf7fd502016-11-25 20:15:51 -0700141 # Import the module if we have not already done so.
142 if not module:
143 try:
Simon Glass16287932020-04-17 18:09:03 -0600144 module = importlib.import_module('binman.etype.' + module_name)
Simon Glassfd8d1f72018-07-17 13:25:36 -0600145 except ImportError as e:
Simon Glassb35fb172021-03-18 20:25:04 +1300146 if expanded:
147 return None
Simon Glass858436d2021-11-23 21:09:49 -0700148 return module_name, e
Simon Glassbf7fd502016-11-25 20:15:51 -0700149 modules[module_name] = module
150
Simon Glassfd8d1f72018-07-17 13:25:36 -0600151 # Look up the expected class name
152 return getattr(module, 'Entry_%s' % module_name)
153
154 @staticmethod
Simon Glass858436d2021-11-23 21:09:49 -0700155 def Lookup(node_path, etype, expanded, missing_etype=False):
156 """Look up the entry class for a node.
157
158 Args:
159 node_node (str): Path name of Node object containing information
160 about the entry to create (used for errors)
161 etype (str): Entry type to use
162 expanded (bool): Use the expanded version of etype
163 missing_etype (bool): True to default to a blob etype if the
164 requested etype is not found
165
166 Returns:
167 The entry class object if found, else None if not found and expanded
168 is True
169
170 Raise:
171 ValueError if expanded is False and the class is not found
172 """
173 # Convert something like 'u-boot@0' to 'u_boot' since we are only
174 # interested in the type.
175 cls = Entry.FindEntryClass(etype, expanded)
176 if cls is None:
177 return None
178 elif isinstance(cls, tuple):
179 if missing_etype:
180 cls = Entry.FindEntryClass('blob', False)
181 if isinstance(cls, tuple): # This should not fail
182 module_name, e = cls
183 raise ValueError(
184 "Unknown entry type '%s' in node '%s' (expected etype/%s.py, error '%s'" %
185 (etype, node_path, module_name, e))
186 return cls
187
188 @staticmethod
189 def Create(section, node, etype=None, expanded=False, missing_etype=False):
Simon Glassfd8d1f72018-07-17 13:25:36 -0600190 """Create a new entry for a node.
191
192 Args:
Simon Glass858436d2021-11-23 21:09:49 -0700193 section (entry_Section): Section object containing this node
194 node (Node): Node object containing information about the entry to
195 create
196 etype (str): Entry type to use, or None to work it out (used for
197 tests)
198 expanded (bool): Use the expanded version of etype
199 missing_etype (bool): True to default to a blob etype if the
200 requested etype is not found
Simon Glassfd8d1f72018-07-17 13:25:36 -0600201
202 Returns:
203 A new Entry object of the correct type (a subclass of Entry)
204 """
205 if not etype:
206 etype = fdt_util.GetString(node, 'type', node.name)
Simon Glass858436d2021-11-23 21:09:49 -0700207 obj = Entry.Lookup(node.path, etype, expanded, missing_etype)
Simon Glassb35fb172021-03-18 20:25:04 +1300208 if obj and expanded:
209 # Check whether to use the expanded entry
210 new_etype = etype + '-expanded'
Simon Glass3d433382021-03-21 18:24:30 +1300211 can_expand = not fdt_util.GetBool(node, 'no-expanded')
212 if can_expand and obj.UseExpanded(node, etype, new_etype):
Simon Glassb35fb172021-03-18 20:25:04 +1300213 etype = new_etype
214 else:
215 obj = None
216 if not obj:
Simon Glass858436d2021-11-23 21:09:49 -0700217 obj = Entry.Lookup(node.path, etype, False, missing_etype)
Simon Glassfd8d1f72018-07-17 13:25:36 -0600218
Simon Glassbf7fd502016-11-25 20:15:51 -0700219 # Call its constructor to get the object we want.
Simon Glass25ac0e62018-06-01 09:38:14 -0600220 return obj(section, etype, node)
Simon Glassbf7fd502016-11-25 20:15:51 -0700221
222 def ReadNode(self):
223 """Read entry information from the node
224
Simon Glassc6bd6e22019-07-20 12:23:45 -0600225 This must be called as the first thing after the Entry is created.
226
Simon Glassbf7fd502016-11-25 20:15:51 -0700227 This reads all the fields we recognise from the node, ready for use.
228 """
Simon Glass15a587c2018-07-17 13:25:51 -0600229 if 'pos' in self._node.props:
230 self.Raise("Please use 'offset' instead of 'pos'")
Simon Glass3ab95982018-08-01 15:22:37 -0600231 self.offset = fdt_util.GetInt(self._node, 'offset')
Simon Glassbf7fd502016-11-25 20:15:51 -0700232 self.size = fdt_util.GetInt(self._node, 'size')
Simon Glass12bb1a92019-07-20 12:23:51 -0600233 self.orig_offset = fdt_util.GetInt(self._node, 'orig-offset')
234 self.orig_size = fdt_util.GetInt(self._node, 'orig-size')
235 if self.GetImage().copy_to_orig:
236 self.orig_offset = self.offset
237 self.orig_size = self.size
Simon Glassc52c9e72019-07-08 14:25:37 -0600238
Simon Glassffded752019-07-08 14:25:46 -0600239 # These should not be set in input files, but are set in an FDT map,
240 # which is also read by this code.
241 self.image_pos = fdt_util.GetInt(self._node, 'image-pos')
242 self.uncomp_size = fdt_util.GetInt(self._node, 'uncomp-size')
243
Simon Glassbf7fd502016-11-25 20:15:51 -0700244 self.align = fdt_util.GetInt(self._node, 'align')
245 if tools.NotPowerOfTwo(self.align):
246 raise ValueError("Node '%s': Alignment %s must be a power of two" %
247 (self._node.path, self.align))
Simon Glass5ff9fed2021-03-21 18:24:33 +1300248 if self.section and self.align is None:
249 self.align = self.section.align_default
Simon Glassbf7fd502016-11-25 20:15:51 -0700250 self.pad_before = fdt_util.GetInt(self._node, 'pad-before', 0)
251 self.pad_after = fdt_util.GetInt(self._node, 'pad-after', 0)
252 self.align_size = fdt_util.GetInt(self._node, 'align-size')
253 if tools.NotPowerOfTwo(self.align_size):
Simon Glass8beb11e2019-07-08 14:25:47 -0600254 self.Raise("Alignment size %s must be a power of two" %
255 self.align_size)
Simon Glassbf7fd502016-11-25 20:15:51 -0700256 self.align_end = fdt_util.GetInt(self._node, 'align-end')
Simon Glass3ab95982018-08-01 15:22:37 -0600257 self.offset_unset = fdt_util.GetBool(self._node, 'offset-unset')
Simon Glassba64a0b2018-09-14 04:57:29 -0600258 self.expand_size = fdt_util.GetBool(self._node, 'expand-size')
Simon Glassb2381432020-09-06 10:39:09 -0600259 self.missing_msg = fdt_util.GetString(self._node, 'missing-msg')
Simon Glassbf7fd502016-11-25 20:15:51 -0700260
Simon Glass87c96292020-10-26 17:40:06 -0600261 # This is only supported by blobs and sections at present
262 self.compress = fdt_util.GetString(self._node, 'compress', 'none')
263
Simon Glass6c234bf2018-09-14 04:57:18 -0600264 def GetDefaultFilename(self):
265 return None
266
Simon Glassa8adb6d2019-07-20 12:23:28 -0600267 def GetFdts(self):
268 """Get the device trees used by this entry
Simon Glass539aece2018-09-14 04:57:22 -0600269
270 Returns:
Simon Glassa8adb6d2019-07-20 12:23:28 -0600271 Empty dict, if this entry is not a .dtb, otherwise:
272 Dict:
273 key: Filename from this entry (without the path)
Simon Glass4bdd3002019-07-20 12:23:31 -0600274 value: Tuple:
Simon Glassadb67bb2021-03-18 20:25:02 +1300275 Entry object for this dtb
Simon Glass4bdd3002019-07-20 12:23:31 -0600276 Filename of file containing this dtb
Simon Glass539aece2018-09-14 04:57:22 -0600277 """
Simon Glassa8adb6d2019-07-20 12:23:28 -0600278 return {}
Simon Glass539aece2018-09-14 04:57:22 -0600279
Simon Glass0a98b282018-09-14 04:57:28 -0600280 def ExpandEntries(self):
Simon Glassa01d1a22021-03-18 20:24:52 +1300281 """Expand out entries which produce other entries
282
283 Some entries generate subnodes automatically, from which sub-entries
284 are then created. This method allows those to be added to the binman
285 definition for the current image. An entry which implements this method
286 should call state.AddSubnode() to add a subnode and can add properties
287 with state.AddString(), etc.
288
289 An example is 'files', which produces a section containing a list of
290 files.
291 """
Simon Glass0a98b282018-09-14 04:57:28 -0600292 pass
293
Simon Glassa9fad072020-10-26 17:40:17 -0600294 def AddMissingProperties(self, have_image_pos):
295 """Add new properties to the device tree as needed for this entry
296
297 Args:
298 have_image_pos: True if this entry has an image position. This can
299 be False if its parent section is compressed, since compression
300 groups all entries together into a compressed block of data,
301 obscuring the start of each individual child entry
302 """
303 for prop in ['offset', 'size']:
Simon Glass078ab1a2018-07-06 10:27:41 -0600304 if not prop in self._node.props:
Simon Glassf46621d2018-09-14 04:57:21 -0600305 state.AddZeroProp(self._node, prop)
Simon Glassa9fad072020-10-26 17:40:17 -0600306 if have_image_pos and 'image-pos' not in self._node.props:
307 state.AddZeroProp(self._node, 'image-pos')
Simon Glass12bb1a92019-07-20 12:23:51 -0600308 if self.GetImage().allow_repack:
309 if self.orig_offset is not None:
310 state.AddZeroProp(self._node, 'orig-offset', True)
311 if self.orig_size is not None:
312 state.AddZeroProp(self._node, 'orig-size', True)
313
Simon Glass8287ee82019-07-08 14:25:30 -0600314 if self.compress != 'none':
315 state.AddZeroProp(self._node, 'uncomp-size')
Simon Glasse0e5df92018-09-14 04:57:31 -0600316 err = state.CheckAddHashProp(self._node)
317 if err:
318 self.Raise(err)
Simon Glass078ab1a2018-07-06 10:27:41 -0600319
320 def SetCalculatedProperties(self):
321 """Set the value of device-tree properties calculated by binman"""
Simon Glassf46621d2018-09-14 04:57:21 -0600322 state.SetInt(self._node, 'offset', self.offset)
323 state.SetInt(self._node, 'size', self.size)
Simon Glass8beb11e2019-07-08 14:25:47 -0600324 base = self.section.GetRootSkipAtStart() if self.section else 0
Simon Glassa9fad072020-10-26 17:40:17 -0600325 if self.image_pos is not None:
Simon Glass08594d42020-11-02 12:55:44 -0700326 state.SetInt(self._node, 'image-pos', self.image_pos - base)
Simon Glass12bb1a92019-07-20 12:23:51 -0600327 if self.GetImage().allow_repack:
328 if self.orig_offset is not None:
329 state.SetInt(self._node, 'orig-offset', self.orig_offset, True)
330 if self.orig_size is not None:
331 state.SetInt(self._node, 'orig-size', self.orig_size, True)
Simon Glass8287ee82019-07-08 14:25:30 -0600332 if self.uncomp_size is not None:
333 state.SetInt(self._node, 'uncomp-size', self.uncomp_size)
Simon Glasse0e5df92018-09-14 04:57:31 -0600334 state.CheckSetHashValue(self._node, self.GetData)
Simon Glass078ab1a2018-07-06 10:27:41 -0600335
Simon Glassecab8972018-07-06 10:27:40 -0600336 def ProcessFdt(self, fdt):
Simon Glass6ed45ba2018-09-14 04:57:24 -0600337 """Allow entries to adjust the device tree
338
339 Some entries need to adjust the device tree for their purposes. This
340 may involve adding or deleting properties.
341
342 Returns:
343 True if processing is complete
344 False if processing could not be completed due to a dependency.
345 This will cause the entry to be retried after others have been
346 called
347 """
Simon Glassecab8972018-07-06 10:27:40 -0600348 return True
349
Simon Glassc8d48ef2018-06-01 09:38:21 -0600350 def SetPrefix(self, prefix):
351 """Set the name prefix for a node
352
353 Args:
354 prefix: Prefix to set, or '' to not use a prefix
355 """
356 if prefix:
357 self.name = prefix + self.name
358
Simon Glass5c890232018-07-06 10:27:19 -0600359 def SetContents(self, data):
360 """Set the contents of an entry
361
362 This sets both the data and content_size properties
363
364 Args:
Simon Glass5b463fc2019-07-08 14:25:33 -0600365 data: Data to set to the contents (bytes)
Simon Glass5c890232018-07-06 10:27:19 -0600366 """
367 self.data = data
368 self.contents_size = len(self.data)
369
370 def ProcessContentsUpdate(self, data):
Simon Glass5b463fc2019-07-08 14:25:33 -0600371 """Update the contents of an entry, after the size is fixed
Simon Glass5c890232018-07-06 10:27:19 -0600372
Simon Glassa0dcaf22019-07-08 14:25:35 -0600373 This checks that the new data is the same size as the old. If the size
374 has changed, this triggers a re-run of the packing algorithm.
Simon Glass5c890232018-07-06 10:27:19 -0600375
376 Args:
Simon Glass5b463fc2019-07-08 14:25:33 -0600377 data: Data to set to the contents (bytes)
Simon Glass5c890232018-07-06 10:27:19 -0600378
379 Raises:
380 ValueError if the new data size is not the same as the old
381 """
Simon Glassa0dcaf22019-07-08 14:25:35 -0600382 size_ok = True
Simon Glassc52c9e72019-07-08 14:25:37 -0600383 new_size = len(data)
Simon Glass61ec04f2019-07-20 12:23:58 -0600384 if state.AllowEntryExpansion() and new_size > self.contents_size:
385 # self.data will indicate the new size needed
386 size_ok = False
387 elif state.AllowEntryContraction() and new_size < self.contents_size:
388 size_ok = False
389
390 # If not allowed to change, try to deal with it or give up
391 if size_ok:
Simon Glassc52c9e72019-07-08 14:25:37 -0600392 if new_size > self.contents_size:
Simon Glass61ec04f2019-07-20 12:23:58 -0600393 self.Raise('Cannot update entry size from %d to %d' %
394 (self.contents_size, new_size))
395
396 # Don't let the data shrink. Pad it if necessary
397 if size_ok and new_size < self.contents_size:
398 data += tools.GetBytes(0, self.contents_size - new_size)
399
400 if not size_ok:
401 tout.Debug("Entry '%s' size change from %s to %s" % (
402 self._node.path, ToHex(self.contents_size),
403 ToHex(new_size)))
Simon Glass5c890232018-07-06 10:27:19 -0600404 self.SetContents(data)
Simon Glassa0dcaf22019-07-08 14:25:35 -0600405 return size_ok
Simon Glass5c890232018-07-06 10:27:19 -0600406
Simon Glassbf7fd502016-11-25 20:15:51 -0700407 def ObtainContents(self):
408 """Figure out the contents of an entry.
409
410 Returns:
411 True if the contents were found, False if another call is needed
412 after the other entries are processed.
413 """
414 # No contents by default: subclasses can implement this
415 return True
416
Simon Glassc52c9e72019-07-08 14:25:37 -0600417 def ResetForPack(self):
418 """Reset offset/size fields so that packing can be done again"""
Simon Glass9f297b02019-07-20 12:23:36 -0600419 self.Detail('ResetForPack: offset %s->%s, size %s->%s' %
420 (ToHex(self.offset), ToHex(self.orig_offset),
421 ToHex(self.size), ToHex(self.orig_size)))
Simon Glass9a5d3dc2019-10-31 07:43:02 -0600422 self.pre_reset_size = self.size
Simon Glassc52c9e72019-07-08 14:25:37 -0600423 self.offset = self.orig_offset
424 self.size = self.orig_size
425
Simon Glass3ab95982018-08-01 15:22:37 -0600426 def Pack(self, offset):
Simon Glass25ac0e62018-06-01 09:38:14 -0600427 """Figure out how to pack the entry into the section
Simon Glassbf7fd502016-11-25 20:15:51 -0700428
429 Most of the time the entries are not fully specified. There may be
430 an alignment but no size. In that case we take the size from the
431 contents of the entry.
432
Simon Glass3ab95982018-08-01 15:22:37 -0600433 If an entry has no hard-coded offset, it will be placed at @offset.
Simon Glassbf7fd502016-11-25 20:15:51 -0700434
Simon Glass3ab95982018-08-01 15:22:37 -0600435 Once this function is complete, both the offset and size of the
Simon Glassbf7fd502016-11-25 20:15:51 -0700436 entry will be know.
437
438 Args:
Simon Glass3ab95982018-08-01 15:22:37 -0600439 Current section offset pointer
Simon Glassbf7fd502016-11-25 20:15:51 -0700440
441 Returns:
Simon Glass3ab95982018-08-01 15:22:37 -0600442 New section offset pointer (after this entry)
Simon Glassbf7fd502016-11-25 20:15:51 -0700443 """
Simon Glass9f297b02019-07-20 12:23:36 -0600444 self.Detail('Packing: offset=%s, size=%s, content_size=%x' %
445 (ToHex(self.offset), ToHex(self.size),
446 self.contents_size))
Simon Glass3ab95982018-08-01 15:22:37 -0600447 if self.offset is None:
448 if self.offset_unset:
449 self.Raise('No offset set with offset-unset: should another '
450 'entry provide this correct offset?')
451 self.offset = tools.Align(offset, self.align)
Simon Glassbf7fd502016-11-25 20:15:51 -0700452 needed = self.pad_before + self.contents_size + self.pad_after
453 needed = tools.Align(needed, self.align_size)
454 size = self.size
455 if not size:
456 size = needed
Simon Glass3ab95982018-08-01 15:22:37 -0600457 new_offset = self.offset + size
458 aligned_offset = tools.Align(new_offset, self.align_end)
459 if aligned_offset != new_offset:
460 size = aligned_offset - self.offset
461 new_offset = aligned_offset
Simon Glassbf7fd502016-11-25 20:15:51 -0700462
463 if not self.size:
464 self.size = size
465
466 if self.size < needed:
467 self.Raise("Entry contents size is %#x (%d) but entry size is "
468 "%#x (%d)" % (needed, needed, self.size, self.size))
469 # Check that the alignment is correct. It could be wrong if the
Simon Glass3ab95982018-08-01 15:22:37 -0600470 # and offset or size values were provided (i.e. not calculated), but
Simon Glassbf7fd502016-11-25 20:15:51 -0700471 # conflict with the provided alignment values
472 if self.size != tools.Align(self.size, self.align_size):
473 self.Raise("Size %#x (%d) does not match align-size %#x (%d)" %
474 (self.size, self.size, self.align_size, self.align_size))
Simon Glass3ab95982018-08-01 15:22:37 -0600475 if self.offset != tools.Align(self.offset, self.align):
476 self.Raise("Offset %#x (%d) does not match align %#x (%d)" %
477 (self.offset, self.offset, self.align, self.align))
Simon Glass9f297b02019-07-20 12:23:36 -0600478 self.Detail(' - packed: offset=%#x, size=%#x, content_size=%#x, next_offset=%x' %
479 (self.offset, self.size, self.contents_size, new_offset))
Simon Glassbf7fd502016-11-25 20:15:51 -0700480
Simon Glass3ab95982018-08-01 15:22:37 -0600481 return new_offset
Simon Glassbf7fd502016-11-25 20:15:51 -0700482
483 def Raise(self, msg):
484 """Convenience function to raise an error referencing a node"""
485 raise ValueError("Node '%s': %s" % (self._node.path, msg))
486
Simon Glass189f2912021-03-21 18:24:31 +1300487 def Info(self, msg):
488 """Convenience function to log info referencing a node"""
489 tag = "Info '%s'" % self._node.path
490 tout.Detail('%30s: %s' % (tag, msg))
491
Simon Glass9f297b02019-07-20 12:23:36 -0600492 def Detail(self, msg):
493 """Convenience function to log detail referencing a node"""
494 tag = "Node '%s'" % self._node.path
495 tout.Detail('%30s: %s' % (tag, msg))
496
Simon Glass53af22a2018-07-17 13:25:32 -0600497 def GetEntryArgsOrProps(self, props, required=False):
498 """Return the values of a set of properties
499
500 Args:
501 props: List of EntryArg objects
502
503 Raises:
504 ValueError if a property is not found
505 """
506 values = []
507 missing = []
508 for prop in props:
509 python_prop = prop.name.replace('-', '_')
510 if hasattr(self, python_prop):
511 value = getattr(self, python_prop)
512 else:
513 value = None
514 if value is None:
515 value = self.GetArg(prop.name, prop.datatype)
516 if value is None and required:
517 missing.append(prop.name)
518 values.append(value)
519 if missing:
Simon Glass939d1062021-01-06 21:35:16 -0700520 self.GetImage().MissingArgs(self, missing)
Simon Glass53af22a2018-07-17 13:25:32 -0600521 return values
522
Simon Glassbf7fd502016-11-25 20:15:51 -0700523 def GetPath(self):
524 """Get the path of a node
525
526 Returns:
527 Full path of the node for this entry
528 """
529 return self._node.path
530
Simon Glass631f7522021-03-21 18:24:32 +1300531 def GetData(self, required=True):
Simon Glass63e7ba62020-10-26 17:40:16 -0600532 """Get the contents of an entry
533
Simon Glass631f7522021-03-21 18:24:32 +1300534 Args:
535 required: True if the data must be present, False if it is OK to
536 return None
537
Simon Glass63e7ba62020-10-26 17:40:16 -0600538 Returns:
539 bytes content of the entry, excluding any padding. If the entry is
540 compressed, the compressed data is returned
541 """
Simon Glass9f297b02019-07-20 12:23:36 -0600542 self.Detail('GetData: size %s' % ToHexSize(self.data))
Simon Glassbf7fd502016-11-25 20:15:51 -0700543 return self.data
544
Simon Glass271a0832020-11-02 12:55:43 -0700545 def GetPaddedData(self, data=None):
546 """Get the data for an entry including any padding
547
548 Gets the entry data and uses its section's pad-byte value to add padding
549 before and after as defined by the pad-before and pad-after properties.
550
551 This does not consider alignment.
552
553 Returns:
554 Contents of the entry along with any pad bytes before and
555 after it (bytes)
556 """
557 if data is None:
558 data = self.GetData()
559 return self.section.GetPaddedDataForEntry(self, data)
560
Simon Glass3ab95982018-08-01 15:22:37 -0600561 def GetOffsets(self):
Simon Glassed7dd5e2019-07-08 13:18:30 -0600562 """Get the offsets for siblings
563
564 Some entry types can contain information about the position or size of
565 other entries. An example of this is the Intel Flash Descriptor, which
566 knows where the Intel Management Engine section should go.
567
568 If this entry knows about the position of other entries, it can specify
569 this by returning values here
570
571 Returns:
572 Dict:
573 key: Entry type
574 value: List containing position and size of the given entry
Simon Glasscf549042019-07-08 13:18:39 -0600575 type. Either can be None if not known
Simon Glassed7dd5e2019-07-08 13:18:30 -0600576 """
Simon Glassbf7fd502016-11-25 20:15:51 -0700577 return {}
578
Simon Glasscf549042019-07-08 13:18:39 -0600579 def SetOffsetSize(self, offset, size):
580 """Set the offset and/or size of an entry
581
582 Args:
583 offset: New offset, or None to leave alone
584 size: New size, or None to leave alone
585 """
586 if offset is not None:
587 self.offset = offset
588 if size is not None:
589 self.size = size
Simon Glassbf7fd502016-11-25 20:15:51 -0700590
Simon Glassdbf6be92018-08-01 15:22:42 -0600591 def SetImagePos(self, image_pos):
592 """Set the position in the image
593
594 Args:
595 image_pos: Position of this entry in the image
596 """
597 self.image_pos = image_pos + self.offset
598
Simon Glassbf7fd502016-11-25 20:15:51 -0700599 def ProcessContents(self):
Simon Glassa0dcaf22019-07-08 14:25:35 -0600600 """Do any post-packing updates of entry contents
601
602 This function should call ProcessContentsUpdate() to update the entry
603 contents, if necessary, returning its return value here.
604
605 Args:
606 data: Data to set to the contents (bytes)
607
608 Returns:
609 True if the new data size is OK, False if expansion is needed
610
611 Raises:
612 ValueError if the new data size is not the same as the old and
613 state.AllowEntryExpansion() is False
614 """
615 return True
Simon Glass19790632017-11-13 18:55:01 -0700616
Simon Glassf55382b2018-06-01 09:38:13 -0600617 def WriteSymbols(self, section):
Simon Glass19790632017-11-13 18:55:01 -0700618 """Write symbol values into binary files for access at run time
619
620 Args:
Simon Glassf55382b2018-06-01 09:38:13 -0600621 section: Section containing the entry
Simon Glass19790632017-11-13 18:55:01 -0700622 """
623 pass
Simon Glass18546952018-06-01 09:38:16 -0600624
Simon Glass6ddd6112020-10-26 17:40:18 -0600625 def CheckEntries(self):
Simon Glass3ab95982018-08-01 15:22:37 -0600626 """Check that the entry offsets are correct
Simon Glass18546952018-06-01 09:38:16 -0600627
Simon Glass3ab95982018-08-01 15:22:37 -0600628 This is used for entries which have extra offset requirements (other
Simon Glass18546952018-06-01 09:38:16 -0600629 than having to be fully inside their section). Sub-classes can implement
630 this function and raise if there is a problem.
631 """
632 pass
Simon Glass3b0c3822018-06-01 09:38:20 -0600633
Simon Glass8122f392018-07-17 13:25:28 -0600634 @staticmethod
Simon Glass163ed6c2018-09-14 04:57:36 -0600635 def GetStr(value):
636 if value is None:
637 return '<none> '
638 return '%08x' % value
639
640 @staticmethod
Simon Glass1be70d22018-07-17 13:25:49 -0600641 def WriteMapLine(fd, indent, name, offset, size, image_pos):
Simon Glass163ed6c2018-09-14 04:57:36 -0600642 print('%s %s%s %s %s' % (Entry.GetStr(image_pos), ' ' * indent,
643 Entry.GetStr(offset), Entry.GetStr(size),
644 name), file=fd)
Simon Glass8122f392018-07-17 13:25:28 -0600645
Simon Glass3b0c3822018-06-01 09:38:20 -0600646 def WriteMap(self, fd, indent):
647 """Write a map of the entry to a .map file
648
649 Args:
650 fd: File to write the map to
651 indent: Curent indent level of map (0=none, 1=one level, etc.)
652 """
Simon Glass1be70d22018-07-17 13:25:49 -0600653 self.WriteMapLine(fd, indent, self.name, self.offset, self.size,
654 self.image_pos)
Simon Glass53af22a2018-07-17 13:25:32 -0600655
Simon Glass11e36cc2018-07-17 13:25:38 -0600656 def GetEntries(self):
657 """Return a list of entries contained by this entry
658
659 Returns:
660 List of entries, or None if none. A normal entry has no entries
661 within it so will return None
662 """
663 return None
664
Simon Glass53af22a2018-07-17 13:25:32 -0600665 def GetArg(self, name, datatype=str):
666 """Get the value of an entry argument or device-tree-node property
667
668 Some node properties can be provided as arguments to binman. First check
669 the entry arguments, and fall back to the device tree if not found
670
671 Args:
672 name: Argument name
673 datatype: Data type (str or int)
674
675 Returns:
676 Value of argument as a string or int, or None if no value
677
678 Raises:
679 ValueError if the argument cannot be converted to in
680 """
Simon Glassc55a50f2018-09-14 04:57:19 -0600681 value = state.GetEntryArg(name)
Simon Glass53af22a2018-07-17 13:25:32 -0600682 if value is not None:
683 if datatype == int:
684 try:
685 value = int(value)
686 except ValueError:
687 self.Raise("Cannot convert entry arg '%s' (value '%s') to integer" %
688 (name, value))
689 elif datatype == str:
690 pass
691 else:
692 raise ValueError("GetArg() internal error: Unknown data type '%s'" %
693 datatype)
694 else:
695 value = fdt_util.GetDatatype(self._node, name, datatype)
696 return value
Simon Glassfd8d1f72018-07-17 13:25:36 -0600697
698 @staticmethod
699 def WriteDocs(modules, test_missing=None):
700 """Write out documentation about the various entry types to stdout
701
702 Args:
703 modules: List of modules to include
704 test_missing: Used for testing. This is a module to report
705 as missing
706 """
707 print('''Binman Entry Documentation
708===========================
709
710This file describes the entry types supported by binman. These entry types can
711be placed in an image one by one to build up a final firmware image. It is
712fairly easy to create new entry types. Just add a new file to the 'etype'
713directory. You can use the existing entries as examples.
714
715Note that some entries are subclasses of others, using and extending their
716features to produce new behaviours.
717
718
719''')
720 modules = sorted(modules)
721
722 # Don't show the test entry
723 if '_testing' in modules:
724 modules.remove('_testing')
725 missing = []
726 for name in modules:
Simon Glassb35fb172021-03-18 20:25:04 +1300727 module = Entry.Lookup('WriteDocs', name, False)
Simon Glassfd8d1f72018-07-17 13:25:36 -0600728 docs = getattr(module, '__doc__')
729 if test_missing == name:
730 docs = None
731 if docs:
732 lines = docs.splitlines()
733 first_line = lines[0]
734 rest = [line[4:] for line in lines[1:]]
735 hdr = 'Entry: %s: %s' % (name.replace('_', '-'), first_line)
736 print(hdr)
737 print('-' * len(hdr))
738 print('\n'.join(rest))
739 print()
740 print()
741 else:
742 missing.append(name)
743
744 if missing:
745 raise ValueError('Documentation is missing for modules: %s' %
746 ', '.join(missing))
Simon Glassa326b492018-09-14 04:57:11 -0600747
748 def GetUniqueName(self):
749 """Get a unique name for a node
750
751 Returns:
752 String containing a unique name for a node, consisting of the name
753 of all ancestors (starting from within the 'binman' node) separated
754 by a dot ('.'). This can be useful for generating unique filesnames
755 in the output directory.
756 """
757 name = self.name
758 node = self._node
759 while node.parent:
760 node = node.parent
761 if node.name == 'binman':
762 break
763 name = '%s.%s' % (node.name, name)
764 return name
Simon Glassba64a0b2018-09-14 04:57:29 -0600765
766 def ExpandToLimit(self, limit):
767 """Expand an entry so that it ends at the given offset limit"""
768 if self.offset + self.size < limit:
769 self.size = limit - self.offset
770 # Request the contents again, since changing the size requires that
771 # the data grows. This should not fail, but check it to be sure.
772 if not self.ObtainContents():
773 self.Raise('Cannot obtain contents when expanding entry')
Simon Glassfa1c9372019-07-08 13:18:38 -0600774
775 def HasSibling(self, name):
776 """Check if there is a sibling of a given name
777
778 Returns:
779 True if there is an entry with this name in the the same section,
780 else False
781 """
782 return name in self.section.GetEntries()
Simon Glasscf228942019-07-08 14:25:28 -0600783
784 def GetSiblingImagePos(self, name):
785 """Return the image position of the given sibling
786
787 Returns:
788 Image position of sibling, or None if the sibling has no position,
789 or False if there is no such sibling
790 """
791 if not self.HasSibling(name):
792 return False
793 return self.section.GetEntries()[name].image_pos
Simon Glass41b8ba02019-07-08 14:25:43 -0600794
795 @staticmethod
796 def AddEntryInfo(entries, indent, name, etype, size, image_pos,
797 uncomp_size, offset, entry):
798 """Add a new entry to the entries list
799
800 Args:
801 entries: List (of EntryInfo objects) to add to
802 indent: Current indent level to add to list
803 name: Entry name (string)
804 etype: Entry type (string)
805 size: Entry size in bytes (int)
806 image_pos: Position within image in bytes (int)
807 uncomp_size: Uncompressed size if the entry uses compression, else
808 None
809 offset: Entry offset within parent in bytes (int)
810 entry: Entry object
811 """
812 entries.append(EntryInfo(indent, name, etype, size, image_pos,
813 uncomp_size, offset, entry))
814
815 def ListEntries(self, entries, indent):
816 """Add files in this entry to the list of entries
817
818 This can be overridden by subclasses which need different behaviour.
819
820 Args:
821 entries: List (of EntryInfo objects) to add to
822 indent: Current indent level to add to list
823 """
824 self.AddEntryInfo(entries, indent, self.name, self.etype, self.size,
825 self.image_pos, self.uncomp_size, self.offset, self)
Simon Glassf667e452019-07-08 14:25:50 -0600826
Simon Glass943bf782021-11-23 21:09:50 -0700827 def ReadData(self, decomp=True, alt_format=None):
Simon Glassf667e452019-07-08 14:25:50 -0600828 """Read the data for an entry from the image
829
830 This is used when the image has been read in and we want to extract the
831 data for a particular entry from that image.
832
833 Args:
834 decomp: True to decompress any compressed data before returning it;
835 False to return the raw, uncompressed data
836
837 Returns:
838 Entry data (bytes)
839 """
840 # Use True here so that we get an uncompressed section to work from,
841 # although compressed sections are currently not supported
Simon Glass2d553c02019-09-25 08:56:21 -0600842 tout.Debug("ReadChildData section '%s', entry '%s'" %
843 (self.section.GetPath(), self.GetPath()))
Simon Glass943bf782021-11-23 21:09:50 -0700844 data = self.section.ReadChildData(self, decomp, alt_format)
Simon Glassa9cd39e2019-07-20 12:24:04 -0600845 return data
Simon Glassd5079332019-07-20 12:23:41 -0600846
Simon Glass943bf782021-11-23 21:09:50 -0700847 def ReadChildData(self, child, decomp=True, alt_format=None):
Simon Glass2d553c02019-09-25 08:56:21 -0600848 """Read the data for a particular child entry
Simon Glass4e185e82019-09-25 08:56:20 -0600849
850 This reads data from the parent and extracts the piece that relates to
851 the given child.
852
853 Args:
Simon Glass943bf782021-11-23 21:09:50 -0700854 child (Entry): Child entry to read data for (must be valid)
855 decomp (bool): True to decompress any compressed data before
856 returning it; False to return the raw, uncompressed data
857 alt_format (str): Alternative format to read in, or None
Simon Glass4e185e82019-09-25 08:56:20 -0600858
859 Returns:
860 Data for the child (bytes)
861 """
862 pass
863
Simon Glassd5079332019-07-20 12:23:41 -0600864 def LoadData(self, decomp=True):
865 data = self.ReadData(decomp)
Simon Glass10f9d002019-07-20 12:23:50 -0600866 self.contents_size = len(data)
Simon Glassd5079332019-07-20 12:23:41 -0600867 self.ProcessContentsUpdate(data)
868 self.Detail('Loaded data size %x' % len(data))
Simon Glassc5ad04b2019-07-20 12:23:46 -0600869
Simon Glass943bf782021-11-23 21:09:50 -0700870 def GetAltFormat(self, data, alt_format):
871 """Read the data for an extry in an alternative format
872
873 Supported formats are list in the documentation for each entry. An
874 example is fdtmap which provides .
875
876 Args:
877 data (bytes): Data to convert (this should have been produced by the
878 entry)
879 alt_format (str): Format to use
880
881 """
882 pass
883
Simon Glassc5ad04b2019-07-20 12:23:46 -0600884 def GetImage(self):
885 """Get the image containing this entry
886
887 Returns:
888 Image object containing this entry
889 """
890 return self.section.GetImage()
Simon Glass10f9d002019-07-20 12:23:50 -0600891
892 def WriteData(self, data, decomp=True):
893 """Write the data to an entry in the image
894
895 This is used when the image has been read in and we want to replace the
896 data for a particular entry in that image.
897
898 The image must be re-packed and written out afterwards.
899
900 Args:
901 data: Data to replace it with
902 decomp: True to compress the data if needed, False if data is
903 already compressed so should be used as is
904
905 Returns:
906 True if the data did not result in a resize of this entry, False if
907 the entry must be resized
908 """
Simon Glass9a5d3dc2019-10-31 07:43:02 -0600909 if self.size is not None:
910 self.contents_size = self.size
911 else:
912 self.contents_size = self.pre_reset_size
Simon Glass10f9d002019-07-20 12:23:50 -0600913 ok = self.ProcessContentsUpdate(data)
914 self.Detail('WriteData: size=%x, ok=%s' % (len(data), ok))
Simon Glass7210c892019-07-20 12:24:05 -0600915 section_ok = self.section.WriteChildData(self)
916 return ok and section_ok
917
918 def WriteChildData(self, child):
919 """Handle writing the data in a child entry
920
921 This should be called on the child's parent section after the child's
Simon Glass557693e2021-11-23 11:03:44 -0700922 data has been updated. It should update any data structures needed to
923 validate that the update is successful.
Simon Glass7210c892019-07-20 12:24:05 -0600924
925 This base-class implementation does nothing, since the base Entry object
926 does not have any children.
927
928 Args:
929 child: Child Entry that was written
930
931 Returns:
932 True if the section could be updated successfully, False if the
Simon Glass557693e2021-11-23 11:03:44 -0700933 data is such that the section could not update
Simon Glass7210c892019-07-20 12:24:05 -0600934 """
935 return True
Simon Glasseba1f0c2019-07-20 12:23:55 -0600936
937 def GetSiblingOrder(self):
938 """Get the relative order of an entry amoung its siblings
939
940 Returns:
941 'start' if this entry is first among siblings, 'end' if last,
942 otherwise None
943 """
944 entries = list(self.section.GetEntries().values())
945 if entries:
946 if self == entries[0]:
947 return 'start'
948 elif self == entries[-1]:
949 return 'end'
950 return 'middle'
Simon Glass4f9f1052020-07-09 18:39:38 -0600951
952 def SetAllowMissing(self, allow_missing):
953 """Set whether a section allows missing external blobs
954
955 Args:
956 allow_missing: True if allowed, False if not allowed
957 """
958 # This is meaningless for anything other than sections
959 pass
Simon Glassb1cca952020-07-09 18:39:40 -0600960
Heiko Thierya89c8f22022-01-06 11:49:41 +0100961 def SetAllowFakeBlob(self, allow_fake):
962 """Set whether a section allows to create a fake blob
963
964 Args:
965 allow_fake: True if allowed, False if not allowed
966 """
Simon Glassf4590e02022-01-09 20:13:46 -0700967 self.allow_fake = allow_fake
Heiko Thierya89c8f22022-01-06 11:49:41 +0100968
Simon Glassb1cca952020-07-09 18:39:40 -0600969 def CheckMissing(self, missing_list):
970 """Check if any entries in this section have missing external blobs
971
972 If there are missing blobs, the entries are added to the list
973
974 Args:
975 missing_list: List of Entry objects to be added to
976 """
977 if self.missing:
978 missing_list.append(self)
Simon Glass87958982020-09-01 05:13:57 -0600979
Simon Glass790ba9f2022-01-12 13:10:36 -0700980 def check_fake_fname(self, fname):
981 """If the file is missing and the entry allows fake blobs, fake it
982
983 Sets self.faked to True if faked
984
985 Args:
986 fname (str): Filename to check
987
988 Returns:
989 fname (str): Filename of faked file
990 """
991 if self.allow_fake and not pathlib.Path(fname).is_file():
992 outfname = tools.GetOutputFilename(os.path.basename(fname))
993 with open(outfname, "wb") as out:
994 out.truncate(1024)
995 self.faked = True
996 return outfname
997 return fname
998
Heiko Thierya89c8f22022-01-06 11:49:41 +0100999 def CheckFakedBlobs(self, faked_blobs_list):
1000 """Check if any entries in this section have faked external blobs
1001
1002 If there are faked blobs, the entries are added to the list
1003
1004 Args:
1005 fake_blobs_list: List of Entry objects to be added to
1006 """
1007 # This is meaningless for anything other than blobs
1008 pass
1009
Simon Glass87958982020-09-01 05:13:57 -06001010 def GetAllowMissing(self):
1011 """Get whether a section allows missing external blobs
1012
1013 Returns:
1014 True if allowed, False if not allowed
1015 """
1016 return self.allow_missing
Simon Glassb2381432020-09-06 10:39:09 -06001017
1018 def GetHelpTags(self):
1019 """Get the tags use for missing-blob help
1020
1021 Returns:
1022 list of possible tags, most desirable first
1023 """
1024 return list(filter(None, [self.missing_msg, self.name, self.etype]))
Simon Glass87c96292020-10-26 17:40:06 -06001025
1026 def CompressData(self, indata):
1027 """Compress data according to the entry's compression method
1028
1029 Args:
1030 indata: Data to compress
1031
1032 Returns:
1033 Compressed data (first word is the compressed size)
1034 """
Simon Glass97c3e9a2020-10-26 17:40:15 -06001035 self.uncomp_data = indata
Simon Glass87c96292020-10-26 17:40:06 -06001036 if self.compress != 'none':
1037 self.uncomp_size = len(indata)
Simon Glassad35ce52022-01-09 20:14:03 -07001038 data = comp_util.Compress(indata, self.compress)
Simon Glass87c96292020-10-26 17:40:06 -06001039 return data
Simon Glassb35fb172021-03-18 20:25:04 +13001040
1041 @classmethod
1042 def UseExpanded(cls, node, etype, new_etype):
1043 """Check whether to use an expanded entry type
1044
1045 This is called by Entry.Create() when it finds an expanded version of
1046 an entry type (e.g. 'u-boot-expanded'). If this method returns True then
1047 it will be used (e.g. in place of 'u-boot'). If it returns False, it is
1048 ignored.
1049
1050 Args:
1051 node: Node object containing information about the entry to
1052 create
1053 etype: Original entry type being used
1054 new_etype: New entry type proposed
1055
1056 Returns:
1057 True to use this entry type, False to use the original one
1058 """
1059 tout.Info("Node '%s': etype '%s': %s selected" %
1060 (node.path, etype, new_etype))
1061 return True
Simon Glass943bf782021-11-23 21:09:50 -07001062
1063 def CheckAltFormats(self, alt_formats):
1064 """Add any alternative formats supported by this entry type
1065
1066 Args:
1067 alt_formats (dict): Dict to add alt_formats to:
1068 key: Name of alt format
1069 value: Help text
1070 """
1071 pass
Simon Glass386c63c2022-01-09 20:13:50 -07001072
1073 def AddBintools(self, tools):
1074 """Add the bintools used by this entry type
1075
1076 Args:
1077 tools (dict of Bintool):
1078 """
1079 pass
1080
1081 @classmethod
1082 def AddBintool(self, tools, name):
1083 """Add a new bintool to the tools used by this etype
1084
1085 Args:
1086 name: Name of the tool
1087 """
1088 btool = bintool.Bintool.create(name)
1089 tools[name] = btool
1090 return btool