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
:
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 FdObj
in GenFdsGlobalVariable
.FdfParser
.Profile
.FdDict
.values():
82 for RegionObj
in FdObj
.RegionList
:
83 if RegionObj
.RegionType
== 'FV':
84 for RegionData
in RegionObj
.RegionDataList
:
85 if RegionData
.endswith(".fv"):
87 elif RegionData
.upper() + 'fv' in GenFds
.ImageBinDict
:
89 elif self
.UiFvName
.upper() == RegionData
.upper():
90 GenFdsGlobalVariable
.ErrorLogger("Capsule %s in FD region can't contain a FV %s in FD region." % (self
.CapsuleName
, self
.UiFvName
.upper()))
92 GenFdsGlobalVariable
.InfLogger( "\nGenerating %s FV" %self
.UiFvName
)
93 GenFdsGlobalVariable
.LargeFileInFvFlags
.append(False)
96 if self
.FvBaseAddress
is not None:
97 BaseAddress
= self
.FvBaseAddress
99 self
.__InitializeInf
__(BaseAddress
, BlockSize
, BlockNum
, ErasePloarity
, VtfDict
)
101 # First Process the Apriori section
103 MacroDict
.update(self
.DefineVarDict
)
105 GenFdsGlobalVariable
.VerboseLogger('First generate Apriori file !')
107 for AprSection
in self
.AprioriSectionList
:
108 FileName
= AprSection
.GenFfs (self
.UiFvName
, MacroDict
, IsMakefile
=Flag
)
109 FfsFileList
.append(FileName
)
110 # Add Apriori file name to Inf file
112 self
.FvInfFile
.writelines("EFI_FILE_NAME = " + \
116 # Process Modules in FfsList
117 for FfsFile
in self
.FfsList
:
119 if isinstance(FfsFile
, FfsFileStatement
.FileStatement
):
121 if GenFdsGlobalVariable
.EnableGenfdsMultiThread
and GenFdsGlobalVariable
.ModuleFile
and GenFdsGlobalVariable
.ModuleFile
.Path
.find(os
.path
.normpath(FfsFile
.InfFileName
)) == -1:
123 FileName
= FfsFile
.GenFfs(MacroDict
, FvParentAddr
=BaseAddress
, IsMakefile
=Flag
, FvName
=self
.UiFvName
)
124 FfsFileList
.append(FileName
)
126 self
.FvInfFile
.writelines("EFI_FILE_NAME = " + \
130 SaveFileOnChange(self
.InfFileName
, self
.FvInfFile
.getvalue(), False)
131 self
.FvInfFile
.close()
135 FvOutputFile
= os
.path
.join(GenFdsGlobalVariable
.FvDir
, self
.UiFvName
)
136 FvOutputFile
= FvOutputFile
+ '.Fv'
137 # BUGBUG: FvOutputFile could be specified from FDF file (FV section, CreateFile statement)
138 if self
.CreateFileName
is not None:
139 FvOutputFile
= self
.CreateFileName
142 GenFds
.ImageBinDict
[self
.UiFvName
.upper() + 'fv'] = FvOutputFile
145 FvInfoFileName
= os
.path
.join(GenFdsGlobalVariable
.FfsDir
, self
.UiFvName
+ '.inf')
147 CopyLongFilePath(GenFdsGlobalVariable
.FvAddressFileName
, FvInfoFileName
)
149 if os
.path
.exists (FvInfoFileName
):
150 OrigFvInfo
= open(FvInfoFileName
, 'r').read()
151 if GenFdsGlobalVariable
.LargeFileInFvFlags
[-1]:
152 FFSGuid
= GenFdsGlobalVariable
.EFI_FIRMWARE_FILE_SYSTEM3_GUID
153 GenFdsGlobalVariable
.GenerateFirmwareVolume(
156 AddressFile
=FvInfoFileName
,
158 ForceRebase
=self
.FvForceRebase
,
159 FileSystemGuid
=FFSGuid
163 if os
.path
.exists (FvInfoFileName
):
164 NewFvInfo
= open(FvInfoFileName
, 'r').read()
165 if NewFvInfo
is not None and NewFvInfo
!= OrigFvInfo
:
167 AddFileObj
= open(FvInfoFileName
, 'r')
168 AddrStrings
= AddFileObj
.readlines()
170 for AddrString
in AddrStrings
:
172 #get base address for the inside FvImage
173 FvChildAddr
.append (AddrString
)
174 elif AddrString
.find ("[FV_BASE_ADDRESS]") != -1:
178 if FvChildAddr
!= []:
180 for FfsFile
in self
.FfsList
:
181 FileName
= FfsFile
.GenFfs(MacroDict
, FvChildAddr
, BaseAddress
, IsMakefile
=Flag
, FvName
=self
.UiFvName
)
183 if GenFdsGlobalVariable
.LargeFileInFvFlags
[-1]:
184 FFSGuid
= GenFdsGlobalVariable
.EFI_FIRMWARE_FILE_SYSTEM3_GUID
;
186 GenFdsGlobalVariable
.GenerateFirmwareVolume(
189 AddressFile
=FvInfoFileName
,
191 ForceRebase
=self
.FvForceRebase
,
192 FileSystemGuid
=FFSGuid
196 # Write the Fv contents to Buffer
198 if os
.path
.isfile(FvOutputFile
):
199 FvFileObj
= open(FvOutputFile
, 'rb')
200 GenFdsGlobalVariable
.VerboseLogger("\nGenerate %s FV Successfully" % self
.UiFvName
)
201 GenFdsGlobalVariable
.SharpCounter
= 0
203 Buffer
.write(FvFileObj
.read())
205 # PI FvHeader is 0x48 byte
206 FvHeaderBuffer
= FvFileObj
.read(0x48)
207 # FV alignment position.
208 FvAlignmentValue
= 1 << (ord(FvHeaderBuffer
[0x2E]) & 0x1F)
209 if FvAlignmentValue
>= 0x400:
210 if FvAlignmentValue
>= 0x100000:
211 if FvAlignmentValue
>= 0x1000000:
212 #The max alignment supported by FFS is 16M.
213 self
.FvAlignment
= "16M"
215 self
.FvAlignment
= str(FvAlignmentValue
/ 0x100000) + "M"
217 self
.FvAlignment
= str(FvAlignmentValue
/ 0x400) + "K"
219 # FvAlignmentValue is less than 1K
220 self
.FvAlignment
= str (FvAlignmentValue
)
222 GenFds
.ImageBinDict
[self
.UiFvName
.upper() + 'fv'] = FvOutputFile
223 GenFdsGlobalVariable
.LargeFileInFvFlags
.pop()
225 GenFdsGlobalVariable
.ErrorLogger("Failed to generate %s FV file." %self
.UiFvName
)
230 # Calculate FV's block size
231 # Inherit block size from FD if no block size specified in FV
233 def _GetBlockSize(self
):
234 if self
.BlockSizeList
:
237 for FdObj
in GenFdsGlobalVariable
.FdfParser
.Profile
.FdDict
.values():
238 for RegionObj
in FdObj
.RegionList
:
239 if RegionObj
.RegionType
!= 'FV':
241 for RegionData
in RegionObj
.RegionDataList
:
243 # Found the FD and region that contain this FV
245 if self
.UiFvName
.upper() == RegionData
.upper():
246 RegionObj
.BlockInfoOfRegion(FdObj
.BlockSizeList
, self
)
247 if self
.BlockSizeList
:
251 ## __InitializeInf__()
253 # Initilize the inf file to create FV
255 # @param self The object pointer
256 # @param BaseAddress base address of FV
257 # @param BlockSize block size of FV
258 # @param BlockNum How many blocks in FV
259 # @param ErasePolarity Flash erase polarity
260 # @param VtfDict VTF objects
262 def __InitializeInf__ (self
, BaseAddress
= None, BlockSize
= None, BlockNum
= None, ErasePloarity
='1', VtfDict
=None) :
266 self
.InfFileName
= os
.path
.join(GenFdsGlobalVariable
.FvDir
,
267 self
.UiFvName
+ '.inf')
268 self
.FvInfFile
= StringIO
.StringIO()
273 self
.FvInfFile
.writelines("[options]" + T_CHAR_LF
)
274 if BaseAddress
is not None :
275 self
.FvInfFile
.writelines("EFI_BASE_ADDRESS = " + \
279 if BlockSize
is not None:
280 self
.FvInfFile
.writelines("EFI_BLOCK_SIZE = " + \
281 '0x%X' %BlockSize
+ \
283 if BlockNum
is not None:
284 self
.FvInfFile
.writelines("EFI_NUM_BLOCKS = " + \
285 ' 0x%X' %BlockNum
+ \
288 if self
.BlockSizeList
== []:
289 if not self
._GetBlockSize
():
290 #set default block size is 1
291 self
.FvInfFile
.writelines("EFI_BLOCK_SIZE = 0x1" + T_CHAR_LF
)
293 for BlockSize
in self
.BlockSizeList
:
294 if BlockSize
[0] is not None:
295 self
.FvInfFile
.writelines("EFI_BLOCK_SIZE = " + \
296 '0x%X' %BlockSize
[0] + \
299 if BlockSize
[1] is not None:
300 self
.FvInfFile
.writelines("EFI_NUM_BLOCKS = " + \
301 ' 0x%X' %BlockSize
[1] + \
304 if self
.BsBaseAddress
is not None:
305 self
.FvInfFile
.writelines('EFI_BOOT_DRIVER_BASE_ADDRESS = ' + \
306 '0x%X' %self
.BsBaseAddress
)
307 if self
.RtBaseAddress
is not None:
308 self
.FvInfFile
.writelines('EFI_RUNTIME_DRIVER_BASE_ADDRESS = ' + \
309 '0x%X' %self
.RtBaseAddress
)
313 self
.FvInfFile
.writelines("[attributes]" + T_CHAR_LF
)
315 self
.FvInfFile
.writelines("EFI_ERASE_POLARITY = " + \
316 ' %s' %ErasePloarity
+ \
318 if not (self
.FvAttributeDict
is None):
319 for FvAttribute
in self
.FvAttributeDict
:
320 if FvAttribute
== "FvUsedSizeEnable":
321 if self
.FvAttributeDict
[FvAttribute
].upper() in ('TRUE', '1') :
322 self
.UsedSizeEnable
= True
324 self
.FvInfFile
.writelines("EFI_" + \
327 self
.FvAttributeDict
[FvAttribute
] + \
329 if self
.FvAlignment
is not None:
330 self
.FvInfFile
.writelines("EFI_FVB2_ALIGNMENT_" + \
331 self
.FvAlignment
.strip() + \
336 # Generate FV extension header file
338 if not self
.FvNameGuid
:
339 if len(self
.FvExtEntryType
) > 0 or self
.UsedSizeEnable
:
340 GenFdsGlobalVariable
.ErrorLogger("FV Extension Header Entries declared for %s with no FvNameGuid declaration." % (self
.UiFvName
))
344 if self
.UsedSizeEnable
:
346 ## define EFI_FV_EXT_TYPE_USED_SIZE_TYPE 0x03
349 # EFI_FIRMWARE_VOLUME_EXT_ENTRY Hdr;
351 # } EFI_FIRMWARE_VOLUME_EXT_ENTRY_USED_SIZE_TYPE;
352 Buffer
+= pack('HHL', 8, 3, 0)
354 if self
.FvNameString
== 'TRUE':
356 # Create EXT entry for FV UI name
357 # This GUID is used: A67DF1FA-8DE8-4E98-AF09-4BDF2EFFBC7C
359 FvUiLen
= len(self
.UiFvName
)
360 TotalSize
+= (FvUiLen
+ 16 + 4)
361 Guid
= FV_UI_EXT_ENTY_GUID
.split('-')
364 # EFI_FIRMWARE_VOLUME_EXT_ENTRY : size 4
368 Buffer
+= (pack('HH', (FvUiLen
+ 16 + 4), 0x0002)
369 + pack('=LHHBBBBBBBB', int(Guid
[0], 16), int(Guid
[1], 16), int(Guid
[2], 16),
370 int(Guid
[3][-4:-2], 16), int(Guid
[3][-2:], 16), int(Guid
[4][-12:-10], 16),
371 int(Guid
[4][-10:-8], 16), int(Guid
[4][-8:-6], 16), int(Guid
[4][-6:-4], 16),
372 int(Guid
[4][-4:-2], 16), int(Guid
[4][-2:], 16))
375 for Index
in range (0, len(self
.FvExtEntryType
)):
376 if self
.FvExtEntryType
[Index
] == 'FILE':
377 # check if the path is absolute or relative
378 if os
.path
.isabs(self
.FvExtEntryData
[Index
]):
379 FileFullPath
= os
.path
.normpath(self
.FvExtEntryData
[Index
])
381 FileFullPath
= os
.path
.normpath(os
.path
.join(GenFdsGlobalVariable
.WorkSpaceDir
, self
.FvExtEntryData
[Index
]))
382 # check if the file path exists or not
383 if not os
.path
.isfile(FileFullPath
):
384 GenFdsGlobalVariable
.ErrorLogger("Error opening FV Extension Header Entry file %s." % (self
.FvExtEntryData
[Index
]))
385 FvExtFile
= open (FileFullPath
,'rb')
387 Size
= FvExtFile
.tell()
389 GenFdsGlobalVariable
.ErrorLogger("The size of FV Extension Header Entry file %s exceeds 0x10000." % (self
.FvExtEntryData
[Index
]))
390 TotalSize
+= (Size
+ 4)
392 Buffer
+= pack('HH', (Size
+ 4), int(self
.FvExtEntryTypeValue
[Index
], 16))
393 Buffer
+= FvExtFile
.read()
395 if self
.FvExtEntryType
[Index
] == 'DATA':
396 ByteList
= self
.FvExtEntryData
[Index
].split(',')
397 Size
= len (ByteList
)
399 GenFdsGlobalVariable
.ErrorLogger("The size of FV Extension Header Entry data %s exceeds 0x10000." % (self
.FvExtEntryData
[Index
]))
400 TotalSize
+= (Size
+ 4)
401 Buffer
+= pack('HH', (Size
+ 4), int(self
.FvExtEntryTypeValue
[Index
], 16))
402 for Index1
in range (0, Size
):
403 Buffer
+= pack('B', int(ByteList
[Index1
], 16))
405 Guid
= self
.FvNameGuid
.split('-')
406 Buffer
= pack('=LHHBBBBBBBBL',
410 int(Guid
[3][-4:-2], 16),
411 int(Guid
[3][-2:], 16),
412 int(Guid
[4][-12:-10], 16),
413 int(Guid
[4][-10:-8], 16),
414 int(Guid
[4][-8:-6], 16),
415 int(Guid
[4][-6:-4], 16),
416 int(Guid
[4][-4:-2], 16),
417 int(Guid
[4][-2:], 16),
422 # Generate FV extension header file if the total size is not zero
425 FvExtHeaderFileName
= os
.path
.join(GenFdsGlobalVariable
.FvDir
, self
.UiFvName
+ '.ext')
426 FvExtHeaderFile
= StringIO
.StringIO()
427 FvExtHeaderFile
.write(Buffer
)
428 Changed
= SaveFileOnChange(FvExtHeaderFileName
, FvExtHeaderFile
.getvalue(), True)
429 FvExtHeaderFile
.close()
431 if os
.path
.exists (self
.InfFileName
):
432 os
.remove (self
.InfFileName
)
433 self
.FvInfFile
.writelines("EFI_FV_EXT_HEADER_FILE_NAME = " + \
434 FvExtHeaderFileName
+ \
441 self
.FvInfFile
.writelines("[files]" + T_CHAR_LF
)
442 if VtfDict
is not None and self
.UiFvName
in VtfDict
:
443 self
.FvInfFile
.writelines("EFI_FILE_NAME = " + \
444 VtfDict
[self
.UiFvName
] + \