xref: /openbmc/u-boot/tools/binman/state.py (revision d24c1d0f4da3b081a4fedf7ae2a08790871f08d0)
1c55a50f5SSimon Glass# SPDX-License-Identifier: GPL-2.0+
2c55a50f5SSimon Glass# Copyright 2018 Google, Inc
3c55a50f5SSimon Glass# Written by Simon Glass <sjg@chromium.org>
4c55a50f5SSimon Glass#
5c55a50f5SSimon Glass# Holds and modifies the state information held by binman
6c55a50f5SSimon Glass#
7c55a50f5SSimon Glass
8*e0e5df93SSimon Glassimport hashlib
9c55a50f5SSimon Glassimport re
10c55a50f5SSimon Glassfrom sets import Set
11c55a50f5SSimon Glass
12c55a50f5SSimon Glassimport os
13c55a50f5SSimon Glassimport tools
14c55a50f5SSimon Glass
15c55a50f5SSimon Glass# Records the device-tree files known to binman, keyed by filename (e.g.
16c55a50f5SSimon Glass# 'u-boot-spl.dtb')
17c55a50f5SSimon Glassfdt_files = {}
18c55a50f5SSimon Glass
19c55a50f5SSimon Glass# Arguments passed to binman to provide arguments to entries
20c55a50f5SSimon Glassentry_args = {}
21c55a50f5SSimon Glass
22539aece5SSimon Glass# True to use fake device-tree files for testing (see U_BOOT_DTB_DATA in
23539aece5SSimon Glass# ftest.py)
2493d17413SSimon Glassuse_fake_dtb = False
25539aece5SSimon Glass
262a72cc72SSimon Glass# Set of all device tree files references by images
272a72cc72SSimon Glassfdt_set = Set()
282a72cc72SSimon Glass
292a72cc72SSimon Glass# Same as above, but excluding the main one
302a72cc72SSimon Glassfdt_subset = Set()
312a72cc72SSimon Glass
322a72cc72SSimon Glass# The DTB which contains the full image information
332a72cc72SSimon Glassmain_dtb = None
342a72cc72SSimon Glass
35c55a50f5SSimon Glassdef GetFdt(fname):
36c55a50f5SSimon Glass    """Get the Fdt object for a particular device-tree filename
37c55a50f5SSimon Glass
38c55a50f5SSimon Glass    Binman keeps track of at least one device-tree file called u-boot.dtb but
39c55a50f5SSimon Glass    can also have others (e.g. for SPL). This function looks up the given
40c55a50f5SSimon Glass    filename and returns the associated Fdt object.
41c55a50f5SSimon Glass
42c55a50f5SSimon Glass    Args:
43c55a50f5SSimon Glass        fname: Filename to look up (e.g. 'u-boot.dtb').
44c55a50f5SSimon Glass
45c55a50f5SSimon Glass    Returns:
46c55a50f5SSimon Glass        Fdt object associated with the filename
47c55a50f5SSimon Glass    """
48c55a50f5SSimon Glass    return fdt_files[fname]
49c55a50f5SSimon Glass
50c55a50f5SSimon Glassdef GetFdtPath(fname):
51c55a50f5SSimon Glass    """Get the full pathname of a particular Fdt object
52c55a50f5SSimon Glass
53c55a50f5SSimon Glass    Similar to GetFdt() but returns the pathname associated with the Fdt.
54c55a50f5SSimon Glass
55c55a50f5SSimon Glass    Args:
56c55a50f5SSimon Glass        fname: Filename to look up (e.g. 'u-boot.dtb').
57c55a50f5SSimon Glass
58c55a50f5SSimon Glass    Returns:
59c55a50f5SSimon Glass        Full path name to the associated Fdt
60c55a50f5SSimon Glass    """
61c55a50f5SSimon Glass    return fdt_files[fname]._fname
62c55a50f5SSimon Glass
636ed45ba0SSimon Glassdef GetFdtContents(fname):
646ed45ba0SSimon Glass    """Looks up the FDT pathname and contents
656ed45ba0SSimon Glass
666ed45ba0SSimon Glass    This is used to obtain the Fdt pathname and contents when needed by an
676ed45ba0SSimon Glass    entry. It supports a 'fake' dtb, allowing tests to substitute test data for
686ed45ba0SSimon Glass    the real dtb.
696ed45ba0SSimon Glass
706ed45ba0SSimon Glass    Args:
716ed45ba0SSimon Glass        fname: Filename to look up (e.g. 'u-boot.dtb').
726ed45ba0SSimon Glass
736ed45ba0SSimon Glass    Returns:
746ed45ba0SSimon Glass        tuple:
756ed45ba0SSimon Glass            pathname to Fdt
766ed45ba0SSimon Glass            Fdt data (as bytes)
776ed45ba0SSimon Glass    """
786ed45ba0SSimon Glass    if fname in fdt_files and not use_fake_dtb:
796ed45ba0SSimon Glass        pathname = GetFdtPath(fname)
806ed45ba0SSimon Glass        data = GetFdt(fname).GetContents()
816ed45ba0SSimon Glass    else:
826ed45ba0SSimon Glass        pathname = tools.GetInputFilename(fname)
836ed45ba0SSimon Glass        data = tools.ReadFile(pathname)
846ed45ba0SSimon Glass    return pathname, data
856ed45ba0SSimon Glass
86c55a50f5SSimon Glassdef SetEntryArgs(args):
87c55a50f5SSimon Glass    """Set the value of the entry args
88c55a50f5SSimon Glass
89c55a50f5SSimon Glass    This sets up the entry_args dict which is used to supply entry arguments to
90c55a50f5SSimon Glass    entries.
91c55a50f5SSimon Glass
92c55a50f5SSimon Glass    Args:
93c55a50f5SSimon Glass        args: List of entry arguments, each in the format "name=value"
94c55a50f5SSimon Glass    """
95c55a50f5SSimon Glass    global entry_args
96c55a50f5SSimon Glass
97c55a50f5SSimon Glass    entry_args = {}
98c55a50f5SSimon Glass    if args:
99c55a50f5SSimon Glass        for arg in args:
100c55a50f5SSimon Glass            m = re.match('([^=]*)=(.*)', arg)
101c55a50f5SSimon Glass            if not m:
102c55a50f5SSimon Glass                raise ValueError("Invalid entry arguemnt '%s'" % arg)
103c55a50f5SSimon Glass            entry_args[m.group(1)] = m.group(2)
104c55a50f5SSimon Glass
105c55a50f5SSimon Glassdef GetEntryArg(name):
106c55a50f5SSimon Glass    """Get the value of an entry argument
107c55a50f5SSimon Glass
108c55a50f5SSimon Glass    Args:
109c55a50f5SSimon Glass        name: Name of argument to retrieve
110c55a50f5SSimon Glass
111c55a50f5SSimon Glass    Returns:
112c55a50f5SSimon Glass        String value of argument
113c55a50f5SSimon Glass    """
114c55a50f5SSimon Glass    return entry_args.get(name)
1152a72cc72SSimon Glass
116539aece5SSimon Glassdef Prepare(images, dtb):
1172a72cc72SSimon Glass    """Get device tree files ready for use
1182a72cc72SSimon Glass
1192a72cc72SSimon Glass    This sets up a set of device tree files that can be retrieved by GetFdts().
1202a72cc72SSimon Glass    At present there is only one, that for U-Boot proper.
1212a72cc72SSimon Glass
1222a72cc72SSimon Glass    Args:
123539aece5SSimon Glass        images: List of images being used
1242a72cc72SSimon Glass        dtb: Main dtb
1252a72cc72SSimon Glass    """
1262a72cc72SSimon Glass    global fdt_set, fdt_subset, fdt_files, main_dtb
1272a72cc72SSimon Glass    # Import these here in case libfdt.py is not available, in which case
1282a72cc72SSimon Glass    # the above help option still works.
1292a72cc72SSimon Glass    import fdt
1302a72cc72SSimon Glass    import fdt_util
1312a72cc72SSimon Glass
1322a72cc72SSimon Glass    # If we are updating the DTBs we need to put these updated versions
1332a72cc72SSimon Glass    # where Entry_blob_dtb can find them. We can ignore 'u-boot.dtb'
1342a72cc72SSimon Glass    # since it is assumed to be the one passed in with options.dt, and
1352a72cc72SSimon Glass    # was handled just above.
1362a72cc72SSimon Glass    main_dtb = dtb
1372a72cc72SSimon Glass    fdt_files.clear()
1382a72cc72SSimon Glass    fdt_files['u-boot.dtb'] = dtb
1392a72cc72SSimon Glass    fdt_subset = Set()
140539aece5SSimon Glass    if not use_fake_dtb:
141539aece5SSimon Glass        for image in images.values():
142539aece5SSimon Glass            fdt_subset.update(image.GetFdtSet())
143539aece5SSimon Glass        fdt_subset.discard('u-boot.dtb')
144539aece5SSimon Glass        for other_fname in fdt_subset:
145539aece5SSimon Glass            infile = tools.GetInputFilename(other_fname)
146539aece5SSimon Glass            other_fname_dtb = fdt_util.EnsureCompiled(infile)
147539aece5SSimon Glass            out_fname = tools.GetOutputFilename('%s.out' %
148539aece5SSimon Glass                    os.path.split(other_fname)[1])
149539aece5SSimon Glass            tools.WriteFile(out_fname, tools.ReadFile(other_fname_dtb))
150539aece5SSimon Glass            other_dtb = fdt.FdtScan(out_fname)
151539aece5SSimon Glass            fdt_files[other_fname] = other_dtb
1522a72cc72SSimon Glass
1532a72cc72SSimon Glassdef GetFdts():
1542a72cc72SSimon Glass    """Yield all device tree files being used by binman
1552a72cc72SSimon Glass
1562a72cc72SSimon Glass    Yields:
1572a72cc72SSimon Glass        Device trees being used (U-Boot proper, SPL, TPL)
1582a72cc72SSimon Glass    """
1592a72cc72SSimon Glass    yield main_dtb
1606ed45ba0SSimon Glass    for other_fname in fdt_subset:
1616ed45ba0SSimon Glass        yield fdt_files[other_fname]
1622a72cc72SSimon Glass
163f46621d2SSimon Glassdef GetUpdateNodes(node):
164f46621d2SSimon Glass    """Yield all the nodes that need to be updated in all device trees
165f46621d2SSimon Glass
166f46621d2SSimon Glass    The property referenced by this node is added to any device trees which
167f46621d2SSimon Glass    have the given node. Due to removable of unwanted notes, SPL and TPL may
168f46621d2SSimon Glass    not have this node.
169f46621d2SSimon Glass
170f46621d2SSimon Glass    Args:
171f46621d2SSimon Glass        node: Node object in the main device tree to look up
172f46621d2SSimon Glass
173f46621d2SSimon Glass    Yields:
174f46621d2SSimon Glass        Node objects in each device tree that is in use (U-Boot proper, which
175f46621d2SSimon Glass            is node, SPL and TPL)
176f46621d2SSimon Glass    """
177f46621d2SSimon Glass    yield node
1786ed45ba0SSimon Glass    for dtb in fdt_files.values():
1796ed45ba0SSimon Glass        if dtb != node.GetFdt():
1806ed45ba0SSimon Glass            other_node = dtb.GetNode(node.path)
1816ed45ba0SSimon Glass            if other_node:
1826ed45ba0SSimon Glass                yield other_node
183f46621d2SSimon Glass
184f46621d2SSimon Glassdef AddZeroProp(node, prop):
185f46621d2SSimon Glass    """Add a new property to affected device trees with an integer value of 0.
186f46621d2SSimon Glass
187f46621d2SSimon Glass    Args:
188f46621d2SSimon Glass        prop_name: Name of property
189f46621d2SSimon Glass    """
190f46621d2SSimon Glass    for n in GetUpdateNodes(node):
191f46621d2SSimon Glass        n.AddZeroProp(prop)
192f46621d2SSimon Glass
1930a98b28bSSimon Glassdef AddSubnode(node, name):
1940a98b28bSSimon Glass    """Add a new subnode to a node in affected device trees
1950a98b28bSSimon Glass
1960a98b28bSSimon Glass    Args:
1970a98b28bSSimon Glass        node: Node to add to
1980a98b28bSSimon Glass        name: name of node to add
1990a98b28bSSimon Glass
2000a98b28bSSimon Glass    Returns:
2010a98b28bSSimon Glass        New subnode that was created in main tree
2020a98b28bSSimon Glass    """
2030a98b28bSSimon Glass    first = None
2040a98b28bSSimon Glass    for n in GetUpdateNodes(node):
2050a98b28bSSimon Glass        subnode = n.AddSubnode(name)
2060a98b28bSSimon Glass        if not first:
2070a98b28bSSimon Glass            first = subnode
2080a98b28bSSimon Glass    return first
2090a98b28bSSimon Glass
2100a98b28bSSimon Glassdef AddString(node, prop, value):
2110a98b28bSSimon Glass    """Add a new string property to affected device trees
2120a98b28bSSimon Glass
2130a98b28bSSimon Glass    Args:
2140a98b28bSSimon Glass        prop_name: Name of property
2150a98b28bSSimon Glass        value: String value (which will be \0-terminated in the DT)
2160a98b28bSSimon Glass    """
2170a98b28bSSimon Glass    for n in GetUpdateNodes(node):
2180a98b28bSSimon Glass        n.AddString(prop, value)
2190a98b28bSSimon Glass
220f46621d2SSimon Glassdef SetInt(node, prop, value):
221f46621d2SSimon Glass    """Update an integer property in affected device trees with an integer value
222f46621d2SSimon Glass
223f46621d2SSimon Glass    This is not allowed to change the size of the FDT.
224f46621d2SSimon Glass
225f46621d2SSimon Glass    Args:
226f46621d2SSimon Glass        prop_name: Name of property
227f46621d2SSimon Glass    """
228f46621d2SSimon Glass    for n in GetUpdateNodes(node):
229f46621d2SSimon Glass        n.SetInt(prop, value)
230*e0e5df93SSimon Glass
231*e0e5df93SSimon Glassdef CheckAddHashProp(node):
232*e0e5df93SSimon Glass    hash_node = node.FindNode('hash')
233*e0e5df93SSimon Glass    if hash_node:
234*e0e5df93SSimon Glass        algo = hash_node.props.get('algo')
235*e0e5df93SSimon Glass        if not algo:
236*e0e5df93SSimon Glass            return "Missing 'algo' property for hash node"
237*e0e5df93SSimon Glass        if algo.value == 'sha256':
238*e0e5df93SSimon Glass            size = 32
239*e0e5df93SSimon Glass        else:
240*e0e5df93SSimon Glass            return "Unknown hash algorithm '%s'" % algo
241*e0e5df93SSimon Glass        for n in GetUpdateNodes(hash_node):
242*e0e5df93SSimon Glass            n.AddEmptyProp('value', size)
243*e0e5df93SSimon Glass
244*e0e5df93SSimon Glassdef CheckSetHashValue(node, get_data_func):
245*e0e5df93SSimon Glass    hash_node = node.FindNode('hash')
246*e0e5df93SSimon Glass    if hash_node:
247*e0e5df93SSimon Glass        algo = hash_node.props.get('algo').value
248*e0e5df93SSimon Glass        if algo == 'sha256':
249*e0e5df93SSimon Glass            m = hashlib.sha256()
250*e0e5df93SSimon Glass            m.update(get_data_func())
251*e0e5df93SSimon Glass            data = m.digest()
252*e0e5df93SSimon Glass        for n in GetUpdateNodes(hash_node):
253*e0e5df93SSimon Glass            n.SetData('value', data)
254