]> git.proxmox.com Git - mirror_edk2.git/blob - BaseTools/Source/Python/GenFds/Fv.py
BaseTools: Fixed bug for single FV generating.
[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 FvFileObj = open ( FvOutputFile,'r+b')
185
186 GenFdsGlobalVariable.VerboseLogger( "\nGenerate %s FV Successfully" %self.UiFvName)
187 GenFdsGlobalVariable.SharpCounter = 0
188
189 Buffer.write(FvFileObj.read())
190 FvFileObj.seek(0)
191 # PI FvHeader is 0x48 byte
192 FvHeaderBuffer = FvFileObj.read(0x48)
193 # FV alignment position.
194 FvAlignmentValue = 1 << (ord (FvHeaderBuffer[0x2E]) & 0x1F)
195 # FvAlignmentValue is larger than or equal to 1K
196 if FvAlignmentValue >= 0x400:
197 if FvAlignmentValue >= 0x10000:
198 #The max alignment supported by FFS is 64K.
199 self.FvAlignment = "64K"
200 else:
201 self.FvAlignment = str (FvAlignmentValue / 0x400) + "K"
202 else:
203 # FvAlignmentValue is less than 1K
204 self.FvAlignment = str (FvAlignmentValue)
205 FvFileObj.close()
206 GenFds.ImageBinDict[self.UiFvName.upper() + 'fv'] = FvOutputFile
207 GenFdsGlobalVariable.LargeFileInFvFlags.pop()
208 return FvOutputFile
209
210 ## _GetBlockSize()
211 #
212 # Calculate FV's block size
213 # Inherit block size from FD if no block size specified in FV
214 #
215 def _GetBlockSize(self):
216 if self.BlockSizeList:
217 return True
218
219 for FdName in GenFdsGlobalVariable.FdfParser.Profile.FdDict.keys():
220 FdObj = GenFdsGlobalVariable.FdfParser.Profile.FdDict[FdName]
221 for RegionObj in FdObj.RegionList:
222 if RegionObj.RegionType != 'FV':
223 continue
224 for RegionData in RegionObj.RegionDataList:
225 #
226 # Found the FD and region that contain this FV
227 #
228 if self.UiFvName.upper() == RegionData.upper():
229 RegionObj.BlockInfoOfRegion(FdObj.BlockSizeList, self)
230 if self.BlockSizeList:
231 return True
232 return False
233
234 ## __InitializeInf__()
235 #
236 # Initilize the inf file to create FV
237 #
238 # @param self The object pointer
239 # @param BaseAddress base address of FV
240 # @param BlockSize block size of FV
241 # @param BlockNum How many blocks in FV
242 # @param ErasePolarity Flash erase polarity
243 # @param VtfDict VTF objects
244 #
245 def __InitializeInf__ (self, BaseAddress = None, BlockSize= None, BlockNum = None, ErasePloarity='1', VtfDict=None) :
246 #
247 # Create FV inf file
248 #
249 self.InfFileName = os.path.join(GenFdsGlobalVariable.FvDir,
250 self.UiFvName + '.inf')
251 self.FvInfFile = StringIO.StringIO()
252
253 #
254 # Add [Options]
255 #
256 self.FvInfFile.writelines("[options]" + T_CHAR_LF)
257 if BaseAddress != None :
258 self.FvInfFile.writelines("EFI_BASE_ADDRESS = " + \
259 BaseAddress + \
260 T_CHAR_LF)
261
262 if BlockSize != None:
263 self.FvInfFile.writelines("EFI_BLOCK_SIZE = " + \
264 '0x%X' %BlockSize + \
265 T_CHAR_LF)
266 if BlockNum != None:
267 self.FvInfFile.writelines("EFI_NUM_BLOCKS = " + \
268 ' 0x%X' %BlockNum + \
269 T_CHAR_LF)
270 else:
271 if self.BlockSizeList == []:
272 if not self._GetBlockSize():
273 #set default block size is 1
274 self.FvInfFile.writelines("EFI_BLOCK_SIZE = 0x1" + T_CHAR_LF)
275
276 for BlockSize in self.BlockSizeList :
277 if BlockSize[0] != None:
278 self.FvInfFile.writelines("EFI_BLOCK_SIZE = " + \
279 '0x%X' %BlockSize[0] + \
280 T_CHAR_LF)
281
282 if BlockSize[1] != None:
283 self.FvInfFile.writelines("EFI_NUM_BLOCKS = " + \
284 ' 0x%X' %BlockSize[1] + \
285 T_CHAR_LF)
286
287 if self.BsBaseAddress != None:
288 self.FvInfFile.writelines('EFI_BOOT_DRIVER_BASE_ADDRESS = ' + \
289 '0x%X' %self.BsBaseAddress)
290 if self.RtBaseAddress != None:
291 self.FvInfFile.writelines('EFI_RUNTIME_DRIVER_BASE_ADDRESS = ' + \
292 '0x%X' %self.RtBaseAddress)
293 #
294 # Add attribute
295 #
296 self.FvInfFile.writelines("[attributes]" + T_CHAR_LF)
297
298 self.FvInfFile.writelines("EFI_ERASE_POLARITY = " + \
299 ' %s' %ErasePloarity + \
300 T_CHAR_LF)
301 if not (self.FvAttributeDict == None):
302 for FvAttribute in self.FvAttributeDict.keys() :
303 self.FvInfFile.writelines("EFI_" + \
304 FvAttribute + \
305 ' = ' + \
306 self.FvAttributeDict[FvAttribute] + \
307 T_CHAR_LF )
308 if self.FvAlignment != None:
309 self.FvInfFile.writelines("EFI_FVB2_ALIGNMENT_" + \
310 self.FvAlignment.strip() + \
311 " = TRUE" + \
312 T_CHAR_LF)
313
314 #
315 # Generate FV extension header file
316 #
317 if self.FvNameGuid == None or self.FvNameGuid == '':
318 if len(self.FvExtEntryType) > 0:
319 GenFdsGlobalVariable.ErrorLogger("FV Extension Header Entries declared for %s with no FvNameGuid declaration." % (self.UiFvName))
320
321 if self.FvNameGuid <> None and self.FvNameGuid <> '':
322 TotalSize = 16 + 4
323 Buffer = ''
324 if self.FvNameString == 'TRUE':
325 #
326 # Create EXT entry for FV UI name
327 # This GUID is used: A67DF1FA-8DE8-4E98-AF09-4BDF2EFFBC7C
328 #
329 FvUiLen = len(self.UiFvName)
330 TotalSize += (FvUiLen + 16 + 4)
331 Guid = FV_UI_EXT_ENTY_GUID.split('-')
332 #
333 # Layout:
334 # EFI_FIRMWARE_VOLUME_EXT_ENTRY : size 4
335 # GUID : size 16
336 # FV UI name
337 #
338 Buffer += (pack('HH', (FvUiLen + 16 + 4), 0x0002)
339 + pack('=LHHBBBBBBBB', int(Guid[0], 16), int(Guid[1], 16), int(Guid[2], 16),
340 int(Guid[3][-4:-2], 16), int(Guid[3][-2:], 16), int(Guid[4][-12:-10], 16),
341 int(Guid[4][-10:-8], 16), int(Guid[4][-8:-6], 16), int(Guid[4][-6:-4], 16),
342 int(Guid[4][-4:-2], 16), int(Guid[4][-2:], 16))
343 + self.UiFvName)
344
345 for Index in range (0, len(self.FvExtEntryType)):
346 if self.FvExtEntryType[Index] == 'FILE':
347 # check if the path is absolute or relative
348 if os.path.isabs(self.FvExtEntryData[Index]):
349 FileFullPath = os.path.normpath(self.FvExtEntryData[Index])
350 else:
351 FileFullPath = os.path.normpath(os.path.join(GenFdsGlobalVariable.WorkSpaceDir, self.FvExtEntryData[Index]))
352 # check if the file path exists or not
353 if not os.path.isfile(FileFullPath):
354 GenFdsGlobalVariable.ErrorLogger("Error opening FV Extension Header Entry file %s." % (self.FvExtEntryData[Index]))
355 FvExtFile = open (FileFullPath,'rb')
356 FvExtFile.seek(0,2)
357 Size = FvExtFile.tell()
358 if Size >= 0x10000:
359 GenFdsGlobalVariable.ErrorLogger("The size of FV Extension Header Entry file %s exceeds 0x10000." % (self.FvExtEntryData[Index]))
360 TotalSize += (Size + 4)
361 FvExtFile.seek(0)
362 Buffer += pack('HH', (Size + 4), int(self.FvExtEntryTypeValue[Index], 16))
363 Buffer += FvExtFile.read()
364 FvExtFile.close()
365 if self.FvExtEntryType[Index] == 'DATA':
366 ByteList = self.FvExtEntryData[Index].split(',')
367 Size = len (ByteList)
368 if Size >= 0x10000:
369 GenFdsGlobalVariable.ErrorLogger("The size of FV Extension Header Entry data %s exceeds 0x10000." % (self.FvExtEntryData[Index]))
370 TotalSize += (Size + 4)
371 Buffer += pack('HH', (Size + 4), int(self.FvExtEntryTypeValue[Index], 16))
372 for Index1 in range (0, Size):
373 Buffer += pack('B', int(ByteList[Index1], 16))
374
375 Guid = self.FvNameGuid.split('-')
376 Buffer = pack('=LHHBBBBBBBBL',
377 int(Guid[0], 16),
378 int(Guid[1], 16),
379 int(Guid[2], 16),
380 int(Guid[3][-4:-2], 16),
381 int(Guid[3][-2:], 16),
382 int(Guid[4][-12:-10], 16),
383 int(Guid[4][-10:-8], 16),
384 int(Guid[4][-8:-6], 16),
385 int(Guid[4][-6:-4], 16),
386 int(Guid[4][-4:-2], 16),
387 int(Guid[4][-2:], 16),
388 TotalSize
389 ) + Buffer
390
391 #
392 # Generate FV extension header file if the total size is not zero
393 #
394 if TotalSize > 0:
395 FvExtHeaderFileName = os.path.join(GenFdsGlobalVariable.FvDir, self.UiFvName + '.ext')
396 FvExtHeaderFile = StringIO.StringIO()
397 FvExtHeaderFile.write(Buffer)
398 Changed = SaveFileOnChange(FvExtHeaderFileName, FvExtHeaderFile.getvalue(), True)
399 FvExtHeaderFile.close()
400 if Changed:
401 if os.path.exists (self.InfFileName):
402 os.remove (self.InfFileName)
403 self.FvInfFile.writelines("EFI_FV_EXT_HEADER_FILE_NAME = " + \
404 FvExtHeaderFileName + \
405 T_CHAR_LF)
406
407
408 #
409 # Add [Files]
410 #
411 self.FvInfFile.writelines("[files]" + T_CHAR_LF)
412 if VtfDict != None and self.UiFvName in VtfDict.keys():
413 self.FvInfFile.writelines("EFI_FILE_NAME = " + \
414 VtfDict.get(self.UiFvName) + \
415 T_CHAR_LF)