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