2 # process FV generation
4 # Copyright (c) 2007 - 2018, Intel Corporation. All rights reserved.<BR>
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
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.
18 import Common
.LongFilePathOs
as os
25 import FfsFileStatement
26 from GenFdsGlobalVariable
import GenFdsGlobalVariable
27 from GenFds
import GenFds
28 from CommonDataClass
.FdfClass
import FvClassObject
29 from Common
.Misc
import SaveFileOnChange
30 from Common
.LongFilePathSupport
import CopyLongFilePath
31 from Common
.LongFilePathSupport
import OpenLongFilePath
as open
34 FV_UI_EXT_ENTY_GUID
= 'A67DF1FA-8DE8-4E98-AF09-4BDF2EFFBC7C'
39 class FV (FvClassObject
):
42 # @param self The object pointer
45 FvClassObject
.__init
__(self
)
47 self
.FvAddressFile
= None
48 self
.BaseAddress
= None
49 self
.InfFileName
= None
50 self
.FvAddressFileName
= None
51 self
.CapsuleName
= None
52 self
.FvBaseAddress
= None
53 self
.FvForceRebase
= None
54 self
.FvRegionInFD
= None
55 self
.UsedSizeEnable
= False
59 # Generate Fv and add it to the Buffer
61 # @param self The object pointer
62 # @param Buffer The buffer generated FV data will be put
63 # @param BaseAddress base address of FV
64 # @param BlockSize block size of FV
65 # @param BlockNum How many blocks in FV
66 # @param ErasePolarity Flash erase polarity
67 # @param VtfDict VTF objects
68 # @param MacroDict macro value pair
69 # @retval string Generated FV file path
71 def AddToBuffer (self
, Buffer
, BaseAddress
=None, BlockSize
= None, BlockNum
=None, ErasePloarity
='1', VtfDict
=None, MacroDict
= {}, Flag
=False) :
73 if BaseAddress
is None and self
.UiFvName
.upper() + 'fv' in GenFds
.ImageBinDict
.keys():
74 return GenFds
.ImageBinDict
[self
.UiFvName
.upper() + 'fv']
77 # Check whether FV in Capsule is in FD flash region.
78 # If yes, return error. Doesn't support FV in Capsule image is also in FD flash region.
80 if self
.CapsuleName
is not None:
81 for FdName
in GenFdsGlobalVariable
.FdfParser
.Profile
.FdDict
.keys():
82 FdObj
= GenFdsGlobalVariable
.FdfParser
.Profile
.FdDict
[FdName
]
83 for RegionObj
in FdObj
.RegionList
:
84 if RegionObj
.RegionType
== 'FV':
85 for RegionData
in RegionObj
.RegionDataList
:
86 if RegionData
.endswith(".fv"):
88 elif RegionData
.upper() + 'fv' in GenFds
.ImageBinDict
.keys():
90 elif self
.UiFvName
.upper() == RegionData
.upper():
91 GenFdsGlobalVariable
.ErrorLogger("Capsule %s in FD region can't contain a FV %s in FD region." % (self
.CapsuleName
, self
.UiFvName
.upper()))
93 GenFdsGlobalVariable
.InfLogger( "\nGenerating %s FV" %self
.UiFvName
)
94 GenFdsGlobalVariable
.LargeFileInFvFlags
.append(False)
97 if self
.FvBaseAddress
is not None:
98 BaseAddress
= self
.FvBaseAddress
100 self
.__InitializeInf
__(BaseAddress
, BlockSize
, BlockNum
, ErasePloarity
, VtfDict
)
102 # First Process the Apriori section
104 MacroDict
.update(self
.DefineVarDict
)
106 GenFdsGlobalVariable
.VerboseLogger('First generate Apriori file !')
108 for AprSection
in self
.AprioriSectionList
:
109 FileName
= AprSection
.GenFfs (self
.UiFvName
, MacroDict
, IsMakefile
=Flag
)
110 FfsFileList
.append(FileName
)
111 # Add Apriori file name to Inf file
113 self
.FvInfFile
.writelines("EFI_FILE_NAME = " + \
117 # Process Modules in FfsList
118 for FfsFile
in self
.FfsList
:
120 if isinstance(FfsFile
, FfsFileStatement
.FileStatement
):
122 if GenFdsGlobalVariable
.EnableGenfdsMultiThread
and GenFdsGlobalVariable
.ModuleFile
and GenFdsGlobalVariable
.ModuleFile
.Path
.find(os
.path
.normpath(FfsFile
.InfFileName
)) == -1:
124 FileName
= FfsFile
.GenFfs(MacroDict
, FvParentAddr
=BaseAddress
, IsMakefile
=Flag
, FvName
=self
.UiFvName
)
125 FfsFileList
.append(FileName
)
127 self
.FvInfFile
.writelines("EFI_FILE_NAME = " + \
131 SaveFileOnChange(self
.InfFileName
, self
.FvInfFile
.getvalue(), False)
132 self
.FvInfFile
.close()
136 FvOutputFile
= os
.path
.join(GenFdsGlobalVariable
.FvDir
, self
.UiFvName
)
137 FvOutputFile
= FvOutputFile
+ '.Fv'
138 # BUGBUG: FvOutputFile could be specified from FDF file (FV section, CreateFile statement)
139 if self
.CreateFileName
is not None:
140 FvOutputFile
= self
.CreateFileName
143 GenFds
.ImageBinDict
[self
.UiFvName
.upper() + 'fv'] = FvOutputFile
146 FvInfoFileName
= os
.path
.join(GenFdsGlobalVariable
.FfsDir
, self
.UiFvName
+ '.inf')
148 CopyLongFilePath(GenFdsGlobalVariable
.FvAddressFileName
, FvInfoFileName
)
150 if os
.path
.exists (FvInfoFileName
):
151 OrigFvInfo
= open(FvInfoFileName
, 'r').read()
152 if GenFdsGlobalVariable
.LargeFileInFvFlags
[-1]:
153 FFSGuid
= GenFdsGlobalVariable
.EFI_FIRMWARE_FILE_SYSTEM3_GUID
154 GenFdsGlobalVariable
.GenerateFirmwareVolume(
157 AddressFile
=FvInfoFileName
,
159 ForceRebase
=self
.FvForceRebase
,
160 FileSystemGuid
=FFSGuid
164 if os
.path
.exists (FvInfoFileName
):
165 NewFvInfo
= open(FvInfoFileName
, 'r').read()
166 if NewFvInfo
is not None and NewFvInfo
!= OrigFvInfo
:
168 AddFileObj
= open(FvInfoFileName
, 'r')
169 AddrStrings
= AddFileObj
.readlines()
171 for AddrString
in AddrStrings
:
173 #get base address for the inside FvImage
174 FvChildAddr
.append (AddrString
)
175 elif AddrString
.find ("[FV_BASE_ADDRESS]") != -1:
179 if FvChildAddr
!= []:
181 for FfsFile
in self
.FfsList
:
182 FileName
= FfsFile
.GenFfs(MacroDict
, FvChildAddr
, BaseAddress
, IsMakefile
=Flag
, FvName
=self
.UiFvName
)
184 if GenFdsGlobalVariable
.LargeFileInFvFlags
[-1]:
185 FFSGuid
= GenFdsGlobalVariable
.EFI_FIRMWARE_FILE_SYSTEM3_GUID
;
187 GenFdsGlobalVariable
.GenerateFirmwareVolume(
190 AddressFile
=FvInfoFileName
,
192 ForceRebase
=self
.FvForceRebase
,
193 FileSystemGuid
=FFSGuid
197 # Write the Fv contents to Buffer
199 if os
.path
.isfile(FvOutputFile
):
200 FvFileObj
= open(FvOutputFile
, 'rb')
201 GenFdsGlobalVariable
.VerboseLogger("\nGenerate %s FV Successfully" % self
.UiFvName
)
202 GenFdsGlobalVariable
.SharpCounter
= 0
204 Buffer
.write(FvFileObj
.read())
206 # PI FvHeader is 0x48 byte
207 FvHeaderBuffer
= FvFileObj
.read(0x48)
208 # FV alignment position.
209 FvAlignmentValue
= 1 << (ord(FvHeaderBuffer
[0x2E]) & 0x1F)
210 if FvAlignmentValue
>= 0x400:
211 if FvAlignmentValue
>= 0x100000:
212 if FvAlignmentValue
>= 0x1000000:
213 #The max alignment supported by FFS is 16M.
214 self
.FvAlignment
= "16M"
216 self
.FvAlignment
= str(FvAlignmentValue
/ 0x100000) + "M"
218 self
.FvAlignment
= str(FvAlignmentValue
/ 0x400) + "K"
220 # FvAlignmentValue is less than 1K
221 self
.FvAlignment
= str (FvAlignmentValue
)
223 GenFds
.ImageBinDict
[self
.UiFvName
.upper() + 'fv'] = FvOutputFile
224 GenFdsGlobalVariable
.LargeFileInFvFlags
.pop()
226 GenFdsGlobalVariable
.ErrorLogger("Failed to generate %s FV file." %self
.UiFvName
)
231 # Calculate FV's block size
232 # Inherit block size from FD if no block size specified in FV
234 def _GetBlockSize(self
):
235 if self
.BlockSizeList
:
238 for FdName
in GenFdsGlobalVariable
.FdfParser
.Profile
.FdDict
.keys():
239 FdObj
= GenFdsGlobalVariable
.FdfParser
.Profile
.FdDict
[FdName
]
240 for RegionObj
in FdObj
.RegionList
:
241 if RegionObj
.RegionType
!= 'FV':
243 for RegionData
in RegionObj
.RegionDataList
:
245 # Found the FD and region that contain this FV
247 if self
.UiFvName
.upper() == RegionData
.upper():
248 RegionObj
.BlockInfoOfRegion(FdObj
.BlockSizeList
, self
)
249 if self
.BlockSizeList
:
253 ## __InitializeInf__()
255 # Initilize the inf file to create FV
257 # @param self The object pointer
258 # @param BaseAddress base address of FV
259 # @param BlockSize block size of FV
260 # @param BlockNum How many blocks in FV
261 # @param ErasePolarity Flash erase polarity
262 # @param VtfDict VTF objects
264 def __InitializeInf__ (self
, BaseAddress
= None, BlockSize
= None, BlockNum
= None, ErasePloarity
='1', VtfDict
=None) :
268 self
.InfFileName
= os
.path
.join(GenFdsGlobalVariable
.FvDir
,
269 self
.UiFvName
+ '.inf')
270 self
.FvInfFile
= StringIO
.StringIO()
275 self
.FvInfFile
.writelines("[options]" + T_CHAR_LF
)
276 if BaseAddress
is not None :
277 self
.FvInfFile
.writelines("EFI_BASE_ADDRESS = " + \
281 if BlockSize
is not None:
282 self
.FvInfFile
.writelines("EFI_BLOCK_SIZE = " + \
283 '0x%X' %BlockSize
+ \
285 if BlockNum
is not None:
286 self
.FvInfFile
.writelines("EFI_NUM_BLOCKS = " + \
287 ' 0x%X' %BlockNum
+ \
290 if self
.BlockSizeList
== []:
291 if not self
._GetBlockSize
():
292 #set default block size is 1
293 self
.FvInfFile
.writelines("EFI_BLOCK_SIZE = 0x1" + T_CHAR_LF
)
295 for BlockSize
in self
.BlockSizeList
:
296 if BlockSize
[0] is not None:
297 self
.FvInfFile
.writelines("EFI_BLOCK_SIZE = " + \
298 '0x%X' %BlockSize
[0] + \
301 if BlockSize
[1] is not None:
302 self
.FvInfFile
.writelines("EFI_NUM_BLOCKS = " + \
303 ' 0x%X' %BlockSize
[1] + \
306 if self
.BsBaseAddress
is not None:
307 self
.FvInfFile
.writelines('EFI_BOOT_DRIVER_BASE_ADDRESS = ' + \
308 '0x%X' %self
.BsBaseAddress
)
309 if self
.RtBaseAddress
is not None:
310 self
.FvInfFile
.writelines('EFI_RUNTIME_DRIVER_BASE_ADDRESS = ' + \
311 '0x%X' %self
.RtBaseAddress
)
315 self
.FvInfFile
.writelines("[attributes]" + T_CHAR_LF
)
317 self
.FvInfFile
.writelines("EFI_ERASE_POLARITY = " + \
318 ' %s' %ErasePloarity
+ \
320 if not (self
.FvAttributeDict
is None):
321 for FvAttribute
in self
.FvAttributeDict
:
322 if FvAttribute
== "FvUsedSizeEnable":
323 if self
.FvAttributeDict
[FvAttribute
].upper() in ('TRUE', '1') :
324 self
.UsedSizeEnable
= True
326 self
.FvInfFile
.writelines("EFI_" + \
329 self
.FvAttributeDict
[FvAttribute
] + \
331 if self
.FvAlignment
is not None:
332 self
.FvInfFile
.writelines("EFI_FVB2_ALIGNMENT_" + \
333 self
.FvAlignment
.strip() + \
338 # Generate FV extension header file
340 if self
.FvNameGuid
is None or self
.FvNameGuid
== '':
341 if len(self
.FvExtEntryType
) > 0 or self
.UsedSizeEnable
:
342 GenFdsGlobalVariable
.ErrorLogger("FV Extension Header Entries declared for %s with no FvNameGuid declaration." % (self
.UiFvName
))
344 if self
.FvNameGuid
<> None and self
.FvNameGuid
<> '':
347 if self
.UsedSizeEnable
:
349 ## define EFI_FV_EXT_TYPE_USED_SIZE_TYPE 0x03
352 # EFI_FIRMWARE_VOLUME_EXT_ENTRY Hdr;
354 # } EFI_FIRMWARE_VOLUME_EXT_ENTRY_USED_SIZE_TYPE;
355 Buffer
+= pack('HHL', 8, 3, 0)
357 if self
.FvNameString
== 'TRUE':
359 # Create EXT entry for FV UI name
360 # This GUID is used: A67DF1FA-8DE8-4E98-AF09-4BDF2EFFBC7C
362 FvUiLen
= len(self
.UiFvName
)
363 TotalSize
+= (FvUiLen
+ 16 + 4)
364 Guid
= FV_UI_EXT_ENTY_GUID
.split('-')
367 # EFI_FIRMWARE_VOLUME_EXT_ENTRY : size 4
371 Buffer
+= (pack('HH', (FvUiLen
+ 16 + 4), 0x0002)
372 + pack('=LHHBBBBBBBB', int(Guid
[0], 16), int(Guid
[1], 16), int(Guid
[2], 16),
373 int(Guid
[3][-4:-2], 16), int(Guid
[3][-2:], 16), int(Guid
[4][-12:-10], 16),
374 int(Guid
[4][-10:-8], 16), int(Guid
[4][-8:-6], 16), int(Guid
[4][-6:-4], 16),
375 int(Guid
[4][-4:-2], 16), int(Guid
[4][-2:], 16))
378 for Index
in range (0, len(self
.FvExtEntryType
)):
379 if self
.FvExtEntryType
[Index
] == 'FILE':
380 # check if the path is absolute or relative
381 if os
.path
.isabs(self
.FvExtEntryData
[Index
]):
382 FileFullPath
= os
.path
.normpath(self
.FvExtEntryData
[Index
])
384 FileFullPath
= os
.path
.normpath(os
.path
.join(GenFdsGlobalVariable
.WorkSpaceDir
, self
.FvExtEntryData
[Index
]))
385 # check if the file path exists or not
386 if not os
.path
.isfile(FileFullPath
):
387 GenFdsGlobalVariable
.ErrorLogger("Error opening FV Extension Header Entry file %s." % (self
.FvExtEntryData
[Index
]))
388 FvExtFile
= open (FileFullPath
,'rb')
390 Size
= FvExtFile
.tell()
392 GenFdsGlobalVariable
.ErrorLogger("The size of FV Extension Header Entry file %s exceeds 0x10000." % (self
.FvExtEntryData
[Index
]))
393 TotalSize
+= (Size
+ 4)
395 Buffer
+= pack('HH', (Size
+ 4), int(self
.FvExtEntryTypeValue
[Index
], 16))
396 Buffer
+= FvExtFile
.read()
398 if self
.FvExtEntryType
[Index
] == 'DATA':
399 ByteList
= self
.FvExtEntryData
[Index
].split(',')
400 Size
= len (ByteList
)
402 GenFdsGlobalVariable
.ErrorLogger("The size of FV Extension Header Entry data %s exceeds 0x10000." % (self
.FvExtEntryData
[Index
]))
403 TotalSize
+= (Size
+ 4)
404 Buffer
+= pack('HH', (Size
+ 4), int(self
.FvExtEntryTypeValue
[Index
], 16))
405 for Index1
in range (0, Size
):
406 Buffer
+= pack('B', int(ByteList
[Index1
], 16))
408 Guid
= self
.FvNameGuid
.split('-')
409 Buffer
= pack('=LHHBBBBBBBBL',
413 int(Guid
[3][-4:-2], 16),
414 int(Guid
[3][-2:], 16),
415 int(Guid
[4][-12:-10], 16),
416 int(Guid
[4][-10:-8], 16),
417 int(Guid
[4][-8:-6], 16),
418 int(Guid
[4][-6:-4], 16),
419 int(Guid
[4][-4:-2], 16),
420 int(Guid
[4][-2:], 16),
425 # Generate FV extension header file if the total size is not zero
428 FvExtHeaderFileName
= os
.path
.join(GenFdsGlobalVariable
.FvDir
, self
.UiFvName
+ '.ext')
429 FvExtHeaderFile
= StringIO
.StringIO()
430 FvExtHeaderFile
.write(Buffer
)
431 Changed
= SaveFileOnChange(FvExtHeaderFileName
, FvExtHeaderFile
.getvalue(), True)
432 FvExtHeaderFile
.close()
434 if os
.path
.exists (self
.InfFileName
):
435 os
.remove (self
.InfFileName
)
436 self
.FvInfFile
.writelines("EFI_FV_EXT_HEADER_FILE_NAME = " + \
437 FvExtHeaderFileName
+ \
444 self
.FvInfFile
.writelines("[files]" + T_CHAR_LF
)
445 if VtfDict
is not None and self
.UiFvName
in VtfDict
.keys():
446 self
.FvInfFile
.writelines("EFI_FILE_NAME = " + \
447 VtfDict
.get(self
.UiFvName
) + \