blob: 7c3a987723eb5ecd02b1e0d92fbd22d8f9560fd3 [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 Glassfb5e8b12019-07-20 12:23:32 -060052 return output_fdt_files[etype][0]
Simon Glassc55a50f2018-09-14 04:57:19 -060053
Simon Glassfb5e8b12019-07-20 12:23:32 -060054def GetFdtPath(etype):
Simon Glassc55a50f2018-09-14 04:57:19 -060055 """Get the full pathname of a particular Fdt object
56
Simon Glass726e2962019-07-20 12:23:30 -060057 Similar to GetFdtForEtype() but returns the pathname associated with the
58 Fdt.
Simon Glassc55a50f2018-09-14 04:57:19 -060059
60 Args:
Simon Glassfb5e8b12019-07-20 12:23:32 -060061 etype: Entry type of device tree (e.g. 'u-boot-dtb')
Simon Glassc55a50f2018-09-14 04:57:19 -060062
63 Returns:
64 Full path name to the associated Fdt
65 """
Simon Glassfb5e8b12019-07-20 12:23:32 -060066 return output_fdt_files[etype][0]._fname
Simon Glassc55a50f2018-09-14 04:57:19 -060067
Simon Glassfb5e8b12019-07-20 12:23:32 -060068def GetFdtContents(etype='u-boot-dtb'):
Simon Glass6ed45ba2018-09-14 04:57:24 -060069 """Looks up the FDT pathname and contents
70
71 This is used to obtain the Fdt pathname and contents when needed by an
72 entry. It supports a 'fake' dtb, allowing tests to substitute test data for
73 the real dtb.
74
75 Args:
Simon Glassfb5e8b12019-07-20 12:23:32 -060076 etype: Entry type to look up (e.g. 'u-boot.dtb').
Simon Glass6ed45ba2018-09-14 04:57:24 -060077
78 Returns:
79 tuple:
80 pathname to Fdt
81 Fdt data (as bytes)
82 """
Simon Glassfb5e8b12019-07-20 12:23:32 -060083 if etype in output_fdt_files and not use_fake_dtb:
84 pathname = GetFdtPath(etype)
85 data = GetFdtForEtype(etype).GetContents()
Simon Glass6ed45ba2018-09-14 04:57:24 -060086 else:
Simon Glassfb5e8b12019-07-20 12:23:32 -060087 fname = output_fdt_files[etype][1]
Simon Glass6ed45ba2018-09-14 04:57:24 -060088 pathname = tools.GetInputFilename(fname)
89 data = tools.ReadFile(pathname)
90 return pathname, data
91
Simon Glassc55a50f2018-09-14 04:57:19 -060092def SetEntryArgs(args):
93 """Set the value of the entry args
94
95 This sets up the entry_args dict which is used to supply entry arguments to
96 entries.
97
98 Args:
99 args: List of entry arguments, each in the format "name=value"
100 """
101 global entry_args
102
103 entry_args = {}
104 if args:
105 for arg in args:
106 m = re.match('([^=]*)=(.*)', arg)
107 if not m:
108 raise ValueError("Invalid entry arguemnt '%s'" % arg)
109 entry_args[m.group(1)] = m.group(2)
110
111def GetEntryArg(name):
112 """Get the value of an entry argument
113
114 Args:
115 name: Name of argument to retrieve
116
117 Returns:
118 String value of argument
119 """
120 return entry_args.get(name)
Simon Glass2a72cc72018-09-14 04:57:20 -0600121
Simon Glass539aece2018-09-14 04:57:22 -0600122def Prepare(images, dtb):
Simon Glass2a72cc72018-09-14 04:57:20 -0600123 """Get device tree files ready for use
124
Simon Glass4bdd1152019-07-20 12:23:29 -0600125 This sets up a set of device tree files that can be retrieved by
126 GetAllFdts(). This includes U-Boot proper and any SPL device trees.
Simon Glass2a72cc72018-09-14 04:57:20 -0600127
128 Args:
Simon Glass539aece2018-09-14 04:57:22 -0600129 images: List of images being used
Simon Glass2a72cc72018-09-14 04:57:20 -0600130 dtb: Main dtb
131 """
Simon Glassf49462e2019-07-20 12:23:34 -0600132 global output_fdt_files, main_dtb
Simon Glass2a72cc72018-09-14 04:57:20 -0600133 # Import these here in case libfdt.py is not available, in which case
134 # the above help option still works.
135 import fdt
136 import fdt_util
137
138 # If we are updating the DTBs we need to put these updated versions
139 # where Entry_blob_dtb can find them. We can ignore 'u-boot.dtb'
140 # since it is assumed to be the one passed in with options.dt, and
141 # was handled just above.
142 main_dtb = dtb
Simon Glassfb5e8b12019-07-20 12:23:32 -0600143 output_fdt_files.clear()
144 output_fdt_files['u-boot-dtb'] = [dtb, 'u-boot.dtb']
145 output_fdt_files['u-boot-spl-dtb'] = [dtb, 'spl/u-boot-spl.dtb']
146 output_fdt_files['u-boot-tpl-dtb'] = [dtb, 'tpl/u-boot-tpl.dtb']
Simon Glass539aece2018-09-14 04:57:22 -0600147 if not use_fake_dtb:
Simon Glassf49462e2019-07-20 12:23:34 -0600148 fdt_set = {}
Simon Glass539aece2018-09-14 04:57:22 -0600149 for image in images.values():
Simon Glass77e4ef12019-07-20 12:23:33 -0600150 fdt_set.update(image.GetFdts())
151 for etype, other in fdt_set.items():
Simon Glass4bdd3002019-07-20 12:23:31 -0600152 _, other_fname = other
Simon Glass539aece2018-09-14 04:57:22 -0600153 infile = tools.GetInputFilename(other_fname)
154 other_fname_dtb = fdt_util.EnsureCompiled(infile)
155 out_fname = tools.GetOutputFilename('%s.out' %
156 os.path.split(other_fname)[1])
157 tools.WriteFile(out_fname, tools.ReadFile(other_fname_dtb))
158 other_dtb = fdt.FdtScan(out_fname)
Simon Glassfb5e8b12019-07-20 12:23:32 -0600159 output_fdt_files[etype] = [other_dtb, other_fname]
Simon Glass2a72cc72018-09-14 04:57:20 -0600160
Simon Glass4bdd1152019-07-20 12:23:29 -0600161def GetAllFdts():
Simon Glass2a72cc72018-09-14 04:57:20 -0600162 """Yield all device tree files being used by binman
163
164 Yields:
165 Device trees being used (U-Boot proper, SPL, TPL)
166 """
167 yield main_dtb
Simon Glassf49462e2019-07-20 12:23:34 -0600168 for etype in output_fdt_files:
Simon Glass77e4ef12019-07-20 12:23:33 -0600169 dtb = output_fdt_files[etype][0]
170 if dtb != main_dtb:
171 yield dtb
Simon Glass2a72cc72018-09-14 04:57:20 -0600172
Simon Glassf46621d2018-09-14 04:57:21 -0600173def GetUpdateNodes(node):
174 """Yield all the nodes that need to be updated in all device trees
175
176 The property referenced by this node is added to any device trees which
177 have the given node. Due to removable of unwanted notes, SPL and TPL may
178 not have this node.
179
180 Args:
181 node: Node object in the main device tree to look up
182
183 Yields:
184 Node objects in each device tree that is in use (U-Boot proper, which
185 is node, SPL and TPL)
186 """
187 yield node
Simon Glassfb5e8b12019-07-20 12:23:32 -0600188 for dtb, fname in output_fdt_files.values():
Simon Glass6ed45ba2018-09-14 04:57:24 -0600189 if dtb != node.GetFdt():
190 other_node = dtb.GetNode(node.path)
191 if other_node:
192 yield other_node
Simon Glassf46621d2018-09-14 04:57:21 -0600193
194def AddZeroProp(node, prop):
195 """Add a new property to affected device trees with an integer value of 0.
196
197 Args:
198 prop_name: Name of property
199 """
200 for n in GetUpdateNodes(node):
201 n.AddZeroProp(prop)
202
Simon Glass0a98b282018-09-14 04:57:28 -0600203def AddSubnode(node, name):
204 """Add a new subnode to a node in affected device trees
205
206 Args:
207 node: Node to add to
208 name: name of node to add
209
210 Returns:
211 New subnode that was created in main tree
212 """
213 first = None
214 for n in GetUpdateNodes(node):
215 subnode = n.AddSubnode(name)
216 if not first:
217 first = subnode
218 return first
219
220def AddString(node, prop, value):
221 """Add a new string property to affected device trees
222
223 Args:
224 prop_name: Name of property
225 value: String value (which will be \0-terminated in the DT)
226 """
227 for n in GetUpdateNodes(node):
228 n.AddString(prop, value)
229
Simon Glassf46621d2018-09-14 04:57:21 -0600230def SetInt(node, prop, value):
231 """Update an integer property in affected device trees with an integer value
232
233 This is not allowed to change the size of the FDT.
234
235 Args:
236 prop_name: Name of property
237 """
238 for n in GetUpdateNodes(node):
239 n.SetInt(prop, value)
Simon Glasse0e5df92018-09-14 04:57:31 -0600240
241def CheckAddHashProp(node):
242 hash_node = node.FindNode('hash')
243 if hash_node:
244 algo = hash_node.props.get('algo')
245 if not algo:
246 return "Missing 'algo' property for hash node"
247 if algo.value == 'sha256':
248 size = 32
249 else:
250 return "Unknown hash algorithm '%s'" % algo
251 for n in GetUpdateNodes(hash_node):
252 n.AddEmptyProp('value', size)
253
254def CheckSetHashValue(node, get_data_func):
255 hash_node = node.FindNode('hash')
256 if hash_node:
257 algo = hash_node.props.get('algo').value
258 if algo == 'sha256':
259 m = hashlib.sha256()
260 m.update(get_data_func())
261 data = m.digest()
262 for n in GetUpdateNodes(hash_node):
263 n.SetData('value', data)
Simon Glassbf6906b2019-07-08 14:25:36 -0600264
265def SetAllowEntryExpansion(allow):
266 """Set whether post-pack expansion of entries is allowed
267
268 Args:
269 allow: True to allow expansion, False to raise an exception
270 """
271 global allow_entry_expansion
272
273 allow_entry_expansion = allow
274
275def AllowEntryExpansion():
276 """Check whether post-pack expansion of entries is allowed
277
278 Returns:
279 True if expansion should be allowed, False if an exception should be
280 raised
281 """
282 return allow_entry_expansion