BaseTools: Replace StringIO.StringIO with io.BytesIO
[mirror_edk2.git] / BaseTools / Source / Python / GenFds / Capsule.py
1 ## @file
2 # generate capsule
3 #
4 # Copyright (c) 2007 - 2018, 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 from io import BytesIO
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 = BytesIO()
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 = BytesIO()
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 = BytesIO()
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.Existed:
145 FwMgrHdr.write(pack('=Q', PreSize))
146 PreSize += len(fmp.Buffer)
147 Content.write(fmp.Buffer)
148 continue
149 if fmp.ImageFile:
150 for Obj in fmp.ImageFile:
151 fmp.ImageFile = Obj.GenCapsuleSubItem()
152 if fmp.VendorCodeFile:
153 for Obj in fmp.VendorCodeFile:
154 fmp.VendorCodeFile = Obj.GenCapsuleSubItem()
155 if fmp.Certificate_Guid:
156 ExternalTool, ExternalOption = FindExtendTool([], GenFdsGlobalVariable.ArchList, fmp.Certificate_Guid)
157 CmdOption = ''
158 CapInputFile = fmp.ImageFile
159 if not os.path.isabs(fmp.ImageFile):
160 CapInputFile = os.path.join(GenFdsGlobalVariable.WorkSpaceDir, fmp.ImageFile)
161 CapOutputTmp = os.path.join(GenFdsGlobalVariable.FvDir, self.UiCapsuleName) + '.tmp'
162 if ExternalTool is None:
163 EdkLogger.error("GenFds", GENFDS_ERROR, "No tool found with GUID %s" % fmp.Certificate_Guid)
164 else:
165 CmdOption += ExternalTool
166 if ExternalOption:
167 CmdOption = CmdOption + ' ' + ExternalOption
168 CmdOption += ' -e ' + ' --monotonic-count ' + str(fmp.MonotonicCount) + ' -o ' + CapOutputTmp + ' ' + CapInputFile
169 CmdList = CmdOption.split()
170 GenFdsGlobalVariable.CallExternalTool(CmdList, "Failed to generate FMP auth capsule")
171 if uuid.UUID(fmp.Certificate_Guid) == EFI_CERT_TYPE_PKCS7_GUID:
172 dwLength = 4 + 2 + 2 + 16 + os.path.getsize(CapOutputTmp) - os.path.getsize(CapInputFile)
173 else:
174 dwLength = 4 + 2 + 2 + 16 + 16 + 256 + 256
175 fmp.ImageFile = CapOutputTmp
176 AuthData = [fmp.MonotonicCount, dwLength, WIN_CERT_REVISION, WIN_CERT_TYPE_EFI_GUID, fmp.Certificate_Guid]
177 fmp.Buffer = fmp.GenCapsuleSubItem(AuthData)
178 else:
179 fmp.Buffer = fmp.GenCapsuleSubItem()
180 FwMgrHdr.write(pack('=Q', PreSize))
181 PreSize += len(fmp.Buffer)
182 Content.write(fmp.Buffer)
183 BodySize = len(FwMgrHdr.getvalue()) + len(Content.getvalue())
184 Header.write(pack('=I', HdrSize + BodySize))
185 #
186 # The real capsule header structure is 28 bytes
187 #
188 Header.write('\x00'*(HdrSize-28))
189 Header.write(FwMgrHdr.getvalue())
190 Header.write(Content.getvalue())
191 #
192 # Generate FMP capsule file
193 #
194 CapOutputFile = os.path.join(GenFdsGlobalVariable.FvDir, self.UiCapsuleName) + '.Cap'
195 SaveFileOnChange(CapOutputFile, Header.getvalue(), True)
196 return CapOutputFile
197
198 ## Generate capsule
199 #
200 # @param self The object pointer
201 # @retval string Generated Capsule file path
202 #
203 def GenCapsule(self):
204 if self.UiCapsuleName.upper() + 'cap' in GenFds.ImageBinDict:
205 return GenFds.ImageBinDict[self.UiCapsuleName.upper() + 'cap']
206
207 GenFdsGlobalVariable.InfLogger( "\nGenerate %s Capsule" %self.UiCapsuleName)
208 if ('CAPSULE_GUID' in self.TokensDict and
209 uuid.UUID(self.TokensDict['CAPSULE_GUID']) == uuid.UUID('6DCBD5ED-E82D-4C44-BDA1-7194199AD92A')):
210 return self.GenFmpCapsule()
211
212 CapInfFile = self.GenCapInf()
213 CapInfFile.writelines("[files]" + T_CHAR_LF)
214 CapFileList = []
215 for CapsuleDataObj in self.CapsuleDataList :
216 CapsuleDataObj.CapsuleName = self.CapsuleName
217 FileName = CapsuleDataObj.GenCapsuleSubItem()
218 CapsuleDataObj.CapsuleName = None
219 CapFileList.append(FileName)
220 CapInfFile.writelines("EFI_FILE_NAME = " + \
221 FileName + \
222 T_CHAR_LF)
223 SaveFileOnChange(self.CapInfFileName, CapInfFile.getvalue(), False)
224 CapInfFile.close()
225 #
226 # Call GenFv tool to generate capsule
227 #
228 CapOutputFile = os.path.join(GenFdsGlobalVariable.FvDir, self.UiCapsuleName)
229 CapOutputFile = CapOutputFile + '.Cap'
230 GenFdsGlobalVariable.GenerateFirmwareVolume(
231 CapOutputFile,
232 [self.CapInfFileName],
233 Capsule=True,
234 FfsList=CapFileList
235 )
236
237 GenFdsGlobalVariable.VerboseLogger( "\nGenerate %s Capsule Successfully" %self.UiCapsuleName)
238 GenFdsGlobalVariable.SharpCounter = 0
239 GenFds.ImageBinDict[self.UiCapsuleName.upper() + 'cap'] = CapOutputFile
240 return CapOutputFile
241
242 ## Generate inf file for capsule
243 #
244 # @param self The object pointer
245 # @retval file inf file object
246 #
247 def GenCapInf(self):
248 self.CapInfFileName = os.path.join(GenFdsGlobalVariable.FvDir,
249 self.UiCapsuleName + "_Cap" + '.inf')
250 CapInfFile = BytesIO() #open (self.CapInfFileName , 'w+')
251
252 CapInfFile.writelines("[options]" + T_CHAR_LF)
253
254 for Item in self.TokensDict:
255 CapInfFile.writelines("EFI_" + \
256 Item + \
257 ' = ' + \
258 self.TokensDict[Item] + \
259 T_CHAR_LF)
260
261 return CapInfFile