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