blob: dc26f8f167b034ee7d7d4dad91567c760b7bcfdb [file] [log] [blame]
Tom Rini10e47792018-05-06 17:58:06 -04001# SPDX-License-Identifier: GPL-2.0+
Simon Glass2574ef62016-11-25 20:15:51 -07002# Copyright (c) 2016 Google, Inc
3#
Simon Glass2574ef62016-11-25 20:15:51 -07004# Base class for all entries
5#
6
Simon Glass91710b32018-07-17 13:25:32 -06007from collections import namedtuple
Simon Glass7ccca832019-10-31 07:42:59 -06008import importlib
Simon Glass691198c2018-06-01 09:38:15 -06009import os
Simon Glass7a602fd2022-01-12 13:10:36 -070010import pathlib
Simon Glass691198c2018-06-01 09:38:15 -060011import sys
Simon Glass29aa7362018-09-14 04:57:19 -060012
Simon Glass4eae9252022-01-09 20:13:50 -070013from binman import bintool
Simon Glass3ac7d832022-01-09 20:14:03 -070014from binman import comp_util
Simon Glassc585dd42020-04-17 18:09:03 -060015from dtoc import fdt_util
Simon Glassa997ea52020-04-17 18:09:04 -060016from patman import tools
Simon Glass80025522022-01-29 14:14:04 -070017from patman.tools import to_hex, to_hex_size
Simon Glassa997ea52020-04-17 18:09:04 -060018from patman import tout
Simon Glass2574ef62016-11-25 20:15:51 -070019
20modules = {}
21
Simon Glass91710b32018-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 Glass6b156f82019-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 Glass91710b32018-07-17 13:25:32 -060031
Simon Glass2574ef62016-11-25 20:15:51 -070032class Entry(object):
Simon Glassad5a7712018-06-01 09:38:14 -060033 """An Entry in the section
Simon Glass2574ef62016-11-25 20:15:51 -070034
35 An entry corresponds to a single node in the device-tree description
Simon Glassad5a7712018-06-01 09:38:14 -060036 of the section. Each entry ends up being a part of the final section.
Simon Glass2574ef62016-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 Glass3a9a2b82018-07-17 13:25:28 -060044 section: Section object containing this entry
Simon Glass2574ef62016-11-25 20:15:51 -070045 node: The node that created this entry
Simon Glasse8561af2018-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 Glass2574ef62016-11-25 20:15:51 -070048 size: Entry size in bytes, None if not known
Simon Glass1fdb4872019-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 Glassaa2fcf92019-07-08 14:25:30 -060051 uncomp_size: Size of uncompressed data in bytes, if the entry is
52 compressed, else None
Simon Glass2574ef62016-11-25 20:15:51 -070053 contents_size: Size of contents in bytes, 0 by default
Simon Glassafb9caa2020-10-26 17:40:10 -060054 align: Entry start offset alignment relative to the start of the
55 containing section, or None
Simon Glass2574ef62016-11-25 20:15:51 -070056 align_size: Entry size alignment, or None
Simon Glassafb9caa2020-10-26 17:40:10 -060057 align_end: Entry end offset alignment relative to the start of the
58 containing section, or None
Simon Glassd12599d2020-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 Glass789b34402020-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 Glassaa2fcf92019-07-08 14:25:30 -060070 compress: Compression algoithm used (e.g. 'lz4'), 'none' if none
Simon Glasse61b6f62019-07-08 14:25:37 -060071 orig_offset: Original offset value read from node
72 orig_size: Original size value read from node
Simon Glassb8f90372020-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 Thiery6d451362022-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 Glassb8f90372020-09-01 05:13:57 -060078 external: True if this entry contains an external binary blob
Simon Glass4eae9252022-01-09 20:13:50 -070079 bintools: Bintools used by this entry (only populated for Image)
Simon Glass66152ce2022-01-09 20:14:09 -070080 missing_bintools: List of missing bintools for this entry
Simon Glass2574ef62016-11-25 20:15:51 -070081 """
Simon Glass2c360cf2019-07-20 12:23:45 -060082 def __init__(self, section, etype, node, name_prefix=''):
Simon Glassb9ba4e02019-08-24 07:22:44 -060083 # Put this here to allow entry-docs and help to work without libfdt
84 global state
Simon Glassc585dd42020-04-17 18:09:03 -060085 from binman import state
Simon Glassb9ba4e02019-08-24 07:22:44 -060086
Simon Glassad5a7712018-06-01 09:38:14 -060087 self.section = section
Simon Glass2574ef62016-11-25 20:15:51 -070088 self.etype = etype
89 self._node = node
Simon Glass3b78d532018-06-01 09:38:21 -060090 self.name = node and (name_prefix + node.name) or 'none'
Simon Glasse8561af2018-08-01 15:22:37 -060091 self.offset = None
Simon Glass2574ef62016-11-25 20:15:51 -070092 self.size = None
Simon Glass1fdb4872019-10-31 07:43:02 -060093 self.pre_reset_size = None
Simon Glassaa2fcf92019-07-08 14:25:30 -060094 self.uncomp_size = None
Simon Glass5c350162018-07-17 13:25:47 -060095 self.data = None
Simon Glass789b34402020-10-26 17:40:15 -060096 self.uncomp_data = None
Simon Glass2574ef62016-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 Glasse8561af2018-08-01 15:22:37 -0600103 self.offset_unset = False
Simon Glass9dcc8612018-08-01 15:22:42 -0600104 self.image_pos = None
Simon Glass9ed71702021-11-23 11:03:43 -0700105 self.expand_size = False
Simon Glassaa2fcf92019-07-08 14:25:30 -0600106 self.compress = 'none'
Simon Glassa003cd32020-07-09 18:39:40 -0600107 self.missing = False
Heiko Thiery6d451362022-01-06 11:49:41 +0100108 self.faked = False
Simon Glassb8f90372020-09-01 05:13:57 -0600109 self.external = False
110 self.allow_missing = False
Heiko Thiery6d451362022-01-06 11:49:41 +0100111 self.allow_fake = False
Simon Glass4eae9252022-01-09 20:13:50 -0700112 self.bintools = {}
Simon Glass66152ce2022-01-09 20:14:09 -0700113 self.missing_bintools = []
Simon Glass2574ef62016-11-25 20:15:51 -0700114
115 @staticmethod
Simon Glassb9028bc2021-11-23 21:09:49 -0700116 def FindEntryClass(etype, expanded):
Simon Glass969616c2018-07-17 13:25:36 -0600117 """Look up the entry class for a node.
Simon Glass2574ef62016-11-25 20:15:51 -0700118
119 Args:
Simon Glass969616c2018-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 Glass2f859412021-03-18 20:25:04 +1300123 expanded: Use the expanded version of etype
Simon Glass2574ef62016-11-25 20:15:51 -0700124
125 Returns:
Simon Glass2f859412021-03-18 20:25:04 +1300126 The entry class object if found, else None if not found and expanded
Simon Glassb9028bc2021-11-23 21:09:49 -0700127 is True, else a tuple:
128 module name that could not be found
129 exception received
Simon Glass2574ef62016-11-25 20:15:51 -0700130 """
Simon Glasse76a3e62018-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 Glass2574ef62016-11-25 20:15:51 -0700133 module_name = etype.replace('-', '_')
Simon Glass2f859412021-03-18 20:25:04 +1300134
Simon Glasse76a3e62018-06-01 09:38:11 -0600135 if '@' in module_name:
136 module_name = module_name.split('@')[0]
Simon Glass2f859412021-03-18 20:25:04 +1300137 if expanded:
138 module_name += '_expanded'
Simon Glass2574ef62016-11-25 20:15:51 -0700139 module = modules.get(module_name)
140
Simon Glass691198c2018-06-01 09:38:15 -0600141 # Also allow entry-type modules to be brought in from the etype directory.
142
Simon Glass2574ef62016-11-25 20:15:51 -0700143 # Import the module if we have not already done so.
144 if not module:
145 try:
Simon Glassc585dd42020-04-17 18:09:03 -0600146 module = importlib.import_module('binman.etype.' + module_name)
Simon Glass969616c2018-07-17 13:25:36 -0600147 except ImportError as e:
Simon Glass2f859412021-03-18 20:25:04 +1300148 if expanded:
149 return None
Simon Glassb9028bc2021-11-23 21:09:49 -0700150 return module_name, e
Simon Glass2574ef62016-11-25 20:15:51 -0700151 modules[module_name] = module
152
Simon Glass969616c2018-07-17 13:25:36 -0600153 # Look up the expected class name
154 return getattr(module, 'Entry_%s' % module_name)
155
156 @staticmethod
Simon Glassb9028bc2021-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 Glass969616c2018-07-17 13:25:36 -0600192 """Create a new entry for a node.
193
194 Args:
Simon Glassb9028bc2021-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 Glass969616c2018-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 Glassb9028bc2021-11-23 21:09:49 -0700209 obj = Entry.Lookup(node.path, etype, expanded, missing_etype)
Simon Glass2f859412021-03-18 20:25:04 +1300210 if obj and expanded:
211 # Check whether to use the expanded entry
212 new_etype = etype + '-expanded'
Simon Glass7098b7f2021-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 Glass2f859412021-03-18 20:25:04 +1300215 etype = new_etype
216 else:
217 obj = None
218 if not obj:
Simon Glassb9028bc2021-11-23 21:09:49 -0700219 obj = Entry.Lookup(node.path, etype, False, missing_etype)
Simon Glass969616c2018-07-17 13:25:36 -0600220
Simon Glass2574ef62016-11-25 20:15:51 -0700221 # Call its constructor to get the object we want.
Simon Glassad5a7712018-06-01 09:38:14 -0600222 return obj(section, etype, node)
Simon Glass2574ef62016-11-25 20:15:51 -0700223
224 def ReadNode(self):
225 """Read entry information from the node
226
Simon Glass2c360cf2019-07-20 12:23:45 -0600227 This must be called as the first thing after the Entry is created.
228
Simon Glass2574ef62016-11-25 20:15:51 -0700229 This reads all the fields we recognise from the node, ready for use.
230 """
Simon Glass24b97442018-07-17 13:25:51 -0600231 if 'pos' in self._node.props:
232 self.Raise("Please use 'offset' instead of 'pos'")
Simon Glasse8561af2018-08-01 15:22:37 -0600233 self.offset = fdt_util.GetInt(self._node, 'offset')
Simon Glass2574ef62016-11-25 20:15:51 -0700234 self.size = fdt_util.GetInt(self._node, 'size')
Simon Glassfb30e292019-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 Glasse61b6f62019-07-08 14:25:37 -0600240
Simon Glassb8424fa2019-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 Glass2574ef62016-11-25 20:15:51 -0700246 self.align = fdt_util.GetInt(self._node, 'align')
Simon Glass80025522022-01-29 14:14:04 -0700247 if tools.not_power_of_two(self.align):
Simon Glass2574ef62016-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 Glassf427c5f2021-03-21 18:24:33 +1300250 if self.section and self.align is None:
251 self.align = self.section.align_default
Simon Glass2574ef62016-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 Glass80025522022-01-29 14:14:04 -0700255 if tools.not_power_of_two(self.align_size):
Simon Glass39dd2152019-07-08 14:25:47 -0600256 self.Raise("Alignment size %s must be a power of two" %
257 self.align_size)
Simon Glass2574ef62016-11-25 20:15:51 -0700258 self.align_end = fdt_util.GetInt(self._node, 'align-end')
Simon Glasse8561af2018-08-01 15:22:37 -0600259 self.offset_unset = fdt_util.GetBool(self._node, 'offset-unset')
Simon Glassfa79a812018-09-14 04:57:29 -0600260 self.expand_size = fdt_util.GetBool(self._node, 'expand-size')
Simon Glassa820af72020-09-06 10:39:09 -0600261 self.missing_msg = fdt_util.GetString(self._node, 'missing-msg')
Simon Glass2574ef62016-11-25 20:15:51 -0700262
Simon Glassa1301a22020-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 Glass3732ec32018-09-14 04:57:18 -0600266 def GetDefaultFilename(self):
267 return None
268
Simon Glass267112e2019-07-20 12:23:28 -0600269 def GetFdts(self):
270 """Get the device trees used by this entry
Simon Glass0c9d5b52018-09-14 04:57:22 -0600271
272 Returns:
Simon Glass267112e2019-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 Glass684a4f12019-07-20 12:23:31 -0600276 value: Tuple:
Simon Glass8235dd82021-03-18 20:25:02 +1300277 Entry object for this dtb
Simon Glass684a4f12019-07-20 12:23:31 -0600278 Filename of file containing this dtb
Simon Glass0c9d5b52018-09-14 04:57:22 -0600279 """
Simon Glass267112e2019-07-20 12:23:28 -0600280 return {}
Simon Glass0c9d5b52018-09-14 04:57:22 -0600281
Simon Glassac6328c2018-09-14 04:57:28 -0600282 def ExpandEntries(self):
Simon Glassfcb2a7c2021-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 Glassac6328c2018-09-14 04:57:28 -0600294 pass
295
Simon Glassacd6c6e2020-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 Glasse22f8fa2018-07-06 10:27:41 -0600306 if not prop in self._node.props:
Simon Glassc8135dc2018-09-14 04:57:21 -0600307 state.AddZeroProp(self._node, prop)
Simon Glassacd6c6e2020-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 Glassfb30e292019-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 Glassaa2fcf92019-07-08 14:25:30 -0600316 if self.compress != 'none':
317 state.AddZeroProp(self._node, 'uncomp-size')
Simon Glassae7cf032018-09-14 04:57:31 -0600318 err = state.CheckAddHashProp(self._node)
319 if err:
320 self.Raise(err)
Simon Glasse22f8fa2018-07-06 10:27:41 -0600321
322 def SetCalculatedProperties(self):
323 """Set the value of device-tree properties calculated by binman"""
Simon Glassc8135dc2018-09-14 04:57:21 -0600324 state.SetInt(self._node, 'offset', self.offset)
325 state.SetInt(self._node, 'size', self.size)
Simon Glass39dd2152019-07-08 14:25:47 -0600326 base = self.section.GetRootSkipAtStart() if self.section else 0
Simon Glassacd6c6e2020-10-26 17:40:17 -0600327 if self.image_pos is not None:
Simon Glasseb943b12020-11-02 12:55:44 -0700328 state.SetInt(self._node, 'image-pos', self.image_pos - base)
Simon Glassfb30e292019-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 Glassaa2fcf92019-07-08 14:25:30 -0600334 if self.uncomp_size is not None:
335 state.SetInt(self._node, 'uncomp-size', self.uncomp_size)
Simon Glassae7cf032018-09-14 04:57:31 -0600336 state.CheckSetHashValue(self._node, self.GetData)
Simon Glasse22f8fa2018-07-06 10:27:41 -0600337
Simon Glass92307732018-07-06 10:27:40 -0600338 def ProcessFdt(self, fdt):
Simon Glasse219aa42018-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 Glass92307732018-07-06 10:27:40 -0600350 return True
351
Simon Glass3b78d532018-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 Glass2e1169f2018-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 Glassd17dfea2019-07-08 14:25:33 -0600367 data: Data to set to the contents (bytes)
Simon Glass2e1169f2018-07-06 10:27:19 -0600368 """
369 self.data = data
370 self.contents_size = len(self.data)
371
372 def ProcessContentsUpdate(self, data):
Simon Glassd17dfea2019-07-08 14:25:33 -0600373 """Update the contents of an entry, after the size is fixed
Simon Glass2e1169f2018-07-06 10:27:19 -0600374
Simon Glassec849852019-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 Glass2e1169f2018-07-06 10:27:19 -0600377
378 Args:
Simon Glassd17dfea2019-07-08 14:25:33 -0600379 data: Data to set to the contents (bytes)
Simon Glass2e1169f2018-07-06 10:27:19 -0600380
381 Raises:
382 ValueError if the new data size is not the same as the old
383 """
Simon Glassec849852019-07-08 14:25:35 -0600384 size_ok = True
Simon Glasse61b6f62019-07-08 14:25:37 -0600385 new_size = len(data)
Simon Glass9d8ee322019-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 Glasse61b6f62019-07-08 14:25:37 -0600394 if new_size > self.contents_size:
Simon Glass9d8ee322019-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 Glass80025522022-01-29 14:14:04 -0700400 data += tools.get_bytes(0, self.contents_size - new_size)
Simon Glass9d8ee322019-07-20 12:23:58 -0600401
402 if not size_ok:
Simon Glass011f1b32022-01-29 14:14:15 -0700403 tout.debug("Entry '%s' size change from %s to %s" % (
Simon Glass80025522022-01-29 14:14:04 -0700404 self._node.path, to_hex(self.contents_size),
405 to_hex(new_size)))
Simon Glass2e1169f2018-07-06 10:27:19 -0600406 self.SetContents(data)
Simon Glassec849852019-07-08 14:25:35 -0600407 return size_ok
Simon Glass2e1169f2018-07-06 10:27:19 -0600408
Simon Glass2574ef62016-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 Glasse61b6f62019-07-08 14:25:37 -0600419 def ResetForPack(self):
420 """Reset offset/size fields so that packing can be done again"""
Simon Glassb6dff4c2019-07-20 12:23:36 -0600421 self.Detail('ResetForPack: offset %s->%s, size %s->%s' %
Simon Glass80025522022-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 Glass1fdb4872019-10-31 07:43:02 -0600424 self.pre_reset_size = self.size
Simon Glasse61b6f62019-07-08 14:25:37 -0600425 self.offset = self.orig_offset
426 self.size = self.orig_size
427
Simon Glasse8561af2018-08-01 15:22:37 -0600428 def Pack(self, offset):
Simon Glassad5a7712018-06-01 09:38:14 -0600429 """Figure out how to pack the entry into the section
Simon Glass2574ef62016-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 Glasse8561af2018-08-01 15:22:37 -0600435 If an entry has no hard-coded offset, it will be placed at @offset.
Simon Glass2574ef62016-11-25 20:15:51 -0700436
Simon Glasse8561af2018-08-01 15:22:37 -0600437 Once this function is complete, both the offset and size of the
Simon Glass2574ef62016-11-25 20:15:51 -0700438 entry will be know.
439
440 Args:
Simon Glasse8561af2018-08-01 15:22:37 -0600441 Current section offset pointer
Simon Glass2574ef62016-11-25 20:15:51 -0700442
443 Returns:
Simon Glasse8561af2018-08-01 15:22:37 -0600444 New section offset pointer (after this entry)
Simon Glass2574ef62016-11-25 20:15:51 -0700445 """
Simon Glassb6dff4c2019-07-20 12:23:36 -0600446 self.Detail('Packing: offset=%s, size=%s, content_size=%x' %
Simon Glass80025522022-01-29 14:14:04 -0700447 (to_hex(self.offset), to_hex(self.size),
Simon Glassb6dff4c2019-07-20 12:23:36 -0600448 self.contents_size))
Simon Glasse8561af2018-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 Glass80025522022-01-29 14:14:04 -0700453 self.offset = tools.align(offset, self.align)
Simon Glass2574ef62016-11-25 20:15:51 -0700454 needed = self.pad_before + self.contents_size + self.pad_after
Simon Glass80025522022-01-29 14:14:04 -0700455 needed = tools.align(needed, self.align_size)
Simon Glass2574ef62016-11-25 20:15:51 -0700456 size = self.size
457 if not size:
458 size = needed
Simon Glasse8561af2018-08-01 15:22:37 -0600459 new_offset = self.offset + size
Simon Glass80025522022-01-29 14:14:04 -0700460 aligned_offset = tools.align(new_offset, self.align_end)
Simon Glasse8561af2018-08-01 15:22:37 -0600461 if aligned_offset != new_offset:
462 size = aligned_offset - self.offset
463 new_offset = aligned_offset
Simon Glass2574ef62016-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 Glasse8561af2018-08-01 15:22:37 -0600472 # and offset or size values were provided (i.e. not calculated), but
Simon Glass2574ef62016-11-25 20:15:51 -0700473 # conflict with the provided alignment values
Simon Glass80025522022-01-29 14:14:04 -0700474 if self.size != tools.align(self.size, self.align_size):
Simon Glass2574ef62016-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 Glass80025522022-01-29 14:14:04 -0700477 if self.offset != tools.align(self.offset, self.align):
Simon Glasse8561af2018-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 Glassb6dff4c2019-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 Glass2574ef62016-11-25 20:15:51 -0700482
Simon Glasse8561af2018-08-01 15:22:37 -0600483 return new_offset
Simon Glass2574ef62016-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 Glasse1915782021-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 Glass011f1b32022-01-29 14:14:15 -0700492 tout.detail('%30s: %s' % (tag, msg))
Simon Glasse1915782021-03-21 18:24:31 +1300493
Simon Glassb6dff4c2019-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 Glass011f1b32022-01-29 14:14:15 -0700497 tout.detail('%30s: %s' % (tag, msg))
Simon Glassb6dff4c2019-07-20 12:23:36 -0600498
Simon Glass91710b32018-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 Glass3fb25402021-01-06 21:35:16 -0700522 self.GetImage().MissingArgs(self, missing)
Simon Glass91710b32018-07-17 13:25:32 -0600523 return values
524
Simon Glass2574ef62016-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 Glass27a7f772021-03-21 18:24:32 +1300533 def GetData(self, required=True):
Simon Glass72eeff12020-10-26 17:40:16 -0600534 """Get the contents of an entry
535
Simon Glass27a7f772021-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 Glass72eeff12020-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 Glass80025522022-01-29 14:14:04 -0700544 self.Detail('GetData: size %s' % to_hex_size(self.data))
Simon Glass2574ef62016-11-25 20:15:51 -0700545 return self.data
546
Simon Glasse17220f2020-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 Glasse8561af2018-08-01 15:22:37 -0600563 def GetOffsets(self):
Simon Glass224bc662019-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 Glassed365eb2019-07-08 13:18:39 -0600577 type. Either can be None if not known
Simon Glass224bc662019-07-08 13:18:30 -0600578 """
Simon Glass2574ef62016-11-25 20:15:51 -0700579 return {}
580
Simon Glassed365eb2019-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 Glass2574ef62016-11-25 20:15:51 -0700592
Simon Glass9dcc8612018-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 Glass2574ef62016-11-25 20:15:51 -0700601 def ProcessContents(self):
Simon Glassec849852019-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 Glass4ca8e042017-11-13 18:55:01 -0700618
Simon Glass8a6f56e2018-06-01 09:38:13 -0600619 def WriteSymbols(self, section):
Simon Glass4ca8e042017-11-13 18:55:01 -0700620 """Write symbol values into binary files for access at run time
621
622 Args:
Simon Glass8a6f56e2018-06-01 09:38:13 -0600623 section: Section containing the entry
Simon Glass4ca8e042017-11-13 18:55:01 -0700624 """
625 pass
Simon Glassa91e1152018-06-01 09:38:16 -0600626
Simon Glass55f68072020-10-26 17:40:18 -0600627 def CheckEntries(self):
Simon Glasse8561af2018-08-01 15:22:37 -0600628 """Check that the entry offsets are correct
Simon Glassa91e1152018-06-01 09:38:16 -0600629
Simon Glasse8561af2018-08-01 15:22:37 -0600630 This is used for entries which have extra offset requirements (other
Simon Glassa91e1152018-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 Glass30732662018-06-01 09:38:20 -0600635
Simon Glass3a9a2b82018-07-17 13:25:28 -0600636 @staticmethod
Simon Glasscd817d52018-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 Glass7eca7922018-07-17 13:25:49 -0600643 def WriteMapLine(fd, indent, name, offset, size, image_pos):
Simon Glasscd817d52018-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 Glass3a9a2b82018-07-17 13:25:28 -0600647
Simon Glass30732662018-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 Glass7eca7922018-07-17 13:25:49 -0600655 self.WriteMapLine(fd, indent, self.name, self.offset, self.size,
656 self.image_pos)
Simon Glass91710b32018-07-17 13:25:32 -0600657
Simon Glass704784b2018-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 Glass91710b32018-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 Glass29aa7362018-09-14 04:57:19 -0600683 value = state.GetEntryArg(name)
Simon Glass91710b32018-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 Glass969616c2018-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 Glass2f859412021-03-18 20:25:04 +1300729 module = Entry.Lookup('WriteDocs', name, False)
Simon Glass969616c2018-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 Glass639505b2018-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 Glassfa79a812018-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 Glassc4056b82019-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 Glasscec34ba2019-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 Glass6b156f82019-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 Glass4c613bf2019-07-08 14:25:50 -0600828
Simon Glass637958f2021-11-23 21:09:50 -0700829 def ReadData(self, decomp=True, alt_format=None):
Simon Glass4c613bf2019-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 Glass011f1b32022-01-29 14:14:15 -0700844 tout.debug("ReadChildData section '%s', entry '%s'" %
Simon Glass4d8151f2019-09-25 08:56:21 -0600845 (self.section.GetPath(), self.GetPath()))
Simon Glass637958f2021-11-23 21:09:50 -0700846 data = self.section.ReadChildData(self, decomp, alt_format)
Simon Glass0cd8ace2019-07-20 12:24:04 -0600847 return data
Simon Glassaf8c45c2019-07-20 12:23:41 -0600848
Simon Glass637958f2021-11-23 21:09:50 -0700849 def ReadChildData(self, child, decomp=True, alt_format=None):
Simon Glass4d8151f2019-09-25 08:56:21 -0600850 """Read the data for a particular child entry
Simon Glass23f00472019-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 Glass637958f2021-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 Glass23f00472019-09-25 08:56:20 -0600860
861 Returns:
862 Data for the child (bytes)
863 """
864 pass
865
Simon Glassaf8c45c2019-07-20 12:23:41 -0600866 def LoadData(self, decomp=True):
867 data = self.ReadData(decomp)
Simon Glass072959a2019-07-20 12:23:50 -0600868 self.contents_size = len(data)
Simon Glassaf8c45c2019-07-20 12:23:41 -0600869 self.ProcessContentsUpdate(data)
870 self.Detail('Loaded data size %x' % len(data))
Simon Glass990b1742019-07-20 12:23:46 -0600871
Simon Glass637958f2021-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 Glass990b1742019-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 Glass072959a2019-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 Glass1fdb4872019-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 Glass072959a2019-07-20 12:23:50 -0600915 ok = self.ProcessContentsUpdate(data)
916 self.Detail('WriteData: size=%x, ok=%s' % (len(data), ok))
Simon Glassd34af7a2019-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 Glasse796f242021-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 Glassd34af7a2019-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 Glasse796f242021-11-23 11:03:44 -0700935 data is such that the section could not update
Simon Glassd34af7a2019-07-20 12:24:05 -0600936 """
937 return True
Simon Glass11453762019-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 Glass5d94cc62020-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 Glassa003cd32020-07-09 18:39:40 -0600962
Heiko Thiery6d451362022-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 Glassceb5f912022-01-09 20:13:46 -0700969 self.allow_fake = allow_fake
Heiko Thiery6d451362022-01-06 11:49:41 +0100970
Simon Glassa003cd32020-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 Glassb8f90372020-09-01 05:13:57 -0600981
Simon Glass7a602fd2022-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 Glass80025522022-01-29 14:14:04 -0700994 outfname = tools.get_output_filename(os.path.basename(fname))
Simon Glass7a602fd2022-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 Thiery6d451362022-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 Glassb8f90372020-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 Glassa820af72020-09-06 10:39:09 -06001019
Simon Glass66152ce2022-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 Glassa820af72020-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 Glassa1301a22020-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 Glass789b34402020-10-26 17:40:15 -06001055 self.uncomp_data = indata
Simon Glassa1301a22020-10-26 17:40:06 -06001056 if self.compress != 'none':
1057 self.uncomp_size = len(indata)
Simon Glassdd5c14ec2022-01-09 20:14:04 -07001058 data = comp_util.compress(indata, self.compress)
Simon Glassa1301a22020-10-26 17:40:06 -06001059 return data
Simon Glass2f859412021-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 Glass011f1b32022-01-29 14:14:15 -07001079 tout.info("Node '%s': etype '%s': %s selected" %
Simon Glass2f859412021-03-18 20:25:04 +13001080 (node.path, etype, new_etype))
1081 return True
Simon Glass637958f2021-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 Glass4eae9252022-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