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 self
.ModuleType
== 'MM_CORE_STANDALONE' and int(self
.PiSpecVersion
, 16) < 0x00010032:
228 EdkLogger
.error("GenFds", FORMAT_NOT_SUPPORTED
, "MM_CORE_STANDALONE module type can't be used in the module with PI_SPECIFICATION_VERSION less than 0x00010032", File
=self
.InfFileName
)
230 if Inf
._Defs
!= None and len(Inf
._Defs
) > 0:
231 self
.OptRomDefs
.update(Inf
._Defs
)
235 Platform
= GenFdsGlobalVariable
.WorkSpace
.BuildObject
[GenFdsGlobalVariable
.ActivePlatform
, self
.CurrentArch
, GenFdsGlobalVariable
.TargetName
, GenFdsGlobalVariable
.ToolChainTag
]
236 FdfPcdDict
= GenFdsGlobalVariable
.FdfParser
.Profile
.PcdDict
238 # Workaround here: both build and GenFds tool convert the workspace path to lower case
239 # But INF file path in FDF and DSC file may have real case characters.
240 # Try to convert the path to lower case to see if PCDs value are override by DSC.
242 for DscModule
in Platform
.Modules
:
243 DscModules
[str(DscModule
).lower()] = Platform
.Modules
[DscModule
]
244 for PcdKey
in InfPcds
:
245 Pcd
= InfPcds
[PcdKey
]
246 if not hasattr(Pcd
, 'Offset'):
248 if Pcd
.Type
!= 'PatchableInModule':
250 # Override Patchable PCD value by the value from DSC
252 if InfLowerPath
in DscModules
and PcdKey
in DscModules
[InfLowerPath
].Pcds
:
253 PatchPcd
= DscModules
[InfLowerPath
].Pcds
[PcdKey
]
254 elif PcdKey
in Platform
.Pcds
:
255 PatchPcd
= Platform
.Pcds
[PcdKey
]
257 if PatchPcd
and Pcd
.Type
== PatchPcd
.Type
:
258 DefaultValue
= PatchPcd
.DefaultValue
261 # Override Patchable PCD value by the value from FDF
263 if PcdKey
in FdfPcdDict
:
264 DefaultValue
= FdfPcdDict
[PcdKey
]
267 # Override Patchable PCD value by the value from Build Option
268 BuildOptionOverride
= False
269 if GlobalData
.BuildOptionPcd
:
270 for pcd
in GlobalData
.BuildOptionPcd
:
271 if PcdKey
== (pcd
[1], pcd
[0]):
272 DefaultValue
= pcd
[2]
273 BuildOptionOverride
= True
276 if not DscOverride
and not FdfOverride
and not BuildOptionOverride
:
278 # Check value, if value are equal, no need to patch
279 if Pcd
.DatumType
== "VOID*":
280 if Pcd
.DefaultValue
== DefaultValue
or DefaultValue
in [None, '']:
282 # Get the string size from FDF or DSC
283 if DefaultValue
[0] == 'L':
284 # Remove L"", but the '\0' must be appended
285 MaxDatumSize
= str((len(DefaultValue
) - 2) * 2)
286 elif DefaultValue
[0] == '{':
287 MaxDatumSize
= str(len(DefaultValue
.split(',')))
289 MaxDatumSize
= str(len(DefaultValue
) - 1)
291 Pcd
.MaxDatumSize
= PatchPcd
.MaxDatumSize
292 # If no defined the maximum size in DSC, try to get current size from INF
293 if Pcd
.MaxDatumSize
in ['', None]:
294 Pcd
.MaxDatumSize
= str(len(Pcd
.DefaultValue
.split(',')))
297 if Pcd
.DefaultValue
.upper().startswith('0X'):
299 if DefaultValue
.upper().startswith('0X'):
302 PcdValueInImg
= int(Pcd
.DefaultValue
, Base1
)
303 PcdValueInDscOrFdf
= int(DefaultValue
, Base2
)
304 if PcdValueInImg
== PcdValueInDscOrFdf
:
308 # Check the Pcd size and data type
309 if Pcd
.DatumType
== "VOID*":
310 if int(MaxDatumSize
) > int(Pcd
.MaxDatumSize
):
311 EdkLogger
.error("GenFds", GENFDS_ERROR
, "The size of VOID* type PCD '%s.%s' exceeds its maximum size %d bytes." \
312 % (Pcd
.TokenSpaceGuidCName
, Pcd
.TokenCName
, int(MaxDatumSize
) - int(Pcd
.MaxDatumSize
)))
314 if PcdValueInDscOrFdf
> FfsInfStatement
._MAX
_SIZE
_TYPE
[Pcd
.DatumType
] \
315 or PcdValueInImg
> FfsInfStatement
._MAX
_SIZE
_TYPE
[Pcd
.DatumType
]:
316 EdkLogger
.error("GenFds", GENFDS_ERROR
, "The size of %s type PCD '%s.%s' doesn't match its data type." \
317 % (Pcd
.DatumType
, Pcd
.TokenSpaceGuidCName
, Pcd
.TokenCName
))
318 self
.PatchPcds
.append((Pcd
, DefaultValue
))
321 self
.PcdIsDriver
= Inf
.PcdIsDriver
322 self
.IsBinaryModule
= Inf
.IsBinaryModule
323 GenFdsGlobalVariable
.VerboseLogger("BaseName : %s" % self
.BaseName
)
324 GenFdsGlobalVariable
.VerboseLogger("ModuleGuid : %s" % self
.ModuleGuid
)
325 GenFdsGlobalVariable
.VerboseLogger("ModuleType : %s" % self
.ModuleType
)
326 GenFdsGlobalVariable
.VerboseLogger("VersionString : %s" % self
.VersionString
)
327 GenFdsGlobalVariable
.VerboseLogger("InfFileName :%s" % self
.InfFileName
)
330 # Set OutputPath = ${WorkSpace}\Build\Fv\Ffs\${ModuleGuid}+ ${MdouleName}\
333 self
.OutputPath
= os
.path
.join(GenFdsGlobalVariable
.FfsDir
, \
334 self
.ModuleGuid
+ self
.BaseName
)
335 if not os
.path
.exists(self
.OutputPath
) :
336 os
.makedirs(self
.OutputPath
)
338 self
.EfiOutputPath
= self
.__GetEFIOutPutPath
__()
339 GenFdsGlobalVariable
.VerboseLogger( "ModuelEFIPath: " + self
.EfiOutputPath
)
343 # Patch EFI file with patch PCD
345 # @param EfiFile: EFI file needs to be patched.
346 # @retval: Full path of patched EFI file: self.OutputPath + EfiFile base name
347 # If passed in file does not end with efi, return as is
349 def PatchEfiFile(self
, EfiFile
, FileType
):
351 # If the module does not have any patches, then return path to input file
353 if not self
.PatchPcds
:
357 # Only patch file if FileType is PE32 or ModuleType is USER_DEFINED
359 if FileType
!= 'PE32' and self
.ModuleType
!= "USER_DEFINED":
363 # Generate path to patched output file
365 Basename
= os
.path
.basename(EfiFile
)
366 Output
= os
.path
.normpath (os
.path
.join(self
.OutputPath
, Basename
))
369 # If this file has already been patched, then return the path to the patched file
371 if self
.PatchedBinFile
== Output
:
375 # If a different file from the same module has already been patched, then generate an error
377 if self
.PatchedBinFile
:
378 EdkLogger
.error("GenFds", GENFDS_ERROR
,
379 'Only one binary file can be patched:\n'
380 ' a binary file has been patched: %s\n'
381 ' current file: %s' % (self
.PatchedBinFile
, EfiFile
),
382 File
=self
.InfFileName
)
385 # Copy unpatched file contents to output file location to perform patching
387 CopyLongFilePath(EfiFile
, Output
)
390 # Apply patches to patched output file
392 for Pcd
, Value
in self
.PatchPcds
:
393 RetVal
, RetStr
= PatchBinaryFile(Output
, int(Pcd
.Offset
, 0), Pcd
.DatumType
, Value
, Pcd
.MaxDatumSize
)
395 EdkLogger
.error("GenFds", GENFDS_ERROR
, RetStr
, File
=self
.InfFileName
)
398 # Save the path of the patched output file
400 self
.PatchedBinFile
= Output
403 # Return path to patched output file
411 # @param self The object pointer
412 # @param Dict dictionary contains macro and value pair
413 # @param FvChildAddr Array of the inside FvImage base address
414 # @param FvParentAddr Parent Fv base address
415 # @retval string Generated FFS file name
417 def GenFfs(self
, Dict
= {}, FvChildAddr
= [], FvParentAddr
=None):
419 # Parse Inf file get Module related information
422 self
.__InfParse
__(Dict
)
423 SrcFile
= mws
.join( GenFdsGlobalVariable
.WorkSpaceDir
, self
.InfFileName
);
424 DestFile
= os
.path
.join( self
.OutputPath
, self
.ModuleGuid
+ '.ffs')
427 SrcPath
= os
.path
.dirname(SrcFile
)
428 SrcFileName
= os
.path
.basename(SrcFile
)
429 SrcFileBase
, SrcFileExt
= os
.path
.splitext(SrcFileName
)
430 DestPath
= os
.path
.dirname(DestFile
)
431 DestFileName
= os
.path
.basename(DestFile
)
432 DestFileBase
, DestFileExt
= os
.path
.splitext(DestFileName
)
436 "${s_path}" : SrcPath
,
437 "${s_dir}" : SrcFileDir
,
438 "${s_name}" : SrcFileName
,
439 "${s_base}" : SrcFileBase
,
440 "${s_ext}" : SrcFileExt
,
443 "${d_path}" : DestPath
,
444 "${d_name}" : DestFileName
,
445 "${d_base}" : DestFileBase
,
446 "${d_ext}" : DestFileExt
449 # Allow binary type module not specify override rule in FDF file.
451 if len(self
.BinFileList
) > 0:
452 if self
.Rule
== None or self
.Rule
== "":
456 # Get the rule of how to generate Ffs file
458 Rule
= self
.__GetRule
__()
459 GenFdsGlobalVariable
.VerboseLogger( "Packing binaries from inf file : %s" %self
.InfFileName
)
461 # Convert Fv File Type for PI1.1 SMM driver.
463 if self
.ModuleType
== 'DXE_SMM_DRIVER' and int(self
.PiSpecVersion
, 16) >= 0x0001000A:
464 if Rule
.FvFileType
== 'DRIVER':
465 Rule
.FvFileType
= 'SMM'
467 # Framework SMM Driver has no SMM FV file type
469 if self
.ModuleType
== 'DXE_SMM_DRIVER' and int(self
.PiSpecVersion
, 16) < 0x0001000A:
470 if Rule
.FvFileType
== 'SMM' or Rule
.FvFileType
== 'SMM_CORE':
471 EdkLogger
.error("GenFds", FORMAT_NOT_SUPPORTED
, "Framework SMM module doesn't support SMM or SMM_CORE FV file type", File
=self
.InfFileName
)
473 # For the rule only has simpleFile
475 if isinstance (Rule
, RuleSimpleFile
.RuleSimpleFile
) :
476 SectionOutputList
= self
.__GenSimpleFileSection
__(Rule
)
477 FfsOutput
= self
.__GenSimpleFileFfs
__(Rule
, SectionOutputList
)
480 # For Rule has ComplexFile
482 elif isinstance(Rule
, RuleComplexFile
.RuleComplexFile
):
483 InputSectList
, InputSectAlignments
= self
.__GenComplexFileSection
__(Rule
, FvChildAddr
, FvParentAddr
)
484 FfsOutput
= self
.__GenComplexFileFfs
__(Rule
, InputSectList
, InputSectAlignments
)
488 ## __ExtendMacro__() method
490 # Replace macro with its value
492 # @param self The object pointer
493 # @param String The string to be replaced
494 # @retval string Macro replaced string
496 def __ExtendMacro__ (self
, String
):
498 '$(INF_OUTPUT)' : self
.EfiOutputPath
,
499 '$(MODULE_NAME)' : self
.BaseName
,
500 '$(BUILD_NUMBER)': self
.BuildNum
,
501 '$(INF_VERSION)' : self
.VersionString
,
502 '$(NAMED_GUID)' : self
.ModuleGuid
504 String
= GenFdsGlobalVariable
.MacroExtend(String
, MacroDict
)
505 String
= GenFdsGlobalVariable
.MacroExtend(String
, self
.MacroDict
)
508 ## __GetRule__() method
510 # Get correct rule for generating FFS for this INF
512 # @param self The object pointer
513 # @retval Rule Rule object
515 def __GetRule__ (self
) :
517 if self
.CurrentArch
== None:
518 CurrentArchList
= ['common']
520 CurrentArchList
.append(self
.CurrentArch
)
522 for CurrentArch
in CurrentArchList
:
523 RuleName
= 'RULE' + \
525 CurrentArch
.upper() + \
527 self
.ModuleType
.upper()
528 if self
.Rule
!= None:
529 RuleName
= RuleName
+ \
533 Rule
= GenFdsGlobalVariable
.FdfParser
.Profile
.RuleDict
.get(RuleName
)
535 GenFdsGlobalVariable
.VerboseLogger ("Want To Find Rule Name is : " + RuleName
)
538 RuleName
= 'RULE' + \
542 self
.ModuleType
.upper()
544 if self
.Rule
!= None:
545 RuleName
= RuleName
+ \
549 GenFdsGlobalVariable
.VerboseLogger ('Trying to apply common rule %s for INF %s' % (RuleName
, self
.InfFileName
))
551 Rule
= GenFdsGlobalVariable
.FdfParser
.Profile
.RuleDict
.get(RuleName
)
553 GenFdsGlobalVariable
.VerboseLogger ("Want To Find Rule Name is : " + RuleName
)
557 EdkLogger
.error("GenFds", GENFDS_ERROR
, 'Don\'t Find common rule %s for INF %s' \
558 % (RuleName
, self
.InfFileName
))
560 ## __GetPlatformArchList__() method
562 # Get Arch list this INF built under
564 # @param self The object pointer
565 # @retval list Arch list
567 def __GetPlatformArchList__(self
):
569 InfFileKey
= os
.path
.normpath(mws
.join(GenFdsGlobalVariable
.WorkSpaceDir
, self
.InfFileName
))
571 for Arch
in GenFdsGlobalVariable
.ArchList
:
572 PlatformDataBase
= GenFdsGlobalVariable
.WorkSpace
.BuildObject
[GenFdsGlobalVariable
.ActivePlatform
, Arch
, GenFdsGlobalVariable
.TargetName
, GenFdsGlobalVariable
.ToolChainTag
]
573 if PlatformDataBase
!= None:
574 if InfFileKey
in PlatformDataBase
.Modules
:
575 DscArchList
.append (Arch
)
578 # BaseTools support build same module more than once, the module path with FILE_GUID overridden has
579 # the file name FILE_GUIDmodule.inf, then PlatformDataBase.Modules use FILE_GUIDmodule.inf as key,
580 # but the path (self.MetaFile.Path) is the real path
582 for key
in PlatformDataBase
.Modules
.keys():
583 if InfFileKey
== str((PlatformDataBase
.Modules
[key
]).MetaFile
.Path
):
584 DscArchList
.append (Arch
)
589 ## GetCurrentArch() method
591 # Get Arch list of the module from this INF is to be placed into flash
593 # @param self The object pointer
594 # @retval list Arch list
596 def GetCurrentArch(self
) :
598 TargetArchList
= GenFdsGlobalVariable
.ArchList
600 PlatformArchList
= self
.__GetPlatformArchList
__()
602 CurArchList
= TargetArchList
603 if PlatformArchList
!= []:
604 CurArchList
= list(set (TargetArchList
) & set (PlatformArchList
))
605 GenFdsGlobalVariable
.VerboseLogger ("Valid target architecture(s) is : " + " ".join(CurArchList
))
608 if self
.KeyStringList
!= []:
609 for Key
in self
.KeyStringList
:
610 Key
= GenFdsGlobalVariable
.MacroExtend(Key
)
611 Target
, Tag
, Arch
= Key
.split('_')
612 if Arch
in CurArchList
:
613 ArchList
.append(Arch
)
614 if Target
not in self
.TargetOverrideList
:
615 self
.TargetOverrideList
.append(Target
)
617 ArchList
= CurArchList
619 UseArchList
= TargetArchList
620 if self
.UseArch
!= None:
622 UseArchList
.append(self
.UseArch
)
623 ArchList
= list(set (UseArchList
) & set (ArchList
))
625 self
.InfFileName
= NormPath(self
.InfFileName
)
626 if len(PlatformArchList
) == 0:
628 PathClassObj
= PathClass(self
.InfFileName
, GenFdsGlobalVariable
.WorkSpaceDir
)
629 ErrorCode
, ErrorInfo
= PathClassObj
.Validate(".inf")
631 EdkLogger
.error("GenFds", ErrorCode
, ExtraData
=ErrorInfo
)
632 if len(ArchList
) == 1:
635 elif len(ArchList
) > 1:
636 if len(PlatformArchList
) == 0:
637 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
))
639 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
))
641 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." \
642 % (self
.InfFileName
, str(PlatformArchList
), GenFdsGlobalVariable
.ActivePlatform
, str(set (UseArchList
) & set (TargetArchList
))))
644 ## __GetEFIOutPutPath__() method
646 # Get the output path for generated files
648 # @param self The object pointer
649 # @retval string Path that output files from this INF go to
651 def __GetEFIOutPutPath__(self
):
654 (ModulePath
, FileName
) = os
.path
.split(self
.InfFileName
)
655 Index
= FileName
.rfind('.')
656 FileName
= FileName
[0:Index
]
657 if self
.OverrideGuid
:
658 FileName
= self
.OverrideGuid
660 if self
.CurrentArch
!= None:
661 Arch
= self
.CurrentArch
663 OutputPath
= os
.path
.join(GenFdsGlobalVariable
.OutputDirDict
[Arch
],
669 OutputPath
= os
.path
.realpath(OutputPath
)
672 ## __GenSimpleFileSection__() method
674 # Generate section by specified file name or a list of files with file extension
676 # @param self The object pointer
677 # @param Rule The rule object used to generate section
678 # @retval string File name of the generated section file
680 def __GenSimpleFileSection__(self
, Rule
):
682 # Prepare the parameter of GenSection
686 GenSecInputFile
= None
687 if Rule
.FileName
!= None:
688 GenSecInputFile
= self
.__ExtendMacro
__(Rule
.FileName
)
689 if os
.path
.isabs(GenSecInputFile
):
690 GenSecInputFile
= os
.path
.normpath(GenSecInputFile
)
692 GenSecInputFile
= os
.path
.normpath(os
.path
.join(self
.EfiOutputPath
, GenSecInputFile
))
694 FileList
, IsSect
= Section
.Section
.GetFileList(self
, '', Rule
.FileExtension
)
697 SectionType
= Rule
.SectionType
699 # Convert Fv Section Type for PI1.1 SMM driver.
701 if self
.ModuleType
== 'DXE_SMM_DRIVER' and int(self
.PiSpecVersion
, 16) >= 0x0001000A:
702 if SectionType
== 'DXE_DEPEX':
703 SectionType
= 'SMM_DEPEX'
705 # Framework SMM Driver has no SMM_DEPEX section type
707 if self
.ModuleType
== 'DXE_SMM_DRIVER' and int(self
.PiSpecVersion
, 16) < 0x0001000A:
708 if SectionType
== 'SMM_DEPEX':
709 EdkLogger
.error("GenFds", FORMAT_NOT_SUPPORTED
, "Framework SMM module doesn't support SMM_DEPEX section type", File
=self
.InfFileName
)
711 if self
.ModuleType
in ('SEC', 'PEI_CORE', 'PEIM'):
712 if self
.KeepReloc
!= None:
713 NoStrip
= self
.KeepReloc
714 elif Rule
.KeepReloc
!= None:
715 NoStrip
= Rule
.KeepReloc
716 elif self
.ShadowFromInfFile
!= None:
717 NoStrip
= self
.ShadowFromInfFile
720 for File
in FileList
:
723 GenSecOutputFile
= self
.__ExtendMacro
__(Rule
.NameGuid
) + \
724 Ffs
.Ffs
.SectionSuffix
[SectionType
] + 'SEC' + SecNum
726 OutputFile
= os
.path
.join(self
.OutputPath
, GenSecOutputFile
)
727 File
= GenFdsGlobalVariable
.MacroExtend(File
, Dict
, self
.CurrentArch
)
729 #Get PE Section alignment when align is set to AUTO
730 if self
.Alignment
== 'Auto' and (SectionType
== 'PE32' or SectionType
== 'TE'):
731 ImageObj
= PeImageClass (File
)
732 if ImageObj
.SectionAlignment
< 0x400:
733 self
.Alignment
= str (ImageObj
.SectionAlignment
)
735 self
.Alignment
= str (ImageObj
.SectionAlignment
/ 0x400) + 'K'
738 FileBeforeStrip
= os
.path
.join(self
.OutputPath
, ModuleName
+ '.reloc')
739 if not os
.path
.exists(FileBeforeStrip
) or \
740 (os
.path
.getmtime(File
) > os
.path
.getmtime(FileBeforeStrip
)):
741 CopyLongFilePath(File
, FileBeforeStrip
)
742 StrippedFile
= os
.path
.join(self
.OutputPath
, ModuleName
+ '.stipped')
743 GenFdsGlobalVariable
.GenerateFirmwareImage(
750 if SectionType
== 'TE':
751 TeFile
= os
.path
.join( self
.OutputPath
, self
.ModuleGuid
+ 'Te.raw')
752 GenFdsGlobalVariable
.GenerateFirmwareImage(
759 GenFdsGlobalVariable
.GenerateSection(OutputFile
, [File
], Section
.Section
.SectionType
[SectionType
])
760 OutputFileList
.append(OutputFile
)
763 GenSecOutputFile
= self
.__ExtendMacro
__(Rule
.NameGuid
) + \
764 Ffs
.Ffs
.SectionSuffix
[SectionType
] + 'SEC' + SecNum
765 OutputFile
= os
.path
.join(self
.OutputPath
, GenSecOutputFile
)
766 GenSecInputFile
= GenFdsGlobalVariable
.MacroExtend(GenSecInputFile
, Dict
, self
.CurrentArch
)
768 #Get PE Section alignment when align is set to AUTO
769 if self
.Alignment
== 'Auto' and (SectionType
== 'PE32' or SectionType
== 'TE'):
770 ImageObj
= PeImageClass (GenSecInputFile
)
771 if ImageObj
.SectionAlignment
< 0x400:
772 self
.Alignment
= str (ImageObj
.SectionAlignment
)
774 self
.Alignment
= str (ImageObj
.SectionAlignment
/ 0x400) + 'K'
777 FileBeforeStrip
= os
.path
.join(self
.OutputPath
, ModuleName
+ '.reloc')
778 if not os
.path
.exists(FileBeforeStrip
) or \
779 (os
.path
.getmtime(GenSecInputFile
) > os
.path
.getmtime(FileBeforeStrip
)):
780 CopyLongFilePath(GenSecInputFile
, FileBeforeStrip
)
782 StrippedFile
= os
.path
.join(self
.OutputPath
, ModuleName
+ '.stipped')
783 GenFdsGlobalVariable
.GenerateFirmwareImage(
788 GenSecInputFile
= StrippedFile
790 if SectionType
== 'TE':
791 TeFile
= os
.path
.join( self
.OutputPath
, self
.ModuleGuid
+ 'Te.raw')
792 GenFdsGlobalVariable
.GenerateFirmwareImage(
797 GenSecInputFile
= TeFile
799 GenFdsGlobalVariable
.GenerateSection(OutputFile
, [GenSecInputFile
], Section
.Section
.SectionType
[SectionType
])
800 OutputFileList
.append(OutputFile
)
802 return OutputFileList
804 ## __GenSimpleFileFfs__() method
808 # @param self The object pointer
809 # @param Rule The rule object used to generate section
810 # @param InputFileList The output file list from GenSection
811 # @retval string Generated FFS file name
813 def __GenSimpleFileFfs__(self
, Rule
, InputFileList
):
814 FfsOutput
= self
.OutputPath
+ \
816 self
.__ExtendMacro
__(Rule
.NameGuid
) + \
819 GenFdsGlobalVariable
.VerboseLogger(self
.__ExtendMacro
__(Rule
.NameGuid
))
821 SectionAlignments
= []
822 for InputFile
in InputFileList
:
823 InputSection
.append(InputFile
)
824 SectionAlignments
.append(Rule
.SectAlignment
)
826 if Rule
.NameGuid
!= None and Rule
.NameGuid
.startswith('PCD('):
827 PcdValue
= GenFdsGlobalVariable
.GetPcdValue(Rule
.NameGuid
)
828 if len(PcdValue
) == 0:
829 EdkLogger
.error("GenFds", GENFDS_ERROR
, '%s NOT defined.' \
831 if PcdValue
.startswith('{'):
832 PcdValue
= GuidStructureByteArrayToGuidString(PcdValue
)
833 RegistryGuidStr
= PcdValue
834 if len(RegistryGuidStr
) == 0:
835 EdkLogger
.error("GenFds", GENFDS_ERROR
, 'GUID value for %s in wrong format.' \
837 self
.ModuleGuid
= RegistryGuidStr
839 GenFdsGlobalVariable
.GenerateFfs(FfsOutput
, InputSection
,
840 Ffs
.Ffs
.FdfFvFileTypeToFileType
[Rule
.FvFileType
],
841 self
.ModuleGuid
, Fixed
=Rule
.Fixed
,
842 CheckSum
=Rule
.CheckSum
, Align
=Rule
.Alignment
,
843 SectionAlign
=SectionAlignments
847 ## __GenComplexFileSection__() method
849 # Generate section by sections in Rule
851 # @param self The object pointer
852 # @param Rule The rule object used to generate section
853 # @param FvChildAddr Array of the inside FvImage base address
854 # @param FvParentAddr Parent Fv base address
855 # @retval string File name of the generated section file
857 def __GenComplexFileSection__(self
, Rule
, FvChildAddr
, FvParentAddr
):
858 if self
.ModuleType
in ('SEC', 'PEI_CORE', 'PEIM'):
859 if Rule
.KeepReloc
!= None:
860 self
.KeepRelocFromRule
= Rule
.KeepReloc
864 HasGneratedFlag
= False
865 if self
.PcdIsDriver
== 'PEI_PCD_DRIVER':
866 if self
.IsBinaryModule
:
867 PcdExDbFileName
= os
.path
.join(GenFdsGlobalVariable
.FvDir
, "PEIPcdDataBase.raw")
869 PcdExDbFileName
= os
.path
.join(self
.EfiOutputPath
, "PEIPcdDataBase.raw")
870 PcdExDbSecName
= os
.path
.join(self
.OutputPath
, "PEIPcdDataBaseSec.raw")
871 GenFdsGlobalVariable
.GenerateSection(PcdExDbSecName
,
875 SectFiles
.append(PcdExDbSecName
)
876 SectAlignments
.append(None)
877 elif self
.PcdIsDriver
== 'DXE_PCD_DRIVER':
878 if self
.IsBinaryModule
:
879 PcdExDbFileName
= os
.path
.join(GenFdsGlobalVariable
.FvDir
, "DXEPcdDataBase.raw")
881 PcdExDbFileName
= os
.path
.join(self
.EfiOutputPath
, "DXEPcdDataBase.raw")
882 PcdExDbSecName
= os
.path
.join(self
.OutputPath
, "DXEPcdDataBaseSec.raw")
883 GenFdsGlobalVariable
.GenerateSection(PcdExDbSecName
,
887 SectFiles
.append(PcdExDbSecName
)
888 SectAlignments
.append(None)
889 for Sect
in Rule
.SectionList
:
890 SecIndex
= '%d' %Index
893 # Convert Fv Section Type for PI1.1 SMM driver.
895 if self
.ModuleType
== 'DXE_SMM_DRIVER' and int(self
.PiSpecVersion
, 16) >= 0x0001000A:
896 if Sect
.SectionType
== 'DXE_DEPEX':
897 Sect
.SectionType
= 'SMM_DEPEX'
899 # Framework SMM Driver has no SMM_DEPEX section type
901 if self
.ModuleType
== 'DXE_SMM_DRIVER' and int(self
.PiSpecVersion
, 16) < 0x0001000A:
902 if Sect
.SectionType
== 'SMM_DEPEX':
903 EdkLogger
.error("GenFds", FORMAT_NOT_SUPPORTED
, "Framework SMM module doesn't support SMM_DEPEX section type", File
=self
.InfFileName
)
905 # process the inside FvImage from FvSection or GuidSection
907 if FvChildAddr
!= []:
908 if isinstance(Sect
, FvImageSection
):
909 Sect
.FvAddr
= FvChildAddr
.pop(0)
910 elif isinstance(Sect
, GuidSection
):
911 Sect
.FvAddr
= FvChildAddr
912 if FvParentAddr
!= None and isinstance(Sect
, GuidSection
):
913 Sect
.FvParentAddr
= FvParentAddr
915 if Rule
.KeyStringList
!= []:
916 SectList
, Align
= Sect
.GenSection(self
.OutputPath
, self
.ModuleGuid
, SecIndex
, Rule
.KeyStringList
, self
)
918 SectList
, Align
= Sect
.GenSection(self
.OutputPath
, self
.ModuleGuid
, SecIndex
, self
.KeyStringList
, self
)
920 if not HasGneratedFlag
:
921 UniVfrOffsetFileSection
= ""
922 ModuleFileName
= mws
.join(GenFdsGlobalVariable
.WorkSpaceDir
, self
.InfFileName
)
923 InfData
= GenFdsGlobalVariable
.WorkSpace
.BuildObject
[PathClass(ModuleFileName
), self
.CurrentArch
]
925 # Search the source list in InfData to find if there are .vfr file exist.
928 VfrUniOffsetList
= []
929 for SourceFile
in InfData
.Sources
:
930 if SourceFile
.Type
.upper() == ".VFR" :
932 # search the .map file to find the offset of vfr binary in the PE32+/TE file.
934 VfrUniBaseName
[SourceFile
.BaseName
] = (SourceFile
.BaseName
+ "Bin")
935 if SourceFile
.Type
.upper() == ".UNI" :
937 # search the .map file to find the offset of Uni strings binary in the PE32+/TE file.
939 VfrUniBaseName
["UniOffsetName"] = (self
.BaseName
+ "Strings")
942 if len(VfrUniBaseName
) > 0:
943 VfrUniOffsetList
= self
.__GetBuildOutputMapFileVfrUniInfo
(VfrUniBaseName
)
945 # Generate the Raw data of raw section
948 os
.path
.join( self
.OutputPath
, self
.BaseName
+ '.offset')
949 UniVfrOffsetFileName
= os
.path
.join( self
.OutputPath
, self
.BaseName
+ '.offset')
950 UniVfrOffsetFileSection
= os
.path
.join( self
.OutputPath
, self
.BaseName
+ 'Offset' + '.raw')
952 self
.__GenUniVfrOffsetFile
(VfrUniOffsetList
, UniVfrOffsetFileName
)
954 UniVfrOffsetFileNameList
= []
955 UniVfrOffsetFileNameList
.append(UniVfrOffsetFileName
)
956 """Call GenSection"""
957 GenFdsGlobalVariable
.GenerateSection(UniVfrOffsetFileSection
,
958 UniVfrOffsetFileNameList
,
961 os
.remove(UniVfrOffsetFileName
)
962 SectList
.append(UniVfrOffsetFileSection
)
963 HasGneratedFlag
= True
965 for SecName
in SectList
:
966 SectFiles
.append(SecName
)
967 SectAlignments
.append(Align
)
969 return SectFiles
, SectAlignments
971 ## __GenComplexFileFfs__() method
975 # @param self The object pointer
976 # @param Rule The rule object used to generate section
977 # @param InputFileList The output file list from GenSection
978 # @retval string Generated FFS file name
980 def __GenComplexFileFfs__(self
, Rule
, InputFile
, Alignments
):
982 if Rule
.NameGuid
!= None and Rule
.NameGuid
.startswith('PCD('):
983 PcdValue
= GenFdsGlobalVariable
.GetPcdValue(Rule
.NameGuid
)
984 if len(PcdValue
) == 0:
985 EdkLogger
.error("GenFds", GENFDS_ERROR
, '%s NOT defined.' \
987 if PcdValue
.startswith('{'):
988 PcdValue
= GuidStructureByteArrayToGuidString(PcdValue
)
989 RegistryGuidStr
= PcdValue
990 if len(RegistryGuidStr
) == 0:
991 EdkLogger
.error("GenFds", GENFDS_ERROR
, 'GUID value for %s in wrong format.' \
993 self
.ModuleGuid
= RegistryGuidStr
995 FfsOutput
= os
.path
.join( self
.OutputPath
, self
.ModuleGuid
+ '.ffs')
996 GenFdsGlobalVariable
.GenerateFfs(FfsOutput
, InputFile
,
997 Ffs
.Ffs
.FdfFvFileTypeToFileType
[Rule
.FvFileType
],
998 self
.ModuleGuid
, Fixed
=Rule
.Fixed
,
999 CheckSum
=Rule
.CheckSum
, Align
=Rule
.Alignment
,
1000 SectionAlign
=Alignments
1004 ## __GetGenFfsCmdParameter__() method
1006 # Create parameter string for GenFfs
1008 # @param self The object pointer
1009 # @param Rule The rule object used to generate section
1010 # @retval tuple (FileType, Fixed, CheckSum, Alignment)
1012 def __GetGenFfsCmdParameter__(self
, Rule
):
1014 result
+= ('-t', Ffs
.Ffs
.FdfFvFileTypeToFileType
[Rule
.FvFileType
])
1015 if Rule
.Fixed
!= False:
1017 if Rule
.CheckSum
!= False:
1020 if Rule
.Alignment
!= None and Rule
.Alignment
!= '':
1021 result
+= ('-a', Rule
.Alignment
)
1025 ## __GetBuildOutputMapFileVfrUniInfo() method
1027 # Find the offset of UNI/INF object offset in the EFI image file.
1029 # @param self The object pointer
1030 # @param VfrUniBaseName A name list contain the UNI/INF object name.
1031 # @retval RetValue A list contain offset of UNI/INF object.
1033 def __GetBuildOutputMapFileVfrUniInfo(self
, VfrUniBaseName
):
1034 MapFileName
= os
.path
.join(self
.EfiOutputPath
, self
.BaseName
+ ".map")
1035 EfiFileName
= os
.path
.join(self
.EfiOutputPath
, self
.BaseName
+ ".efi")
1036 return GetVariableOffset(MapFileName
, EfiFileName
, VfrUniBaseName
.values())
1038 ## __GenUniVfrOffsetFile() method
1040 # Generate the offset file for the module which contain VFR or UNI file.
1042 # @param self The object pointer
1043 # @param VfrUniOffsetList A list contain the VFR/UNI offsets in the EFI image file.
1044 # @param UniVfrOffsetFileName The output offset file name.
1046 def __GenUniVfrOffsetFile(self
, VfrUniOffsetList
, UniVfrOffsetFileName
):
1049 fInputfile
= open(UniVfrOffsetFileName
, "wb+", 0)
1051 EdkLogger
.error("GenFds", FILE_OPEN_FAILURE
, "File open failed for %s" %UniVfrOffsetFileName
,None)
1053 # Use a instance of StringIO to cache data
1054 fStringIO
= StringIO
.StringIO('')
1056 for Item
in VfrUniOffsetList
:
1057 if (Item
[0].find("Strings") != -1):
1059 # UNI offset in image.
1061 # { 0x8913c5e0, 0x33f6, 0x4d86, { 0x9b, 0xf1, 0x43, 0xef, 0x89, 0xfc, 0x6, 0x66 } }
1063 UniGuid
= [0xe0, 0xc5, 0x13, 0x89, 0xf6, 0x33, 0x86, 0x4d, 0x9b, 0xf1, 0x43, 0xef, 0x89, 0xfc, 0x6, 0x66]
1064 UniGuid
= [chr(ItemGuid
) for ItemGuid
in UniGuid
]
1065 fStringIO
.write(''.join(UniGuid
))
1066 UniValue
= pack ('Q', int (Item
[1], 16))
1067 fStringIO
.write (UniValue
)
1070 # VFR binary offset in image.
1072 # { 0xd0bc7cb4, 0x6a47, 0x495f, { 0xaa, 0x11, 0x71, 0x7, 0x46, 0xda, 0x6, 0xa2 } };
1074 VfrGuid
= [0xb4, 0x7c, 0xbc, 0xd0, 0x47, 0x6a, 0x5f, 0x49, 0xaa, 0x11, 0x71, 0x7, 0x46, 0xda, 0x6, 0xa2]
1075 VfrGuid
= [chr(ItemGuid
) for ItemGuid
in VfrGuid
]
1076 fStringIO
.write(''.join(VfrGuid
))
1078 VfrValue
= pack ('Q', int (Item
[1], 16))
1079 fStringIO
.write (VfrValue
)
1082 # write data into file.
1085 fInputfile
.write (fStringIO
.getvalue())
1087 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)