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