2 # process FV generation
4 # Copyright (c) 2007 - 2017, 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 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
33 FV_UI_EXT_ENTY_GUID
= 'A67DF1FA-8DE8-4E98-AF09-4BDF2EFFBC7C'
38 class FV (FvClassObject
):
41 # @param self The object pointer
44 FvClassObject
.__init
__(self
)
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
57 # Generate Fv and add it to the Buffer
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
69 def AddToBuffer (self
, Buffer
, BaseAddress
=None, BlockSize
= None, BlockNum
=None, ErasePloarity
='1', VtfDict
=None, MacroDict
= {}) :
71 if BaseAddress
== None and self
.UiFvName
.upper() + 'fv' in GenFds
.ImageBinDict
.keys():
72 return GenFds
.ImageBinDict
[self
.UiFvName
.upper() + 'fv']
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.
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"):
86 elif RegionData
.upper() + 'fv' in GenFds
.ImageBinDict
.keys():
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()))
91 GenFdsGlobalVariable
.InfLogger( "\nGenerating %s FV" %self
.UiFvName
)
92 GenFdsGlobalVariable
.LargeFileInFvFlags
.append(False)
95 if self
.FvBaseAddress
!= None:
96 BaseAddress
= self
.FvBaseAddress
98 self
.__InitializeInf
__(BaseAddress
, BlockSize
, BlockNum
, ErasePloarity
, VtfDict
)
100 # First Process the Apriori section
102 MacroDict
.update(self
.DefineVarDict
)
104 GenFdsGlobalVariable
.VerboseLogger('First generate Apriori file !')
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 = " + \
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 = " + \
122 SaveFileOnChange(self
.InfFileName
, self
.FvInfFile
.getvalue(), False)
123 self
.FvInfFile
.close()
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
133 FvInfoFileName
= os
.path
.join(GenFdsGlobalVariable
.FfsDir
, self
.UiFvName
+ '.inf')
134 CopyLongFilePath(GenFdsGlobalVariable
.FvAddressFileName
, FvInfoFileName
)
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(
143 AddressFile
=FvInfoFileName
,
145 ForceRebase
=self
.FvForceRebase
,
146 FileSystemGuid
=FFSGuid
150 if os
.path
.exists (FvInfoFileName
):
151 NewFvInfo
= open(FvInfoFileName
, 'r').read()
152 if NewFvInfo
!= None and NewFvInfo
!= OrigFvInfo
:
154 AddFileObj
= open(FvInfoFileName
, 'r')
155 AddrStrings
= AddFileObj
.readlines()
157 for AddrString
in AddrStrings
:
159 #get base address for the inside FvImage
160 FvChildAddr
.append (AddrString
)
161 elif AddrString
.find ("[FV_BASE_ADDRESS]") != -1:
165 if FvChildAddr
!= []:
167 for FfsFile
in self
.FfsList
:
168 FileName
= FfsFile
.GenFfs(MacroDict
, FvChildAddr
, BaseAddress
)
170 if GenFdsGlobalVariable
.LargeFileInFvFlags
[-1]:
171 FFSGuid
= GenFdsGlobalVariable
.EFI_FIRMWARE_FILE_SYSTEM3_GUID
;
173 GenFdsGlobalVariable
.GenerateFirmwareVolume(
176 AddressFile
=FvInfoFileName
,
178 ForceRebase
=self
.FvForceRebase
,
179 FileSystemGuid
=FFSGuid
183 # Write the Fv contents to Buffer
185 if os
.path
.isfile(FvOutputFile
):
186 FvFileObj
= open ( FvOutputFile
,'rb')
188 GenFdsGlobalVariable
.VerboseLogger( "\nGenerate %s FV Successfully" %self
.UiFvName
)
189 GenFdsGlobalVariable
.SharpCounter
= 0
191 Buffer
.write(FvFileObj
.read())
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
>= 0x100000:
200 #The max alignment supported by FFS is 16M.
201 if FvAlignmentValue
>= 0x1000000:
202 self
.FvAlignment
= "16M"
204 self
.FvAlignment
= str(FvAlignmentValue
/ 0x100000) + "M"
206 self
.FvAlignment
= str (FvAlignmentValue
/ 0x400) + "K"
208 # FvAlignmentValue is less than 1K
209 self
.FvAlignment
= str (FvAlignmentValue
)
211 GenFds
.ImageBinDict
[self
.UiFvName
.upper() + 'fv'] = FvOutputFile
212 GenFdsGlobalVariable
.LargeFileInFvFlags
.pop()
214 GenFdsGlobalVariable
.ErrorLogger("Failed to generate %s FV file." %self
.UiFvName
)
219 # Calculate FV's block size
220 # Inherit block size from FD if no block size specified in FV
222 def _GetBlockSize(self
):
223 if self
.BlockSizeList
:
226 for FdName
in GenFdsGlobalVariable
.FdfParser
.Profile
.FdDict
.keys():
227 FdObj
= GenFdsGlobalVariable
.FdfParser
.Profile
.FdDict
[FdName
]
228 for RegionObj
in FdObj
.RegionList
:
229 if RegionObj
.RegionType
!= 'FV':
231 for RegionData
in RegionObj
.RegionDataList
:
233 # Found the FD and region that contain this FV
235 if self
.UiFvName
.upper() == RegionData
.upper():
236 RegionObj
.BlockInfoOfRegion(FdObj
.BlockSizeList
, self
)
237 if self
.BlockSizeList
:
241 ## __InitializeInf__()
243 # Initilize the inf file to create FV
245 # @param self The object pointer
246 # @param BaseAddress base address of FV
247 # @param BlockSize block size of FV
248 # @param BlockNum How many blocks in FV
249 # @param ErasePolarity Flash erase polarity
250 # @param VtfDict VTF objects
252 def __InitializeInf__ (self
, BaseAddress
= None, BlockSize
= None, BlockNum
= None, ErasePloarity
='1', VtfDict
=None) :
256 self
.InfFileName
= os
.path
.join(GenFdsGlobalVariable
.FvDir
,
257 self
.UiFvName
+ '.inf')
258 self
.FvInfFile
= StringIO
.StringIO()
263 self
.FvInfFile
.writelines("[options]" + T_CHAR_LF
)
264 if BaseAddress
!= None :
265 self
.FvInfFile
.writelines("EFI_BASE_ADDRESS = " + \
269 if BlockSize
!= None:
270 self
.FvInfFile
.writelines("EFI_BLOCK_SIZE = " + \
271 '0x%X' %BlockSize
+ \
274 self
.FvInfFile
.writelines("EFI_NUM_BLOCKS = " + \
275 ' 0x%X' %BlockNum
+ \
278 if self
.BlockSizeList
== []:
279 if not self
._GetBlockSize
():
280 #set default block size is 1
281 self
.FvInfFile
.writelines("EFI_BLOCK_SIZE = 0x1" + T_CHAR_LF
)
283 for BlockSize
in self
.BlockSizeList
:
284 if BlockSize
[0] != None:
285 self
.FvInfFile
.writelines("EFI_BLOCK_SIZE = " + \
286 '0x%X' %BlockSize
[0] + \
289 if BlockSize
[1] != None:
290 self
.FvInfFile
.writelines("EFI_NUM_BLOCKS = " + \
291 ' 0x%X' %BlockSize
[1] + \
294 if self
.BsBaseAddress
!= None:
295 self
.FvInfFile
.writelines('EFI_BOOT_DRIVER_BASE_ADDRESS = ' + \
296 '0x%X' %self
.BsBaseAddress
)
297 if self
.RtBaseAddress
!= None:
298 self
.FvInfFile
.writelines('EFI_RUNTIME_DRIVER_BASE_ADDRESS = ' + \
299 '0x%X' %self
.RtBaseAddress
)
303 self
.FvInfFile
.writelines("[attributes]" + T_CHAR_LF
)
305 self
.FvInfFile
.writelines("EFI_ERASE_POLARITY = " + \
306 ' %s' %ErasePloarity
+ \
308 if not (self
.FvAttributeDict
== None):
309 for FvAttribute
in self
.FvAttributeDict
.keys() :
310 self
.FvInfFile
.writelines("EFI_" + \
313 self
.FvAttributeDict
[FvAttribute
] + \
315 if self
.FvAlignment
!= None:
316 self
.FvInfFile
.writelines("EFI_FVB2_ALIGNMENT_" + \
317 self
.FvAlignment
.strip() + \
322 # Generate FV extension header file
324 if self
.FvNameGuid
== None or self
.FvNameGuid
== '':
325 if len(self
.FvExtEntryType
) > 0:
326 GenFdsGlobalVariable
.ErrorLogger("FV Extension Header Entries declared for %s with no FvNameGuid declaration." % (self
.UiFvName
))
328 if self
.FvNameGuid
<> None and self
.FvNameGuid
<> '':
331 if self
.FvNameString
== 'TRUE':
333 # Create EXT entry for FV UI name
334 # This GUID is used: A67DF1FA-8DE8-4E98-AF09-4BDF2EFFBC7C
336 FvUiLen
= len(self
.UiFvName
)
337 TotalSize
+= (FvUiLen
+ 16 + 4)
338 Guid
= FV_UI_EXT_ENTY_GUID
.split('-')
341 # EFI_FIRMWARE_VOLUME_EXT_ENTRY : size 4
345 Buffer
+= (pack('HH', (FvUiLen
+ 16 + 4), 0x0002)
346 + pack('=LHHBBBBBBBB', int(Guid
[0], 16), int(Guid
[1], 16), int(Guid
[2], 16),
347 int(Guid
[3][-4:-2], 16), int(Guid
[3][-2:], 16), int(Guid
[4][-12:-10], 16),
348 int(Guid
[4][-10:-8], 16), int(Guid
[4][-8:-6], 16), int(Guid
[4][-6:-4], 16),
349 int(Guid
[4][-4:-2], 16), int(Guid
[4][-2:], 16))
352 for Index
in range (0, len(self
.FvExtEntryType
)):
353 if self
.FvExtEntryType
[Index
] == 'FILE':
354 # check if the path is absolute or relative
355 if os
.path
.isabs(self
.FvExtEntryData
[Index
]):
356 FileFullPath
= os
.path
.normpath(self
.FvExtEntryData
[Index
])
358 FileFullPath
= os
.path
.normpath(os
.path
.join(GenFdsGlobalVariable
.WorkSpaceDir
, self
.FvExtEntryData
[Index
]))
359 # check if the file path exists or not
360 if not os
.path
.isfile(FileFullPath
):
361 GenFdsGlobalVariable
.ErrorLogger("Error opening FV Extension Header Entry file %s." % (self
.FvExtEntryData
[Index
]))
362 FvExtFile
= open (FileFullPath
,'rb')
364 Size
= FvExtFile
.tell()
366 GenFdsGlobalVariable
.ErrorLogger("The size of FV Extension Header Entry file %s exceeds 0x10000." % (self
.FvExtEntryData
[Index
]))
367 TotalSize
+= (Size
+ 4)
369 Buffer
+= pack('HH', (Size
+ 4), int(self
.FvExtEntryTypeValue
[Index
], 16))
370 Buffer
+= FvExtFile
.read()
372 if self
.FvExtEntryType
[Index
] == 'DATA':
373 ByteList
= self
.FvExtEntryData
[Index
].split(',')
374 Size
= len (ByteList
)
376 GenFdsGlobalVariable
.ErrorLogger("The size of FV Extension Header Entry data %s exceeds 0x10000." % (self
.FvExtEntryData
[Index
]))
377 TotalSize
+= (Size
+ 4)
378 Buffer
+= pack('HH', (Size
+ 4), int(self
.FvExtEntryTypeValue
[Index
], 16))
379 for Index1
in range (0, Size
):
380 Buffer
+= pack('B', int(ByteList
[Index1
], 16))
382 Guid
= self
.FvNameGuid
.split('-')
383 Buffer
= pack('=LHHBBBBBBBBL',
387 int(Guid
[3][-4:-2], 16),
388 int(Guid
[3][-2:], 16),
389 int(Guid
[4][-12:-10], 16),
390 int(Guid
[4][-10:-8], 16),
391 int(Guid
[4][-8:-6], 16),
392 int(Guid
[4][-6:-4], 16),
393 int(Guid
[4][-4:-2], 16),
394 int(Guid
[4][-2:], 16),
399 # Generate FV extension header file if the total size is not zero
402 FvExtHeaderFileName
= os
.path
.join(GenFdsGlobalVariable
.FvDir
, self
.UiFvName
+ '.ext')
403 FvExtHeaderFile
= StringIO
.StringIO()
404 FvExtHeaderFile
.write(Buffer
)
405 Changed
= SaveFileOnChange(FvExtHeaderFileName
, FvExtHeaderFile
.getvalue(), True)
406 FvExtHeaderFile
.close()
408 if os
.path
.exists (self
.InfFileName
):
409 os
.remove (self
.InfFileName
)
410 self
.FvInfFile
.writelines("EFI_FV_EXT_HEADER_FILE_NAME = " + \
411 FvExtHeaderFileName
+ \
418 self
.FvInfFile
.writelines("[files]" + T_CHAR_LF
)
419 if VtfDict
!= None and self
.UiFvName
in VtfDict
.keys():
420 self
.FvInfFile
.writelines("EFI_FILE_NAME = " + \
421 VtfDict
.get(self
.UiFvName
) + \