Home | History | Annotate | Download | only in GenFds
      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 #

     18 from GenFdsGlobalVariable import GenFdsGlobalVariable
     19 from CommonDataClass.FdfClass import CapsuleClassObject
     20 import Common.LongFilePathOs as os
     21 import subprocess
     22 import StringIO
     23 from Common.Misc import SaveFileOnChange
     24 from GenFds import GenFds
     25 from Common.Misc import PackRegistryFormatGuid
     26 import uuid
     27 from struct import pack
     28 from GenFds import FindExtendTool
     29 from Common import EdkLogger
     30 from Common.BuildToolError import *
     31 
     32 
     33 T_CHAR_LF = '\n'
     34 WIN_CERT_REVISION      = 0x0200
     35 WIN_CERT_TYPE_EFI_GUID = 0x0EF1
     36 EFI_CERT_TYPE_PKCS7_GUID = uuid.UUID('{4aafd29d-68df-49ee-8aa9-347d375665a7}')
     37 EFI_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 #

     42 class 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