4 # Copyright (c) 2007 - 2017, Intel Corporation. All rights reserved.<BR>
6 # This program and the accompanying materials
7 # are licensed and made available under the terms and conditions of the BSD License
8 # which accompanies this distribution. The full text of the license may be found at
9 # http://opensource.org/licenses/bsd-license.php
11 # THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
12 # WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
18 from optparse
import OptionParser
20 import Common
.LongFilePathOs
as os
23 import Common
.BuildToolError
as BuildToolError
24 from GenFdsGlobalVariable
import GenFdsGlobalVariable
25 from Workspace
.WorkspaceDatabase
import WorkspaceDatabase
26 from Workspace
.BuildClassObject
import PcdClassObject
27 from Workspace
.BuildClassObject
import ModuleBuildClassObject
28 import RuleComplexFile
29 from EfiSection
import EfiSection
31 import Common
.TargetTxtClassObject
as TargetTxtClassObject
32 import Common
.ToolDefClassObject
as ToolDefClassObject
33 from Common
.DataType
import *
34 import Common
.GlobalData
as GlobalData
35 from Common
import EdkLogger
36 from Common
.String
import *
37 from Common
.Misc
import DirCache
, PathClass
38 from Common
.Misc
import SaveFileOnChange
39 from Common
.Misc
import ClearDuplicatedInf
40 from Common
.Misc
import GuidStructureStringToGuidString
41 from Common
.Misc
import CheckPcdDatum
42 from Common
.Misc
import BuildOptionPcdValueFormat
43 from Common
.BuildVersion
import gBUILD_VERSION
44 from Common
.MultipleWorkspace
import MultipleWorkspace
as mws
45 import FfsFileStatement
47 from struct
import unpack
49 ## Version and Copyright
50 versionNumber
= "1.0" + ' ' + gBUILD_VERSION
51 __version__
= "%prog Version " + versionNumber
52 __copyright__
= "Copyright (c) 2007 - 2017, Intel Corporation All rights reserved."
54 ## Tool entrance method
56 # This method mainly dispatch specific methods per the command line options.
57 # If no error found, return zero value so the caller of this tool can know
58 # if it's executed successfully or not.
60 # @retval 0 Tool was successful
61 # @retval 1 Tool failed
65 Options
= myOptionParser()
72 EdkLogger
.Initialize()
74 if Options
.verbose
!= None:
75 EdkLogger
.SetLevel(EdkLogger
.VERBOSE
)
76 GenFdsGlobalVariable
.VerboseMode
= True
78 if Options
.FixedAddress
!= None:
79 GenFdsGlobalVariable
.FixedLoadAddress
= True
81 if Options
.quiet
!= None:
82 EdkLogger
.SetLevel(EdkLogger
.QUIET
)
83 if Options
.debug
!= None:
84 EdkLogger
.SetLevel(Options
.debug
+ 1)
85 GenFdsGlobalVariable
.DebugLevel
= Options
.debug
87 EdkLogger
.SetLevel(EdkLogger
.INFO
)
89 if (Options
.Workspace
== None):
90 EdkLogger
.error("GenFds", OPTION_MISSING
, "WORKSPACE not defined",
91 ExtraData
="Please use '-w' switch to pass it or set the WORKSPACE environment variable.")
92 elif not os
.path
.exists(Options
.Workspace
):
93 EdkLogger
.error("GenFds", PARAMETER_INVALID
, "WORKSPACE is invalid",
94 ExtraData
="Please use '-w' switch to pass it or set the WORKSPACE environment variable.")
96 Workspace
= os
.path
.normcase(Options
.Workspace
)
97 GenFdsGlobalVariable
.WorkSpaceDir
= Workspace
98 if 'EDK_SOURCE' in os
.environ
.keys():
99 GenFdsGlobalVariable
.EdkSourceDir
= os
.path
.normcase(os
.environ
['EDK_SOURCE'])
101 GenFdsGlobalVariable
.VerboseLogger("Using Workspace:" + Workspace
)
102 if Options
.GenfdsMultiThread
:
103 GenFdsGlobalVariable
.EnableGenfdsMultiThread
= True
104 os
.chdir(GenFdsGlobalVariable
.WorkSpaceDir
)
106 # set multiple workspace
107 PackagesPath
= os
.getenv("PACKAGES_PATH")
108 mws
.setWs(GenFdsGlobalVariable
.WorkSpaceDir
, PackagesPath
)
110 if (Options
.filename
):
111 FdfFilename
= Options
.filename
112 FdfFilename
= GenFdsGlobalVariable
.ReplaceWorkspaceMacro(FdfFilename
)
114 if FdfFilename
[0:2] == '..':
115 FdfFilename
= os
.path
.realpath(FdfFilename
)
116 if not os
.path
.isabs(FdfFilename
):
117 FdfFilename
= mws
.join(GenFdsGlobalVariable
.WorkSpaceDir
, FdfFilename
)
118 if not os
.path
.exists(FdfFilename
):
119 EdkLogger
.error("GenFds", FILE_NOT_FOUND
, ExtraData
=FdfFilename
)
121 GenFdsGlobalVariable
.FdfFile
= FdfFilename
122 GenFdsGlobalVariable
.FdfFileTimeStamp
= os
.path
.getmtime(FdfFilename
)
124 EdkLogger
.error("GenFds", OPTION_MISSING
, "Missing FDF filename")
126 if (Options
.BuildTarget
):
127 GenFdsGlobalVariable
.TargetName
= Options
.BuildTarget
129 if (Options
.ToolChain
):
130 GenFdsGlobalVariable
.ToolChainTag
= Options
.ToolChain
132 if (Options
.activePlatform
):
133 ActivePlatform
= Options
.activePlatform
134 ActivePlatform
= GenFdsGlobalVariable
.ReplaceWorkspaceMacro(ActivePlatform
)
136 if ActivePlatform
[0:2] == '..':
137 ActivePlatform
= os
.path
.realpath(ActivePlatform
)
139 if not os
.path
.isabs (ActivePlatform
):
140 ActivePlatform
= mws
.join(GenFdsGlobalVariable
.WorkSpaceDir
, ActivePlatform
)
142 if not os
.path
.exists(ActivePlatform
) :
143 EdkLogger
.error("GenFds", FILE_NOT_FOUND
, "ActivePlatform doesn't exist!")
145 EdkLogger
.error("GenFds", OPTION_MISSING
, "Missing active platform")
147 GenFdsGlobalVariable
.ActivePlatform
= PathClass(NormPath(ActivePlatform
))
149 if (Options
.ConfDirectory
):
150 # Get alternate Conf location, if it is absolute, then just use the absolute directory name
151 ConfDirectoryPath
= os
.path
.normpath(Options
.ConfDirectory
)
152 if ConfDirectoryPath
.startswith('"'):
153 ConfDirectoryPath
= ConfDirectoryPath
[1:]
154 if ConfDirectoryPath
.endswith('"'):
155 ConfDirectoryPath
= ConfDirectoryPath
[:-1]
156 if not os
.path
.isabs(ConfDirectoryPath
):
157 # Since alternate directory name is not absolute, the alternate directory is located within the WORKSPACE
158 # This also handles someone specifying the Conf directory in the workspace. Using --conf=Conf
159 ConfDirectoryPath
= os
.path
.join(GenFdsGlobalVariable
.WorkSpaceDir
, ConfDirectoryPath
)
161 if "CONF_PATH" in os
.environ
.keys():
162 ConfDirectoryPath
= os
.path
.normcase(os
.environ
["CONF_PATH"])
164 # Get standard WORKSPACE/Conf, use the absolute path to the WORKSPACE/Conf
165 ConfDirectoryPath
= mws
.join(GenFdsGlobalVariable
.WorkSpaceDir
, 'Conf')
166 GenFdsGlobalVariable
.ConfDir
= ConfDirectoryPath
167 BuildConfigurationFile
= os
.path
.normpath(os
.path
.join(ConfDirectoryPath
, "target.txt"))
168 if os
.path
.isfile(BuildConfigurationFile
) == True:
169 TargetTxt
= TargetTxtClassObject
.TargetTxtClassObject()
170 TargetTxt
.LoadTargetTxtFile(BuildConfigurationFile
)
171 # if no build target given in command line, get it from target.txt
172 if not GenFdsGlobalVariable
.TargetName
:
173 BuildTargetList
= TargetTxt
.TargetTxtDictionary
[DataType
.TAB_TAT_DEFINES_TARGET
]
174 if len(BuildTargetList
) != 1:
175 EdkLogger
.error("GenFds", OPTION_VALUE_INVALID
, ExtraData
="Only allows one instance for Target.")
176 GenFdsGlobalVariable
.TargetName
= BuildTargetList
[0]
178 # if no tool chain given in command line, get it from target.txt
179 if not GenFdsGlobalVariable
.ToolChainTag
:
180 ToolChainList
= TargetTxt
.TargetTxtDictionary
[DataType
.TAB_TAT_DEFINES_TOOL_CHAIN_TAG
]
181 if ToolChainList
== None or len(ToolChainList
) == 0:
182 EdkLogger
.error("GenFds", RESOURCE_NOT_AVAILABLE
, ExtraData
="No toolchain given. Don't know how to build.")
183 if len(ToolChainList
) != 1:
184 EdkLogger
.error("GenFds", OPTION_VALUE_INVALID
, ExtraData
="Only allows one instance for ToolChain.")
185 GenFdsGlobalVariable
.ToolChainTag
= ToolChainList
[0]
187 EdkLogger
.error("GenFds", FILE_NOT_FOUND
, ExtraData
=BuildConfigurationFile
)
189 #Set global flag for build mode
190 GlobalData
.gIgnoreSource
= Options
.IgnoreSources
193 for Pair
in Options
.Macros
:
194 if Pair
.startswith('"'):
196 if Pair
.endswith('"'):
198 List
= Pair
.split('=')
200 if not List
[1].strip():
201 EdkLogger
.error("GenFds", OPTION_VALUE_INVALID
, ExtraData
="No Value given for Macro %s" %List
[0])
202 if List
[0].strip() == "EFI_SOURCE":
203 GlobalData
.gEfiSource
= List
[1].strip()
204 GlobalData
.gGlobalDefines
["EFI_SOURCE"] = GlobalData
.gEfiSource
206 elif List
[0].strip() == "EDK_SOURCE":
207 GlobalData
.gEdkSource
= List
[1].strip()
208 GlobalData
.gGlobalDefines
["EDK_SOURCE"] = GlobalData
.gEdkSource
210 elif List
[0].strip() in ["WORKSPACE", "TARGET", "TOOLCHAIN"]:
211 GlobalData
.gGlobalDefines
[List
[0].strip()] = List
[1].strip()
213 GlobalData
.gCommandLineDefines
[List
[0].strip()] = List
[1].strip()
215 GlobalData
.gCommandLineDefines
[List
[0].strip()] = "TRUE"
216 os
.environ
["WORKSPACE"] = Workspace
218 # Use the -t and -b option as gGlobalDefines's TOOLCHAIN and TARGET if they are not defined
219 if "TARGET" not in GlobalData
.gGlobalDefines
.keys():
220 GlobalData
.gGlobalDefines
["TARGET"] = GenFdsGlobalVariable
.TargetName
221 if "TOOLCHAIN" not in GlobalData
.gGlobalDefines
.keys():
222 GlobalData
.gGlobalDefines
["TOOLCHAIN"] = GenFdsGlobalVariable
.ToolChainTag
223 if "TOOL_CHAIN_TAG" not in GlobalData
.gGlobalDefines
.keys():
224 GlobalData
.gGlobalDefines
['TOOL_CHAIN_TAG'] = GenFdsGlobalVariable
.ToolChainTag
226 """call Workspace build create database"""
227 GlobalData
.gDatabasePath
= os
.path
.normpath(os
.path
.join(ConfDirectoryPath
, GlobalData
.gDatabasePath
))
228 BuildWorkSpace
= WorkspaceDatabase(GlobalData
.gDatabasePath
)
229 BuildWorkSpace
.InitDatabase()
232 # Get files real name in workspace dir
234 GlobalData
.gAllFiles
= DirCache(Workspace
)
235 GlobalData
.gWorkspace
= Workspace
237 if (Options
.archList
) :
238 ArchList
= Options
.archList
.split(',')
240 # EdkLogger.error("GenFds", OPTION_MISSING, "Missing build ARCH")
241 ArchList
= BuildWorkSpace
.BuildObject
[GenFdsGlobalVariable
.ActivePlatform
, 'COMMON', Options
.BuildTarget
, Options
.ToolChain
].SupArchList
243 TargetArchList
= set(BuildWorkSpace
.BuildObject
[GenFdsGlobalVariable
.ActivePlatform
, 'COMMON', Options
.BuildTarget
, Options
.ToolChain
].SupArchList
) & set(ArchList
)
244 if len(TargetArchList
) == 0:
245 EdkLogger
.error("GenFds", GENFDS_ERROR
, "Target ARCH %s not in platform supported ARCH %s" % (str(ArchList
), str(BuildWorkSpace
.BuildObject
[GenFdsGlobalVariable
.ActivePlatform
, 'COMMON'].SupArchList
)))
247 for Arch
in ArchList
:
248 GenFdsGlobalVariable
.OutputDirFromDscDict
[Arch
] = NormPath(BuildWorkSpace
.BuildObject
[GenFdsGlobalVariable
.ActivePlatform
, Arch
, Options
.BuildTarget
, Options
.ToolChain
].OutputDirectory
)
249 GenFdsGlobalVariable
.PlatformName
= BuildWorkSpace
.BuildObject
[GenFdsGlobalVariable
.ActivePlatform
, Arch
, Options
.BuildTarget
, Options
.ToolChain
].PlatformName
251 if (Options
.outputDir
):
252 OutputDirFromCommandLine
= GenFdsGlobalVariable
.ReplaceWorkspaceMacro(Options
.outputDir
)
253 if not os
.path
.isabs (OutputDirFromCommandLine
):
254 OutputDirFromCommandLine
= os
.path
.join(GenFdsGlobalVariable
.WorkSpaceDir
, OutputDirFromCommandLine
)
255 for Arch
in ArchList
:
256 GenFdsGlobalVariable
.OutputDirDict
[Arch
] = OutputDirFromCommandLine
258 for Arch
in ArchList
:
259 GenFdsGlobalVariable
.OutputDirDict
[Arch
] = os
.path
.join(GenFdsGlobalVariable
.OutputDirFromDscDict
[Arch
], GenFdsGlobalVariable
.TargetName
+ '_' + GenFdsGlobalVariable
.ToolChainTag
)
261 for Key
in GenFdsGlobalVariable
.OutputDirDict
:
262 OutputDir
= GenFdsGlobalVariable
.OutputDirDict
[Key
]
263 if OutputDir
[0:2] == '..':
264 OutputDir
= os
.path
.realpath(OutputDir
)
266 if OutputDir
[1] != ':':
267 OutputDir
= os
.path
.join (GenFdsGlobalVariable
.WorkSpaceDir
, OutputDir
)
269 if not os
.path
.exists(OutputDir
):
270 EdkLogger
.error("GenFds", FILE_NOT_FOUND
, ExtraData
=OutputDir
)
271 GenFdsGlobalVariable
.OutputDirDict
[Key
] = OutputDir
273 """ Parse Fdf file, has to place after build Workspace as FDF may contain macros from DSC file """
274 FdfParserObj
= FdfParser
.FdfParser(FdfFilename
)
275 FdfParserObj
.ParseFile()
277 if FdfParserObj
.CycleReferenceCheck():
278 EdkLogger
.error("GenFds", FORMAT_NOT_SUPPORTED
, "Cycle Reference Detected in FDF file")
280 if (Options
.uiFdName
) :
281 if Options
.uiFdName
.upper() in FdfParserObj
.Profile
.FdDict
.keys():
282 GenFds
.OnlyGenerateThisFd
= Options
.uiFdName
284 EdkLogger
.error("GenFds", OPTION_VALUE_INVALID
,
285 "No such an FD in FDF file: %s" % Options
.uiFdName
)
287 if (Options
.uiFvName
) :
288 if Options
.uiFvName
.upper() in FdfParserObj
.Profile
.FvDict
.keys():
289 GenFds
.OnlyGenerateThisFv
= Options
.uiFvName
291 EdkLogger
.error("GenFds", OPTION_VALUE_INVALID
,
292 "No such an FV in FDF file: %s" % Options
.uiFvName
)
294 if (Options
.uiCapName
) :
295 if Options
.uiCapName
.upper() in FdfParserObj
.Profile
.CapsuleDict
.keys():
296 GenFds
.OnlyGenerateThisCap
= Options
.uiCapName
298 EdkLogger
.error("GenFds", OPTION_VALUE_INVALID
,
299 "No such a Capsule in FDF file: %s" % Options
.uiCapName
)
301 GenFdsGlobalVariable
.WorkSpace
= BuildWorkSpace
303 GenFdsGlobalVariable
.ArchList
= ArchList
305 if Options
.OptionPcd
:
306 GlobalData
.BuildOptionPcd
= Options
.OptionPcd
307 CheckBuildOptionPcd()
309 """Modify images from build output if the feature of loading driver at fixed address is on."""
310 if GenFdsGlobalVariable
.FixedLoadAddress
:
311 GenFds
.PreprocessImage(BuildWorkSpace
, GenFdsGlobalVariable
.ActivePlatform
)
313 # Record the FV Region info that may specific in the FD
314 if FdfParserObj
.Profile
.FvDict
and FdfParserObj
.Profile
.FdDict
:
315 for Fv
in FdfParserObj
.Profile
.FvDict
:
316 FvObj
= FdfParserObj
.Profile
.FvDict
[Fv
]
317 for Fd
in FdfParserObj
.Profile
.FdDict
:
318 FdObj
= FdfParserObj
.Profile
.FdDict
[Fd
]
319 for RegionObj
in FdObj
.RegionList
:
320 if RegionObj
.RegionType
!= 'FV':
322 for RegionData
in RegionObj
.RegionDataList
:
323 if FvObj
.UiFvName
.upper() == RegionData
.upper():
324 if FvObj
.FvRegionInFD
:
325 if FvObj
.FvRegionInFD
!= RegionObj
.Size
:
326 EdkLogger
.error("GenFds", FORMAT_INVALID
, "The FV %s's region is specified in multiple FD with different value." %FvObj
.UiFvName
)
328 FvObj
.FvRegionInFD
= RegionObj
.Size
329 RegionObj
.BlockInfoOfRegion(FdObj
.BlockSizeList
, FvObj
)
332 GenFds
.GenFd('', FdfParserObj
, BuildWorkSpace
, ArchList
)
334 """Generate GUID cross reference file"""
335 GenFds
.GenerateGuidXRefFile(BuildWorkSpace
, ArchList
, FdfParserObj
)
337 """Display FV space info."""
338 GenFds
.DisplayFvSpaceInfo(FdfParserObj
)
340 except FdfParser
.Warning, X
:
341 EdkLogger
.error(X
.ToolName
, FORMAT_INVALID
, File
=X
.FileName
, Line
=X
.LineNumber
, ExtraData
=X
.Message
, RaiseError
=False)
342 ReturnCode
= FORMAT_INVALID
343 except FatalError
, X
:
344 if Options
.debug
!= None:
346 EdkLogger
.quiet(traceback
.format_exc())
347 ReturnCode
= X
.args
[0]
353 "Tools code failure",
354 ExtraData
="Please send email to edk2-devel@lists.01.org for help, attaching following call stack trace!\n",
357 EdkLogger
.quiet(traceback
.format_exc())
358 ReturnCode
= CODE_ERROR
364 def SingleCheckCallback(option
, opt_str
, value
, parser
):
365 if option
not in gParamCheck
:
366 setattr(parser
.values
, option
.dest
, value
)
367 gParamCheck
.append(option
)
369 parser
.error("Option %s only allows one instance in command line!" % option
)
371 def CheckBuildOptionPcd():
372 for Arch
in GenFdsGlobalVariable
.ArchList
:
373 PkgList
= GenFdsGlobalVariable
.WorkSpace
.GetPackageList(GenFdsGlobalVariable
.ActivePlatform
, Arch
, GenFdsGlobalVariable
.TargetName
, GenFdsGlobalVariable
.ToolChainTag
)
374 for i
, pcd
in enumerate(GlobalData
.BuildOptionPcd
):
375 if type(pcd
) is tuple:
377 (pcdname
, pcdvalue
) = pcd
.split('=')
379 EdkLogger
.error('GenFds', OPTION_MISSING
, "No Value specified for the PCD %s." % (pcdname
))
381 (TokenSpaceGuidCName
, TokenCName
) = pcdname
.split('.')
385 TokenSpaceGuidCName
= ''
386 HasTokenSpace
= False
387 TokenSpaceGuidCNameList
= []
391 for package
in PkgList
:
392 for key
in package
.Pcds
:
393 PcdItem
= package
.Pcds
[key
]
395 if (PcdItem
.TokenCName
, PcdItem
.TokenSpaceGuidCName
) == (TokenCName
, TokenSpaceGuidCName
):
396 PcdDatumType
= PcdItem
.DatumType
397 NewValue
= BuildOptionPcdValueFormat(TokenSpaceGuidCName
, TokenCName
, PcdDatumType
, pcdvalue
)
400 if PcdItem
.TokenCName
== TokenCName
:
401 if not PcdItem
.TokenSpaceGuidCName
in TokenSpaceGuidCNameList
:
402 if len (TokenSpaceGuidCNameList
) < 1:
403 TokenSpaceGuidCNameList
.append(PcdItem
.TokenSpaceGuidCName
)
404 PcdDatumType
= PcdItem
.DatumType
405 TokenSpaceGuidCName
= PcdItem
.TokenSpaceGuidCName
406 NewValue
= BuildOptionPcdValueFormat(TokenSpaceGuidCName
, TokenCName
, PcdDatumType
, pcdvalue
)
411 PCD_VALIDATION_INFO_ERROR
,
412 "The Pcd %s is found under multiple different TokenSpaceGuid: %s and %s." % (TokenCName
, PcdItem
.TokenSpaceGuidCName
, TokenSpaceGuidCNameList
[0])
415 GlobalData
.BuildOptionPcd
[i
] = (TokenSpaceGuidCName
, TokenCName
, NewValue
)
420 # Find location of tools to process data
422 # @param KeyStringList Filter for inputs of section generation
423 # @param CurrentArchList Arch list
424 # @param NameGuid The Guid name
426 def FindExtendTool(KeyStringList
, CurrentArchList
, NameGuid
):
427 ToolDb
= ToolDefClassObject
.ToolDefDict(GenFdsGlobalVariable
.ConfDir
).ToolsDefTxtDatabase
428 # if user not specify filter, try to deduce it from global data.
429 if KeyStringList
== None or KeyStringList
== []:
430 Target
= GenFdsGlobalVariable
.TargetName
431 ToolChain
= GenFdsGlobalVariable
.ToolChainTag
432 if ToolChain
not in ToolDb
['TOOL_CHAIN_TAG']:
433 EdkLogger
.error("GenFds", GENFDS_ERROR
, "Can not find external tool because tool tag %s is not defined in tools_def.txt!" % ToolChain
)
434 KeyStringList
= [Target
+ '_' + ToolChain
+ '_' + CurrentArchList
[0]]
435 for Arch
in CurrentArchList
:
436 if Target
+ '_' + ToolChain
+ '_' + Arch
not in KeyStringList
:
437 KeyStringList
.append(Target
+ '_' + ToolChain
+ '_' + Arch
)
439 if GenFdsGlobalVariable
.GuidToolDefinition
:
440 if NameGuid
in GenFdsGlobalVariable
.GuidToolDefinition
.keys():
441 return GenFdsGlobalVariable
.GuidToolDefinition
[NameGuid
]
443 ToolDefinition
= ToolDefClassObject
.ToolDefDict(GenFdsGlobalVariable
.ConfDir
).ToolsDefTxtDictionary
449 for ToolDef
in ToolDefinition
.items():
450 if NameGuid
== ToolDef
[1]:
451 KeyList
= ToolDef
[0].split('_')
457 if Key
in KeyStringList
and KeyList
[4] == 'GUID':
458 ToolPathKey
= Key
+ '_' + KeyList
[3] + '_PATH'
459 ToolOptionKey
= Key
+ '_' + KeyList
[3] + '_FLAGS'
460 ToolPath
= ToolDefinition
.get(ToolPathKey
)
461 ToolOption
= ToolDefinition
.get(ToolOptionKey
)
462 if ToolPathTmp
== None:
463 ToolPathTmp
= ToolPath
465 if ToolPathTmp
!= ToolPath
:
466 EdkLogger
.error("GenFds", GENFDS_ERROR
, "Don't know which tool to use, %s or %s ?" % (ToolPathTmp
, ToolPath
))
469 for Arch
in CurrentArchList
:
470 Platform
= GenFdsGlobalVariable
.WorkSpace
.BuildObject
[GenFdsGlobalVariable
.ActivePlatform
, Arch
, GenFdsGlobalVariable
.TargetName
, GenFdsGlobalVariable
.ToolChainTag
]
471 # key is (ToolChainFamily, ToolChain, CodeBase)
472 for item
in Platform
.BuildOptions
:
473 if '_PATH' in item
[1] or '_FLAGS' in item
[1] or '_GUID' in item
[1]:
474 if not item
[0] or (item
[0] and GenFdsGlobalVariable
.ToolChainFamily
== item
[0]):
475 if item
[1] not in BuildOption
:
476 BuildOption
[item
[1]] = Platform
.BuildOptions
[item
]
478 ToolList
= [TAB_TOD_DEFINES_TARGET
, TAB_TOD_DEFINES_TOOL_CHAIN_TAG
, TAB_TOD_DEFINES_TARGET_ARCH
]
479 for Index
in range(2, -1, -1):
480 for Key
in dict(BuildOption
):
481 List
= Key
.split('_')
482 if List
[Index
] == '*':
483 for String
in ToolDb
[ToolList
[Index
]]:
484 if String
in [Arch
, GenFdsGlobalVariable
.TargetName
, GenFdsGlobalVariable
.ToolChainTag
]:
486 NewKey
= '%s_%s_%s_%s_%s' % tuple(List
)
487 if NewKey
not in BuildOption
:
488 BuildOption
[NewKey
] = BuildOption
[Key
]
491 elif List
[Index
] not in ToolDb
[ToolList
[Index
]]:
495 for Op
in BuildOption
:
496 if NameGuid
== BuildOption
[Op
]:
497 KeyList
= Op
.split('_')
498 Key
= KeyList
[0] + '_' + KeyList
[1] +'_' + KeyList
[2]
499 if Key
in KeyStringList
and KeyList
[4] == 'GUID':
500 ToolPathKey
= Key
+ '_' + KeyList
[3] + '_PATH'
501 ToolOptionKey
= Key
+ '_' + KeyList
[3] + '_FLAGS'
502 if ToolPathKey
in BuildOption
.keys():
503 ToolPathTmp
= BuildOption
.get(ToolPathKey
)
504 if ToolOptionKey
in BuildOption
.keys():
505 ToolOption
= BuildOption
.get(ToolOptionKey
)
507 GenFdsGlobalVariable
.GuidToolDefinition
[NameGuid
] = (ToolPathTmp
, ToolOption
)
508 return ToolPathTmp
, ToolOption
510 ## Parse command line options
512 # Using standard Python module optparse to parse command line option of this tool.
514 # @retval Opt A optparse.Values object containing the parsed options
515 # @retval Args Target of build command
517 def myOptionParser():
518 usage
= "%prog [options] -f input_file -a arch_list -b build_target -p active_platform -t tool_chain_tag -D \"MacroName [= MacroValue]\""
519 Parser
= OptionParser(usage
=usage
, description
=__copyright__
, version
="%prog " + str(versionNumber
))
520 Parser
.add_option("-f", "--file", dest
="filename", type="string", help="Name of FDF file to convert", action
="callback", callback
=SingleCheckCallback
)
521 Parser
.add_option("-a", "--arch", dest
="archList", help="comma separated list containing one or more of: IA32, X64, IPF, ARM, AARCH64 or EBC which should be built, overrides target.txt?s TARGET_ARCH")
522 Parser
.add_option("-q", "--quiet", action
="store_true", type=None, help="Disable all messages except FATAL ERRORS.")
523 Parser
.add_option("-v", "--verbose", action
="store_true", type=None, help="Turn on verbose output with informational messages printed.")
524 Parser
.add_option("-d", "--debug", action
="store", type="int", help="Enable debug messages at specified level.")
525 Parser
.add_option("-p", "--platform", type="string", dest
="activePlatform", help="Set the ACTIVE_PLATFORM, overrides target.txt ACTIVE_PLATFORM setting.",
526 action
="callback", callback
=SingleCheckCallback
)
527 Parser
.add_option("-w", "--workspace", type="string", dest
="Workspace", default
=os
.environ
.get('WORKSPACE'), help="Set the WORKSPACE",
528 action
="callback", callback
=SingleCheckCallback
)
529 Parser
.add_option("-o", "--outputDir", type="string", dest
="outputDir", help="Name of Build Output directory",
530 action
="callback", callback
=SingleCheckCallback
)
531 Parser
.add_option("-r", "--rom_image", dest
="uiFdName", help="Build the image using the [FD] section named by FdUiName.")
532 Parser
.add_option("-i", "--FvImage", dest
="uiFvName", help="Build the FV image using the [FV] section named by UiFvName")
533 Parser
.add_option("-C", "--CapsuleImage", dest
="uiCapName", help="Build the Capsule image using the [Capsule] section named by UiCapName")
534 Parser
.add_option("-b", "--buildtarget", type="string", dest
="BuildTarget", help="Set the build TARGET, overrides target.txt TARGET setting.",
535 action
="callback", callback
=SingleCheckCallback
)
536 Parser
.add_option("-t", "--tagname", type="string", dest
="ToolChain", help="Using the tools: TOOL_CHAIN_TAG name to build the platform.",
537 action
="callback", callback
=SingleCheckCallback
)
538 Parser
.add_option("-D", "--define", action
="append", type="string", dest
="Macros", help="Macro: \"Name [= Value]\".")
539 Parser
.add_option("-s", "--specifyaddress", dest
="FixedAddress", action
="store_true", type=None, help="Specify driver load address.")
540 Parser
.add_option("--conf", action
="store", type="string", dest
="ConfDirectory", help="Specify the customized Conf directory.")
541 Parser
.add_option("--ignore-sources", action
="store_true", dest
="IgnoreSources", default
=False, help="Focus to a binary build and ignore all source files")
542 Parser
.add_option("--pcd", action
="append", dest
="OptionPcd", help="Set PCD value by command line. Format: \"PcdName=Value\" ")
543 Parser
.add_option("--genfds-multi-thread", action
="store_true", dest
="GenfdsMultiThread", default
=False, help="Enable GenFds multi thread to generate ffs file.")
545 (Options
, args
) = Parser
.parse_args()
548 ## The class implementing the EDK2 flash image generation process
550 # This process includes:
551 # 1. Collect workspace information, includes platform and module information
552 # 2. Call methods of Fd class to generate FD
553 # 3. Call methods of Fv class to generate FV that not belong to FD
557 # FvName, FdName, CapName in FDF, Image file name
559 OnlyGenerateThisFd
= None
560 OnlyGenerateThisFv
= None
561 OnlyGenerateThisCap
= None
565 # @param OutputDir Output directory
566 # @param FdfParser FDF contents parser
567 # @param Workspace The directory of workspace
568 # @param ArchList The Arch list of platform
570 def GenFd (OutputDir
, FdfParser
, WorkSpace
, ArchList
):
571 GenFdsGlobalVariable
.SetDir ('', FdfParser
, WorkSpace
, ArchList
)
573 GenFdsGlobalVariable
.VerboseLogger(" Generate all Fd images and their required FV and Capsule images!")
574 if GenFds
.OnlyGenerateThisCap
!= None and GenFds
.OnlyGenerateThisCap
.upper() in GenFdsGlobalVariable
.FdfParser
.Profile
.CapsuleDict
.keys():
575 CapsuleObj
= GenFdsGlobalVariable
.FdfParser
.Profile
.CapsuleDict
.get(GenFds
.OnlyGenerateThisCap
.upper())
576 if CapsuleObj
!= None:
577 CapsuleObj
.GenCapsule()
580 if GenFds
.OnlyGenerateThisFd
!= None and GenFds
.OnlyGenerateThisFd
.upper() in GenFdsGlobalVariable
.FdfParser
.Profile
.FdDict
.keys():
581 FdObj
= GenFdsGlobalVariable
.FdfParser
.Profile
.FdDict
.get(GenFds
.OnlyGenerateThisFd
.upper())
585 elif GenFds
.OnlyGenerateThisFd
== None and GenFds
.OnlyGenerateThisFv
== None:
586 for FdName
in GenFdsGlobalVariable
.FdfParser
.Profile
.FdDict
.keys():
587 FdObj
= GenFdsGlobalVariable
.FdfParser
.Profile
.FdDict
[FdName
]
590 GenFdsGlobalVariable
.VerboseLogger("\n Generate other FV images! ")
591 if GenFds
.OnlyGenerateThisFv
!= None and GenFds
.OnlyGenerateThisFv
.upper() in GenFdsGlobalVariable
.FdfParser
.Profile
.FvDict
.keys():
592 FvObj
= GenFdsGlobalVariable
.FdfParser
.Profile
.FvDict
.get(GenFds
.OnlyGenerateThisFv
.upper())
594 Buffer
= StringIO
.StringIO()
595 FvObj
.AddToBuffer(Buffer
)
598 elif GenFds
.OnlyGenerateThisFv
== None:
599 for FvName
in GenFdsGlobalVariable
.FdfParser
.Profile
.FvDict
.keys():
600 Buffer
= StringIO
.StringIO('')
601 FvObj
= GenFdsGlobalVariable
.FdfParser
.Profile
.FvDict
[FvName
]
602 FvObj
.AddToBuffer(Buffer
)
605 if GenFds
.OnlyGenerateThisFv
== None and GenFds
.OnlyGenerateThisFd
== None and GenFds
.OnlyGenerateThisCap
== None:
606 if GenFdsGlobalVariable
.FdfParser
.Profile
.CapsuleDict
!= {}:
607 GenFdsGlobalVariable
.VerboseLogger("\n Generate other Capsule images!")
608 for CapsuleName
in GenFdsGlobalVariable
.FdfParser
.Profile
.CapsuleDict
.keys():
609 CapsuleObj
= GenFdsGlobalVariable
.FdfParser
.Profile
.CapsuleDict
[CapsuleName
]
610 CapsuleObj
.GenCapsule()
612 if GenFdsGlobalVariable
.FdfParser
.Profile
.OptRomDict
!= {}:
613 GenFdsGlobalVariable
.VerboseLogger("\n Generate all Option ROM!")
614 for DriverName
in GenFdsGlobalVariable
.FdfParser
.Profile
.OptRomDict
.keys():
615 OptRomObj
= GenFdsGlobalVariable
.FdfParser
.Profile
.OptRomDict
[DriverName
]
616 OptRomObj
.AddToBuffer(None)
618 def GenFfsMakefile(OutputDir
, FdfParser
, WorkSpace
, ArchList
, GlobalData
):
619 GenFdsGlobalVariable
.SetEnv(FdfParser
, WorkSpace
, ArchList
, GlobalData
)
620 for FdName
in GenFdsGlobalVariable
.FdfParser
.Profile
.FdDict
.keys():
621 FdObj
= GenFdsGlobalVariable
.FdfParser
.Profile
.FdDict
[FdName
]
622 FdObj
.GenFd(Flag
=True)
624 for FvName
in GenFdsGlobalVariable
.FdfParser
.Profile
.FvDict
.keys():
625 FvObj
= GenFdsGlobalVariable
.FdfParser
.Profile
.FvDict
[FvName
]
626 FvObj
.AddToBuffer(Buffer
=None, Flag
=True)
628 if GenFdsGlobalVariable
.FdfParser
.Profile
.OptRomDict
!= {}:
629 for DriverName
in GenFdsGlobalVariable
.FdfParser
.Profile
.OptRomDict
.keys():
630 OptRomObj
= GenFdsGlobalVariable
.FdfParser
.Profile
.OptRomDict
[DriverName
]
631 OptRomObj
.AddToBuffer(Buffer
=None, Flag
=True)
633 return GenFdsGlobalVariable
.FfsCmdDict
637 # @param FvObj Whose block size to get
638 # @retval int Block size value
640 def GetFvBlockSize(FvObj
):
641 DefaultBlockSize
= 0x1
643 if GenFds
.OnlyGenerateThisFd
!= None and GenFds
.OnlyGenerateThisFd
.upper() in GenFdsGlobalVariable
.FdfParser
.Profile
.FdDict
.keys():
644 FdObj
= GenFdsGlobalVariable
.FdfParser
.Profile
.FdDict
[GenFds
.OnlyGenerateThisFd
.upper()]
646 for ElementFd
in GenFdsGlobalVariable
.FdfParser
.Profile
.FdDict
.values():
647 for ElementRegion
in ElementFd
.RegionList
:
648 if ElementRegion
.RegionType
== 'FV':
649 for ElementRegionData
in ElementRegion
.RegionDataList
:
650 if ElementRegionData
!= None and ElementRegionData
.upper() == FvObj
.UiFvName
:
651 if FvObj
.BlockSizeList
!= []:
652 return FvObj
.BlockSizeList
[0][0]
654 return ElementRegion
.BlockSizeOfRegion(ElementFd
.BlockSizeList
)
655 if FvObj
.BlockSizeList
!= []:
656 return FvObj
.BlockSizeList
[0][0]
657 return DefaultBlockSize
659 for ElementRegion
in FdObj
.RegionList
:
660 if ElementRegion
.RegionType
== 'FV':
661 for ElementRegionData
in ElementRegion
.RegionDataList
:
662 if ElementRegionData
!= None and ElementRegionData
.upper() == FvObj
.UiFvName
:
663 if FvObj
.BlockSizeList
!= []:
664 return FvObj
.BlockSizeList
[0][0]
666 return ElementRegion
.BlockSizeOfRegion(ElementFd
.BlockSizeList
)
667 return DefaultBlockSize
669 ## DisplayFvSpaceInfo()
671 # @param FvObj Whose block size to get
674 def DisplayFvSpaceInfo(FdfParser
):
678 for FvName
in FdfParser
.Profile
.FvDict
:
679 if len(FvName
) > MaxFvNameLength
:
680 MaxFvNameLength
= len(FvName
)
681 FvSpaceInfoFileName
= os
.path
.join(GenFdsGlobalVariable
.FvDir
, FvName
.upper() + '.Fv.map')
682 if os
.path
.exists(FvSpaceInfoFileName
):
683 FileLinesList
= linecache
.getlines(FvSpaceInfoFileName
)
690 for Line
in FileLinesList
:
691 NameValue
= Line
.split('=')
692 if len(NameValue
) == 2:
693 if NameValue
[0].strip() == 'EFI_FV_TOTAL_SIZE':
695 Total
= NameValue
[1].strip()
696 if NameValue
[0].strip() == 'EFI_FV_TAKEN_SIZE':
698 Used
= NameValue
[1].strip()
699 if NameValue
[0].strip() == 'EFI_FV_SPACE_SIZE':
701 Free
= NameValue
[1].strip()
703 if TotalFound
and UsedFound
and FreeFound
:
704 FvSpaceInfoList
.append((FvName
, Total
, Used
, Free
))
706 GenFdsGlobalVariable
.InfLogger('\nFV Space Information')
707 for FvSpaceInfo
in FvSpaceInfoList
:
708 Name
= FvSpaceInfo
[0]
709 TotalSizeValue
= long(FvSpaceInfo
[1], 0)
710 UsedSizeValue
= long(FvSpaceInfo
[2], 0)
711 FreeSizeValue
= long(FvSpaceInfo
[3], 0)
712 if UsedSizeValue
== TotalSizeValue
:
715 Percentage
= str((UsedSizeValue
+ 0.0) / TotalSizeValue
)[0:4].lstrip('0.')
717 GenFdsGlobalVariable
.InfLogger(Name
+ ' ' + '[' + Percentage
+ '%Full] ' + str(TotalSizeValue
) + ' total, ' + str(UsedSizeValue
) + ' used, ' + str(FreeSizeValue
) + ' free')
721 # @param BuildDb Database from build meta data files
722 # @param DscFile modules from dsc file will be preprocessed
725 def PreprocessImage(BuildDb
, DscFile
):
726 PcdDict
= BuildDb
.BuildObject
[DscFile
, 'COMMON', GenFdsGlobalVariable
.TargetName
, GenFdsGlobalVariable
.ToolChainTag
].Pcds
729 PcdObj
= PcdDict
[Key
]
730 if PcdObj
.TokenCName
== 'PcdBsBaseAddress':
731 PcdValue
= PcdObj
.DefaultValue
737 Int64PcdValue
= long(PcdValue
, 0)
738 if Int64PcdValue
== 0 or Int64PcdValue
< -1:
742 if Int64PcdValue
> 0:
743 TopAddress
= Int64PcdValue
745 ModuleDict
= BuildDb
.BuildObject
[DscFile
, 'COMMON', GenFdsGlobalVariable
.TargetName
, GenFdsGlobalVariable
.ToolChainTag
].Modules
746 for Key
in ModuleDict
:
747 ModuleObj
= BuildDb
.BuildObject
[Key
, 'COMMON', GenFdsGlobalVariable
.TargetName
, GenFdsGlobalVariable
.ToolChainTag
]
748 print ModuleObj
.BaseName
+ ' ' + ModuleObj
.ModuleType
750 def GenerateGuidXRefFile(BuildDb
, ArchList
, FdfParserObj
):
751 GuidXRefFileName
= os
.path
.join(GenFdsGlobalVariable
.FvDir
, "Guid.xref")
752 GuidXRefFile
= StringIO
.StringIO('')
756 for Arch
in ArchList
:
757 PlatformDataBase
= BuildDb
.BuildObject
[GenFdsGlobalVariable
.ActivePlatform
, Arch
, GenFdsGlobalVariable
.TargetName
, GenFdsGlobalVariable
.ToolChainTag
]
758 for ModuleFile
in PlatformDataBase
.Modules
:
759 Module
= BuildDb
.BuildObject
[ModuleFile
, Arch
, GenFdsGlobalVariable
.TargetName
, GenFdsGlobalVariable
.ToolChainTag
]
760 if Module
in ModuleList
:
763 ModuleList
.append(Module
)
764 GuidXRefFile
.write("%s %s\n" % (Module
.Guid
, Module
.BaseName
))
765 for key
, item
in Module
.Protocols
.items():
767 for key
, item
in Module
.Guids
.items():
769 for key
, item
in Module
.Ppis
.items():
771 for FvName
in FdfParserObj
.Profile
.FvDict
:
772 for FfsObj
in FdfParserObj
.Profile
.FvDict
[FvName
].FfsList
:
773 if not isinstance(FfsObj
, FfsFileStatement
.FileStatement
):
774 InfPath
= PathClass(NormPath(mws
.join(GenFdsGlobalVariable
.WorkSpaceDir
, FfsObj
.InfFileName
)))
775 FdfModule
= BuildDb
.BuildObject
[InfPath
, Arch
, GenFdsGlobalVariable
.TargetName
, GenFdsGlobalVariable
.ToolChainTag
]
776 if FdfModule
in ModuleList
:
779 ModuleList
.append(FdfModule
)
780 GuidXRefFile
.write("%s %s\n" % (FdfModule
.Guid
, FdfModule
.BaseName
))
781 for key
, item
in FdfModule
.Protocols
.items():
783 for key
, item
in FdfModule
.Guids
.items():
785 for key
, item
in FdfModule
.Ppis
.items():
788 FileStatementGuid
= FfsObj
.NameGuid
789 if FileStatementGuid
in FileGuidList
:
792 FileGuidList
.append(FileStatementGuid
)
794 FfsPath
= os
.path
.join(GenFdsGlobalVariable
.FvDir
, 'Ffs')
795 FfsPath
= glob
.glob(os
.path
.join(FfsPath
, FileStatementGuid
) + '*')
798 if not os
.path
.exists(FfsPath
[0]):
801 ReFileEnds
= re
.compile('\S+(.ui)$|\S+(fv.sec.txt)$|\S+(.pe32.txt)$|\S+(.te.txt)$|\S+(.pic.txt)$|\S+(.raw.txt)$|\S+(.ffs.txt)$')
802 FileList
= os
.listdir(FfsPath
[0])
803 for File
in FileList
:
804 Match
= ReFileEnds
.search(File
)
806 for Index
in range(1, 8):
807 if Match
.group(Index
) and Match
.group(Index
) in MatchDict
:
808 MatchDict
[Match
.group(Index
)].append(File
)
809 elif Match
.group(Index
):
810 MatchDict
[Match
.group(Index
)] = [File
]
813 if '.ui' in MatchDict
:
814 for File
in MatchDict
['.ui']:
815 with
open(os
.path
.join(FfsPath
[0], File
), 'rb') as F
:
819 TmpStr
= unpack('%dh' % ((length
- 4) / 2), F
.read())
820 Name
= ''.join([chr(c
) for c
in TmpStr
[:-1]])
823 if 'fv.sec.txt' in MatchDict
:
824 FileList
= MatchDict
['fv.sec.txt']
825 elif '.pe32.txt' in MatchDict
:
826 FileList
= MatchDict
['.pe32.txt']
827 elif '.te.txt' in MatchDict
:
828 FileList
= MatchDict
['.te.txt']
829 elif '.pic.txt' in MatchDict
:
830 FileList
= MatchDict
['.pic.txt']
831 elif '.raw.txt' in MatchDict
:
832 FileList
= MatchDict
['.raw.txt']
833 elif '.ffs.txt' in MatchDict
:
834 FileList
= MatchDict
['.ffs.txt']
837 for File
in FileList
:
838 with
open(os
.path
.join(FfsPath
[0], File
), 'r') as F
:
839 Name
.append((F
.read().split()[-1]))
843 Name
= ' '.join(Name
) if type(Name
) == type([]) else Name
844 GuidXRefFile
.write("%s %s\n" %(FileStatementGuid
, Name
))
846 # Append GUIDs, Protocols, and PPIs to the Xref file
847 GuidXRefFile
.write("\n")
848 for key
, item
in GuidDict
.items():
849 GuidXRefFile
.write("%s %s\n" % (GuidStructureStringToGuidString(item
).upper(), key
))
851 if GuidXRefFile
.getvalue():
852 SaveFileOnChange(GuidXRefFileName
, GuidXRefFile
.getvalue(), False)
853 GenFdsGlobalVariable
.InfLogger("\nGUID cross reference file can be found at %s" % GuidXRefFileName
)
854 elif os
.path
.exists(GuidXRefFileName
):
855 os
.remove(GuidXRefFileName
)
858 ##Define GenFd as static function
859 GenFd
= staticmethod(GenFd
)
860 GetFvBlockSize
= staticmethod(GetFvBlockSize
)
861 DisplayFvSpaceInfo
= staticmethod(DisplayFvSpaceInfo
)
862 PreprocessImage
= staticmethod(PreprocessImage
)
863 GenerateGuidXRefFile
= staticmethod(GenerateGuidXRefFile
)
865 if __name__
== '__main__':
867 ## 0-127 is a safe return range, and 1 is a standard default error
868 if r
< 0 or r
> 127: r
= 1