1## @file
2# generate capsule
3#
4#  Copyright (c) 2007 - 2016, Intel Corporation. All rights reserved.<BR>
5#
6#  This program and the accompanying materials
7#  are licensed and made available under the terms and conditions of the BSD License
8#  which accompanies this distribution.  The full text of the license may be found at
9#  http://opensource.org/licenses/bsd-license.php
10#
11#  THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
12#  WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
13#
14
15##
16# Import Modules
17#
18from GenFdsGlobalVariable import GenFdsGlobalVariable
19from CommonDataClass.FdfClass import CapsuleClassObject
20import Common.LongFilePathOs as os
21import subprocess
22import StringIO
23from Common.Misc import SaveFileOnChange
24from GenFds import GenFds
25from Common.Misc import PackRegistryFormatGuid
26import uuid
27from struct import pack
28from GenFds import FindExtendTool
29from Common import EdkLogger
30from Common.BuildToolError import *
31
32
33T_CHAR_LF = '\n'
34WIN_CERT_REVISION      = 0x0200
35WIN_CERT_TYPE_EFI_GUID = 0x0EF1
36EFI_CERT_TYPE_PKCS7_GUID = uuid.UUID('{4aafd29d-68df-49ee-8aa9-347d375665a7}')
37EFI_CERT_TYPE_RSA2048_SHA256_GUID = uuid.UUID('{a7717414-c616-4977-9420-844712a735bf}')
38
39## create inf file describes what goes into capsule and call GenFv to generate capsule
40#
41#
42class Capsule (CapsuleClassObject) :
43    ## The constructor
44    #
45    #   @param  self        The object pointer
46    #
47    def __init__(self):
48        CapsuleClassObject.__init__(self)
49        # For GenFv
50        self.BlockSize = None
51        # For GenFv
52        self.BlockNum = None
53        self.CapsuleName = None
54
55    ## Generate FMP capsule
56    #
57    #   @retval string      Generated Capsule file path
58    #
59    def GenFmpCapsule(self):
60        #
61        # Generate capsule header
62        # typedef struct {
63        #     EFI_GUID          CapsuleGuid;
64        #     UINT32            HeaderSize;
65        #     UINT32            Flags;
66        #     UINT32            CapsuleImageSize;
67        # } EFI_CAPSULE_HEADER;
68        #
69        Header = StringIO.StringIO()
70        #
71        # Use FMP capsule GUID: 6DCBD5ED-E82D-4C44-BDA1-7194199AD92A
72        #
73        Header.write(PackRegistryFormatGuid('6DCBD5ED-E82D-4C44-BDA1-7194199AD92A'))
74        HdrSize = 0
75        if 'CAPSULE_HEADER_SIZE' in self.TokensDict:
76            Header.write(pack('=I', int(self.TokensDict['CAPSULE_HEADER_SIZE'], 16)))
77            HdrSize = int(self.TokensDict['CAPSULE_HEADER_SIZE'], 16)
78        else:
79            Header.write(pack('=I', 0x20))
80            HdrSize = 0x20
81        Flags = 0
82        if 'CAPSULE_FLAGS' in self.TokensDict:
83            for flag in self.TokensDict['CAPSULE_FLAGS'].split(','):
84                flag = flag.strip()
85                if flag == 'PopulateSystemTable':
86                    Flags |= 0x00010000 | 0x00020000
87                elif flag == 'PersistAcrossReset':
88                    Flags |= 0x00010000
89                elif flag == 'InitiateReset':
90                    Flags |= 0x00040000
91        Header.write(pack('=I', Flags))
92        #
93        # typedef struct {
94        #     UINT32 Version;
95        #     UINT16 EmbeddedDriverCount;
96        #     UINT16 PayloadItemCount;
97        #     // UINT64 ItemOffsetList[];
98        # } EFI_FIRMWARE_MANAGEMENT_CAPSULE_HEADER;
99        #
100        FwMgrHdr = StringIO.StringIO()
101        if 'CAPSULE_HEADER_INIT_VERSION' in self.TokensDict:
102            FwMgrHdr.write(pack('=I', int(self.TokensDict['CAPSULE_HEADER_INIT_VERSION'], 16)))
103        else:
104            FwMgrHdr.write(pack('=I', 0x00000001))
105        FwMgrHdr.write(pack('=HH', len(self.CapsuleDataList), len(self.FmpPayloadList)))
106        FwMgrHdrSize = 4+2+2+8*(len(self.CapsuleDataList)+len(self.FmpPayloadList))
107
108        #
109        # typedef struct _WIN_CERTIFICATE {
110        #   UINT32 dwLength;
111        #   UINT16 wRevision;
112        #   UINT16 wCertificateType;
113        # //UINT8 bCertificate[ANYSIZE_ARRAY];
114        # } WIN_CERTIFICATE;
115        #
116        # typedef struct _WIN_CERTIFICATE_UEFI_GUID {
117        #   WIN_CERTIFICATE Hdr;
118        #   EFI_GUID        CertType;
119        # //UINT8 CertData[ANYSIZE_ARRAY];
120        # } WIN_CERTIFICATE_UEFI_GUID;
121        #
122        # typedef struct {
123        #   UINT64                    MonotonicCount;
124        #   WIN_CERTIFICATE_UEFI_GUID AuthInfo;
125        # } EFI_FIRMWARE_IMAGE_AUTHENTICATION;
126        #
127        # typedef struct _EFI_CERT_BLOCK_RSA_2048_SHA256 {
128        #   EFI_GUID HashType;
129        #   UINT8 PublicKey[256];
130        #   UINT8 Signature[256];
131        # } EFI_CERT_BLOCK_RSA_2048_SHA256;
132        #
133
134        PreSize = FwMgrHdrSize
135        Content = StringIO.StringIO()
136        for driver in self.CapsuleDataList:
137            FileName = driver.GenCapsuleSubItem()
138            FwMgrHdr.write(pack('=Q', PreSize))
139            PreSize += os.path.getsize(FileName)
140            File = open(FileName, 'rb')
141            Content.write(File.read())
142            File.close()
143        for fmp in self.FmpPayloadList:
144            if fmp.ImageFile:
145                for Obj in fmp.ImageFile:
146                    fmp.ImageFile = Obj.GenCapsuleSubItem()
147            if fmp.VendorCodeFile:
148                for Obj in fmp.VendorCodeFile:
149                    fmp.VendorCodeFile = Obj.GenCapsuleSubItem()
150            if fmp.Certificate_Guid:
151                ExternalTool, ExternalOption = FindExtendTool([], GenFdsGlobalVariable.ArchList, fmp.Certificate_Guid)
152                CmdOption = ''
153                CapInputFile = fmp.ImageFile
154                if not os.path.isabs(fmp.ImageFile):
155                    CapInputFile = os.path.join(GenFdsGlobalVariable.WorkSpaceDir, fmp.ImageFile)
156                CapOutputTmp = os.path.join(GenFdsGlobalVariable.FvDir, self.UiCapsuleName) + '.tmp'
157                if ExternalTool == None:
158                    EdkLogger.error("GenFds", GENFDS_ERROR, "No tool found with GUID %s" % fmp.Certificate_Guid)
159                else:
160                    CmdOption += ExternalTool
161                if ExternalOption:
162                    CmdOption = CmdOption + ' ' + ExternalOption
163                CmdOption += ' -e ' + ' --monotonic-count ' + str(fmp.MonotonicCount) + ' -o ' + CapOutputTmp + ' ' + CapInputFile
164                CmdList = CmdOption.split()
165                GenFdsGlobalVariable.CallExternalTool(CmdList, "Failed to generate FMP auth capsule")
166                if uuid.UUID(fmp.Certificate_Guid) == EFI_CERT_TYPE_PKCS7_GUID:
167                    dwLength = 4 + 2 + 2 + 16 + os.path.getsize(CapOutputTmp) - os.path.getsize(CapInputFile)
168                else:
169                    dwLength = 4 + 2 + 2 + 16 + 16 + 256 + 256
170                fmp.ImageFile = CapOutputTmp
171                AuthData = [fmp.MonotonicCount, dwLength, WIN_CERT_REVISION, WIN_CERT_TYPE_EFI_GUID, fmp.Certificate_Guid]
172                Buffer = fmp.GenCapsuleSubItem(AuthData)
173            else:
174                Buffer = fmp.GenCapsuleSubItem()
175            FwMgrHdr.write(pack('=Q', PreSize))
176            PreSize += len(Buffer)
177            Content.write(Buffer)
178        BodySize = len(FwMgrHdr.getvalue()) + len(Content.getvalue())
179        Header.write(pack('=I', HdrSize + BodySize))
180        #
181        # The real capsule header structure is 28 bytes
182        #
183        Header.write('\x00'*(HdrSize-28))
184        Header.write(FwMgrHdr.getvalue())
185        Header.write(Content.getvalue())
186        #
187        # Generate FMP capsule file
188        #
189        CapOutputFile = os.path.join(GenFdsGlobalVariable.FvDir, self.UiCapsuleName) + '.Cap'
190        SaveFileOnChange(CapOutputFile, Header.getvalue(), True)
191        return CapOutputFile
192
193    ## Generate capsule
194    #
195    #   @param  self        The object pointer
196    #   @retval string      Generated Capsule file path
197    #
198    def GenCapsule(self):
199        if self.UiCapsuleName.upper() + 'cap' in GenFds.ImageBinDict.keys():
200            return GenFds.ImageBinDict[self.UiCapsuleName.upper() + 'cap']
201
202        GenFdsGlobalVariable.InfLogger( "\nGenerate %s Capsule" %self.UiCapsuleName)
203        if ('CAPSULE_GUID' in self.TokensDict and
204            uuid.UUID(self.TokensDict['CAPSULE_GUID']) == uuid.UUID('6DCBD5ED-E82D-4C44-BDA1-7194199AD92A')):
205            return self.GenFmpCapsule()
206
207        CapInfFile = self.GenCapInf()
208        CapInfFile.writelines("[files]" + T_CHAR_LF)
209        CapFileList = []
210        for CapsuleDataObj in self.CapsuleDataList :
211            CapsuleDataObj.CapsuleName = self.CapsuleName
212            FileName = CapsuleDataObj.GenCapsuleSubItem()
213            CapsuleDataObj.CapsuleName = None
214            CapFileList.append(FileName)
215            CapInfFile.writelines("EFI_FILE_NAME = " + \
216                                   FileName      + \
217                                   T_CHAR_LF)
218        SaveFileOnChange(self.CapInfFileName, CapInfFile.getvalue(), False)
219        CapInfFile.close()
220        #
221        # Call GenFv tool to generate capsule
222        #
223        CapOutputFile = os.path.join(GenFdsGlobalVariable.FvDir, self.UiCapsuleName)
224        CapOutputFile = CapOutputFile + '.Cap'
225        GenFdsGlobalVariable.GenerateFirmwareVolume(
226                                CapOutputFile,
227                                [self.CapInfFileName],
228                                Capsule=True,
229                                FfsList=CapFileList
230                                )
231
232        GenFdsGlobalVariable.VerboseLogger( "\nGenerate %s Capsule Successfully" %self.UiCapsuleName)
233        GenFdsGlobalVariable.SharpCounter = 0
234        GenFds.ImageBinDict[self.UiCapsuleName.upper() + 'cap'] = CapOutputFile
235        return CapOutputFile
236
237    ## Generate inf file for capsule
238    #
239    #   @param  self        The object pointer
240    #   @retval file        inf file object
241    #
242    def GenCapInf(self):
243        self.CapInfFileName = os.path.join(GenFdsGlobalVariable.FvDir,
244                                   self.UiCapsuleName +  "_Cap" + '.inf')
245        CapInfFile = StringIO.StringIO() #open (self.CapInfFileName , 'w+')
246
247        CapInfFile.writelines("[options]" + T_CHAR_LF)
248
249        for Item in self.TokensDict.keys():
250            CapInfFile.writelines("EFI_"                    + \
251                                  Item                      + \
252                                  ' = '                     + \
253                                  self.TokensDict.get(Item) + \
254                                  T_CHAR_LF)
255
256        return CapInfFile
257