~funderscore blog cgit wiki get in touch
aboutsummaryrefslogtreecommitdiff
blob: f1f6217940f281e48176771022a6dde3a1371ee8 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
# SPDX-License-Identifier: GPL-2.0+
# Copyright (c) 2018 Google, Inc
# Written by Simon Glass <sjg@chromium.org>

"""# Entry-type module for a full map of the firmware image

This handles putting an FDT into the image with just the information about the
image.
"""

from binman.entry import Entry
from u_boot_pylib import tools
from u_boot_pylib import tout

FDTMAP_MAGIC   = b'_FDTMAP_'
FDTMAP_HDR_LEN = 16

# These is imported if needed
Fdt = None
libfdt = None
state = None

def LocateFdtmap(data):
    """Search an image for an fdt map

    Args:
        data: Data to search

    Returns:
        Position of fdt map in data, or None if not found. Note that the
            position returned is of the FDT header, i.e. before the FDT data
    """
    hdr_pos = data.find(FDTMAP_MAGIC)
    size = len(data)
    if hdr_pos != -1:
        hdr = data[hdr_pos:hdr_pos + FDTMAP_HDR_LEN]
        if len(hdr) == FDTMAP_HDR_LEN:
            return hdr_pos
    return None

class Entry_fdtmap(Entry):
    """An entry which contains an FDT map

    Properties / Entry arguments:
        None

    An FDT map is just a header followed by an FDT containing a list of all the
    entries in the image. The root node corresponds to the image node in the
    original FDT, and an image-name property indicates the image name in that
    original tree.

    The header is the string _FDTMAP_ followed by 8 unused bytes.

    When used, this entry will be populated with an FDT map which reflects the
    entries in the current image. Hierarchy is preserved, and all offsets and
    sizes are included.

    Note that the -u option must be provided to ensure that binman updates the
    FDT with the position of each entry.

    Example output for a simple image with U-Boot and an FDT map::

        / {
            image-name = "binman";
            size = <0x00000112>;
            image-pos = <0x00000000>;
            offset = <0x00000000>;
            u-boot {
                size = <0x00000004>;
                image-pos = <0x00000000>;
                offset = <0x00000000>;
            };
            fdtmap {
                size = <0x0000010e>;
                image-pos = <0x00000004>;
                offset = <0x00000004>;
            };
        };

    If allow-repack is used then 'orig-offset' and 'orig-size' properties are
    added as necessary. See the binman README.

    When extracting files, an alternative 'fdt' format is available for fdtmaps.
    Use `binman extract -F fdt ...` to use this. It will export a devicetree,
    without the fdtmap header, so it can be viewed with `fdtdump`.
    """
    def __init__(self, section, etype, node):
        # Put these here to allow entry-docs and help to work without libfdt
        global libfdt
        global state
        global Fdt

        import libfdt
        from binman import state
        from dtoc.fdt import Fdt

        super().__init__(section, etype, node)
        self.alt_formats = ['fdt']

    def CheckAltFormats(self, alt_formats):
        alt_formats['fdt'] = self, 'Extract the devicetree blob from the fdtmap'

    def _GetFdtmap(self):
        """Build an FDT map from the entries in the current image

        Returns:
            FDT map binary data
        """
        def _AddNode(node):
            """Add a node to the FDT map"""
            for pname, prop in node.props.items():
                fsw.property(pname, prop.bytes)
            for subnode in node.subnodes:
                with fsw.add_node(subnode.name):
                    _AddNode(subnode)

        data = state.GetFdtContents('fdtmap')[1]
        # If we have an fdtmap it means that we are using this as the
        # fdtmap for this image.
        if data is None:
            # Get the FDT data into an Fdt object
            data = state.GetFdtContents()[1]
            infdt = Fdt.FromData(data)
            infdt.Scan()

            # Find the node for the image containing the Fdt-map entry
            path = self.section.GetPath()
            self.Detail("Fdtmap: Using section '%s' (path '%s')" %
                        (self.section.name, path))
            node = infdt.GetNode(path)
            if not node:
                self.Raise("Internal error: Cannot locate node for path '%s'" %
                           path)

            # Build a new tree with all nodes and properties starting from that
            # node
            fsw = libfdt.FdtSw()
            fsw.finish_reservemap()
            with fsw.add_node(''):
                fsw.property_string('image-node', node.name)
                _AddNode(node)
            fdt = fsw.as_fdt()

            # Pack this new FDT and return its contents
            fdt.pack()
            outfdt = Fdt.FromData(fdt.as_bytearray())
            data = outfdt.GetContents()
        data = FDTMAP_MAGIC + tools.get_bytes(0, 8) + data
        return data

    def ObtainContents(self):
        """Obtain a placeholder for the fdt-map contents"""
        self.SetContents(self._GetFdtmap())
        return True

    def ProcessContents(self):
        """Write an updated version of the FDT map to this entry

        This is necessary since new data may have been written back to it during
        processing, e.g. the image-pos properties.
        """
        return self.ProcessContentsUpdate(self._GetFdtmap())

    def GetAltFormat(self, data, alt_format):
        if alt_format == 'fdt':
            return data[FDTMAP_HDR_LEN:]