blob: f890350a8d0451a1947d8773f4973ea1a140093a [file] [log] [blame]
Tom Rini83d290c2018-05-06 17:58:06 -04001# SPDX-License-Identifier: GPL-2.0+
Simon Glassbf7fd502016-11-25 20:15:51 -07002# Copyright (c) 2016 Google, Inc
3# Written by Simon Glass <sjg@chromium.org>
4#
Simon Glassbf7fd502016-11-25 20:15:51 -07005# Class for an image, the output of binman
6#
7
Simon Glass19790632017-11-13 18:55:01 -07008from __future__ import print_function
9
Simon Glassbf7fd502016-11-25 20:15:51 -070010from collections import OrderedDict
11from operator import attrgetter
Simon Glass19790632017-11-13 18:55:01 -070012import re
13import sys
Simon Glassbf7fd502016-11-25 20:15:51 -070014
Simon Glassffded752019-07-08 14:25:46 -060015from etype import fdtmap
16from etype import image_header
17import fdt
Simon Glassbf7fd502016-11-25 20:15:51 -070018import fdt_util
Simon Glass8f1da502018-06-01 09:38:12 -060019import bsection
Simon Glassbf7fd502016-11-25 20:15:51 -070020import tools
21
22class Image:
23 """A Image, representing an output from binman
24
25 An image is comprised of a collection of entries each containing binary
26 data. The image size must be large enough to hold all of this data.
27
28 This class implements the various operations needed for images.
29
30 Atrtributes:
31 _node: Node object that contains the image definition in device tree
32 _name: Image name
33 _size: Image size in bytes, or None if not known yet
Simon Glassbf7fd502016-11-25 20:15:51 -070034 _filename: Output filename for image
Simon Glass8f1da502018-06-01 09:38:12 -060035 _sections: Sections present in this image (may be one or more)
Simon Glass7ae5f312018-06-01 09:38:19 -060036
37 Args:
38 test: True if this is being called from a test of Images. This this case
39 there is no device tree defining the structure of the section, so
40 we create a section manually.
Simon Glassbf7fd502016-11-25 20:15:51 -070041 """
Simon Glass19790632017-11-13 18:55:01 -070042 def __init__(self, name, node, test=False):
Simon Glassbf7fd502016-11-25 20:15:51 -070043 self._node = node
44 self._name = name
45 self._size = None
Simon Glassbf7fd502016-11-25 20:15:51 -070046 self._filename = '%s.bin' % self._name
Simon Glass8f1da502018-06-01 09:38:12 -060047 if test:
Simon Glass08723a72018-09-14 04:57:33 -060048 self._section = bsection.Section('main-section', None, self._node,
49 self, True)
Simon Glass8f1da502018-06-01 09:38:12 -060050 else:
Simon Glass19790632017-11-13 18:55:01 -070051 self._ReadNode()
Simon Glassbf7fd502016-11-25 20:15:51 -070052
Simon Glassffded752019-07-08 14:25:46 -060053 @classmethod
54 def FromFile(cls, fname):
55 """Convert an image file into an Image for use in binman
56
57 Args:
58 fname: Filename of image file to read
59
60 Returns:
61 Image object on success
62
63 Raises:
64 ValueError if something goes wrong
65 """
66 data = tools.ReadFile(fname)
67 size = len(data)
68
69 # First look for an image header
70 pos = image_header.LocateHeaderOffset(data)
71 if pos is None:
72 # Look for the FDT map
73 pos = fdtmap.LocateFdtmap(data)
74 if pos is None:
75 raise ValueError('Cannot find FDT map in image')
76
77 # We don't know the FDT size, so check its header first
78 probe_dtb = fdt.Fdt.FromData(
79 data[pos + fdtmap.FDTMAP_HDR_LEN:pos + 256])
80 dtb_size = probe_dtb.GetFdtObj().totalsize()
81 fdtmap_data = data[pos:pos + dtb_size + fdtmap.FDTMAP_HDR_LEN]
82 dtb = fdt.Fdt.FromData(fdtmap_data[fdtmap.FDTMAP_HDR_LEN:])
83 dtb.Scan()
84
85 # Return an Image with the associated nodes
86 return Image('image', dtb.GetRoot())
87
Simon Glassbf7fd502016-11-25 20:15:51 -070088 def _ReadNode(self):
89 """Read properties from the image node"""
90 self._size = fdt_util.GetInt(self._node, 'size')
Simon Glassbf7fd502016-11-25 20:15:51 -070091 filename = fdt_util.GetString(self._node, 'filename')
92 if filename:
93 self._filename = filename
Simon Glass08723a72018-09-14 04:57:33 -060094 self._section = bsection.Section('main-section', None, self._node, self)
Simon Glassbf7fd502016-11-25 20:15:51 -070095
Simon Glassc52c9e72019-07-08 14:25:37 -060096 def Raise(self, msg):
97 """Convenience function to raise an error referencing an image"""
98 raise ValueError("Image '%s': %s" % (self._node.path, msg))
99
Simon Glass539aece2018-09-14 04:57:22 -0600100 def GetFdtSet(self):
101 """Get the set of device tree files used by this image"""
102 return self._section.GetFdtSet()
103
Simon Glass0a98b282018-09-14 04:57:28 -0600104 def ExpandEntries(self):
105 """Expand out any entries which have calculated sub-entries
106
107 Some entries are expanded out at runtime, e.g. 'files', which produces
108 a section containing a list of files. Process these entries so that
109 this information is added to the device tree.
110 """
111 self._section.ExpandEntries()
112
Simon Glass078ab1a2018-07-06 10:27:41 -0600113 def AddMissingProperties(self):
114 """Add properties that are not present in the device tree
115
Simon Glass3ab95982018-08-01 15:22:37 -0600116 When binman has completed packing the entries the offset and size of
Simon Glass078ab1a2018-07-06 10:27:41 -0600117 each entry are known. But before this the device tree may not specify
118 these. Add any missing properties, with a dummy value, so that the
119 size of the entry is correct. That way we can insert the correct values
120 later.
121 """
122 self._section.AddMissingProperties()
123
Simon Glassecab8972018-07-06 10:27:40 -0600124 def ProcessFdt(self, fdt):
Simon Glass6ed45ba2018-09-14 04:57:24 -0600125 """Allow entries to adjust the device tree
126
127 Some entries need to adjust the device tree for their purposes. This
128 may involve adding or deleting properties.
129 """
Simon Glassecab8972018-07-06 10:27:40 -0600130 return self._section.ProcessFdt(fdt)
131
Simon Glassbf7fd502016-11-25 20:15:51 -0700132 def GetEntryContents(self):
Simon Glass8f1da502018-06-01 09:38:12 -0600133 """Call ObtainContents() for the section
Simon Glassbf7fd502016-11-25 20:15:51 -0700134 """
Simon Glass8f1da502018-06-01 09:38:12 -0600135 self._section.GetEntryContents()
Simon Glassbf7fd502016-11-25 20:15:51 -0700136
Simon Glass3ab95982018-08-01 15:22:37 -0600137 def GetEntryOffsets(self):
138 """Handle entries that want to set the offset/size of other entries
Simon Glassbf7fd502016-11-25 20:15:51 -0700139
Simon Glass3ab95982018-08-01 15:22:37 -0600140 This calls each entry's GetOffsets() method. If it returns a list
Simon Glassbf7fd502016-11-25 20:15:51 -0700141 of entries to update, it updates them.
142 """
Simon Glass3ab95982018-08-01 15:22:37 -0600143 self._section.GetEntryOffsets()
Simon Glassbf7fd502016-11-25 20:15:51 -0700144
Simon Glassc52c9e72019-07-08 14:25:37 -0600145 def ResetForPack(self):
146 """Reset offset/size fields so that packing can be done again"""
147 self._section.ResetForPack()
148
Simon Glassbf7fd502016-11-25 20:15:51 -0700149 def PackEntries(self):
150 """Pack all entries into the image"""
Simon Glass8f1da502018-06-01 09:38:12 -0600151 self._section.PackEntries()
Simon Glassbf7fd502016-11-25 20:15:51 -0700152
Simon Glass8f1da502018-06-01 09:38:12 -0600153 def CheckSize(self):
154 """Check that the image contents does not exceed its size, etc."""
155 self._size = self._section.CheckSize()
Simon Glassbf7fd502016-11-25 20:15:51 -0700156
157 def CheckEntries(self):
158 """Check that entries do not overlap or extend outside the image"""
Simon Glass8f1da502018-06-01 09:38:12 -0600159 self._section.CheckEntries()
Simon Glassbf7fd502016-11-25 20:15:51 -0700160
Simon Glass078ab1a2018-07-06 10:27:41 -0600161 def SetCalculatedProperties(self):
162 self._section.SetCalculatedProperties()
163
Simon Glassdbf6be92018-08-01 15:22:42 -0600164 def SetImagePos(self):
165 self._section.SetImagePos(0)
166
Simon Glassbf7fd502016-11-25 20:15:51 -0700167 def ProcessEntryContents(self):
168 """Call the ProcessContents() method for each entry
169
170 This is intended to adjust the contents as needed by the entry type.
Simon Glassa0dcaf22019-07-08 14:25:35 -0600171
172 Returns:
173 True if the new data size is OK, False if expansion is needed
Simon Glassbf7fd502016-11-25 20:15:51 -0700174 """
Simon Glassa0dcaf22019-07-08 14:25:35 -0600175 return self._section.ProcessEntryContents()
Simon Glassbf7fd502016-11-25 20:15:51 -0700176
Simon Glass19790632017-11-13 18:55:01 -0700177 def WriteSymbols(self):
178 """Write symbol values into binary files for access at run time"""
Simon Glass8f1da502018-06-01 09:38:12 -0600179 self._section.WriteSymbols()
Simon Glass19790632017-11-13 18:55:01 -0700180
Simon Glassbf7fd502016-11-25 20:15:51 -0700181 def BuildImage(self):
182 """Write the image to a file"""
183 fname = tools.GetOutputFilename(self._filename)
184 with open(fname, 'wb') as fd:
Simon Glass8f1da502018-06-01 09:38:12 -0600185 self._section.BuildSection(fd, 0)
Simon Glassbf7fd502016-11-25 20:15:51 -0700186
Simon Glass8f1da502018-06-01 09:38:12 -0600187 def GetEntries(self):
188 return self._section.GetEntries()
Simon Glass3b0c3822018-06-01 09:38:20 -0600189
190 def WriteMap(self):
Simon Glass163ed6c2018-09-14 04:57:36 -0600191 """Write a map of the image to a .map file
192
193 Returns:
194 Filename of map file written
195 """
Simon Glass3b0c3822018-06-01 09:38:20 -0600196 filename = '%s.map' % self._name
197 fname = tools.GetOutputFilename(filename)
198 with open(fname, 'w') as fd:
Simon Glass1be70d22018-07-17 13:25:49 -0600199 print('%8s %8s %8s %s' % ('ImagePos', 'Offset', 'Size', 'Name'),
200 file=fd)
Simon Glass3b0c3822018-06-01 09:38:20 -0600201 self._section.WriteMap(fd, 0)
Simon Glass163ed6c2018-09-14 04:57:36 -0600202 return fname
Simon Glass41b8ba02019-07-08 14:25:43 -0600203
204 def BuildEntryList(self):
205 """List the files in an image
206
207 Returns:
208 List of entry.EntryInfo objects describing all entries in the image
209 """
210 entries = []
211 self._section.ListEntries(entries, 0)
212 return entries