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