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