blob: 0278f87df22d51a08e746369811940d82c8b4d61 [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
22output_fdt_files = {}
Simon Glassc55a50f2018-09-14 04:57:19 -060023
24# Arguments passed to binman to provide arguments to entries
25entry_args = {}
26
Simon Glass539aece2018-09-14 04:57:22 -060027# True to use fake device-tree files for testing (see U_BOOT_DTB_DATA in
28# ftest.py)
Simon Glass93d17412018-09-14 04:57:23 -060029use_fake_dtb = False
Simon Glass539aece2018-09-14 04:57:22 -060030
Simon Glass4bdd3002019-07-20 12:23:31 -060031# Dict of device trees, keyed by entry type, but excluding the main one
32# The value is as returned by Entry.GetFdts(), i.e. a tuple:
33# Fdt object for this dtb, or None if not available
34# Filename of file containing this dtb
Simon Glassa8adb6d2019-07-20 12:23:28 -060035fdt_subset = {}
Simon Glass2a72cc72018-09-14 04:57:20 -060036
37# The DTB which contains the full image information
38main_dtb = None
39
Simon Glassbf6906b2019-07-08 14:25:36 -060040# Allow entries to expand after they have been packed. This is detected and
41# forces a re-pack. If not allowed, any attempted expansion causes an error in
42# Entry.ProcessContentsUpdate()
43allow_entry_expansion = True
44
Simon Glassfb5e8b12019-07-20 12:23:32 -060045def GetFdtForEtype(etype):
46 """Get the Fdt object for a particular device-tree entry
Simon Glassc55a50f2018-09-14 04:57:19 -060047
48 Binman keeps track of at least one device-tree file called u-boot.dtb but
49 can also have others (e.g. for SPL). This function looks up the given
Simon Glassfb5e8b12019-07-20 12:23:32 -060050 entry and returns the associated Fdt object.
Simon Glassc55a50f2018-09-14 04:57:19 -060051
52 Args:
Simon Glassfb5e8b12019-07-20 12:23:32 -060053 etype: Entry type of device tree (e.g. 'u-boot-dtb')
Simon Glassc55a50f2018-09-14 04:57:19 -060054
55 Returns:
Simon Glassfb5e8b12019-07-20 12:23:32 -060056 Fdt object associated with the entry type
Simon Glassc55a50f2018-09-14 04:57:19 -060057 """
Simon Glassfb5e8b12019-07-20 12:23:32 -060058 return output_fdt_files[etype][0]
Simon Glassc55a50f2018-09-14 04:57:19 -060059
Simon Glassfb5e8b12019-07-20 12:23:32 -060060def GetFdtPath(etype):
Simon Glassc55a50f2018-09-14 04:57:19 -060061 """Get the full pathname of a particular Fdt object
62
Simon Glass726e2962019-07-20 12:23:30 -060063 Similar to GetFdtForEtype() but returns the pathname associated with the
64 Fdt.
Simon Glassc55a50f2018-09-14 04:57:19 -060065
66 Args:
Simon Glassfb5e8b12019-07-20 12:23:32 -060067 etype: Entry type of device tree (e.g. 'u-boot-dtb')
Simon Glassc55a50f2018-09-14 04:57:19 -060068
69 Returns:
70 Full path name to the associated Fdt
71 """
Simon Glassfb5e8b12019-07-20 12:23:32 -060072 return output_fdt_files[etype][0]._fname
Simon Glassc55a50f2018-09-14 04:57:19 -060073
Simon Glassfb5e8b12019-07-20 12:23:32 -060074def GetFdtContents(etype='u-boot-dtb'):
Simon Glass6ed45ba2018-09-14 04:57:24 -060075 """Looks up the FDT pathname and contents
76
77 This is used to obtain the Fdt pathname and contents when needed by an
78 entry. It supports a 'fake' dtb, allowing tests to substitute test data for
79 the real dtb.
80
81 Args:
Simon Glassfb5e8b12019-07-20 12:23:32 -060082 etype: Entry type to look up (e.g. 'u-boot.dtb').
Simon Glass6ed45ba2018-09-14 04:57:24 -060083
84 Returns:
85 tuple:
86 pathname to Fdt
87 Fdt data (as bytes)
88 """
Simon Glassfb5e8b12019-07-20 12:23:32 -060089 if etype in output_fdt_files and not use_fake_dtb:
90 pathname = GetFdtPath(etype)
91 data = GetFdtForEtype(etype).GetContents()
Simon Glass6ed45ba2018-09-14 04:57:24 -060092 else:
Simon Glassfb5e8b12019-07-20 12:23:32 -060093 fname = output_fdt_files[etype][1]
Simon Glass6ed45ba2018-09-14 04:57:24 -060094 pathname = tools.GetInputFilename(fname)
95 data = tools.ReadFile(pathname)
96 return pathname, data
97
Simon Glassc55a50f2018-09-14 04:57:19 -060098def SetEntryArgs(args):
99 """Set the value of the entry args
100
101 This sets up the entry_args dict which is used to supply entry arguments to
102 entries.
103
104 Args:
105 args: List of entry arguments, each in the format "name=value"
106 """
107 global entry_args
108
109 entry_args = {}
110 if args:
111 for arg in args:
112 m = re.match('([^=]*)=(.*)', arg)
113 if not m:
114 raise ValueError("Invalid entry arguemnt '%s'" % arg)
115 entry_args[m.group(1)] = m.group(2)
116
117def GetEntryArg(name):
118 """Get the value of an entry argument
119
120 Args:
121 name: Name of argument to retrieve
122
123 Returns:
124 String value of argument
125 """
126 return entry_args.get(name)
Simon Glass2a72cc72018-09-14 04:57:20 -0600127
Simon Glass539aece2018-09-14 04:57:22 -0600128def Prepare(images, dtb):
Simon Glass2a72cc72018-09-14 04:57:20 -0600129 """Get device tree files ready for use
130
Simon Glass4bdd1152019-07-20 12:23:29 -0600131 This sets up a set of device tree files that can be retrieved by
132 GetAllFdts(). This includes U-Boot proper and any SPL device trees.
Simon Glass2a72cc72018-09-14 04:57:20 -0600133
134 Args:
Simon Glass539aece2018-09-14 04:57:22 -0600135 images: List of images being used
Simon Glass2a72cc72018-09-14 04:57:20 -0600136 dtb: Main dtb
137 """
Simon Glassfb5e8b12019-07-20 12:23:32 -0600138 global fdt_set, fdt_subset, output_fdt_files, main_dtb
Simon Glass2a72cc72018-09-14 04:57:20 -0600139 # Import these here in case libfdt.py is not available, in which case
140 # the above help option still works.
141 import fdt
142 import fdt_util
143
144 # If we are updating the DTBs we need to put these updated versions
145 # where Entry_blob_dtb can find them. We can ignore 'u-boot.dtb'
146 # since it is assumed to be the one passed in with options.dt, and
147 # was handled just above.
148 main_dtb = dtb
Simon Glassfb5e8b12019-07-20 12:23:32 -0600149 output_fdt_files.clear()
150 output_fdt_files['u-boot-dtb'] = [dtb, 'u-boot.dtb']
151 output_fdt_files['u-boot-spl-dtb'] = [dtb, 'spl/u-boot-spl.dtb']
152 output_fdt_files['u-boot-tpl-dtb'] = [dtb, 'tpl/u-boot-tpl.dtb']
Simon Glassa8adb6d2019-07-20 12:23:28 -0600153 fdt_subset = {}
Simon Glass539aece2018-09-14 04:57:22 -0600154 if not use_fake_dtb:
155 for image in images.values():
Simon Glassa8adb6d2019-07-20 12:23:28 -0600156 fdt_subset.update(image.GetFdts())
Simon Glass4bdd3002019-07-20 12:23:31 -0600157 if 'u-boot-dtb' in fdt_subset:
158 del fdt_subset['u-boot-dtb']
159 for etype, other in fdt_subset.items():
160 _, other_fname = other
Simon Glass539aece2018-09-14 04:57:22 -0600161 infile = tools.GetInputFilename(other_fname)
162 other_fname_dtb = fdt_util.EnsureCompiled(infile)
163 out_fname = tools.GetOutputFilename('%s.out' %
164 os.path.split(other_fname)[1])
165 tools.WriteFile(out_fname, tools.ReadFile(other_fname_dtb))
166 other_dtb = fdt.FdtScan(out_fname)
Simon Glassfb5e8b12019-07-20 12:23:32 -0600167 output_fdt_files[etype] = [other_dtb, other_fname]
Simon Glass2a72cc72018-09-14 04:57:20 -0600168
Simon Glass4bdd1152019-07-20 12:23:29 -0600169def GetAllFdts():
Simon Glass2a72cc72018-09-14 04:57:20 -0600170 """Yield all device tree files being used by binman
171
172 Yields:
173 Device trees being used (U-Boot proper, SPL, TPL)
174 """
175 yield main_dtb
Simon Glassfb5e8b12019-07-20 12:23:32 -0600176 for etype in fdt_subset:
177 yield output_fdt_files[etype][0]
Simon Glass2a72cc72018-09-14 04:57:20 -0600178
Simon Glassf46621d2018-09-14 04:57:21 -0600179def GetUpdateNodes(node):
180 """Yield all the nodes that need to be updated in all device trees
181
182 The property referenced by this node is added to any device trees which
183 have the given node. Due to removable of unwanted notes, SPL and TPL may
184 not have this node.
185
186 Args:
187 node: Node object in the main device tree to look up
188
189 Yields:
190 Node objects in each device tree that is in use (U-Boot proper, which
191 is node, SPL and TPL)
192 """
193 yield node
Simon Glassfb5e8b12019-07-20 12:23:32 -0600194 for dtb, fname in output_fdt_files.values():
Simon Glass6ed45ba2018-09-14 04:57:24 -0600195 if dtb != node.GetFdt():
196 other_node = dtb.GetNode(node.path)
197 if other_node:
198 yield other_node
Simon Glassf46621d2018-09-14 04:57:21 -0600199
200def AddZeroProp(node, prop):
201 """Add a new property to affected device trees with an integer value of 0.
202
203 Args:
204 prop_name: Name of property
205 """
206 for n in GetUpdateNodes(node):
207 n.AddZeroProp(prop)
208
Simon Glass0a98b282018-09-14 04:57:28 -0600209def AddSubnode(node, name):
210 """Add a new subnode to a node in affected device trees
211
212 Args:
213 node: Node to add to
214 name: name of node to add
215
216 Returns:
217 New subnode that was created in main tree
218 """
219 first = None
220 for n in GetUpdateNodes(node):
221 subnode = n.AddSubnode(name)
222 if not first:
223 first = subnode
224 return first
225
226def AddString(node, prop, value):
227 """Add a new string property to affected device trees
228
229 Args:
230 prop_name: Name of property
231 value: String value (which will be \0-terminated in the DT)
232 """
233 for n in GetUpdateNodes(node):
234 n.AddString(prop, value)
235
Simon Glassf46621d2018-09-14 04:57:21 -0600236def SetInt(node, prop, value):
237 """Update an integer property in affected device trees with an integer value
238
239 This is not allowed to change the size of the FDT.
240
241 Args:
242 prop_name: Name of property
243 """
244 for n in GetUpdateNodes(node):
245 n.SetInt(prop, value)
Simon Glasse0e5df92018-09-14 04:57:31 -0600246
247def CheckAddHashProp(node):
248 hash_node = node.FindNode('hash')
249 if hash_node:
250 algo = hash_node.props.get('algo')
251 if not algo:
252 return "Missing 'algo' property for hash node"
253 if algo.value == 'sha256':
254 size = 32
255 else:
256 return "Unknown hash algorithm '%s'" % algo
257 for n in GetUpdateNodes(hash_node):
258 n.AddEmptyProp('value', size)
259
260def CheckSetHashValue(node, get_data_func):
261 hash_node = node.FindNode('hash')
262 if hash_node:
263 algo = hash_node.props.get('algo').value
264 if algo == 'sha256':
265 m = hashlib.sha256()
266 m.update(get_data_func())
267 data = m.digest()
268 for n in GetUpdateNodes(hash_node):
269 n.SetData('value', data)
Simon Glassbf6906b2019-07-08 14:25:36 -0600270
271def SetAllowEntryExpansion(allow):
272 """Set whether post-pack expansion of entries is allowed
273
274 Args:
275 allow: True to allow expansion, False to raise an exception
276 """
277 global allow_entry_expansion
278
279 allow_entry_expansion = allow
280
281def AllowEntryExpansion():
282 """Check whether post-pack expansion of entries is allowed
283
284 Returns:
285 True if expansion should be allowed, False if an exception should be
286 raised
287 """
288 return allow_entry_expansion