blob: 9cd900670e15e2670501c46c1982c93f9d380198 [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 Glassc585dd42020-04-17 18:09:03 -060014from dtoc import fdt_util
Simon Glassa997ea52020-04-17 18:09:04 -060015from patman import tools
Simon Glassc585dd42020-04-17 18:09:03 -060016from patman.tools import ToHex, ToHexSize
Simon Glassa997ea52020-04-17 18:09:04 -060017from patman import tout
Simon Glass2574ef62016-11-25 20:15:51 -070018
19modules = {}
20
Simon Glass91710b32018-07-17 13:25:32 -060021
22# An argument which can be passed to entries on the command line, in lieu of
23# device-tree properties.
24EntryArg = namedtuple('EntryArg', ['name', 'datatype'])
25
Simon Glass6b156f82019-07-08 14:25:43 -060026# Information about an entry for use when displaying summaries
27EntryInfo = namedtuple('EntryInfo', ['indent', 'name', 'etype', 'size',
28 'image_pos', 'uncomp_size', 'offset',
29 'entry'])
Simon Glass91710b32018-07-17 13:25:32 -060030
Simon Glass2574ef62016-11-25 20:15:51 -070031class Entry(object):
Simon Glassad5a7712018-06-01 09:38:14 -060032 """An Entry in the section
Simon Glass2574ef62016-11-25 20:15:51 -070033
34 An entry corresponds to a single node in the device-tree description
Simon Glassad5a7712018-06-01 09:38:14 -060035 of the section. Each entry ends up being a part of the final section.
Simon Glass2574ef62016-11-25 20:15:51 -070036 Entries can be placed either right next to each other, or with padding
37 between them. The type of the entry determines the data that is in it.
38
39 This class is not used by itself. All entry objects are subclasses of
40 Entry.
41
42 Attributes:
Simon Glass3a9a2b82018-07-17 13:25:28 -060043 section: Section object containing this entry
Simon Glass2574ef62016-11-25 20:15:51 -070044 node: The node that created this entry
Simon Glasse8561af2018-08-01 15:22:37 -060045 offset: Offset of entry within the section, None if not known yet (in
46 which case it will be calculated by Pack())
Simon Glass2574ef62016-11-25 20:15:51 -070047 size: Entry size in bytes, None if not known
Simon Glass1fdb4872019-10-31 07:43:02 -060048 pre_reset_size: size as it was before ResetForPack(). This allows us to
49 keep track of the size we started with and detect size changes
Simon Glassaa2fcf92019-07-08 14:25:30 -060050 uncomp_size: Size of uncompressed data in bytes, if the entry is
51 compressed, else None
Simon Glass2574ef62016-11-25 20:15:51 -070052 contents_size: Size of contents in bytes, 0 by default
Simon Glassafb9caa2020-10-26 17:40:10 -060053 align: Entry start offset alignment relative to the start of the
54 containing section, or None
Simon Glass2574ef62016-11-25 20:15:51 -070055 align_size: Entry size alignment, or None
Simon Glassafb9caa2020-10-26 17:40:10 -060056 align_end: Entry end offset alignment relative to the start of the
57 containing section, or None
Simon Glassd12599d2020-10-26 17:40:09 -060058 pad_before: Number of pad bytes before the contents when it is placed
59 in the containing section, 0 if none. The pad bytes become part of
60 the entry.
61 pad_after: Number of pad bytes after the contents when it is placed in
62 the containing section, 0 if none. The pad bytes become part of
63 the entry.
64 data: Contents of entry (string of bytes). This does not include
Simon Glass789b34402020-10-26 17:40:15 -060065 padding created by pad_before or pad_after. If the entry is
66 compressed, this contains the compressed data.
67 uncomp_data: Original uncompressed data, if this entry is compressed,
68 else None
Simon Glassaa2fcf92019-07-08 14:25:30 -060069 compress: Compression algoithm used (e.g. 'lz4'), 'none' if none
Simon Glasse61b6f62019-07-08 14:25:37 -060070 orig_offset: Original offset value read from node
71 orig_size: Original size value read from node
Simon Glassb8f90372020-09-01 05:13:57 -060072 missing: True if this entry is missing its contents
73 allow_missing: Allow children of this entry to be missing (used by
74 subclasses such as Entry_section)
Heiko Thiery6d451362022-01-06 11:49:41 +010075 allow_fake: Allow creating a dummy fake file if the blob file is not
76 available. This is mainly used for testing.
Simon Glassb8f90372020-09-01 05:13:57 -060077 external: True if this entry contains an external binary blob
Simon Glass4eae9252022-01-09 20:13:50 -070078 bintools: Bintools used by this entry (only populated for Image)
Simon Glass2574ef62016-11-25 20:15:51 -070079 """
Simon Glass2c360cf2019-07-20 12:23:45 -060080 def __init__(self, section, etype, node, name_prefix=''):
Simon Glassb9ba4e02019-08-24 07:22:44 -060081 # Put this here to allow entry-docs and help to work without libfdt
82 global state
Simon Glassc585dd42020-04-17 18:09:03 -060083 from binman import state
Simon Glassb9ba4e02019-08-24 07:22:44 -060084
Simon Glassad5a7712018-06-01 09:38:14 -060085 self.section = section
Simon Glass2574ef62016-11-25 20:15:51 -070086 self.etype = etype
87 self._node = node
Simon Glass3b78d532018-06-01 09:38:21 -060088 self.name = node and (name_prefix + node.name) or 'none'
Simon Glasse8561af2018-08-01 15:22:37 -060089 self.offset = None
Simon Glass2574ef62016-11-25 20:15:51 -070090 self.size = None
Simon Glass1fdb4872019-10-31 07:43:02 -060091 self.pre_reset_size = None
Simon Glassaa2fcf92019-07-08 14:25:30 -060092 self.uncomp_size = None
Simon Glass5c350162018-07-17 13:25:47 -060093 self.data = None
Simon Glass789b34402020-10-26 17:40:15 -060094 self.uncomp_data = None
Simon Glass2574ef62016-11-25 20:15:51 -070095 self.contents_size = 0
96 self.align = None
97 self.align_size = None
98 self.align_end = None
99 self.pad_before = 0
100 self.pad_after = 0
Simon Glasse8561af2018-08-01 15:22:37 -0600101 self.offset_unset = False
Simon Glass9dcc8612018-08-01 15:22:42 -0600102 self.image_pos = None
Simon Glass9ed71702021-11-23 11:03:43 -0700103 self.expand_size = False
Simon Glassaa2fcf92019-07-08 14:25:30 -0600104 self.compress = 'none'
Simon Glassa003cd32020-07-09 18:39:40 -0600105 self.missing = False
Heiko Thiery6d451362022-01-06 11:49:41 +0100106 self.faked = False
Simon Glassb8f90372020-09-01 05:13:57 -0600107 self.external = False
108 self.allow_missing = False
Heiko Thiery6d451362022-01-06 11:49:41 +0100109 self.allow_fake = False
Simon Glass4eae9252022-01-09 20:13:50 -0700110 self.bintools = {}
Simon Glass2574ef62016-11-25 20:15:51 -0700111
112 @staticmethod
Simon Glassb9028bc2021-11-23 21:09:49 -0700113 def FindEntryClass(etype, expanded):
Simon Glass969616c2018-07-17 13:25:36 -0600114 """Look up the entry class for a node.
Simon Glass2574ef62016-11-25 20:15:51 -0700115
116 Args:
Simon Glass969616c2018-07-17 13:25:36 -0600117 node_node: Path name of Node object containing information about
118 the entry to create (used for errors)
119 etype: Entry type to use
Simon Glass2f859412021-03-18 20:25:04 +1300120 expanded: Use the expanded version of etype
Simon Glass2574ef62016-11-25 20:15:51 -0700121
122 Returns:
Simon Glass2f859412021-03-18 20:25:04 +1300123 The entry class object if found, else None if not found and expanded
Simon Glassb9028bc2021-11-23 21:09:49 -0700124 is True, else a tuple:
125 module name that could not be found
126 exception received
Simon Glass2574ef62016-11-25 20:15:51 -0700127 """
Simon Glasse76a3e62018-06-01 09:38:11 -0600128 # Convert something like 'u-boot@0' to 'u_boot' since we are only
129 # interested in the type.
Simon Glass2574ef62016-11-25 20:15:51 -0700130 module_name = etype.replace('-', '_')
Simon Glass2f859412021-03-18 20:25:04 +1300131
Simon Glasse76a3e62018-06-01 09:38:11 -0600132 if '@' in module_name:
133 module_name = module_name.split('@')[0]
Simon Glass2f859412021-03-18 20:25:04 +1300134 if expanded:
135 module_name += '_expanded'
Simon Glass2574ef62016-11-25 20:15:51 -0700136 module = modules.get(module_name)
137
Simon Glass691198c2018-06-01 09:38:15 -0600138 # Also allow entry-type modules to be brought in from the etype directory.
139
Simon Glass2574ef62016-11-25 20:15:51 -0700140 # Import the module if we have not already done so.
141 if not module:
142 try:
Simon Glassc585dd42020-04-17 18:09:03 -0600143 module = importlib.import_module('binman.etype.' + module_name)
Simon Glass969616c2018-07-17 13:25:36 -0600144 except ImportError as e:
Simon Glass2f859412021-03-18 20:25:04 +1300145 if expanded:
146 return None
Simon Glassb9028bc2021-11-23 21:09:49 -0700147 return module_name, e
Simon Glass2574ef62016-11-25 20:15:51 -0700148 modules[module_name] = module
149
Simon Glass969616c2018-07-17 13:25:36 -0600150 # Look up the expected class name
151 return getattr(module, 'Entry_%s' % module_name)
152
153 @staticmethod
Simon Glassb9028bc2021-11-23 21:09:49 -0700154 def Lookup(node_path, etype, expanded, missing_etype=False):
155 """Look up the entry class for a node.
156
157 Args:
158 node_node (str): Path name of Node object containing information
159 about the entry to create (used for errors)
160 etype (str): Entry type to use
161 expanded (bool): Use the expanded version of etype
162 missing_etype (bool): True to default to a blob etype if the
163 requested etype is not found
164
165 Returns:
166 The entry class object if found, else None if not found and expanded
167 is True
168
169 Raise:
170 ValueError if expanded is False and the class is not found
171 """
172 # Convert something like 'u-boot@0' to 'u_boot' since we are only
173 # interested in the type.
174 cls = Entry.FindEntryClass(etype, expanded)
175 if cls is None:
176 return None
177 elif isinstance(cls, tuple):
178 if missing_etype:
179 cls = Entry.FindEntryClass('blob', False)
180 if isinstance(cls, tuple): # This should not fail
181 module_name, e = cls
182 raise ValueError(
183 "Unknown entry type '%s' in node '%s' (expected etype/%s.py, error '%s'" %
184 (etype, node_path, module_name, e))
185 return cls
186
187 @staticmethod
188 def Create(section, node, etype=None, expanded=False, missing_etype=False):
Simon Glass969616c2018-07-17 13:25:36 -0600189 """Create a new entry for a node.
190
191 Args:
Simon Glassb9028bc2021-11-23 21:09:49 -0700192 section (entry_Section): Section object containing this node
193 node (Node): Node object containing information about the entry to
194 create
195 etype (str): Entry type to use, or None to work it out (used for
196 tests)
197 expanded (bool): Use the expanded version of etype
198 missing_etype (bool): True to default to a blob etype if the
199 requested etype is not found
Simon Glass969616c2018-07-17 13:25:36 -0600200
201 Returns:
202 A new Entry object of the correct type (a subclass of Entry)
203 """
204 if not etype:
205 etype = fdt_util.GetString(node, 'type', node.name)
Simon Glassb9028bc2021-11-23 21:09:49 -0700206 obj = Entry.Lookup(node.path, etype, expanded, missing_etype)
Simon Glass2f859412021-03-18 20:25:04 +1300207 if obj and expanded:
208 # Check whether to use the expanded entry
209 new_etype = etype + '-expanded'
Simon Glass7098b7f2021-03-21 18:24:30 +1300210 can_expand = not fdt_util.GetBool(node, 'no-expanded')
211 if can_expand and obj.UseExpanded(node, etype, new_etype):
Simon Glass2f859412021-03-18 20:25:04 +1300212 etype = new_etype
213 else:
214 obj = None
215 if not obj:
Simon Glassb9028bc2021-11-23 21:09:49 -0700216 obj = Entry.Lookup(node.path, etype, False, missing_etype)
Simon Glass969616c2018-07-17 13:25:36 -0600217
Simon Glass2574ef62016-11-25 20:15:51 -0700218 # Call its constructor to get the object we want.
Simon Glassad5a7712018-06-01 09:38:14 -0600219 return obj(section, etype, node)
Simon Glass2574ef62016-11-25 20:15:51 -0700220
221 def ReadNode(self):
222 """Read entry information from the node
223
Simon Glass2c360cf2019-07-20 12:23:45 -0600224 This must be called as the first thing after the Entry is created.
225
Simon Glass2574ef62016-11-25 20:15:51 -0700226 This reads all the fields we recognise from the node, ready for use.
227 """
Simon Glass24b97442018-07-17 13:25:51 -0600228 if 'pos' in self._node.props:
229 self.Raise("Please use 'offset' instead of 'pos'")
Simon Glasse8561af2018-08-01 15:22:37 -0600230 self.offset = fdt_util.GetInt(self._node, 'offset')
Simon Glass2574ef62016-11-25 20:15:51 -0700231 self.size = fdt_util.GetInt(self._node, 'size')
Simon Glassfb30e292019-07-20 12:23:51 -0600232 self.orig_offset = fdt_util.GetInt(self._node, 'orig-offset')
233 self.orig_size = fdt_util.GetInt(self._node, 'orig-size')
234 if self.GetImage().copy_to_orig:
235 self.orig_offset = self.offset
236 self.orig_size = self.size
Simon Glasse61b6f62019-07-08 14:25:37 -0600237
Simon Glassb8424fa2019-07-08 14:25:46 -0600238 # These should not be set in input files, but are set in an FDT map,
239 # which is also read by this code.
240 self.image_pos = fdt_util.GetInt(self._node, 'image-pos')
241 self.uncomp_size = fdt_util.GetInt(self._node, 'uncomp-size')
242
Simon Glass2574ef62016-11-25 20:15:51 -0700243 self.align = fdt_util.GetInt(self._node, 'align')
244 if tools.NotPowerOfTwo(self.align):
245 raise ValueError("Node '%s': Alignment %s must be a power of two" %
246 (self._node.path, self.align))
Simon Glassf427c5f2021-03-21 18:24:33 +1300247 if self.section and self.align is None:
248 self.align = self.section.align_default
Simon Glass2574ef62016-11-25 20:15:51 -0700249 self.pad_before = fdt_util.GetInt(self._node, 'pad-before', 0)
250 self.pad_after = fdt_util.GetInt(self._node, 'pad-after', 0)
251 self.align_size = fdt_util.GetInt(self._node, 'align-size')
252 if tools.NotPowerOfTwo(self.align_size):
Simon Glass39dd2152019-07-08 14:25:47 -0600253 self.Raise("Alignment size %s must be a power of two" %
254 self.align_size)
Simon Glass2574ef62016-11-25 20:15:51 -0700255 self.align_end = fdt_util.GetInt(self._node, 'align-end')
Simon Glasse8561af2018-08-01 15:22:37 -0600256 self.offset_unset = fdt_util.GetBool(self._node, 'offset-unset')
Simon Glassfa79a812018-09-14 04:57:29 -0600257 self.expand_size = fdt_util.GetBool(self._node, 'expand-size')
Simon Glassa820af72020-09-06 10:39:09 -0600258 self.missing_msg = fdt_util.GetString(self._node, 'missing-msg')
Simon Glass2574ef62016-11-25 20:15:51 -0700259
Simon Glassa1301a22020-10-26 17:40:06 -0600260 # This is only supported by blobs and sections at present
261 self.compress = fdt_util.GetString(self._node, 'compress', 'none')
262
Simon Glass3732ec32018-09-14 04:57:18 -0600263 def GetDefaultFilename(self):
264 return None
265
Simon Glass267112e2019-07-20 12:23:28 -0600266 def GetFdts(self):
267 """Get the device trees used by this entry
Simon Glass0c9d5b52018-09-14 04:57:22 -0600268
269 Returns:
Simon Glass267112e2019-07-20 12:23:28 -0600270 Empty dict, if this entry is not a .dtb, otherwise:
271 Dict:
272 key: Filename from this entry (without the path)
Simon Glass684a4f12019-07-20 12:23:31 -0600273 value: Tuple:
Simon Glass8235dd82021-03-18 20:25:02 +1300274 Entry object for this dtb
Simon Glass684a4f12019-07-20 12:23:31 -0600275 Filename of file containing this dtb
Simon Glass0c9d5b52018-09-14 04:57:22 -0600276 """
Simon Glass267112e2019-07-20 12:23:28 -0600277 return {}
Simon Glass0c9d5b52018-09-14 04:57:22 -0600278
Simon Glassac6328c2018-09-14 04:57:28 -0600279 def ExpandEntries(self):
Simon Glassfcb2a7c2021-03-18 20:24:52 +1300280 """Expand out entries which produce other entries
281
282 Some entries generate subnodes automatically, from which sub-entries
283 are then created. This method allows those to be added to the binman
284 definition for the current image. An entry which implements this method
285 should call state.AddSubnode() to add a subnode and can add properties
286 with state.AddString(), etc.
287
288 An example is 'files', which produces a section containing a list of
289 files.
290 """
Simon Glassac6328c2018-09-14 04:57:28 -0600291 pass
292
Simon Glassacd6c6e2020-10-26 17:40:17 -0600293 def AddMissingProperties(self, have_image_pos):
294 """Add new properties to the device tree as needed for this entry
295
296 Args:
297 have_image_pos: True if this entry has an image position. This can
298 be False if its parent section is compressed, since compression
299 groups all entries together into a compressed block of data,
300 obscuring the start of each individual child entry
301 """
302 for prop in ['offset', 'size']:
Simon Glasse22f8fa2018-07-06 10:27:41 -0600303 if not prop in self._node.props:
Simon Glassc8135dc2018-09-14 04:57:21 -0600304 state.AddZeroProp(self._node, prop)
Simon Glassacd6c6e2020-10-26 17:40:17 -0600305 if have_image_pos and 'image-pos' not in self._node.props:
306 state.AddZeroProp(self._node, 'image-pos')
Simon Glassfb30e292019-07-20 12:23:51 -0600307 if self.GetImage().allow_repack:
308 if self.orig_offset is not None:
309 state.AddZeroProp(self._node, 'orig-offset', True)
310 if self.orig_size is not None:
311 state.AddZeroProp(self._node, 'orig-size', True)
312
Simon Glassaa2fcf92019-07-08 14:25:30 -0600313 if self.compress != 'none':
314 state.AddZeroProp(self._node, 'uncomp-size')
Simon Glassae7cf032018-09-14 04:57:31 -0600315 err = state.CheckAddHashProp(self._node)
316 if err:
317 self.Raise(err)
Simon Glasse22f8fa2018-07-06 10:27:41 -0600318
319 def SetCalculatedProperties(self):
320 """Set the value of device-tree properties calculated by binman"""
Simon Glassc8135dc2018-09-14 04:57:21 -0600321 state.SetInt(self._node, 'offset', self.offset)
322 state.SetInt(self._node, 'size', self.size)
Simon Glass39dd2152019-07-08 14:25:47 -0600323 base = self.section.GetRootSkipAtStart() if self.section else 0
Simon Glassacd6c6e2020-10-26 17:40:17 -0600324 if self.image_pos is not None:
Simon Glasseb943b12020-11-02 12:55:44 -0700325 state.SetInt(self._node, 'image-pos', self.image_pos - base)
Simon Glassfb30e292019-07-20 12:23:51 -0600326 if self.GetImage().allow_repack:
327 if self.orig_offset is not None:
328 state.SetInt(self._node, 'orig-offset', self.orig_offset, True)
329 if self.orig_size is not None:
330 state.SetInt(self._node, 'orig-size', self.orig_size, True)
Simon Glassaa2fcf92019-07-08 14:25:30 -0600331 if self.uncomp_size is not None:
332 state.SetInt(self._node, 'uncomp-size', self.uncomp_size)
Simon Glassae7cf032018-09-14 04:57:31 -0600333 state.CheckSetHashValue(self._node, self.GetData)
Simon Glasse22f8fa2018-07-06 10:27:41 -0600334
Simon Glass92307732018-07-06 10:27:40 -0600335 def ProcessFdt(self, fdt):
Simon Glasse219aa42018-09-14 04:57:24 -0600336 """Allow entries to adjust the device tree
337
338 Some entries need to adjust the device tree for their purposes. This
339 may involve adding or deleting properties.
340
341 Returns:
342 True if processing is complete
343 False if processing could not be completed due to a dependency.
344 This will cause the entry to be retried after others have been
345 called
346 """
Simon Glass92307732018-07-06 10:27:40 -0600347 return True
348
Simon Glass3b78d532018-06-01 09:38:21 -0600349 def SetPrefix(self, prefix):
350 """Set the name prefix for a node
351
352 Args:
353 prefix: Prefix to set, or '' to not use a prefix
354 """
355 if prefix:
356 self.name = prefix + self.name
357
Simon Glass2e1169f2018-07-06 10:27:19 -0600358 def SetContents(self, data):
359 """Set the contents of an entry
360
361 This sets both the data and content_size properties
362
363 Args:
Simon Glassd17dfea2019-07-08 14:25:33 -0600364 data: Data to set to the contents (bytes)
Simon Glass2e1169f2018-07-06 10:27:19 -0600365 """
366 self.data = data
367 self.contents_size = len(self.data)
368
369 def ProcessContentsUpdate(self, data):
Simon Glassd17dfea2019-07-08 14:25:33 -0600370 """Update the contents of an entry, after the size is fixed
Simon Glass2e1169f2018-07-06 10:27:19 -0600371
Simon Glassec849852019-07-08 14:25:35 -0600372 This checks that the new data is the same size as the old. If the size
373 has changed, this triggers a re-run of the packing algorithm.
Simon Glass2e1169f2018-07-06 10:27:19 -0600374
375 Args:
Simon Glassd17dfea2019-07-08 14:25:33 -0600376 data: Data to set to the contents (bytes)
Simon Glass2e1169f2018-07-06 10:27:19 -0600377
378 Raises:
379 ValueError if the new data size is not the same as the old
380 """
Simon Glassec849852019-07-08 14:25:35 -0600381 size_ok = True
Simon Glasse61b6f62019-07-08 14:25:37 -0600382 new_size = len(data)
Simon Glass9d8ee322019-07-20 12:23:58 -0600383 if state.AllowEntryExpansion() and new_size > self.contents_size:
384 # self.data will indicate the new size needed
385 size_ok = False
386 elif state.AllowEntryContraction() and new_size < self.contents_size:
387 size_ok = False
388
389 # If not allowed to change, try to deal with it or give up
390 if size_ok:
Simon Glasse61b6f62019-07-08 14:25:37 -0600391 if new_size > self.contents_size:
Simon Glass9d8ee322019-07-20 12:23:58 -0600392 self.Raise('Cannot update entry size from %d to %d' %
393 (self.contents_size, new_size))
394
395 # Don't let the data shrink. Pad it if necessary
396 if size_ok and new_size < self.contents_size:
397 data += tools.GetBytes(0, self.contents_size - new_size)
398
399 if not size_ok:
400 tout.Debug("Entry '%s' size change from %s to %s" % (
401 self._node.path, ToHex(self.contents_size),
402 ToHex(new_size)))
Simon Glass2e1169f2018-07-06 10:27:19 -0600403 self.SetContents(data)
Simon Glassec849852019-07-08 14:25:35 -0600404 return size_ok
Simon Glass2e1169f2018-07-06 10:27:19 -0600405
Simon Glass2574ef62016-11-25 20:15:51 -0700406 def ObtainContents(self):
407 """Figure out the contents of an entry.
408
409 Returns:
410 True if the contents were found, False if another call is needed
411 after the other entries are processed.
412 """
413 # No contents by default: subclasses can implement this
414 return True
415
Simon Glasse61b6f62019-07-08 14:25:37 -0600416 def ResetForPack(self):
417 """Reset offset/size fields so that packing can be done again"""
Simon Glassb6dff4c2019-07-20 12:23:36 -0600418 self.Detail('ResetForPack: offset %s->%s, size %s->%s' %
419 (ToHex(self.offset), ToHex(self.orig_offset),
420 ToHex(self.size), ToHex(self.orig_size)))
Simon Glass1fdb4872019-10-31 07:43:02 -0600421 self.pre_reset_size = self.size
Simon Glasse61b6f62019-07-08 14:25:37 -0600422 self.offset = self.orig_offset
423 self.size = self.orig_size
424
Simon Glasse8561af2018-08-01 15:22:37 -0600425 def Pack(self, offset):
Simon Glassad5a7712018-06-01 09:38:14 -0600426 """Figure out how to pack the entry into the section
Simon Glass2574ef62016-11-25 20:15:51 -0700427
428 Most of the time the entries are not fully specified. There may be
429 an alignment but no size. In that case we take the size from the
430 contents of the entry.
431
Simon Glasse8561af2018-08-01 15:22:37 -0600432 If an entry has no hard-coded offset, it will be placed at @offset.
Simon Glass2574ef62016-11-25 20:15:51 -0700433
Simon Glasse8561af2018-08-01 15:22:37 -0600434 Once this function is complete, both the offset and size of the
Simon Glass2574ef62016-11-25 20:15:51 -0700435 entry will be know.
436
437 Args:
Simon Glasse8561af2018-08-01 15:22:37 -0600438 Current section offset pointer
Simon Glass2574ef62016-11-25 20:15:51 -0700439
440 Returns:
Simon Glasse8561af2018-08-01 15:22:37 -0600441 New section offset pointer (after this entry)
Simon Glass2574ef62016-11-25 20:15:51 -0700442 """
Simon Glassb6dff4c2019-07-20 12:23:36 -0600443 self.Detail('Packing: offset=%s, size=%s, content_size=%x' %
444 (ToHex(self.offset), ToHex(self.size),
445 self.contents_size))
Simon Glasse8561af2018-08-01 15:22:37 -0600446 if self.offset is None:
447 if self.offset_unset:
448 self.Raise('No offset set with offset-unset: should another '
449 'entry provide this correct offset?')
450 self.offset = tools.Align(offset, self.align)
Simon Glass2574ef62016-11-25 20:15:51 -0700451 needed = self.pad_before + self.contents_size + self.pad_after
452 needed = tools.Align(needed, self.align_size)
453 size = self.size
454 if not size:
455 size = needed
Simon Glasse8561af2018-08-01 15:22:37 -0600456 new_offset = self.offset + size
457 aligned_offset = tools.Align(new_offset, self.align_end)
458 if aligned_offset != new_offset:
459 size = aligned_offset - self.offset
460 new_offset = aligned_offset
Simon Glass2574ef62016-11-25 20:15:51 -0700461
462 if not self.size:
463 self.size = size
464
465 if self.size < needed:
466 self.Raise("Entry contents size is %#x (%d) but entry size is "
467 "%#x (%d)" % (needed, needed, self.size, self.size))
468 # Check that the alignment is correct. It could be wrong if the
Simon Glasse8561af2018-08-01 15:22:37 -0600469 # and offset or size values were provided (i.e. not calculated), but
Simon Glass2574ef62016-11-25 20:15:51 -0700470 # conflict with the provided alignment values
471 if self.size != tools.Align(self.size, self.align_size):
472 self.Raise("Size %#x (%d) does not match align-size %#x (%d)" %
473 (self.size, self.size, self.align_size, self.align_size))
Simon Glasse8561af2018-08-01 15:22:37 -0600474 if self.offset != tools.Align(self.offset, self.align):
475 self.Raise("Offset %#x (%d) does not match align %#x (%d)" %
476 (self.offset, self.offset, self.align, self.align))
Simon Glassb6dff4c2019-07-20 12:23:36 -0600477 self.Detail(' - packed: offset=%#x, size=%#x, content_size=%#x, next_offset=%x' %
478 (self.offset, self.size, self.contents_size, new_offset))
Simon Glass2574ef62016-11-25 20:15:51 -0700479
Simon Glasse8561af2018-08-01 15:22:37 -0600480 return new_offset
Simon Glass2574ef62016-11-25 20:15:51 -0700481
482 def Raise(self, msg):
483 """Convenience function to raise an error referencing a node"""
484 raise ValueError("Node '%s': %s" % (self._node.path, msg))
485
Simon Glasse1915782021-03-21 18:24:31 +1300486 def Info(self, msg):
487 """Convenience function to log info referencing a node"""
488 tag = "Info '%s'" % self._node.path
489 tout.Detail('%30s: %s' % (tag, msg))
490
Simon Glassb6dff4c2019-07-20 12:23:36 -0600491 def Detail(self, msg):
492 """Convenience function to log detail referencing a node"""
493 tag = "Node '%s'" % self._node.path
494 tout.Detail('%30s: %s' % (tag, msg))
495
Simon Glass91710b32018-07-17 13:25:32 -0600496 def GetEntryArgsOrProps(self, props, required=False):
497 """Return the values of a set of properties
498
499 Args:
500 props: List of EntryArg objects
501
502 Raises:
503 ValueError if a property is not found
504 """
505 values = []
506 missing = []
507 for prop in props:
508 python_prop = prop.name.replace('-', '_')
509 if hasattr(self, python_prop):
510 value = getattr(self, python_prop)
511 else:
512 value = None
513 if value is None:
514 value = self.GetArg(prop.name, prop.datatype)
515 if value is None and required:
516 missing.append(prop.name)
517 values.append(value)
518 if missing:
Simon Glass3fb25402021-01-06 21:35:16 -0700519 self.GetImage().MissingArgs(self, missing)
Simon Glass91710b32018-07-17 13:25:32 -0600520 return values
521
Simon Glass2574ef62016-11-25 20:15:51 -0700522 def GetPath(self):
523 """Get the path of a node
524
525 Returns:
526 Full path of the node for this entry
527 """
528 return self._node.path
529
Simon Glass27a7f772021-03-21 18:24:32 +1300530 def GetData(self, required=True):
Simon Glass72eeff12020-10-26 17:40:16 -0600531 """Get the contents of an entry
532
Simon Glass27a7f772021-03-21 18:24:32 +1300533 Args:
534 required: True if the data must be present, False if it is OK to
535 return None
536
Simon Glass72eeff12020-10-26 17:40:16 -0600537 Returns:
538 bytes content of the entry, excluding any padding. If the entry is
539 compressed, the compressed data is returned
540 """
Simon Glassb6dff4c2019-07-20 12:23:36 -0600541 self.Detail('GetData: size %s' % ToHexSize(self.data))
Simon Glass2574ef62016-11-25 20:15:51 -0700542 return self.data
543
Simon Glasse17220f2020-11-02 12:55:43 -0700544 def GetPaddedData(self, data=None):
545 """Get the data for an entry including any padding
546
547 Gets the entry data and uses its section's pad-byte value to add padding
548 before and after as defined by the pad-before and pad-after properties.
549
550 This does not consider alignment.
551
552 Returns:
553 Contents of the entry along with any pad bytes before and
554 after it (bytes)
555 """
556 if data is None:
557 data = self.GetData()
558 return self.section.GetPaddedDataForEntry(self, data)
559
Simon Glasse8561af2018-08-01 15:22:37 -0600560 def GetOffsets(self):
Simon Glass224bc662019-07-08 13:18:30 -0600561 """Get the offsets for siblings
562
563 Some entry types can contain information about the position or size of
564 other entries. An example of this is the Intel Flash Descriptor, which
565 knows where the Intel Management Engine section should go.
566
567 If this entry knows about the position of other entries, it can specify
568 this by returning values here
569
570 Returns:
571 Dict:
572 key: Entry type
573 value: List containing position and size of the given entry
Simon Glassed365eb2019-07-08 13:18:39 -0600574 type. Either can be None if not known
Simon Glass224bc662019-07-08 13:18:30 -0600575 """
Simon Glass2574ef62016-11-25 20:15:51 -0700576 return {}
577
Simon Glassed365eb2019-07-08 13:18:39 -0600578 def SetOffsetSize(self, offset, size):
579 """Set the offset and/or size of an entry
580
581 Args:
582 offset: New offset, or None to leave alone
583 size: New size, or None to leave alone
584 """
585 if offset is not None:
586 self.offset = offset
587 if size is not None:
588 self.size = size
Simon Glass2574ef62016-11-25 20:15:51 -0700589
Simon Glass9dcc8612018-08-01 15:22:42 -0600590 def SetImagePos(self, image_pos):
591 """Set the position in the image
592
593 Args:
594 image_pos: Position of this entry in the image
595 """
596 self.image_pos = image_pos + self.offset
597
Simon Glass2574ef62016-11-25 20:15:51 -0700598 def ProcessContents(self):
Simon Glassec849852019-07-08 14:25:35 -0600599 """Do any post-packing updates of entry contents
600
601 This function should call ProcessContentsUpdate() to update the entry
602 contents, if necessary, returning its return value here.
603
604 Args:
605 data: Data to set to the contents (bytes)
606
607 Returns:
608 True if the new data size is OK, False if expansion is needed
609
610 Raises:
611 ValueError if the new data size is not the same as the old and
612 state.AllowEntryExpansion() is False
613 """
614 return True
Simon Glass4ca8e042017-11-13 18:55:01 -0700615
Simon Glass8a6f56e2018-06-01 09:38:13 -0600616 def WriteSymbols(self, section):
Simon Glass4ca8e042017-11-13 18:55:01 -0700617 """Write symbol values into binary files for access at run time
618
619 Args:
Simon Glass8a6f56e2018-06-01 09:38:13 -0600620 section: Section containing the entry
Simon Glass4ca8e042017-11-13 18:55:01 -0700621 """
622 pass
Simon Glassa91e1152018-06-01 09:38:16 -0600623
Simon Glass55f68072020-10-26 17:40:18 -0600624 def CheckEntries(self):
Simon Glasse8561af2018-08-01 15:22:37 -0600625 """Check that the entry offsets are correct
Simon Glassa91e1152018-06-01 09:38:16 -0600626
Simon Glasse8561af2018-08-01 15:22:37 -0600627 This is used for entries which have extra offset requirements (other
Simon Glassa91e1152018-06-01 09:38:16 -0600628 than having to be fully inside their section). Sub-classes can implement
629 this function and raise if there is a problem.
630 """
631 pass
Simon Glass30732662018-06-01 09:38:20 -0600632
Simon Glass3a9a2b82018-07-17 13:25:28 -0600633 @staticmethod
Simon Glasscd817d52018-09-14 04:57:36 -0600634 def GetStr(value):
635 if value is None:
636 return '<none> '
637 return '%08x' % value
638
639 @staticmethod
Simon Glass7eca7922018-07-17 13:25:49 -0600640 def WriteMapLine(fd, indent, name, offset, size, image_pos):
Simon Glasscd817d52018-09-14 04:57:36 -0600641 print('%s %s%s %s %s' % (Entry.GetStr(image_pos), ' ' * indent,
642 Entry.GetStr(offset), Entry.GetStr(size),
643 name), file=fd)
Simon Glass3a9a2b82018-07-17 13:25:28 -0600644
Simon Glass30732662018-06-01 09:38:20 -0600645 def WriteMap(self, fd, indent):
646 """Write a map of the entry to a .map file
647
648 Args:
649 fd: File to write the map to
650 indent: Curent indent level of map (0=none, 1=one level, etc.)
651 """
Simon Glass7eca7922018-07-17 13:25:49 -0600652 self.WriteMapLine(fd, indent, self.name, self.offset, self.size,
653 self.image_pos)
Simon Glass91710b32018-07-17 13:25:32 -0600654
Simon Glass704784b2018-07-17 13:25:38 -0600655 def GetEntries(self):
656 """Return a list of entries contained by this entry
657
658 Returns:
659 List of entries, or None if none. A normal entry has no entries
660 within it so will return None
661 """
662 return None
663
Simon Glass91710b32018-07-17 13:25:32 -0600664 def GetArg(self, name, datatype=str):
665 """Get the value of an entry argument or device-tree-node property
666
667 Some node properties can be provided as arguments to binman. First check
668 the entry arguments, and fall back to the device tree if not found
669
670 Args:
671 name: Argument name
672 datatype: Data type (str or int)
673
674 Returns:
675 Value of argument as a string or int, or None if no value
676
677 Raises:
678 ValueError if the argument cannot be converted to in
679 """
Simon Glass29aa7362018-09-14 04:57:19 -0600680 value = state.GetEntryArg(name)
Simon Glass91710b32018-07-17 13:25:32 -0600681 if value is not None:
682 if datatype == int:
683 try:
684 value = int(value)
685 except ValueError:
686 self.Raise("Cannot convert entry arg '%s' (value '%s') to integer" %
687 (name, value))
688 elif datatype == str:
689 pass
690 else:
691 raise ValueError("GetArg() internal error: Unknown data type '%s'" %
692 datatype)
693 else:
694 value = fdt_util.GetDatatype(self._node, name, datatype)
695 return value
Simon Glass969616c2018-07-17 13:25:36 -0600696
697 @staticmethod
698 def WriteDocs(modules, test_missing=None):
699 """Write out documentation about the various entry types to stdout
700
701 Args:
702 modules: List of modules to include
703 test_missing: Used for testing. This is a module to report
704 as missing
705 """
706 print('''Binman Entry Documentation
707===========================
708
709This file describes the entry types supported by binman. These entry types can
710be placed in an image one by one to build up a final firmware image. It is
711fairly easy to create new entry types. Just add a new file to the 'etype'
712directory. You can use the existing entries as examples.
713
714Note that some entries are subclasses of others, using and extending their
715features to produce new behaviours.
716
717
718''')
719 modules = sorted(modules)
720
721 # Don't show the test entry
722 if '_testing' in modules:
723 modules.remove('_testing')
724 missing = []
725 for name in modules:
Simon Glass2f859412021-03-18 20:25:04 +1300726 module = Entry.Lookup('WriteDocs', name, False)
Simon Glass969616c2018-07-17 13:25:36 -0600727 docs = getattr(module, '__doc__')
728 if test_missing == name:
729 docs = None
730 if docs:
731 lines = docs.splitlines()
732 first_line = lines[0]
733 rest = [line[4:] for line in lines[1:]]
734 hdr = 'Entry: %s: %s' % (name.replace('_', '-'), first_line)
735 print(hdr)
736 print('-' * len(hdr))
737 print('\n'.join(rest))
738 print()
739 print()
740 else:
741 missing.append(name)
742
743 if missing:
744 raise ValueError('Documentation is missing for modules: %s' %
745 ', '.join(missing))
Simon Glass639505b2018-09-14 04:57:11 -0600746
747 def GetUniqueName(self):
748 """Get a unique name for a node
749
750 Returns:
751 String containing a unique name for a node, consisting of the name
752 of all ancestors (starting from within the 'binman' node) separated
753 by a dot ('.'). This can be useful for generating unique filesnames
754 in the output directory.
755 """
756 name = self.name
757 node = self._node
758 while node.parent:
759 node = node.parent
760 if node.name == 'binman':
761 break
762 name = '%s.%s' % (node.name, name)
763 return name
Simon Glassfa79a812018-09-14 04:57:29 -0600764
765 def ExpandToLimit(self, limit):
766 """Expand an entry so that it ends at the given offset limit"""
767 if self.offset + self.size < limit:
768 self.size = limit - self.offset
769 # Request the contents again, since changing the size requires that
770 # the data grows. This should not fail, but check it to be sure.
771 if not self.ObtainContents():
772 self.Raise('Cannot obtain contents when expanding entry')
Simon Glassc4056b82019-07-08 13:18:38 -0600773
774 def HasSibling(self, name):
775 """Check if there is a sibling of a given name
776
777 Returns:
778 True if there is an entry with this name in the the same section,
779 else False
780 """
781 return name in self.section.GetEntries()
Simon Glasscec34ba2019-07-08 14:25:28 -0600782
783 def GetSiblingImagePos(self, name):
784 """Return the image position of the given sibling
785
786 Returns:
787 Image position of sibling, or None if the sibling has no position,
788 or False if there is no such sibling
789 """
790 if not self.HasSibling(name):
791 return False
792 return self.section.GetEntries()[name].image_pos
Simon Glass6b156f82019-07-08 14:25:43 -0600793
794 @staticmethod
795 def AddEntryInfo(entries, indent, name, etype, size, image_pos,
796 uncomp_size, offset, entry):
797 """Add a new entry to the entries list
798
799 Args:
800 entries: List (of EntryInfo objects) to add to
801 indent: Current indent level to add to list
802 name: Entry name (string)
803 etype: Entry type (string)
804 size: Entry size in bytes (int)
805 image_pos: Position within image in bytes (int)
806 uncomp_size: Uncompressed size if the entry uses compression, else
807 None
808 offset: Entry offset within parent in bytes (int)
809 entry: Entry object
810 """
811 entries.append(EntryInfo(indent, name, etype, size, image_pos,
812 uncomp_size, offset, entry))
813
814 def ListEntries(self, entries, indent):
815 """Add files in this entry to the list of entries
816
817 This can be overridden by subclasses which need different behaviour.
818
819 Args:
820 entries: List (of EntryInfo objects) to add to
821 indent: Current indent level to add to list
822 """
823 self.AddEntryInfo(entries, indent, self.name, self.etype, self.size,
824 self.image_pos, self.uncomp_size, self.offset, self)
Simon Glass4c613bf2019-07-08 14:25:50 -0600825
Simon Glass637958f2021-11-23 21:09:50 -0700826 def ReadData(self, decomp=True, alt_format=None):
Simon Glass4c613bf2019-07-08 14:25:50 -0600827 """Read the data for an entry from the image
828
829 This is used when the image has been read in and we want to extract the
830 data for a particular entry from that image.
831
832 Args:
833 decomp: True to decompress any compressed data before returning it;
834 False to return the raw, uncompressed data
835
836 Returns:
837 Entry data (bytes)
838 """
839 # Use True here so that we get an uncompressed section to work from,
840 # although compressed sections are currently not supported
Simon Glass4d8151f2019-09-25 08:56:21 -0600841 tout.Debug("ReadChildData section '%s', entry '%s'" %
842 (self.section.GetPath(), self.GetPath()))
Simon Glass637958f2021-11-23 21:09:50 -0700843 data = self.section.ReadChildData(self, decomp, alt_format)
Simon Glass0cd8ace2019-07-20 12:24:04 -0600844 return data
Simon Glassaf8c45c2019-07-20 12:23:41 -0600845
Simon Glass637958f2021-11-23 21:09:50 -0700846 def ReadChildData(self, child, decomp=True, alt_format=None):
Simon Glass4d8151f2019-09-25 08:56:21 -0600847 """Read the data for a particular child entry
Simon Glass23f00472019-09-25 08:56:20 -0600848
849 This reads data from the parent and extracts the piece that relates to
850 the given child.
851
852 Args:
Simon Glass637958f2021-11-23 21:09:50 -0700853 child (Entry): Child entry to read data for (must be valid)
854 decomp (bool): True to decompress any compressed data before
855 returning it; False to return the raw, uncompressed data
856 alt_format (str): Alternative format to read in, or None
Simon Glass23f00472019-09-25 08:56:20 -0600857
858 Returns:
859 Data for the child (bytes)
860 """
861 pass
862
Simon Glassaf8c45c2019-07-20 12:23:41 -0600863 def LoadData(self, decomp=True):
864 data = self.ReadData(decomp)
Simon Glass072959a2019-07-20 12:23:50 -0600865 self.contents_size = len(data)
Simon Glassaf8c45c2019-07-20 12:23:41 -0600866 self.ProcessContentsUpdate(data)
867 self.Detail('Loaded data size %x' % len(data))
Simon Glass990b1742019-07-20 12:23:46 -0600868
Simon Glass637958f2021-11-23 21:09:50 -0700869 def GetAltFormat(self, data, alt_format):
870 """Read the data for an extry in an alternative format
871
872 Supported formats are list in the documentation for each entry. An
873 example is fdtmap which provides .
874
875 Args:
876 data (bytes): Data to convert (this should have been produced by the
877 entry)
878 alt_format (str): Format to use
879
880 """
881 pass
882
Simon Glass990b1742019-07-20 12:23:46 -0600883 def GetImage(self):
884 """Get the image containing this entry
885
886 Returns:
887 Image object containing this entry
888 """
889 return self.section.GetImage()
Simon Glass072959a2019-07-20 12:23:50 -0600890
891 def WriteData(self, data, decomp=True):
892 """Write the data to an entry in the image
893
894 This is used when the image has been read in and we want to replace the
895 data for a particular entry in that image.
896
897 The image must be re-packed and written out afterwards.
898
899 Args:
900 data: Data to replace it with
901 decomp: True to compress the data if needed, False if data is
902 already compressed so should be used as is
903
904 Returns:
905 True if the data did not result in a resize of this entry, False if
906 the entry must be resized
907 """
Simon Glass1fdb4872019-10-31 07:43:02 -0600908 if self.size is not None:
909 self.contents_size = self.size
910 else:
911 self.contents_size = self.pre_reset_size
Simon Glass072959a2019-07-20 12:23:50 -0600912 ok = self.ProcessContentsUpdate(data)
913 self.Detail('WriteData: size=%x, ok=%s' % (len(data), ok))
Simon Glassd34af7a2019-07-20 12:24:05 -0600914 section_ok = self.section.WriteChildData(self)
915 return ok and section_ok
916
917 def WriteChildData(self, child):
918 """Handle writing the data in a child entry
919
920 This should be called on the child's parent section after the child's
Simon Glasse796f242021-11-23 11:03:44 -0700921 data has been updated. It should update any data structures needed to
922 validate that the update is successful.
Simon Glassd34af7a2019-07-20 12:24:05 -0600923
924 This base-class implementation does nothing, since the base Entry object
925 does not have any children.
926
927 Args:
928 child: Child Entry that was written
929
930 Returns:
931 True if the section could be updated successfully, False if the
Simon Glasse796f242021-11-23 11:03:44 -0700932 data is such that the section could not update
Simon Glassd34af7a2019-07-20 12:24:05 -0600933 """
934 return True
Simon Glass11453762019-07-20 12:23:55 -0600935
936 def GetSiblingOrder(self):
937 """Get the relative order of an entry amoung its siblings
938
939 Returns:
940 'start' if this entry is first among siblings, 'end' if last,
941 otherwise None
942 """
943 entries = list(self.section.GetEntries().values())
944 if entries:
945 if self == entries[0]:
946 return 'start'
947 elif self == entries[-1]:
948 return 'end'
949 return 'middle'
Simon Glass5d94cc62020-07-09 18:39:38 -0600950
951 def SetAllowMissing(self, allow_missing):
952 """Set whether a section allows missing external blobs
953
954 Args:
955 allow_missing: True if allowed, False if not allowed
956 """
957 # This is meaningless for anything other than sections
958 pass
Simon Glassa003cd32020-07-09 18:39:40 -0600959
Heiko Thiery6d451362022-01-06 11:49:41 +0100960 def SetAllowFakeBlob(self, allow_fake):
961 """Set whether a section allows to create a fake blob
962
963 Args:
964 allow_fake: True if allowed, False if not allowed
965 """
Simon Glassceb5f912022-01-09 20:13:46 -0700966 self.allow_fake = allow_fake
Heiko Thiery6d451362022-01-06 11:49:41 +0100967
Simon Glassa003cd32020-07-09 18:39:40 -0600968 def CheckMissing(self, missing_list):
969 """Check if any entries in this section have missing external blobs
970
971 If there are missing blobs, the entries are added to the list
972
973 Args:
974 missing_list: List of Entry objects to be added to
975 """
976 if self.missing:
977 missing_list.append(self)
Simon Glassb8f90372020-09-01 05:13:57 -0600978
Simon Glass7a602fd2022-01-12 13:10:36 -0700979 def check_fake_fname(self, fname):
980 """If the file is missing and the entry allows fake blobs, fake it
981
982 Sets self.faked to True if faked
983
984 Args:
985 fname (str): Filename to check
986
987 Returns:
988 fname (str): Filename of faked file
989 """
990 if self.allow_fake and not pathlib.Path(fname).is_file():
991 outfname = tools.GetOutputFilename(os.path.basename(fname))
992 with open(outfname, "wb") as out:
993 out.truncate(1024)
994 self.faked = True
995 return outfname
996 return fname
997
Heiko Thiery6d451362022-01-06 11:49:41 +0100998 def CheckFakedBlobs(self, faked_blobs_list):
999 """Check if any entries in this section have faked external blobs
1000
1001 If there are faked blobs, the entries are added to the list
1002
1003 Args:
1004 fake_blobs_list: List of Entry objects to be added to
1005 """
1006 # This is meaningless for anything other than blobs
1007 pass
1008
Simon Glassb8f90372020-09-01 05:13:57 -06001009 def GetAllowMissing(self):
1010 """Get whether a section allows missing external blobs
1011
1012 Returns:
1013 True if allowed, False if not allowed
1014 """
1015 return self.allow_missing
Simon Glassa820af72020-09-06 10:39:09 -06001016
1017 def GetHelpTags(self):
1018 """Get the tags use for missing-blob help
1019
1020 Returns:
1021 list of possible tags, most desirable first
1022 """
1023 return list(filter(None, [self.missing_msg, self.name, self.etype]))
Simon Glassa1301a22020-10-26 17:40:06 -06001024
1025 def CompressData(self, indata):
1026 """Compress data according to the entry's compression method
1027
1028 Args:
1029 indata: Data to compress
1030
1031 Returns:
1032 Compressed data (first word is the compressed size)
1033 """
Simon Glass789b34402020-10-26 17:40:15 -06001034 self.uncomp_data = indata
Simon Glassa1301a22020-10-26 17:40:06 -06001035 if self.compress != 'none':
1036 self.uncomp_size = len(indata)
1037 data = tools.Compress(indata, self.compress)
1038 return data
Simon Glass2f859412021-03-18 20:25:04 +13001039
1040 @classmethod
1041 def UseExpanded(cls, node, etype, new_etype):
1042 """Check whether to use an expanded entry type
1043
1044 This is called by Entry.Create() when it finds an expanded version of
1045 an entry type (e.g. 'u-boot-expanded'). If this method returns True then
1046 it will be used (e.g. in place of 'u-boot'). If it returns False, it is
1047 ignored.
1048
1049 Args:
1050 node: Node object containing information about the entry to
1051 create
1052 etype: Original entry type being used
1053 new_etype: New entry type proposed
1054
1055 Returns:
1056 True to use this entry type, False to use the original one
1057 """
1058 tout.Info("Node '%s': etype '%s': %s selected" %
1059 (node.path, etype, new_etype))
1060 return True
Simon Glass637958f2021-11-23 21:09:50 -07001061
1062 def CheckAltFormats(self, alt_formats):
1063 """Add any alternative formats supported by this entry type
1064
1065 Args:
1066 alt_formats (dict): Dict to add alt_formats to:
1067 key: Name of alt format
1068 value: Help text
1069 """
1070 pass
Simon Glass4eae9252022-01-09 20:13:50 -07001071
1072 def AddBintools(self, tools):
1073 """Add the bintools used by this entry type
1074
1075 Args:
1076 tools (dict of Bintool):
1077 """
1078 pass
1079
1080 @classmethod
1081 def AddBintool(self, tools, name):
1082 """Add a new bintool to the tools used by this etype
1083
1084 Args:
1085 name: Name of the tool
1086 """
1087 btool = bintool.Bintool.create(name)
1088 tools[name] = btool
1089 return btool