blob: c8175a303342d86e24a40de82619c38c852de7fb [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 Glassa8adb6d2019-07-20 12:23:28 -060025# Dict of device trees, keyed by filename, but excluding the main one
26fdt_subset = {}
Simon Glass2a72cc72018-09-14 04:57:20 -060027
28# The DTB which contains the full image information
29main_dtb = None
30
Simon Glassbf6906b2019-07-08 14:25:36 -060031# Allow entries to expand after they have been packed. This is detected and
32# forces a re-pack. If not allowed, any attempted expansion causes an error in
33# Entry.ProcessContentsUpdate()
34allow_entry_expansion = True
35
Simon Glass726e2962019-07-20 12:23:30 -060036def GetFdtForEtype(fname):
Simon Glassc55a50f2018-09-14 04:57:19 -060037 """Get the Fdt object for a particular device-tree filename
38
39 Binman keeps track of at least one device-tree file called u-boot.dtb but
40 can also have others (e.g. for SPL). This function looks up the given
41 filename and returns the associated Fdt object.
42
43 Args:
44 fname: Filename to look up (e.g. 'u-boot.dtb').
45
46 Returns:
47 Fdt object associated with the filename
48 """
49 return fdt_files[fname]
50
51def GetFdtPath(fname):
52 """Get the full pathname of a particular Fdt object
53
Simon Glass726e2962019-07-20 12:23:30 -060054 Similar to GetFdtForEtype() but returns the pathname associated with the
55 Fdt.
Simon Glassc55a50f2018-09-14 04:57:19 -060056
57 Args:
58 fname: Filename to look up (e.g. 'u-boot.dtb').
59
60 Returns:
61 Full path name to the associated Fdt
62 """
63 return fdt_files[fname]._fname
64
Simon Glass086cec92019-07-08 14:25:27 -060065def GetFdtContents(fname='u-boot.dtb'):
Simon Glass6ed45ba2018-09-14 04:57:24 -060066 """Looks up the FDT pathname and contents
67
68 This is used to obtain the Fdt pathname and contents when needed by an
69 entry. It supports a 'fake' dtb, allowing tests to substitute test data for
70 the real dtb.
71
72 Args:
73 fname: Filename to look up (e.g. 'u-boot.dtb').
74
75 Returns:
76 tuple:
77 pathname to Fdt
78 Fdt data (as bytes)
79 """
80 if fname in fdt_files and not use_fake_dtb:
81 pathname = GetFdtPath(fname)
Simon Glass726e2962019-07-20 12:23:30 -060082 data = GetFdtForEtype(fname).GetContents()
Simon Glass6ed45ba2018-09-14 04:57:24 -060083 else:
84 pathname = tools.GetInputFilename(fname)
85 data = tools.ReadFile(pathname)
86 return pathname, data
87
Simon Glassc55a50f2018-09-14 04:57:19 -060088def SetEntryArgs(args):
89 """Set the value of the entry args
90
91 This sets up the entry_args dict which is used to supply entry arguments to
92 entries.
93
94 Args:
95 args: List of entry arguments, each in the format "name=value"
96 """
97 global entry_args
98
99 entry_args = {}
100 if args:
101 for arg in args:
102 m = re.match('([^=]*)=(.*)', arg)
103 if not m:
104 raise ValueError("Invalid entry arguemnt '%s'" % arg)
105 entry_args[m.group(1)] = m.group(2)
106
107def GetEntryArg(name):
108 """Get the value of an entry argument
109
110 Args:
111 name: Name of argument to retrieve
112
113 Returns:
114 String value of argument
115 """
116 return entry_args.get(name)
Simon Glass2a72cc72018-09-14 04:57:20 -0600117
Simon Glass539aece2018-09-14 04:57:22 -0600118def Prepare(images, dtb):
Simon Glass2a72cc72018-09-14 04:57:20 -0600119 """Get device tree files ready for use
120
Simon Glass4bdd1152019-07-20 12:23:29 -0600121 This sets up a set of device tree files that can be retrieved by
122 GetAllFdts(). This includes U-Boot proper and any SPL device trees.
Simon Glass2a72cc72018-09-14 04:57:20 -0600123
124 Args:
Simon Glass539aece2018-09-14 04:57:22 -0600125 images: List of images being used
Simon Glass2a72cc72018-09-14 04:57:20 -0600126 dtb: Main dtb
127 """
128 global fdt_set, fdt_subset, fdt_files, main_dtb
129 # Import these here in case libfdt.py is not available, in which case
130 # the above help option still works.
131 import fdt
132 import fdt_util
133
134 # If we are updating the DTBs we need to put these updated versions
135 # where Entry_blob_dtb can find them. We can ignore 'u-boot.dtb'
136 # since it is assumed to be the one passed in with options.dt, and
137 # was handled just above.
138 main_dtb = dtb
139 fdt_files.clear()
140 fdt_files['u-boot.dtb'] = dtb
Simon Glassa8adb6d2019-07-20 12:23:28 -0600141 fdt_subset = {}
Simon Glass539aece2018-09-14 04:57:22 -0600142 if not use_fake_dtb:
143 for image in images.values():
Simon Glassa8adb6d2019-07-20 12:23:28 -0600144 fdt_subset.update(image.GetFdts())
145 if 'u-boot.dtb' in fdt_subset:
146 del fdt_subset['u-boot.dtb']
Simon Glass539aece2018-09-14 04:57:22 -0600147 for other_fname in fdt_subset:
148 infile = tools.GetInputFilename(other_fname)
149 other_fname_dtb = fdt_util.EnsureCompiled(infile)
150 out_fname = tools.GetOutputFilename('%s.out' %
151 os.path.split(other_fname)[1])
152 tools.WriteFile(out_fname, tools.ReadFile(other_fname_dtb))
153 other_dtb = fdt.FdtScan(out_fname)
154 fdt_files[other_fname] = other_dtb
Simon Glass2a72cc72018-09-14 04:57:20 -0600155
Simon Glass4bdd1152019-07-20 12:23:29 -0600156def GetAllFdts():
Simon Glass2a72cc72018-09-14 04:57:20 -0600157 """Yield all device tree files being used by binman
158
159 Yields:
160 Device trees being used (U-Boot proper, SPL, TPL)
161 """
162 yield main_dtb
Simon Glass6ed45ba2018-09-14 04:57:24 -0600163 for other_fname in fdt_subset:
164 yield fdt_files[other_fname]
Simon Glass2a72cc72018-09-14 04:57:20 -0600165
Simon Glassf46621d2018-09-14 04:57:21 -0600166def GetUpdateNodes(node):
167 """Yield all the nodes that need to be updated in all device trees
168
169 The property referenced by this node is added to any device trees which
170 have the given node. Due to removable of unwanted notes, SPL and TPL may
171 not have this node.
172
173 Args:
174 node: Node object in the main device tree to look up
175
176 Yields:
177 Node objects in each device tree that is in use (U-Boot proper, which
178 is node, SPL and TPL)
179 """
180 yield node
Simon Glass6ed45ba2018-09-14 04:57:24 -0600181 for dtb in fdt_files.values():
182 if dtb != node.GetFdt():
183 other_node = dtb.GetNode(node.path)
184 if other_node:
185 yield other_node
Simon Glassf46621d2018-09-14 04:57:21 -0600186
187def AddZeroProp(node, prop):
188 """Add a new property to affected device trees with an integer value of 0.
189
190 Args:
191 prop_name: Name of property
192 """
193 for n in GetUpdateNodes(node):
194 n.AddZeroProp(prop)
195
Simon Glass0a98b282018-09-14 04:57:28 -0600196def AddSubnode(node, name):
197 """Add a new subnode to a node in affected device trees
198
199 Args:
200 node: Node to add to
201 name: name of node to add
202
203 Returns:
204 New subnode that was created in main tree
205 """
206 first = None
207 for n in GetUpdateNodes(node):
208 subnode = n.AddSubnode(name)
209 if not first:
210 first = subnode
211 return first
212
213def AddString(node, prop, value):
214 """Add a new string property to affected device trees
215
216 Args:
217 prop_name: Name of property
218 value: String value (which will be \0-terminated in the DT)
219 """
220 for n in GetUpdateNodes(node):
221 n.AddString(prop, value)
222
Simon Glassf46621d2018-09-14 04:57:21 -0600223def SetInt(node, prop, value):
224 """Update an integer property in affected device trees with an integer value
225
226 This is not allowed to change the size of the FDT.
227
228 Args:
229 prop_name: Name of property
230 """
231 for n in GetUpdateNodes(node):
232 n.SetInt(prop, value)
Simon Glasse0e5df92018-09-14 04:57:31 -0600233
234def CheckAddHashProp(node):
235 hash_node = node.FindNode('hash')
236 if hash_node:
237 algo = hash_node.props.get('algo')
238 if not algo:
239 return "Missing 'algo' property for hash node"
240 if algo.value == 'sha256':
241 size = 32
242 else:
243 return "Unknown hash algorithm '%s'" % algo
244 for n in GetUpdateNodes(hash_node):
245 n.AddEmptyProp('value', size)
246
247def CheckSetHashValue(node, get_data_func):
248 hash_node = node.FindNode('hash')
249 if hash_node:
250 algo = hash_node.props.get('algo').value
251 if algo == 'sha256':
252 m = hashlib.sha256()
253 m.update(get_data_func())
254 data = m.digest()
255 for n in GetUpdateNodes(hash_node):
256 n.SetData('value', data)
Simon Glassbf6906b2019-07-08 14:25:36 -0600257
258def SetAllowEntryExpansion(allow):
259 """Set whether post-pack expansion of entries is allowed
260
261 Args:
262 allow: True to allow expansion, False to raise an exception
263 """
264 global allow_entry_expansion
265
266 allow_entry_expansion = allow
267
268def AllowEntryExpansion():
269 """Check whether post-pack expansion of entries is allowed
270
271 Returns:
272 True if expansion should be allowed, False if an exception should be
273 raised
274 """
275 return allow_entry_expansion