blob: 87674100665d9365d134b57fb56916cb065a03ca [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 Glass2a72cc72018-09-14 04:57:20 -060031# The DTB which contains the full image information
32main_dtb = None
33
Simon Glassbf6906b2019-07-08 14:25:36 -060034# Allow entries to expand after they have been packed. This is detected and
35# forces a re-pack. If not allowed, any attempted expansion causes an error in
36# Entry.ProcessContentsUpdate()
37allow_entry_expansion = True
38
Simon Glassfb5e8b12019-07-20 12:23:32 -060039def GetFdtForEtype(etype):
40 """Get the Fdt object for a particular device-tree entry
Simon Glassc55a50f2018-09-14 04:57:19 -060041
42 Binman keeps track of at least one device-tree file called u-boot.dtb but
43 can also have others (e.g. for SPL). This function looks up the given
Simon Glassfb5e8b12019-07-20 12:23:32 -060044 entry and returns the associated Fdt object.
Simon Glassc55a50f2018-09-14 04:57:19 -060045
46 Args:
Simon Glassfb5e8b12019-07-20 12:23:32 -060047 etype: Entry type of device tree (e.g. 'u-boot-dtb')
Simon Glassc55a50f2018-09-14 04:57:19 -060048
49 Returns:
Simon Glassfb5e8b12019-07-20 12:23:32 -060050 Fdt object associated with the entry type
Simon Glassc55a50f2018-09-14 04:57:19 -060051 """
Simon Glass6a3b5b52019-07-20 12:23:42 -060052 value = output_fdt_files.get(etype);
53 if not value:
54 return None
55 return value[0]
Simon Glassc55a50f2018-09-14 04:57:19 -060056
Simon Glassfb5e8b12019-07-20 12:23:32 -060057def GetFdtPath(etype):
Simon Glassc55a50f2018-09-14 04:57:19 -060058 """Get the full pathname of a particular Fdt object
59
Simon Glass726e2962019-07-20 12:23:30 -060060 Similar to GetFdtForEtype() but returns the pathname associated with the
61 Fdt.
Simon Glassc55a50f2018-09-14 04:57:19 -060062
63 Args:
Simon Glassfb5e8b12019-07-20 12:23:32 -060064 etype: Entry type of device tree (e.g. 'u-boot-dtb')
Simon Glassc55a50f2018-09-14 04:57:19 -060065
66 Returns:
67 Full path name to the associated Fdt
68 """
Simon Glassfb5e8b12019-07-20 12:23:32 -060069 return output_fdt_files[etype][0]._fname
Simon Glassc55a50f2018-09-14 04:57:19 -060070
Simon Glassfb5e8b12019-07-20 12:23:32 -060071def GetFdtContents(etype='u-boot-dtb'):
Simon Glass6ed45ba2018-09-14 04:57:24 -060072 """Looks up the FDT pathname and contents
73
74 This is used to obtain the Fdt pathname and contents when needed by an
75 entry. It supports a 'fake' dtb, allowing tests to substitute test data for
76 the real dtb.
77
78 Args:
Simon Glassfb5e8b12019-07-20 12:23:32 -060079 etype: Entry type to look up (e.g. 'u-boot.dtb').
Simon Glass6ed45ba2018-09-14 04:57:24 -060080
81 Returns:
82 tuple:
83 pathname to Fdt
84 Fdt data (as bytes)
85 """
Simon Glass6a3b5b52019-07-20 12:23:42 -060086 if etype not in output_fdt_files:
87 return None, None
88 if not use_fake_dtb:
Simon Glassfb5e8b12019-07-20 12:23:32 -060089 pathname = GetFdtPath(etype)
90 data = GetFdtForEtype(etype).GetContents()
Simon Glass6ed45ba2018-09-14 04:57:24 -060091 else:
Simon Glassfb5e8b12019-07-20 12:23:32 -060092 fname = output_fdt_files[etype][1]
Simon Glass6ed45ba2018-09-14 04:57:24 -060093 pathname = tools.GetInputFilename(fname)
94 data = tools.ReadFile(pathname)
95 return pathname, data
96
Simon Glassc55a50f2018-09-14 04:57:19 -060097def SetEntryArgs(args):
98 """Set the value of the entry args
99
100 This sets up the entry_args dict which is used to supply entry arguments to
101 entries.
102
103 Args:
104 args: List of entry arguments, each in the format "name=value"
105 """
106 global entry_args
107
108 entry_args = {}
109 if args:
110 for arg in args:
111 m = re.match('([^=]*)=(.*)', arg)
112 if not m:
113 raise ValueError("Invalid entry arguemnt '%s'" % arg)
114 entry_args[m.group(1)] = m.group(2)
115
116def GetEntryArg(name):
117 """Get the value of an entry argument
118
119 Args:
120 name: Name of argument to retrieve
121
122 Returns:
123 String value of argument
124 """
125 return entry_args.get(name)
Simon Glass2a72cc72018-09-14 04:57:20 -0600126
Simon Glass539aece2018-09-14 04:57:22 -0600127def Prepare(images, dtb):
Simon Glass2a72cc72018-09-14 04:57:20 -0600128 """Get device tree files ready for use
129
Simon Glass4bdd1152019-07-20 12:23:29 -0600130 This sets up a set of device tree files that can be retrieved by
131 GetAllFdts(). This includes U-Boot proper and any SPL device trees.
Simon Glass2a72cc72018-09-14 04:57:20 -0600132
133 Args:
Simon Glass539aece2018-09-14 04:57:22 -0600134 images: List of images being used
Simon Glass2a72cc72018-09-14 04:57:20 -0600135 dtb: Main dtb
136 """
Simon Glassf49462e2019-07-20 12:23:34 -0600137 global output_fdt_files, main_dtb
Simon Glass2a72cc72018-09-14 04:57:20 -0600138 # Import these here in case libfdt.py is not available, in which case
139 # the above help option still works.
140 import fdt
141 import fdt_util
142
143 # If we are updating the DTBs we need to put these updated versions
144 # where Entry_blob_dtb can find them. We can ignore 'u-boot.dtb'
145 # since it is assumed to be the one passed in with options.dt, and
146 # was handled just above.
147 main_dtb = dtb
Simon Glassfb5e8b12019-07-20 12:23:32 -0600148 output_fdt_files.clear()
149 output_fdt_files['u-boot-dtb'] = [dtb, 'u-boot.dtb']
150 output_fdt_files['u-boot-spl-dtb'] = [dtb, 'spl/u-boot-spl.dtb']
151 output_fdt_files['u-boot-tpl-dtb'] = [dtb, 'tpl/u-boot-tpl.dtb']
Simon Glass539aece2018-09-14 04:57:22 -0600152 if not use_fake_dtb:
Simon Glassf49462e2019-07-20 12:23:34 -0600153 fdt_set = {}
Simon Glass539aece2018-09-14 04:57:22 -0600154 for image in images.values():
Simon Glass77e4ef12019-07-20 12:23:33 -0600155 fdt_set.update(image.GetFdts())
156 for etype, other in fdt_set.items():
Simon Glass4bdd3002019-07-20 12:23:31 -0600157 _, other_fname = other
Simon Glass539aece2018-09-14 04:57:22 -0600158 infile = tools.GetInputFilename(other_fname)
159 other_fname_dtb = fdt_util.EnsureCompiled(infile)
160 out_fname = tools.GetOutputFilename('%s.out' %
161 os.path.split(other_fname)[1])
162 tools.WriteFile(out_fname, tools.ReadFile(other_fname_dtb))
163 other_dtb = fdt.FdtScan(out_fname)
Simon Glassfb5e8b12019-07-20 12:23:32 -0600164 output_fdt_files[etype] = [other_dtb, other_fname]
Simon Glass2a72cc72018-09-14 04:57:20 -0600165
Simon Glass4bdd1152019-07-20 12:23:29 -0600166def GetAllFdts():
Simon Glass2a72cc72018-09-14 04:57:20 -0600167 """Yield all device tree files being used by binman
168
169 Yields:
170 Device trees being used (U-Boot proper, SPL, TPL)
171 """
172 yield main_dtb
Simon Glassf49462e2019-07-20 12:23:34 -0600173 for etype in output_fdt_files:
Simon Glass77e4ef12019-07-20 12:23:33 -0600174 dtb = output_fdt_files[etype][0]
175 if dtb != main_dtb:
176 yield dtb
Simon Glass2a72cc72018-09-14 04:57:20 -0600177
Simon Glassf46621d2018-09-14 04:57:21 -0600178def GetUpdateNodes(node):
179 """Yield all the nodes that need to be updated in all device trees
180
181 The property referenced by this node is added to any device trees which
182 have the given node. Due to removable of unwanted notes, SPL and TPL may
183 not have this node.
184
185 Args:
186 node: Node object in the main device tree to look up
187
188 Yields:
189 Node objects in each device tree that is in use (U-Boot proper, which
190 is node, SPL and TPL)
191 """
192 yield node
Simon Glassfb5e8b12019-07-20 12:23:32 -0600193 for dtb, fname in output_fdt_files.values():
Simon Glass6ed45ba2018-09-14 04:57:24 -0600194 if dtb != node.GetFdt():
195 other_node = dtb.GetNode(node.path)
196 if other_node:
197 yield other_node
Simon Glassf46621d2018-09-14 04:57:21 -0600198
199def AddZeroProp(node, prop):
200 """Add a new property to affected device trees with an integer value of 0.
201
202 Args:
203 prop_name: Name of property
204 """
205 for n in GetUpdateNodes(node):
206 n.AddZeroProp(prop)
207
Simon Glass0a98b282018-09-14 04:57:28 -0600208def AddSubnode(node, name):
209 """Add a new subnode to a node in affected device trees
210
211 Args:
212 node: Node to add to
213 name: name of node to add
214
215 Returns:
216 New subnode that was created in main tree
217 """
218 first = None
219 for n in GetUpdateNodes(node):
220 subnode = n.AddSubnode(name)
221 if not first:
222 first = subnode
223 return first
224
225def AddString(node, prop, value):
226 """Add a new string property to affected device trees
227
228 Args:
229 prop_name: Name of property
230 value: String value (which will be \0-terminated in the DT)
231 """
232 for n in GetUpdateNodes(node):
233 n.AddString(prop, value)
234
Simon Glassf46621d2018-09-14 04:57:21 -0600235def SetInt(node, prop, value):
236 """Update an integer property in affected device trees with an integer value
237
238 This is not allowed to change the size of the FDT.
239
240 Args:
241 prop_name: Name of property
242 """
243 for n in GetUpdateNodes(node):
244 n.SetInt(prop, value)
Simon Glasse0e5df92018-09-14 04:57:31 -0600245
246def CheckAddHashProp(node):
247 hash_node = node.FindNode('hash')
248 if hash_node:
249 algo = hash_node.props.get('algo')
250 if not algo:
251 return "Missing 'algo' property for hash node"
252 if algo.value == 'sha256':
253 size = 32
254 else:
255 return "Unknown hash algorithm '%s'" % algo
256 for n in GetUpdateNodes(hash_node):
257 n.AddEmptyProp('value', size)
258
259def CheckSetHashValue(node, get_data_func):
260 hash_node = node.FindNode('hash')
261 if hash_node:
262 algo = hash_node.props.get('algo').value
263 if algo == 'sha256':
264 m = hashlib.sha256()
265 m.update(get_data_func())
266 data = m.digest()
267 for n in GetUpdateNodes(hash_node):
268 n.SetData('value', data)
Simon Glassbf6906b2019-07-08 14:25:36 -0600269
270def SetAllowEntryExpansion(allow):
271 """Set whether post-pack expansion of entries is allowed
272
273 Args:
274 allow: True to allow expansion, False to raise an exception
275 """
276 global allow_entry_expansion
277
278 allow_entry_expansion = allow
279
280def AllowEntryExpansion():
281 """Check whether post-pack expansion of entries is allowed
282
283 Returns:
284 True if expansion should be allowed, False if an exception should be
285 raised
286 """
287 return allow_entry_expansion