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
>= 0x10000:
200 #The max alignment supported by FFS is 64K.
201 self
.FvAlignment
= "64K"
203 self
.FvAlignment
= str (FvAlignmentValue
/ 0x400) + "K"
205 # FvAlignmentValue is less than 1K
206 self
.FvAlignment
= str (FvAlignmentValue
)
208 GenFds
.ImageBinDict
[self
.UiFvName
.upper() + 'fv'] = FvOutputFile
209 GenFdsGlobalVariable
.LargeFileInFvFlags
.pop()
211 GenFdsGlobalVariable
.ErrorLogger("Failed to generate %s FV file." %self
.UiFvName
)
216 # Calculate FV's block size
217 # Inherit block size from FD if no block size specified in FV
219 def _GetBlockSize(self
):
220 if self
.BlockSizeList
:
223 for FdName
in GenFdsGlobalVariable
.FdfParser
.Profile
.FdDict
.keys():
224 FdObj
= GenFdsGlobalVariable
.FdfParser
.Profile
.FdDict
[FdName
]
225 for RegionObj
in FdObj
.RegionList
:
226 if RegionObj
.RegionType
!= 'FV':
228 for RegionData
in RegionObj
.RegionDataList
:
230 # Found the FD and region that contain this FV
232 if self
.UiFvName
.upper() == RegionData
.upper():
233 RegionObj
.BlockInfoOfRegion(FdObj
.BlockSizeList
, self
)
234 if self
.BlockSizeList
:
238 ## __InitializeInf__()
240 # Initilize the inf file to create FV
242 # @param self The object pointer
243 # @param BaseAddress base address of FV
244 # @param BlockSize block size of FV
245 # @param BlockNum How many blocks in FV
246 # @param ErasePolarity Flash erase polarity
247 # @param VtfDict VTF objects
249 def __InitializeInf__ (self
, BaseAddress
= None, BlockSize
= None, BlockNum
= None, ErasePloarity
='1', VtfDict
=None) :
253 self
.InfFileName
= os
.path
.join(GenFdsGlobalVariable
.FvDir
,
254 self
.UiFvName
+ '.inf')
255 self
.FvInfFile
= StringIO
.StringIO()
260 self
.FvInfFile
.writelines("[options]" + T_CHAR_LF
)
261 if BaseAddress
!= None :
262 self
.FvInfFile
.writelines("EFI_BASE_ADDRESS = " + \
266 if BlockSize
!= None:
267 self
.FvInfFile
.writelines("EFI_BLOCK_SIZE = " + \
268 '0x%X' %BlockSize
+ \
271 self
.FvInfFile
.writelines("EFI_NUM_BLOCKS = " + \
272 ' 0x%X' %BlockNum
+ \
275 if self
.BlockSizeList
== []:
276 if not self
._GetBlockSize
():
277 #set default block size is 1
278 self
.FvInfFile
.writelines("EFI_BLOCK_SIZE = 0x1" + T_CHAR_LF
)
280 for BlockSize
in self
.BlockSizeList
:
281 if BlockSize
[0] != None:
282 self
.FvInfFile
.writelines("EFI_BLOCK_SIZE = " + \
283 '0x%X' %BlockSize
[0] + \
286 if BlockSize
[1] != None:
287 self
.FvInfFile
.writelines("EFI_NUM_BLOCKS = " + \
288 ' 0x%X' %BlockSize
[1] + \
291 if self
.BsBaseAddress
!= None:
292 self
.FvInfFile
.writelines('EFI_BOOT_DRIVER_BASE_ADDRESS = ' + \
293 '0x%X' %self
.BsBaseAddress
)
294 if self
.RtBaseAddress
!= None:
295 self
.FvInfFile
.writelines('EFI_RUNTIME_DRIVER_BASE_ADDRESS = ' + \
296 '0x%X' %self
.RtBaseAddress
)
300 self
.FvInfFile
.writelines("[attributes]" + T_CHAR_LF
)
302 self
.FvInfFile
.writelines("EFI_ERASE_POLARITY = " + \
303 ' %s' %ErasePloarity
+ \
305 if not (self
.FvAttributeDict
== None):
306 for FvAttribute
in self
.FvAttributeDict
.keys() :
307 self
.FvInfFile
.writelines("EFI_" + \
310 self
.FvAttributeDict
[FvAttribute
] + \
312 if self
.FvAlignment
!= None:
313 self
.FvInfFile
.writelines("EFI_FVB2_ALIGNMENT_" + \
314 self
.FvAlignment
.strip() + \
319 # Generate FV extension header file
321 if self
.FvNameGuid
== None or self
.FvNameGuid
== '':
322 if len(self
.FvExtEntryType
) > 0:
323 GenFdsGlobalVariable
.ErrorLogger("FV Extension Header Entries declared for %s with no FvNameGuid declaration." % (self
.UiFvName
))
325 if self
.FvNameGuid
<> None and self
.FvNameGuid
<> '':
328 if self
.FvNameString
== 'TRUE':
330 # Create EXT entry for FV UI name
331 # This GUID is used: A67DF1FA-8DE8-4E98-AF09-4BDF2EFFBC7C
333 FvUiLen
= len(self
.UiFvName
)
334 TotalSize
+= (FvUiLen
+ 16 + 4)
335 Guid
= FV_UI_EXT_ENTY_GUID
.split('-')
338 # EFI_FIRMWARE_VOLUME_EXT_ENTRY : size 4
342 Buffer
+= (pack('HH', (FvUiLen
+ 16 + 4), 0x0002)
343 + pack('=LHHBBBBBBBB', int(Guid
[0], 16), int(Guid
[1], 16), int(Guid
[2], 16),
344 int(Guid
[3][-4:-2], 16), int(Guid
[3][-2:], 16), int(Guid
[4][-12:-10], 16),
345 int(Guid
[4][-10:-8], 16), int(Guid
[4][-8:-6], 16), int(Guid
[4][-6:-4], 16),
346 int(Guid
[4][-4:-2], 16), int(Guid
[4][-2:], 16))
349 for Index
in range (0, len(self
.FvExtEntryType
)):
350 if self
.FvExtEntryType
[Index
] == 'FILE':
351 # check if the path is absolute or relative
352 if os
.path
.isabs(self
.FvExtEntryData
[Index
]):
353 FileFullPath
= os
.path
.normpath(self
.FvExtEntryData
[Index
])
355 FileFullPath
= os
.path
.normpath(os
.path
.join(GenFdsGlobalVariable
.WorkSpaceDir
, self
.FvExtEntryData
[Index
]))
356 # check if the file path exists or not
357 if not os
.path
.isfile(FileFullPath
):
358 GenFdsGlobalVariable
.ErrorLogger("Error opening FV Extension Header Entry file %s." % (self
.FvExtEntryData
[Index
]))
359 FvExtFile
= open (FileFullPath
,'rb')
361 Size
= FvExtFile
.tell()
363 GenFdsGlobalVariable
.ErrorLogger("The size of FV Extension Header Entry file %s exceeds 0x10000." % (self
.FvExtEntryData
[Index
]))
364 TotalSize
+= (Size
+ 4)
366 Buffer
+= pack('HH', (Size
+ 4), int(self
.FvExtEntryTypeValue
[Index
], 16))
367 Buffer
+= FvExtFile
.read()
369 if self
.FvExtEntryType
[Index
] == 'DATA':
370 ByteList
= self
.FvExtEntryData
[Index
].split(',')
371 Size
= len (ByteList
)
373 GenFdsGlobalVariable
.ErrorLogger("The size of FV Extension Header Entry data %s exceeds 0x10000." % (self
.FvExtEntryData
[Index
]))
374 TotalSize
+= (Size
+ 4)
375 Buffer
+= pack('HH', (Size
+ 4), int(self
.FvExtEntryTypeValue
[Index
], 16))
376 for Index1
in range (0, Size
):
377 Buffer
+= pack('B', int(ByteList
[Index1
], 16))
379 Guid
= self
.FvNameGuid
.split('-')
380 Buffer
= pack('=LHHBBBBBBBBL',
384 int(Guid
[3][-4:-2], 16),
385 int(Guid
[3][-2:], 16),
386 int(Guid
[4][-12:-10], 16),
387 int(Guid
[4][-10:-8], 16),
388 int(Guid
[4][-8:-6], 16),
389 int(Guid
[4][-6:-4], 16),
390 int(Guid
[4][-4:-2], 16),
391 int(Guid
[4][-2:], 16),
396 # Generate FV extension header file if the total size is not zero
399 FvExtHeaderFileName
= os
.path
.join(GenFdsGlobalVariable
.FvDir
, self
.UiFvName
+ '.ext')
400 FvExtHeaderFile
= StringIO
.StringIO()
401 FvExtHeaderFile
.write(Buffer
)
402 Changed
= SaveFileOnChange(FvExtHeaderFileName
, FvExtHeaderFile
.getvalue(), True)
403 FvExtHeaderFile
.close()
405 if os
.path
.exists (self
.InfFileName
):
406 os
.remove (self
.InfFileName
)
407 self
.FvInfFile
.writelines("EFI_FV_EXT_HEADER_FILE_NAME = " + \
408 FvExtHeaderFileName
+ \
415 self
.FvInfFile
.writelines("[files]" + T_CHAR_LF
)
416 if VtfDict
!= None and self
.UiFvName
in VtfDict
.keys():
417 self
.FvInfFile
.writelines("EFI_FILE_NAME = " + \
418 VtfDict
.get(self
.UiFvName
) + \