blob: 46c1c8d613a417ab35e27607dee2c065d99c2fe9 [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
Simon Glass2be381d2019-07-20 12:23:32 -060014# 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.
17#
18# key: entry type
19# value: tuple:
20# Fdt object
21# Filename
22output_fdt_files = {}
Simon Glass29aa7362018-09-14 04:57:19 -060023
24# Arguments passed to binman to provide arguments to entries
25entry_args = {}
26
Simon Glass0c9d5b52018-09-14 04:57:22 -060027# True to use fake device-tree files for testing (see U_BOOT_DTB_DATA in
28# ftest.py)
Simon Glass31402012018-09-14 04:57:23 -060029use_fake_dtb = False
Simon Glass0c9d5b52018-09-14 04:57:22 -060030
Simon Glass132fa722019-07-20 12:23:33 -060031# Dict of device trees, keyed by entry type. These are the input device trees,
32# before any modification by U-Boot
Simon Glass684a4f12019-07-20 12:23:31 -060033# The value is as returned by Entry.GetFdts(), i.e. a tuple:
34# Fdt object for this dtb, or None if not available
35# Filename of file containing this dtb
Simon Glass132fa722019-07-20 12:23:33 -060036fdt_set = {}
Simon Glassbdb40312018-09-14 04:57:20 -060037
38# The DTB which contains the full image information
39main_dtb = None
40
Simon Glasscbc80e82019-07-08 14:25:36 -060041# Allow entries to expand after they have been packed. This is detected and
42# forces a re-pack. If not allowed, any attempted expansion causes an error in
43# Entry.ProcessContentsUpdate()
44allow_entry_expansion = True
45
Simon Glass2be381d2019-07-20 12:23:32 -060046def GetFdtForEtype(etype):
47 """Get the Fdt object for a particular device-tree entry
Simon Glass29aa7362018-09-14 04:57:19 -060048
49 Binman keeps track of at least one device-tree file called u-boot.dtb but
50 can also have others (e.g. for SPL). This function looks up the given
Simon Glass2be381d2019-07-20 12:23:32 -060051 entry and returns the associated Fdt object.
Simon Glass29aa7362018-09-14 04:57:19 -060052
53 Args:
Simon Glass2be381d2019-07-20 12:23:32 -060054 etype: Entry type of device tree (e.g. 'u-boot-dtb')
Simon Glass29aa7362018-09-14 04:57:19 -060055
56 Returns:
Simon Glass2be381d2019-07-20 12:23:32 -060057 Fdt object associated with the entry type
Simon Glass29aa7362018-09-14 04:57:19 -060058 """
Simon Glass2be381d2019-07-20 12:23:32 -060059 return output_fdt_files[etype][0]
Simon Glass29aa7362018-09-14 04:57:19 -060060
Simon Glass2be381d2019-07-20 12:23:32 -060061def GetFdtPath(etype):
Simon Glass29aa7362018-09-14 04:57:19 -060062 """Get the full pathname of a particular Fdt object
63
Simon Glassa3030a52019-07-20 12:23:30 -060064 Similar to GetFdtForEtype() but returns the pathname associated with the
65 Fdt.
Simon Glass29aa7362018-09-14 04:57:19 -060066
67 Args:
Simon Glass2be381d2019-07-20 12:23:32 -060068 etype: Entry type of device tree (e.g. 'u-boot-dtb')
Simon Glass29aa7362018-09-14 04:57:19 -060069
70 Returns:
71 Full path name to the associated Fdt
72 """
Simon Glass2be381d2019-07-20 12:23:32 -060073 return output_fdt_files[etype][0]._fname
Simon Glass29aa7362018-09-14 04:57:19 -060074
Simon Glass2be381d2019-07-20 12:23:32 -060075def GetFdtContents(etype='u-boot-dtb'):
Simon Glasse219aa42018-09-14 04:57:24 -060076 """Looks up the FDT pathname and contents
77
78 This is used to obtain the Fdt pathname and contents when needed by an
79 entry. It supports a 'fake' dtb, allowing tests to substitute test data for
80 the real dtb.
81
82 Args:
Simon Glass2be381d2019-07-20 12:23:32 -060083 etype: Entry type to look up (e.g. 'u-boot.dtb').
Simon Glasse219aa42018-09-14 04:57:24 -060084
85 Returns:
86 tuple:
87 pathname to Fdt
88 Fdt data (as bytes)
89 """
Simon Glass2be381d2019-07-20 12:23:32 -060090 if etype in output_fdt_files and not use_fake_dtb:
91 pathname = GetFdtPath(etype)
92 data = GetFdtForEtype(etype).GetContents()
Simon Glasse219aa42018-09-14 04:57:24 -060093 else:
Simon Glass2be381d2019-07-20 12:23:32 -060094 fname = output_fdt_files[etype][1]
Simon Glasse219aa42018-09-14 04:57:24 -060095 pathname = tools.GetInputFilename(fname)
96 data = tools.ReadFile(pathname)
97 return pathname, data
98
Simon Glass29aa7362018-09-14 04:57:19 -060099def SetEntryArgs(args):
100 """Set the value of the entry args
101
102 This sets up the entry_args dict which is used to supply entry arguments to
103 entries.
104
105 Args:
106 args: List of entry arguments, each in the format "name=value"
107 """
108 global entry_args
109
110 entry_args = {}
111 if args:
112 for arg in args:
113 m = re.match('([^=]*)=(.*)', arg)
114 if not m:
115 raise ValueError("Invalid entry arguemnt '%s'" % arg)
116 entry_args[m.group(1)] = m.group(2)
117
118def GetEntryArg(name):
119 """Get the value of an entry argument
120
121 Args:
122 name: Name of argument to retrieve
123
124 Returns:
125 String value of argument
126 """
127 return entry_args.get(name)
Simon Glassbdb40312018-09-14 04:57:20 -0600128
Simon Glass0c9d5b52018-09-14 04:57:22 -0600129def Prepare(images, dtb):
Simon Glassbdb40312018-09-14 04:57:20 -0600130 """Get device tree files ready for use
131
Simon Glass5a300602019-07-20 12:23:29 -0600132 This sets up a set of device tree files that can be retrieved by
133 GetAllFdts(). This includes U-Boot proper and any SPL device trees.
Simon Glassbdb40312018-09-14 04:57:20 -0600134
135 Args:
Simon Glass0c9d5b52018-09-14 04:57:22 -0600136 images: List of images being used
Simon Glassbdb40312018-09-14 04:57:20 -0600137 dtb: Main dtb
138 """
Simon Glass132fa722019-07-20 12:23:33 -0600139 global fdt_set, output_fdt_files, main_dtb
Simon Glassbdb40312018-09-14 04:57:20 -0600140 # Import these here in case libfdt.py is not available, in which case
141 # the above help option still works.
142 import fdt
143 import fdt_util
144
145 # If we are updating the DTBs we need to put these updated versions
146 # where Entry_blob_dtb can find them. We can ignore 'u-boot.dtb'
147 # since it is assumed to be the one passed in with options.dt, and
148 # was handled just above.
149 main_dtb = dtb
Simon Glass2be381d2019-07-20 12:23:32 -0600150 output_fdt_files.clear()
151 output_fdt_files['u-boot-dtb'] = [dtb, 'u-boot.dtb']
152 output_fdt_files['u-boot-spl-dtb'] = [dtb, 'spl/u-boot-spl.dtb']
153 output_fdt_files['u-boot-tpl-dtb'] = [dtb, 'tpl/u-boot-tpl.dtb']
Simon Glass132fa722019-07-20 12:23:33 -0600154 fdt_set = {}
Simon Glass0c9d5b52018-09-14 04:57:22 -0600155 if not use_fake_dtb:
156 for image in images.values():
Simon Glass132fa722019-07-20 12:23:33 -0600157 fdt_set.update(image.GetFdts())
158 for etype, other in fdt_set.items():
Simon Glass684a4f12019-07-20 12:23:31 -0600159 _, other_fname = other
Simon Glass0c9d5b52018-09-14 04:57:22 -0600160 infile = tools.GetInputFilename(other_fname)
161 other_fname_dtb = fdt_util.EnsureCompiled(infile)
162 out_fname = tools.GetOutputFilename('%s.out' %
163 os.path.split(other_fname)[1])
164 tools.WriteFile(out_fname, tools.ReadFile(other_fname_dtb))
165 other_dtb = fdt.FdtScan(out_fname)
Simon Glass2be381d2019-07-20 12:23:32 -0600166 output_fdt_files[etype] = [other_dtb, other_fname]
Simon Glassbdb40312018-09-14 04:57:20 -0600167
Simon Glass5a300602019-07-20 12:23:29 -0600168def GetAllFdts():
Simon Glassbdb40312018-09-14 04:57:20 -0600169 """Yield all device tree files being used by binman
170
171 Yields:
172 Device trees being used (U-Boot proper, SPL, TPL)
173 """
174 yield main_dtb
Simon Glass132fa722019-07-20 12:23:33 -0600175 for etype in fdt_set:
176 dtb = output_fdt_files[etype][0]
177 if dtb != main_dtb:
178 yield dtb
Simon Glassbdb40312018-09-14 04:57:20 -0600179
Simon Glassc8135dc2018-09-14 04:57:21 -0600180def GetUpdateNodes(node):
181 """Yield all the nodes that need to be updated in all device trees
182
183 The property referenced by this node is added to any device trees which
184 have the given node. Due to removable of unwanted notes, SPL and TPL may
185 not have this node.
186
187 Args:
188 node: Node object in the main device tree to look up
189
190 Yields:
191 Node objects in each device tree that is in use (U-Boot proper, which
192 is node, SPL and TPL)
193 """
194 yield node
Simon Glass2be381d2019-07-20 12:23:32 -0600195 for dtb, fname in output_fdt_files.values():
Simon Glasse219aa42018-09-14 04:57:24 -0600196 if dtb != node.GetFdt():
197 other_node = dtb.GetNode(node.path)
198 if other_node:
199 yield other_node
Simon Glassc8135dc2018-09-14 04:57:21 -0600200
201def AddZeroProp(node, prop):
202 """Add a new property to affected device trees with an integer value of 0.
203
204 Args:
205 prop_name: Name of property
206 """
207 for n in GetUpdateNodes(node):
208 n.AddZeroProp(prop)
209
Simon Glassac6328c2018-09-14 04:57:28 -0600210def AddSubnode(node, name):
211 """Add a new subnode to a node in affected device trees
212
213 Args:
214 node: Node to add to
215 name: name of node to add
216
217 Returns:
218 New subnode that was created in main tree
219 """
220 first = None
221 for n in GetUpdateNodes(node):
222 subnode = n.AddSubnode(name)
223 if not first:
224 first = subnode
225 return first
226
227def AddString(node, prop, value):
228 """Add a new string property to affected device trees
229
230 Args:
231 prop_name: Name of property
232 value: String value (which will be \0-terminated in the DT)
233 """
234 for n in GetUpdateNodes(node):
235 n.AddString(prop, value)
236
Simon Glassc8135dc2018-09-14 04:57:21 -0600237def SetInt(node, prop, value):
238 """Update an integer property in affected device trees with an integer value
239
240 This is not allowed to change the size of the FDT.
241
242 Args:
243 prop_name: Name of property
244 """
245 for n in GetUpdateNodes(node):
246 n.SetInt(prop, value)
Simon Glassae7cf032018-09-14 04:57:31 -0600247
248def CheckAddHashProp(node):
249 hash_node = node.FindNode('hash')
250 if hash_node:
251 algo = hash_node.props.get('algo')
252 if not algo:
253 return "Missing 'algo' property for hash node"
254 if algo.value == 'sha256':
255 size = 32
256 else:
257 return "Unknown hash algorithm '%s'" % algo
258 for n in GetUpdateNodes(hash_node):
259 n.AddEmptyProp('value', size)
260
261def CheckSetHashValue(node, get_data_func):
262 hash_node = node.FindNode('hash')
263 if hash_node:
264 algo = hash_node.props.get('algo').value
265 if algo == 'sha256':
266 m = hashlib.sha256()
267 m.update(get_data_func())
268 data = m.digest()
269 for n in GetUpdateNodes(hash_node):
270 n.SetData('value', data)
Simon Glasscbc80e82019-07-08 14:25:36 -0600271
272def SetAllowEntryExpansion(allow):
273 """Set whether post-pack expansion of entries is allowed
274
275 Args:
276 allow: True to allow expansion, False to raise an exception
277 """
278 global allow_entry_expansion
279
280 allow_entry_expansion = allow
281
282def AllowEntryExpansion():
283 """Check whether post-pack expansion of entries is allowed
284
285 Returns:
286 True if expansion should be allowed, False if an exception should be
287 raised
288 """
289 return allow_entry_expansion