1## @file
2# generate capsule
3#
4#  Copyright (c) 2007 - 2014, 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
28
29
30T_CHAR_LF = '\n'
31
32## create inf file describes what goes into capsule and call GenFv to generate capsule
33#
34#
35class Capsule (CapsuleClassObject) :
36    ## The constructor
37    #
38    #   @param  self        The object pointer
39    #
40    def __init__(self):
41        CapsuleClassObject.__init__(self)
42        # For GenFv
43        self.BlockSize = None
44        # For GenFv
45        self.BlockNum = None
46        self.CapsuleName = None
47
48    ## Generate FMP capsule
49    #
50    #   @retval string      Generated Capsule file path
51    #
52    def GenFmpCapsule(self):
53        #
54        # Generate capsule header
55        # typedef struct {
56        #     EFI_GUID          CapsuleGuid;
57        #     UINT32            HeaderSize;
58        #     UINT32            Flags;
59        #     UINT32            CapsuleImageSize;
60        # } EFI_CAPSULE_HEADER;
61        #
62        Header = StringIO.StringIO()
63        #
64        # Use FMP capsule GUID: 6DCBD5ED-E82D-4C44-BDA1-7194199AD92A
65        #
66        Header.write(PackRegistryFormatGuid('6DCBD5ED-E82D-4C44-BDA1-7194199AD92A'))
67        HdrSize = 0
68        if 'CAPSULE_HEADER_SIZE' in self.TokensDict:
69            Header.write(pack('=I', int(self.TokensDict['CAPSULE_HEADER_SIZE'], 16)))
70            HdrSize = int(self.TokensDict['CAPSULE_HEADER_SIZE'], 16)
71        else:
72            Header.write(pack('=I', 0x20))
73            HdrSize = 0x20
74        Flags = 0
75        if 'CAPSULE_FLAGS' in self.TokensDict:
76            for flag in self.TokensDict['CAPSULE_FLAGS'].split(','):
77                flag = flag.strip()
78                if flag == 'PopulateSystemTable':
79                    Flags |= 0x00010000 | 0x00020000
80                elif flag == 'PersistAcrossReset':
81                    Flags |= 0x00010000
82                elif flag == 'InitiateReset':
83                    Flags |= 0x00040000
84        Header.write(pack('=I', Flags))
85        #
86        # typedef struct {
87        #     UINT32 Version;
88        #     UINT16 EmbeddedDriverCount;
89        #     UINT16 PayloadItemCount;
90        #     // UINT64 ItemOffsetList[];
91        # } EFI_FIRMWARE_MANAGEMENT_CAPSULE_HEADER;
92        #
93        FwMgrHdr = StringIO.StringIO()
94        if 'CAPSULE_HEADER_INIT_VERSION' in self.TokensDict:
95            FwMgrHdr.write(pack('=I', int(self.TokensDict['CAPSULE_HEADER_INIT_VERSION'], 16)))
96        else:
97            FwMgrHdr.write(pack('=I', 0x00000001))
98        FwMgrHdr.write(pack('=HH', len(self.CapsuleDataList), len(self.FmpPayloadList)))
99        FwMgrHdrSize = 4+2+2+8*(len(self.CapsuleDataList)+len(self.FmpPayloadList))
100
101        PreSize = FwMgrHdrSize
102        Content = StringIO.StringIO()
103        for driver in self.CapsuleDataList:
104            FileName = driver.GenCapsuleSubItem()
105            FwMgrHdr.write(pack('=Q', PreSize))
106            PreSize += os.path.getsize(FileName)
107            File = open(FileName, 'rb')
108            Content.write(File.read())
109            File.close()
110        for fmp in self.FmpPayloadList:
111            payload = fmp.GenCapsuleSubItem()
112            FwMgrHdr.write(pack('=Q', PreSize))
113            PreSize += len(payload)
114            Content.write(payload)
115        BodySize = len(FwMgrHdr.getvalue()) + len(Content.getvalue())
116        Header.write(pack('=I', HdrSize + BodySize))
117        #
118        # The real capsule header structure is 28 bytes
119        #
120        Header.write('\x00'*(HdrSize-28))
121        Header.write(FwMgrHdr.getvalue())
122        Header.write(Content.getvalue())
123        #
124        # Generate FMP capsule file
125        #
126        CapOutputFile = os.path.join(GenFdsGlobalVariable.FvDir, self.UiCapsuleName) + '.Cap'
127        SaveFileOnChange(CapOutputFile, Header.getvalue(), True)
128        return CapOutputFile
129
130    ## Generate capsule
131    #
132    #   @param  self        The object pointer
133    #   @retval string      Generated Capsule file path
134    #
135    def GenCapsule(self):
136        if self.UiCapsuleName.upper() + 'cap' in GenFds.ImageBinDict.keys():
137            return GenFds.ImageBinDict[self.UiCapsuleName.upper() + 'cap']
138
139        GenFdsGlobalVariable.InfLogger( "\nGenerate %s Capsule" %self.UiCapsuleName)
140        if ('CAPSULE_GUID' in self.TokensDict and
141            uuid.UUID(self.TokensDict['CAPSULE_GUID']) == uuid.UUID('6DCBD5ED-E82D-4C44-BDA1-7194199AD92A')):
142            return self.GenFmpCapsule()
143
144        CapInfFile = self.GenCapInf()
145        CapInfFile.writelines("[files]" + T_CHAR_LF)
146        CapFileList = []
147        for CapsuleDataObj in self.CapsuleDataList :
148            CapsuleDataObj.CapsuleName = self.CapsuleName
149            FileName = CapsuleDataObj.GenCapsuleSubItem()
150            CapsuleDataObj.CapsuleName = None
151            CapFileList.append(FileName)
152            CapInfFile.writelines("EFI_FILE_NAME = " + \
153                                   FileName      + \
154                                   T_CHAR_LF)
155        SaveFileOnChange(self.CapInfFileName, CapInfFile.getvalue(), False)
156        CapInfFile.close()
157        #
158        # Call GenFv tool to generate capsule
159        #
160        CapOutputFile = os.path.join(GenFdsGlobalVariable.FvDir, self.UiCapsuleName)
161        CapOutputFile = CapOutputFile + '.Cap'
162        GenFdsGlobalVariable.GenerateFirmwareVolume(
163                                CapOutputFile,
164                                [self.CapInfFileName],
165                                Capsule=True,
166                                FfsList=CapFileList
167                                )
168
169        GenFdsGlobalVariable.VerboseLogger( "\nGenerate %s Capsule Successfully" %self.UiCapsuleName)
170        GenFdsGlobalVariable.SharpCounter = 0
171        GenFds.ImageBinDict[self.UiCapsuleName.upper() + 'cap'] = CapOutputFile
172        return CapOutputFile
173
174    ## Generate inf file for capsule
175    #
176    #   @param  self        The object pointer
177    #   @retval file        inf file object
178    #
179    def GenCapInf(self):
180        self.CapInfFileName = os.path.join(GenFdsGlobalVariable.FvDir,
181                                   self.UiCapsuleName +  "_Cap" + '.inf')
182        CapInfFile = StringIO.StringIO() #open (self.CapInfFileName , 'w+')
183
184        CapInfFile.writelines("[options]" + T_CHAR_LF)
185
186        for Item in self.TokensDict.keys():
187            CapInfFile.writelines("EFI_"                    + \
188                                  Item                      + \
189                                  ' = '                     + \
190                                  self.TokensDict.get(Item) + \
191                                  T_CHAR_LF)
192
193        return CapInfFile
194