1 from __future__
import absolute_import
3 # process FV generation
5 # Copyright (c) 2007 - 2018, Intel Corporation. All rights reserved.<BR>
7 # This program and the accompanying materials
8 # are licensed and made available under the terms and conditions of the BSD License
9 # which accompanies this distribution. The full text of the license may be found at
10 # http://opensource.org/licenses/bsd-license.php
12 # THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
13 # WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
19 import Common
.LongFilePathOs
as os
21 from io
import BytesIO
25 from . import AprioriSection
26 from . import FfsFileStatement
27 from .GenFdsGlobalVariable
import GenFdsGlobalVariable
28 from CommonDataClass
.FdfClass
import FvClassObject
29 from Common
.Misc
import SaveFileOnChange
, PackGUID
30 from Common
.LongFilePathSupport
import CopyLongFilePath
31 from Common
.LongFilePathSupport
import OpenLongFilePath
as open
32 from Common
.DataType
import *
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 GenFdsGlobalVariable
.ImageBinDict
:
74 return GenFdsGlobalVariable
.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
== BINARY_FILE_TYPE_FV
:
84 for RegionData
in RegionObj
.RegionDataList
:
85 if RegionData
.endswith(".fv"):
87 elif RegionData
.upper() + 'fv' in GenFdsGlobalVariable
.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 GenFdsGlobalVariable
.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 GenFdsGlobalVariable
.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
!= BINARY_FILE_TYPE_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
= BytesIO()
273 self
.FvInfFile
.writelines("[options]" + TAB_LINE_BREAK
)
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" + TAB_LINE_BREAK
)
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]" + TAB_LINE_BREAK
)
315 self
.FvInfFile
.writelines("EFI_ERASE_POLARITY = " + \
316 ' %s' %ErasePloarity
+ \
318 if not (self
.FvAttributeDict
is None):
319 for FvAttribute
in self
.FvAttributeDict
.keys() :
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)
372 for Index
in range (0, len(self
.FvExtEntryType
)):
373 if self
.FvExtEntryType
[Index
] == 'FILE':
374 # check if the path is absolute or relative
375 if os
.path
.isabs(self
.FvExtEntryData
[Index
]):
376 FileFullPath
= os
.path
.normpath(self
.FvExtEntryData
[Index
])
378 FileFullPath
= os
.path
.normpath(os
.path
.join(GenFdsGlobalVariable
.WorkSpaceDir
, self
.FvExtEntryData
[Index
]))
379 # check if the file path exists or not
380 if not os
.path
.isfile(FileFullPath
):
381 GenFdsGlobalVariable
.ErrorLogger("Error opening FV Extension Header Entry file %s." % (self
.FvExtEntryData
[Index
]))
382 FvExtFile
= open (FileFullPath
, 'rb')
384 Size
= FvExtFile
.tell()
386 GenFdsGlobalVariable
.ErrorLogger("The size of FV Extension Header Entry file %s exceeds 0x10000." % (self
.FvExtEntryData
[Index
]))
387 TotalSize
+= (Size
+ 4)
389 Buffer
+= pack('HH', (Size
+ 4), int(self
.FvExtEntryTypeValue
[Index
], 16))
390 Buffer
+= FvExtFile
.read()
392 if self
.FvExtEntryType
[Index
] == 'DATA':
393 ByteList
= self
.FvExtEntryData
[Index
].split(',')
394 Size
= len (ByteList
)
396 GenFdsGlobalVariable
.ErrorLogger("The size of FV Extension Header Entry data %s exceeds 0x10000." % (self
.FvExtEntryData
[Index
]))
397 TotalSize
+= (Size
+ 4)
398 Buffer
+= pack('HH', (Size
+ 4), int(self
.FvExtEntryTypeValue
[Index
], 16))
399 for Index1
in range (0, Size
):
400 Buffer
+= pack('B', int(ByteList
[Index1
], 16))
402 Guid
= self
.FvNameGuid
.split('-')
403 Buffer
= PackGUID(Guid
) + pack('=L', TotalSize
) + Buffer
406 # Generate FV extension header file if the total size is not zero
409 FvExtHeaderFileName
= os
.path
.join(GenFdsGlobalVariable
.FvDir
, self
.UiFvName
+ '.ext')
410 FvExtHeaderFile
= BytesIO()
411 FvExtHeaderFile
.write(Buffer
)
412 Changed
= SaveFileOnChange(FvExtHeaderFileName
, FvExtHeaderFile
.getvalue(), True)
413 FvExtHeaderFile
.close()
415 if os
.path
.exists (self
.InfFileName
):
416 os
.remove (self
.InfFileName
)
417 self
.FvInfFile
.writelines("EFI_FV_EXT_HEADER_FILE_NAME = " + \
418 FvExtHeaderFileName
+ \
425 self
.FvInfFile
.writelines("[files]" + TAB_LINE_BREAK
)
426 if VtfDict
and self
.UiFvName
in VtfDict
:
427 self
.FvInfFile
.writelines("EFI_FILE_NAME = " + \
428 VtfDict
[self
.UiFvName
] + \