1 # SPDX-License-Identifier: GPL-2.0+
2 # Copyright 2018 Google, Inc
3 # Written by Simon Glass <sjg@chromium.org>
5 # Holds and modifies the state information held by binman
14 # 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.
22 # Entry object, or None if not known
25 # Arguments passed to binman to provide arguments to entries
28 # True to use fake device-tree files for testing (see U_BOOT_DTB_DATA in
32 # The DTB which contains the full image information
35 # Allow entries to expand after they have been packed. This is detected and
36 # forces a re-pack. If not allowed, any attempted expansion causes an error in
37 # Entry.ProcessContentsUpdate()
38 allow_entry_expansion = True
40 def GetFdtForEtype(etype):
41 """Get the Fdt object for a particular device-tree entry
43 Binman keeps track of at least one device-tree file called u-boot.dtb but
44 can also have others (e.g. for SPL). This function looks up the given
45 entry and returns the associated Fdt object.
48 etype: Entry type of device tree (e.g. 'u-boot-dtb')
51 Fdt object associated with the entry type
53 value = output_fdt_info.get(etype);
58 def GetEntryForEtype(etype):
59 """Get the Entry for a particular device-tree filename
61 Binman keeps track of at least one device-tree file called u-boot.dtb but
62 can also have others (e.g. for SPL). This function looks up the given
63 filename and returns the associated Fdt object.
66 etype: Entry type of device tree (e.g. 'u-boot-dtb')
69 Entry object associated with the entry type, if present in the image
71 value = output_fdt_info.get(etype);
76 def GetFdtPath(etype):
77 """Get the full pathname of a particular Fdt object
79 Similar to GetFdtForEtype() but returns the pathname associated with the
83 etype: Entry type of device tree (e.g. 'u-boot-dtb')
86 Full path name to the associated Fdt
88 return output_fdt_info[etype][0]._fname
90 def GetFdtContents(etype='u-boot-dtb'):
91 """Looks up the FDT pathname and contents
93 This is used to obtain the Fdt pathname and contents when needed by an
94 entry. It supports a 'fake' dtb, allowing tests to substitute test data for
98 etype: Entry type to look up (e.g. 'u-boot.dtb').
105 if etype not in output_fdt_info:
108 pathname = GetFdtPath(etype)
109 data = GetFdtForEtype(etype).GetContents()
111 fname = output_fdt_info[etype][1]
112 pathname = tools.GetInputFilename(fname)
113 data = tools.ReadFile(pathname)
114 return pathname, data
116 def SetEntryArgs(args):
117 """Set the value of the entry args
119 This sets up the entry_args dict which is used to supply entry arguments to
123 args: List of entry arguments, each in the format "name=value"
130 m = re.match('([^=]*)=(.*)', arg)
132 raise ValueError("Invalid entry arguemnt '%s'" % arg)
133 entry_args[m.group(1)] = m.group(2)
135 def GetEntryArg(name):
136 """Get the value of an entry argument
139 name: Name of argument to retrieve
142 String value of argument
144 return entry_args.get(name)
146 def Prepare(images, dtb):
147 """Get device tree files ready for use
149 This sets up a set of device tree files that can be retrieved by
150 GetAllFdts(). This includes U-Boot proper and any SPL device trees.
153 images: List of images being used
156 global output_fdt_info, main_dtb
157 # Import these here in case libfdt.py is not available, in which case
158 # the above help option still works.
162 # If we are updating the DTBs we need to put these updated versions
163 # where Entry_blob_dtb can find them. We can ignore 'u-boot.dtb'
164 # since it is assumed to be the one passed in with options.dt, and
165 # was handled just above.
167 output_fdt_info.clear()
168 output_fdt_info['u-boot-dtb'] = [dtb, 'u-boot.dtb', None]
169 output_fdt_info['u-boot-spl-dtb'] = [dtb, 'spl/u-boot-spl.dtb', None]
170 output_fdt_info['u-boot-tpl-dtb'] = [dtb, 'tpl/u-boot-tpl.dtb', None]
173 for image in images.values():
174 fdt_set.update(image.GetFdts())
175 for etype, other in fdt_set.items():
176 entry, other_fname = other
177 infile = tools.GetInputFilename(other_fname)
178 other_fname_dtb = fdt_util.EnsureCompiled(infile)
179 out_fname = tools.GetOutputFilename('%s.out' %
180 os.path.split(other_fname)[1])
181 tools.WriteFile(out_fname, tools.ReadFile(other_fname_dtb))
182 other_dtb = fdt.FdtScan(out_fname)
183 output_fdt_info[etype] = [other_dtb, out_fname, entry]
186 """Yield all device tree files being used by binman
189 Device trees being used (U-Boot proper, SPL, TPL)
192 for etype in output_fdt_info:
193 dtb = output_fdt_info[etype][0]
197 def GetUpdateNodes(node):
198 """Yield all the nodes that need to be updated in all device trees
200 The property referenced by this node is added to any device trees which
201 have the given node. Due to removable of unwanted notes, SPL and TPL may
205 node: Node object in the main device tree to look up
208 Node objects in each device tree that is in use (U-Boot proper, which
209 is node, SPL and TPL)
212 for dtb, fname, _ in output_fdt_info.values():
213 if dtb != node.GetFdt():
214 other_node = dtb.GetNode(node.path)
218 def AddZeroProp(node, prop):
219 """Add a new property to affected device trees with an integer value of 0.
222 prop_name: Name of property
224 for n in GetUpdateNodes(node):
227 def AddSubnode(node, name):
228 """Add a new subnode to a node in affected device trees
232 name: name of node to add
235 New subnode that was created in main tree
238 for n in GetUpdateNodes(node):
239 subnode = n.AddSubnode(name)
244 def AddString(node, prop, value):
245 """Add a new string property to affected device trees
248 prop_name: Name of property
249 value: String value (which will be \0-terminated in the DT)
251 for n in GetUpdateNodes(node):
252 n.AddString(prop, value)
254 def SetInt(node, prop, value):
255 """Update an integer property in affected device trees with an integer value
257 This is not allowed to change the size of the FDT.
260 prop_name: Name of property
262 for n in GetUpdateNodes(node):
263 n.SetInt(prop, value)
265 def CheckAddHashProp(node):
266 hash_node = node.FindNode('hash')
268 algo = hash_node.props.get('algo')
270 return "Missing 'algo' property for hash node"
271 if algo.value == 'sha256':
274 return "Unknown hash algorithm '%s'" % algo
275 for n in GetUpdateNodes(hash_node):
276 n.AddEmptyProp('value', size)
278 def CheckSetHashValue(node, get_data_func):
279 hash_node = node.FindNode('hash')
281 algo = hash_node.props.get('algo').value
284 m.update(get_data_func())
286 for n in GetUpdateNodes(hash_node):
287 n.SetData('value', data)
289 def SetAllowEntryExpansion(allow):
290 """Set whether post-pack expansion of entries is allowed
293 allow: True to allow expansion, False to raise an exception
295 global allow_entry_expansion
297 allow_entry_expansion = allow
299 def AllowEntryExpansion():
300 """Check whether post-pack expansion of entries is allowed
303 True if expansion should be allowed, False if an exception should be
306 return allow_entry_expansion