2 # process FV generation
4 # Copyright (c) 2007 - 2016, 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
56 # Generate Fv and add it to the Buffer
58 # @param self The object pointer
59 # @param Buffer The buffer generated FV data will be put
60 # @param BaseAddress base address of FV
61 # @param BlockSize block size of FV
62 # @param BlockNum How many blocks in FV
63 # @param ErasePolarity Flash erase polarity
64 # @param VtfDict VTF objects
65 # @param MacroDict macro value pair
66 # @retval string Generated FV file path
68 def AddToBuffer (self
, Buffer
, BaseAddress
=None, BlockSize
= None, BlockNum
=None, ErasePloarity
='1', VtfDict
=None, MacroDict
= {}) :
70 if BaseAddress
== None and self
.UiFvName
.upper() + 'fv' in GenFds
.ImageBinDict
.keys():
71 return GenFds
.ImageBinDict
[self
.UiFvName
.upper() + 'fv']
74 # Check whether FV in Capsule is in FD flash region.
75 # If yes, return error. Doesn't support FV in Capsule image is also in FD flash region.
77 if self
.CapsuleName
!= None:
78 for FdName
in GenFdsGlobalVariable
.FdfParser
.Profile
.FdDict
.keys():
79 FdObj
= GenFdsGlobalVariable
.FdfParser
.Profile
.FdDict
[FdName
]
80 for RegionObj
in FdObj
.RegionList
:
81 if RegionObj
.RegionType
== 'FV':
82 for RegionData
in RegionObj
.RegionDataList
:
83 if RegionData
.endswith(".fv"):
85 elif RegionData
.upper() + 'fv' in GenFds
.ImageBinDict
.keys():
87 elif self
.UiFvName
.upper() == RegionData
.upper():
88 GenFdsGlobalVariable
.ErrorLogger("Capsule %s in FD region can't contain a FV %s in FD region." % (self
.CapsuleName
, self
.UiFvName
.upper()))
90 GenFdsGlobalVariable
.InfLogger( "\nGenerating %s FV" %self
.UiFvName
)
91 GenFdsGlobalVariable
.LargeFileInFvFlags
.append(False)
94 if self
.FvBaseAddress
!= None:
95 BaseAddress
= self
.FvBaseAddress
97 self
.__InitializeInf
__(BaseAddress
, BlockSize
, BlockNum
, ErasePloarity
, VtfDict
)
99 # First Process the Apriori section
101 MacroDict
.update(self
.DefineVarDict
)
103 GenFdsGlobalVariable
.VerboseLogger('First generate Apriori file !')
105 for AprSection
in self
.AprioriSectionList
:
106 FileName
= AprSection
.GenFfs (self
.UiFvName
, MacroDict
)
107 FfsFileList
.append(FileName
)
108 # Add Apriori file name to Inf file
109 self
.FvInfFile
.writelines("EFI_FILE_NAME = " + \
113 # Process Modules in FfsList
114 for FfsFile
in self
.FfsList
:
115 if hasattr(FfsFile
, 'FvFileType') and FfsFile
.FvFileType
== 'RAW':
116 if isinstance(FfsFile
.FileName
, list) and isinstance(FfsFile
.Alignment
, list) and len(FfsFile
.FileName
) == len(FfsFile
.Alignment
):
118 for Index
, File
in enumerate(FfsFile
.FileName
):
120 f
= open(File
, 'r+b')
122 GenFdsGlobalVariable
.ErrorLogger("Error opening RAW file %s." % (File
))
125 AlignValue
= FfsFile
.Alignment
[Index
]
126 if AlignValue
== None:
128 FileContent
+= Content
129 if len(FileContent
) % AlignValue
!= 0:
130 Size
= AlignValue
- len(FileContent
) % AlignValue
131 for i
in range(0, Size
):
132 FileContent
+= pack('B', 0xFF)
135 OutputRAWFile
= os
.path
.join(GenFdsGlobalVariable
.FfsDir
, FfsFile
.NameGuid
, FfsFile
.NameGuid
+ '.raw')
136 SaveFileOnChange(OutputRAWFile
, FileContent
, True)
137 FfsFile
.FileName
= OutputRAWFile
138 if max(FfsFile
.Alignment
):
139 FfsFile
.Alignment
= str(max(FfsFile
.Alignment
))
141 FfsFile
.Alignment
= None
143 FileName
= FfsFile
.GenFfs(MacroDict
, FvParentAddr
=BaseAddress
)
144 FfsFileList
.append(FileName
)
145 self
.FvInfFile
.writelines("EFI_FILE_NAME = " + \
149 SaveFileOnChange(self
.InfFileName
, self
.FvInfFile
.getvalue(), False)
150 self
.FvInfFile
.close()
154 FvOutputFile
= os
.path
.join(GenFdsGlobalVariable
.FvDir
, self
.UiFvName
)
155 FvOutputFile
= FvOutputFile
+ '.Fv'
156 # BUGBUG: FvOutputFile could be specified from FDF file (FV section, CreateFile statement)
157 if self
.CreateFileName
!= None:
158 FvOutputFile
= self
.CreateFileName
160 FvInfoFileName
= os
.path
.join(GenFdsGlobalVariable
.FfsDir
, self
.UiFvName
+ '.inf')
161 CopyLongFilePath(GenFdsGlobalVariable
.FvAddressFileName
, FvInfoFileName
)
163 if os
.path
.exists (FvInfoFileName
):
164 OrigFvInfo
= open(FvInfoFileName
, 'r').read()
165 if GenFdsGlobalVariable
.LargeFileInFvFlags
[-1]:
166 FFSGuid
= GenFdsGlobalVariable
.EFI_FIRMWARE_FILE_SYSTEM3_GUID
;
167 GenFdsGlobalVariable
.GenerateFirmwareVolume(
170 AddressFile
=FvInfoFileName
,
172 ForceRebase
=self
.FvForceRebase
,
173 FileSystemGuid
=FFSGuid
177 if os
.path
.exists (FvInfoFileName
):
178 NewFvInfo
= open(FvInfoFileName
, 'r').read()
179 if NewFvInfo
!= None and NewFvInfo
!= OrigFvInfo
:
181 AddFileObj
= open(FvInfoFileName
, 'r')
182 AddrStrings
= AddFileObj
.readlines()
184 for AddrString
in AddrStrings
:
186 #get base address for the inside FvImage
187 FvChildAddr
.append (AddrString
)
188 elif AddrString
.find ("[FV_BASE_ADDRESS]") != -1:
192 if FvChildAddr
!= []:
194 for FfsFile
in self
.FfsList
:
195 FileName
= FfsFile
.GenFfs(MacroDict
, FvChildAddr
, BaseAddress
)
197 if GenFdsGlobalVariable
.LargeFileInFvFlags
[-1]:
198 FFSGuid
= GenFdsGlobalVariable
.EFI_FIRMWARE_FILE_SYSTEM3_GUID
;
200 GenFdsGlobalVariable
.GenerateFirmwareVolume(
203 AddressFile
=FvInfoFileName
,
205 ForceRebase
=self
.FvForceRebase
,
206 FileSystemGuid
=FFSGuid
210 # Write the Fv contents to Buffer
212 if os
.path
.isfile(FvOutputFile
):
213 FvFileObj
= open ( FvOutputFile
,'r+b')
215 GenFdsGlobalVariable
.VerboseLogger( "\nGenerate %s FV Successfully" %self
.UiFvName
)
216 GenFdsGlobalVariable
.SharpCounter
= 0
218 Buffer
.write(FvFileObj
.read())
220 # PI FvHeader is 0x48 byte
221 FvHeaderBuffer
= FvFileObj
.read(0x48)
222 # FV alignment position.
223 FvAlignmentValue
= 1 << (ord (FvHeaderBuffer
[0x2E]) & 0x1F)
224 # FvAlignmentValue is larger than or equal to 1K
225 if FvAlignmentValue
>= 0x400:
226 if FvAlignmentValue
>= 0x10000:
227 #The max alignment supported by FFS is 64K.
228 self
.FvAlignment
= "64K"
230 self
.FvAlignment
= str (FvAlignmentValue
/ 0x400) + "K"
232 # FvAlignmentValue is less than 1K
233 self
.FvAlignment
= str (FvAlignmentValue
)
235 GenFds
.ImageBinDict
[self
.UiFvName
.upper() + 'fv'] = FvOutputFile
236 GenFdsGlobalVariable
.LargeFileInFvFlags
.pop()
238 GenFdsGlobalVariable
.ErrorLogger("Failed to generate %s FV file." %self
.UiFvName
)
243 # Calculate FV's block size
244 # Inherit block size from FD if no block size specified in FV
246 def _GetBlockSize(self
):
247 if self
.BlockSizeList
:
250 for FdName
in GenFdsGlobalVariable
.FdfParser
.Profile
.FdDict
.keys():
251 FdObj
= GenFdsGlobalVariable
.FdfParser
.Profile
.FdDict
[FdName
]
252 for RegionObj
in FdObj
.RegionList
:
253 if RegionObj
.RegionType
!= 'FV':
255 for RegionData
in RegionObj
.RegionDataList
:
257 # Found the FD and region that contain this FV
259 if self
.UiFvName
.upper() == RegionData
.upper():
260 RegionObj
.BlockInfoOfRegion(FdObj
.BlockSizeList
, self
)
261 if self
.BlockSizeList
:
265 ## __InitializeInf__()
267 # Initilize the inf file to create FV
269 # @param self The object pointer
270 # @param BaseAddress base address of FV
271 # @param BlockSize block size of FV
272 # @param BlockNum How many blocks in FV
273 # @param ErasePolarity Flash erase polarity
274 # @param VtfDict VTF objects
276 def __InitializeInf__ (self
, BaseAddress
= None, BlockSize
= None, BlockNum
= None, ErasePloarity
='1', VtfDict
=None) :
280 self
.InfFileName
= os
.path
.join(GenFdsGlobalVariable
.FvDir
,
281 self
.UiFvName
+ '.inf')
282 self
.FvInfFile
= StringIO
.StringIO()
287 self
.FvInfFile
.writelines("[options]" + T_CHAR_LF
)
288 if BaseAddress
!= None :
289 self
.FvInfFile
.writelines("EFI_BASE_ADDRESS = " + \
293 if BlockSize
!= None:
294 self
.FvInfFile
.writelines("EFI_BLOCK_SIZE = " + \
295 '0x%X' %BlockSize
+ \
298 self
.FvInfFile
.writelines("EFI_NUM_BLOCKS = " + \
299 ' 0x%X' %BlockNum
+ \
302 if self
.BlockSizeList
== []:
303 if not self
._GetBlockSize
():
304 #set default block size is 1
305 self
.FvInfFile
.writelines("EFI_BLOCK_SIZE = 0x1" + T_CHAR_LF
)
307 for BlockSize
in self
.BlockSizeList
:
308 if BlockSize
[0] != None:
309 self
.FvInfFile
.writelines("EFI_BLOCK_SIZE = " + \
310 '0x%X' %BlockSize
[0] + \
313 if BlockSize
[1] != None:
314 self
.FvInfFile
.writelines("EFI_NUM_BLOCKS = " + \
315 ' 0x%X' %BlockSize
[1] + \
318 if self
.BsBaseAddress
!= None:
319 self
.FvInfFile
.writelines('EFI_BOOT_DRIVER_BASE_ADDRESS = ' + \
320 '0x%X' %self
.BsBaseAddress
)
321 if self
.RtBaseAddress
!= None:
322 self
.FvInfFile
.writelines('EFI_RUNTIME_DRIVER_BASE_ADDRESS = ' + \
323 '0x%X' %self
.RtBaseAddress
)
327 self
.FvInfFile
.writelines("[attributes]" + T_CHAR_LF
)
329 self
.FvInfFile
.writelines("EFI_ERASE_POLARITY = " + \
330 ' %s' %ErasePloarity
+ \
332 if not (self
.FvAttributeDict
== None):
333 for FvAttribute
in self
.FvAttributeDict
.keys() :
334 self
.FvInfFile
.writelines("EFI_" + \
337 self
.FvAttributeDict
[FvAttribute
] + \
339 if self
.FvAlignment
!= None:
340 self
.FvInfFile
.writelines("EFI_FVB2_ALIGNMENT_" + \
341 self
.FvAlignment
.strip() + \
346 # Generate FV extension header file
348 if self
.FvNameGuid
== None or self
.FvNameGuid
== '':
349 if len(self
.FvExtEntryType
) > 0:
350 GenFdsGlobalVariable
.ErrorLogger("FV Extension Header Entries declared for %s with no FvNameGuid declaration." % (self
.UiFvName
))
352 if self
.FvNameGuid
<> None and self
.FvNameGuid
<> '':
355 if self
.FvNameString
== 'TRUE':
357 # Create EXT entry for FV UI name
358 # This GUID is used: A67DF1FA-8DE8-4E98-AF09-4BDF2EFFBC7C
360 FvUiLen
= len(self
.UiFvName
)
361 TotalSize
+= (FvUiLen
+ 16 + 4)
362 Guid
= FV_UI_EXT_ENTY_GUID
.split('-')
365 # EFI_FIRMWARE_VOLUME_EXT_ENTRY : size 4
369 Buffer
+= (pack('HH', (FvUiLen
+ 16 + 4), 0x0002)
370 + pack('=LHHBBBBBBBB', int(Guid
[0], 16), int(Guid
[1], 16), int(Guid
[2], 16),
371 int(Guid
[3][-4:-2], 16), int(Guid
[3][-2:], 16), int(Guid
[4][-12:-10], 16),
372 int(Guid
[4][-10:-8], 16), int(Guid
[4][-8:-6], 16), int(Guid
[4][-6:-4], 16),
373 int(Guid
[4][-4:-2], 16), int(Guid
[4][-2:], 16))
376 for Index
in range (0, len(self
.FvExtEntryType
)):
377 if self
.FvExtEntryType
[Index
] == 'FILE':
378 # check if the path is absolute or relative
379 if os
.path
.isabs(self
.FvExtEntryData
[Index
]):
380 FileFullPath
= os
.path
.normpath(self
.FvExtEntryData
[Index
])
382 FileFullPath
= os
.path
.normpath(os
.path
.join(GenFdsGlobalVariable
.WorkSpaceDir
, self
.FvExtEntryData
[Index
]))
383 # check if the file path exists or not
384 if not os
.path
.isfile(FileFullPath
):
385 GenFdsGlobalVariable
.ErrorLogger("Error opening FV Extension Header Entry file %s." % (self
.FvExtEntryData
[Index
]))
386 FvExtFile
= open (FileFullPath
,'rb')
388 Size
= FvExtFile
.tell()
390 GenFdsGlobalVariable
.ErrorLogger("The size of FV Extension Header Entry file %s exceeds 0x10000." % (self
.FvExtEntryData
[Index
]))
391 TotalSize
+= (Size
+ 4)
393 Buffer
+= pack('HH', (Size
+ 4), int(self
.FvExtEntryTypeValue
[Index
], 16))
394 Buffer
+= FvExtFile
.read()
396 if self
.FvExtEntryType
[Index
] == 'DATA':
397 ByteList
= self
.FvExtEntryData
[Index
].split(',')
398 Size
= len (ByteList
)
400 GenFdsGlobalVariable
.ErrorLogger("The size of FV Extension Header Entry data %s exceeds 0x10000." % (self
.FvExtEntryData
[Index
]))
401 TotalSize
+= (Size
+ 4)
402 Buffer
+= pack('HH', (Size
+ 4), int(self
.FvExtEntryTypeValue
[Index
], 16))
403 for Index1
in range (0, Size
):
404 Buffer
+= pack('B', int(ByteList
[Index1
], 16))
406 Guid
= self
.FvNameGuid
.split('-')
407 Buffer
= pack('=LHHBBBBBBBBL',
411 int(Guid
[3][-4:-2], 16),
412 int(Guid
[3][-2:], 16),
413 int(Guid
[4][-12:-10], 16),
414 int(Guid
[4][-10:-8], 16),
415 int(Guid
[4][-8:-6], 16),
416 int(Guid
[4][-6:-4], 16),
417 int(Guid
[4][-4:-2], 16),
418 int(Guid
[4][-2:], 16),
423 # Generate FV extension header file if the total size is not zero
426 FvExtHeaderFileName
= os
.path
.join(GenFdsGlobalVariable
.FvDir
, self
.UiFvName
+ '.ext')
427 FvExtHeaderFile
= StringIO
.StringIO()
428 FvExtHeaderFile
.write(Buffer
)
429 Changed
= SaveFileOnChange(FvExtHeaderFileName
, FvExtHeaderFile
.getvalue(), True)
430 FvExtHeaderFile
.close()
432 if os
.path
.exists (self
.InfFileName
):
433 os
.remove (self
.InfFileName
)
434 self
.FvInfFile
.writelines("EFI_FV_EXT_HEADER_FILE_NAME = " + \
435 FvExtHeaderFileName
+ \
442 self
.FvInfFile
.writelines("[files]" + T_CHAR_LF
)
443 if VtfDict
!= None and self
.UiFvName
in VtfDict
.keys():
444 self
.FvInfFile
.writelines("EFI_FILE_NAME = " + \
445 VtfDict
.get(self
.UiFvName
) + \