]> git.proxmox.com Git - mirror_edk2.git/blob - BaseTools/Source/Python/GenFds/Fv.py
BaseTools: Fix regression boot hang issue by commit 0e982cf03dd5
[mirror_edk2.git] / BaseTools / Source / Python / GenFds / Fv.py
1 from __future__ import absolute_import
2 ## @file
3 # process FV generation
4 #
5 # Copyright (c) 2007 - 2018, Intel Corporation. All rights reserved.<BR>
6 #
7 # This program and the accompanying materials
8 # are licensed and made available under the terms and conditions of the BSD License
9 # which accompanies this distribution. The full text of the license may be found at
10 # http://opensource.org/licenses/bsd-license.php
11 #
12 # THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
13 # WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
14 #
15
16 ##
17 # Import Modules
18 #
19 import Common.LongFilePathOs as os
20 import subprocess
21 from io import BytesIO
22 from struct import *
23
24 from . import Ffs
25 from . import AprioriSection
26 from . import FfsFileStatement
27 from .GenFdsGlobalVariable import GenFdsGlobalVariable
28 from CommonDataClass.FdfClass import FvClassObject
29 from Common.Misc import SaveFileOnChange, PackGUID
30 from Common.LongFilePathSupport import CopyLongFilePath
31 from Common.LongFilePathSupport import OpenLongFilePath as open
32 from Common.DataType import *
33
34 FV_UI_EXT_ENTY_GUID = 'A67DF1FA-8DE8-4E98-AF09-4BDF2EFFBC7C'
35
36 ## generate FV
37 #
38 #
39 class FV (FvClassObject):
40 ## The constructor
41 #
42 # @param self The object pointer
43 #
44 def __init__(self):
45 FvClassObject.__init__(self)
46 self.FvInfFile = None
47 self.FvAddressFile = None
48 self.BaseAddress = None
49 self.InfFileName = None
50 self.FvAddressFileName = None
51 self.CapsuleName = None
52 self.FvBaseAddress = None
53 self.FvForceRebase = None
54 self.FvRegionInFD = None
55 self.UsedSizeEnable = False
56
57 ## AddToBuffer()
58 #
59 # Generate Fv and add it to the Buffer
60 #
61 # @param self The object pointer
62 # @param Buffer The buffer generated FV data will be put
63 # @param BaseAddress base address of FV
64 # @param BlockSize block size of FV
65 # @param BlockNum How many blocks in FV
66 # @param ErasePolarity Flash erase polarity
67 # @param VtfDict VTF objects
68 # @param MacroDict macro value pair
69 # @retval string Generated FV file path
70 #
71 def AddToBuffer (self, Buffer, BaseAddress=None, BlockSize= None, BlockNum=None, ErasePloarity='1', VtfDict=None, MacroDict = {}, Flag=False) :
72
73 if BaseAddress is None and self.UiFvName.upper() + 'fv' in GenFdsGlobalVariable.ImageBinDict:
74 return GenFdsGlobalVariable.ImageBinDict[self.UiFvName.upper() + 'fv']
75
76 #
77 # Check whether FV in Capsule is in FD flash region.
78 # If yes, return error. Doesn't support FV in Capsule image is also in FD flash region.
79 #
80 if self.CapsuleName is not None:
81 for FdObj in GenFdsGlobalVariable.FdfParser.Profile.FdDict.values():
82 for RegionObj in FdObj.RegionList:
83 if RegionObj.RegionType == BINARY_FILE_TYPE_FV:
84 for RegionData in RegionObj.RegionDataList:
85 if RegionData.endswith(".fv"):
86 continue
87 elif RegionData.upper() + 'fv' in GenFdsGlobalVariable.ImageBinDict:
88 continue
89 elif self.UiFvName.upper() == RegionData.upper():
90 GenFdsGlobalVariable.ErrorLogger("Capsule %s in FD region can't contain a FV %s in FD region." % (self.CapsuleName, self.UiFvName.upper()))
91 if not Flag:
92 GenFdsGlobalVariable.InfLogger( "\nGenerating %s FV" %self.UiFvName)
93 GenFdsGlobalVariable.LargeFileInFvFlags.append(False)
94 FFSGuid = None
95
96 if self.FvBaseAddress is not None:
97 BaseAddress = self.FvBaseAddress
98 if not Flag:
99 self.__InitializeInf__(BaseAddress, BlockSize, BlockNum, ErasePloarity, VtfDict)
100 #
101 # First Process the Apriori section
102 #
103 MacroDict.update(self.DefineVarDict)
104
105 GenFdsGlobalVariable.VerboseLogger('First generate Apriori file !')
106 FfsFileList = []
107 for AprSection in self.AprioriSectionList:
108 FileName = AprSection.GenFfs (self.UiFvName, MacroDict, IsMakefile=Flag)
109 FfsFileList.append(FileName)
110 # Add Apriori file name to Inf file
111 if not Flag:
112 self.FvInfFile.writelines("EFI_FILE_NAME = " + \
113 FileName + \
114 TAB_LINE_BREAK)
115
116 # Process Modules in FfsList
117 for FfsFile in self.FfsList :
118 if Flag:
119 if isinstance(FfsFile, FfsFileStatement.FileStatement):
120 continue
121 if GenFdsGlobalVariable.EnableGenfdsMultiThread and GenFdsGlobalVariable.ModuleFile and GenFdsGlobalVariable.ModuleFile.Path.find(os.path.normpath(FfsFile.InfFileName)) == -1:
122 continue
123 FileName = FfsFile.GenFfs(MacroDict, FvParentAddr=BaseAddress, IsMakefile=Flag, FvName=self.UiFvName)
124 FfsFileList.append(FileName)
125 if not Flag:
126 self.FvInfFile.writelines("EFI_FILE_NAME = " + \
127 FileName + \
128 TAB_LINE_BREAK)
129 if not Flag:
130 SaveFileOnChange(self.InfFileName, self.FvInfFile.getvalue(), False)
131 self.FvInfFile.close()
132 #
133 # Call GenFv tool
134 #
135 FvOutputFile = os.path.join(GenFdsGlobalVariable.FvDir, self.UiFvName)
136 FvOutputFile = FvOutputFile + '.Fv'
137 # BUGBUG: FvOutputFile could be specified from FDF file (FV section, CreateFile statement)
138 if self.CreateFileName is not None:
139 FvOutputFile = self.CreateFileName
140
141 if Flag:
142 GenFdsGlobalVariable.ImageBinDict[self.UiFvName.upper() + 'fv'] = FvOutputFile
143 return FvOutputFile
144
145 FvInfoFileName = os.path.join(GenFdsGlobalVariable.FfsDir, self.UiFvName + '.inf')
146 if not Flag:
147 CopyLongFilePath(GenFdsGlobalVariable.FvAddressFileName, FvInfoFileName)
148 OrigFvInfo = None
149 if os.path.exists (FvInfoFileName):
150 OrigFvInfo = open(FvInfoFileName, 'r').read()
151 if GenFdsGlobalVariable.LargeFileInFvFlags[-1]:
152 FFSGuid = GenFdsGlobalVariable.EFI_FIRMWARE_FILE_SYSTEM3_GUID
153 GenFdsGlobalVariable.GenerateFirmwareVolume(
154 FvOutputFile,
155 [self.InfFileName],
156 AddressFile=FvInfoFileName,
157 FfsList=FfsFileList,
158 ForceRebase=self.FvForceRebase,
159 FileSystemGuid=FFSGuid
160 )
161
162 NewFvInfo = None
163 if os.path.exists (FvInfoFileName):
164 NewFvInfo = open(FvInfoFileName, 'r').read()
165 if NewFvInfo is not None and NewFvInfo != OrigFvInfo:
166 FvChildAddr = []
167 AddFileObj = open(FvInfoFileName, 'r')
168 AddrStrings = AddFileObj.readlines()
169 AddrKeyFound = False
170 for AddrString in AddrStrings:
171 if AddrKeyFound:
172 #get base address for the inside FvImage
173 FvChildAddr.append (AddrString)
174 elif AddrString.find ("[FV_BASE_ADDRESS]") != -1:
175 AddrKeyFound = True
176 AddFileObj.close()
177
178 if FvChildAddr != []:
179 # Update Ffs again
180 for FfsFile in self.FfsList :
181 FileName = FfsFile.GenFfs(MacroDict, FvChildAddr, BaseAddress, IsMakefile=Flag, FvName=self.UiFvName)
182
183 if GenFdsGlobalVariable.LargeFileInFvFlags[-1]:
184 FFSGuid = GenFdsGlobalVariable.EFI_FIRMWARE_FILE_SYSTEM3_GUID;
185 #Update GenFv again
186 GenFdsGlobalVariable.GenerateFirmwareVolume(
187 FvOutputFile,
188 [self.InfFileName],
189 AddressFile=FvInfoFileName,
190 FfsList=FfsFileList,
191 ForceRebase=self.FvForceRebase,
192 FileSystemGuid=FFSGuid
193 )
194
195 #
196 # Write the Fv contents to Buffer
197 #
198 if os.path.isfile(FvOutputFile) and os.path.getsize(FvOutputFile) >= 0x48:
199 FvFileObj = open(FvOutputFile, 'rb')
200 # PI FvHeader is 0x48 byte
201 FvHeaderBuffer = FvFileObj.read(0x48)
202 Signature = FvHeaderBuffer[0x28:0x32]
203 if Signature and Signature.startswith('_FVH'):
204 GenFdsGlobalVariable.VerboseLogger("\nGenerate %s FV Successfully" % self.UiFvName)
205 GenFdsGlobalVariable.SharpCounter = 0
206
207 FvFileObj.seek(0)
208 Buffer.write(FvFileObj.read())
209 # FV alignment position.
210 FvAlignmentValue = 1 << (ord(FvHeaderBuffer[0x2E]) & 0x1F)
211 if FvAlignmentValue >= 0x400:
212 if FvAlignmentValue >= 0x100000:
213 if FvAlignmentValue >= 0x1000000:
214 #The max alignment supported by FFS is 16M.
215 self.FvAlignment = "16M"
216 else:
217 self.FvAlignment = str(FvAlignmentValue / 0x100000) + "M"
218 else:
219 self.FvAlignment = str(FvAlignmentValue / 0x400) + "K"
220 else:
221 # FvAlignmentValue is less than 1K
222 self.FvAlignment = str (FvAlignmentValue)
223 FvFileObj.close()
224 GenFdsGlobalVariable.ImageBinDict[self.UiFvName.upper() + 'fv'] = FvOutputFile
225 GenFdsGlobalVariable.LargeFileInFvFlags.pop()
226 else:
227 GenFdsGlobalVariable.ErrorLogger("Invalid FV file %s." % self.UiFvName)
228 else:
229 GenFdsGlobalVariable.ErrorLogger("Failed to generate %s FV file." %self.UiFvName)
230 return FvOutputFile
231
232 ## _GetBlockSize()
233 #
234 # Calculate FV's block size
235 # Inherit block size from FD if no block size specified in FV
236 #
237 def _GetBlockSize(self):
238 if self.BlockSizeList:
239 return True
240
241 for FdObj in GenFdsGlobalVariable.FdfParser.Profile.FdDict.values():
242 for RegionObj in FdObj.RegionList:
243 if RegionObj.RegionType != BINARY_FILE_TYPE_FV:
244 continue
245 for RegionData in RegionObj.RegionDataList:
246 #
247 # Found the FD and region that contain this FV
248 #
249 if self.UiFvName.upper() == RegionData.upper():
250 RegionObj.BlockInfoOfRegion(FdObj.BlockSizeList, self)
251 if self.BlockSizeList:
252 return True
253 return False
254
255 ## __InitializeInf__()
256 #
257 # Initilize the inf file to create FV
258 #
259 # @param self The object pointer
260 # @param BaseAddress base address of FV
261 # @param BlockSize block size of FV
262 # @param BlockNum How many blocks in FV
263 # @param ErasePolarity Flash erase polarity
264 # @param VtfDict VTF objects
265 #
266 def __InitializeInf__ (self, BaseAddress = None, BlockSize= None, BlockNum = None, ErasePloarity='1', VtfDict=None) :
267 #
268 # Create FV inf file
269 #
270 self.InfFileName = os.path.join(GenFdsGlobalVariable.FvDir,
271 self.UiFvName + '.inf')
272 self.FvInfFile = BytesIO()
273
274 #
275 # Add [Options]
276 #
277 self.FvInfFile.writelines("[options]" + TAB_LINE_BREAK)
278 if BaseAddress is not None :
279 self.FvInfFile.writelines("EFI_BASE_ADDRESS = " + \
280 BaseAddress + \
281 TAB_LINE_BREAK)
282
283 if BlockSize is not None:
284 self.FvInfFile.writelines("EFI_BLOCK_SIZE = " + \
285 '0x%X' %BlockSize + \
286 TAB_LINE_BREAK)
287 if BlockNum is not None:
288 self.FvInfFile.writelines("EFI_NUM_BLOCKS = " + \
289 ' 0x%X' %BlockNum + \
290 TAB_LINE_BREAK)
291 else:
292 if self.BlockSizeList == []:
293 if not self._GetBlockSize():
294 #set default block size is 1
295 self.FvInfFile.writelines("EFI_BLOCK_SIZE = 0x1" + TAB_LINE_BREAK)
296
297 for BlockSize in self.BlockSizeList :
298 if BlockSize[0] is not None:
299 self.FvInfFile.writelines("EFI_BLOCK_SIZE = " + \
300 '0x%X' %BlockSize[0] + \
301 TAB_LINE_BREAK)
302
303 if BlockSize[1] is not None:
304 self.FvInfFile.writelines("EFI_NUM_BLOCKS = " + \
305 ' 0x%X' %BlockSize[1] + \
306 TAB_LINE_BREAK)
307
308 if self.BsBaseAddress is not None:
309 self.FvInfFile.writelines('EFI_BOOT_DRIVER_BASE_ADDRESS = ' + \
310 '0x%X' %self.BsBaseAddress)
311 if self.RtBaseAddress is not None:
312 self.FvInfFile.writelines('EFI_RUNTIME_DRIVER_BASE_ADDRESS = ' + \
313 '0x%X' %self.RtBaseAddress)
314 #
315 # Add attribute
316 #
317 self.FvInfFile.writelines("[attributes]" + TAB_LINE_BREAK)
318
319 self.FvInfFile.writelines("EFI_ERASE_POLARITY = " + \
320 ' %s' %ErasePloarity + \
321 TAB_LINE_BREAK)
322 if not (self.FvAttributeDict is None):
323 for FvAttribute in self.FvAttributeDict.keys() :
324 if FvAttribute == "FvUsedSizeEnable":
325 if self.FvAttributeDict[FvAttribute].upper() in ('TRUE', '1') :
326 self.UsedSizeEnable = True
327 continue
328 self.FvInfFile.writelines("EFI_" + \
329 FvAttribute + \
330 ' = ' + \
331 self.FvAttributeDict[FvAttribute] + \
332 TAB_LINE_BREAK )
333 if self.FvAlignment is not None:
334 self.FvInfFile.writelines("EFI_FVB2_ALIGNMENT_" + \
335 self.FvAlignment.strip() + \
336 " = TRUE" + \
337 TAB_LINE_BREAK)
338
339 #
340 # Generate FV extension header file
341 #
342 if not self.FvNameGuid:
343 if len(self.FvExtEntryType) > 0 or self.UsedSizeEnable:
344 GenFdsGlobalVariable.ErrorLogger("FV Extension Header Entries declared for %s with no FvNameGuid declaration." % (self.UiFvName))
345 else:
346 TotalSize = 16 + 4
347 Buffer = ''
348 if self.UsedSizeEnable:
349 TotalSize += (4 + 4)
350 ## define EFI_FV_EXT_TYPE_USED_SIZE_TYPE 0x03
351 #typedef struct
352 # {
353 # EFI_FIRMWARE_VOLUME_EXT_ENTRY Hdr;
354 # UINT32 UsedSize;
355 # } EFI_FIRMWARE_VOLUME_EXT_ENTRY_USED_SIZE_TYPE;
356 Buffer += pack('HHL', 8, 3, 0)
357
358 if self.FvNameString == 'TRUE':
359 #
360 # Create EXT entry for FV UI name
361 # This GUID is used: A67DF1FA-8DE8-4E98-AF09-4BDF2EFFBC7C
362 #
363 FvUiLen = len(self.UiFvName)
364 TotalSize += (FvUiLen + 16 + 4)
365 Guid = FV_UI_EXT_ENTY_GUID.split('-')
366 #
367 # Layout:
368 # EFI_FIRMWARE_VOLUME_EXT_ENTRY : size 4
369 # GUID : size 16
370 # FV UI name
371 #
372 Buffer += (pack('HH', (FvUiLen + 16 + 4), 0x0002)
373 + PackGUID(Guid)
374 + self.UiFvName)
375
376 for Index in range (0, len(self.FvExtEntryType)):
377 if self.FvExtEntryType[Index] == 'FILE':
378 # check if the path is absolute or relative
379 if os.path.isabs(self.FvExtEntryData[Index]):
380 FileFullPath = os.path.normpath(self.FvExtEntryData[Index])
381 else:
382 FileFullPath = os.path.normpath(os.path.join(GenFdsGlobalVariable.WorkSpaceDir, self.FvExtEntryData[Index]))
383 # check if the file path exists or not
384 if not os.path.isfile(FileFullPath):
385 GenFdsGlobalVariable.ErrorLogger("Error opening FV Extension Header Entry file %s." % (self.FvExtEntryData[Index]))
386 FvExtFile = open (FileFullPath, 'rb')
387 FvExtFile.seek(0, 2)
388 Size = FvExtFile.tell()
389 if Size >= 0x10000:
390 GenFdsGlobalVariable.ErrorLogger("The size of FV Extension Header Entry file %s exceeds 0x10000." % (self.FvExtEntryData[Index]))
391 TotalSize += (Size + 4)
392 FvExtFile.seek(0)
393 Buffer += pack('HH', (Size + 4), int(self.FvExtEntryTypeValue[Index], 16))
394 Buffer += FvExtFile.read()
395 FvExtFile.close()
396 if self.FvExtEntryType[Index] == 'DATA':
397 ByteList = self.FvExtEntryData[Index].split(',')
398 Size = len (ByteList)
399 if Size >= 0x10000:
400 GenFdsGlobalVariable.ErrorLogger("The size of FV Extension Header Entry data %s exceeds 0x10000." % (self.FvExtEntryData[Index]))
401 TotalSize += (Size + 4)
402 Buffer += pack('HH', (Size + 4), int(self.FvExtEntryTypeValue[Index], 16))
403 for Index1 in range (0, Size):
404 Buffer += pack('B', int(ByteList[Index1], 16))
405
406 Guid = self.FvNameGuid.split('-')
407 Buffer = PackGUID(Guid) + pack('=L', TotalSize) + Buffer
408
409 #
410 # Generate FV extension header file if the total size is not zero
411 #
412 if TotalSize > 0:
413 FvExtHeaderFileName = os.path.join(GenFdsGlobalVariable.FvDir, self.UiFvName + '.ext')
414 FvExtHeaderFile = BytesIO()
415 FvExtHeaderFile.write(Buffer)
416 Changed = SaveFileOnChange(FvExtHeaderFileName, FvExtHeaderFile.getvalue(), True)
417 FvExtHeaderFile.close()
418 if Changed:
419 if os.path.exists (self.InfFileName):
420 os.remove (self.InfFileName)
421 self.FvInfFile.writelines("EFI_FV_EXT_HEADER_FILE_NAME = " + \
422 FvExtHeaderFileName + \
423 TAB_LINE_BREAK)
424
425
426 #
427 # Add [Files]
428 #
429 self.FvInfFile.writelines("[files]" + TAB_LINE_BREAK)
430 if VtfDict and self.UiFvName in VtfDict:
431 self.FvInfFile.writelines("EFI_FILE_NAME = " + \
432 VtfDict[self.UiFvName] + \
433 TAB_LINE_BREAK)