blob: 382bda3221963e2a2850ce18fed17912dc086280 [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 Glass2a72cc72018-09-14 04:57:20 -060025# Set of all device tree files references by images
Simon Glassd141f6c2019-05-14 15:53:39 -060026fdt_set = set()
Simon Glass2a72cc72018-09-14 04:57:20 -060027
28# Same as above, but excluding the main one
Simon Glassd141f6c2019-05-14 15:53:39 -060029fdt_subset = set()
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 Glassc55a50f2018-09-14 04:57:19 -060039def GetFdt(fname):
40 """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
57 Similar to GetFdt() but returns the pathname associated with the Fdt.
58
59 Args:
60 fname: Filename to look up (e.g. 'u-boot.dtb').
61
62 Returns:
63 Full path name to the associated Fdt
64 """
65 return fdt_files[fname]._fname
66
Simon Glass086cec92019-07-08 14:25:27 -060067def GetFdtContents(fname='u-boot.dtb'):
Simon Glass6ed45ba2018-09-14 04:57:24 -060068 """Looks up the FDT pathname and contents
69
70 This is used to obtain the Fdt pathname and contents when needed by an
71 entry. It supports a 'fake' dtb, allowing tests to substitute test data for
72 the real dtb.
73
74 Args:
75 fname: Filename to look up (e.g. 'u-boot.dtb').
76
77 Returns:
78 tuple:
79 pathname to Fdt
80 Fdt data (as bytes)
81 """
82 if fname in fdt_files and not use_fake_dtb:
83 pathname = GetFdtPath(fname)
84 data = GetFdt(fname).GetContents()
85 else:
86 pathname = tools.GetInputFilename(fname)
87 data = tools.ReadFile(pathname)
88 return pathname, data
89
Simon Glassc55a50f2018-09-14 04:57:19 -060090def SetEntryArgs(args):
91 """Set the value of the entry args
92
93 This sets up the entry_args dict which is used to supply entry arguments to
94 entries.
95
96 Args:
97 args: List of entry arguments, each in the format "name=value"
98 """
99 global entry_args
100
101 entry_args = {}
102 if args:
103 for arg in args:
104 m = re.match('([^=]*)=(.*)', arg)
105 if not m:
106 raise ValueError("Invalid entry arguemnt '%s'" % arg)
107 entry_args[m.group(1)] = m.group(2)
108
109def GetEntryArg(name):
110 """Get the value of an entry argument
111
112 Args:
113 name: Name of argument to retrieve
114
115 Returns:
116 String value of argument
117 """
118 return entry_args.get(name)
Simon Glass2a72cc72018-09-14 04:57:20 -0600119
Simon Glass539aece2018-09-14 04:57:22 -0600120def Prepare(images, dtb):
Simon Glass2a72cc72018-09-14 04:57:20 -0600121 """Get device tree files ready for use
122
123 This sets up a set of device tree files that can be retrieved by GetFdts().
124 At present there is only one, that for U-Boot proper.
125
126 Args:
Simon Glass539aece2018-09-14 04:57:22 -0600127 images: List of images being used
Simon Glass2a72cc72018-09-14 04:57:20 -0600128 dtb: Main dtb
129 """
130 global fdt_set, fdt_subset, fdt_files, main_dtb
131 # Import these here in case libfdt.py is not available, in which case
132 # the above help option still works.
133 import fdt
134 import fdt_util
135
136 # If we are updating the DTBs we need to put these updated versions
137 # where Entry_blob_dtb can find them. We can ignore 'u-boot.dtb'
138 # since it is assumed to be the one passed in with options.dt, and
139 # was handled just above.
140 main_dtb = dtb
141 fdt_files.clear()
142 fdt_files['u-boot.dtb'] = dtb
Simon Glassd141f6c2019-05-14 15:53:39 -0600143 fdt_subset = set()
Simon Glass539aece2018-09-14 04:57:22 -0600144 if not use_fake_dtb:
145 for image in images.values():
146 fdt_subset.update(image.GetFdtSet())
147 fdt_subset.discard('u-boot.dtb')
148 for other_fname in fdt_subset:
149 infile = tools.GetInputFilename(other_fname)
150 other_fname_dtb = fdt_util.EnsureCompiled(infile)
151 out_fname = tools.GetOutputFilename('%s.out' %
152 os.path.split(other_fname)[1])
153 tools.WriteFile(out_fname, tools.ReadFile(other_fname_dtb))
154 other_dtb = fdt.FdtScan(out_fname)
155 fdt_files[other_fname] = other_dtb
Simon Glass2a72cc72018-09-14 04:57:20 -0600156
157def GetFdts():
158 """Yield all device tree files being used by binman
159
160 Yields:
161 Device trees being used (U-Boot proper, SPL, TPL)
162 """
163 yield main_dtb
Simon Glass6ed45ba2018-09-14 04:57:24 -0600164 for other_fname in fdt_subset:
165 yield fdt_files[other_fname]
Simon Glass2a72cc72018-09-14 04:57:20 -0600166
Simon Glassf46621d2018-09-14 04:57:21 -0600167def GetUpdateNodes(node):
168 """Yield all the nodes that need to be updated in all device trees
169
170 The property referenced by this node is added to any device trees which
171 have the given node. Due to removable of unwanted notes, SPL and TPL may
172 not have this node.
173
174 Args:
175 node: Node object in the main device tree to look up
176
177 Yields:
178 Node objects in each device tree that is in use (U-Boot proper, which
179 is node, SPL and TPL)
180 """
181 yield node
Simon Glass6ed45ba2018-09-14 04:57:24 -0600182 for dtb in fdt_files.values():
183 if dtb != node.GetFdt():
184 other_node = dtb.GetNode(node.path)
185 if other_node:
186 yield other_node
Simon Glassf46621d2018-09-14 04:57:21 -0600187
188def AddZeroProp(node, prop):
189 """Add a new property to affected device trees with an integer value of 0.
190
191 Args:
192 prop_name: Name of property
193 """
194 for n in GetUpdateNodes(node):
195 n.AddZeroProp(prop)
196
Simon Glass0a98b282018-09-14 04:57:28 -0600197def AddSubnode(node, name):
198 """Add a new subnode to a node in affected device trees
199
200 Args:
201 node: Node to add to
202 name: name of node to add
203
204 Returns:
205 New subnode that was created in main tree
206 """
207 first = None
208 for n in GetUpdateNodes(node):
209 subnode = n.AddSubnode(name)
210 if not first:
211 first = subnode
212 return first
213
214def AddString(node, prop, value):
215 """Add a new string property to affected device trees
216
217 Args:
218 prop_name: Name of property
219 value: String value (which will be \0-terminated in the DT)
220 """
221 for n in GetUpdateNodes(node):
222 n.AddString(prop, value)
223
Simon Glassf46621d2018-09-14 04:57:21 -0600224def SetInt(node, prop, value):
225 """Update an integer property in affected device trees with an integer value
226
227 This is not allowed to change the size of the FDT.
228
229 Args:
230 prop_name: Name of property
231 """
232 for n in GetUpdateNodes(node):
233 n.SetInt(prop, value)
Simon Glasse0e5df92018-09-14 04:57:31 -0600234
235def CheckAddHashProp(node):
236 hash_node = node.FindNode('hash')
237 if hash_node:
238 algo = hash_node.props.get('algo')
239 if not algo:
240 return "Missing 'algo' property for hash node"
241 if algo.value == 'sha256':
242 size = 32
243 else:
244 return "Unknown hash algorithm '%s'" % algo
245 for n in GetUpdateNodes(hash_node):
246 n.AddEmptyProp('value', size)
247
248def CheckSetHashValue(node, get_data_func):
249 hash_node = node.FindNode('hash')
250 if hash_node:
251 algo = hash_node.props.get('algo').value
252 if algo == 'sha256':
253 m = hashlib.sha256()
254 m.update(get_data_func())
255 data = m.digest()
256 for n in GetUpdateNodes(hash_node):
257 n.SetData('value', data)
Simon Glassbf6906b2019-07-08 14:25:36 -0600258
259def SetAllowEntryExpansion(allow):
260 """Set whether post-pack expansion of entries is allowed
261
262 Args:
263 allow: True to allow expansion, False to raise an exception
264 """
265 global allow_entry_expansion
266
267 allow_entry_expansion = allow
268
269def AllowEntryExpansion():
270 """Check whether post-pack expansion of entries is allowed
271
272 Returns:
273 True if expansion should be allowed, False if an exception should be
274 raised
275 """
276 return allow_entry_expansion