1# SPDX-License-Identifier: GPL-2.0+
2# Copyright (c) 2016 Google, Inc
3# Written by Simon Glass <sjg@chromium.org>
4#
5# Entry-type module for Intel Management Engine binary blob
6#
7
8from collections import OrderedDict
9
10from binman.entry import Entry
11from binman.etype.blob_ext import Entry_blob_ext
12from dtoc import fdt_util
13from u_boot_pylib import tools
14
15class Entry_intel_ifwi(Entry_blob_ext):
16    """Intel Integrated Firmware Image (IFWI) file
17
18    Properties / Entry arguments:
19        - filename: Filename of file to read into entry. This is either the
20            IFWI file itself, or a file that can be converted into one using a
21            tool
22        - convert-fit: If present this indicates that the ifwitool should be
23            used to convert the provided file into a IFWI.
24
25    This file contains code and data used by the SoC that is required to make
26    it work. It includes U-Boot TPL, microcode, things related to the CSE
27    (Converged Security Engine, the microcontroller that loads all the firmware)
28    and other items beyond the wit of man.
29
30    A typical filename is 'ifwi.bin' for an IFWI file, or 'fitimage.bin' for a
31    file that will be converted to an IFWI.
32
33    The position of this entry is generally set by the intel-descriptor entry.
34
35    The contents of the IFWI are specified by the subnodes of the IFWI node.
36    Each subnode describes an entry which is placed into the IFWFI with a given
37    sub-partition (and optional entry name).
38
39    Properties for subnodes:
40        - ifwi-subpart: sub-parition to put this entry into, e.g. "IBBP"
41        - ifwi-entry: entry name t use, e.g. "IBBL"
42        - ifwi-replace: if present, indicates that the item should be replaced
43          in the IFWI. Otherwise it is added.
44
45    See README.x86 for information about x86 binary blobs.
46    """
47    def __init__(self, section, etype, node):
48        super().__init__(section, etype, node)
49        self._convert_fit = fdt_util.GetBool(self._node, 'convert-fit')
50        self._ifwi_entries = OrderedDict()
51
52    def ReadNode(self):
53        self.ReadEntries()
54        super().ReadNode()
55
56    def _BuildIfwi(self):
57        """Build the contents of the IFWI and write it to the 'data' property"""
58        # Create the IFWI file if needed
59        if self._convert_fit:
60            inname = self._pathname
61            outname = tools.get_output_filename('ifwi.bin')
62            if self.ifwitool.create_ifwi(inname, outname) is None:
63                # Bintool is missing; just create a zeroed ifwi.bin
64                self.record_missing_bintool(self.ifwitool)
65                self.SetContents(tools.get_bytes(0, 1024))
66
67            self._filename = 'ifwi.bin'
68            self._pathname = outname
69        else:
70            # Provide a different code path here to ensure we have test coverage
71            outname = self._pathname
72
73        # Delete OBBP if it is there, then add the required new items
74        if self.ifwitool.delete_subpart(outname, 'OBBP') is None:
75            # Bintool is missing; just use zero data
76            self.record_missing_bintool(self.ifwitool)
77            self.SetContents(tools.get_bytes(0, 1024))
78            return True
79
80        for entry in self._ifwi_entries.values():
81            # First get the input data and put it in a file
82            data = entry.GetPaddedData()
83            uniq = self.GetUniqueName()
84            input_fname = tools.get_output_filename('input.%s' % uniq)
85            tools.write_file(input_fname, data)
86
87            # At this point we know that ifwitool is present, so we don't need
88            # to check for None here
89            self.ifwitool.add_subpart(
90                outname, entry._ifwi_subpart, entry._ifwi_entry_name,
91                input_fname, entry._ifwi_replace)
92
93        self.ReadBlobContents()
94        return True
95
96    def ObtainContents(self):
97        """Get the contents for the IFWI
98
99        Unfortunately we cannot create anything from scratch here, as Intel has
100        tools which create precursor binaries with lots of data and settings,
101        and these are not incorporated into binman.
102
103        The first step is to get a file in the IFWI format. This is either
104        supplied directly or is extracted from a fitimage using the 'create'
105        subcommand.
106
107        After that we delete the OBBP sub-partition and add each of the files
108        that we want in the IFWI file, one for each sub-entry of the IWFI node.
109        """
110        self._pathname = tools.get_input_filename(self._filename,
111                                                self.section.GetAllowMissing())
112        # Allow the file to be missing
113        if not self._pathname:
114            self.SetContents(b'')
115            self.missing = True
116            return True
117        for entry in self._ifwi_entries.values():
118            if not entry.ObtainContents():
119                return False
120        return self._BuildIfwi()
121
122    def ProcessContents(self):
123        if self.missing:
124            return True
125        orig_data = self.data
126        self._BuildIfwi()
127        same = orig_data == self.data
128        return same
129
130    def ReadEntries(self):
131        """Read the subnodes to find out what should go in this IFWI"""
132        for node in self._node.subnodes:
133            entry = Entry.Create(self.section, node)
134            entry.ReadNode()
135            entry._ifwi_replace = fdt_util.GetBool(node, 'ifwi-replace')
136            entry._ifwi_subpart = fdt_util.GetString(node, 'ifwi-subpart')
137            entry._ifwi_entry_name = fdt_util.GetString(node, 'ifwi-entry')
138            self._ifwi_entries[entry._ifwi_subpart] = entry
139
140    def WriteSymbols(self, section):
141        """Write symbol values into binary files for access at run time"""
142        if not self.missing:
143            for entry in self._ifwi_entries.values():
144                entry.WriteSymbols(self)
145
146    def AddBintools(self, btools):
147        super().AddBintools(btools)
148        self.ifwitool = self.AddBintool(btools, 'ifwitool')
149