blob: 7c3a987723eb5ecd02b1e0d92fbd22d8f9560fd3 [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 Glassbdb40312018-09-14 04:57:20 -060031# The DTB which contains the full image information
32main_dtb = None
33
Simon Glasscbc80e82019-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 Glass2be381d2019-07-20 12:23:32 -060039def GetFdtForEtype(etype):
40 """Get the Fdt object for a particular device-tree entry
Simon Glass29aa7362018-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 Glass2be381d2019-07-20 12:23:32 -060044 entry and returns the associated Fdt object.
Simon Glass29aa7362018-09-14 04:57:19 -060045
46 Args:
Simon Glass2be381d2019-07-20 12:23:32 -060047 etype: Entry type of device tree (e.g. 'u-boot-dtb')
Simon Glass29aa7362018-09-14 04:57:19 -060048
49 Returns:
Simon Glass2be381d2019-07-20 12:23:32 -060050 Fdt object associated with the entry type
Simon Glass29aa7362018-09-14 04:57:19 -060051 """
Simon Glass2be381d2019-07-20 12:23:32 -060052 return output_fdt_files[etype][0]
Simon Glass29aa7362018-09-14 04:57:19 -060053
Simon Glass2be381d2019-07-20 12:23:32 -060054def GetFdtPath(etype):
Simon Glass29aa7362018-09-14 04:57:19 -060055 """Get the full pathname of a particular Fdt object
56
Simon Glassa3030a52019-07-20 12:23:30 -060057 Similar to GetFdtForEtype() but returns the pathname associated with the
58 Fdt.
Simon Glass29aa7362018-09-14 04:57:19 -060059
60 Args:
Simon Glass2be381d2019-07-20 12:23:32 -060061 etype: Entry type of device tree (e.g. 'u-boot-dtb')
Simon Glass29aa7362018-09-14 04:57:19 -060062
63 Returns:
64 Full path name to the associated Fdt
65 """
Simon Glass2be381d2019-07-20 12:23:32 -060066 return output_fdt_files[etype][0]._fname
Simon Glass29aa7362018-09-14 04:57:19 -060067
Simon Glass2be381d2019-07-20 12:23:32 -060068def GetFdtContents(etype='u-boot-dtb'):
Simon Glasse219aa42018-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 Glass2be381d2019-07-20 12:23:32 -060076 etype: Entry type to look up (e.g. 'u-boot.dtb').
Simon Glasse219aa42018-09-14 04:57:24 -060077
78 Returns:
79 tuple:
80 pathname to Fdt
81 Fdt data (as bytes)
82 """
Simon Glass2be381d2019-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 Glasse219aa42018-09-14 04:57:24 -060086 else:
Simon Glass2be381d2019-07-20 12:23:32 -060087 fname = output_fdt_files[etype][1]
Simon Glasse219aa42018-09-14 04:57:24 -060088 pathname = tools.GetInputFilename(fname)
89 data = tools.ReadFile(pathname)
90 return pathname, data
91
Simon Glass29aa7362018-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 Glassbdb40312018-09-14 04:57:20 -0600121
Simon Glass0c9d5b52018-09-14 04:57:22 -0600122def Prepare(images, dtb):
Simon Glassbdb40312018-09-14 04:57:20 -0600123 """Get device tree files ready for use
124
Simon Glass5a300602019-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 Glassbdb40312018-09-14 04:57:20 -0600127
128 Args:
Simon Glass0c9d5b52018-09-14 04:57:22 -0600129 images: List of images being used
Simon Glassbdb40312018-09-14 04:57:20 -0600130 dtb: Main dtb
131 """
Simon Glassf3aba912019-07-20 12:23:34 -0600132 global output_fdt_files, main_dtb
Simon Glassbdb40312018-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 Glass2be381d2019-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 Glass0c9d5b52018-09-14 04:57:22 -0600147 if not use_fake_dtb:
Simon Glassf3aba912019-07-20 12:23:34 -0600148 fdt_set = {}
Simon Glass0c9d5b52018-09-14 04:57:22 -0600149 for image in images.values():
Simon Glass132fa722019-07-20 12:23:33 -0600150 fdt_set.update(image.GetFdts())
151 for etype, other in fdt_set.items():
Simon Glass684a4f12019-07-20 12:23:31 -0600152 _, other_fname = other
Simon Glass0c9d5b52018-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 Glass2be381d2019-07-20 12:23:32 -0600159 output_fdt_files[etype] = [other_dtb, other_fname]
Simon Glassbdb40312018-09-14 04:57:20 -0600160
Simon Glass5a300602019-07-20 12:23:29 -0600161def GetAllFdts():
Simon Glassbdb40312018-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 Glassf3aba912019-07-20 12:23:34 -0600168 for etype in output_fdt_files:
Simon Glass132fa722019-07-20 12:23:33 -0600169 dtb = output_fdt_files[etype][0]
170 if dtb != main_dtb:
171 yield dtb
Simon Glassbdb40312018-09-14 04:57:20 -0600172
Simon Glassc8135dc2018-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 Glass2be381d2019-07-20 12:23:32 -0600188 for dtb, fname in output_fdt_files.values():
Simon Glasse219aa42018-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 Glassc8135dc2018-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 Glassac6328c2018-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 Glassc8135dc2018-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 Glassae7cf032018-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 Glasscbc80e82019-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