BaseTools: refactor and remove un-needed use of .keys() on dictionaries
[mirror_edk2.git] / BaseTools / Source / Python / GenFds / Fv.py
1 ## @file
2 # process FV generation
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 import Common.LongFilePathOs as os
19 import subprocess
20 import StringIO
21 from struct import *
22
23 import Ffs
24 import AprioriSection
25 import FfsFileStatement
26 from GenFdsGlobalVariable import GenFdsGlobalVariable
27 from GenFds import GenFds
28 from CommonDataClass.FdfClass import FvClassObject
29 from Common.Misc import SaveFileOnChange
30 from Common.LongFilePathSupport import CopyLongFilePath
31 from Common.LongFilePathSupport import OpenLongFilePath as open
32
33 T_CHAR_LF = '\n'
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 GenFds.ImageBinDict:
74 return GenFds.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 == 'FV':
84 for RegionData in RegionObj.RegionDataList:
85 if RegionData.endswith(".fv"):
86 continue
87 elif RegionData.upper() + 'fv' in GenFds.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 T_CHAR_LF)
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 T_CHAR_LF)
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 GenFds.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):
199 FvFileObj = open(FvOutputFile, 'rb')
200 GenFdsGlobalVariable.VerboseLogger("\nGenerate %s FV Successfully" % self.UiFvName)
201 GenFdsGlobalVariable.SharpCounter = 0
202
203 Buffer.write(FvFileObj.read())
204 FvFileObj.seek(0)
205 # PI FvHeader is 0x48 byte
206 FvHeaderBuffer = FvFileObj.read(0x48)
207 # FV alignment position.
208 FvAlignmentValue = 1 << (ord(FvHeaderBuffer[0x2E]) & 0x1F)
209 if FvAlignmentValue >= 0x400:
210 if FvAlignmentValue >= 0x100000:
211 if FvAlignmentValue >= 0x1000000:
212 #The max alignment supported by FFS is 16M.
213 self.FvAlignment = "16M"
214 else:
215 self.FvAlignment = str(FvAlignmentValue / 0x100000) + "M"
216 else:
217 self.FvAlignment = str(FvAlignmentValue / 0x400) + "K"
218 else:
219 # FvAlignmentValue is less than 1K
220 self.FvAlignment = str (FvAlignmentValue)
221 FvFileObj.close()
222 GenFds.ImageBinDict[self.UiFvName.upper() + 'fv'] = FvOutputFile
223 GenFdsGlobalVariable.LargeFileInFvFlags.pop()
224 else:
225 GenFdsGlobalVariable.ErrorLogger("Failed to generate %s FV file." %self.UiFvName)
226 return FvOutputFile
227
228 ## _GetBlockSize()
229 #
230 # Calculate FV's block size
231 # Inherit block size from FD if no block size specified in FV
232 #
233 def _GetBlockSize(self):
234 if self.BlockSizeList:
235 return True
236
237 for FdObj in GenFdsGlobalVariable.FdfParser.Profile.FdDict.values():
238 for RegionObj in FdObj.RegionList:
239 if RegionObj.RegionType != 'FV':
240 continue
241 for RegionData in RegionObj.RegionDataList:
242 #
243 # Found the FD and region that contain this FV
244 #
245 if self.UiFvName.upper() == RegionData.upper():
246 RegionObj.BlockInfoOfRegion(FdObj.BlockSizeList, self)
247 if self.BlockSizeList:
248 return True
249 return False
250
251 ## __InitializeInf__()
252 #
253 # Initilize the inf file to create FV
254 #
255 # @param self The object pointer
256 # @param BaseAddress base address of FV
257 # @param BlockSize block size of FV
258 # @param BlockNum How many blocks in FV
259 # @param ErasePolarity Flash erase polarity
260 # @param VtfDict VTF objects
261 #
262 def __InitializeInf__ (self, BaseAddress = None, BlockSize= None, BlockNum = None, ErasePloarity='1', VtfDict=None) :
263 #
264 # Create FV inf file
265 #
266 self.InfFileName = os.path.join(GenFdsGlobalVariable.FvDir,
267 self.UiFvName + '.inf')
268 self.FvInfFile = StringIO.StringIO()
269
270 #
271 # Add [Options]
272 #
273 self.FvInfFile.writelines("[options]" + T_CHAR_LF)
274 if BaseAddress is not None :
275 self.FvInfFile.writelines("EFI_BASE_ADDRESS = " + \
276 BaseAddress + \
277 T_CHAR_LF)
278
279 if BlockSize is not None:
280 self.FvInfFile.writelines("EFI_BLOCK_SIZE = " + \
281 '0x%X' %BlockSize + \
282 T_CHAR_LF)
283 if BlockNum is not None:
284 self.FvInfFile.writelines("EFI_NUM_BLOCKS = " + \
285 ' 0x%X' %BlockNum + \
286 T_CHAR_LF)
287 else:
288 if self.BlockSizeList == []:
289 if not self._GetBlockSize():
290 #set default block size is 1
291 self.FvInfFile.writelines("EFI_BLOCK_SIZE = 0x1" + T_CHAR_LF)
292
293 for BlockSize in self.BlockSizeList :
294 if BlockSize[0] is not None:
295 self.FvInfFile.writelines("EFI_BLOCK_SIZE = " + \
296 '0x%X' %BlockSize[0] + \
297 T_CHAR_LF)
298
299 if BlockSize[1] is not None:
300 self.FvInfFile.writelines("EFI_NUM_BLOCKS = " + \
301 ' 0x%X' %BlockSize[1] + \
302 T_CHAR_LF)
303
304 if self.BsBaseAddress is not None:
305 self.FvInfFile.writelines('EFI_BOOT_DRIVER_BASE_ADDRESS = ' + \
306 '0x%X' %self.BsBaseAddress)
307 if self.RtBaseAddress is not None:
308 self.FvInfFile.writelines('EFI_RUNTIME_DRIVER_BASE_ADDRESS = ' + \
309 '0x%X' %self.RtBaseAddress)
310 #
311 # Add attribute
312 #
313 self.FvInfFile.writelines("[attributes]" + T_CHAR_LF)
314
315 self.FvInfFile.writelines("EFI_ERASE_POLARITY = " + \
316 ' %s' %ErasePloarity + \
317 T_CHAR_LF)
318 if not (self.FvAttributeDict is None):
319 for FvAttribute in self.FvAttributeDict:
320 if FvAttribute == "FvUsedSizeEnable":
321 if self.FvAttributeDict[FvAttribute].upper() in ('TRUE', '1') :
322 self.UsedSizeEnable = True
323 continue
324 self.FvInfFile.writelines("EFI_" + \
325 FvAttribute + \
326 ' = ' + \
327 self.FvAttributeDict[FvAttribute] + \
328 T_CHAR_LF )
329 if self.FvAlignment is not None:
330 self.FvInfFile.writelines("EFI_FVB2_ALIGNMENT_" + \
331 self.FvAlignment.strip() + \
332 " = TRUE" + \
333 T_CHAR_LF)
334
335 #
336 # Generate FV extension header file
337 #
338 if not self.FvNameGuid:
339 if len(self.FvExtEntryType) > 0 or self.UsedSizeEnable:
340 GenFdsGlobalVariable.ErrorLogger("FV Extension Header Entries declared for %s with no FvNameGuid declaration." % (self.UiFvName))
341 else:
342 TotalSize = 16 + 4
343 Buffer = ''
344 if self.UsedSizeEnable:
345 TotalSize += (4 + 4)
346 ## define EFI_FV_EXT_TYPE_USED_SIZE_TYPE 0x03
347 #typedef struct
348 # {
349 # EFI_FIRMWARE_VOLUME_EXT_ENTRY Hdr;
350 # UINT32 UsedSize;
351 # } EFI_FIRMWARE_VOLUME_EXT_ENTRY_USED_SIZE_TYPE;
352 Buffer += pack('HHL', 8, 3, 0)
353
354 if self.FvNameString == 'TRUE':
355 #
356 # Create EXT entry for FV UI name
357 # This GUID is used: A67DF1FA-8DE8-4E98-AF09-4BDF2EFFBC7C
358 #
359 FvUiLen = len(self.UiFvName)
360 TotalSize += (FvUiLen + 16 + 4)
361 Guid = FV_UI_EXT_ENTY_GUID.split('-')
362 #
363 # Layout:
364 # EFI_FIRMWARE_VOLUME_EXT_ENTRY : size 4
365 # GUID : size 16
366 # FV UI name
367 #
368 Buffer += (pack('HH', (FvUiLen + 16 + 4), 0x0002)
369 + pack('=LHHBBBBBBBB', int(Guid[0], 16), int(Guid[1], 16), int(Guid[2], 16),
370 int(Guid[3][-4:-2], 16), int(Guid[3][-2:], 16), int(Guid[4][-12:-10], 16),
371 int(Guid[4][-10:-8], 16), int(Guid[4][-8:-6], 16), int(Guid[4][-6:-4], 16),
372 int(Guid[4][-4:-2], 16), int(Guid[4][-2:], 16))
373 + self.UiFvName)
374
375 for Index in range (0, len(self.FvExtEntryType)):
376 if self.FvExtEntryType[Index] == 'FILE':
377 # check if the path is absolute or relative
378 if os.path.isabs(self.FvExtEntryData[Index]):
379 FileFullPath = os.path.normpath(self.FvExtEntryData[Index])
380 else:
381 FileFullPath = os.path.normpath(os.path.join(GenFdsGlobalVariable.WorkSpaceDir, self.FvExtEntryData[Index]))
382 # check if the file path exists or not
383 if not os.path.isfile(FileFullPath):
384 GenFdsGlobalVariable.ErrorLogger("Error opening FV Extension Header Entry file %s." % (self.FvExtEntryData[Index]))
385 FvExtFile = open (FileFullPath,'rb')
386 FvExtFile.seek(0,2)
387 Size = FvExtFile.tell()
388 if Size >= 0x10000:
389 GenFdsGlobalVariable.ErrorLogger("The size of FV Extension Header Entry file %s exceeds 0x10000." % (self.FvExtEntryData[Index]))
390 TotalSize += (Size + 4)
391 FvExtFile.seek(0)
392 Buffer += pack('HH', (Size + 4), int(self.FvExtEntryTypeValue[Index], 16))
393 Buffer += FvExtFile.read()
394 FvExtFile.close()
395 if self.FvExtEntryType[Index] == 'DATA':
396 ByteList = self.FvExtEntryData[Index].split(',')
397 Size = len (ByteList)
398 if Size >= 0x10000:
399 GenFdsGlobalVariable.ErrorLogger("The size of FV Extension Header Entry data %s exceeds 0x10000." % (self.FvExtEntryData[Index]))
400 TotalSize += (Size + 4)
401 Buffer += pack('HH', (Size + 4), int(self.FvExtEntryTypeValue[Index], 16))
402 for Index1 in range (0, Size):
403 Buffer += pack('B', int(ByteList[Index1], 16))
404
405 Guid = self.FvNameGuid.split('-')
406 Buffer = pack('=LHHBBBBBBBBL',
407 int(Guid[0], 16),
408 int(Guid[1], 16),
409 int(Guid[2], 16),
410 int(Guid[3][-4:-2], 16),
411 int(Guid[3][-2:], 16),
412 int(Guid[4][-12:-10], 16),
413 int(Guid[4][-10:-8], 16),
414 int(Guid[4][-8:-6], 16),
415 int(Guid[4][-6:-4], 16),
416 int(Guid[4][-4:-2], 16),
417 int(Guid[4][-2:], 16),
418 TotalSize
419 ) + Buffer
420
421 #
422 # Generate FV extension header file if the total size is not zero
423 #
424 if TotalSize > 0:
425 FvExtHeaderFileName = os.path.join(GenFdsGlobalVariable.FvDir, self.UiFvName + '.ext')
426 FvExtHeaderFile = StringIO.StringIO()
427 FvExtHeaderFile.write(Buffer)
428 Changed = SaveFileOnChange(FvExtHeaderFileName, FvExtHeaderFile.getvalue(), True)
429 FvExtHeaderFile.close()
430 if Changed:
431 if os.path.exists (self.InfFileName):
432 os.remove (self.InfFileName)
433 self.FvInfFile.writelines("EFI_FV_EXT_HEADER_FILE_NAME = " + \
434 FvExtHeaderFileName + \
435 T_CHAR_LF)
436
437
438 #
439 # Add [Files]
440 #
441 self.FvInfFile.writelines("[files]" + T_CHAR_LF)
442 if VtfDict is not None and self.UiFvName in VtfDict:
443 self.FvInfFile.writelines("EFI_FILE_NAME = " + \
444 VtfDict[self.UiFvName] + \
445 T_CHAR_LF)