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