blob: af9678649cd7187cac9d21140b2b3f9942f531dc [file] [log] [blame]
Simon Glass29aa7362018-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 Glassae7cf032018-09-14 04:57:31 -06008import hashlib
Simon Glass29aa7362018-09-14 04:57:19 -06009import re
Simon Glass29aa7362018-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 Glass0c9d5b52018-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 Glass31402012018-09-14 04:57:23 -060023use_fake_dtb = False
Simon Glass0c9d5b52018-09-14 04:57:22 -060024
Simon Glassbdb40312018-09-14 04:57:20 -060025# Set of all device tree files references by images
Simon Glass4aea9542019-05-14 15:53:39 -060026fdt_set = set()
Simon Glassbdb40312018-09-14 04:57:20 -060027
28# Same as above, but excluding the main one
Simon Glass4aea9542019-05-14 15:53:39 -060029fdt_subset = set()
Simon Glassbdb40312018-09-14 04:57:20 -060030
31# The DTB which contains the full image information
32main_dtb = None
33
Simon Glass29aa7362018-09-14 04:57:19 -060034def GetFdt(fname):
35 """Get the Fdt object for a particular device-tree filename
36
37 Binman keeps track of at least one device-tree file called u-boot.dtb but
38 can also have others (e.g. for SPL). This function looks up the given
39 filename and returns the associated Fdt object.
40
41 Args:
42 fname: Filename to look up (e.g. 'u-boot.dtb').
43
44 Returns:
45 Fdt object associated with the filename
46 """
47 return fdt_files[fname]
48
49def GetFdtPath(fname):
50 """Get the full pathname of a particular Fdt object
51
52 Similar to GetFdt() but returns the pathname associated with the Fdt.
53
54 Args:
55 fname: Filename to look up (e.g. 'u-boot.dtb').
56
57 Returns:
58 Full path name to the associated Fdt
59 """
60 return fdt_files[fname]._fname
61
Simon Glasse219aa42018-09-14 04:57:24 -060062def GetFdtContents(fname):
63 """Looks up the FDT pathname and contents
64
65 This is used to obtain the Fdt pathname and contents when needed by an
66 entry. It supports a 'fake' dtb, allowing tests to substitute test data for
67 the real dtb.
68
69 Args:
70 fname: Filename to look up (e.g. 'u-boot.dtb').
71
72 Returns:
73 tuple:
74 pathname to Fdt
75 Fdt data (as bytes)
76 """
77 if fname in fdt_files and not use_fake_dtb:
78 pathname = GetFdtPath(fname)
79 data = GetFdt(fname).GetContents()
80 else:
81 pathname = tools.GetInputFilename(fname)
82 data = tools.ReadFile(pathname)
83 return pathname, data
84
Simon Glass29aa7362018-09-14 04:57:19 -060085def SetEntryArgs(args):
86 """Set the value of the entry args
87
88 This sets up the entry_args dict which is used to supply entry arguments to
89 entries.
90
91 Args:
92 args: List of entry arguments, each in the format "name=value"
93 """
94 global entry_args
95
96 entry_args = {}
97 if args:
98 for arg in args:
99 m = re.match('([^=]*)=(.*)', arg)
100 if not m:
101 raise ValueError("Invalid entry arguemnt '%s'" % arg)
102 entry_args[m.group(1)] = m.group(2)
103
104def GetEntryArg(name):
105 """Get the value of an entry argument
106
107 Args:
108 name: Name of argument to retrieve
109
110 Returns:
111 String value of argument
112 """
113 return entry_args.get(name)
Simon Glassbdb40312018-09-14 04:57:20 -0600114
Simon Glass0c9d5b52018-09-14 04:57:22 -0600115def Prepare(images, dtb):
Simon Glassbdb40312018-09-14 04:57:20 -0600116 """Get device tree files ready for use
117
118 This sets up a set of device tree files that can be retrieved by GetFdts().
119 At present there is only one, that for U-Boot proper.
120
121 Args:
Simon Glass0c9d5b52018-09-14 04:57:22 -0600122 images: List of images being used
Simon Glassbdb40312018-09-14 04:57:20 -0600123 dtb: Main dtb
124 """
125 global fdt_set, fdt_subset, fdt_files, main_dtb
126 # Import these here in case libfdt.py is not available, in which case
127 # the above help option still works.
128 import fdt
129 import fdt_util
130
131 # If we are updating the DTBs we need to put these updated versions
132 # where Entry_blob_dtb can find them. We can ignore 'u-boot.dtb'
133 # since it is assumed to be the one passed in with options.dt, and
134 # was handled just above.
135 main_dtb = dtb
136 fdt_files.clear()
137 fdt_files['u-boot.dtb'] = dtb
Simon Glass4aea9542019-05-14 15:53:39 -0600138 fdt_subset = set()
Simon Glass0c9d5b52018-09-14 04:57:22 -0600139 if not use_fake_dtb:
140 for image in images.values():
141 fdt_subset.update(image.GetFdtSet())
142 fdt_subset.discard('u-boot.dtb')
143 for other_fname in fdt_subset:
144 infile = tools.GetInputFilename(other_fname)
145 other_fname_dtb = fdt_util.EnsureCompiled(infile)
146 out_fname = tools.GetOutputFilename('%s.out' %
147 os.path.split(other_fname)[1])
148 tools.WriteFile(out_fname, tools.ReadFile(other_fname_dtb))
149 other_dtb = fdt.FdtScan(out_fname)
150 fdt_files[other_fname] = other_dtb
Simon Glassbdb40312018-09-14 04:57:20 -0600151
152def GetFdts():
153 """Yield all device tree files being used by binman
154
155 Yields:
156 Device trees being used (U-Boot proper, SPL, TPL)
157 """
158 yield main_dtb
Simon Glasse219aa42018-09-14 04:57:24 -0600159 for other_fname in fdt_subset:
160 yield fdt_files[other_fname]
Simon Glassbdb40312018-09-14 04:57:20 -0600161
Simon Glassc8135dc2018-09-14 04:57:21 -0600162def GetUpdateNodes(node):
163 """Yield all the nodes that need to be updated in all device trees
164
165 The property referenced by this node is added to any device trees which
166 have the given node. Due to removable of unwanted notes, SPL and TPL may
167 not have this node.
168
169 Args:
170 node: Node object in the main device tree to look up
171
172 Yields:
173 Node objects in each device tree that is in use (U-Boot proper, which
174 is node, SPL and TPL)
175 """
176 yield node
Simon Glasse219aa42018-09-14 04:57:24 -0600177 for dtb in fdt_files.values():
178 if dtb != node.GetFdt():
179 other_node = dtb.GetNode(node.path)
180 if other_node:
181 yield other_node
Simon Glassc8135dc2018-09-14 04:57:21 -0600182
183def AddZeroProp(node, prop):
184 """Add a new property to affected device trees with an integer value of 0.
185
186 Args:
187 prop_name: Name of property
188 """
189 for n in GetUpdateNodes(node):
190 n.AddZeroProp(prop)
191
Simon Glassac6328c2018-09-14 04:57:28 -0600192def AddSubnode(node, name):
193 """Add a new subnode to a node in affected device trees
194
195 Args:
196 node: Node to add to
197 name: name of node to add
198
199 Returns:
200 New subnode that was created in main tree
201 """
202 first = None
203 for n in GetUpdateNodes(node):
204 subnode = n.AddSubnode(name)
205 if not first:
206 first = subnode
207 return first
208
209def AddString(node, prop, value):
210 """Add a new string property to affected device trees
211
212 Args:
213 prop_name: Name of property
214 value: String value (which will be \0-terminated in the DT)
215 """
216 for n in GetUpdateNodes(node):
217 n.AddString(prop, value)
218
Simon Glassc8135dc2018-09-14 04:57:21 -0600219def SetInt(node, prop, value):
220 """Update an integer property in affected device trees with an integer value
221
222 This is not allowed to change the size of the FDT.
223
224 Args:
225 prop_name: Name of property
226 """
227 for n in GetUpdateNodes(node):
228 n.SetInt(prop, value)
Simon Glassae7cf032018-09-14 04:57:31 -0600229
230def CheckAddHashProp(node):
231 hash_node = node.FindNode('hash')
232 if hash_node:
233 algo = hash_node.props.get('algo')
234 if not algo:
235 return "Missing 'algo' property for hash node"
236 if algo.value == 'sha256':
237 size = 32
238 else:
239 return "Unknown hash algorithm '%s'" % algo
240 for n in GetUpdateNodes(hash_node):
241 n.AddEmptyProp('value', size)
242
243def CheckSetHashValue(node, get_data_func):
244 hash_node = node.FindNode('hash')
245 if hash_node:
246 algo = hash_node.props.get('algo').value
247 if algo == 'sha256':
248 m = hashlib.sha256()
249 m.update(get_data_func())
250 data = m.digest()
251 for n in GetUpdateNodes(hash_node):
252 n.SetData('value', data)