blob: 0278f87df22d51a08e746369811940d82c8b4d61 [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 Glassae7cf032018-09-14 04:57:31 -06008import hashlib
Simon Glass29aa7362018-09-14 04:57:19 -06009import re
Simon Glass29aa7362018-09-14 04:57:19 -060010
11import os
12import tools
13
Simon Glass2be381d2019-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 Glass29aa7362018-09-14 04:57:19 -060023
24# Arguments passed to binman to provide arguments to entries
25entry_args = {}
26
Simon Glass0c9d5b52018-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 Glass31402012018-09-14 04:57:23 -060029use_fake_dtb = False
Simon Glass0c9d5b52018-09-14 04:57:22 -060030
Simon Glass684a4f12019-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 Glass267112e2019-07-20 12:23:28 -060035fdt_subset = {}
Simon Glassbdb40312018-09-14 04:57:20 -060036
37# The DTB which contains the full image information
38main_dtb = None
39
Simon Glasscbc80e82019-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 Glass2be381d2019-07-20 12:23:32 -060045def GetFdtForEtype(etype):
46 """Get the Fdt object for a particular device-tree entry
Simon Glass29aa7362018-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 Glass2be381d2019-07-20 12:23:32 -060050 entry and returns the associated Fdt object.
Simon Glass29aa7362018-09-14 04:57:19 -060051
52 Args:
Simon Glass2be381d2019-07-20 12:23:32 -060053 etype: Entry type of device tree (e.g. 'u-boot-dtb')
Simon Glass29aa7362018-09-14 04:57:19 -060054
55 Returns:
Simon Glass2be381d2019-07-20 12:23:32 -060056 Fdt object associated with the entry type
Simon Glass29aa7362018-09-14 04:57:19 -060057 """
Simon Glass2be381d2019-07-20 12:23:32 -060058 return output_fdt_files[etype][0]
Simon Glass29aa7362018-09-14 04:57:19 -060059
Simon Glass2be381d2019-07-20 12:23:32 -060060def GetFdtPath(etype):
Simon Glass29aa7362018-09-14 04:57:19 -060061 """Get the full pathname of a particular Fdt object
62
Simon Glassa3030a52019-07-20 12:23:30 -060063 Similar to GetFdtForEtype() but returns the pathname associated with the
64 Fdt.
Simon Glass29aa7362018-09-14 04:57:19 -060065
66 Args:
Simon Glass2be381d2019-07-20 12:23:32 -060067 etype: Entry type of device tree (e.g. 'u-boot-dtb')
Simon Glass29aa7362018-09-14 04:57:19 -060068
69 Returns:
70 Full path name to the associated Fdt
71 """
Simon Glass2be381d2019-07-20 12:23:32 -060072 return output_fdt_files[etype][0]._fname
Simon Glass29aa7362018-09-14 04:57:19 -060073
Simon Glass2be381d2019-07-20 12:23:32 -060074def GetFdtContents(etype='u-boot-dtb'):
Simon Glasse219aa42018-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 Glass2be381d2019-07-20 12:23:32 -060082 etype: Entry type to look up (e.g. 'u-boot.dtb').
Simon Glasse219aa42018-09-14 04:57:24 -060083
84 Returns:
85 tuple:
86 pathname to Fdt
87 Fdt data (as bytes)
88 """
Simon Glass2be381d2019-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 Glasse219aa42018-09-14 04:57:24 -060092 else:
Simon Glass2be381d2019-07-20 12:23:32 -060093 fname = output_fdt_files[etype][1]
Simon Glasse219aa42018-09-14 04:57:24 -060094 pathname = tools.GetInputFilename(fname)
95 data = tools.ReadFile(pathname)
96 return pathname, data
97
Simon Glass29aa7362018-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 Glassbdb40312018-09-14 04:57:20 -0600127
Simon Glass0c9d5b52018-09-14 04:57:22 -0600128def Prepare(images, dtb):
Simon Glassbdb40312018-09-14 04:57:20 -0600129 """Get device tree files ready for use
130
Simon Glass5a300602019-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 Glassbdb40312018-09-14 04:57:20 -0600133
134 Args:
Simon Glass0c9d5b52018-09-14 04:57:22 -0600135 images: List of images being used
Simon Glassbdb40312018-09-14 04:57:20 -0600136 dtb: Main dtb
137 """
Simon Glass2be381d2019-07-20 12:23:32 -0600138 global fdt_set, fdt_subset, output_fdt_files, main_dtb
Simon Glassbdb40312018-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 Glass2be381d2019-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 Glass267112e2019-07-20 12:23:28 -0600153 fdt_subset = {}
Simon Glass0c9d5b52018-09-14 04:57:22 -0600154 if not use_fake_dtb:
155 for image in images.values():
Simon Glass267112e2019-07-20 12:23:28 -0600156 fdt_subset.update(image.GetFdts())
Simon Glass684a4f12019-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 Glass0c9d5b52018-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 Glass2be381d2019-07-20 12:23:32 -0600167 output_fdt_files[etype] = [other_dtb, other_fname]
Simon Glassbdb40312018-09-14 04:57:20 -0600168
Simon Glass5a300602019-07-20 12:23:29 -0600169def GetAllFdts():
Simon Glassbdb40312018-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 Glass2be381d2019-07-20 12:23:32 -0600176 for etype in fdt_subset:
177 yield output_fdt_files[etype][0]
Simon Glassbdb40312018-09-14 04:57:20 -0600178
Simon Glassc8135dc2018-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 Glass2be381d2019-07-20 12:23:32 -0600194 for dtb, fname in output_fdt_files.values():
Simon Glasse219aa42018-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 Glassc8135dc2018-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 Glassac6328c2018-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 Glassc8135dc2018-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 Glassae7cf032018-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 Glasscbc80e82019-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