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