blob: dc26f8f167b034ee7d7d4dad91567c760b7bcfdb [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 Glassc1aa66e2022-01-29 14:14:04 -070017from patman.tools import to_hex, to_hex_size
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 Glass4f9ee832022-01-09 20:14:09 -070080 missing_bintools: List of missing bintools for this entry
Simon Glassbf7fd502016-11-25 20:15:51 -070081 """
Simon Glassc6bd6e22019-07-20 12:23:45 -060082 def __init__(self, section, etype, node, name_prefix=''):
Simon Glass8dbb7442019-08-24 07:22:44 -060083 # Put this here to allow entry-docs and help to work without libfdt
84 global state
Simon Glass16287932020-04-17 18:09:03 -060085 from binman import state
Simon Glass8dbb7442019-08-24 07:22:44 -060086
Simon Glass25ac0e62018-06-01 09:38:14 -060087 self.section = section
Simon Glassbf7fd502016-11-25 20:15:51 -070088 self.etype = etype
89 self._node = node
Simon Glassc8d48ef2018-06-01 09:38:21 -060090 self.name = node and (name_prefix + node.name) or 'none'
Simon Glass3ab95982018-08-01 15:22:37 -060091 self.offset = None
Simon Glassbf7fd502016-11-25 20:15:51 -070092 self.size = None
Simon Glass9a5d3dc2019-10-31 07:43:02 -060093 self.pre_reset_size = None
Simon Glass8287ee82019-07-08 14:25:30 -060094 self.uncomp_size = None
Simon Glass24d0d3c2018-07-17 13:25:47 -060095 self.data = None
Simon Glass97c3e9a2020-10-26 17:40:15 -060096 self.uncomp_data = None
Simon Glassbf7fd502016-11-25 20:15:51 -070097 self.contents_size = 0
98 self.align = None
99 self.align_size = None
100 self.align_end = None
101 self.pad_before = 0
102 self.pad_after = 0
Simon Glass3ab95982018-08-01 15:22:37 -0600103 self.offset_unset = False
Simon Glassdbf6be92018-08-01 15:22:42 -0600104 self.image_pos = None
Simon Glassc4738312021-11-23 11:03:43 -0700105 self.expand_size = False
Simon Glass8287ee82019-07-08 14:25:30 -0600106 self.compress = 'none'
Simon Glassb1cca952020-07-09 18:39:40 -0600107 self.missing = False
Heiko Thierya89c8f22022-01-06 11:49:41 +0100108 self.faked = False
Simon Glass87958982020-09-01 05:13:57 -0600109 self.external = False
110 self.allow_missing = False
Heiko Thierya89c8f22022-01-06 11:49:41 +0100111 self.allow_fake = False
Simon Glass386c63c2022-01-09 20:13:50 -0700112 self.bintools = {}
Simon Glass4f9ee832022-01-09 20:14:09 -0700113 self.missing_bintools = []
Simon Glassbf7fd502016-11-25 20:15:51 -0700114
115 @staticmethod
Simon Glass858436d2021-11-23 21:09:49 -0700116 def FindEntryClass(etype, expanded):
Simon Glassfd8d1f72018-07-17 13:25:36 -0600117 """Look up the entry class for a node.
Simon Glassbf7fd502016-11-25 20:15:51 -0700118
119 Args:
Simon Glassfd8d1f72018-07-17 13:25:36 -0600120 node_node: Path name of Node object containing information about
121 the entry to create (used for errors)
122 etype: Entry type to use
Simon Glassb35fb172021-03-18 20:25:04 +1300123 expanded: Use the expanded version of etype
Simon Glassbf7fd502016-11-25 20:15:51 -0700124
125 Returns:
Simon Glassb35fb172021-03-18 20:25:04 +1300126 The entry class object if found, else None if not found and expanded
Simon Glass858436d2021-11-23 21:09:49 -0700127 is True, else a tuple:
128 module name that could not be found
129 exception received
Simon Glassbf7fd502016-11-25 20:15:51 -0700130 """
Simon Glassdd57c132018-06-01 09:38:11 -0600131 # Convert something like 'u-boot@0' to 'u_boot' since we are only
132 # interested in the type.
Simon Glassbf7fd502016-11-25 20:15:51 -0700133 module_name = etype.replace('-', '_')
Simon Glassb35fb172021-03-18 20:25:04 +1300134
Simon Glassdd57c132018-06-01 09:38:11 -0600135 if '@' in module_name:
136 module_name = module_name.split('@')[0]
Simon Glassb35fb172021-03-18 20:25:04 +1300137 if expanded:
138 module_name += '_expanded'
Simon Glassbf7fd502016-11-25 20:15:51 -0700139 module = modules.get(module_name)
140
Simon Glassbadf0ec2018-06-01 09:38:15 -0600141 # Also allow entry-type modules to be brought in from the etype directory.
142
Simon Glassbf7fd502016-11-25 20:15:51 -0700143 # Import the module if we have not already done so.
144 if not module:
145 try:
Simon Glass16287932020-04-17 18:09:03 -0600146 module = importlib.import_module('binman.etype.' + module_name)
Simon Glassfd8d1f72018-07-17 13:25:36 -0600147 except ImportError as e:
Simon Glassb35fb172021-03-18 20:25:04 +1300148 if expanded:
149 return None
Simon Glass858436d2021-11-23 21:09:49 -0700150 return module_name, e
Simon Glassbf7fd502016-11-25 20:15:51 -0700151 modules[module_name] = module
152
Simon Glassfd8d1f72018-07-17 13:25:36 -0600153 # Look up the expected class name
154 return getattr(module, 'Entry_%s' % module_name)
155
156 @staticmethod
Simon Glass858436d2021-11-23 21:09:49 -0700157 def Lookup(node_path, etype, expanded, missing_etype=False):
158 """Look up the entry class for a node.
159
160 Args:
161 node_node (str): Path name of Node object containing information
162 about the entry to create (used for errors)
163 etype (str): Entry type to use
164 expanded (bool): Use the expanded version of etype
165 missing_etype (bool): True to default to a blob etype if the
166 requested etype is not found
167
168 Returns:
169 The entry class object if found, else None if not found and expanded
170 is True
171
172 Raise:
173 ValueError if expanded is False and the class is not found
174 """
175 # Convert something like 'u-boot@0' to 'u_boot' since we are only
176 # interested in the type.
177 cls = Entry.FindEntryClass(etype, expanded)
178 if cls is None:
179 return None
180 elif isinstance(cls, tuple):
181 if missing_etype:
182 cls = Entry.FindEntryClass('blob', False)
183 if isinstance(cls, tuple): # This should not fail
184 module_name, e = cls
185 raise ValueError(
186 "Unknown entry type '%s' in node '%s' (expected etype/%s.py, error '%s'" %
187 (etype, node_path, module_name, e))
188 return cls
189
190 @staticmethod
191 def Create(section, node, etype=None, expanded=False, missing_etype=False):
Simon Glassfd8d1f72018-07-17 13:25:36 -0600192 """Create a new entry for a node.
193
194 Args:
Simon Glass858436d2021-11-23 21:09:49 -0700195 section (entry_Section): Section object containing this node
196 node (Node): Node object containing information about the entry to
197 create
198 etype (str): Entry type to use, or None to work it out (used for
199 tests)
200 expanded (bool): Use the expanded version of etype
201 missing_etype (bool): True to default to a blob etype if the
202 requested etype is not found
Simon Glassfd8d1f72018-07-17 13:25:36 -0600203
204 Returns:
205 A new Entry object of the correct type (a subclass of Entry)
206 """
207 if not etype:
208 etype = fdt_util.GetString(node, 'type', node.name)
Simon Glass858436d2021-11-23 21:09:49 -0700209 obj = Entry.Lookup(node.path, etype, expanded, missing_etype)
Simon Glassb35fb172021-03-18 20:25:04 +1300210 if obj and expanded:
211 # Check whether to use the expanded entry
212 new_etype = etype + '-expanded'
Simon Glass3d433382021-03-21 18:24:30 +1300213 can_expand = not fdt_util.GetBool(node, 'no-expanded')
214 if can_expand and obj.UseExpanded(node, etype, new_etype):
Simon Glassb35fb172021-03-18 20:25:04 +1300215 etype = new_etype
216 else:
217 obj = None
218 if not obj:
Simon Glass858436d2021-11-23 21:09:49 -0700219 obj = Entry.Lookup(node.path, etype, False, missing_etype)
Simon Glassfd8d1f72018-07-17 13:25:36 -0600220
Simon Glassbf7fd502016-11-25 20:15:51 -0700221 # Call its constructor to get the object we want.
Simon Glass25ac0e62018-06-01 09:38:14 -0600222 return obj(section, etype, node)
Simon Glassbf7fd502016-11-25 20:15:51 -0700223
224 def ReadNode(self):
225 """Read entry information from the node
226
Simon Glassc6bd6e22019-07-20 12:23:45 -0600227 This must be called as the first thing after the Entry is created.
228
Simon Glassbf7fd502016-11-25 20:15:51 -0700229 This reads all the fields we recognise from the node, ready for use.
230 """
Simon Glass15a587c2018-07-17 13:25:51 -0600231 if 'pos' in self._node.props:
232 self.Raise("Please use 'offset' instead of 'pos'")
Simon Glass3ab95982018-08-01 15:22:37 -0600233 self.offset = fdt_util.GetInt(self._node, 'offset')
Simon Glassbf7fd502016-11-25 20:15:51 -0700234 self.size = fdt_util.GetInt(self._node, 'size')
Simon Glass12bb1a92019-07-20 12:23:51 -0600235 self.orig_offset = fdt_util.GetInt(self._node, 'orig-offset')
236 self.orig_size = fdt_util.GetInt(self._node, 'orig-size')
237 if self.GetImage().copy_to_orig:
238 self.orig_offset = self.offset
239 self.orig_size = self.size
Simon Glassc52c9e72019-07-08 14:25:37 -0600240
Simon Glassffded752019-07-08 14:25:46 -0600241 # These should not be set in input files, but are set in an FDT map,
242 # which is also read by this code.
243 self.image_pos = fdt_util.GetInt(self._node, 'image-pos')
244 self.uncomp_size = fdt_util.GetInt(self._node, 'uncomp-size')
245
Simon Glassbf7fd502016-11-25 20:15:51 -0700246 self.align = fdt_util.GetInt(self._node, 'align')
Simon Glassc1aa66e2022-01-29 14:14:04 -0700247 if tools.not_power_of_two(self.align):
Simon Glassbf7fd502016-11-25 20:15:51 -0700248 raise ValueError("Node '%s': Alignment %s must be a power of two" %
249 (self._node.path, self.align))
Simon Glass5ff9fed2021-03-21 18:24:33 +1300250 if self.section and self.align is None:
251 self.align = self.section.align_default
Simon Glassbf7fd502016-11-25 20:15:51 -0700252 self.pad_before = fdt_util.GetInt(self._node, 'pad-before', 0)
253 self.pad_after = fdt_util.GetInt(self._node, 'pad-after', 0)
254 self.align_size = fdt_util.GetInt(self._node, 'align-size')
Simon Glassc1aa66e2022-01-29 14:14:04 -0700255 if tools.not_power_of_two(self.align_size):
Simon Glass8beb11e2019-07-08 14:25:47 -0600256 self.Raise("Alignment size %s must be a power of two" %
257 self.align_size)
Simon Glassbf7fd502016-11-25 20:15:51 -0700258 self.align_end = fdt_util.GetInt(self._node, 'align-end')
Simon Glass3ab95982018-08-01 15:22:37 -0600259 self.offset_unset = fdt_util.GetBool(self._node, 'offset-unset')
Simon Glassba64a0b2018-09-14 04:57:29 -0600260 self.expand_size = fdt_util.GetBool(self._node, 'expand-size')
Simon Glassb2381432020-09-06 10:39:09 -0600261 self.missing_msg = fdt_util.GetString(self._node, 'missing-msg')
Simon Glassbf7fd502016-11-25 20:15:51 -0700262
Simon Glass87c96292020-10-26 17:40:06 -0600263 # This is only supported by blobs and sections at present
264 self.compress = fdt_util.GetString(self._node, 'compress', 'none')
265
Simon Glass6c234bf2018-09-14 04:57:18 -0600266 def GetDefaultFilename(self):
267 return None
268
Simon Glassa8adb6d2019-07-20 12:23:28 -0600269 def GetFdts(self):
270 """Get the device trees used by this entry
Simon Glass539aece2018-09-14 04:57:22 -0600271
272 Returns:
Simon Glassa8adb6d2019-07-20 12:23:28 -0600273 Empty dict, if this entry is not a .dtb, otherwise:
274 Dict:
275 key: Filename from this entry (without the path)
Simon Glass4bdd3002019-07-20 12:23:31 -0600276 value: Tuple:
Simon Glassadb67bb2021-03-18 20:25:02 +1300277 Entry object for this dtb
Simon Glass4bdd3002019-07-20 12:23:31 -0600278 Filename of file containing this dtb
Simon Glass539aece2018-09-14 04:57:22 -0600279 """
Simon Glassa8adb6d2019-07-20 12:23:28 -0600280 return {}
Simon Glass539aece2018-09-14 04:57:22 -0600281
Simon Glass0a98b282018-09-14 04:57:28 -0600282 def ExpandEntries(self):
Simon Glassa01d1a22021-03-18 20:24:52 +1300283 """Expand out entries which produce other entries
284
285 Some entries generate subnodes automatically, from which sub-entries
286 are then created. This method allows those to be added to the binman
287 definition for the current image. An entry which implements this method
288 should call state.AddSubnode() to add a subnode and can add properties
289 with state.AddString(), etc.
290
291 An example is 'files', which produces a section containing a list of
292 files.
293 """
Simon Glass0a98b282018-09-14 04:57:28 -0600294 pass
295
Simon Glassa9fad072020-10-26 17:40:17 -0600296 def AddMissingProperties(self, have_image_pos):
297 """Add new properties to the device tree as needed for this entry
298
299 Args:
300 have_image_pos: True if this entry has an image position. This can
301 be False if its parent section is compressed, since compression
302 groups all entries together into a compressed block of data,
303 obscuring the start of each individual child entry
304 """
305 for prop in ['offset', 'size']:
Simon Glass078ab1a2018-07-06 10:27:41 -0600306 if not prop in self._node.props:
Simon Glassf46621d2018-09-14 04:57:21 -0600307 state.AddZeroProp(self._node, prop)
Simon Glassa9fad072020-10-26 17:40:17 -0600308 if have_image_pos and 'image-pos' not in self._node.props:
309 state.AddZeroProp(self._node, 'image-pos')
Simon Glass12bb1a92019-07-20 12:23:51 -0600310 if self.GetImage().allow_repack:
311 if self.orig_offset is not None:
312 state.AddZeroProp(self._node, 'orig-offset', True)
313 if self.orig_size is not None:
314 state.AddZeroProp(self._node, 'orig-size', True)
315
Simon Glass8287ee82019-07-08 14:25:30 -0600316 if self.compress != 'none':
317 state.AddZeroProp(self._node, 'uncomp-size')
Simon Glasse0e5df92018-09-14 04:57:31 -0600318 err = state.CheckAddHashProp(self._node)
319 if err:
320 self.Raise(err)
Simon Glass078ab1a2018-07-06 10:27:41 -0600321
322 def SetCalculatedProperties(self):
323 """Set the value of device-tree properties calculated by binman"""
Simon Glassf46621d2018-09-14 04:57:21 -0600324 state.SetInt(self._node, 'offset', self.offset)
325 state.SetInt(self._node, 'size', self.size)
Simon Glass8beb11e2019-07-08 14:25:47 -0600326 base = self.section.GetRootSkipAtStart() if self.section else 0
Simon Glassa9fad072020-10-26 17:40:17 -0600327 if self.image_pos is not None:
Simon Glass08594d42020-11-02 12:55:44 -0700328 state.SetInt(self._node, 'image-pos', self.image_pos - base)
Simon Glass12bb1a92019-07-20 12:23:51 -0600329 if self.GetImage().allow_repack:
330 if self.orig_offset is not None:
331 state.SetInt(self._node, 'orig-offset', self.orig_offset, True)
332 if self.orig_size is not None:
333 state.SetInt(self._node, 'orig-size', self.orig_size, True)
Simon Glass8287ee82019-07-08 14:25:30 -0600334 if self.uncomp_size is not None:
335 state.SetInt(self._node, 'uncomp-size', self.uncomp_size)
Simon Glasse0e5df92018-09-14 04:57:31 -0600336 state.CheckSetHashValue(self._node, self.GetData)
Simon Glass078ab1a2018-07-06 10:27:41 -0600337
Simon Glassecab8972018-07-06 10:27:40 -0600338 def ProcessFdt(self, fdt):
Simon Glass6ed45ba2018-09-14 04:57:24 -0600339 """Allow entries to adjust the device tree
340
341 Some entries need to adjust the device tree for their purposes. This
342 may involve adding or deleting properties.
343
344 Returns:
345 True if processing is complete
346 False if processing could not be completed due to a dependency.
347 This will cause the entry to be retried after others have been
348 called
349 """
Simon Glassecab8972018-07-06 10:27:40 -0600350 return True
351
Simon Glassc8d48ef2018-06-01 09:38:21 -0600352 def SetPrefix(self, prefix):
353 """Set the name prefix for a node
354
355 Args:
356 prefix: Prefix to set, or '' to not use a prefix
357 """
358 if prefix:
359 self.name = prefix + self.name
360
Simon Glass5c890232018-07-06 10:27:19 -0600361 def SetContents(self, data):
362 """Set the contents of an entry
363
364 This sets both the data and content_size properties
365
366 Args:
Simon Glass5b463fc2019-07-08 14:25:33 -0600367 data: Data to set to the contents (bytes)
Simon Glass5c890232018-07-06 10:27:19 -0600368 """
369 self.data = data
370 self.contents_size = len(self.data)
371
372 def ProcessContentsUpdate(self, data):
Simon Glass5b463fc2019-07-08 14:25:33 -0600373 """Update the contents of an entry, after the size is fixed
Simon Glass5c890232018-07-06 10:27:19 -0600374
Simon Glassa0dcaf22019-07-08 14:25:35 -0600375 This checks that the new data is the same size as the old. If the size
376 has changed, this triggers a re-run of the packing algorithm.
Simon Glass5c890232018-07-06 10:27:19 -0600377
378 Args:
Simon Glass5b463fc2019-07-08 14:25:33 -0600379 data: Data to set to the contents (bytes)
Simon Glass5c890232018-07-06 10:27:19 -0600380
381 Raises:
382 ValueError if the new data size is not the same as the old
383 """
Simon Glassa0dcaf22019-07-08 14:25:35 -0600384 size_ok = True
Simon Glassc52c9e72019-07-08 14:25:37 -0600385 new_size = len(data)
Simon Glass61ec04f2019-07-20 12:23:58 -0600386 if state.AllowEntryExpansion() and new_size > self.contents_size:
387 # self.data will indicate the new size needed
388 size_ok = False
389 elif state.AllowEntryContraction() and new_size < self.contents_size:
390 size_ok = False
391
392 # If not allowed to change, try to deal with it or give up
393 if size_ok:
Simon Glassc52c9e72019-07-08 14:25:37 -0600394 if new_size > self.contents_size:
Simon Glass61ec04f2019-07-20 12:23:58 -0600395 self.Raise('Cannot update entry size from %d to %d' %
396 (self.contents_size, new_size))
397
398 # Don't let the data shrink. Pad it if necessary
399 if size_ok and new_size < self.contents_size:
Simon Glassc1aa66e2022-01-29 14:14:04 -0700400 data += tools.get_bytes(0, self.contents_size - new_size)
Simon Glass61ec04f2019-07-20 12:23:58 -0600401
402 if not size_ok:
Simon Glassf3385a52022-01-29 14:14:15 -0700403 tout.debug("Entry '%s' size change from %s to %s" % (
Simon Glassc1aa66e2022-01-29 14:14:04 -0700404 self._node.path, to_hex(self.contents_size),
405 to_hex(new_size)))
Simon Glass5c890232018-07-06 10:27:19 -0600406 self.SetContents(data)
Simon Glassa0dcaf22019-07-08 14:25:35 -0600407 return size_ok
Simon Glass5c890232018-07-06 10:27:19 -0600408
Simon Glassbf7fd502016-11-25 20:15:51 -0700409 def ObtainContents(self):
410 """Figure out the contents of an entry.
411
412 Returns:
413 True if the contents were found, False if another call is needed
414 after the other entries are processed.
415 """
416 # No contents by default: subclasses can implement this
417 return True
418
Simon Glassc52c9e72019-07-08 14:25:37 -0600419 def ResetForPack(self):
420 """Reset offset/size fields so that packing can be done again"""
Simon Glass9f297b02019-07-20 12:23:36 -0600421 self.Detail('ResetForPack: offset %s->%s, size %s->%s' %
Simon Glassc1aa66e2022-01-29 14:14:04 -0700422 (to_hex(self.offset), to_hex(self.orig_offset),
423 to_hex(self.size), to_hex(self.orig_size)))
Simon Glass9a5d3dc2019-10-31 07:43:02 -0600424 self.pre_reset_size = self.size
Simon Glassc52c9e72019-07-08 14:25:37 -0600425 self.offset = self.orig_offset
426 self.size = self.orig_size
427
Simon Glass3ab95982018-08-01 15:22:37 -0600428 def Pack(self, offset):
Simon Glass25ac0e62018-06-01 09:38:14 -0600429 """Figure out how to pack the entry into the section
Simon Glassbf7fd502016-11-25 20:15:51 -0700430
431 Most of the time the entries are not fully specified. There may be
432 an alignment but no size. In that case we take the size from the
433 contents of the entry.
434
Simon Glass3ab95982018-08-01 15:22:37 -0600435 If an entry has no hard-coded offset, it will be placed at @offset.
Simon Glassbf7fd502016-11-25 20:15:51 -0700436
Simon Glass3ab95982018-08-01 15:22:37 -0600437 Once this function is complete, both the offset and size of the
Simon Glassbf7fd502016-11-25 20:15:51 -0700438 entry will be know.
439
440 Args:
Simon Glass3ab95982018-08-01 15:22:37 -0600441 Current section offset pointer
Simon Glassbf7fd502016-11-25 20:15:51 -0700442
443 Returns:
Simon Glass3ab95982018-08-01 15:22:37 -0600444 New section offset pointer (after this entry)
Simon Glassbf7fd502016-11-25 20:15:51 -0700445 """
Simon Glass9f297b02019-07-20 12:23:36 -0600446 self.Detail('Packing: offset=%s, size=%s, content_size=%x' %
Simon Glassc1aa66e2022-01-29 14:14:04 -0700447 (to_hex(self.offset), to_hex(self.size),
Simon Glass9f297b02019-07-20 12:23:36 -0600448 self.contents_size))
Simon Glass3ab95982018-08-01 15:22:37 -0600449 if self.offset is None:
450 if self.offset_unset:
451 self.Raise('No offset set with offset-unset: should another '
452 'entry provide this correct offset?')
Simon Glassc1aa66e2022-01-29 14:14:04 -0700453 self.offset = tools.align(offset, self.align)
Simon Glassbf7fd502016-11-25 20:15:51 -0700454 needed = self.pad_before + self.contents_size + self.pad_after
Simon Glassc1aa66e2022-01-29 14:14:04 -0700455 needed = tools.align(needed, self.align_size)
Simon Glassbf7fd502016-11-25 20:15:51 -0700456 size = self.size
457 if not size:
458 size = needed
Simon Glass3ab95982018-08-01 15:22:37 -0600459 new_offset = self.offset + size
Simon Glassc1aa66e2022-01-29 14:14:04 -0700460 aligned_offset = tools.align(new_offset, self.align_end)
Simon Glass3ab95982018-08-01 15:22:37 -0600461 if aligned_offset != new_offset:
462 size = aligned_offset - self.offset
463 new_offset = aligned_offset
Simon Glassbf7fd502016-11-25 20:15:51 -0700464
465 if not self.size:
466 self.size = size
467
468 if self.size < needed:
469 self.Raise("Entry contents size is %#x (%d) but entry size is "
470 "%#x (%d)" % (needed, needed, self.size, self.size))
471 # Check that the alignment is correct. It could be wrong if the
Simon Glass3ab95982018-08-01 15:22:37 -0600472 # and offset or size values were provided (i.e. not calculated), but
Simon Glassbf7fd502016-11-25 20:15:51 -0700473 # conflict with the provided alignment values
Simon Glassc1aa66e2022-01-29 14:14:04 -0700474 if self.size != tools.align(self.size, self.align_size):
Simon Glassbf7fd502016-11-25 20:15:51 -0700475 self.Raise("Size %#x (%d) does not match align-size %#x (%d)" %
476 (self.size, self.size, self.align_size, self.align_size))
Simon Glassc1aa66e2022-01-29 14:14:04 -0700477 if self.offset != tools.align(self.offset, self.align):
Simon Glass3ab95982018-08-01 15:22:37 -0600478 self.Raise("Offset %#x (%d) does not match align %#x (%d)" %
479 (self.offset, self.offset, self.align, self.align))
Simon Glass9f297b02019-07-20 12:23:36 -0600480 self.Detail(' - packed: offset=%#x, size=%#x, content_size=%#x, next_offset=%x' %
481 (self.offset, self.size, self.contents_size, new_offset))
Simon Glassbf7fd502016-11-25 20:15:51 -0700482
Simon Glass3ab95982018-08-01 15:22:37 -0600483 return new_offset
Simon Glassbf7fd502016-11-25 20:15:51 -0700484
485 def Raise(self, msg):
486 """Convenience function to raise an error referencing a node"""
487 raise ValueError("Node '%s': %s" % (self._node.path, msg))
488
Simon Glass189f2912021-03-21 18:24:31 +1300489 def Info(self, msg):
490 """Convenience function to log info referencing a node"""
491 tag = "Info '%s'" % self._node.path
Simon Glassf3385a52022-01-29 14:14:15 -0700492 tout.detail('%30s: %s' % (tag, msg))
Simon Glass189f2912021-03-21 18:24:31 +1300493
Simon Glass9f297b02019-07-20 12:23:36 -0600494 def Detail(self, msg):
495 """Convenience function to log detail referencing a node"""
496 tag = "Node '%s'" % self._node.path
Simon Glassf3385a52022-01-29 14:14:15 -0700497 tout.detail('%30s: %s' % (tag, msg))
Simon Glass9f297b02019-07-20 12:23:36 -0600498
Simon Glass53af22a2018-07-17 13:25:32 -0600499 def GetEntryArgsOrProps(self, props, required=False):
500 """Return the values of a set of properties
501
502 Args:
503 props: List of EntryArg objects
504
505 Raises:
506 ValueError if a property is not found
507 """
508 values = []
509 missing = []
510 for prop in props:
511 python_prop = prop.name.replace('-', '_')
512 if hasattr(self, python_prop):
513 value = getattr(self, python_prop)
514 else:
515 value = None
516 if value is None:
517 value = self.GetArg(prop.name, prop.datatype)
518 if value is None and required:
519 missing.append(prop.name)
520 values.append(value)
521 if missing:
Simon Glass939d1062021-01-06 21:35:16 -0700522 self.GetImage().MissingArgs(self, missing)
Simon Glass53af22a2018-07-17 13:25:32 -0600523 return values
524
Simon Glassbf7fd502016-11-25 20:15:51 -0700525 def GetPath(self):
526 """Get the path of a node
527
528 Returns:
529 Full path of the node for this entry
530 """
531 return self._node.path
532
Simon Glass631f7522021-03-21 18:24:32 +1300533 def GetData(self, required=True):
Simon Glass63e7ba62020-10-26 17:40:16 -0600534 """Get the contents of an entry
535
Simon Glass631f7522021-03-21 18:24:32 +1300536 Args:
537 required: True if the data must be present, False if it is OK to
538 return None
539
Simon Glass63e7ba62020-10-26 17:40:16 -0600540 Returns:
541 bytes content of the entry, excluding any padding. If the entry is
542 compressed, the compressed data is returned
543 """
Simon Glassc1aa66e2022-01-29 14:14:04 -0700544 self.Detail('GetData: size %s' % to_hex_size(self.data))
Simon Glassbf7fd502016-11-25 20:15:51 -0700545 return self.data
546
Simon Glass271a0832020-11-02 12:55:43 -0700547 def GetPaddedData(self, data=None):
548 """Get the data for an entry including any padding
549
550 Gets the entry data and uses its section's pad-byte value to add padding
551 before and after as defined by the pad-before and pad-after properties.
552
553 This does not consider alignment.
554
555 Returns:
556 Contents of the entry along with any pad bytes before and
557 after it (bytes)
558 """
559 if data is None:
560 data = self.GetData()
561 return self.section.GetPaddedDataForEntry(self, data)
562
Simon Glass3ab95982018-08-01 15:22:37 -0600563 def GetOffsets(self):
Simon Glassed7dd5e2019-07-08 13:18:30 -0600564 """Get the offsets for siblings
565
566 Some entry types can contain information about the position or size of
567 other entries. An example of this is the Intel Flash Descriptor, which
568 knows where the Intel Management Engine section should go.
569
570 If this entry knows about the position of other entries, it can specify
571 this by returning values here
572
573 Returns:
574 Dict:
575 key: Entry type
576 value: List containing position and size of the given entry
Simon Glasscf549042019-07-08 13:18:39 -0600577 type. Either can be None if not known
Simon Glassed7dd5e2019-07-08 13:18:30 -0600578 """
Simon Glassbf7fd502016-11-25 20:15:51 -0700579 return {}
580
Simon Glasscf549042019-07-08 13:18:39 -0600581 def SetOffsetSize(self, offset, size):
582 """Set the offset and/or size of an entry
583
584 Args:
585 offset: New offset, or None to leave alone
586 size: New size, or None to leave alone
587 """
588 if offset is not None:
589 self.offset = offset
590 if size is not None:
591 self.size = size
Simon Glassbf7fd502016-11-25 20:15:51 -0700592
Simon Glassdbf6be92018-08-01 15:22:42 -0600593 def SetImagePos(self, image_pos):
594 """Set the position in the image
595
596 Args:
597 image_pos: Position of this entry in the image
598 """
599 self.image_pos = image_pos + self.offset
600
Simon Glassbf7fd502016-11-25 20:15:51 -0700601 def ProcessContents(self):
Simon Glassa0dcaf22019-07-08 14:25:35 -0600602 """Do any post-packing updates of entry contents
603
604 This function should call ProcessContentsUpdate() to update the entry
605 contents, if necessary, returning its return value here.
606
607 Args:
608 data: Data to set to the contents (bytes)
609
610 Returns:
611 True if the new data size is OK, False if expansion is needed
612
613 Raises:
614 ValueError if the new data size is not the same as the old and
615 state.AllowEntryExpansion() is False
616 """
617 return True
Simon Glass19790632017-11-13 18:55:01 -0700618
Simon Glassf55382b2018-06-01 09:38:13 -0600619 def WriteSymbols(self, section):
Simon Glass19790632017-11-13 18:55:01 -0700620 """Write symbol values into binary files for access at run time
621
622 Args:
Simon Glassf55382b2018-06-01 09:38:13 -0600623 section: Section containing the entry
Simon Glass19790632017-11-13 18:55:01 -0700624 """
625 pass
Simon Glass18546952018-06-01 09:38:16 -0600626
Simon Glass6ddd6112020-10-26 17:40:18 -0600627 def CheckEntries(self):
Simon Glass3ab95982018-08-01 15:22:37 -0600628 """Check that the entry offsets are correct
Simon Glass18546952018-06-01 09:38:16 -0600629
Simon Glass3ab95982018-08-01 15:22:37 -0600630 This is used for entries which have extra offset requirements (other
Simon Glass18546952018-06-01 09:38:16 -0600631 than having to be fully inside their section). Sub-classes can implement
632 this function and raise if there is a problem.
633 """
634 pass
Simon Glass3b0c3822018-06-01 09:38:20 -0600635
Simon Glass8122f392018-07-17 13:25:28 -0600636 @staticmethod
Simon Glass163ed6c2018-09-14 04:57:36 -0600637 def GetStr(value):
638 if value is None:
639 return '<none> '
640 return '%08x' % value
641
642 @staticmethod
Simon Glass1be70d22018-07-17 13:25:49 -0600643 def WriteMapLine(fd, indent, name, offset, size, image_pos):
Simon Glass163ed6c2018-09-14 04:57:36 -0600644 print('%s %s%s %s %s' % (Entry.GetStr(image_pos), ' ' * indent,
645 Entry.GetStr(offset), Entry.GetStr(size),
646 name), file=fd)
Simon Glass8122f392018-07-17 13:25:28 -0600647
Simon Glass3b0c3822018-06-01 09:38:20 -0600648 def WriteMap(self, fd, indent):
649 """Write a map of the entry to a .map file
650
651 Args:
652 fd: File to write the map to
653 indent: Curent indent level of map (0=none, 1=one level, etc.)
654 """
Simon Glass1be70d22018-07-17 13:25:49 -0600655 self.WriteMapLine(fd, indent, self.name, self.offset, self.size,
656 self.image_pos)
Simon Glass53af22a2018-07-17 13:25:32 -0600657
Simon Glass11e36cc2018-07-17 13:25:38 -0600658 def GetEntries(self):
659 """Return a list of entries contained by this entry
660
661 Returns:
662 List of entries, or None if none. A normal entry has no entries
663 within it so will return None
664 """
665 return None
666
Simon Glass53af22a2018-07-17 13:25:32 -0600667 def GetArg(self, name, datatype=str):
668 """Get the value of an entry argument or device-tree-node property
669
670 Some node properties can be provided as arguments to binman. First check
671 the entry arguments, and fall back to the device tree if not found
672
673 Args:
674 name: Argument name
675 datatype: Data type (str or int)
676
677 Returns:
678 Value of argument as a string or int, or None if no value
679
680 Raises:
681 ValueError if the argument cannot be converted to in
682 """
Simon Glassc55a50f2018-09-14 04:57:19 -0600683 value = state.GetEntryArg(name)
Simon Glass53af22a2018-07-17 13:25:32 -0600684 if value is not None:
685 if datatype == int:
686 try:
687 value = int(value)
688 except ValueError:
689 self.Raise("Cannot convert entry arg '%s' (value '%s') to integer" %
690 (name, value))
691 elif datatype == str:
692 pass
693 else:
694 raise ValueError("GetArg() internal error: Unknown data type '%s'" %
695 datatype)
696 else:
697 value = fdt_util.GetDatatype(self._node, name, datatype)
698 return value
Simon Glassfd8d1f72018-07-17 13:25:36 -0600699
700 @staticmethod
701 def WriteDocs(modules, test_missing=None):
702 """Write out documentation about the various entry types to stdout
703
704 Args:
705 modules: List of modules to include
706 test_missing: Used for testing. This is a module to report
707 as missing
708 """
709 print('''Binman Entry Documentation
710===========================
711
712This file describes the entry types supported by binman. These entry types can
713be placed in an image one by one to build up a final firmware image. It is
714fairly easy to create new entry types. Just add a new file to the 'etype'
715directory. You can use the existing entries as examples.
716
717Note that some entries are subclasses of others, using and extending their
718features to produce new behaviours.
719
720
721''')
722 modules = sorted(modules)
723
724 # Don't show the test entry
725 if '_testing' in modules:
726 modules.remove('_testing')
727 missing = []
728 for name in modules:
Simon Glassb35fb172021-03-18 20:25:04 +1300729 module = Entry.Lookup('WriteDocs', name, False)
Simon Glassfd8d1f72018-07-17 13:25:36 -0600730 docs = getattr(module, '__doc__')
731 if test_missing == name:
732 docs = None
733 if docs:
734 lines = docs.splitlines()
735 first_line = lines[0]
736 rest = [line[4:] for line in lines[1:]]
737 hdr = 'Entry: %s: %s' % (name.replace('_', '-'), first_line)
738 print(hdr)
739 print('-' * len(hdr))
740 print('\n'.join(rest))
741 print()
742 print()
743 else:
744 missing.append(name)
745
746 if missing:
747 raise ValueError('Documentation is missing for modules: %s' %
748 ', '.join(missing))
Simon Glassa326b492018-09-14 04:57:11 -0600749
750 def GetUniqueName(self):
751 """Get a unique name for a node
752
753 Returns:
754 String containing a unique name for a node, consisting of the name
755 of all ancestors (starting from within the 'binman' node) separated
756 by a dot ('.'). This can be useful for generating unique filesnames
757 in the output directory.
758 """
759 name = self.name
760 node = self._node
761 while node.parent:
762 node = node.parent
763 if node.name == 'binman':
764 break
765 name = '%s.%s' % (node.name, name)
766 return name
Simon Glassba64a0b2018-09-14 04:57:29 -0600767
768 def ExpandToLimit(self, limit):
769 """Expand an entry so that it ends at the given offset limit"""
770 if self.offset + self.size < limit:
771 self.size = limit - self.offset
772 # Request the contents again, since changing the size requires that
773 # the data grows. This should not fail, but check it to be sure.
774 if not self.ObtainContents():
775 self.Raise('Cannot obtain contents when expanding entry')
Simon Glassfa1c9372019-07-08 13:18:38 -0600776
777 def HasSibling(self, name):
778 """Check if there is a sibling of a given name
779
780 Returns:
781 True if there is an entry with this name in the the same section,
782 else False
783 """
784 return name in self.section.GetEntries()
Simon Glasscf228942019-07-08 14:25:28 -0600785
786 def GetSiblingImagePos(self, name):
787 """Return the image position of the given sibling
788
789 Returns:
790 Image position of sibling, or None if the sibling has no position,
791 or False if there is no such sibling
792 """
793 if not self.HasSibling(name):
794 return False
795 return self.section.GetEntries()[name].image_pos
Simon Glass41b8ba02019-07-08 14:25:43 -0600796
797 @staticmethod
798 def AddEntryInfo(entries, indent, name, etype, size, image_pos,
799 uncomp_size, offset, entry):
800 """Add a new entry to the entries list
801
802 Args:
803 entries: List (of EntryInfo objects) to add to
804 indent: Current indent level to add to list
805 name: Entry name (string)
806 etype: Entry type (string)
807 size: Entry size in bytes (int)
808 image_pos: Position within image in bytes (int)
809 uncomp_size: Uncompressed size if the entry uses compression, else
810 None
811 offset: Entry offset within parent in bytes (int)
812 entry: Entry object
813 """
814 entries.append(EntryInfo(indent, name, etype, size, image_pos,
815 uncomp_size, offset, entry))
816
817 def ListEntries(self, entries, indent):
818 """Add files in this entry to the list of entries
819
820 This can be overridden by subclasses which need different behaviour.
821
822 Args:
823 entries: List (of EntryInfo objects) to add to
824 indent: Current indent level to add to list
825 """
826 self.AddEntryInfo(entries, indent, self.name, self.etype, self.size,
827 self.image_pos, self.uncomp_size, self.offset, self)
Simon Glassf667e452019-07-08 14:25:50 -0600828
Simon Glass943bf782021-11-23 21:09:50 -0700829 def ReadData(self, decomp=True, alt_format=None):
Simon Glassf667e452019-07-08 14:25:50 -0600830 """Read the data for an entry from the image
831
832 This is used when the image has been read in and we want to extract the
833 data for a particular entry from that image.
834
835 Args:
836 decomp: True to decompress any compressed data before returning it;
837 False to return the raw, uncompressed data
838
839 Returns:
840 Entry data (bytes)
841 """
842 # Use True here so that we get an uncompressed section to work from,
843 # although compressed sections are currently not supported
Simon Glassf3385a52022-01-29 14:14:15 -0700844 tout.debug("ReadChildData section '%s', entry '%s'" %
Simon Glass2d553c02019-09-25 08:56:21 -0600845 (self.section.GetPath(), self.GetPath()))
Simon Glass943bf782021-11-23 21:09:50 -0700846 data = self.section.ReadChildData(self, decomp, alt_format)
Simon Glassa9cd39e2019-07-20 12:24:04 -0600847 return data
Simon Glassd5079332019-07-20 12:23:41 -0600848
Simon Glass943bf782021-11-23 21:09:50 -0700849 def ReadChildData(self, child, decomp=True, alt_format=None):
Simon Glass2d553c02019-09-25 08:56:21 -0600850 """Read the data for a particular child entry
Simon Glass4e185e82019-09-25 08:56:20 -0600851
852 This reads data from the parent and extracts the piece that relates to
853 the given child.
854
855 Args:
Simon Glass943bf782021-11-23 21:09:50 -0700856 child (Entry): Child entry to read data for (must be valid)
857 decomp (bool): True to decompress any compressed data before
858 returning it; False to return the raw, uncompressed data
859 alt_format (str): Alternative format to read in, or None
Simon Glass4e185e82019-09-25 08:56:20 -0600860
861 Returns:
862 Data for the child (bytes)
863 """
864 pass
865
Simon Glassd5079332019-07-20 12:23:41 -0600866 def LoadData(self, decomp=True):
867 data = self.ReadData(decomp)
Simon Glass10f9d002019-07-20 12:23:50 -0600868 self.contents_size = len(data)
Simon Glassd5079332019-07-20 12:23:41 -0600869 self.ProcessContentsUpdate(data)
870 self.Detail('Loaded data size %x' % len(data))
Simon Glassc5ad04b2019-07-20 12:23:46 -0600871
Simon Glass943bf782021-11-23 21:09:50 -0700872 def GetAltFormat(self, data, alt_format):
873 """Read the data for an extry in an alternative format
874
875 Supported formats are list in the documentation for each entry. An
876 example is fdtmap which provides .
877
878 Args:
879 data (bytes): Data to convert (this should have been produced by the
880 entry)
881 alt_format (str): Format to use
882
883 """
884 pass
885
Simon Glassc5ad04b2019-07-20 12:23:46 -0600886 def GetImage(self):
887 """Get the image containing this entry
888
889 Returns:
890 Image object containing this entry
891 """
892 return self.section.GetImage()
Simon Glass10f9d002019-07-20 12:23:50 -0600893
894 def WriteData(self, data, decomp=True):
895 """Write the data to an entry in the image
896
897 This is used when the image has been read in and we want to replace the
898 data for a particular entry in that image.
899
900 The image must be re-packed and written out afterwards.
901
902 Args:
903 data: Data to replace it with
904 decomp: True to compress the data if needed, False if data is
905 already compressed so should be used as is
906
907 Returns:
908 True if the data did not result in a resize of this entry, False if
909 the entry must be resized
910 """
Simon Glass9a5d3dc2019-10-31 07:43:02 -0600911 if self.size is not None:
912 self.contents_size = self.size
913 else:
914 self.contents_size = self.pre_reset_size
Simon Glass10f9d002019-07-20 12:23:50 -0600915 ok = self.ProcessContentsUpdate(data)
916 self.Detail('WriteData: size=%x, ok=%s' % (len(data), ok))
Simon Glass7210c892019-07-20 12:24:05 -0600917 section_ok = self.section.WriteChildData(self)
918 return ok and section_ok
919
920 def WriteChildData(self, child):
921 """Handle writing the data in a child entry
922
923 This should be called on the child's parent section after the child's
Simon Glass557693e2021-11-23 11:03:44 -0700924 data has been updated. It should update any data structures needed to
925 validate that the update is successful.
Simon Glass7210c892019-07-20 12:24:05 -0600926
927 This base-class implementation does nothing, since the base Entry object
928 does not have any children.
929
930 Args:
931 child: Child Entry that was written
932
933 Returns:
934 True if the section could be updated successfully, False if the
Simon Glass557693e2021-11-23 11:03:44 -0700935 data is such that the section could not update
Simon Glass7210c892019-07-20 12:24:05 -0600936 """
937 return True
Simon Glasseba1f0c2019-07-20 12:23:55 -0600938
939 def GetSiblingOrder(self):
940 """Get the relative order of an entry amoung its siblings
941
942 Returns:
943 'start' if this entry is first among siblings, 'end' if last,
944 otherwise None
945 """
946 entries = list(self.section.GetEntries().values())
947 if entries:
948 if self == entries[0]:
949 return 'start'
950 elif self == entries[-1]:
951 return 'end'
952 return 'middle'
Simon Glass4f9f1052020-07-09 18:39:38 -0600953
954 def SetAllowMissing(self, allow_missing):
955 """Set whether a section allows missing external blobs
956
957 Args:
958 allow_missing: True if allowed, False if not allowed
959 """
960 # This is meaningless for anything other than sections
961 pass
Simon Glassb1cca952020-07-09 18:39:40 -0600962
Heiko Thierya89c8f22022-01-06 11:49:41 +0100963 def SetAllowFakeBlob(self, allow_fake):
964 """Set whether a section allows to create a fake blob
965
966 Args:
967 allow_fake: True if allowed, False if not allowed
968 """
Simon Glassf4590e02022-01-09 20:13:46 -0700969 self.allow_fake = allow_fake
Heiko Thierya89c8f22022-01-06 11:49:41 +0100970
Simon Glassb1cca952020-07-09 18:39:40 -0600971 def CheckMissing(self, missing_list):
972 """Check if any entries in this section have missing external blobs
973
974 If there are missing blobs, the entries are added to the list
975
976 Args:
977 missing_list: List of Entry objects to be added to
978 """
979 if self.missing:
980 missing_list.append(self)
Simon Glass87958982020-09-01 05:13:57 -0600981
Simon Glass790ba9f2022-01-12 13:10:36 -0700982 def check_fake_fname(self, fname):
983 """If the file is missing and the entry allows fake blobs, fake it
984
985 Sets self.faked to True if faked
986
987 Args:
988 fname (str): Filename to check
989
990 Returns:
991 fname (str): Filename of faked file
992 """
993 if self.allow_fake and not pathlib.Path(fname).is_file():
Simon Glassc1aa66e2022-01-29 14:14:04 -0700994 outfname = tools.get_output_filename(os.path.basename(fname))
Simon Glass790ba9f2022-01-12 13:10:36 -0700995 with open(outfname, "wb") as out:
996 out.truncate(1024)
997 self.faked = True
998 return outfname
999 return fname
1000
Heiko Thierya89c8f22022-01-06 11:49:41 +01001001 def CheckFakedBlobs(self, faked_blobs_list):
1002 """Check if any entries in this section have faked external blobs
1003
1004 If there are faked blobs, the entries are added to the list
1005
1006 Args:
1007 fake_blobs_list: List of Entry objects to be added to
1008 """
1009 # This is meaningless for anything other than blobs
1010 pass
1011
Simon Glass87958982020-09-01 05:13:57 -06001012 def GetAllowMissing(self):
1013 """Get whether a section allows missing external blobs
1014
1015 Returns:
1016 True if allowed, False if not allowed
1017 """
1018 return self.allow_missing
Simon Glassb2381432020-09-06 10:39:09 -06001019
Simon Glass4f9ee832022-01-09 20:14:09 -07001020 def record_missing_bintool(self, bintool):
1021 """Record a missing bintool that was needed to produce this entry
1022
1023 Args:
1024 bintool (Bintool): Bintool that was missing
1025 """
1026 self.missing_bintools.append(bintool)
1027
1028 def check_missing_bintools(self, missing_list):
1029 """Check if any entries in this section have missing bintools
1030
1031 If there are missing bintools, these are added to the list
1032
1033 Args:
1034 missing_list: List of Bintool objects to be added to
1035 """
1036 missing_list += self.missing_bintools
1037
Simon Glassb2381432020-09-06 10:39:09 -06001038 def GetHelpTags(self):
1039 """Get the tags use for missing-blob help
1040
1041 Returns:
1042 list of possible tags, most desirable first
1043 """
1044 return list(filter(None, [self.missing_msg, self.name, self.etype]))
Simon Glass87c96292020-10-26 17:40:06 -06001045
1046 def CompressData(self, indata):
1047 """Compress data according to the entry's compression method
1048
1049 Args:
1050 indata: Data to compress
1051
1052 Returns:
1053 Compressed data (first word is the compressed size)
1054 """
Simon Glass97c3e9a2020-10-26 17:40:15 -06001055 self.uncomp_data = indata
Simon Glass87c96292020-10-26 17:40:06 -06001056 if self.compress != 'none':
1057 self.uncomp_size = len(indata)
Simon Glass0d1e95a2022-01-09 20:14:04 -07001058 data = comp_util.compress(indata, self.compress)
Simon Glass87c96292020-10-26 17:40:06 -06001059 return data
Simon Glassb35fb172021-03-18 20:25:04 +13001060
1061 @classmethod
1062 def UseExpanded(cls, node, etype, new_etype):
1063 """Check whether to use an expanded entry type
1064
1065 This is called by Entry.Create() when it finds an expanded version of
1066 an entry type (e.g. 'u-boot-expanded'). If this method returns True then
1067 it will be used (e.g. in place of 'u-boot'). If it returns False, it is
1068 ignored.
1069
1070 Args:
1071 node: Node object containing information about the entry to
1072 create
1073 etype: Original entry type being used
1074 new_etype: New entry type proposed
1075
1076 Returns:
1077 True to use this entry type, False to use the original one
1078 """
Simon Glassf3385a52022-01-29 14:14:15 -07001079 tout.info("Node '%s': etype '%s': %s selected" %
Simon Glassb35fb172021-03-18 20:25:04 +13001080 (node.path, etype, new_etype))
1081 return True
Simon Glass943bf782021-11-23 21:09:50 -07001082
1083 def CheckAltFormats(self, alt_formats):
1084 """Add any alternative formats supported by this entry type
1085
1086 Args:
1087 alt_formats (dict): Dict to add alt_formats to:
1088 key: Name of alt format
1089 value: Help text
1090 """
1091 pass
Simon Glass386c63c2022-01-09 20:13:50 -07001092
1093 def AddBintools(self, tools):
1094 """Add the bintools used by this entry type
1095
1096 Args:
1097 tools (dict of Bintool):
1098 """
1099 pass
1100
1101 @classmethod
1102 def AddBintool(self, tools, name):
1103 """Add a new bintool to the tools used by this etype
1104
1105 Args:
1106 name: Name of the tool
1107 """
1108 btool = bintool.Bintool.create(name)
1109 tools[name] = btool
1110 return btool