2 # process FFS generation from INF statement
4 # Copyright (c) 2007 - 2016, Intel Corporation. All rights reserved.<BR>
5 # Copyright (c) 2014-2016 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
46 import Common
.GlobalData
as GlobalData
48 ## generate FFS from INF
51 class FfsInfStatement(FfsInfStatementClassObject
):
52 ## The mapping dictionary from datum type to its maximum number.
53 _MAX_SIZE_TYPE
= {"BOOLEAN":0x01, "UINT8":0xFF, "UINT16":0xFFFF, "UINT32":0xFFFFFFFF, "UINT64":0xFFFFFFFFFFFFFFFF}
56 # @param self The object pointer
59 FfsInfStatementClassObject
.__init
__(self
)
60 self
.TargetOverrideList
= []
61 self
.ShadowFromInfFile
= None
62 self
.KeepRelocFromRule
= None
65 self
.PiSpecVersion
= '0x00000000'
67 self
.FinalTargetSuffixMap
= {}
68 self
.CurrentLineNum
= None
69 self
.CurrentLineContent
= None
71 self
.InfFileName
= None
72 self
.OverrideGuid
= None
73 self
.PatchedBinFile
= ''
76 ## GetFinalTargetSuffixMap() method
78 # Get final build target list
79 def GetFinalTargetSuffixMap(self
):
80 if not self
.InfModule
or not self
.CurrentArch
:
82 if not self
.FinalTargetSuffixMap
:
83 FinalBuildTargetList
= GenFdsGlobalVariable
.GetModuleCodaTargetList(self
.InfModule
, self
.CurrentArch
)
84 for File
in FinalBuildTargetList
:
85 self
.FinalTargetSuffixMap
.setdefault(os
.path
.splitext(File
)[1], []).append(File
)
87 # Check if current INF module has DEPEX
88 if '.depex' not in self
.FinalTargetSuffixMap
and self
.InfModule
.ModuleType
!= "USER_DEFINED" \
89 and not self
.InfModule
.DxsFile
and not self
.InfModule
.LibraryClass
:
90 ModuleType
= self
.InfModule
.ModuleType
91 PlatformDataBase
= GenFdsGlobalVariable
.WorkSpace
.BuildObject
[GenFdsGlobalVariable
.ActivePlatform
, self
.CurrentArch
, GenFdsGlobalVariable
.TargetName
, GenFdsGlobalVariable
.ToolChainTag
]
93 if ModuleType
!= DataType
.SUP_MODULE_USER_DEFINED
:
94 for LibraryClass
in PlatformDataBase
.LibraryClasses
.GetKeys():
95 if LibraryClass
.startswith("NULL") and PlatformDataBase
.LibraryClasses
[LibraryClass
, ModuleType
]:
96 self
.InfModule
.LibraryClasses
[LibraryClass
] = PlatformDataBase
.LibraryClasses
[LibraryClass
, ModuleType
]
98 StrModule
= str(self
.InfModule
)
100 if StrModule
in PlatformDataBase
.Modules
:
101 PlatformModule
= PlatformDataBase
.Modules
[StrModule
]
102 for LibraryClass
in PlatformModule
.LibraryClasses
:
103 if LibraryClass
.startswith("NULL"):
104 self
.InfModule
.LibraryClasses
[LibraryClass
] = PlatformModule
.LibraryClasses
[LibraryClass
]
106 DependencyList
= [self
.InfModule
]
109 while len(DependencyList
) > 0:
110 Module
= DependencyList
.pop(0)
113 for Dep
in Module
.Depex
[self
.CurrentArch
, ModuleType
]:
115 DepexList
.append('AND')
116 DepexList
.append('(')
117 DepexList
.extend(Dep
)
118 if DepexList
[-1] == 'END': # no need of a END at this time
120 DepexList
.append(')')
121 if 'BEFORE' in DepexList
or 'AFTER' in DepexList
:
123 for LibName
in Module
.LibraryClasses
:
124 if LibName
in LibraryInstance
:
126 if PlatformModule
and LibName
in PlatformModule
.LibraryClasses
:
127 LibraryPath
= PlatformModule
.LibraryClasses
[LibName
]
129 LibraryPath
= PlatformDataBase
.LibraryClasses
[LibName
, ModuleType
]
131 LibraryPath
= Module
.LibraryClasses
[LibName
]
134 LibraryModule
= GenFdsGlobalVariable
.WorkSpace
.BuildObject
[LibraryPath
, self
.CurrentArch
, GenFdsGlobalVariable
.TargetName
, GenFdsGlobalVariable
.ToolChainTag
]
135 LibraryInstance
[LibName
] = LibraryModule
136 DependencyList
.append(LibraryModule
)
138 Dpx
= DependencyExpression(DepexList
, ModuleType
, True)
139 if len(Dpx
.PostfixNotation
) != 0:
140 # It means this module has DEPEX
141 self
.FinalTargetSuffixMap
['.depex'] = [os
.path
.join(self
.EfiOutputPath
, self
.BaseName
) + '.depex']
142 return self
.FinalTargetSuffixMap
144 ## __InfParse() method
146 # Parse inf file to get module information
148 # @param self The object pointer
149 # @param Dict dictionary contains macro and value pair
151 def __InfParse__(self
, Dict
= {}):
153 GenFdsGlobalVariable
.VerboseLogger( " Begine parsing INf file : %s" %self
.InfFileName
)
155 self
.InfFileName
= self
.InfFileName
.replace('$(WORKSPACE)', '')
156 if len(self
.InfFileName
) > 1 and self
.InfFileName
[0] == '\\' and self
.InfFileName
[1] == '\\':
158 elif self
.InfFileName
[0] == '\\' or self
.InfFileName
[0] == '/' :
159 self
.InfFileName
= self
.InfFileName
[1:]
161 if self
.InfFileName
.find('$') == -1:
162 InfPath
= NormPath(self
.InfFileName
)
163 if not os
.path
.exists(InfPath
):
164 InfPath
= GenFdsGlobalVariable
.ReplaceWorkspaceMacro(InfPath
)
165 if not os
.path
.exists(InfPath
):
166 EdkLogger
.error("GenFds", GENFDS_ERROR
, "Non-existant Module %s !" % (self
.InfFileName
))
168 self
.CurrentArch
= self
.GetCurrentArch()
170 # Get the InfClass object
173 PathClassObj
= PathClass(self
.InfFileName
, GenFdsGlobalVariable
.WorkSpaceDir
)
174 ErrorCode
, ErrorInfo
= PathClassObj
.Validate(".inf")
176 EdkLogger
.error("GenFds", ErrorCode
, ExtraData
=ErrorInfo
)
179 # Cache lower case version of INF path before processing FILE_GUID override
181 InfLowerPath
= str(PathClassObj
).lower()
182 if self
.OverrideGuid
:
183 PathClassObj
= ProcessDuplicatedInf(PathClassObj
, self
.OverrideGuid
, GenFdsGlobalVariable
.WorkSpaceDir
)
184 if self
.CurrentArch
!= None:
186 Inf
= GenFdsGlobalVariable
.WorkSpace
.BuildObject
[PathClassObj
, self
.CurrentArch
, GenFdsGlobalVariable
.TargetName
, GenFdsGlobalVariable
.ToolChainTag
]
188 # Set Ffs BaseName, MdouleGuid, ModuleType, Version, OutputPath
190 self
.BaseName
= Inf
.BaseName
191 self
.ModuleGuid
= Inf
.Guid
192 self
.ModuleType
= Inf
.ModuleType
193 if Inf
.Specification
!= None and 'PI_SPECIFICATION_VERSION' in Inf
.Specification
:
194 self
.PiSpecVersion
= Inf
.Specification
['PI_SPECIFICATION_VERSION']
195 if Inf
.AutoGenVersion
< 0x00010005:
196 self
.ModuleType
= Inf
.ComponentType
197 self
.VersionString
= Inf
.Version
198 self
.BinFileList
= Inf
.Binaries
199 self
.SourceFileList
= Inf
.Sources
200 if self
.KeepReloc
== None and Inf
.Shadow
:
201 self
.ShadowFromInfFile
= Inf
.Shadow
204 Inf
= GenFdsGlobalVariable
.WorkSpace
.BuildObject
[PathClassObj
, 'COMMON', GenFdsGlobalVariable
.TargetName
, GenFdsGlobalVariable
.ToolChainTag
]
205 self
.BaseName
= Inf
.BaseName
206 self
.ModuleGuid
= Inf
.Guid
207 self
.ModuleType
= Inf
.ModuleType
208 if Inf
.Specification
!= None and 'PI_SPECIFICATION_VERSION' in Inf
.Specification
:
209 self
.PiSpecVersion
= Inf
.Specification
['PI_SPECIFICATION_VERSION']
210 self
.VersionString
= Inf
.Version
211 self
.BinFileList
= Inf
.Binaries
212 self
.SourceFileList
= Inf
.Sources
213 if self
.BinFileList
== []:
214 EdkLogger
.error("GenFds", GENFDS_ERROR
,
215 "INF %s specified in FDF could not be found in build ARCH %s!" \
216 % (self
.InfFileName
, GenFdsGlobalVariable
.ArchList
))
218 if self
.OverrideGuid
:
219 self
.ModuleGuid
= self
.OverrideGuid
221 if len(self
.SourceFileList
) != 0 and not self
.InDsc
:
222 EdkLogger
.warn("GenFds", GENFDS_ERROR
, "Module %s NOT found in DSC file; Is it really a binary module?" % (self
.InfFileName
))
224 if self
.ModuleType
== 'SMM_CORE' and int(self
.PiSpecVersion
, 16) < 0x0001000A:
225 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
)
227 if Inf
._Defs
!= None and len(Inf
._Defs
) > 0:
228 self
.OptRomDefs
.update(Inf
._Defs
)
232 Platform
= GenFdsGlobalVariable
.WorkSpace
.BuildObject
[GenFdsGlobalVariable
.ActivePlatform
, self
.CurrentArch
, GenFdsGlobalVariable
.TargetName
, GenFdsGlobalVariable
.ToolChainTag
]
233 FdfPcdDict
= GenFdsGlobalVariable
.FdfParser
.Profile
.PcdDict
235 # Workaround here: both build and GenFds tool convert the workspace path to lower case
236 # But INF file path in FDF and DSC file may have real case characters.
237 # Try to convert the path to lower case to see if PCDs value are override by DSC.
239 for DscModule
in Platform
.Modules
:
240 DscModules
[str(DscModule
).lower()] = Platform
.Modules
[DscModule
]
241 for PcdKey
in InfPcds
:
242 Pcd
= InfPcds
[PcdKey
]
243 if not hasattr(Pcd
, 'Offset'):
245 if Pcd
.Type
!= 'PatchableInModule':
247 # Override Patchable PCD value by the value from DSC
249 if InfLowerPath
in DscModules
and PcdKey
in DscModules
[InfLowerPath
].Pcds
:
250 PatchPcd
= DscModules
[InfLowerPath
].Pcds
[PcdKey
]
251 elif PcdKey
in Platform
.Pcds
:
252 PatchPcd
= Platform
.Pcds
[PcdKey
]
254 if PatchPcd
and Pcd
.Type
== PatchPcd
.Type
:
255 DefaultValue
= PatchPcd
.DefaultValue
258 # Override Patchable PCD value by the value from FDF
260 if PcdKey
in FdfPcdDict
:
261 DefaultValue
= FdfPcdDict
[PcdKey
]
264 # Override Patchable PCD value by the value from Build Option
265 BuildOptionOverride
= False
266 if GlobalData
.BuildOptionPcd
:
267 for pcd
in GlobalData
.BuildOptionPcd
:
268 if PcdKey
== (pcd
[1], pcd
[0]):
269 DefaultValue
= pcd
[2]
270 BuildOptionOverride
= True
273 if not DscOverride
and not FdfOverride
and not BuildOptionOverride
:
275 # Check value, if value are equal, no need to patch
276 if Pcd
.DatumType
== "VOID*":
277 if Pcd
.DefaultValue
== DefaultValue
or DefaultValue
in [None, '']:
279 # Get the string size from FDF or DSC
280 if DefaultValue
[0] == 'L':
281 # Remove L"", but the '\0' must be appended
282 MaxDatumSize
= str((len(DefaultValue
) - 2) * 2)
283 elif DefaultValue
[0] == '{':
284 MaxDatumSize
= str(len(DefaultValue
.split(',')))
286 MaxDatumSize
= str(len(DefaultValue
) - 1)
288 Pcd
.MaxDatumSize
= PatchPcd
.MaxDatumSize
289 # If no defined the maximum size in DSC, try to get current size from INF
290 if Pcd
.MaxDatumSize
in ['', None]:
291 Pcd
.MaxDatumSize
= str(len(Pcd
.DefaultValue
.split(',')))
294 if Pcd
.DefaultValue
.upper().startswith('0X'):
296 if DefaultValue
.upper().startswith('0X'):
299 PcdValueInImg
= int(Pcd
.DefaultValue
, Base1
)
300 PcdValueInDscOrFdf
= int(DefaultValue
, Base2
)
301 if PcdValueInImg
== PcdValueInDscOrFdf
:
305 # Check the Pcd size and data type
306 if Pcd
.DatumType
== "VOID*":
307 if int(MaxDatumSize
) > int(Pcd
.MaxDatumSize
):
308 EdkLogger
.error("GenFds", GENFDS_ERROR
, "The size of VOID* type PCD '%s.%s' exceeds its maximum size %d bytes." \
309 % (Pcd
.TokenSpaceGuidCName
, Pcd
.TokenCName
, int(MaxDatumSize
) - int(Pcd
.MaxDatumSize
)))
311 if PcdValueInDscOrFdf
> FfsInfStatement
._MAX
_SIZE
_TYPE
[Pcd
.DatumType
] \
312 or PcdValueInImg
> FfsInfStatement
._MAX
_SIZE
_TYPE
[Pcd
.DatumType
]:
313 EdkLogger
.error("GenFds", GENFDS_ERROR
, "The size of %s type PCD '%s.%s' doesn't match its data type." \
314 % (Pcd
.DatumType
, Pcd
.TokenSpaceGuidCName
, Pcd
.TokenCName
))
315 self
.PatchPcds
.append((Pcd
, DefaultValue
))
318 self
.PcdIsDriver
= Inf
.PcdIsDriver
319 self
.IsBinaryModule
= Inf
.IsBinaryModule
320 GenFdsGlobalVariable
.VerboseLogger("BaseName : %s" % self
.BaseName
)
321 GenFdsGlobalVariable
.VerboseLogger("ModuleGuid : %s" % self
.ModuleGuid
)
322 GenFdsGlobalVariable
.VerboseLogger("ModuleType : %s" % self
.ModuleType
)
323 GenFdsGlobalVariable
.VerboseLogger("VersionString : %s" % self
.VersionString
)
324 GenFdsGlobalVariable
.VerboseLogger("InfFileName :%s" % self
.InfFileName
)
327 # Set OutputPath = ${WorkSpace}\Build\Fv\Ffs\${ModuleGuid}+ ${MdouleName}\
330 self
.OutputPath
= os
.path
.join(GenFdsGlobalVariable
.FfsDir
, \
331 self
.ModuleGuid
+ self
.BaseName
)
332 if not os
.path
.exists(self
.OutputPath
) :
333 os
.makedirs(self
.OutputPath
)
335 self
.EfiOutputPath
= self
.__GetEFIOutPutPath
__()
336 GenFdsGlobalVariable
.VerboseLogger( "ModuelEFIPath: " + self
.EfiOutputPath
)
340 # Patch EFI file with patch PCD
342 # @param EfiFile: EFI file needs to be patched.
343 # @retval: Full path of patched EFI file: self.OutputPath + EfiFile base name
344 # If passed in file does not end with efi, return as is
346 def PatchEfiFile(self
, EfiFile
, FileType
):
348 # If the module does not have any patches, then return path to input file
350 if not self
.PatchPcds
:
354 # Only patch file if FileType is PE32 or ModuleType is USER_DEFINED
356 if FileType
!= 'PE32' and self
.ModuleType
!= "USER_DEFINED":
360 # Generate path to patched output file
362 Basename
= os
.path
.basename(EfiFile
)
363 Output
= os
.path
.normpath (os
.path
.join(self
.OutputPath
, Basename
))
366 # If this file has already been patched, then return the path to the patched file
368 if self
.PatchedBinFile
== Output
:
372 # If a different file from the same module has already been patched, then generate an error
374 if self
.PatchedBinFile
:
375 EdkLogger
.error("GenFds", GENFDS_ERROR
,
376 'Only one binary file can be patched:\n'
377 ' a binary file has been patched: %s\n'
378 ' current file: %s' % (self
.PatchedBinFile
, EfiFile
),
379 File
=self
.InfFileName
)
382 # Copy unpatched file contents to output file location to perform patching
384 CopyLongFilePath(EfiFile
, Output
)
387 # Apply patches to patched output file
389 for Pcd
, Value
in self
.PatchPcds
:
390 RetVal
, RetStr
= PatchBinaryFile(Output
, int(Pcd
.Offset
, 0), Pcd
.DatumType
, Value
, Pcd
.MaxDatumSize
)
392 EdkLogger
.error("GenFds", GENFDS_ERROR
, RetStr
, File
=self
.InfFileName
)
395 # Save the path of the patched output file
397 self
.PatchedBinFile
= Output
400 # Return path to patched output file
408 # @param self The object pointer
409 # @param Dict dictionary contains macro and value pair
410 # @param FvChildAddr Array of the inside FvImage base address
411 # @param FvParentAddr Parent Fv base address
412 # @retval string Generated FFS file name
414 def GenFfs(self
, Dict
= {}, FvChildAddr
= [], FvParentAddr
=None):
416 # Parse Inf file get Module related information
419 self
.__InfParse
__(Dict
)
420 SrcFile
= mws
.join( GenFdsGlobalVariable
.WorkSpaceDir
, self
.InfFileName
);
421 DestFile
= os
.path
.join( self
.OutputPath
, self
.ModuleGuid
+ '.ffs')
424 SrcPath
= os
.path
.dirname(SrcFile
)
425 SrcFileName
= os
.path
.basename(SrcFile
)
426 SrcFileBase
, SrcFileExt
= os
.path
.splitext(SrcFileName
)
427 DestPath
= os
.path
.dirname(DestFile
)
428 DestFileName
= os
.path
.basename(DestFile
)
429 DestFileBase
, DestFileExt
= os
.path
.splitext(DestFileName
)
433 "${s_path}" : SrcPath
,
434 "${s_dir}" : SrcFileDir
,
435 "${s_name}" : SrcFileName
,
436 "${s_base}" : SrcFileBase
,
437 "${s_ext}" : SrcFileExt
,
440 "${d_path}" : DestPath
,
441 "${d_name}" : DestFileName
,
442 "${d_base}" : DestFileBase
,
443 "${d_ext}" : DestFileExt
446 # Allow binary type module not specify override rule in FDF file.
448 if len(self
.BinFileList
) > 0:
449 if self
.Rule
== None or self
.Rule
== "":
453 # Get the rule of how to generate Ffs file
455 Rule
= self
.__GetRule
__()
456 GenFdsGlobalVariable
.VerboseLogger( "Packing binaries from inf file : %s" %self
.InfFileName
)
458 # Convert Fv File Type for PI1.1 SMM driver.
460 if self
.ModuleType
== 'DXE_SMM_DRIVER' and int(self
.PiSpecVersion
, 16) >= 0x0001000A:
461 if Rule
.FvFileType
== 'DRIVER':
462 Rule
.FvFileType
= 'SMM'
464 # Framework SMM Driver has no SMM FV file type
466 if self
.ModuleType
== 'DXE_SMM_DRIVER' and int(self
.PiSpecVersion
, 16) < 0x0001000A:
467 if Rule
.FvFileType
== 'SMM' or Rule
.FvFileType
== 'SMM_CORE':
468 EdkLogger
.error("GenFds", FORMAT_NOT_SUPPORTED
, "Framework SMM module doesn't support SMM or SMM_CORE FV file type", File
=self
.InfFileName
)
470 # For the rule only has simpleFile
472 if isinstance (Rule
, RuleSimpleFile
.RuleSimpleFile
) :
473 SectionOutputList
= self
.__GenSimpleFileSection
__(Rule
)
474 FfsOutput
= self
.__GenSimpleFileFfs
__(Rule
, SectionOutputList
)
477 # For Rule has ComplexFile
479 elif isinstance(Rule
, RuleComplexFile
.RuleComplexFile
):
480 InputSectList
, InputSectAlignments
= self
.__GenComplexFileSection
__(Rule
, FvChildAddr
, FvParentAddr
)
481 FfsOutput
= self
.__GenComplexFileFfs
__(Rule
, InputSectList
, InputSectAlignments
)
485 ## __ExtendMacro__() method
487 # Replace macro with its value
489 # @param self The object pointer
490 # @param String The string to be replaced
491 # @retval string Macro replaced string
493 def __ExtendMacro__ (self
, String
):
495 '$(INF_OUTPUT)' : self
.EfiOutputPath
,
496 '$(MODULE_NAME)' : self
.BaseName
,
497 '$(BUILD_NUMBER)': self
.BuildNum
,
498 '$(INF_VERSION)' : self
.VersionString
,
499 '$(NAMED_GUID)' : self
.ModuleGuid
501 String
= GenFdsGlobalVariable
.MacroExtend(String
, MacroDict
)
502 String
= GenFdsGlobalVariable
.MacroExtend(String
, self
.MacroDict
)
505 ## __GetRule__() method
507 # Get correct rule for generating FFS for this INF
509 # @param self The object pointer
510 # @retval Rule Rule object
512 def __GetRule__ (self
) :
514 if self
.CurrentArch
== None:
515 CurrentArchList
= ['common']
517 CurrentArchList
.append(self
.CurrentArch
)
519 for CurrentArch
in CurrentArchList
:
520 RuleName
= 'RULE' + \
522 CurrentArch
.upper() + \
524 self
.ModuleType
.upper()
525 if self
.Rule
!= None:
526 RuleName
= RuleName
+ \
530 Rule
= GenFdsGlobalVariable
.FdfParser
.Profile
.RuleDict
.get(RuleName
)
532 GenFdsGlobalVariable
.VerboseLogger ("Want To Find Rule Name is : " + RuleName
)
535 RuleName
= 'RULE' + \
539 self
.ModuleType
.upper()
541 if self
.Rule
!= None:
542 RuleName
= RuleName
+ \
546 GenFdsGlobalVariable
.VerboseLogger ('Trying to apply common rule %s for INF %s' % (RuleName
, self
.InfFileName
))
548 Rule
= GenFdsGlobalVariable
.FdfParser
.Profile
.RuleDict
.get(RuleName
)
550 GenFdsGlobalVariable
.VerboseLogger ("Want To Find Rule Name is : " + RuleName
)
554 EdkLogger
.error("GenFds", GENFDS_ERROR
, 'Don\'t Find common rule %s for INF %s' \
555 % (RuleName
, self
.InfFileName
))
557 ## __GetPlatformArchList__() method
559 # Get Arch list this INF built under
561 # @param self The object pointer
562 # @retval list Arch list
564 def __GetPlatformArchList__(self
):
566 InfFileKey
= os
.path
.normpath(mws
.join(GenFdsGlobalVariable
.WorkSpaceDir
, self
.InfFileName
))
568 for Arch
in GenFdsGlobalVariable
.ArchList
:
569 PlatformDataBase
= GenFdsGlobalVariable
.WorkSpace
.BuildObject
[GenFdsGlobalVariable
.ActivePlatform
, Arch
, GenFdsGlobalVariable
.TargetName
, GenFdsGlobalVariable
.ToolChainTag
]
570 if PlatformDataBase
!= None:
571 if InfFileKey
in PlatformDataBase
.Modules
:
572 DscArchList
.append (Arch
)
575 # BaseTools support build same module more than once, the module path with FILE_GUID overridden has
576 # the file name FILE_GUIDmodule.inf, then PlatformDataBase.Modules use FILE_GUIDmodule.inf as key,
577 # but the path (self.MetaFile.Path) is the real path
579 for key
in PlatformDataBase
.Modules
.keys():
580 if InfFileKey
== str((PlatformDataBase
.Modules
[key
]).MetaFile
.Path
):
581 DscArchList
.append (Arch
)
586 ## GetCurrentArch() method
588 # Get Arch list of the module from this INF is to be placed into flash
590 # @param self The object pointer
591 # @retval list Arch list
593 def GetCurrentArch(self
) :
595 TargetArchList
= GenFdsGlobalVariable
.ArchList
597 PlatformArchList
= self
.__GetPlatformArchList
__()
599 CurArchList
= TargetArchList
600 if PlatformArchList
!= []:
601 CurArchList
= list(set (TargetArchList
) & set (PlatformArchList
))
602 GenFdsGlobalVariable
.VerboseLogger ("Valid target architecture(s) is : " + " ".join(CurArchList
))
605 if self
.KeyStringList
!= []:
606 for Key
in self
.KeyStringList
:
607 Key
= GenFdsGlobalVariable
.MacroExtend(Key
)
608 Target
, Tag
, Arch
= Key
.split('_')
609 if Arch
in CurArchList
:
610 ArchList
.append(Arch
)
611 if Target
not in self
.TargetOverrideList
:
612 self
.TargetOverrideList
.append(Target
)
614 ArchList
= CurArchList
616 UseArchList
= TargetArchList
617 if self
.UseArch
!= None:
619 UseArchList
.append(self
.UseArch
)
620 ArchList
= list(set (UseArchList
) & set (ArchList
))
622 self
.InfFileName
= NormPath(self
.InfFileName
)
623 if len(PlatformArchList
) == 0:
625 PathClassObj
= PathClass(self
.InfFileName
, GenFdsGlobalVariable
.WorkSpaceDir
)
626 ErrorCode
, ErrorInfo
= PathClassObj
.Validate(".inf")
628 EdkLogger
.error("GenFds", ErrorCode
, ExtraData
=ErrorInfo
)
629 if len(ArchList
) == 1:
632 elif len(ArchList
) > 1:
633 if len(PlatformArchList
) == 0:
634 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
))
636 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
))
638 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." \
639 % (self
.InfFileName
, str(PlatformArchList
), GenFdsGlobalVariable
.ActivePlatform
, str(set (UseArchList
) & set (TargetArchList
))))
641 ## __GetEFIOutPutPath__() method
643 # Get the output path for generated files
645 # @param self The object pointer
646 # @retval string Path that output files from this INF go to
648 def __GetEFIOutPutPath__(self
):
651 (ModulePath
, FileName
) = os
.path
.split(self
.InfFileName
)
652 Index
= FileName
.rfind('.')
653 FileName
= FileName
[0:Index
]
654 if self
.OverrideGuid
:
655 FileName
= self
.OverrideGuid
657 if self
.CurrentArch
!= None:
658 Arch
= self
.CurrentArch
660 OutputPath
= os
.path
.join(GenFdsGlobalVariable
.OutputDirDict
[Arch
],
666 OutputPath
= os
.path
.realpath(OutputPath
)
669 ## __GenSimpleFileSection__() method
671 # Generate section by specified file name or a list of files with file extension
673 # @param self The object pointer
674 # @param Rule The rule object used to generate section
675 # @retval string File name of the generated section file
677 def __GenSimpleFileSection__(self
, Rule
):
679 # Prepare the parameter of GenSection
683 GenSecInputFile
= None
684 if Rule
.FileName
!= None:
685 GenSecInputFile
= self
.__ExtendMacro
__(Rule
.FileName
)
686 if os
.path
.isabs(GenSecInputFile
):
687 GenSecInputFile
= os
.path
.normpath(GenSecInputFile
)
689 GenSecInputFile
= os
.path
.normpath(os
.path
.join(self
.EfiOutputPath
, GenSecInputFile
))
691 FileList
, IsSect
= Section
.Section
.GetFileList(self
, '', Rule
.FileExtension
)
694 SectionType
= Rule
.SectionType
696 # Convert Fv Section Type for PI1.1 SMM driver.
698 if self
.ModuleType
== 'DXE_SMM_DRIVER' and int(self
.PiSpecVersion
, 16) >= 0x0001000A:
699 if SectionType
== 'DXE_DEPEX':
700 SectionType
= 'SMM_DEPEX'
702 # Framework SMM Driver has no SMM_DEPEX section type
704 if self
.ModuleType
== 'DXE_SMM_DRIVER' and int(self
.PiSpecVersion
, 16) < 0x0001000A:
705 if SectionType
== 'SMM_DEPEX':
706 EdkLogger
.error("GenFds", FORMAT_NOT_SUPPORTED
, "Framework SMM module doesn't support SMM_DEPEX section type", File
=self
.InfFileName
)
708 if self
.ModuleType
in ('SEC', 'PEI_CORE', 'PEIM'):
709 if self
.KeepReloc
!= None:
710 NoStrip
= self
.KeepReloc
711 elif Rule
.KeepReloc
!= None:
712 NoStrip
= Rule
.KeepReloc
713 elif self
.ShadowFromInfFile
!= None:
714 NoStrip
= self
.ShadowFromInfFile
717 for File
in FileList
:
720 GenSecOutputFile
= self
.__ExtendMacro
__(Rule
.NameGuid
) + \
721 Ffs
.Ffs
.SectionSuffix
[SectionType
] + 'SEC' + SecNum
723 OutputFile
= os
.path
.join(self
.OutputPath
, GenSecOutputFile
)
724 File
= GenFdsGlobalVariable
.MacroExtend(File
, Dict
, self
.CurrentArch
)
726 #Get PE Section alignment when align is set to AUTO
727 if self
.Alignment
== 'Auto' and (SectionType
== 'PE32' or SectionType
== 'TE'):
728 ImageObj
= PeImageClass (File
)
729 if ImageObj
.SectionAlignment
< 0x400:
730 self
.Alignment
= str (ImageObj
.SectionAlignment
)
732 self
.Alignment
= str (ImageObj
.SectionAlignment
/ 0x400) + 'K'
735 FileBeforeStrip
= os
.path
.join(self
.OutputPath
, ModuleName
+ '.reloc')
736 if not os
.path
.exists(FileBeforeStrip
) or \
737 (os
.path
.getmtime(File
) > os
.path
.getmtime(FileBeforeStrip
)):
738 CopyLongFilePath(File
, FileBeforeStrip
)
739 StrippedFile
= os
.path
.join(self
.OutputPath
, ModuleName
+ '.stipped')
740 GenFdsGlobalVariable
.GenerateFirmwareImage(
747 if SectionType
== 'TE':
748 TeFile
= os
.path
.join( self
.OutputPath
, self
.ModuleGuid
+ 'Te.raw')
749 GenFdsGlobalVariable
.GenerateFirmwareImage(
756 GenFdsGlobalVariable
.GenerateSection(OutputFile
, [File
], Section
.Section
.SectionType
[SectionType
])
757 OutputFileList
.append(OutputFile
)
760 GenSecOutputFile
= self
.__ExtendMacro
__(Rule
.NameGuid
) + \
761 Ffs
.Ffs
.SectionSuffix
[SectionType
] + 'SEC' + SecNum
762 OutputFile
= os
.path
.join(self
.OutputPath
, GenSecOutputFile
)
763 GenSecInputFile
= GenFdsGlobalVariable
.MacroExtend(GenSecInputFile
, Dict
, self
.CurrentArch
)
765 #Get PE Section alignment when align is set to AUTO
766 if self
.Alignment
== 'Auto' and (SectionType
== 'PE32' or SectionType
== 'TE'):
767 ImageObj
= PeImageClass (GenSecInputFile
)
768 if ImageObj
.SectionAlignment
< 0x400:
769 self
.Alignment
= str (ImageObj
.SectionAlignment
)
771 self
.Alignment
= str (ImageObj
.SectionAlignment
/ 0x400) + 'K'
774 FileBeforeStrip
= os
.path
.join(self
.OutputPath
, ModuleName
+ '.reloc')
775 if not os
.path
.exists(FileBeforeStrip
) or \
776 (os
.path
.getmtime(GenSecInputFile
) > os
.path
.getmtime(FileBeforeStrip
)):
777 CopyLongFilePath(GenSecInputFile
, FileBeforeStrip
)
779 StrippedFile
= os
.path
.join(self
.OutputPath
, ModuleName
+ '.stipped')
780 GenFdsGlobalVariable
.GenerateFirmwareImage(
785 GenSecInputFile
= StrippedFile
787 if SectionType
== 'TE':
788 TeFile
= os
.path
.join( self
.OutputPath
, self
.ModuleGuid
+ 'Te.raw')
789 GenFdsGlobalVariable
.GenerateFirmwareImage(
794 GenSecInputFile
= TeFile
796 GenFdsGlobalVariable
.GenerateSection(OutputFile
, [GenSecInputFile
], Section
.Section
.SectionType
[SectionType
])
797 OutputFileList
.append(OutputFile
)
799 return OutputFileList
801 ## __GenSimpleFileFfs__() method
805 # @param self The object pointer
806 # @param Rule The rule object used to generate section
807 # @param InputFileList The output file list from GenSection
808 # @retval string Generated FFS file name
810 def __GenSimpleFileFfs__(self
, Rule
, InputFileList
):
811 FfsOutput
= self
.OutputPath
+ \
813 self
.__ExtendMacro
__(Rule
.NameGuid
) + \
816 GenFdsGlobalVariable
.VerboseLogger(self
.__ExtendMacro
__(Rule
.NameGuid
))
818 SectionAlignments
= []
819 for InputFile
in InputFileList
:
820 InputSection
.append(InputFile
)
821 SectionAlignments
.append(Rule
.SectAlignment
)
823 if Rule
.NameGuid
!= None and Rule
.NameGuid
.startswith('PCD('):
824 PcdValue
= GenFdsGlobalVariable
.GetPcdValue(Rule
.NameGuid
)
825 if len(PcdValue
) == 0:
826 EdkLogger
.error("GenFds", GENFDS_ERROR
, '%s NOT defined.' \
828 if PcdValue
.startswith('{'):
829 PcdValue
= GuidStructureByteArrayToGuidString(PcdValue
)
830 RegistryGuidStr
= PcdValue
831 if len(RegistryGuidStr
) == 0:
832 EdkLogger
.error("GenFds", GENFDS_ERROR
, 'GUID value for %s in wrong format.' \
834 self
.ModuleGuid
= RegistryGuidStr
836 GenFdsGlobalVariable
.GenerateFfs(FfsOutput
, InputSection
,
837 Ffs
.Ffs
.FdfFvFileTypeToFileType
[Rule
.FvFileType
],
838 self
.ModuleGuid
, Fixed
=Rule
.Fixed
,
839 CheckSum
=Rule
.CheckSum
, Align
=Rule
.Alignment
,
840 SectionAlign
=SectionAlignments
844 ## __GenComplexFileSection__() method
846 # Generate section by sections in Rule
848 # @param self The object pointer
849 # @param Rule The rule object used to generate section
850 # @param FvChildAddr Array of the inside FvImage base address
851 # @param FvParentAddr Parent Fv base address
852 # @retval string File name of the generated section file
854 def __GenComplexFileSection__(self
, Rule
, FvChildAddr
, FvParentAddr
):
855 if self
.ModuleType
in ('SEC', 'PEI_CORE', 'PEIM'):
856 if Rule
.KeepReloc
!= None:
857 self
.KeepRelocFromRule
= Rule
.KeepReloc
861 HasGneratedFlag
= False
862 if self
.PcdIsDriver
== 'PEI_PCD_DRIVER':
863 if self
.IsBinaryModule
:
864 PcdExDbFileName
= os
.path
.join(GenFdsGlobalVariable
.FvDir
, "PEIPcdDataBase.raw")
866 PcdExDbFileName
= os
.path
.join(self
.EfiOutputPath
, "PEIPcdDataBase.raw")
867 PcdExDbSecName
= os
.path
.join(self
.OutputPath
, "PEIPcdDataBaseSec.raw")
868 GenFdsGlobalVariable
.GenerateSection(PcdExDbSecName
,
872 SectFiles
.append(PcdExDbSecName
)
873 SectAlignments
.append(None)
874 elif self
.PcdIsDriver
== 'DXE_PCD_DRIVER':
875 if self
.IsBinaryModule
:
876 PcdExDbFileName
= os
.path
.join(GenFdsGlobalVariable
.FvDir
, "DXEPcdDataBase.raw")
878 PcdExDbFileName
= os
.path
.join(self
.EfiOutputPath
, "DXEPcdDataBase.raw")
879 PcdExDbSecName
= os
.path
.join(self
.OutputPath
, "DXEPcdDataBaseSec.raw")
880 GenFdsGlobalVariable
.GenerateSection(PcdExDbSecName
,
884 SectFiles
.append(PcdExDbSecName
)
885 SectAlignments
.append(None)
886 for Sect
in Rule
.SectionList
:
887 SecIndex
= '%d' %Index
890 # Convert Fv Section Type for PI1.1 SMM driver.
892 if self
.ModuleType
== 'DXE_SMM_DRIVER' and int(self
.PiSpecVersion
, 16) >= 0x0001000A:
893 if Sect
.SectionType
== 'DXE_DEPEX':
894 Sect
.SectionType
= 'SMM_DEPEX'
896 # Framework SMM Driver has no SMM_DEPEX section type
898 if self
.ModuleType
== 'DXE_SMM_DRIVER' and int(self
.PiSpecVersion
, 16) < 0x0001000A:
899 if Sect
.SectionType
== 'SMM_DEPEX':
900 EdkLogger
.error("GenFds", FORMAT_NOT_SUPPORTED
, "Framework SMM module doesn't support SMM_DEPEX section type", File
=self
.InfFileName
)
902 # process the inside FvImage from FvSection or GuidSection
904 if FvChildAddr
!= []:
905 if isinstance(Sect
, FvImageSection
):
906 Sect
.FvAddr
= FvChildAddr
.pop(0)
907 elif isinstance(Sect
, GuidSection
):
908 Sect
.FvAddr
= FvChildAddr
909 if FvParentAddr
!= None and isinstance(Sect
, GuidSection
):
910 Sect
.FvParentAddr
= FvParentAddr
912 if Rule
.KeyStringList
!= []:
913 SectList
, Align
= Sect
.GenSection(self
.OutputPath
, self
.ModuleGuid
, SecIndex
, Rule
.KeyStringList
, self
)
915 SectList
, Align
= Sect
.GenSection(self
.OutputPath
, self
.ModuleGuid
, SecIndex
, self
.KeyStringList
, self
)
917 if not HasGneratedFlag
:
918 UniVfrOffsetFileSection
= ""
919 ModuleFileName
= mws
.join(GenFdsGlobalVariable
.WorkSpaceDir
, self
.InfFileName
)
920 InfData
= GenFdsGlobalVariable
.WorkSpace
.BuildObject
[PathClass(ModuleFileName
), self
.CurrentArch
]
922 # Search the source list in InfData to find if there are .vfr file exist.
925 VfrUniOffsetList
= []
926 for SourceFile
in InfData
.Sources
:
927 if SourceFile
.Type
.upper() == ".VFR" :
929 # search the .map file to find the offset of vfr binary in the PE32+/TE file.
931 VfrUniBaseName
[SourceFile
.BaseName
] = (SourceFile
.BaseName
+ "Bin")
932 if SourceFile
.Type
.upper() == ".UNI" :
934 # search the .map file to find the offset of Uni strings binary in the PE32+/TE file.
936 VfrUniBaseName
["UniOffsetName"] = (self
.BaseName
+ "Strings")
939 if len(VfrUniBaseName
) > 0:
940 VfrUniOffsetList
= self
.__GetBuildOutputMapFileVfrUniInfo
(VfrUniBaseName
)
942 # Generate the Raw data of raw section
944 os
.path
.join( self
.OutputPath
, self
.BaseName
+ '.offset')
945 UniVfrOffsetFileName
= os
.path
.join( self
.OutputPath
, self
.BaseName
+ '.offset')
946 UniVfrOffsetFileSection
= os
.path
.join( self
.OutputPath
, self
.BaseName
+ 'Offset' + '.raw')
948 self
.__GenUniVfrOffsetFile
(VfrUniOffsetList
, UniVfrOffsetFileName
)
950 UniVfrOffsetFileNameList
= []
951 UniVfrOffsetFileNameList
.append(UniVfrOffsetFileName
)
952 """Call GenSection"""
953 GenFdsGlobalVariable
.GenerateSection(UniVfrOffsetFileSection
,
954 UniVfrOffsetFileNameList
,
957 os
.remove(UniVfrOffsetFileName
)
958 SectList
.append(UniVfrOffsetFileSection
)
959 HasGneratedFlag
= True
961 for SecName
in SectList
:
962 SectFiles
.append(SecName
)
963 SectAlignments
.append(Align
)
965 return SectFiles
, SectAlignments
967 ## __GenComplexFileFfs__() method
971 # @param self The object pointer
972 # @param Rule The rule object used to generate section
973 # @param InputFileList The output file list from GenSection
974 # @retval string Generated FFS file name
976 def __GenComplexFileFfs__(self
, Rule
, InputFile
, Alignments
):
978 if Rule
.NameGuid
!= None and Rule
.NameGuid
.startswith('PCD('):
979 PcdValue
= GenFdsGlobalVariable
.GetPcdValue(Rule
.NameGuid
)
980 if len(PcdValue
) == 0:
981 EdkLogger
.error("GenFds", GENFDS_ERROR
, '%s NOT defined.' \
983 if PcdValue
.startswith('{'):
984 PcdValue
= GuidStructureByteArrayToGuidString(PcdValue
)
985 RegistryGuidStr
= PcdValue
986 if len(RegistryGuidStr
) == 0:
987 EdkLogger
.error("GenFds", GENFDS_ERROR
, 'GUID value for %s in wrong format.' \
989 self
.ModuleGuid
= RegistryGuidStr
991 FfsOutput
= os
.path
.join( self
.OutputPath
, self
.ModuleGuid
+ '.ffs')
992 GenFdsGlobalVariable
.GenerateFfs(FfsOutput
, InputFile
,
993 Ffs
.Ffs
.FdfFvFileTypeToFileType
[Rule
.FvFileType
],
994 self
.ModuleGuid
, Fixed
=Rule
.Fixed
,
995 CheckSum
=Rule
.CheckSum
, Align
=Rule
.Alignment
,
996 SectionAlign
=Alignments
1000 ## __GetGenFfsCmdParameter__() method
1002 # Create parameter string for GenFfs
1004 # @param self The object pointer
1005 # @param Rule The rule object used to generate section
1006 # @retval tuple (FileType, Fixed, CheckSum, Alignment)
1008 def __GetGenFfsCmdParameter__(self
, Rule
):
1010 result
+= ('-t', Ffs
.Ffs
.FdfFvFileTypeToFileType
[Rule
.FvFileType
])
1011 if Rule
.Fixed
!= False:
1013 if Rule
.CheckSum
!= False:
1016 if Rule
.Alignment
!= None and Rule
.Alignment
!= '':
1017 result
+= ('-a', Rule
.Alignment
)
1021 ## __GetBuildOutputMapFileVfrUniInfo() method
1023 # Find the offset of UNI/INF object offset in the EFI image file.
1025 # @param self The object pointer
1026 # @param VfrUniBaseName A name list contain the UNI/INF object name.
1027 # @retval RetValue A list contain offset of UNI/INF object.
1029 def __GetBuildOutputMapFileVfrUniInfo(self
, VfrUniBaseName
):
1030 MapFileName
= os
.path
.join(self
.EfiOutputPath
, self
.BaseName
+ ".map")
1031 EfiFileName
= os
.path
.join(self
.EfiOutputPath
, self
.BaseName
+ ".efi")
1032 return GetVariableOffset(MapFileName
, EfiFileName
, VfrUniBaseName
.values())
1034 ## __GenUniVfrOffsetFile() method
1036 # Generate the offset file for the module which contain VFR or UNI file.
1038 # @param self The object pointer
1039 # @param VfrUniOffsetList A list contain the VFR/UNI offsets in the EFI image file.
1040 # @param UniVfrOffsetFileName The output offset file name.
1042 def __GenUniVfrOffsetFile(self
, VfrUniOffsetList
, UniVfrOffsetFileName
):
1045 fInputfile
= open(UniVfrOffsetFileName
, "wb+", 0)
1047 EdkLogger
.error("GenFds", FILE_OPEN_FAILURE
, "File open failed for %s" %UniVfrOffsetFileName
,None)
1049 # Use a instance of StringIO to cache data
1050 fStringIO
= StringIO
.StringIO('')
1052 for Item
in VfrUniOffsetList
:
1053 if (Item
[0].find("Strings") != -1):
1055 # UNI offset in image.
1057 # { 0x8913c5e0, 0x33f6, 0x4d86, { 0x9b, 0xf1, 0x43, 0xef, 0x89, 0xfc, 0x6, 0x66 } }
1059 UniGuid
= [0xe0, 0xc5, 0x13, 0x89, 0xf6, 0x33, 0x86, 0x4d, 0x9b, 0xf1, 0x43, 0xef, 0x89, 0xfc, 0x6, 0x66]
1060 UniGuid
= [chr(ItemGuid
) for ItemGuid
in UniGuid
]
1061 fStringIO
.write(''.join(UniGuid
))
1062 UniValue
= pack ('Q', int (Item
[1], 16))
1063 fStringIO
.write (UniValue
)
1066 # VFR binary offset in image.
1068 # { 0xd0bc7cb4, 0x6a47, 0x495f, { 0xaa, 0x11, 0x71, 0x7, 0x46, 0xda, 0x6, 0xa2 } };
1070 VfrGuid
= [0xb4, 0x7c, 0xbc, 0xd0, 0x47, 0x6a, 0x5f, 0x49, 0xaa, 0x11, 0x71, 0x7, 0x46, 0xda, 0x6, 0xa2]
1071 VfrGuid
= [chr(ItemGuid
) for ItemGuid
in VfrGuid
]
1072 fStringIO
.write(''.join(VfrGuid
))
1074 VfrValue
= pack ('Q', int (Item
[1], 16))
1075 fStringIO
.write (VfrValue
)
1078 # write data into file.
1081 fInputfile
.write (fStringIO
.getvalue())
1083 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)