blob: 487290b6c4e840d17fef4ba7aa78114d64d4781c [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 Glass8beb11e2019-07-08 14:25:47 -060015from entry import Entry
Simon Glassffded752019-07-08 14:25:46 -060016from etype import fdtmap
17from etype import image_header
Simon Glass8beb11e2019-07-08 14:25:47 -060018from etype import section
Simon Glassffded752019-07-08 14:25:46 -060019import fdt
Simon Glassbf7fd502016-11-25 20:15:51 -070020import fdt_util
21import tools
22
Simon Glass8beb11e2019-07-08 14:25:47 -060023class Image(section.Entry_section):
Simon Glassbf7fd502016-11-25 20:15:51 -070024 """A Image, representing an output from binman
25
26 An image is comprised of a collection of entries each containing binary
27 data. The image size must be large enough to hold all of this data.
28
29 This class implements the various operations needed for images.
30
Simon Glass8beb11e2019-07-08 14:25:47 -060031 Attributes:
32 filename: Output filename for image
Simon Glass7ae5f312018-06-01 09:38:19 -060033
34 Args:
35 test: True if this is being called from a test of Images. This this case
36 there is no device tree defining the structure of the section, so
37 we create a section manually.
Simon Glassbf7fd502016-11-25 20:15:51 -070038 """
Simon Glass19790632017-11-13 18:55:01 -070039 def __init__(self, name, node, test=False):
Simon Glass8beb11e2019-07-08 14:25:47 -060040 self.image = self
41 section.Entry_section.__init__(self, None, 'section', node, test)
42 self.name = 'main-section'
43 self.image_name = name
44 self._filename = '%s.bin' % self.image_name
45 if not test:
46 filename = fdt_util.GetString(self._node, 'filename')
47 if filename:
48 self._filename = filename
Simon Glassbf7fd502016-11-25 20:15:51 -070049
Simon Glassffded752019-07-08 14:25:46 -060050 @classmethod
51 def FromFile(cls, fname):
52 """Convert an image file into an Image for use in binman
53
54 Args:
55 fname: Filename of image file to read
56
57 Returns:
58 Image object on success
59
60 Raises:
61 ValueError if something goes wrong
62 """
63 data = tools.ReadFile(fname)
64 size = len(data)
65
66 # First look for an image header
67 pos = image_header.LocateHeaderOffset(data)
68 if pos is None:
69 # Look for the FDT map
70 pos = fdtmap.LocateFdtmap(data)
71 if pos is None:
72 raise ValueError('Cannot find FDT map in image')
73
74 # We don't know the FDT size, so check its header first
75 probe_dtb = fdt.Fdt.FromData(
76 data[pos + fdtmap.FDTMAP_HDR_LEN:pos + 256])
77 dtb_size = probe_dtb.GetFdtObj().totalsize()
78 fdtmap_data = data[pos:pos + dtb_size + fdtmap.FDTMAP_HDR_LEN]
79 dtb = fdt.Fdt.FromData(fdtmap_data[fdtmap.FDTMAP_HDR_LEN:])
80 dtb.Scan()
81
82 # Return an Image with the associated nodes
83 return Image('image', dtb.GetRoot())
84
Simon Glassc52c9e72019-07-08 14:25:37 -060085 def Raise(self, msg):
86 """Convenience function to raise an error referencing an image"""
87 raise ValueError("Image '%s': %s" % (self._node.path, msg))
88
Simon Glassbf7fd502016-11-25 20:15:51 -070089 def PackEntries(self):
90 """Pack all entries into the image"""
Simon Glass8beb11e2019-07-08 14:25:47 -060091 section.Entry_section.Pack(self, 0)
Simon Glass078ab1a2018-07-06 10:27:41 -060092
Simon Glassdbf6be92018-08-01 15:22:42 -060093 def SetImagePos(self):
Simon Glass8beb11e2019-07-08 14:25:47 -060094 # This first section in the image so it starts at 0
95 section.Entry_section.SetImagePos(self, 0)
Simon Glassdbf6be92018-08-01 15:22:42 -060096
Simon Glassbf7fd502016-11-25 20:15:51 -070097 def ProcessEntryContents(self):
98 """Call the ProcessContents() method for each entry
99
100 This is intended to adjust the contents as needed by the entry type.
Simon Glassa0dcaf22019-07-08 14:25:35 -0600101
102 Returns:
103 True if the new data size is OK, False if expansion is needed
Simon Glassbf7fd502016-11-25 20:15:51 -0700104 """
Simon Glass8beb11e2019-07-08 14:25:47 -0600105 sizes_ok = True
106 for entry in self._entries.values():
107 if not entry.ProcessContents():
108 sizes_ok = False
109 print("Entry '%s' size change" % self._node.path)
110 return sizes_ok
Simon Glassbf7fd502016-11-25 20:15:51 -0700111
Simon Glass19790632017-11-13 18:55:01 -0700112 def WriteSymbols(self):
113 """Write symbol values into binary files for access at run time"""
Simon Glass8beb11e2019-07-08 14:25:47 -0600114 section.Entry_section.WriteSymbols(self, self)
115
116 def BuildSection(self, fd, base_offset):
117 """Write the section to a file"""
118 fd.seek(base_offset)
119 fd.write(self.GetData())
Simon Glass19790632017-11-13 18:55:01 -0700120
Simon Glassbf7fd502016-11-25 20:15:51 -0700121 def BuildImage(self):
122 """Write the image to a file"""
123 fname = tools.GetOutputFilename(self._filename)
124 with open(fname, 'wb') as fd:
Simon Glass8beb11e2019-07-08 14:25:47 -0600125 self.BuildSection(fd, 0)
Simon Glass3b0c3822018-06-01 09:38:20 -0600126
127 def WriteMap(self):
Simon Glass163ed6c2018-09-14 04:57:36 -0600128 """Write a map of the image to a .map file
129
130 Returns:
131 Filename of map file written
132 """
Simon Glass8beb11e2019-07-08 14:25:47 -0600133 filename = '%s.map' % self.image_name
Simon Glass3b0c3822018-06-01 09:38:20 -0600134 fname = tools.GetOutputFilename(filename)
135 with open(fname, 'w') as fd:
Simon Glass1be70d22018-07-17 13:25:49 -0600136 print('%8s %8s %8s %s' % ('ImagePos', 'Offset', 'Size', 'Name'),
137 file=fd)
Simon Glass8beb11e2019-07-08 14:25:47 -0600138 section.Entry_section.WriteMap(self, fd, 0)
Simon Glass163ed6c2018-09-14 04:57:36 -0600139 return fname
Simon Glass41b8ba02019-07-08 14:25:43 -0600140
141 def BuildEntryList(self):
142 """List the files in an image
143
144 Returns:
145 List of entry.EntryInfo objects describing all entries in the image
146 """
147 entries = []
Simon Glass8beb11e2019-07-08 14:25:47 -0600148 self.ListEntries(entries, 0)
Simon Glass41b8ba02019-07-08 14:25:43 -0600149 return entries