blob: 3e78cf343004b2d932d084ad5f5239e525c1b05e [file] [log] [blame]
Simon Glass29aa7362018-09-14 04:57:19 -06001# SPDX-License-Identifier: GPL-2.0+
2# Copyright 2018 Google, Inc
3# Written by Simon Glass <sjg@chromium.org>
4#
5# Holds and modifies the state information held by binman
6#
7
Simon Glass748a1d42021-07-06 10:36:41 -06008from collections import defaultdict
Simon Glassae7cf032018-09-14 04:57:31 -06009import hashlib
Simon Glass29aa7362018-09-14 04:57:19 -060010import re
Simon Glass748a1d42021-07-06 10:36:41 -060011import time
Simon Glass76f496d2021-07-06 10:36:37 -060012import threading
Simon Glass29aa7362018-09-14 04:57:19 -060013
Simon Glassc585dd42020-04-17 18:09:03 -060014from dtoc import fdt
Simon Glass29aa7362018-09-14 04:57:19 -060015import os
Simon Glass131444f2023-02-23 18:18:04 -070016from u_boot_pylib import tools
17from u_boot_pylib import tout
Simon Glass29aa7362018-09-14 04:57:19 -060018
Simon Glass88e04da2021-11-23 11:03:42 -070019OUR_PATH = os.path.dirname(os.path.realpath(__file__))
20
Simon Glassf184d952021-03-18 20:25:00 +130021# Map an dtb etype to its expected filename
22DTB_TYPE_FNAME = {
23 'u-boot-spl-dtb': 'spl/u-boot-spl.dtb',
24 'u-boot-tpl-dtb': 'tpl/u-boot-tpl.dtb',
Simon Glass56d05412022-02-28 07:16:54 -070025 'u-boot-vpl-dtb': 'vpl/u-boot-vpl.dtb',
Simon Glassf184d952021-03-18 20:25:00 +130026 }
27
Simon Glass2be381d2019-07-20 12:23:32 -060028# Records the device-tree files known to binman, keyed by entry type (e.g.
29# 'u-boot-spl-dtb'). These are the output FDT files, which can be updated by
30# binman. They have been copied to <xxx>.out files.
31#
Simon Glassa1ba6182021-03-18 20:25:01 +130032# key: entry type (e.g. 'u-boot-dtb)
Simon Glass2be381d2019-07-20 12:23:32 -060033# value: tuple:
34# Fdt object
35# Filename
Simon Glass95f1a942019-07-20 12:23:43 -060036output_fdt_info = {}
Simon Glass29aa7362018-09-14 04:57:19 -060037
Simon Glass072959a2019-07-20 12:23:50 -060038# Prefix to add to an fdtmap path to turn it into a path to the /binman node
39fdt_path_prefix = ''
40
Simon Glass29aa7362018-09-14 04:57:19 -060041# Arguments passed to binman to provide arguments to entries
42entry_args = {}
43
Simon Glass0c9d5b52018-09-14 04:57:22 -060044# True to use fake device-tree files for testing (see U_BOOT_DTB_DATA in
45# ftest.py)
Simon Glass31402012018-09-14 04:57:23 -060046use_fake_dtb = False
Simon Glass0c9d5b52018-09-14 04:57:22 -060047
Simon Glassbdb40312018-09-14 04:57:20 -060048# The DTB which contains the full image information
49main_dtb = None
50
Simon Glasscbc80e82019-07-08 14:25:36 -060051# Allow entries to expand after they have been packed. This is detected and
52# forces a re-pack. If not allowed, any attempted expansion causes an error in
53# Entry.ProcessContentsUpdate()
54allow_entry_expansion = True
55
Simon Glass9d8ee322019-07-20 12:23:58 -060056# Don't allow entries to contract after they have been packed. Instead just
57# leave some wasted space. If allowed, this is detected and forces a re-pack,
58# but may result in entries that oscillate in size, thus causing a pack error.
59# An example is a compressed device tree where the original offset values
60# result in a larger compressed size than the new ones, but then after updating
61# to the new ones, the compressed size increases, etc.
62allow_entry_contraction = False
63
Simon Glass76f496d2021-07-06 10:36:37 -060064# Number of threads to use for binman (None means machine-dependent)
65num_threads = None
66
Simon Glass748a1d42021-07-06 10:36:41 -060067
68class Timing:
69 """Holds information about an operation that is being timed
70
71 Properties:
72 name: Operation name (only one of each name is stored)
73 start: Start time of operation in seconds (None if not start)
74 accum:: Amount of time spent on this operation so far, in seconds
75 """
76 def __init__(self, name):
77 self.name = name
78 self.start = None # cause an error if TimingStart() is not called
79 self.accum = 0.0
80
81
82# Holds timing info for each name:
83# key: name of Timing info (Timing.name)
84# value: Timing object
85timing_info = {}
86
87
Simon Glass2be381d2019-07-20 12:23:32 -060088def GetFdtForEtype(etype):
89 """Get the Fdt object for a particular device-tree entry
Simon Glass29aa7362018-09-14 04:57:19 -060090
91 Binman keeps track of at least one device-tree file called u-boot.dtb but
92 can also have others (e.g. for SPL). This function looks up the given
Simon Glass2be381d2019-07-20 12:23:32 -060093 entry and returns the associated Fdt object.
Simon Glass29aa7362018-09-14 04:57:19 -060094
95 Args:
Simon Glass2be381d2019-07-20 12:23:32 -060096 etype: Entry type of device tree (e.g. 'u-boot-dtb')
Simon Glass29aa7362018-09-14 04:57:19 -060097
98 Returns:
Simon Glass2be381d2019-07-20 12:23:32 -060099 Fdt object associated with the entry type
Simon Glass29aa7362018-09-14 04:57:19 -0600100 """
Simon Glass95f1a942019-07-20 12:23:43 -0600101 value = output_fdt_info.get(etype);
Simon Glass385138a2019-07-20 12:23:42 -0600102 if not value:
103 return None
104 return value[0]
Simon Glass29aa7362018-09-14 04:57:19 -0600105
Simon Glass2be381d2019-07-20 12:23:32 -0600106def GetFdtPath(etype):
Simon Glass29aa7362018-09-14 04:57:19 -0600107 """Get the full pathname of a particular Fdt object
108
Simon Glassa3030a52019-07-20 12:23:30 -0600109 Similar to GetFdtForEtype() but returns the pathname associated with the
110 Fdt.
Simon Glass29aa7362018-09-14 04:57:19 -0600111
112 Args:
Simon Glass2be381d2019-07-20 12:23:32 -0600113 etype: Entry type of device tree (e.g. 'u-boot-dtb')
Simon Glass29aa7362018-09-14 04:57:19 -0600114
115 Returns:
116 Full path name to the associated Fdt
117 """
Simon Glass95f1a942019-07-20 12:23:43 -0600118 return output_fdt_info[etype][0]._fname
Simon Glass29aa7362018-09-14 04:57:19 -0600119
Simon Glass2be381d2019-07-20 12:23:32 -0600120def GetFdtContents(etype='u-boot-dtb'):
Simon Glasse219aa42018-09-14 04:57:24 -0600121 """Looks up the FDT pathname and contents
122
123 This is used to obtain the Fdt pathname and contents when needed by an
124 entry. It supports a 'fake' dtb, allowing tests to substitute test data for
125 the real dtb.
126
127 Args:
Simon Glass2be381d2019-07-20 12:23:32 -0600128 etype: Entry type to look up (e.g. 'u-boot.dtb').
Simon Glasse219aa42018-09-14 04:57:24 -0600129
130 Returns:
131 tuple:
132 pathname to Fdt
133 Fdt data (as bytes)
134 """
Simon Glass95f1a942019-07-20 12:23:43 -0600135 if etype not in output_fdt_info:
Simon Glass385138a2019-07-20 12:23:42 -0600136 return None, None
137 if not use_fake_dtb:
Simon Glass2be381d2019-07-20 12:23:32 -0600138 pathname = GetFdtPath(etype)
139 data = GetFdtForEtype(etype).GetContents()
Simon Glasse219aa42018-09-14 04:57:24 -0600140 else:
Simon Glass95f1a942019-07-20 12:23:43 -0600141 fname = output_fdt_info[etype][1]
Simon Glass80025522022-01-29 14:14:04 -0700142 pathname = tools.get_input_filename(fname)
143 data = tools.read_file(pathname)
Simon Glasse219aa42018-09-14 04:57:24 -0600144 return pathname, data
145
Simon Glass74f5feb2019-07-20 12:24:08 -0600146def UpdateFdtContents(etype, data):
147 """Update the contents of a particular device tree
148
149 The device tree is updated and written back to its file. This affects what
150 is returned from future called to GetFdtContents(), etc.
151
152 Args:
153 etype: Entry type (e.g. 'u-boot-dtb')
154 data: Data to replace the DTB with
155 """
Simon Glassa1ba6182021-03-18 20:25:01 +1300156 dtb, fname = output_fdt_info[etype]
Simon Glass74f5feb2019-07-20 12:24:08 -0600157 dtb_fname = dtb.GetFilename()
Simon Glass80025522022-01-29 14:14:04 -0700158 tools.write_file(dtb_fname, data)
Simon Glass74f5feb2019-07-20 12:24:08 -0600159 dtb = fdt.FdtScan(dtb_fname)
Simon Glassa1ba6182021-03-18 20:25:01 +1300160 output_fdt_info[etype] = [dtb, fname]
Simon Glass74f5feb2019-07-20 12:24:08 -0600161
Simon Glass29aa7362018-09-14 04:57:19 -0600162def SetEntryArgs(args):
163 """Set the value of the entry args
164
165 This sets up the entry_args dict which is used to supply entry arguments to
166 entries.
167
168 Args:
169 args: List of entry arguments, each in the format "name=value"
170 """
171 global entry_args
172
173 entry_args = {}
Simon Glass011f1b32022-01-29 14:14:15 -0700174 tout.debug('Processing entry args:')
Simon Glass29aa7362018-09-14 04:57:19 -0600175 if args:
176 for arg in args:
177 m = re.match('([^=]*)=(.*)', arg)
178 if not m:
179 raise ValueError("Invalid entry arguemnt '%s'" % arg)
Simon Glass718b5292021-03-18 20:25:07 +1300180 name, value = m.groups()
Simon Glass011f1b32022-01-29 14:14:15 -0700181 tout.debug(' %20s = %s' % (name, value))
Simon Glass718b5292021-03-18 20:25:07 +1300182 entry_args[name] = value
Simon Glass011f1b32022-01-29 14:14:15 -0700183 tout.debug('Processing entry args done')
Simon Glass29aa7362018-09-14 04:57:19 -0600184
185def GetEntryArg(name):
186 """Get the value of an entry argument
187
188 Args:
189 name: Name of argument to retrieve
190
191 Returns:
192 String value of argument
193 """
194 return entry_args.get(name)
Simon Glassbdb40312018-09-14 04:57:20 -0600195
Simon Glass718b5292021-03-18 20:25:07 +1300196def GetEntryArgBool(name):
197 """Get the value of an entry argument as a boolean
198
199 Args:
200 name: Name of argument to retrieve
201
202 Returns:
203 False if the entry argument is consider False (empty, '0' or 'n'), else
204 True
205 """
206 val = GetEntryArg(name)
207 return val and val not in ['n', '0']
208
Simon Glass0c9d5b52018-09-14 04:57:22 -0600209def Prepare(images, dtb):
Simon Glassbdb40312018-09-14 04:57:20 -0600210 """Get device tree files ready for use
211
Simon Glass5a300602019-07-20 12:23:29 -0600212 This sets up a set of device tree files that can be retrieved by
213 GetAllFdts(). This includes U-Boot proper and any SPL device trees.
Simon Glassbdb40312018-09-14 04:57:20 -0600214
215 Args:
Simon Glass0c9d5b52018-09-14 04:57:22 -0600216 images: List of images being used
Simon Glassbdb40312018-09-14 04:57:20 -0600217 dtb: Main dtb
218 """
Simon Glass072959a2019-07-20 12:23:50 -0600219 global output_fdt_info, main_dtb, fdt_path_prefix
Simon Glassbdb40312018-09-14 04:57:20 -0600220 # Import these here in case libfdt.py is not available, in which case
221 # the above help option still works.
Simon Glassc585dd42020-04-17 18:09:03 -0600222 from dtoc import fdt
223 from dtoc import fdt_util
Simon Glassbdb40312018-09-14 04:57:20 -0600224
225 # If we are updating the DTBs we need to put these updated versions
226 # where Entry_blob_dtb can find them. We can ignore 'u-boot.dtb'
227 # since it is assumed to be the one passed in with options.dt, and
228 # was handled just above.
229 main_dtb = dtb
Simon Glass95f1a942019-07-20 12:23:43 -0600230 output_fdt_info.clear()
Simon Glass072959a2019-07-20 12:23:50 -0600231 fdt_path_prefix = ''
Simon Glassa1ba6182021-03-18 20:25:01 +1300232 output_fdt_info['u-boot-dtb'] = [dtb, 'u-boot.dtb']
Simon Glassf184d952021-03-18 20:25:00 +1300233 if use_fake_dtb:
234 for etype, fname in DTB_TYPE_FNAME.items():
Simon Glassa1ba6182021-03-18 20:25:01 +1300235 output_fdt_info[etype] = [dtb, fname]
Simon Glassf184d952021-03-18 20:25:00 +1300236 else:
Simon Glassf3aba912019-07-20 12:23:34 -0600237 fdt_set = {}
Simon Glasseb751fd2021-03-18 20:25:03 +1300238 for etype, fname in DTB_TYPE_FNAME.items():
Simon Glass80025522022-01-29 14:14:04 -0700239 infile = tools.get_input_filename(fname, allow_missing=True)
Simon Glasseb751fd2021-03-18 20:25:03 +1300240 if infile and os.path.exists(infile):
241 fname_dtb = fdt_util.EnsureCompiled(infile)
Simon Glass80025522022-01-29 14:14:04 -0700242 out_fname = tools.get_output_filename('%s.out' %
Simon Glasseb751fd2021-03-18 20:25:03 +1300243 os.path.split(fname)[1])
Simon Glass80025522022-01-29 14:14:04 -0700244 tools.write_file(out_fname, tools.read_file(fname_dtb))
Simon Glasseb751fd2021-03-18 20:25:03 +1300245 other_dtb = fdt.FdtScan(out_fname)
246 output_fdt_info[etype] = [other_dtb, out_fname]
247
Simon Glassbdb40312018-09-14 04:57:20 -0600248
Simon Glass072959a2019-07-20 12:23:50 -0600249def PrepareFromLoadedData(image):
250 """Get device tree files ready for use with a loaded image
251
252 Loaded images are different from images that are being created by binman,
253 since there is generally already an fdtmap and we read the description from
254 that. This provides the position and size of every entry in the image with
255 no calculation required.
256
257 This function uses the same output_fdt_info[] as Prepare(). It finds the
258 device tree files, adds a reference to the fdtmap and sets the FDT path
259 prefix to translate from the fdtmap (where the root node is the image node)
260 to the normal device tree (where the image node is under a /binman node).
261
262 Args:
263 images: List of images being used
264 """
265 global output_fdt_info, main_dtb, fdt_path_prefix
266
Simon Glass011f1b32022-01-29 14:14:15 -0700267 tout.info('Preparing device trees')
Simon Glass072959a2019-07-20 12:23:50 -0600268 output_fdt_info.clear()
269 fdt_path_prefix = ''
Simon Glassa1ba6182021-03-18 20:25:01 +1300270 output_fdt_info['fdtmap'] = [image.fdtmap_dtb, 'u-boot.dtb']
Simon Glass072959a2019-07-20 12:23:50 -0600271 main_dtb = None
Simon Glass011f1b32022-01-29 14:14:15 -0700272 tout.info(" Found device tree type 'fdtmap' '%s'" % image.fdtmap_dtb.name)
Simon Glass072959a2019-07-20 12:23:50 -0600273 for etype, value in image.GetFdts().items():
274 entry, fname = value
Simon Glass80025522022-01-29 14:14:04 -0700275 out_fname = tools.get_output_filename('%s.dtb' % entry.etype)
Simon Glass011f1b32022-01-29 14:14:15 -0700276 tout.info(" Found device tree type '%s' at '%s' path '%s'" %
Simon Glass072959a2019-07-20 12:23:50 -0600277 (etype, out_fname, entry.GetPath()))
278 entry._filename = entry.GetDefaultFilename()
279 data = entry.ReadData()
280
Simon Glass80025522022-01-29 14:14:04 -0700281 tools.write_file(out_fname, data)
Simon Glass072959a2019-07-20 12:23:50 -0600282 dtb = fdt.Fdt(out_fname)
283 dtb.Scan()
284 image_node = dtb.GetNode('/binman')
285 if 'multiple-images' in image_node.props:
286 image_node = dtb.GetNode('/binman/%s' % image.image_node)
287 fdt_path_prefix = image_node.path
Simon Glassa1ba6182021-03-18 20:25:01 +1300288 output_fdt_info[etype] = [dtb, None]
Simon Glass011f1b32022-01-29 14:14:15 -0700289 tout.info(" FDT path prefix '%s'" % fdt_path_prefix)
Simon Glass072959a2019-07-20 12:23:50 -0600290
291
Simon Glass5a300602019-07-20 12:23:29 -0600292def GetAllFdts():
Simon Glassbdb40312018-09-14 04:57:20 -0600293 """Yield all device tree files being used by binman
294
295 Yields:
Simon Glass56d05412022-02-28 07:16:54 -0700296 Device trees being used (U-Boot proper, SPL, TPL, VPL)
Simon Glassbdb40312018-09-14 04:57:20 -0600297 """
Simon Glass072959a2019-07-20 12:23:50 -0600298 if main_dtb:
299 yield main_dtb
Simon Glass95f1a942019-07-20 12:23:43 -0600300 for etype in output_fdt_info:
301 dtb = output_fdt_info[etype][0]
Simon Glass132fa722019-07-20 12:23:33 -0600302 if dtb != main_dtb:
303 yield dtb
Simon Glassbdb40312018-09-14 04:57:20 -0600304
Simon Glassfb30e292019-07-20 12:23:51 -0600305def GetUpdateNodes(node, for_repack=False):
Simon Glassc8135dc2018-09-14 04:57:21 -0600306 """Yield all the nodes that need to be updated in all device trees
307
308 The property referenced by this node is added to any device trees which
Jonas Karlman85a861b2023-02-19 22:02:03 +0000309 have the given node. Due to removable of unwanted nodes, SPL and TPL may
Simon Glassc8135dc2018-09-14 04:57:21 -0600310 not have this node.
311
312 Args:
313 node: Node object in the main device tree to look up
Simon Glassfb30e292019-07-20 12:23:51 -0600314 for_repack: True if we want only nodes which need 'repack' properties
315 added to them (e.g. 'orig-offset'), False to return all nodes. We
316 don't add repack properties to SPL/TPL device trees.
Simon Glassc8135dc2018-09-14 04:57:21 -0600317
318 Yields:
319 Node objects in each device tree that is in use (U-Boot proper, which
320 is node, SPL and TPL)
321 """
322 yield node
Simon Glassa1ba6182021-03-18 20:25:01 +1300323 for entry_type, (dtb, fname) in output_fdt_info.items():
Simon Glasse219aa42018-09-14 04:57:24 -0600324 if dtb != node.GetFdt():
Simon Glassa1ba6182021-03-18 20:25:01 +1300325 if for_repack and entry_type != 'u-boot-dtb':
Simon Glassfb30e292019-07-20 12:23:51 -0600326 continue
Simon Glass072959a2019-07-20 12:23:50 -0600327 other_node = dtb.GetNode(fdt_path_prefix + node.path)
Simon Glasse219aa42018-09-14 04:57:24 -0600328 if other_node:
329 yield other_node
Simon Glassc8135dc2018-09-14 04:57:21 -0600330
Simon Glassfb30e292019-07-20 12:23:51 -0600331def AddZeroProp(node, prop, for_repack=False):
Simon Glassc8135dc2018-09-14 04:57:21 -0600332 """Add a new property to affected device trees with an integer value of 0.
333
334 Args:
335 prop_name: Name of property
Simon Glassfb30e292019-07-20 12:23:51 -0600336 for_repack: True is this property is only needed for repacking
Simon Glassc8135dc2018-09-14 04:57:21 -0600337 """
Simon Glassfb30e292019-07-20 12:23:51 -0600338 for n in GetUpdateNodes(node, for_repack):
Simon Glassc8135dc2018-09-14 04:57:21 -0600339 n.AddZeroProp(prop)
340
Simon Glassac6328c2018-09-14 04:57:28 -0600341def AddSubnode(node, name):
342 """Add a new subnode to a node in affected device trees
343
344 Args:
345 node: Node to add to
346 name: name of node to add
347
348 Returns:
349 New subnode that was created in main tree
350 """
351 first = None
352 for n in GetUpdateNodes(node):
353 subnode = n.AddSubnode(name)
354 if not first:
355 first = subnode
356 return first
357
358def AddString(node, prop, value):
359 """Add a new string property to affected device trees
360
361 Args:
362 prop_name: Name of property
363 value: String value (which will be \0-terminated in the DT)
364 """
365 for n in GetUpdateNodes(node):
366 n.AddString(prop, value)
367
Simon Glassa2af7302021-01-06 21:35:18 -0700368def AddInt(node, prop, value):
369 """Add a new string property to affected device trees
370
371 Args:
372 prop_name: Name of property
373 val: Integer value of property
374 """
375 for n in GetUpdateNodes(node):
376 n.AddInt(prop, value)
377
Simon Glassfb30e292019-07-20 12:23:51 -0600378def SetInt(node, prop, value, for_repack=False):
Simon Glassc8135dc2018-09-14 04:57:21 -0600379 """Update an integer property in affected device trees with an integer value
380
381 This is not allowed to change the size of the FDT.
382
383 Args:
384 prop_name: Name of property
Simon Glassfb30e292019-07-20 12:23:51 -0600385 for_repack: True is this property is only needed for repacking
Simon Glassc8135dc2018-09-14 04:57:21 -0600386 """
Simon Glassfb30e292019-07-20 12:23:51 -0600387 for n in GetUpdateNodes(node, for_repack):
Simon Glass011f1b32022-01-29 14:14:15 -0700388 tout.detail("File %s: Update node '%s' prop '%s' to %#x" %
Simon Glassf8a54bc2019-07-20 12:23:56 -0600389 (n.GetFdt().name, n.path, prop, value))
Simon Glassc8135dc2018-09-14 04:57:21 -0600390 n.SetInt(prop, value)
Simon Glassae7cf032018-09-14 04:57:31 -0600391
392def CheckAddHashProp(node):
393 hash_node = node.FindNode('hash')
394 if hash_node:
395 algo = hash_node.props.get('algo')
396 if not algo:
397 return "Missing 'algo' property for hash node"
398 if algo.value == 'sha256':
399 size = 32
400 else:
Simon Glass64af7c22022-02-08 10:59:44 -0700401 return "Unknown hash algorithm '%s'" % algo.value
Simon Glassae7cf032018-09-14 04:57:31 -0600402 for n in GetUpdateNodes(hash_node):
403 n.AddEmptyProp('value', size)
404
405def CheckSetHashValue(node, get_data_func):
406 hash_node = node.FindNode('hash')
407 if hash_node:
408 algo = hash_node.props.get('algo').value
409 if algo == 'sha256':
410 m = hashlib.sha256()
411 m.update(get_data_func())
412 data = m.digest()
413 for n in GetUpdateNodes(hash_node):
414 n.SetData('value', data)
Simon Glasscbc80e82019-07-08 14:25:36 -0600415
416def SetAllowEntryExpansion(allow):
417 """Set whether post-pack expansion of entries is allowed
418
419 Args:
420 allow: True to allow expansion, False to raise an exception
421 """
422 global allow_entry_expansion
423
424 allow_entry_expansion = allow
425
426def AllowEntryExpansion():
427 """Check whether post-pack expansion of entries is allowed
428
429 Returns:
430 True if expansion should be allowed, False if an exception should be
431 raised
432 """
433 return allow_entry_expansion
Simon Glass9d8ee322019-07-20 12:23:58 -0600434
435def SetAllowEntryContraction(allow):
436 """Set whether post-pack contraction of entries is allowed
437
438 Args:
439 allow: True to allow contraction, False to raise an exception
440 """
441 global allow_entry_contraction
442
443 allow_entry_contraction = allow
444
445def AllowEntryContraction():
446 """Check whether post-pack contraction of entries is allowed
447
448 Returns:
449 True if contraction should be allowed, False if an exception should be
450 raised
451 """
452 return allow_entry_contraction
Simon Glass76f496d2021-07-06 10:36:37 -0600453
454def SetThreads(threads):
455 """Set the number of threads to use when building sections
456
457 Args:
458 threads: Number of threads to use (None for default, 0 for
459 single-threaded)
460 """
461 global num_threads
462
463 num_threads = threads
464
465def GetThreads():
466 """Get the number of threads to use when building sections
467
468 Returns:
469 Number of threads to use (None for default, 0 for single-threaded)
470 """
471 return num_threads
Simon Glass748a1d42021-07-06 10:36:41 -0600472
473def GetTiming(name):
474 """Get the timing info for a particular operation
475
476 The object is created if it does not already exist.
477
478 Args:
479 name: Operation name to get
480
481 Returns:
482 Timing object for the current thread
483 """
484 threaded_name = '%s:%d' % (name, threading.get_ident())
485 timing = timing_info.get(threaded_name)
486 if not timing:
487 timing = Timing(threaded_name)
488 timing_info[threaded_name] = timing
489 return timing
490
491def TimingStart(name):
492 """Start the timer for an operation
493
494 Args:
495 name: Operation name to start
496 """
497 timing = GetTiming(name)
498 timing.start = time.monotonic()
499
500def TimingAccum(name):
501 """Stop and accumlate the time for an operation
502
503 This measures the time since the last TimingStart() and adds that to the
504 accumulated time.
505
506 Args:
507 name: Operation name to start
508 """
509 timing = GetTiming(name)
510 timing.accum += time.monotonic() - timing.start
511
512def TimingShow():
513 """Show all timing information"""
514 duration = defaultdict(float)
515 for threaded_name, timing in timing_info.items():
516 name = threaded_name.split(':')[0]
517 duration[name] += timing.accum
518
519 for name, seconds in duration.items():
520 print('%10s: %10.1fms' % (name, seconds * 1000))
Simon Glass88e04da2021-11-23 11:03:42 -0700521
522def GetVersion(path=OUR_PATH):
523 """Get the version string for binman
524
525 Args:
526 path: Path to 'version' file
527
528 Returns:
529 str: String version, e.g. 'v2021.10'
530 """
531 version_fname = os.path.join(path, 'version')
532 if os.path.exists(version_fname):
Simon Glass80025522022-01-29 14:14:04 -0700533 version = tools.read_file(version_fname, binary=False)
Simon Glass88e04da2021-11-23 11:03:42 -0700534 else:
535 version = '(unreleased)'
536 return version