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