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