blob: 34907d9d43cc03762c0bfbbe88d66f8b544c015b [file] [log] [blame]
Simon Glassc55a50f2018-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 Glasse0e5df92018-09-14 04:57:31 -06008import hashlib
Simon Glassc55a50f2018-09-14 04:57:19 -06009import re
Simon Glassc55a50f2018-09-14 04:57:19 -060010
11import os
12import tools
13
Simon Glassfb5e8b12019-07-20 12:23:32 -060014# Records the device-tree files known to binman, keyed by entry type (e.g.
15# 'u-boot-spl-dtb'). These are the output FDT files, which can be updated by
16# binman. They have been copied to <xxx>.out files.
17#
18# key: entry type
19# value: tuple:
20# Fdt object
21# Filename
Simon Glass6ca0dcb2019-07-20 12:23:43 -060022# Entry object, or None if not known
23output_fdt_info = {}
Simon Glassc55a50f2018-09-14 04:57:19 -060024
25# Arguments passed to binman to provide arguments to entries
26entry_args = {}
27
Simon Glass539aece2018-09-14 04:57:22 -060028# True to use fake device-tree files for testing (see U_BOOT_DTB_DATA in
29# ftest.py)
Simon Glass93d17412018-09-14 04:57:23 -060030use_fake_dtb = False
Simon Glass539aece2018-09-14 04:57:22 -060031
Simon Glass2a72cc72018-09-14 04:57:20 -060032# The DTB which contains the full image information
33main_dtb = None
34
Simon Glassbf6906b2019-07-08 14:25:36 -060035# Allow entries to expand after they have been packed. This is detected and
36# forces a re-pack. If not allowed, any attempted expansion causes an error in
37# Entry.ProcessContentsUpdate()
38allow_entry_expansion = True
39
Simon Glassfb5e8b12019-07-20 12:23:32 -060040def GetFdtForEtype(etype):
41 """Get the Fdt object for a particular device-tree entry
Simon Glassc55a50f2018-09-14 04:57:19 -060042
43 Binman keeps track of at least one device-tree file called u-boot.dtb but
44 can also have others (e.g. for SPL). This function looks up the given
Simon Glassfb5e8b12019-07-20 12:23:32 -060045 entry and returns the associated Fdt object.
Simon Glassc55a50f2018-09-14 04:57:19 -060046
47 Args:
Simon Glassfb5e8b12019-07-20 12:23:32 -060048 etype: Entry type of device tree (e.g. 'u-boot-dtb')
Simon Glassc55a50f2018-09-14 04:57:19 -060049
50 Returns:
Simon Glassfb5e8b12019-07-20 12:23:32 -060051 Fdt object associated with the entry type
Simon Glassc55a50f2018-09-14 04:57:19 -060052 """
Simon Glass6ca0dcb2019-07-20 12:23:43 -060053 value = output_fdt_info.get(etype);
Simon Glass6a3b5b52019-07-20 12:23:42 -060054 if not value:
55 return None
56 return value[0]
Simon Glassc55a50f2018-09-14 04:57:19 -060057
Simon Glass6ca0dcb2019-07-20 12:23:43 -060058def GetEntryForEtype(etype):
59 """Get the Entry for a particular device-tree filename
60
61 Binman keeps track of at least one device-tree file called u-boot.dtb but
62 can also have others (e.g. for SPL). This function looks up the given
63 filename and returns the associated Fdt object.
64
65 Args:
66 etype: Entry type of device tree (e.g. 'u-boot-dtb')
67
68 Returns:
69 Entry object associated with the entry type, if present in the image
70 """
71 value = output_fdt_info.get(etype);
72 if not value:
73 return None
74 return value[2]
75
Simon Glassfb5e8b12019-07-20 12:23:32 -060076def GetFdtPath(etype):
Simon Glassc55a50f2018-09-14 04:57:19 -060077 """Get the full pathname of a particular Fdt object
78
Simon Glass726e2962019-07-20 12:23:30 -060079 Similar to GetFdtForEtype() but returns the pathname associated with the
80 Fdt.
Simon Glassc55a50f2018-09-14 04:57:19 -060081
82 Args:
Simon Glassfb5e8b12019-07-20 12:23:32 -060083 etype: Entry type of device tree (e.g. 'u-boot-dtb')
Simon Glassc55a50f2018-09-14 04:57:19 -060084
85 Returns:
86 Full path name to the associated Fdt
87 """
Simon Glass6ca0dcb2019-07-20 12:23:43 -060088 return output_fdt_info[etype][0]._fname
Simon Glassc55a50f2018-09-14 04:57:19 -060089
Simon Glassfb5e8b12019-07-20 12:23:32 -060090def GetFdtContents(etype='u-boot-dtb'):
Simon Glass6ed45ba2018-09-14 04:57:24 -060091 """Looks up the FDT pathname and contents
92
93 This is used to obtain the Fdt pathname and contents when needed by an
94 entry. It supports a 'fake' dtb, allowing tests to substitute test data for
95 the real dtb.
96
97 Args:
Simon Glassfb5e8b12019-07-20 12:23:32 -060098 etype: Entry type to look up (e.g. 'u-boot.dtb').
Simon Glass6ed45ba2018-09-14 04:57:24 -060099
100 Returns:
101 tuple:
102 pathname to Fdt
103 Fdt data (as bytes)
104 """
Simon Glass6ca0dcb2019-07-20 12:23:43 -0600105 if etype not in output_fdt_info:
Simon Glass6a3b5b52019-07-20 12:23:42 -0600106 return None, None
107 if not use_fake_dtb:
Simon Glassfb5e8b12019-07-20 12:23:32 -0600108 pathname = GetFdtPath(etype)
109 data = GetFdtForEtype(etype).GetContents()
Simon Glass6ed45ba2018-09-14 04:57:24 -0600110 else:
Simon Glass6ca0dcb2019-07-20 12:23:43 -0600111 fname = output_fdt_info[etype][1]
Simon Glass6ed45ba2018-09-14 04:57:24 -0600112 pathname = tools.GetInputFilename(fname)
113 data = tools.ReadFile(pathname)
114 return pathname, data
115
Simon Glassc55a50f2018-09-14 04:57:19 -0600116def SetEntryArgs(args):
117 """Set the value of the entry args
118
119 This sets up the entry_args dict which is used to supply entry arguments to
120 entries.
121
122 Args:
123 args: List of entry arguments, each in the format "name=value"
124 """
125 global entry_args
126
127 entry_args = {}
128 if args:
129 for arg in args:
130 m = re.match('([^=]*)=(.*)', arg)
131 if not m:
132 raise ValueError("Invalid entry arguemnt '%s'" % arg)
133 entry_args[m.group(1)] = m.group(2)
134
135def GetEntryArg(name):
136 """Get the value of an entry argument
137
138 Args:
139 name: Name of argument to retrieve
140
141 Returns:
142 String value of argument
143 """
144 return entry_args.get(name)
Simon Glass2a72cc72018-09-14 04:57:20 -0600145
Simon Glass539aece2018-09-14 04:57:22 -0600146def Prepare(images, dtb):
Simon Glass2a72cc72018-09-14 04:57:20 -0600147 """Get device tree files ready for use
148
Simon Glass4bdd1152019-07-20 12:23:29 -0600149 This sets up a set of device tree files that can be retrieved by
150 GetAllFdts(). This includes U-Boot proper and any SPL device trees.
Simon Glass2a72cc72018-09-14 04:57:20 -0600151
152 Args:
Simon Glass539aece2018-09-14 04:57:22 -0600153 images: List of images being used
Simon Glass2a72cc72018-09-14 04:57:20 -0600154 dtb: Main dtb
155 """
Simon Glass6ca0dcb2019-07-20 12:23:43 -0600156 global output_fdt_info, main_dtb
Simon Glass2a72cc72018-09-14 04:57:20 -0600157 # Import these here in case libfdt.py is not available, in which case
158 # the above help option still works.
159 import fdt
160 import fdt_util
161
162 # If we are updating the DTBs we need to put these updated versions
163 # where Entry_blob_dtb can find them. We can ignore 'u-boot.dtb'
164 # since it is assumed to be the one passed in with options.dt, and
165 # was handled just above.
166 main_dtb = dtb
Simon Glass6ca0dcb2019-07-20 12:23:43 -0600167 output_fdt_info.clear()
168 output_fdt_info['u-boot-dtb'] = [dtb, 'u-boot.dtb', None]
169 output_fdt_info['u-boot-spl-dtb'] = [dtb, 'spl/u-boot-spl.dtb', None]
170 output_fdt_info['u-boot-tpl-dtb'] = [dtb, 'tpl/u-boot-tpl.dtb', None]
Simon Glass539aece2018-09-14 04:57:22 -0600171 if not use_fake_dtb:
Simon Glassf49462e2019-07-20 12:23:34 -0600172 fdt_set = {}
Simon Glass539aece2018-09-14 04:57:22 -0600173 for image in images.values():
Simon Glass77e4ef12019-07-20 12:23:33 -0600174 fdt_set.update(image.GetFdts())
175 for etype, other in fdt_set.items():
Simon Glass6ca0dcb2019-07-20 12:23:43 -0600176 entry, other_fname = other
Simon Glass539aece2018-09-14 04:57:22 -0600177 infile = tools.GetInputFilename(other_fname)
178 other_fname_dtb = fdt_util.EnsureCompiled(infile)
179 out_fname = tools.GetOutputFilename('%s.out' %
180 os.path.split(other_fname)[1])
181 tools.WriteFile(out_fname, tools.ReadFile(other_fname_dtb))
182 other_dtb = fdt.FdtScan(out_fname)
Simon Glass6ca0dcb2019-07-20 12:23:43 -0600183 output_fdt_info[etype] = [other_dtb, out_fname, entry]
Simon Glass2a72cc72018-09-14 04:57:20 -0600184
Simon Glass4bdd1152019-07-20 12:23:29 -0600185def GetAllFdts():
Simon Glass2a72cc72018-09-14 04:57:20 -0600186 """Yield all device tree files being used by binman
187
188 Yields:
189 Device trees being used (U-Boot proper, SPL, TPL)
190 """
191 yield main_dtb
Simon Glass6ca0dcb2019-07-20 12:23:43 -0600192 for etype in output_fdt_info:
193 dtb = output_fdt_info[etype][0]
Simon Glass77e4ef12019-07-20 12:23:33 -0600194 if dtb != main_dtb:
195 yield dtb
Simon Glass2a72cc72018-09-14 04:57:20 -0600196
Simon Glassf46621d2018-09-14 04:57:21 -0600197def GetUpdateNodes(node):
198 """Yield all the nodes that need to be updated in all device trees
199
200 The property referenced by this node is added to any device trees which
201 have the given node. Due to removable of unwanted notes, SPL and TPL may
202 not have this node.
203
204 Args:
205 node: Node object in the main device tree to look up
206
207 Yields:
208 Node objects in each device tree that is in use (U-Boot proper, which
209 is node, SPL and TPL)
210 """
211 yield node
Simon Glass6ca0dcb2019-07-20 12:23:43 -0600212 for dtb, fname, _ in output_fdt_info.values():
Simon Glass6ed45ba2018-09-14 04:57:24 -0600213 if dtb != node.GetFdt():
214 other_node = dtb.GetNode(node.path)
215 if other_node:
216 yield other_node
Simon Glassf46621d2018-09-14 04:57:21 -0600217
218def AddZeroProp(node, prop):
219 """Add a new property to affected device trees with an integer value of 0.
220
221 Args:
222 prop_name: Name of property
223 """
224 for n in GetUpdateNodes(node):
225 n.AddZeroProp(prop)
226
Simon Glass0a98b282018-09-14 04:57:28 -0600227def AddSubnode(node, name):
228 """Add a new subnode to a node in affected device trees
229
230 Args:
231 node: Node to add to
232 name: name of node to add
233
234 Returns:
235 New subnode that was created in main tree
236 """
237 first = None
238 for n in GetUpdateNodes(node):
239 subnode = n.AddSubnode(name)
240 if not first:
241 first = subnode
242 return first
243
244def AddString(node, prop, value):
245 """Add a new string property to affected device trees
246
247 Args:
248 prop_name: Name of property
249 value: String value (which will be \0-terminated in the DT)
250 """
251 for n in GetUpdateNodes(node):
252 n.AddString(prop, value)
253
Simon Glassf46621d2018-09-14 04:57:21 -0600254def SetInt(node, prop, value):
255 """Update an integer property in affected device trees with an integer value
256
257 This is not allowed to change the size of the FDT.
258
259 Args:
260 prop_name: Name of property
261 """
262 for n in GetUpdateNodes(node):
263 n.SetInt(prop, value)
Simon Glasse0e5df92018-09-14 04:57:31 -0600264
265def CheckAddHashProp(node):
266 hash_node = node.FindNode('hash')
267 if hash_node:
268 algo = hash_node.props.get('algo')
269 if not algo:
270 return "Missing 'algo' property for hash node"
271 if algo.value == 'sha256':
272 size = 32
273 else:
274 return "Unknown hash algorithm '%s'" % algo
275 for n in GetUpdateNodes(hash_node):
276 n.AddEmptyProp('value', size)
277
278def CheckSetHashValue(node, get_data_func):
279 hash_node = node.FindNode('hash')
280 if hash_node:
281 algo = hash_node.props.get('algo').value
282 if algo == 'sha256':
283 m = hashlib.sha256()
284 m.update(get_data_func())
285 data = m.digest()
286 for n in GetUpdateNodes(hash_node):
287 n.SetData('value', data)
Simon Glassbf6906b2019-07-08 14:25:36 -0600288
289def SetAllowEntryExpansion(allow):
290 """Set whether post-pack expansion of entries is allowed
291
292 Args:
293 allow: True to allow expansion, False to raise an exception
294 """
295 global allow_entry_expansion
296
297 allow_entry_expansion = allow
298
299def AllowEntryExpansion():
300 """Check whether post-pack expansion of entries is allowed
301
302 Returns:
303 True if expansion should be allowed, False if an exception should be
304 raised
305 """
306 return allow_entry_expansion