blob: ee11ba470e08347459affc500eb02b26b73d831a [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
14# Records the device-tree files known to binman, keyed by filename (e.g.
15# 'u-boot-spl.dtb')
16fdt_files = {}
17
18# Arguments passed to binman to provide arguments to entries
19entry_args = {}
20
Simon Glass539aece2018-09-14 04:57:22 -060021# True to use fake device-tree files for testing (see U_BOOT_DTB_DATA in
22# ftest.py)
Simon Glass93d17412018-09-14 04:57:23 -060023use_fake_dtb = False
Simon Glass539aece2018-09-14 04:57:22 -060024
Simon Glass4bdd3002019-07-20 12:23:31 -060025# Dict of device trees, keyed by entry type, but excluding the main one
26# The value is as returned by Entry.GetFdts(), i.e. a tuple:
27# Fdt object for this dtb, or None if not available
28# Filename of file containing this dtb
Simon Glassa8adb6d2019-07-20 12:23:28 -060029fdt_subset = {}
Simon Glass2a72cc72018-09-14 04:57:20 -060030
31# 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 Glass726e2962019-07-20 12:23:30 -060039def GetFdtForEtype(fname):
Simon Glassc55a50f2018-09-14 04:57:19 -060040 """Get the Fdt object for a particular device-tree filename
41
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
44 filename and returns the associated Fdt object.
45
46 Args:
47 fname: Filename to look up (e.g. 'u-boot.dtb').
48
49 Returns:
50 Fdt object associated with the filename
51 """
52 return fdt_files[fname]
53
54def GetFdtPath(fname):
55 """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:
61 fname: Filename to look up (e.g. 'u-boot.dtb').
62
63 Returns:
64 Full path name to the associated Fdt
65 """
66 return fdt_files[fname]._fname
67
Simon Glass086cec92019-07-08 14:25:27 -060068def GetFdtContents(fname='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:
76 fname: Filename to look up (e.g. 'u-boot.dtb').
77
78 Returns:
79 tuple:
80 pathname to Fdt
81 Fdt data (as bytes)
82 """
83 if fname in fdt_files and not use_fake_dtb:
84 pathname = GetFdtPath(fname)
Simon Glass726e2962019-07-20 12:23:30 -060085 data = GetFdtForEtype(fname).GetContents()
Simon Glass6ed45ba2018-09-14 04:57:24 -060086 else:
87 pathname = tools.GetInputFilename(fname)
88 data = tools.ReadFile(pathname)
89 return pathname, data
90
Simon Glassc55a50f2018-09-14 04:57:19 -060091def SetEntryArgs(args):
92 """Set the value of the entry args
93
94 This sets up the entry_args dict which is used to supply entry arguments to
95 entries.
96
97 Args:
98 args: List of entry arguments, each in the format "name=value"
99 """
100 global entry_args
101
102 entry_args = {}
103 if args:
104 for arg in args:
105 m = re.match('([^=]*)=(.*)', arg)
106 if not m:
107 raise ValueError("Invalid entry arguemnt '%s'" % arg)
108 entry_args[m.group(1)] = m.group(2)
109
110def GetEntryArg(name):
111 """Get the value of an entry argument
112
113 Args:
114 name: Name of argument to retrieve
115
116 Returns:
117 String value of argument
118 """
119 return entry_args.get(name)
Simon Glass2a72cc72018-09-14 04:57:20 -0600120
Simon Glass539aece2018-09-14 04:57:22 -0600121def Prepare(images, dtb):
Simon Glass2a72cc72018-09-14 04:57:20 -0600122 """Get device tree files ready for use
123
Simon Glass4bdd1152019-07-20 12:23:29 -0600124 This sets up a set of device tree files that can be retrieved by
125 GetAllFdts(). This includes U-Boot proper and any SPL device trees.
Simon Glass2a72cc72018-09-14 04:57:20 -0600126
127 Args:
Simon Glass539aece2018-09-14 04:57:22 -0600128 images: List of images being used
Simon Glass2a72cc72018-09-14 04:57:20 -0600129 dtb: Main dtb
130 """
131 global fdt_set, fdt_subset, fdt_files, main_dtb
132 # Import these here in case libfdt.py is not available, in which case
133 # the above help option still works.
134 import fdt
135 import fdt_util
136
137 # If we are updating the DTBs we need to put these updated versions
138 # where Entry_blob_dtb can find them. We can ignore 'u-boot.dtb'
139 # since it is assumed to be the one passed in with options.dt, and
140 # was handled just above.
141 main_dtb = dtb
142 fdt_files.clear()
143 fdt_files['u-boot.dtb'] = dtb
Simon Glassa8adb6d2019-07-20 12:23:28 -0600144 fdt_subset = {}
Simon Glass539aece2018-09-14 04:57:22 -0600145 if not use_fake_dtb:
146 for image in images.values():
Simon Glassa8adb6d2019-07-20 12:23:28 -0600147 fdt_subset.update(image.GetFdts())
Simon Glass4bdd3002019-07-20 12:23:31 -0600148 if 'u-boot-dtb' in fdt_subset:
149 del fdt_subset['u-boot-dtb']
150 for etype, other in fdt_subset.items():
151 _, other_fname = other
Simon Glass539aece2018-09-14 04:57:22 -0600152 infile = tools.GetInputFilename(other_fname)
153 other_fname_dtb = fdt_util.EnsureCompiled(infile)
154 out_fname = tools.GetOutputFilename('%s.out' %
155 os.path.split(other_fname)[1])
156 tools.WriteFile(out_fname, tools.ReadFile(other_fname_dtb))
157 other_dtb = fdt.FdtScan(out_fname)
158 fdt_files[other_fname] = other_dtb
Simon Glass2a72cc72018-09-14 04:57:20 -0600159
Simon Glass4bdd1152019-07-20 12:23:29 -0600160def GetAllFdts():
Simon Glass2a72cc72018-09-14 04:57:20 -0600161 """Yield all device tree files being used by binman
162
163 Yields:
164 Device trees being used (U-Boot proper, SPL, TPL)
165 """
166 yield main_dtb
Simon Glass4bdd3002019-07-20 12:23:31 -0600167 for etype, other_fname in fdt_subset.values():
Simon Glass6ed45ba2018-09-14 04:57:24 -0600168 yield fdt_files[other_fname]
Simon Glass2a72cc72018-09-14 04:57:20 -0600169
Simon Glassf46621d2018-09-14 04:57:21 -0600170def GetUpdateNodes(node):
171 """Yield all the nodes that need to be updated in all device trees
172
173 The property referenced by this node is added to any device trees which
174 have the given node. Due to removable of unwanted notes, SPL and TPL may
175 not have this node.
176
177 Args:
178 node: Node object in the main device tree to look up
179
180 Yields:
181 Node objects in each device tree that is in use (U-Boot proper, which
182 is node, SPL and TPL)
183 """
184 yield node
Simon Glass6ed45ba2018-09-14 04:57:24 -0600185 for dtb in fdt_files.values():
186 if dtb != node.GetFdt():
187 other_node = dtb.GetNode(node.path)
188 if other_node:
189 yield other_node
Simon Glassf46621d2018-09-14 04:57:21 -0600190
191def AddZeroProp(node, prop):
192 """Add a new property to affected device trees with an integer value of 0.
193
194 Args:
195 prop_name: Name of property
196 """
197 for n in GetUpdateNodes(node):
198 n.AddZeroProp(prop)
199
Simon Glass0a98b282018-09-14 04:57:28 -0600200def AddSubnode(node, name):
201 """Add a new subnode to a node in affected device trees
202
203 Args:
204 node: Node to add to
205 name: name of node to add
206
207 Returns:
208 New subnode that was created in main tree
209 """
210 first = None
211 for n in GetUpdateNodes(node):
212 subnode = n.AddSubnode(name)
213 if not first:
214 first = subnode
215 return first
216
217def AddString(node, prop, value):
218 """Add a new string property to affected device trees
219
220 Args:
221 prop_name: Name of property
222 value: String value (which will be \0-terminated in the DT)
223 """
224 for n in GetUpdateNodes(node):
225 n.AddString(prop, value)
226
Simon Glassf46621d2018-09-14 04:57:21 -0600227def SetInt(node, prop, value):
228 """Update an integer property in affected device trees with an integer value
229
230 This is not allowed to change the size of the FDT.
231
232 Args:
233 prop_name: Name of property
234 """
235 for n in GetUpdateNodes(node):
236 n.SetInt(prop, value)
Simon Glasse0e5df92018-09-14 04:57:31 -0600237
238def CheckAddHashProp(node):
239 hash_node = node.FindNode('hash')
240 if hash_node:
241 algo = hash_node.props.get('algo')
242 if not algo:
243 return "Missing 'algo' property for hash node"
244 if algo.value == 'sha256':
245 size = 32
246 else:
247 return "Unknown hash algorithm '%s'" % algo
248 for n in GetUpdateNodes(hash_node):
249 n.AddEmptyProp('value', size)
250
251def CheckSetHashValue(node, get_data_func):
252 hash_node = node.FindNode('hash')
253 if hash_node:
254 algo = hash_node.props.get('algo').value
255 if algo == 'sha256':
256 m = hashlib.sha256()
257 m.update(get_data_func())
258 data = m.digest()
259 for n in GetUpdateNodes(hash_node):
260 n.SetData('value', data)
Simon Glassbf6906b2019-07-08 14:25:36 -0600261
262def SetAllowEntryExpansion(allow):
263 """Set whether post-pack expansion of entries is allowed
264
265 Args:
266 allow: True to allow expansion, False to raise an exception
267 """
268 global allow_entry_expansion
269
270 allow_entry_expansion = allow
271
272def AllowEntryExpansion():
273 """Check whether post-pack expansion of entries is allowed
274
275 Returns:
276 True if expansion should be allowed, False if an exception should be
277 raised
278 """
279 return allow_entry_expansion