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 from __future__
import absolute_import
19 import Common
.LongFilePathOs
as os
21 from io
import BytesIO
23 from . import FfsFileStatement
24 from .GenFdsGlobalVariable
import GenFdsGlobalVariable
25 from Common
.Misc
import SaveFileOnChange
, PackGUID
26 from Common
.LongFilePathSupport
import CopyLongFilePath
27 from Common
.LongFilePathSupport
import OpenLongFilePath
as open
28 from Common
.DataType
import *
30 FV_UI_EXT_ENTY_GUID
= 'A67DF1FA-8DE8-4E98-AF09-4BDF2EFFBC7C'
38 # @param self The object pointer
40 def __init__(self
, Name
=None):
42 self
.CreateFileName
= None
43 self
.BlockSizeList
= []
44 self
.DefineVarDict
= {}
46 self
.FvAlignment
= None
47 self
.FvAttributeDict
= {}
48 self
.FvNameGuid
= None
49 self
.FvNameString
= None
50 self
.AprioriSectionList
= []
52 self
.BsBaseAddress
= None
53 self
.RtBaseAddress
= None
55 self
.FvAddressFile
= None
56 self
.BaseAddress
= None
57 self
.InfFileName
= None
58 self
.FvAddressFileName
= None
59 self
.CapsuleName
= None
60 self
.FvBaseAddress
= None
61 self
.FvForceRebase
= None
62 self
.FvRegionInFD
= None
63 self
.UsedSizeEnable
= False
64 self
.FvExtEntryTypeValue
= []
65 self
.FvExtEntryType
= []
66 self
.FvExtEntryData
= []
69 # Generate Fv and add it to the Buffer
71 # @param self The object pointer
72 # @param Buffer The buffer generated FV data will be put
73 # @param BaseAddress base address of FV
74 # @param BlockSize block size of FV
75 # @param BlockNum How many blocks in FV
76 # @param ErasePolarity Flash erase polarity
77 # @param MacroDict macro value pair
78 # @retval string Generated FV file path
80 def AddToBuffer (self
, Buffer
, BaseAddress
=None, BlockSize
= None, BlockNum
=None, ErasePloarity
='1', MacroDict
= {}, Flag
=False):
81 if BaseAddress
is None and self
.UiFvName
.upper() + 'fv' in GenFdsGlobalVariable
.ImageBinDict
:
82 return GenFdsGlobalVariable
.ImageBinDict
[self
.UiFvName
.upper() + 'fv']
85 # Check whether FV in Capsule is in FD flash region.
86 # If yes, return error. Doesn't support FV in Capsule image is also in FD flash region.
88 if self
.CapsuleName
is not None:
89 for FdObj
in GenFdsGlobalVariable
.FdfParser
.Profile
.FdDict
.values():
90 for RegionObj
in FdObj
.RegionList
:
91 if RegionObj
.RegionType
== BINARY_FILE_TYPE_FV
:
92 for RegionData
in RegionObj
.RegionDataList
:
93 if RegionData
.endswith(".fv"):
95 elif RegionData
.upper() + 'fv' in GenFdsGlobalVariable
.ImageBinDict
:
97 elif self
.UiFvName
.upper() == RegionData
.upper():
98 GenFdsGlobalVariable
.ErrorLogger("Capsule %s in FD region can't contain a FV %s in FD region." % (self
.CapsuleName
, self
.UiFvName
.upper()))
100 GenFdsGlobalVariable
.InfLogger( "\nGenerating %s FV" %self
.UiFvName
)
101 GenFdsGlobalVariable
.LargeFileInFvFlags
.append(False)
104 if self
.FvBaseAddress
is not None:
105 BaseAddress
= self
.FvBaseAddress
107 self
._InitializeInf
(BaseAddress
, BlockSize
, BlockNum
, ErasePloarity
)
109 # First Process the Apriori section
111 MacroDict
.update(self
.DefineVarDict
)
113 GenFdsGlobalVariable
.VerboseLogger('First generate Apriori file !')
115 for AprSection
in self
.AprioriSectionList
:
116 FileName
= AprSection
.GenFfs (self
.UiFvName
, MacroDict
, IsMakefile
=Flag
)
117 FfsFileList
.append(FileName
)
118 # Add Apriori file name to Inf file
120 self
.FvInfFile
.append("EFI_FILE_NAME = " + \
124 # Process Modules in FfsList
125 for FfsFile
in self
.FfsList
:
127 if isinstance(FfsFile
, FfsFileStatement
.FileStatement
):
129 if GenFdsGlobalVariable
.EnableGenfdsMultiThread
and GenFdsGlobalVariable
.ModuleFile
and GenFdsGlobalVariable
.ModuleFile
.Path
.find(os
.path
.normpath(FfsFile
.InfFileName
)) == -1:
131 FileName
= FfsFile
.GenFfs(MacroDict
, FvParentAddr
=BaseAddress
, IsMakefile
=Flag
, FvName
=self
.UiFvName
)
132 FfsFileList
.append(FileName
)
134 self
.FvInfFile
.append("EFI_FILE_NAME = " + \
138 FvInfFile
= ''.join(self
.FvInfFile
)
139 SaveFileOnChange(self
.InfFileName
, FvInfFile
, False)
143 FvOutputFile
= os
.path
.join(GenFdsGlobalVariable
.FvDir
, self
.UiFvName
)
144 FvOutputFile
= FvOutputFile
+ '.Fv'
145 # BUGBUG: FvOutputFile could be specified from FDF file (FV section, CreateFile statement)
146 if self
.CreateFileName
is not None:
147 FvOutputFile
= self
.CreateFileName
150 GenFdsGlobalVariable
.ImageBinDict
[self
.UiFvName
.upper() + 'fv'] = FvOutputFile
153 FvInfoFileName
= os
.path
.join(GenFdsGlobalVariable
.FfsDir
, self
.UiFvName
+ '.inf')
155 CopyLongFilePath(GenFdsGlobalVariable
.FvAddressFileName
, FvInfoFileName
)
157 if os
.path
.exists (FvInfoFileName
):
158 OrigFvInfo
= open(FvInfoFileName
, 'r').read()
159 if GenFdsGlobalVariable
.LargeFileInFvFlags
[-1]:
160 FFSGuid
= GenFdsGlobalVariable
.EFI_FIRMWARE_FILE_SYSTEM3_GUID
161 GenFdsGlobalVariable
.GenerateFirmwareVolume(
164 AddressFile
=FvInfoFileName
,
166 ForceRebase
=self
.FvForceRebase
,
167 FileSystemGuid
=FFSGuid
171 if os
.path
.exists (FvInfoFileName
):
172 NewFvInfo
= open(FvInfoFileName
, 'r').read()
173 if NewFvInfo
is not None and NewFvInfo
!= OrigFvInfo
:
175 AddFileObj
= open(FvInfoFileName
, 'r')
176 AddrStrings
= AddFileObj
.readlines()
178 for AddrString
in AddrStrings
:
180 #get base address for the inside FvImage
181 FvChildAddr
.append (AddrString
)
182 elif AddrString
.find ("[FV_BASE_ADDRESS]") != -1:
186 if FvChildAddr
!= []:
188 for FfsFile
in self
.FfsList
:
189 FileName
= FfsFile
.GenFfs(MacroDict
, FvChildAddr
, BaseAddress
, IsMakefile
=Flag
, FvName
=self
.UiFvName
)
191 if GenFdsGlobalVariable
.LargeFileInFvFlags
[-1]:
192 FFSGuid
= GenFdsGlobalVariable
.EFI_FIRMWARE_FILE_SYSTEM3_GUID
;
194 GenFdsGlobalVariable
.GenerateFirmwareVolume(
197 AddressFile
=FvInfoFileName
,
199 ForceRebase
=self
.FvForceRebase
,
200 FileSystemGuid
=FFSGuid
204 # Write the Fv contents to Buffer
206 if os
.path
.isfile(FvOutputFile
) and os
.path
.getsize(FvOutputFile
) >= 0x48:
207 FvFileObj
= open(FvOutputFile
, 'rb')
208 # PI FvHeader is 0x48 byte
209 FvHeaderBuffer
= FvFileObj
.read(0x48)
210 Signature
= FvHeaderBuffer
[0x28:0x32]
211 if Signature
and Signature
.startswith(b
'_FVH'):
212 GenFdsGlobalVariable
.VerboseLogger("\nGenerate %s FV Successfully" % self
.UiFvName
)
213 GenFdsGlobalVariable
.SharpCounter
= 0
216 Buffer
.write(FvFileObj
.read())
217 # FV alignment position.
218 FvAlignmentValue
= 1 << (ord(FvHeaderBuffer
[0x2E:0x2F]) & 0x1F)
219 if FvAlignmentValue
>= 0x400:
220 if FvAlignmentValue
>= 0x100000:
221 if FvAlignmentValue
>= 0x1000000:
222 #The max alignment supported by FFS is 16M.
223 self
.FvAlignment
= "16M"
225 self
.FvAlignment
= str(FvAlignmentValue
// 0x100000) + "M"
227 self
.FvAlignment
= str(FvAlignmentValue
// 0x400) + "K"
229 # FvAlignmentValue is less than 1K
230 self
.FvAlignment
= str (FvAlignmentValue
)
232 GenFdsGlobalVariable
.ImageBinDict
[self
.UiFvName
.upper() + 'fv'] = FvOutputFile
233 GenFdsGlobalVariable
.LargeFileInFvFlags
.pop()
235 GenFdsGlobalVariable
.ErrorLogger("Invalid FV file %s." % self
.UiFvName
)
237 GenFdsGlobalVariable
.ErrorLogger("Failed to generate %s FV file." %self
.UiFvName
)
242 # Calculate FV's block size
243 # Inherit block size from FD if no block size specified in FV
245 def _GetBlockSize(self
):
246 if self
.BlockSizeList
:
249 for FdObj
in GenFdsGlobalVariable
.FdfParser
.Profile
.FdDict
.values():
250 for RegionObj
in FdObj
.RegionList
:
251 if RegionObj
.RegionType
!= BINARY_FILE_TYPE_FV
:
253 for RegionData
in RegionObj
.RegionDataList
:
255 # Found the FD and region that contain this FV
257 if self
.UiFvName
.upper() == RegionData
.upper():
258 RegionObj
.BlockInfoOfRegion(FdObj
.BlockSizeList
, self
)
259 if self
.BlockSizeList
:
265 # Initialize the inf file to create FV
267 # @param self The object pointer
268 # @param BaseAddress base address of FV
269 # @param BlockSize block size of FV
270 # @param BlockNum How many blocks in FV
271 # @param ErasePolarity Flash erase polarity
273 def _InitializeInf (self
, BaseAddress
= None, BlockSize
= None, BlockNum
= None, ErasePloarity
='1'):
277 self
.InfFileName
= os
.path
.join(GenFdsGlobalVariable
.FvDir
,
278 self
.UiFvName
+ '.inf')
284 self
.FvInfFile
.append("[options]" + TAB_LINE_BREAK
)
285 if BaseAddress
is not None:
286 self
.FvInfFile
.append("EFI_BASE_ADDRESS = " + \
290 if BlockSize
is not None:
291 self
.FvInfFile
.append("EFI_BLOCK_SIZE = " + \
292 '0x%X' %BlockSize
+ \
294 if BlockNum
is not None:
295 self
.FvInfFile
.append("EFI_NUM_BLOCKS = " + \
296 ' 0x%X' %BlockNum
+ \
299 if self
.BlockSizeList
== []:
300 if not self
._GetBlockSize
():
301 #set default block size is 1
302 self
.FvInfFile
.append("EFI_BLOCK_SIZE = 0x1" + TAB_LINE_BREAK
)
304 for BlockSize
in self
.BlockSizeList
:
305 if BlockSize
[0] is not None:
306 self
.FvInfFile
.append("EFI_BLOCK_SIZE = " + \
307 '0x%X' %BlockSize
[0] + \
310 if BlockSize
[1] is not None:
311 self
.FvInfFile
.append("EFI_NUM_BLOCKS = " + \
312 ' 0x%X' %BlockSize
[1] + \
315 if self
.BsBaseAddress
is not None:
316 self
.FvInfFile
.append('EFI_BOOT_DRIVER_BASE_ADDRESS = ' + \
317 '0x%X' %self
.BsBaseAddress
)
318 if self
.RtBaseAddress
is not None:
319 self
.FvInfFile
.append('EFI_RUNTIME_DRIVER_BASE_ADDRESS = ' + \
320 '0x%X' %self
.RtBaseAddress
)
324 self
.FvInfFile
.append("[attributes]" + TAB_LINE_BREAK
)
326 self
.FvInfFile
.append("EFI_ERASE_POLARITY = " + \
327 ' %s' %ErasePloarity
+ \
329 if not (self
.FvAttributeDict
is None):
330 for FvAttribute
in self
.FvAttributeDict
.keys():
331 if FvAttribute
== "FvUsedSizeEnable":
332 if self
.FvAttributeDict
[FvAttribute
].upper() in ('TRUE', '1'):
333 self
.UsedSizeEnable
= True
335 self
.FvInfFile
.append("EFI_" + \
338 self
.FvAttributeDict
[FvAttribute
] + \
340 if self
.FvAlignment
is not None:
341 self
.FvInfFile
.append("EFI_FVB2_ALIGNMENT_" + \
342 self
.FvAlignment
.strip() + \
347 # Generate FV extension header file
349 if not self
.FvNameGuid
:
350 if len(self
.FvExtEntryType
) > 0 or self
.UsedSizeEnable
:
351 GenFdsGlobalVariable
.ErrorLogger("FV Extension Header Entries declared for %s with no FvNameGuid declaration." % (self
.UiFvName
))
355 if self
.UsedSizeEnable
:
357 ## define EFI_FV_EXT_TYPE_USED_SIZE_TYPE 0x03
360 # EFI_FIRMWARE_VOLUME_EXT_ENTRY Hdr;
362 # } EFI_FIRMWARE_VOLUME_EXT_ENTRY_USED_SIZE_TYPE;
363 Buffer
+= pack('HHL', 8, 3, 0)
365 if self
.FvNameString
== 'TRUE':
367 # Create EXT entry for FV UI name
368 # This GUID is used: A67DF1FA-8DE8-4E98-AF09-4BDF2EFFBC7C
370 FvUiLen
= len(self
.UiFvName
)
371 TotalSize
+= (FvUiLen
+ 16 + 4)
372 Guid
= FV_UI_EXT_ENTY_GUID
.split('-')
375 # EFI_FIRMWARE_VOLUME_EXT_ENTRY: size 4
379 Buffer
+= (pack('HH', (FvUiLen
+ 16 + 4), 0x0002)
381 + self
.UiFvName
.encode('utf-8'))
383 for Index
in range (0, len(self
.FvExtEntryType
)):
384 if self
.FvExtEntryType
[Index
] == 'FILE':
385 # check if the path is absolute or relative
386 if os
.path
.isabs(self
.FvExtEntryData
[Index
]):
387 FileFullPath
= os
.path
.normpath(self
.FvExtEntryData
[Index
])
389 FileFullPath
= os
.path
.normpath(os
.path
.join(GenFdsGlobalVariable
.WorkSpaceDir
, self
.FvExtEntryData
[Index
]))
390 # check if the file path exists or not
391 if not os
.path
.isfile(FileFullPath
):
392 GenFdsGlobalVariable
.ErrorLogger("Error opening FV Extension Header Entry file %s." % (self
.FvExtEntryData
[Index
]))
393 FvExtFile
= open (FileFullPath
, 'rb')
395 Size
= FvExtFile
.tell()
397 GenFdsGlobalVariable
.ErrorLogger("The size of FV Extension Header Entry file %s exceeds 0x10000." % (self
.FvExtEntryData
[Index
]))
398 TotalSize
+= (Size
+ 4)
400 Buffer
+= pack('HH', (Size
+ 4), int(self
.FvExtEntryTypeValue
[Index
], 16))
401 Buffer
+= FvExtFile
.read()
403 if self
.FvExtEntryType
[Index
] == 'DATA':
404 ByteList
= self
.FvExtEntryData
[Index
].split(',')
405 Size
= len (ByteList
)
407 GenFdsGlobalVariable
.ErrorLogger("The size of FV Extension Header Entry data %s exceeds 0x10000." % (self
.FvExtEntryData
[Index
]))
408 TotalSize
+= (Size
+ 4)
409 Buffer
+= pack('HH', (Size
+ 4), int(self
.FvExtEntryTypeValue
[Index
], 16))
410 for Index1
in range (0, Size
):
411 Buffer
+= pack('B', int(ByteList
[Index1
], 16))
413 Guid
= self
.FvNameGuid
.split('-')
414 Buffer
= PackGUID(Guid
) + pack('=L', TotalSize
) + Buffer
417 # Generate FV extension header file if the total size is not zero
420 FvExtHeaderFileName
= os
.path
.join(GenFdsGlobalVariable
.FvDir
, self
.UiFvName
+ '.ext')
421 FvExtHeaderFile
= BytesIO()
422 FvExtHeaderFile
.write(Buffer
)
423 Changed
= SaveFileOnChange(FvExtHeaderFileName
, FvExtHeaderFile
.getvalue(), True)
424 FvExtHeaderFile
.close()
426 if os
.path
.exists (self
.InfFileName
):
427 os
.remove (self
.InfFileName
)
428 self
.FvInfFile
.append("EFI_FV_EXT_HEADER_FILE_NAME = " + \
429 FvExtHeaderFileName
+ \
435 self
.FvInfFile
.append("[files]" + TAB_LINE_BREAK
)