blob: f890350a8d0451a1947d8773f4973ea1a140093a [file] [log] [blame]
Tom Rini10e47792018-05-06 17:58:06 -04001# SPDX-License-Identifier: GPL-2.0+
Simon Glass2574ef62016-11-25 20:15:51 -07002# Copyright (c) 2016 Google, Inc
3# Written by Simon Glass <sjg@chromium.org>
4#
Simon Glass2574ef62016-11-25 20:15:51 -07005# Class for an image, the output of binman
6#
7
Simon Glass4ca8e042017-11-13 18:55:01 -07008from __future__ import print_function
9
Simon Glass2574ef62016-11-25 20:15:51 -070010from collections import OrderedDict
11from operator import attrgetter
Simon Glass4ca8e042017-11-13 18:55:01 -070012import re
13import sys
Simon Glass2574ef62016-11-25 20:15:51 -070014
Simon Glassb8424fa2019-07-08 14:25:46 -060015from etype import fdtmap
16from etype import image_header
17import fdt
Simon Glass2574ef62016-11-25 20:15:51 -070018import fdt_util
Simon Glasseca32212018-06-01 09:38:12 -060019import bsection
Simon Glass2574ef62016-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 Glass2574ef62016-11-25 20:15:51 -070034 _filename: Output filename for image
Simon Glasseca32212018-06-01 09:38:12 -060035 _sections: Sections present in this image (may be one or more)
Simon Glass1e324002018-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 Glass2574ef62016-11-25 20:15:51 -070041 """
Simon Glass4ca8e042017-11-13 18:55:01 -070042 def __init__(self, name, node, test=False):
Simon Glass2574ef62016-11-25 20:15:51 -070043 self._node = node
44 self._name = name
45 self._size = None
Simon Glass2574ef62016-11-25 20:15:51 -070046 self._filename = '%s.bin' % self._name
Simon Glasseca32212018-06-01 09:38:12 -060047 if test:
Simon Glass7c767ad2018-09-14 04:57:33 -060048 self._section = bsection.Section('main-section', None, self._node,
49 self, True)
Simon Glasseca32212018-06-01 09:38:12 -060050 else:
Simon Glass4ca8e042017-11-13 18:55:01 -070051 self._ReadNode()
Simon Glass2574ef62016-11-25 20:15:51 -070052
Simon Glassb8424fa2019-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 Glass2574ef62016-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 Glass2574ef62016-11-25 20:15:51 -070091 filename = fdt_util.GetString(self._node, 'filename')
92 if filename:
93 self._filename = filename
Simon Glass7c767ad2018-09-14 04:57:33 -060094 self._section = bsection.Section('main-section', None, self._node, self)
Simon Glass2574ef62016-11-25 20:15:51 -070095
Simon Glasse61b6f62019-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 Glass0c9d5b52018-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 Glassac6328c2018-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 Glasse22f8fa2018-07-06 10:27:41 -0600113 def AddMissingProperties(self):
114 """Add properties that are not present in the device tree
115
Simon Glasse8561af2018-08-01 15:22:37 -0600116 When binman has completed packing the entries the offset and size of
Simon Glasse22f8fa2018-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 Glass92307732018-07-06 10:27:40 -0600124 def ProcessFdt(self, fdt):
Simon Glasse219aa42018-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 Glass92307732018-07-06 10:27:40 -0600130 return self._section.ProcessFdt(fdt)
131
Simon Glass2574ef62016-11-25 20:15:51 -0700132 def GetEntryContents(self):
Simon Glasseca32212018-06-01 09:38:12 -0600133 """Call ObtainContents() for the section
Simon Glass2574ef62016-11-25 20:15:51 -0700134 """
Simon Glasseca32212018-06-01 09:38:12 -0600135 self._section.GetEntryContents()
Simon Glass2574ef62016-11-25 20:15:51 -0700136
Simon Glasse8561af2018-08-01 15:22:37 -0600137 def GetEntryOffsets(self):
138 """Handle entries that want to set the offset/size of other entries
Simon Glass2574ef62016-11-25 20:15:51 -0700139
Simon Glasse8561af2018-08-01 15:22:37 -0600140 This calls each entry's GetOffsets() method. If it returns a list
Simon Glass2574ef62016-11-25 20:15:51 -0700141 of entries to update, it updates them.
142 """
Simon Glasse8561af2018-08-01 15:22:37 -0600143 self._section.GetEntryOffsets()
Simon Glass2574ef62016-11-25 20:15:51 -0700144
Simon Glasse61b6f62019-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 Glass2574ef62016-11-25 20:15:51 -0700149 def PackEntries(self):
150 """Pack all entries into the image"""
Simon Glasseca32212018-06-01 09:38:12 -0600151 self._section.PackEntries()
Simon Glass2574ef62016-11-25 20:15:51 -0700152
Simon Glasseca32212018-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 Glass2574ef62016-11-25 20:15:51 -0700156
157 def CheckEntries(self):
158 """Check that entries do not overlap or extend outside the image"""
Simon Glasseca32212018-06-01 09:38:12 -0600159 self._section.CheckEntries()
Simon Glass2574ef62016-11-25 20:15:51 -0700160
Simon Glasse22f8fa2018-07-06 10:27:41 -0600161 def SetCalculatedProperties(self):
162 self._section.SetCalculatedProperties()
163
Simon Glass9dcc8612018-08-01 15:22:42 -0600164 def SetImagePos(self):
165 self._section.SetImagePos(0)
166
Simon Glass2574ef62016-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 Glassec849852019-07-08 14:25:35 -0600171
172 Returns:
173 True if the new data size is OK, False if expansion is needed
Simon Glass2574ef62016-11-25 20:15:51 -0700174 """
Simon Glassec849852019-07-08 14:25:35 -0600175 return self._section.ProcessEntryContents()
Simon Glass2574ef62016-11-25 20:15:51 -0700176
Simon Glass4ca8e042017-11-13 18:55:01 -0700177 def WriteSymbols(self):
178 """Write symbol values into binary files for access at run time"""
Simon Glasseca32212018-06-01 09:38:12 -0600179 self._section.WriteSymbols()
Simon Glass4ca8e042017-11-13 18:55:01 -0700180
Simon Glass2574ef62016-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 Glasseca32212018-06-01 09:38:12 -0600185 self._section.BuildSection(fd, 0)
Simon Glass2574ef62016-11-25 20:15:51 -0700186
Simon Glasseca32212018-06-01 09:38:12 -0600187 def GetEntries(self):
188 return self._section.GetEntries()
Simon Glass30732662018-06-01 09:38:20 -0600189
190 def WriteMap(self):
Simon Glasscd817d52018-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 Glass30732662018-06-01 09:38:20 -0600196 filename = '%s.map' % self._name
197 fname = tools.GetOutputFilename(filename)
198 with open(fname, 'w') as fd:
Simon Glass7eca7922018-07-17 13:25:49 -0600199 print('%8s %8s %8s %s' % ('ImagePos', 'Offset', 'Size', 'Name'),
200 file=fd)
Simon Glass30732662018-06-01 09:38:20 -0600201 self._section.WriteMap(fd, 0)
Simon Glasscd817d52018-09-14 04:57:36 -0600202 return fname
Simon Glass6b156f82019-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