2 # process FFS generation from INF statement
4 # Copyright (c) 2007 - 2015, Intel Corporation. All rights reserved.<BR>
5 # Copyright (c) 2014 Hewlett-Packard Development Company, L.P.<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.
20 import Common
.LongFilePathOs
as os
23 from GenFdsGlobalVariable
import GenFdsGlobalVariable
29 import RuleComplexFile
30 from CommonDataClass
.FdfClass
import FfsInfStatementClassObject
31 from Common
.MultipleWorkspace
import MultipleWorkspace
as mws
32 from Common
.String
import *
33 from Common
.Misc
import PathClass
34 from Common
.Misc
import GuidStructureByteArrayToGuidString
35 from Common
.Misc
import ProcessDuplicatedInf
36 from Common
.Misc
import GetVariableOffset
37 from Common
import EdkLogger
38 from Common
.BuildToolError
import *
39 from GuidSection
import GuidSection
40 from FvImageSection
import FvImageSection
41 from Common
.Misc
import PeImageClass
42 from AutoGen
.GenDepex
import DependencyExpression
43 from PatchPcdValue
.PatchPcdValue
import PatchBinaryFile
44 from Common
.LongFilePathSupport
import CopyLongFilePath
45 from Common
.LongFilePathSupport
import OpenLongFilePath
as open
47 ## generate FFS from INF
50 class FfsInfStatement(FfsInfStatementClassObject
):
51 ## The mapping dictionary from datum type to its maximum number.
52 _MAX_SIZE_TYPE
= {"BOOLEAN":0x01, "UINT8":0xFF, "UINT16":0xFFFF, "UINT32":0xFFFFFFFF, "UINT64":0xFFFFFFFFFFFFFFFF}
55 # @param self The object pointer
58 FfsInfStatementClassObject
.__init
__(self
)
59 self
.TargetOverrideList
= []
60 self
.ShadowFromInfFile
= None
61 self
.KeepRelocFromRule
= None
64 self
.PiSpecVersion
= '0x00000000'
66 self
.FinalTargetSuffixMap
= {}
67 self
.CurrentLineNum
= None
68 self
.CurrentLineContent
= None
70 self
.InfFileName
= None
71 self
.OverrideGuid
= None
72 self
.PatchedBinFile
= ''
75 ## GetFinalTargetSuffixMap() method
77 # Get final build target list
78 def GetFinalTargetSuffixMap(self
):
79 if not self
.InfModule
or not self
.CurrentArch
:
81 if not self
.FinalTargetSuffixMap
:
82 FinalBuildTargetList
= GenFdsGlobalVariable
.GetModuleCodaTargetList(self
.InfModule
, self
.CurrentArch
)
83 for File
in FinalBuildTargetList
:
84 self
.FinalTargetSuffixMap
.setdefault(os
.path
.splitext(File
)[1], []).append(File
)
86 # Check if current INF module has DEPEX
87 if '.depex' not in self
.FinalTargetSuffixMap
and self
.InfModule
.ModuleType
!= "USER_DEFINED" \
88 and not self
.InfModule
.DxsFile
and not self
.InfModule
.LibraryClass
:
89 ModuleType
= self
.InfModule
.ModuleType
90 PlatformDataBase
= GenFdsGlobalVariable
.WorkSpace
.BuildObject
[GenFdsGlobalVariable
.ActivePlatform
, self
.CurrentArch
, GenFdsGlobalVariable
.TargetName
, GenFdsGlobalVariable
.ToolChainTag
]
92 if ModuleType
!= DataType
.SUP_MODULE_USER_DEFINED
:
93 for LibraryClass
in PlatformDataBase
.LibraryClasses
.GetKeys():
94 if LibraryClass
.startswith("NULL") and PlatformDataBase
.LibraryClasses
[LibraryClass
, ModuleType
]:
95 self
.InfModule
.LibraryClasses
[LibraryClass
] = PlatformDataBase
.LibraryClasses
[LibraryClass
, ModuleType
]
97 StrModule
= str(self
.InfModule
)
99 if StrModule
in PlatformDataBase
.Modules
:
100 PlatformModule
= PlatformDataBase
.Modules
[StrModule
]
101 for LibraryClass
in PlatformModule
.LibraryClasses
:
102 if LibraryClass
.startswith("NULL"):
103 self
.InfModule
.LibraryClasses
[LibraryClass
] = PlatformModule
.LibraryClasses
[LibraryClass
]
105 DependencyList
= [self
.InfModule
]
108 while len(DependencyList
) > 0:
109 Module
= DependencyList
.pop(0)
112 for Dep
in Module
.Depex
[self
.CurrentArch
, ModuleType
]:
114 DepexList
.append('AND')
115 DepexList
.append('(')
116 DepexList
.extend(Dep
)
117 if DepexList
[-1] == 'END': # no need of a END at this time
119 DepexList
.append(')')
120 if 'BEFORE' in DepexList
or 'AFTER' in DepexList
:
122 for LibName
in Module
.LibraryClasses
:
123 if LibName
in LibraryInstance
:
125 if PlatformModule
and LibName
in PlatformModule
.LibraryClasses
:
126 LibraryPath
= PlatformModule
.LibraryClasses
[LibName
]
128 LibraryPath
= PlatformDataBase
.LibraryClasses
[LibName
, ModuleType
]
130 LibraryPath
= Module
.LibraryClasses
[LibName
]
133 LibraryModule
= GenFdsGlobalVariable
.WorkSpace
.BuildObject
[LibraryPath
, self
.CurrentArch
, GenFdsGlobalVariable
.TargetName
, GenFdsGlobalVariable
.ToolChainTag
]
134 LibraryInstance
[LibName
] = LibraryModule
135 DependencyList
.append(LibraryModule
)
137 Dpx
= DependencyExpression(DepexList
, ModuleType
, True)
138 if len(Dpx
.PostfixNotation
) != 0:
139 # It means this module has DEPEX
140 self
.FinalTargetSuffixMap
['.depex'] = [os
.path
.join(self
.EfiOutputPath
, self
.BaseName
) + '.depex']
141 return self
.FinalTargetSuffixMap
143 ## __InfParse() method
145 # Parse inf file to get module information
147 # @param self The object pointer
148 # @param Dict dictionary contains macro and value pair
150 def __InfParse__(self
, Dict
= {}):
152 GenFdsGlobalVariable
.VerboseLogger( " Begine parsing INf file : %s" %self
.InfFileName
)
154 self
.InfFileName
= self
.InfFileName
.replace('$(WORKSPACE)', '')
155 if len(self
.InfFileName
) > 1 and self
.InfFileName
[0] == '\\' and self
.InfFileName
[1] == '\\':
157 elif self
.InfFileName
[0] == '\\' or self
.InfFileName
[0] == '/' :
158 self
.InfFileName
= self
.InfFileName
[1:]
160 if self
.InfFileName
.find('$') == -1:
161 InfPath
= NormPath(self
.InfFileName
)
162 if not os
.path
.exists(InfPath
):
163 InfPath
= GenFdsGlobalVariable
.ReplaceWorkspaceMacro(InfPath
)
164 if not os
.path
.exists(InfPath
):
165 EdkLogger
.error("GenFds", GENFDS_ERROR
, "Non-existant Module %s !" % (self
.InfFileName
))
167 self
.CurrentArch
= self
.GetCurrentArch()
169 # Get the InfClass object
172 PathClassObj
= PathClass(self
.InfFileName
, GenFdsGlobalVariable
.WorkSpaceDir
)
173 ErrorCode
, ErrorInfo
= PathClassObj
.Validate(".inf")
175 EdkLogger
.error("GenFds", ErrorCode
, ExtraData
=ErrorInfo
)
177 if self
.OverrideGuid
:
178 PathClassObj
= ProcessDuplicatedInf(PathClassObj
, self
.OverrideGuid
, GenFdsGlobalVariable
.WorkSpaceDir
)
179 if self
.CurrentArch
!= None:
181 Inf
= GenFdsGlobalVariable
.WorkSpace
.BuildObject
[PathClassObj
, self
.CurrentArch
, GenFdsGlobalVariable
.TargetName
, GenFdsGlobalVariable
.ToolChainTag
]
183 # Set Ffs BaseName, MdouleGuid, ModuleType, Version, OutputPath
185 self
.BaseName
= Inf
.BaseName
186 self
.ModuleGuid
= Inf
.Guid
187 self
.ModuleType
= Inf
.ModuleType
188 if Inf
.Specification
!= None and 'PI_SPECIFICATION_VERSION' in Inf
.Specification
:
189 self
.PiSpecVersion
= Inf
.Specification
['PI_SPECIFICATION_VERSION']
190 if Inf
.AutoGenVersion
< 0x00010005:
191 self
.ModuleType
= Inf
.ComponentType
192 self
.VersionString
= Inf
.Version
193 self
.BinFileList
= Inf
.Binaries
194 self
.SourceFileList
= Inf
.Sources
195 if self
.KeepReloc
== None and Inf
.Shadow
:
196 self
.ShadowFromInfFile
= Inf
.Shadow
199 Inf
= GenFdsGlobalVariable
.WorkSpace
.BuildObject
[PathClassObj
, 'COMMON', GenFdsGlobalVariable
.TargetName
, GenFdsGlobalVariable
.ToolChainTag
]
200 self
.BaseName
= Inf
.BaseName
201 self
.ModuleGuid
= Inf
.Guid
202 self
.ModuleType
= Inf
.ModuleType
203 if Inf
.Specification
!= None and 'PI_SPECIFICATION_VERSION' in Inf
.Specification
:
204 self
.PiSpecVersion
= Inf
.Specification
['PI_SPECIFICATION_VERSION']
205 self
.VersionString
= Inf
.Version
206 self
.BinFileList
= Inf
.Binaries
207 self
.SourceFileList
= Inf
.Sources
208 if self
.BinFileList
== []:
209 EdkLogger
.error("GenFds", GENFDS_ERROR
,
210 "INF %s specified in FDF could not be found in build ARCH %s!" \
211 % (self
.InfFileName
, GenFdsGlobalVariable
.ArchList
))
213 if self
.OverrideGuid
:
214 self
.ModuleGuid
= self
.OverrideGuid
216 if len(self
.SourceFileList
) != 0 and not self
.InDsc
:
217 EdkLogger
.warn("GenFds", GENFDS_ERROR
, "Module %s NOT found in DSC file; Is it really a binary module?" % (self
.InfFileName
))
219 if self
.ModuleType
== 'SMM_CORE' and int(self
.PiSpecVersion
, 16) < 0x0001000A:
220 EdkLogger
.error("GenFds", FORMAT_NOT_SUPPORTED
, "SMM_CORE module type can't be used in the module with PI_SPECIFICATION_VERSION less than 0x0001000A", File
=self
.InfFileName
)
222 if Inf
._Defs
!= None and len(Inf
._Defs
) > 0:
223 self
.OptRomDefs
.update(Inf
._Defs
)
227 Platform
= GenFdsGlobalVariable
.WorkSpace
.BuildObject
[GenFdsGlobalVariable
.ActivePlatform
, self
.CurrentArch
, GenFdsGlobalVariable
.TargetName
, GenFdsGlobalVariable
.ToolChainTag
]
228 FdfPcdDict
= GenFdsGlobalVariable
.FdfParser
.Profile
.PcdDict
230 # Workaround here: both build and GenFds tool convert the workspace path to lower case
231 # But INF file path in FDF and DSC file may have real case characters.
232 # Try to convert the path to lower case to see if PCDs value are override by DSC.
234 for DscModule
in Platform
.Modules
:
235 DscModules
[str(DscModule
).lower()] = Platform
.Modules
[DscModule
]
236 for PcdKey
in InfPcds
:
237 Pcd
= InfPcds
[PcdKey
]
238 if not hasattr(Pcd
, 'Offset'):
240 if Pcd
.Type
!= 'PatchableInModule':
242 # Override Patchable PCD value by the value from DSC
244 InfLowerPath
= str(PathClassObj
).lower()
245 if InfLowerPath
in DscModules
and PcdKey
in DscModules
[InfLowerPath
].Pcds
:
246 PatchPcd
= DscModules
[InfLowerPath
].Pcds
[PcdKey
]
247 elif PcdKey
in Platform
.Pcds
:
248 PatchPcd
= Platform
.Pcds
[PcdKey
]
250 if PatchPcd
and Pcd
.Type
== PatchPcd
.Type
:
251 DefaultValue
= PatchPcd
.DefaultValue
254 # Override Patchable PCD value by the value from FDF
256 if PcdKey
in FdfPcdDict
:
257 DefaultValue
= FdfPcdDict
[PcdKey
]
260 if not DscOverride
and not FdfOverride
:
262 # Check value, if value are equal, no need to patch
263 if Pcd
.DatumType
== "VOID*":
264 if Pcd
.DefaultValue
== DefaultValue
or DefaultValue
in [None, '']:
266 # Get the string size from FDF or DSC
267 if DefaultValue
[0] == 'L':
268 # Remove L"", but the '\0' must be appended
269 MaxDatumSize
= str((len(DefaultValue
) - 2) * 2)
270 elif DefaultValue
[0] == '{':
271 MaxDatumSize
= str(len(DefaultValue
.split(',')))
273 MaxDatumSize
= str(len(DefaultValue
) - 1)
275 Pcd
.MaxDatumSize
= PatchPcd
.MaxDatumSize
276 # If no defined the maximum size in DSC, try to get current size from INF
277 if Pcd
.MaxDatumSize
in ['', None]:
278 Pcd
.MaxDatumSize
= str(len(Pcd
.DefaultValue
.split(',')))
281 if Pcd
.DefaultValue
.upper().startswith('0X'):
283 if DefaultValue
.upper().startswith('0X'):
286 PcdValueInImg
= int(Pcd
.DefaultValue
, Base1
)
287 PcdValueInDscOrFdf
= int(DefaultValue
, Base2
)
288 if PcdValueInImg
== PcdValueInDscOrFdf
:
292 # Check the Pcd size and data type
293 if Pcd
.DatumType
== "VOID*":
294 if int(MaxDatumSize
) > int(Pcd
.MaxDatumSize
):
295 EdkLogger
.error("GenFds", GENFDS_ERROR
, "The size of VOID* type PCD '%s.%s' exceeds its maximum size %d bytes." \
296 % (Pcd
.TokenSpaceGuidCName
, Pcd
.TokenCName
, int(MaxDatumSize
) - int(Pcd
.MaxDatumSize
)))
298 if PcdValueInDscOrFdf
> FfsInfStatement
._MAX
_SIZE
_TYPE
[Pcd
.DatumType
] \
299 or PcdValueInImg
> FfsInfStatement
._MAX
_SIZE
_TYPE
[Pcd
.DatumType
]:
300 EdkLogger
.error("GenFds", GENFDS_ERROR
, "The size of %s type PCD '%s.%s' doesn't match its data type." \
301 % (Pcd
.DatumType
, Pcd
.TokenSpaceGuidCName
, Pcd
.TokenCName
))
302 self
.PatchPcds
.append((Pcd
, DefaultValue
))
305 self
.PcdIsDriver
= Inf
.PcdIsDriver
306 self
.IsBinaryModule
= Inf
.IsBinaryModule
307 GenFdsGlobalVariable
.VerboseLogger("BaseName : %s" % self
.BaseName
)
308 GenFdsGlobalVariable
.VerboseLogger("ModuleGuid : %s" % self
.ModuleGuid
)
309 GenFdsGlobalVariable
.VerboseLogger("ModuleType : %s" % self
.ModuleType
)
310 GenFdsGlobalVariable
.VerboseLogger("VersionString : %s" % self
.VersionString
)
311 GenFdsGlobalVariable
.VerboseLogger("InfFileName :%s" % self
.InfFileName
)
314 # Set OutputPath = ${WorkSpace}\Build\Fv\Ffs\${ModuleGuid}+ ${MdouleName}\
317 self
.OutputPath
= os
.path
.join(GenFdsGlobalVariable
.FfsDir
, \
318 self
.ModuleGuid
+ self
.BaseName
)
319 if not os
.path
.exists(self
.OutputPath
) :
320 os
.makedirs(self
.OutputPath
)
322 self
.EfiOutputPath
= self
.__GetEFIOutPutPath
__()
323 GenFdsGlobalVariable
.VerboseLogger( "ModuelEFIPath: " + self
.EfiOutputPath
)
327 # Patch EFI file with patch PCD
329 # @param EfiFile: EFI file needs to be patched.
330 # @retval: Full path of patched EFI file: self.OutputPath + EfiFile base name
331 # If passed in file does not end with efi, return as is
333 def PatchEfiFile(self
, EfiFile
, FileType
):
335 # If the module does not have any patches, then return path to input file
337 if not self
.PatchPcds
:
341 # Only patch file if FileType is PE32 or ModuleType is USER_DEFINED
343 if FileType
!= 'PE32' and self
.ModuleType
!= "USER_DEFINED":
347 # Generate path to patched output file
349 Basename
= os
.path
.basename(EfiFile
)
350 Output
= os
.path
.normpath (os
.path
.join(self
.OutputPath
, Basename
))
353 # If this file has already been patched, then return the path to the patched file
355 if self
.PatchedBinFile
== Output
:
359 # If a different file from the same module has already been patched, then generate an error
361 if self
.PatchedBinFile
:
362 EdkLogger
.error("GenFds", GENFDS_ERROR
,
363 'Only one binary file can be patched:\n'
364 ' a binary file has been patched: %s\n'
365 ' current file: %s' % (self
.PatchedBinFile
, EfiFile
),
366 File
=self
.InfFileName
)
369 # Copy unpatched file contents to output file location to perform patching
371 CopyLongFilePath(EfiFile
, Output
)
374 # Apply patches to patched output file
376 for Pcd
, Value
in self
.PatchPcds
:
377 RetVal
, RetStr
= PatchBinaryFile(Output
, int(Pcd
.Offset
, 0), Pcd
.DatumType
, Value
, Pcd
.MaxDatumSize
)
379 EdkLogger
.error("GenFds", GENFDS_ERROR
, RetStr
, File
=self
.InfFileName
)
382 # Save the path of the patched output file
384 self
.PatchedBinFile
= Output
387 # Return path to patched output file
395 # @param self The object pointer
396 # @param Dict dictionary contains macro and value pair
397 # @param FvChildAddr Array of the inside FvImage base address
398 # @param FvParentAddr Parent Fv base address
399 # @retval string Generated FFS file name
401 def GenFfs(self
, Dict
= {}, FvChildAddr
= [], FvParentAddr
=None):
403 # Parse Inf file get Module related information
406 self
.__InfParse
__(Dict
)
407 SrcFile
= mws
.join( GenFdsGlobalVariable
.WorkSpaceDir
, self
.InfFileName
);
408 DestFile
= os
.path
.join( self
.OutputPath
, self
.ModuleGuid
+ '.ffs')
411 SrcPath
= os
.path
.dirname(SrcFile
)
412 SrcFileName
= os
.path
.basename(SrcFile
)
413 SrcFileBase
, SrcFileExt
= os
.path
.splitext(SrcFileName
)
414 DestPath
= os
.path
.dirname(DestFile
)
415 DestFileName
= os
.path
.basename(DestFile
)
416 DestFileBase
, DestFileExt
= os
.path
.splitext(DestFileName
)
420 "${s_path}" : SrcPath
,
421 "${s_dir}" : SrcFileDir
,
422 "${s_name}" : SrcFileName
,
423 "${s_base}" : SrcFileBase
,
424 "${s_ext}" : SrcFileExt
,
427 "${d_path}" : DestPath
,
428 "${d_name}" : DestFileName
,
429 "${d_base}" : DestFileBase
,
430 "${d_ext}" : DestFileExt
433 # Allow binary type module not specify override rule in FDF file.
435 if len(self
.BinFileList
) > 0:
436 if self
.Rule
== None or self
.Rule
== "":
440 # Get the rule of how to generate Ffs file
442 Rule
= self
.__GetRule
__()
443 GenFdsGlobalVariable
.VerboseLogger( "Packing binaries from inf file : %s" %self
.InfFileName
)
445 # Convert Fv File Type for PI1.1 SMM driver.
447 if self
.ModuleType
== 'DXE_SMM_DRIVER' and int(self
.PiSpecVersion
, 16) >= 0x0001000A:
448 if Rule
.FvFileType
== 'DRIVER':
449 Rule
.FvFileType
= 'SMM'
451 # Framework SMM Driver has no SMM FV file type
453 if self
.ModuleType
== 'DXE_SMM_DRIVER' and int(self
.PiSpecVersion
, 16) < 0x0001000A:
454 if Rule
.FvFileType
== 'SMM' or Rule
.FvFileType
== 'SMM_CORE':
455 EdkLogger
.error("GenFds", FORMAT_NOT_SUPPORTED
, "Framework SMM module doesn't support SMM or SMM_CORE FV file type", File
=self
.InfFileName
)
457 # For the rule only has simpleFile
459 if isinstance (Rule
, RuleSimpleFile
.RuleSimpleFile
) :
460 SectionOutputList
= self
.__GenSimpleFileSection
__(Rule
)
461 FfsOutput
= self
.__GenSimpleFileFfs
__(Rule
, SectionOutputList
)
464 # For Rule has ComplexFile
466 elif isinstance(Rule
, RuleComplexFile
.RuleComplexFile
):
467 InputSectList
, InputSectAlignments
= self
.__GenComplexFileSection
__(Rule
, FvChildAddr
, FvParentAddr
)
468 FfsOutput
= self
.__GenComplexFileFfs
__(Rule
, InputSectList
, InputSectAlignments
)
472 ## __ExtendMacro__() method
474 # Replace macro with its value
476 # @param self The object pointer
477 # @param String The string to be replaced
478 # @retval string Macro replaced string
480 def __ExtendMacro__ (self
, String
):
482 '$(INF_OUTPUT)' : self
.EfiOutputPath
,
483 '$(MODULE_NAME)' : self
.BaseName
,
484 '$(BUILD_NUMBER)': self
.BuildNum
,
485 '$(INF_VERSION)' : self
.VersionString
,
486 '$(NAMED_GUID)' : self
.ModuleGuid
488 String
= GenFdsGlobalVariable
.MacroExtend(String
, MacroDict
)
489 String
= GenFdsGlobalVariable
.MacroExtend(String
, self
.MacroDict
)
492 ## __GetRule__() method
494 # Get correct rule for generating FFS for this INF
496 # @param self The object pointer
497 # @retval Rule Rule object
499 def __GetRule__ (self
) :
501 if self
.CurrentArch
== None:
502 CurrentArchList
= ['common']
504 CurrentArchList
.append(self
.CurrentArch
)
506 for CurrentArch
in CurrentArchList
:
507 RuleName
= 'RULE' + \
509 CurrentArch
.upper() + \
511 self
.ModuleType
.upper()
512 if self
.Rule
!= None:
513 RuleName
= RuleName
+ \
517 Rule
= GenFdsGlobalVariable
.FdfParser
.Profile
.RuleDict
.get(RuleName
)
519 GenFdsGlobalVariable
.VerboseLogger ("Want To Find Rule Name is : " + RuleName
)
522 RuleName
= 'RULE' + \
526 self
.ModuleType
.upper()
528 if self
.Rule
!= None:
529 RuleName
= RuleName
+ \
533 GenFdsGlobalVariable
.VerboseLogger ('Trying to apply common rule %s for INF %s' % (RuleName
, self
.InfFileName
))
535 Rule
= GenFdsGlobalVariable
.FdfParser
.Profile
.RuleDict
.get(RuleName
)
537 GenFdsGlobalVariable
.VerboseLogger ("Want To Find Rule Name is : " + RuleName
)
541 EdkLogger
.error("GenFds", GENFDS_ERROR
, 'Don\'t Find common rule %s for INF %s' \
542 % (RuleName
, self
.InfFileName
))
544 ## __GetPlatformArchList__() method
546 # Get Arch list this INF built under
548 # @param self The object pointer
549 # @retval list Arch list
551 def __GetPlatformArchList__(self
):
553 InfFileKey
= os
.path
.normpath(mws
.join(GenFdsGlobalVariable
.WorkSpaceDir
, self
.InfFileName
))
555 PlatformDataBase
= GenFdsGlobalVariable
.WorkSpace
.BuildObject
[GenFdsGlobalVariable
.ActivePlatform
, 'IA32', GenFdsGlobalVariable
.TargetName
, GenFdsGlobalVariable
.ToolChainTag
]
556 if PlatformDataBase
!= None:
557 if InfFileKey
in PlatformDataBase
.Modules
:
558 DscArchList
.append ('IA32')
560 PlatformDataBase
= GenFdsGlobalVariable
.WorkSpace
.BuildObject
[GenFdsGlobalVariable
.ActivePlatform
, 'X64', GenFdsGlobalVariable
.TargetName
, GenFdsGlobalVariable
.ToolChainTag
]
561 if PlatformDataBase
!= None:
562 if InfFileKey
in PlatformDataBase
.Modules
:
563 DscArchList
.append ('X64')
565 PlatformDataBase
= GenFdsGlobalVariable
.WorkSpace
.BuildObject
[GenFdsGlobalVariable
.ActivePlatform
, 'IPF', GenFdsGlobalVariable
.TargetName
, GenFdsGlobalVariable
.ToolChainTag
]
566 if PlatformDataBase
!= None:
567 if InfFileKey
in (PlatformDataBase
.Modules
):
568 DscArchList
.append ('IPF')
570 PlatformDataBase
= GenFdsGlobalVariable
.WorkSpace
.BuildObject
[GenFdsGlobalVariable
.ActivePlatform
, 'ARM', GenFdsGlobalVariable
.TargetName
, GenFdsGlobalVariable
.ToolChainTag
]
571 if PlatformDataBase
!= None:
572 if InfFileKey
in (PlatformDataBase
.Modules
):
573 DscArchList
.append ('ARM')
575 PlatformDataBase
= GenFdsGlobalVariable
.WorkSpace
.BuildObject
[GenFdsGlobalVariable
.ActivePlatform
, 'EBC', GenFdsGlobalVariable
.TargetName
, GenFdsGlobalVariable
.ToolChainTag
]
576 if PlatformDataBase
!= None:
577 if InfFileKey
in (PlatformDataBase
.Modules
):
578 DscArchList
.append ('EBC')
580 PlatformDataBase
= GenFdsGlobalVariable
.WorkSpace
.BuildObject
[GenFdsGlobalVariable
.ActivePlatform
, 'AARCH64', GenFdsGlobalVariable
.TargetName
, GenFdsGlobalVariable
.ToolChainTag
]
581 if PlatformDataBase
!= None:
582 if InfFileKey
in (PlatformDataBase
.Modules
):
583 DscArchList
.append ('AARCH64')
587 ## GetCurrentArch() method
589 # Get Arch list of the module from this INF is to be placed into flash
591 # @param self The object pointer
592 # @retval list Arch list
594 def GetCurrentArch(self
) :
596 TargetArchList
= GenFdsGlobalVariable
.ArchList
598 PlatformArchList
= self
.__GetPlatformArchList
__()
600 CurArchList
= TargetArchList
601 if PlatformArchList
!= []:
602 CurArchList
= list(set (TargetArchList
) & set (PlatformArchList
))
603 GenFdsGlobalVariable
.VerboseLogger ("Valid target architecture(s) is : " + " ".join(CurArchList
))
606 if self
.KeyStringList
!= []:
607 for Key
in self
.KeyStringList
:
608 Key
= GenFdsGlobalVariable
.MacroExtend(Key
)
609 Target
, Tag
, Arch
= Key
.split('_')
610 if Arch
in CurArchList
:
611 ArchList
.append(Arch
)
612 if Target
not in self
.TargetOverrideList
:
613 self
.TargetOverrideList
.append(Target
)
615 ArchList
= CurArchList
617 UseArchList
= TargetArchList
618 if self
.UseArch
!= None:
620 UseArchList
.append(self
.UseArch
)
621 ArchList
= list(set (UseArchList
) & set (ArchList
))
623 self
.InfFileName
= NormPath(self
.InfFileName
)
624 if len(PlatformArchList
) == 0:
626 PathClassObj
= PathClass(self
.InfFileName
, GenFdsGlobalVariable
.WorkSpaceDir
)
627 ErrorCode
, ErrorInfo
= PathClassObj
.Validate(".inf")
629 EdkLogger
.error("GenFds", ErrorCode
, ExtraData
=ErrorInfo
)
630 if len(ArchList
) == 1:
633 elif len(ArchList
) > 1:
634 if len(PlatformArchList
) == 0:
635 EdkLogger
.error("GenFds", GENFDS_ERROR
, "GenFds command line option has multiple ARCHs %s. Not able to determine which ARCH is valid for Module %s !" % (str(ArchList
), self
.InfFileName
))
637 EdkLogger
.error("GenFds", GENFDS_ERROR
, "Module built under multiple ARCHs %s. Not able to determine which output to put into flash for Module %s !" % (str(ArchList
), self
.InfFileName
))
639 EdkLogger
.error("GenFds", GENFDS_ERROR
, "Module %s appears under ARCH %s in platform %s, but current deduced ARCH is %s, so NO build output could be put into flash." \
640 % (self
.InfFileName
, str(PlatformArchList
), GenFdsGlobalVariable
.ActivePlatform
, str(set (UseArchList
) & set (TargetArchList
))))
642 ## __GetEFIOutPutPath__() method
644 # Get the output path for generated files
646 # @param self The object pointer
647 # @retval string Path that output files from this INF go to
649 def __GetEFIOutPutPath__(self
):
652 (ModulePath
, FileName
) = os
.path
.split(self
.InfFileName
)
653 Index
= FileName
.rfind('.')
654 FileName
= FileName
[0:Index
]
655 if self
.OverrideGuid
:
656 FileName
= self
.OverrideGuid
658 if self
.CurrentArch
!= None:
659 Arch
= self
.CurrentArch
661 OutputPath
= os
.path
.join(GenFdsGlobalVariable
.OutputDirDict
[Arch
],
667 OutputPath
= os
.path
.realpath(OutputPath
)
670 ## __GenSimpleFileSection__() method
672 # Generate section by specified file name or a list of files with file extension
674 # @param self The object pointer
675 # @param Rule The rule object used to generate section
676 # @retval string File name of the generated section file
678 def __GenSimpleFileSection__(self
, Rule
):
680 # Prepare the parameter of GenSection
684 GenSecInputFile
= None
685 if Rule
.FileName
!= None:
686 GenSecInputFile
= self
.__ExtendMacro
__(Rule
.FileName
)
687 if os
.path
.isabs(GenSecInputFile
):
688 GenSecInputFile
= os
.path
.normpath(GenSecInputFile
)
690 GenSecInputFile
= os
.path
.normpath(os
.path
.join(self
.EfiOutputPath
, GenSecInputFile
))
692 FileList
, IsSect
= Section
.Section
.GetFileList(self
, '', Rule
.FileExtension
)
695 SectionType
= Rule
.SectionType
697 # Convert Fv Section Type for PI1.1 SMM driver.
699 if self
.ModuleType
== 'DXE_SMM_DRIVER' and int(self
.PiSpecVersion
, 16) >= 0x0001000A:
700 if SectionType
== 'DXE_DEPEX':
701 SectionType
= 'SMM_DEPEX'
703 # Framework SMM Driver has no SMM_DEPEX section type
705 if self
.ModuleType
== 'DXE_SMM_DRIVER' and int(self
.PiSpecVersion
, 16) < 0x0001000A:
706 if SectionType
== 'SMM_DEPEX':
707 EdkLogger
.error("GenFds", FORMAT_NOT_SUPPORTED
, "Framework SMM module doesn't support SMM_DEPEX section type", File
=self
.InfFileName
)
709 if self
.ModuleType
in ('SEC', 'PEI_CORE', 'PEIM'):
710 if self
.KeepReloc
!= None:
711 NoStrip
= self
.KeepReloc
712 elif Rule
.KeepReloc
!= None:
713 NoStrip
= Rule
.KeepReloc
714 elif self
.ShadowFromInfFile
!= None:
715 NoStrip
= self
.ShadowFromInfFile
718 for File
in FileList
:
721 GenSecOutputFile
= self
.__ExtendMacro
__(Rule
.NameGuid
) + \
722 Ffs
.Ffs
.SectionSuffix
[SectionType
] + 'SEC' + SecNum
724 OutputFile
= os
.path
.join(self
.OutputPath
, GenSecOutputFile
)
725 File
= GenFdsGlobalVariable
.MacroExtend(File
, Dict
, self
.CurrentArch
)
727 #Get PE Section alignment when align is set to AUTO
728 if self
.Alignment
== 'Auto' and (SectionType
== 'PE32' or SectionType
== 'TE'):
729 ImageObj
= PeImageClass (File
)
730 if ImageObj
.SectionAlignment
< 0x400:
731 self
.Alignment
= str (ImageObj
.SectionAlignment
)
733 self
.Alignment
= str (ImageObj
.SectionAlignment
/ 0x400) + 'K'
736 FileBeforeStrip
= os
.path
.join(self
.OutputPath
, ModuleName
+ '.reloc')
737 if not os
.path
.exists(FileBeforeStrip
) or \
738 (os
.path
.getmtime(File
) > os
.path
.getmtime(FileBeforeStrip
)):
739 CopyLongFilePath(File
, FileBeforeStrip
)
740 StrippedFile
= os
.path
.join(self
.OutputPath
, ModuleName
+ '.stipped')
741 GenFdsGlobalVariable
.GenerateFirmwareImage(
748 if SectionType
== 'TE':
749 TeFile
= os
.path
.join( self
.OutputPath
, self
.ModuleGuid
+ 'Te.raw')
750 GenFdsGlobalVariable
.GenerateFirmwareImage(
757 GenFdsGlobalVariable
.GenerateSection(OutputFile
, [File
], Section
.Section
.SectionType
[SectionType
])
758 OutputFileList
.append(OutputFile
)
761 GenSecOutputFile
= self
.__ExtendMacro
__(Rule
.NameGuid
) + \
762 Ffs
.Ffs
.SectionSuffix
[SectionType
] + 'SEC' + SecNum
763 OutputFile
= os
.path
.join(self
.OutputPath
, GenSecOutputFile
)
764 GenSecInputFile
= GenFdsGlobalVariable
.MacroExtend(GenSecInputFile
, Dict
, self
.CurrentArch
)
766 #Get PE Section alignment when align is set to AUTO
767 if self
.Alignment
== 'Auto' and (SectionType
== 'PE32' or SectionType
== 'TE'):
768 ImageObj
= PeImageClass (GenSecInputFile
)
769 if ImageObj
.SectionAlignment
< 0x400:
770 self
.Alignment
= str (ImageObj
.SectionAlignment
)
772 self
.Alignment
= str (ImageObj
.SectionAlignment
/ 0x400) + 'K'
775 FileBeforeStrip
= os
.path
.join(self
.OutputPath
, ModuleName
+ '.reloc')
776 if not os
.path
.exists(FileBeforeStrip
) or \
777 (os
.path
.getmtime(GenSecInputFile
) > os
.path
.getmtime(FileBeforeStrip
)):
778 CopyLongFilePath(GenSecInputFile
, FileBeforeStrip
)
780 StrippedFile
= os
.path
.join(self
.OutputPath
, ModuleName
+ '.stipped')
781 GenFdsGlobalVariable
.GenerateFirmwareImage(
786 GenSecInputFile
= StrippedFile
788 if SectionType
== 'TE':
789 TeFile
= os
.path
.join( self
.OutputPath
, self
.ModuleGuid
+ 'Te.raw')
790 GenFdsGlobalVariable
.GenerateFirmwareImage(
795 GenSecInputFile
= TeFile
797 GenFdsGlobalVariable
.GenerateSection(OutputFile
, [GenSecInputFile
], Section
.Section
.SectionType
[SectionType
])
798 OutputFileList
.append(OutputFile
)
800 return OutputFileList
802 ## __GenSimpleFileFfs__() method
806 # @param self The object pointer
807 # @param Rule The rule object used to generate section
808 # @param InputFileList The output file list from GenSection
809 # @retval string Generated FFS file name
811 def __GenSimpleFileFfs__(self
, Rule
, InputFileList
):
812 FfsOutput
= self
.OutputPath
+ \
814 self
.__ExtendMacro
__(Rule
.NameGuid
) + \
817 GenFdsGlobalVariable
.VerboseLogger(self
.__ExtendMacro
__(Rule
.NameGuid
))
819 SectionAlignments
= []
820 for InputFile
in InputFileList
:
821 InputSection
.append(InputFile
)
822 SectionAlignments
.append(Rule
.SectAlignment
)
824 if Rule
.NameGuid
!= None and Rule
.NameGuid
.startswith('PCD('):
825 PcdValue
= GenFdsGlobalVariable
.GetPcdValue(Rule
.NameGuid
)
826 if len(PcdValue
) == 0:
827 EdkLogger
.error("GenFds", GENFDS_ERROR
, '%s NOT defined.' \
829 if PcdValue
.startswith('{'):
830 PcdValue
= GuidStructureByteArrayToGuidString(PcdValue
)
831 RegistryGuidStr
= PcdValue
832 if len(RegistryGuidStr
) == 0:
833 EdkLogger
.error("GenFds", GENFDS_ERROR
, 'GUID value for %s in wrong format.' \
835 self
.ModuleGuid
= RegistryGuidStr
837 GenFdsGlobalVariable
.GenerateFfs(FfsOutput
, InputSection
,
838 Ffs
.Ffs
.FdfFvFileTypeToFileType
[Rule
.FvFileType
],
839 self
.ModuleGuid
, Fixed
=Rule
.Fixed
,
840 CheckSum
=Rule
.CheckSum
, Align
=Rule
.Alignment
,
841 SectionAlign
=SectionAlignments
845 ## __GenComplexFileSection__() method
847 # Generate section by sections in Rule
849 # @param self The object pointer
850 # @param Rule The rule object used to generate section
851 # @param FvChildAddr Array of the inside FvImage base address
852 # @param FvParentAddr Parent Fv base address
853 # @retval string File name of the generated section file
855 def __GenComplexFileSection__(self
, Rule
, FvChildAddr
, FvParentAddr
):
856 if self
.ModuleType
in ('SEC', 'PEI_CORE', 'PEIM'):
857 if Rule
.KeepReloc
!= None:
858 self
.KeepRelocFromRule
= Rule
.KeepReloc
862 HasGneratedFlag
= False
863 if self
.PcdIsDriver
== 'PEI_PCD_DRIVER':
864 if self
.IsBinaryModule
:
865 PcdExDbFileName
= os
.path
.join(GenFdsGlobalVariable
.FvDir
, "PEIPcdDataBase.raw")
867 PcdExDbFileName
= os
.path
.join(self
.EfiOutputPath
, "PEIPcdDataBase.raw")
868 PcdExDbSecName
= os
.path
.join(self
.OutputPath
, "PEIPcdDataBaseSec.raw")
869 GenFdsGlobalVariable
.GenerateSection(PcdExDbSecName
,
873 SectFiles
.append(PcdExDbSecName
)
874 SectAlignments
.append(None)
875 elif self
.PcdIsDriver
== 'DXE_PCD_DRIVER':
876 if self
.IsBinaryModule
:
877 PcdExDbFileName
= os
.path
.join(GenFdsGlobalVariable
.FvDir
, "DXEPcdDataBase.raw")
879 PcdExDbFileName
= os
.path
.join(self
.EfiOutputPath
, "DXEPcdDataBase.raw")
880 PcdExDbSecName
= os
.path
.join(self
.OutputPath
, "DXEPcdDataBaseSec.raw")
881 GenFdsGlobalVariable
.GenerateSection(PcdExDbSecName
,
885 SectFiles
.append(PcdExDbSecName
)
886 SectAlignments
.append(None)
887 for Sect
in Rule
.SectionList
:
888 SecIndex
= '%d' %Index
891 # Convert Fv Section Type for PI1.1 SMM driver.
893 if self
.ModuleType
== 'DXE_SMM_DRIVER' and int(self
.PiSpecVersion
, 16) >= 0x0001000A:
894 if Sect
.SectionType
== 'DXE_DEPEX':
895 Sect
.SectionType
= 'SMM_DEPEX'
897 # Framework SMM Driver has no SMM_DEPEX section type
899 if self
.ModuleType
== 'DXE_SMM_DRIVER' and int(self
.PiSpecVersion
, 16) < 0x0001000A:
900 if Sect
.SectionType
== 'SMM_DEPEX':
901 EdkLogger
.error("GenFds", FORMAT_NOT_SUPPORTED
, "Framework SMM module doesn't support SMM_DEPEX section type", File
=self
.InfFileName
)
903 # process the inside FvImage from FvSection or GuidSection
905 if FvChildAddr
!= []:
906 if isinstance(Sect
, FvImageSection
):
907 Sect
.FvAddr
= FvChildAddr
.pop(0)
908 elif isinstance(Sect
, GuidSection
):
909 Sect
.FvAddr
= FvChildAddr
910 if FvParentAddr
!= None and isinstance(Sect
, GuidSection
):
911 Sect
.FvParentAddr
= FvParentAddr
913 if Rule
.KeyStringList
!= []:
914 SectList
, Align
= Sect
.GenSection(self
.OutputPath
, self
.ModuleGuid
, SecIndex
, Rule
.KeyStringList
, self
)
916 SectList
, Align
= Sect
.GenSection(self
.OutputPath
, self
.ModuleGuid
, SecIndex
, self
.KeyStringList
, self
)
918 if not HasGneratedFlag
:
919 UniVfrOffsetFileSection
= ""
920 ModuleFileName
= mws
.join(GenFdsGlobalVariable
.WorkSpaceDir
, self
.InfFileName
)
921 InfData
= GenFdsGlobalVariable
.WorkSpace
.BuildObject
[PathClass(ModuleFileName
), self
.CurrentArch
]
923 # Search the source list in InfData to find if there are .vfr file exist.
926 VfrUniOffsetList
= []
927 for SourceFile
in InfData
.Sources
:
928 if SourceFile
.Type
.upper() == ".VFR" :
930 # search the .map file to find the offset of vfr binary in the PE32+/TE file.
932 VfrUniBaseName
[SourceFile
.BaseName
] = (SourceFile
.BaseName
+ "Bin")
933 if SourceFile
.Type
.upper() == ".UNI" :
935 # search the .map file to find the offset of Uni strings binary in the PE32+/TE file.
937 VfrUniBaseName
["UniOffsetName"] = (self
.BaseName
+ "Strings")
940 if len(VfrUniBaseName
) > 0:
941 VfrUniOffsetList
= self
.__GetBuildOutputMapFileVfrUniInfo
(VfrUniBaseName
)
943 # Generate the Raw data of raw section
945 os
.path
.join( self
.OutputPath
, self
.BaseName
+ '.offset')
946 UniVfrOffsetFileName
= os
.path
.join( self
.OutputPath
, self
.BaseName
+ '.offset')
947 UniVfrOffsetFileSection
= os
.path
.join( self
.OutputPath
, self
.BaseName
+ 'Offset' + '.raw')
949 self
.__GenUniVfrOffsetFile
(VfrUniOffsetList
, UniVfrOffsetFileName
)
951 UniVfrOffsetFileNameList
= []
952 UniVfrOffsetFileNameList
.append(UniVfrOffsetFileName
)
953 """Call GenSection"""
954 GenFdsGlobalVariable
.GenerateSection(UniVfrOffsetFileSection
,
955 UniVfrOffsetFileNameList
,
958 os
.remove(UniVfrOffsetFileName
)
959 SectList
.append(UniVfrOffsetFileSection
)
960 HasGneratedFlag
= True
962 for SecName
in SectList
:
963 SectFiles
.append(SecName
)
964 SectAlignments
.append(Align
)
966 return SectFiles
, SectAlignments
968 ## __GenComplexFileFfs__() method
972 # @param self The object pointer
973 # @param Rule The rule object used to generate section
974 # @param InputFileList The output file list from GenSection
975 # @retval string Generated FFS file name
977 def __GenComplexFileFfs__(self
, Rule
, InputFile
, Alignments
):
979 if Rule
.NameGuid
!= None and Rule
.NameGuid
.startswith('PCD('):
980 PcdValue
= GenFdsGlobalVariable
.GetPcdValue(Rule
.NameGuid
)
981 if len(PcdValue
) == 0:
982 EdkLogger
.error("GenFds", GENFDS_ERROR
, '%s NOT defined.' \
984 if PcdValue
.startswith('{'):
985 PcdValue
= GuidStructureByteArrayToGuidString(PcdValue
)
986 RegistryGuidStr
= PcdValue
987 if len(RegistryGuidStr
) == 0:
988 EdkLogger
.error("GenFds", GENFDS_ERROR
, 'GUID value for %s in wrong format.' \
990 self
.ModuleGuid
= RegistryGuidStr
992 FfsOutput
= os
.path
.join( self
.OutputPath
, self
.ModuleGuid
+ '.ffs')
993 GenFdsGlobalVariable
.GenerateFfs(FfsOutput
, InputFile
,
994 Ffs
.Ffs
.FdfFvFileTypeToFileType
[Rule
.FvFileType
],
995 self
.ModuleGuid
, Fixed
=Rule
.Fixed
,
996 CheckSum
=Rule
.CheckSum
, Align
=Rule
.Alignment
,
997 SectionAlign
=Alignments
1001 ## __GetGenFfsCmdParameter__() method
1003 # Create parameter string for GenFfs
1005 # @param self The object pointer
1006 # @param Rule The rule object used to generate section
1007 # @retval tuple (FileType, Fixed, CheckSum, Alignment)
1009 def __GetGenFfsCmdParameter__(self
, Rule
):
1011 result
+= ('-t', Ffs
.Ffs
.FdfFvFileTypeToFileType
[Rule
.FvFileType
])
1012 if Rule
.Fixed
!= False:
1014 if Rule
.CheckSum
!= False:
1017 if Rule
.Alignment
!= None and Rule
.Alignment
!= '':
1018 result
+= ('-a', Rule
.Alignment
)
1022 ## __GetBuildOutputMapFileVfrUniInfo() method
1024 # Find the offset of UNI/INF object offset in the EFI image file.
1026 # @param self The object pointer
1027 # @param VfrUniBaseName A name list contain the UNI/INF object name.
1028 # @retval RetValue A list contain offset of UNI/INF object.
1030 def __GetBuildOutputMapFileVfrUniInfo(self
, VfrUniBaseName
):
1031 MapFileName
= os
.path
.join(self
.EfiOutputPath
, self
.BaseName
+ ".map")
1032 EfiFileName
= os
.path
.join(self
.EfiOutputPath
, self
.BaseName
+ ".efi")
1033 return GetVariableOffset(MapFileName
, EfiFileName
, VfrUniBaseName
.values())
1035 ## __GenUniVfrOffsetFile() method
1037 # Generate the offset file for the module which contain VFR or UNI file.
1039 # @param self The object pointer
1040 # @param VfrUniOffsetList A list contain the VFR/UNI offsets in the EFI image file.
1041 # @param UniVfrOffsetFileName The output offset file name.
1043 def __GenUniVfrOffsetFile(self
, VfrUniOffsetList
, UniVfrOffsetFileName
):
1046 fInputfile
= open(UniVfrOffsetFileName
, "wb+", 0)
1048 EdkLogger
.error("GenFds", FILE_OPEN_FAILURE
, "File open failed for %s" %UniVfrOffsetFileName
,None)
1050 # Use a instance of StringIO to cache data
1051 fStringIO
= StringIO
.StringIO('')
1053 for Item
in VfrUniOffsetList
:
1054 if (Item
[0].find("Strings") != -1):
1056 # UNI offset in image.
1058 # { 0x8913c5e0, 0x33f6, 0x4d86, { 0x9b, 0xf1, 0x43, 0xef, 0x89, 0xfc, 0x6, 0x66 } }
1060 UniGuid
= [0xe0, 0xc5, 0x13, 0x89, 0xf6, 0x33, 0x86, 0x4d, 0x9b, 0xf1, 0x43, 0xef, 0x89, 0xfc, 0x6, 0x66]
1061 UniGuid
= [chr(ItemGuid
) for ItemGuid
in UniGuid
]
1062 fStringIO
.write(''.join(UniGuid
))
1063 UniValue
= pack ('Q', int (Item
[1], 16))
1064 fStringIO
.write (UniValue
)
1067 # VFR binary offset in image.
1069 # { 0xd0bc7cb4, 0x6a47, 0x495f, { 0xaa, 0x11, 0x71, 0x7, 0x46, 0xda, 0x6, 0xa2 } };
1071 VfrGuid
= [0xb4, 0x7c, 0xbc, 0xd0, 0x47, 0x6a, 0x5f, 0x49, 0xaa, 0x11, 0x71, 0x7, 0x46, 0xda, 0x6, 0xa2]
1072 VfrGuid
= [chr(ItemGuid
) for ItemGuid
in VfrGuid
]
1073 fStringIO
.write(''.join(VfrGuid
))
1075 VfrValue
= pack ('Q', int (Item
[1], 16))
1076 fStringIO
.write (VfrValue
)
1079 # write data into file.
1082 fInputfile
.write (fStringIO
.getvalue())
1084 EdkLogger
.error("GenFds", FILE_WRITE_FAILURE
, "Write data to file %s failed, please check whether the file been locked or using by other applications." %UniVfrOffsetFileName
,None)