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