Merge branch 'master' of git://git.denx.de/u-boot-sh
[platform/kernel/u-boot.git] / tools / binman / etype / fdtmap.py
1 # SPDX-License-Identifier: GPL-2.0+
2 # Copyright (c) 2018 Google, Inc
3 # Written by Simon Glass <sjg@chromium.org>
4
5 """# Entry-type module for a full map of the firmware image
6
7 This handles putting an FDT into the image with just the information about the
8 image.
9 """
10
11 import libfdt
12
13 from entry import Entry
14 from fdt import Fdt
15 import state
16 import tools
17 import tout
18
19 FDTMAP_MAGIC   = b'_FDTMAP_'
20 FDTMAP_HDR_LEN = 16
21
22 def LocateFdtmap(data):
23     """Search an image for an fdt map
24
25     Args:
26         data: Data to search
27
28     Returns:
29         Position of fdt map in data, or None if not found. Note that the
30             position returned is of the FDT header, i.e. before the FDT data
31     """
32     hdr_pos = data.find(FDTMAP_MAGIC)
33     size = len(data)
34     if hdr_pos != -1:
35         hdr = data[hdr_pos:hdr_pos + FDTMAP_HDR_LEN]
36         if len(hdr) == FDTMAP_HDR_LEN:
37             return hdr_pos
38     return None
39
40 class Entry_fdtmap(Entry):
41     """An entry which contains an FDT map
42
43     Properties / Entry arguments:
44         None
45
46     An FDT map is just a header followed by an FDT containing a list of all the
47     entries in the image. The root node corresponds to the image node in the
48     original FDT, and an image-name property indicates the image name in that
49     original tree.
50
51     The header is the string _FDTMAP_ followed by 8 unused bytes.
52
53     When used, this entry will be populated with an FDT map which reflects the
54     entries in the current image. Hierarchy is preserved, and all offsets and
55     sizes are included.
56
57     Note that the -u option must be provided to ensure that binman updates the
58     FDT with the position of each entry.
59
60     Example output for a simple image with U-Boot and an FDT map:
61
62     / {
63         image-name = "binman";
64         size = <0x00000112>;
65         image-pos = <0x00000000>;
66         offset = <0x00000000>;
67         u-boot {
68             size = <0x00000004>;
69             image-pos = <0x00000000>;
70             offset = <0x00000000>;
71         };
72         fdtmap {
73             size = <0x0000010e>;
74             image-pos = <0x00000004>;
75             offset = <0x00000004>;
76         };
77     };
78
79     If allow-repack is used then 'orig-offset' and 'orig-size' properties are
80     added as necessary. See the binman README.
81     """
82     def __init__(self, section, etype, node):
83         Entry.__init__(self, section, etype, node)
84
85     def _GetFdtmap(self):
86         """Build an FDT map from the entries in the current image
87
88         Returns:
89             FDT map binary data
90         """
91         def _AddNode(node):
92             """Add a node to the FDT map"""
93             for pname, prop in node.props.items():
94                 fsw.property(pname, prop.bytes)
95             for subnode in node.subnodes:
96                 with fsw.add_node(subnode.name):
97                     _AddNode(subnode)
98
99         data = state.GetFdtContents('fdtmap')[1]
100         # If we have an fdtmap it means that we are using this as the
101         # fdtmap for this image.
102         if data is None:
103             # Get the FDT data into an Fdt object
104             data = state.GetFdtContents()[1]
105             infdt = Fdt.FromData(data)
106             infdt.Scan()
107
108             # Find the node for the image containing the Fdt-map entry
109             path = self.section.GetPath()
110             self.Detail("Fdtmap: Using section '%s' (path '%s')" %
111                         (self.section.name, path))
112             node = infdt.GetNode(path)
113             if not node:
114                 self.Raise("Internal error: Cannot locate node for path '%s'" %
115                            path)
116
117             # Build a new tree with all nodes and properties starting from that
118             # node
119             fsw = libfdt.FdtSw()
120             fsw.finish_reservemap()
121             with fsw.add_node(''):
122                 fsw.property_string('image-node', node.name)
123                 _AddNode(node)
124             fdt = fsw.as_fdt()
125
126             # Pack this new FDT and return its contents
127             fdt.pack()
128             outfdt = Fdt.FromData(fdt.as_bytearray())
129             data = outfdt.GetContents()
130         data = FDTMAP_MAGIC + tools.GetBytes(0, 8) + data
131         return data
132
133     def ObtainContents(self):
134         """Obtain a placeholder for the fdt-map contents"""
135         self.SetContents(self._GetFdtmap())
136         return True
137
138     def ProcessContents(self):
139         """Write an updated version of the FDT map to this entry
140
141         This is necessary since new data may have been written back to it during
142         processing, e.g. the image-pos properties.
143         """
144         return self.ProcessContentsUpdate(self._GetFdtmap())