4 # Copyright (c) 2007 - 2018, 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 __future__
import print_function
19 from optparse
import OptionParser
21 import Common
.LongFilePathOs
as os
24 import Common
.BuildToolError
as BuildToolError
25 from GenFdsGlobalVariable
import GenFdsGlobalVariable
26 from Workspace
.WorkspaceDatabase
import WorkspaceDatabase
27 from Workspace
.BuildClassObject
import PcdClassObject
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
.StringUtils
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
.BuildVersion
import gBUILD_VERSION
42 from Common
.MultipleWorkspace
import MultipleWorkspace
as mws
43 import FfsFileStatement
45 from struct
import unpack
47 ## Version and Copyright
48 versionNumber
= "1.0" + ' ' + gBUILD_VERSION
49 __version__
= "%prog Version " + versionNumber
50 __copyright__
= "Copyright (c) 2007 - 2017, Intel Corporation All rights reserved."
52 ## Tool entrance method
54 # This method mainly dispatch specific methods per the command line options.
55 # If no error found, return zero value so the caller of this tool can know
56 # if it's executed successfully or not.
58 # @retval 0 Tool was successful
59 # @retval 1 Tool failed
63 Options
= myOptionParser()
70 EdkLogger
.Initialize()
72 if Options
.verbose
is not None:
73 EdkLogger
.SetLevel(EdkLogger
.VERBOSE
)
74 GenFdsGlobalVariable
.VerboseMode
= True
76 if Options
.FixedAddress
is not None:
77 GenFdsGlobalVariable
.FixedLoadAddress
= True
79 if Options
.quiet
is not None:
80 EdkLogger
.SetLevel(EdkLogger
.QUIET
)
81 if Options
.debug
is not None:
82 EdkLogger
.SetLevel(Options
.debug
+ 1)
83 GenFdsGlobalVariable
.DebugLevel
= Options
.debug
85 EdkLogger
.SetLevel(EdkLogger
.INFO
)
87 if (Options
.Workspace
is None):
88 EdkLogger
.error("GenFds", OPTION_MISSING
, "WORKSPACE not defined",
89 ExtraData
="Please use '-w' switch to pass it or set the WORKSPACE environment variable.")
90 elif not os
.path
.exists(Options
.Workspace
):
91 EdkLogger
.error("GenFds", PARAMETER_INVALID
, "WORKSPACE is invalid",
92 ExtraData
="Please use '-w' switch to pass it or set the WORKSPACE environment variable.")
94 Workspace
= os
.path
.normcase(Options
.Workspace
)
95 GenFdsGlobalVariable
.WorkSpaceDir
= Workspace
96 if 'EDK_SOURCE' in os
.environ
:
97 GenFdsGlobalVariable
.EdkSourceDir
= os
.path
.normcase(os
.environ
['EDK_SOURCE'])
99 GenFdsGlobalVariable
.VerboseLogger("Using Workspace:" + Workspace
)
100 if Options
.GenfdsMultiThread
:
101 GenFdsGlobalVariable
.EnableGenfdsMultiThread
= True
102 os
.chdir(GenFdsGlobalVariable
.WorkSpaceDir
)
104 # set multiple workspace
105 PackagesPath
= os
.getenv("PACKAGES_PATH")
106 mws
.setWs(GenFdsGlobalVariable
.WorkSpaceDir
, PackagesPath
)
108 if (Options
.filename
):
109 FdfFilename
= Options
.filename
110 FdfFilename
= GenFdsGlobalVariable
.ReplaceWorkspaceMacro(FdfFilename
)
112 if FdfFilename
[0:2] == '..':
113 FdfFilename
= os
.path
.realpath(FdfFilename
)
114 if not os
.path
.isabs(FdfFilename
):
115 FdfFilename
= mws
.join(GenFdsGlobalVariable
.WorkSpaceDir
, FdfFilename
)
116 if not os
.path
.exists(FdfFilename
):
117 EdkLogger
.error("GenFds", FILE_NOT_FOUND
, ExtraData
=FdfFilename
)
119 GenFdsGlobalVariable
.FdfFile
= FdfFilename
120 GenFdsGlobalVariable
.FdfFileTimeStamp
= os
.path
.getmtime(FdfFilename
)
122 EdkLogger
.error("GenFds", OPTION_MISSING
, "Missing FDF filename")
124 if (Options
.BuildTarget
):
125 GenFdsGlobalVariable
.TargetName
= Options
.BuildTarget
127 if (Options
.ToolChain
):
128 GenFdsGlobalVariable
.ToolChainTag
= Options
.ToolChain
130 if (Options
.activePlatform
):
131 ActivePlatform
= Options
.activePlatform
132 ActivePlatform
= GenFdsGlobalVariable
.ReplaceWorkspaceMacro(ActivePlatform
)
134 if ActivePlatform
[0:2] == '..':
135 ActivePlatform
= os
.path
.realpath(ActivePlatform
)
137 if not os
.path
.isabs (ActivePlatform
):
138 ActivePlatform
= mws
.join(GenFdsGlobalVariable
.WorkSpaceDir
, ActivePlatform
)
140 if not os
.path
.exists(ActivePlatform
) :
141 EdkLogger
.error("GenFds", FILE_NOT_FOUND
, "ActivePlatform doesn't exist!")
143 EdkLogger
.error("GenFds", OPTION_MISSING
, "Missing active platform")
145 GlobalData
.BuildOptionPcd
= Options
.OptionPcd
if Options
.OptionPcd
else {}
146 GenFdsGlobalVariable
.ActivePlatform
= PathClass(NormPath(ActivePlatform
))
148 if (Options
.ConfDirectory
):
149 # Get alternate Conf location, if it is absolute, then just use the absolute directory name
150 ConfDirectoryPath
= os
.path
.normpath(Options
.ConfDirectory
)
151 if ConfDirectoryPath
.startswith('"'):
152 ConfDirectoryPath
= ConfDirectoryPath
[1:]
153 if ConfDirectoryPath
.endswith('"'):
154 ConfDirectoryPath
= ConfDirectoryPath
[:-1]
155 if not os
.path
.isabs(ConfDirectoryPath
):
156 # Since alternate directory name is not absolute, the alternate directory is located within the WORKSPACE
157 # This also handles someone specifying the Conf directory in the workspace. Using --conf=Conf
158 ConfDirectoryPath
= os
.path
.join(GenFdsGlobalVariable
.WorkSpaceDir
, ConfDirectoryPath
)
160 if "CONF_PATH" in os
.environ
:
161 ConfDirectoryPath
= os
.path
.normcase(os
.environ
["CONF_PATH"])
163 # Get standard WORKSPACE/Conf, use the absolute path to the WORKSPACE/Conf
164 ConfDirectoryPath
= mws
.join(GenFdsGlobalVariable
.WorkSpaceDir
, 'Conf')
165 GenFdsGlobalVariable
.ConfDir
= ConfDirectoryPath
166 if not GlobalData
.gConfDirectory
:
167 GlobalData
.gConfDirectory
= GenFdsGlobalVariable
.ConfDir
168 BuildConfigurationFile
= os
.path
.normpath(os
.path
.join(ConfDirectoryPath
, "target.txt"))
169 if os
.path
.isfile(BuildConfigurationFile
) == True:
170 TargetTxt
= TargetTxtClassObject
.TargetTxtClassObject()
171 TargetTxt
.LoadTargetTxtFile(BuildConfigurationFile
)
172 # if no build target given in command line, get it from target.txt
173 if not GenFdsGlobalVariable
.TargetName
:
174 BuildTargetList
= TargetTxt
.TargetTxtDictionary
[DataType
.TAB_TAT_DEFINES_TARGET
]
175 if len(BuildTargetList
) != 1:
176 EdkLogger
.error("GenFds", OPTION_VALUE_INVALID
, ExtraData
="Only allows one instance for Target.")
177 GenFdsGlobalVariable
.TargetName
= BuildTargetList
[0]
179 # if no tool chain given in command line, get it from target.txt
180 if not GenFdsGlobalVariable
.ToolChainTag
:
181 ToolChainList
= TargetTxt
.TargetTxtDictionary
[DataType
.TAB_TAT_DEFINES_TOOL_CHAIN_TAG
]
182 if ToolChainList
is None or len(ToolChainList
) == 0:
183 EdkLogger
.error("GenFds", RESOURCE_NOT_AVAILABLE
, ExtraData
="No toolchain given. Don't know how to build.")
184 if len(ToolChainList
) != 1:
185 EdkLogger
.error("GenFds", OPTION_VALUE_INVALID
, ExtraData
="Only allows one instance for ToolChain.")
186 GenFdsGlobalVariable
.ToolChainTag
= ToolChainList
[0]
188 EdkLogger
.error("GenFds", FILE_NOT_FOUND
, ExtraData
=BuildConfigurationFile
)
190 #Set global flag for build mode
191 GlobalData
.gIgnoreSource
= Options
.IgnoreSources
194 for Pair
in Options
.Macros
:
195 if Pair
.startswith('"'):
197 if Pair
.endswith('"'):
199 List
= Pair
.split('=')
201 if not List
[1].strip():
202 EdkLogger
.error("GenFds", OPTION_VALUE_INVALID
, ExtraData
="No Value given for Macro %s" %List
[0])
203 if List
[0].strip() == "EFI_SOURCE":
204 GlobalData
.gEfiSource
= List
[1].strip()
205 GlobalData
.gGlobalDefines
["EFI_SOURCE"] = GlobalData
.gEfiSource
207 elif List
[0].strip() == "EDK_SOURCE":
208 GlobalData
.gEdkSource
= List
[1].strip()
209 GlobalData
.gGlobalDefines
["EDK_SOURCE"] = GlobalData
.gEdkSource
211 elif List
[0].strip() in ["WORKSPACE", "TARGET", "TOOLCHAIN"]:
212 GlobalData
.gGlobalDefines
[List
[0].strip()] = List
[1].strip()
214 GlobalData
.gCommandLineDefines
[List
[0].strip()] = List
[1].strip()
216 GlobalData
.gCommandLineDefines
[List
[0].strip()] = "TRUE"
217 os
.environ
["WORKSPACE"] = Workspace
219 # Use the -t and -b option as gGlobalDefines's TOOLCHAIN and TARGET if they are not defined
220 if "TARGET" not in GlobalData
.gGlobalDefines
:
221 GlobalData
.gGlobalDefines
["TARGET"] = GenFdsGlobalVariable
.TargetName
222 if "TOOLCHAIN" not in GlobalData
.gGlobalDefines
:
223 GlobalData
.gGlobalDefines
["TOOLCHAIN"] = GenFdsGlobalVariable
.ToolChainTag
224 if "TOOL_CHAIN_TAG" not in GlobalData
.gGlobalDefines
:
225 GlobalData
.gGlobalDefines
['TOOL_CHAIN_TAG'] = GenFdsGlobalVariable
.ToolChainTag
227 """call Workspace build create database"""
228 GlobalData
.gDatabasePath
= os
.path
.normpath(os
.path
.join(ConfDirectoryPath
, GlobalData
.gDatabasePath
))
229 BuildWorkSpace
= WorkspaceDatabase(GlobalData
.gDatabasePath
)
230 BuildWorkSpace
.InitDatabase()
233 # Get files real name in workspace dir
235 GlobalData
.gAllFiles
= DirCache(Workspace
)
236 GlobalData
.gWorkspace
= Workspace
238 if (Options
.archList
) :
239 ArchList
= Options
.archList
.split(',')
241 # EdkLogger.error("GenFds", OPTION_MISSING, "Missing build ARCH")
242 ArchList
= BuildWorkSpace
.BuildObject
[GenFdsGlobalVariable
.ActivePlatform
, TAB_COMMON
, Options
.BuildTarget
, Options
.ToolChain
].SupArchList
244 TargetArchList
= set(BuildWorkSpace
.BuildObject
[GenFdsGlobalVariable
.ActivePlatform
, TAB_COMMON
, Options
.BuildTarget
, Options
.ToolChain
].SupArchList
) & set(ArchList
)
245 if len(TargetArchList
) == 0:
246 EdkLogger
.error("GenFds", GENFDS_ERROR
, "Target ARCH %s not in platform supported ARCH %s" % (str(ArchList
), str(BuildWorkSpace
.BuildObject
[GenFdsGlobalVariable
.ActivePlatform
, TAB_COMMON
].SupArchList
)))
248 for Arch
in ArchList
:
249 GenFdsGlobalVariable
.OutputDirFromDscDict
[Arch
] = NormPath(BuildWorkSpace
.BuildObject
[GenFdsGlobalVariable
.ActivePlatform
, Arch
, Options
.BuildTarget
, Options
.ToolChain
].OutputDirectory
)
250 GenFdsGlobalVariable
.PlatformName
= BuildWorkSpace
.BuildObject
[GenFdsGlobalVariable
.ActivePlatform
, Arch
, Options
.BuildTarget
, Options
.ToolChain
].PlatformName
252 if (Options
.outputDir
):
253 OutputDirFromCommandLine
= GenFdsGlobalVariable
.ReplaceWorkspaceMacro(Options
.outputDir
)
254 if not os
.path
.isabs (OutputDirFromCommandLine
):
255 OutputDirFromCommandLine
= os
.path
.join(GenFdsGlobalVariable
.WorkSpaceDir
, OutputDirFromCommandLine
)
256 for Arch
in ArchList
:
257 GenFdsGlobalVariable
.OutputDirDict
[Arch
] = OutputDirFromCommandLine
259 for Arch
in ArchList
:
260 GenFdsGlobalVariable
.OutputDirDict
[Arch
] = os
.path
.join(GenFdsGlobalVariable
.OutputDirFromDscDict
[Arch
], GenFdsGlobalVariable
.TargetName
+ '_' + GenFdsGlobalVariable
.ToolChainTag
)
262 for Key
in GenFdsGlobalVariable
.OutputDirDict
:
263 OutputDir
= GenFdsGlobalVariable
.OutputDirDict
[Key
]
264 if OutputDir
[0:2] == '..':
265 OutputDir
= os
.path
.realpath(OutputDir
)
267 if OutputDir
[1] != ':':
268 OutputDir
= os
.path
.join (GenFdsGlobalVariable
.WorkSpaceDir
, OutputDir
)
270 if not os
.path
.exists(OutputDir
):
271 EdkLogger
.error("GenFds", FILE_NOT_FOUND
, ExtraData
=OutputDir
)
272 GenFdsGlobalVariable
.OutputDirDict
[Key
] = OutputDir
274 """ Parse Fdf file, has to place after build Workspace as FDF may contain macros from DSC file """
275 FdfParserObj
= FdfParser
.FdfParser(FdfFilename
)
276 FdfParserObj
.ParseFile()
278 if FdfParserObj
.CycleReferenceCheck():
279 EdkLogger
.error("GenFds", FORMAT_NOT_SUPPORTED
, "Cycle Reference Detected in FDF file")
281 if (Options
.uiFdName
) :
282 if Options
.uiFdName
.upper() in FdfParserObj
.Profile
.FdDict
:
283 GenFds
.OnlyGenerateThisFd
= Options
.uiFdName
285 EdkLogger
.error("GenFds", OPTION_VALUE_INVALID
,
286 "No such an FD in FDF file: %s" % Options
.uiFdName
)
288 if (Options
.uiFvName
) :
289 if Options
.uiFvName
.upper() in FdfParserObj
.Profile
.FvDict
:
290 GenFds
.OnlyGenerateThisFv
= Options
.uiFvName
292 EdkLogger
.error("GenFds", OPTION_VALUE_INVALID
,
293 "No such an FV in FDF file: %s" % Options
.uiFvName
)
295 if (Options
.uiCapName
) :
296 if Options
.uiCapName
.upper() in FdfParserObj
.Profile
.CapsuleDict
:
297 GenFds
.OnlyGenerateThisCap
= Options
.uiCapName
299 EdkLogger
.error("GenFds", OPTION_VALUE_INVALID
,
300 "No such a Capsule in FDF file: %s" % Options
.uiCapName
)
302 GenFdsGlobalVariable
.WorkSpace
= BuildWorkSpace
303 if ArchList
is not None:
304 GenFdsGlobalVariable
.ArchList
= ArchList
306 # Dsc Build Data will handle Pcd Settings from CommandLine.
308 """Modify images from build output if the feature of loading driver at fixed address is on."""
309 if GenFdsGlobalVariable
.FixedLoadAddress
:
310 GenFds
.PreprocessImage(BuildWorkSpace
, GenFdsGlobalVariable
.ActivePlatform
)
312 # Record the FV Region info that may specific in the FD
313 if FdfParserObj
.Profile
.FvDict
and FdfParserObj
.Profile
.FdDict
:
314 for Fv
in FdfParserObj
.Profile
.FvDict
:
315 FvObj
= FdfParserObj
.Profile
.FvDict
[Fv
]
316 for Fd
in FdfParserObj
.Profile
.FdDict
:
317 FdObj
= FdfParserObj
.Profile
.FdDict
[Fd
]
318 for RegionObj
in FdObj
.RegionList
:
319 if RegionObj
.RegionType
!= BINARY_FILE_TYPE_FV
:
321 for RegionData
in RegionObj
.RegionDataList
:
322 if FvObj
.UiFvName
.upper() == RegionData
.upper():
323 if FvObj
.FvRegionInFD
:
324 if FvObj
.FvRegionInFD
!= RegionObj
.Size
:
325 EdkLogger
.error("GenFds", FORMAT_INVALID
, "The FV %s's region is specified in multiple FD with different value." %FvObj
.UiFvName
)
327 FvObj
.FvRegionInFD
= RegionObj
.Size
328 RegionObj
.BlockInfoOfRegion(FdObj
.BlockSizeList
, FvObj
)
331 GenFds
.GenFd('', FdfParserObj
, BuildWorkSpace
, ArchList
)
333 """Generate GUID cross reference file"""
334 GenFds
.GenerateGuidXRefFile(BuildWorkSpace
, ArchList
, FdfParserObj
)
336 """Display FV space info."""
337 GenFds
.DisplayFvSpaceInfo(FdfParserObj
)
339 except FdfParser
.Warning as X
:
340 EdkLogger
.error(X
.ToolName
, FORMAT_INVALID
, File
=X
.FileName
, Line
=X
.LineNumber
, ExtraData
=X
.Message
, RaiseError
=False)
341 ReturnCode
= FORMAT_INVALID
342 except FatalError
as X
:
343 if Options
.debug
is not None:
345 EdkLogger
.quiet(traceback
.format_exc())
346 ReturnCode
= X
.args
[0]
352 "Tools code failure",
353 ExtraData
="Please send email to edk2-devel@lists.01.org for help, attaching following call stack trace!\n",
356 EdkLogger
.quiet(traceback
.format_exc())
357 ReturnCode
= CODE_ERROR
363 def SingleCheckCallback(option
, opt_str
, value
, parser
):
364 if option
not in gParamCheck
:
365 setattr(parser
.values
, option
.dest
, value
)
366 gParamCheck
.append(option
)
368 parser
.error("Option %s only allows one instance in command line!" % option
)
372 # Find location of tools to process data
374 # @param KeyStringList Filter for inputs of section generation
375 # @param CurrentArchList Arch list
376 # @param NameGuid The Guid name
378 def FindExtendTool(KeyStringList
, CurrentArchList
, NameGuid
):
379 ToolDb
= ToolDefClassObject
.ToolDefDict(GenFdsGlobalVariable
.ConfDir
).ToolsDefTxtDatabase
380 # if user not specify filter, try to deduce it from global data.
381 if KeyStringList
is None or KeyStringList
== []:
382 Target
= GenFdsGlobalVariable
.TargetName
383 ToolChain
= GenFdsGlobalVariable
.ToolChainTag
384 if ToolChain
not in ToolDb
['TOOL_CHAIN_TAG']:
385 EdkLogger
.error("GenFds", GENFDS_ERROR
, "Can not find external tool because tool tag %s is not defined in tools_def.txt!" % ToolChain
)
386 KeyStringList
= [Target
+ '_' + ToolChain
+ '_' + CurrentArchList
[0]]
387 for Arch
in CurrentArchList
:
388 if Target
+ '_' + ToolChain
+ '_' + Arch
not in KeyStringList
:
389 KeyStringList
.append(Target
+ '_' + ToolChain
+ '_' + Arch
)
391 if GenFdsGlobalVariable
.GuidToolDefinition
:
392 if NameGuid
in GenFdsGlobalVariable
.GuidToolDefinition
:
393 return GenFdsGlobalVariable
.GuidToolDefinition
[NameGuid
]
395 ToolDefinition
= ToolDefClassObject
.ToolDefDict(GenFdsGlobalVariable
.ConfDir
).ToolsDefTxtDictionary
401 for ToolDef
in ToolDefinition
.items():
402 if NameGuid
.lower() == ToolDef
[1].lower() :
403 KeyList
= ToolDef
[0].split('_')
409 if Key
in KeyStringList
and KeyList
[4] == TAB_GUID
:
410 ToolPathKey
= Key
+ '_' + KeyList
[3] + '_PATH'
411 ToolOptionKey
= Key
+ '_' + KeyList
[3] + '_FLAGS'
412 ToolPath
= ToolDefinition
.get(ToolPathKey
)
413 ToolOption
= ToolDefinition
.get(ToolOptionKey
)
414 if ToolPathTmp
is None:
415 ToolPathTmp
= ToolPath
417 if ToolPathTmp
!= ToolPath
:
418 EdkLogger
.error("GenFds", GENFDS_ERROR
, "Don't know which tool to use, %s or %s ?" % (ToolPathTmp
, ToolPath
))
421 for Arch
in CurrentArchList
:
422 Platform
= GenFdsGlobalVariable
.WorkSpace
.BuildObject
[GenFdsGlobalVariable
.ActivePlatform
, Arch
, GenFdsGlobalVariable
.TargetName
, GenFdsGlobalVariable
.ToolChainTag
]
423 # key is (ToolChainFamily, ToolChain, CodeBase)
424 for item
in Platform
.BuildOptions
:
425 if '_PATH' in item
[1] or '_FLAGS' in item
[1] or '_GUID' in item
[1]:
426 if not item
[0] or (item
[0] and GenFdsGlobalVariable
.ToolChainFamily
== item
[0]):
427 if item
[1] not in BuildOption
:
428 BuildOption
[item
[1]] = Platform
.BuildOptions
[item
]
430 ToolList
= [TAB_TOD_DEFINES_TARGET
, TAB_TOD_DEFINES_TOOL_CHAIN_TAG
, TAB_TOD_DEFINES_TARGET_ARCH
]
431 for Index
in range(2, -1, -1):
432 for Key
in list(BuildOption
.keys()):
433 List
= Key
.split('_')
434 if List
[Index
] == '*':
435 for String
in ToolDb
[ToolList
[Index
]]:
436 if String
in [Arch
, GenFdsGlobalVariable
.TargetName
, GenFdsGlobalVariable
.ToolChainTag
]:
438 NewKey
= '%s_%s_%s_%s_%s' % tuple(List
)
439 if NewKey
not in BuildOption
:
440 BuildOption
[NewKey
] = BuildOption
[Key
]
443 elif List
[Index
] not in ToolDb
[ToolList
[Index
]]:
447 for Op
in BuildOption
:
448 if NameGuid
== BuildOption
[Op
]:
449 KeyList
= Op
.split('_')
450 Key
= KeyList
[0] + '_' + KeyList
[1] +'_' + KeyList
[2]
451 if Key
in KeyStringList
and KeyList
[4] == TAB_GUID
:
452 ToolPathKey
= Key
+ '_' + KeyList
[3] + '_PATH'
453 ToolOptionKey
= Key
+ '_' + KeyList
[3] + '_FLAGS'
454 if ToolPathKey
in BuildOption
:
455 ToolPathTmp
= BuildOption
[ToolPathKey
]
456 if ToolOptionKey
in BuildOption
:
457 ToolOption
= BuildOption
[ToolOptionKey
]
459 GenFdsGlobalVariable
.GuidToolDefinition
[NameGuid
] = (ToolPathTmp
, ToolOption
)
460 return ToolPathTmp
, ToolOption
462 ## Parse command line options
464 # Using standard Python module optparse to parse command line option of this tool.
466 # @retval Opt A optparse.Values object containing the parsed options
467 # @retval Args Target of build command
469 def myOptionParser():
470 usage
= "%prog [options] -f input_file -a arch_list -b build_target -p active_platform -t tool_chain_tag -D \"MacroName [= MacroValue]\""
471 Parser
= OptionParser(usage
=usage
, description
=__copyright__
, version
="%prog " + str(versionNumber
))
472 Parser
.add_option("-f", "--file", dest
="filename", type="string", help="Name of FDF file to convert", action
="callback", callback
=SingleCheckCallback
)
473 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")
474 Parser
.add_option("-q", "--quiet", action
="store_true", type=None, help="Disable all messages except FATAL ERRORS.")
475 Parser
.add_option("-v", "--verbose", action
="store_true", type=None, help="Turn on verbose output with informational messages printed.")
476 Parser
.add_option("-d", "--debug", action
="store", type="int", help="Enable debug messages at specified level.")
477 Parser
.add_option("-p", "--platform", type="string", dest
="activePlatform", help="Set the ACTIVE_PLATFORM, overrides target.txt ACTIVE_PLATFORM setting.",
478 action
="callback", callback
=SingleCheckCallback
)
479 Parser
.add_option("-w", "--workspace", type="string", dest
="Workspace", default
=os
.environ
.get('WORKSPACE'), help="Set the WORKSPACE",
480 action
="callback", callback
=SingleCheckCallback
)
481 Parser
.add_option("-o", "--outputDir", type="string", dest
="outputDir", help="Name of Build Output directory",
482 action
="callback", callback
=SingleCheckCallback
)
483 Parser
.add_option("-r", "--rom_image", dest
="uiFdName", help="Build the image using the [FD] section named by FdUiName.")
484 Parser
.add_option("-i", "--FvImage", dest
="uiFvName", help="Build the FV image using the [FV] section named by UiFvName")
485 Parser
.add_option("-C", "--CapsuleImage", dest
="uiCapName", help="Build the Capsule image using the [Capsule] section named by UiCapName")
486 Parser
.add_option("-b", "--buildtarget", type="string", dest
="BuildTarget", help="Set the build TARGET, overrides target.txt TARGET setting.",
487 action
="callback", callback
=SingleCheckCallback
)
488 Parser
.add_option("-t", "--tagname", type="string", dest
="ToolChain", help="Using the tools: TOOL_CHAIN_TAG name to build the platform.",
489 action
="callback", callback
=SingleCheckCallback
)
490 Parser
.add_option("-D", "--define", action
="append", type="string", dest
="Macros", help="Macro: \"Name [= Value]\".")
491 Parser
.add_option("-s", "--specifyaddress", dest
="FixedAddress", action
="store_true", type=None, help="Specify driver load address.")
492 Parser
.add_option("--conf", action
="store", type="string", dest
="ConfDirectory", help="Specify the customized Conf directory.")
493 Parser
.add_option("--ignore-sources", action
="store_true", dest
="IgnoreSources", default
=False, help="Focus to a binary build and ignore all source files")
494 Parser
.add_option("--pcd", action
="append", dest
="OptionPcd", help="Set PCD value by command line. Format: \"PcdName=Value\" ")
495 Parser
.add_option("--genfds-multi-thread", action
="store_true", dest
="GenfdsMultiThread", default
=False, help="Enable GenFds multi thread to generate ffs file.")
497 (Options
, args
) = Parser
.parse_args()
500 ## The class implementing the EDK2 flash image generation process
502 # This process includes:
503 # 1. Collect workspace information, includes platform and module information
504 # 2. Call methods of Fd class to generate FD
505 # 3. Call methods of Fv class to generate FV that not belong to FD
509 # FvName, FdName, CapName in FDF, Image file name
511 OnlyGenerateThisFd
= None
512 OnlyGenerateThisFv
= None
513 OnlyGenerateThisCap
= None
517 # @param OutputDir Output directory
518 # @param FdfParser FDF contents parser
519 # @param Workspace The directory of workspace
520 # @param ArchList The Arch list of platform
522 def GenFd (OutputDir
, FdfParser
, WorkSpace
, ArchList
):
523 GenFdsGlobalVariable
.SetDir ('', FdfParser
, WorkSpace
, ArchList
)
525 GenFdsGlobalVariable
.VerboseLogger(" Generate all Fd images and their required FV and Capsule images!")
526 if GenFds
.OnlyGenerateThisCap
is not None and GenFds
.OnlyGenerateThisCap
.upper() in GenFdsGlobalVariable
.FdfParser
.Profile
.CapsuleDict
:
527 CapsuleObj
= GenFdsGlobalVariable
.FdfParser
.Profile
.CapsuleDict
[GenFds
.OnlyGenerateThisCap
.upper()]
528 if CapsuleObj
is not None:
529 CapsuleObj
.GenCapsule()
532 if GenFds
.OnlyGenerateThisFd
is not None and GenFds
.OnlyGenerateThisFd
.upper() in GenFdsGlobalVariable
.FdfParser
.Profile
.FdDict
:
533 FdObj
= GenFdsGlobalVariable
.FdfParser
.Profile
.FdDict
[GenFds
.OnlyGenerateThisFd
.upper()]
534 if FdObj
is not None:
537 elif GenFds
.OnlyGenerateThisFd
is None and GenFds
.OnlyGenerateThisFv
is None:
538 for FdObj
in GenFdsGlobalVariable
.FdfParser
.Profile
.FdDict
.values():
541 GenFdsGlobalVariable
.VerboseLogger("\n Generate other FV images! ")
542 if GenFds
.OnlyGenerateThisFv
is not None and GenFds
.OnlyGenerateThisFv
.upper() in GenFdsGlobalVariable
.FdfParser
.Profile
.FvDict
:
543 FvObj
= GenFdsGlobalVariable
.FdfParser
.Profile
.FvDict
[GenFds
.OnlyGenerateThisFv
.upper()]
544 if FvObj
is not None:
545 Buffer
= StringIO
.StringIO()
546 FvObj
.AddToBuffer(Buffer
)
549 elif GenFds
.OnlyGenerateThisFv
is None:
550 for FvObj
in GenFdsGlobalVariable
.FdfParser
.Profile
.FvDict
.values():
551 Buffer
= StringIO
.StringIO('')
552 FvObj
.AddToBuffer(Buffer
)
555 if GenFds
.OnlyGenerateThisFv
is None and GenFds
.OnlyGenerateThisFd
is None and GenFds
.OnlyGenerateThisCap
is None:
556 if GenFdsGlobalVariable
.FdfParser
.Profile
.CapsuleDict
!= {}:
557 GenFdsGlobalVariable
.VerboseLogger("\n Generate other Capsule images!")
558 for CapsuleObj
in GenFdsGlobalVariable
.FdfParser
.Profile
.CapsuleDict
.values():
559 CapsuleObj
.GenCapsule()
561 if GenFdsGlobalVariable
.FdfParser
.Profile
.OptRomDict
!= {}:
562 GenFdsGlobalVariable
.VerboseLogger("\n Generate all Option ROM!")
563 for OptRomObj
in GenFdsGlobalVariable
.FdfParser
.Profile
.OptRomDict
.values():
564 OptRomObj
.AddToBuffer(None)
566 def GenFfsMakefile(OutputDir
, FdfParser
, WorkSpace
, ArchList
, GlobalData
):
567 GenFdsGlobalVariable
.SetEnv(FdfParser
, WorkSpace
, ArchList
, GlobalData
)
568 for FdObj
in GenFdsGlobalVariable
.FdfParser
.Profile
.FdDict
.values():
569 FdObj
.GenFd(Flag
=True)
571 for FvObj
in GenFdsGlobalVariable
.FdfParser
.Profile
.FvDict
.values():
572 FvObj
.AddToBuffer(Buffer
=None, Flag
=True)
574 if GenFdsGlobalVariable
.FdfParser
.Profile
.OptRomDict
!= {}:
575 for OptRomObj
in GenFdsGlobalVariable
.FdfParser
.Profile
.OptRomDict
.values():
576 OptRomObj
.AddToBuffer(Buffer
=None, Flag
=True)
578 return GenFdsGlobalVariable
.FfsCmdDict
582 # @param FvObj Whose block size to get
583 # @retval int Block size value
585 def GetFvBlockSize(FvObj
):
586 DefaultBlockSize
= 0x1
588 if GenFds
.OnlyGenerateThisFd
is not None and GenFds
.OnlyGenerateThisFd
.upper() in GenFdsGlobalVariable
.FdfParser
.Profile
.FdDict
:
589 FdObj
= GenFdsGlobalVariable
.FdfParser
.Profile
.FdDict
[GenFds
.OnlyGenerateThisFd
.upper()]
591 for ElementFd
in GenFdsGlobalVariable
.FdfParser
.Profile
.FdDict
.values():
592 for ElementRegion
in ElementFd
.RegionList
:
593 if ElementRegion
.RegionType
== BINARY_FILE_TYPE_FV
:
594 for ElementRegionData
in ElementRegion
.RegionDataList
:
595 if ElementRegionData
is not None and ElementRegionData
.upper() == FvObj
.UiFvName
:
596 if FvObj
.BlockSizeList
!= []:
597 return FvObj
.BlockSizeList
[0][0]
599 return ElementRegion
.BlockSizeOfRegion(ElementFd
.BlockSizeList
)
600 if FvObj
.BlockSizeList
!= []:
601 return FvObj
.BlockSizeList
[0][0]
602 return DefaultBlockSize
604 for ElementRegion
in FdObj
.RegionList
:
605 if ElementRegion
.RegionType
== BINARY_FILE_TYPE_FV
:
606 for ElementRegionData
in ElementRegion
.RegionDataList
:
607 if ElementRegionData
is not None and ElementRegionData
.upper() == FvObj
.UiFvName
:
608 if FvObj
.BlockSizeList
!= []:
609 return FvObj
.BlockSizeList
[0][0]
611 return ElementRegion
.BlockSizeOfRegion(ElementFd
.BlockSizeList
)
612 return DefaultBlockSize
614 ## DisplayFvSpaceInfo()
616 # @param FvObj Whose block size to get
619 def DisplayFvSpaceInfo(FdfParser
):
623 for FvName
in FdfParser
.Profile
.FvDict
:
624 if len(FvName
) > MaxFvNameLength
:
625 MaxFvNameLength
= len(FvName
)
626 FvSpaceInfoFileName
= os
.path
.join(GenFdsGlobalVariable
.FvDir
, FvName
.upper() + '.Fv.map')
627 if os
.path
.exists(FvSpaceInfoFileName
):
628 FileLinesList
= linecache
.getlines(FvSpaceInfoFileName
)
635 for Line
in FileLinesList
:
636 NameValue
= Line
.split('=')
637 if len(NameValue
) == 2:
638 if NameValue
[0].strip() == 'EFI_FV_TOTAL_SIZE':
640 Total
= NameValue
[1].strip()
641 if NameValue
[0].strip() == 'EFI_FV_TAKEN_SIZE':
643 Used
= NameValue
[1].strip()
644 if NameValue
[0].strip() == 'EFI_FV_SPACE_SIZE':
646 Free
= NameValue
[1].strip()
648 if TotalFound
and UsedFound
and FreeFound
:
649 FvSpaceInfoList
.append((FvName
, Total
, Used
, Free
))
651 GenFdsGlobalVariable
.InfLogger('\nFV Space Information')
652 for FvSpaceInfo
in FvSpaceInfoList
:
653 Name
= FvSpaceInfo
[0]
654 TotalSizeValue
= long(FvSpaceInfo
[1], 0)
655 UsedSizeValue
= long(FvSpaceInfo
[2], 0)
656 FreeSizeValue
= long(FvSpaceInfo
[3], 0)
657 if UsedSizeValue
== TotalSizeValue
:
660 Percentage
= str((UsedSizeValue
+ 0.0) / TotalSizeValue
)[0:4].lstrip('0.')
662 GenFdsGlobalVariable
.InfLogger(Name
+ ' ' + '[' + Percentage
+ '%Full] ' + str(TotalSizeValue
) + ' total, ' + str(UsedSizeValue
) + ' used, ' + str(FreeSizeValue
) + ' free')
666 # @param BuildDb Database from build meta data files
667 # @param DscFile modules from dsc file will be preprocessed
670 def PreprocessImage(BuildDb
, DscFile
):
671 PcdDict
= BuildDb
.BuildObject
[DscFile
, TAB_COMMON
, GenFdsGlobalVariable
.TargetName
, GenFdsGlobalVariable
.ToolChainTag
].Pcds
674 PcdObj
= PcdDict
[Key
]
675 if PcdObj
.TokenCName
== 'PcdBsBaseAddress':
676 PcdValue
= PcdObj
.DefaultValue
682 Int64PcdValue
= long(PcdValue
, 0)
683 if Int64PcdValue
== 0 or Int64PcdValue
< -1:
687 if Int64PcdValue
> 0:
688 TopAddress
= Int64PcdValue
690 ModuleDict
= BuildDb
.BuildObject
[DscFile
, TAB_COMMON
, GenFdsGlobalVariable
.TargetName
, GenFdsGlobalVariable
.ToolChainTag
].Modules
691 for Key
in ModuleDict
:
692 ModuleObj
= BuildDb
.BuildObject
[Key
, TAB_COMMON
, GenFdsGlobalVariable
.TargetName
, GenFdsGlobalVariable
.ToolChainTag
]
693 print(ModuleObj
.BaseName
+ ' ' + ModuleObj
.ModuleType
)
695 def GenerateGuidXRefFile(BuildDb
, ArchList
, FdfParserObj
):
696 GuidXRefFileName
= os
.path
.join(GenFdsGlobalVariable
.FvDir
, "Guid.xref")
697 GuidXRefFile
= StringIO
.StringIO('')
701 for Arch
in ArchList
:
702 PlatformDataBase
= BuildDb
.BuildObject
[GenFdsGlobalVariable
.ActivePlatform
, Arch
, GenFdsGlobalVariable
.TargetName
, GenFdsGlobalVariable
.ToolChainTag
]
703 for ModuleFile
in PlatformDataBase
.Modules
:
704 Module
= BuildDb
.BuildObject
[ModuleFile
, Arch
, GenFdsGlobalVariable
.TargetName
, GenFdsGlobalVariable
.ToolChainTag
]
705 if Module
in ModuleList
:
708 ModuleList
.append(Module
)
709 GuidXRefFile
.write("%s %s\n" % (Module
.Guid
, Module
.BaseName
))
710 for key
, item
in Module
.Protocols
.items():
712 for key
, item
in Module
.Guids
.items():
714 for key
, item
in Module
.Ppis
.items():
716 for FvName
in FdfParserObj
.Profile
.FvDict
:
717 for FfsObj
in FdfParserObj
.Profile
.FvDict
[FvName
].FfsList
:
718 if not isinstance(FfsObj
, FfsFileStatement
.FileStatement
):
719 InfPath
= PathClass(NormPath(mws
.join(GenFdsGlobalVariable
.WorkSpaceDir
, FfsObj
.InfFileName
)))
720 FdfModule
= BuildDb
.BuildObject
[InfPath
, Arch
, GenFdsGlobalVariable
.TargetName
, GenFdsGlobalVariable
.ToolChainTag
]
721 if FdfModule
in ModuleList
:
724 ModuleList
.append(FdfModule
)
725 GuidXRefFile
.write("%s %s\n" % (FdfModule
.Guid
, FdfModule
.BaseName
))
726 for key
, item
in FdfModule
.Protocols
.items():
728 for key
, item
in FdfModule
.Guids
.items():
730 for key
, item
in FdfModule
.Ppis
.items():
733 FileStatementGuid
= FfsObj
.NameGuid
734 if FileStatementGuid
in FileGuidList
:
737 FileGuidList
.append(FileStatementGuid
)
739 FfsPath
= os
.path
.join(GenFdsGlobalVariable
.FvDir
, 'Ffs')
740 FfsPath
= glob
.glob(os
.path
.join(FfsPath
, FileStatementGuid
) + '*')
743 if not os
.path
.exists(FfsPath
[0]):
746 ReFileEnds
= re
.compile('\S+(.ui)$|\S+(fv.sec.txt)$|\S+(.pe32.txt)$|\S+(.te.txt)$|\S+(.pic.txt)$|\S+(.raw.txt)$|\S+(.ffs.txt)$')
747 FileList
= os
.listdir(FfsPath
[0])
748 for File
in FileList
:
749 Match
= ReFileEnds
.search(File
)
751 for Index
in range(1, 8):
752 if Match
.group(Index
) and Match
.group(Index
) in MatchDict
:
753 MatchDict
[Match
.group(Index
)].append(File
)
754 elif Match
.group(Index
):
755 MatchDict
[Match
.group(Index
)] = [File
]
758 if '.ui' in MatchDict
:
759 for File
in MatchDict
['.ui']:
760 with
open(os
.path
.join(FfsPath
[0], File
), 'rb') as F
:
764 TmpStr
= unpack('%dh' % ((length
- 4) / 2), F
.read())
765 Name
= ''.join(chr(c
) for c
in TmpStr
[:-1])
768 if 'fv.sec.txt' in MatchDict
:
769 FileList
= MatchDict
['fv.sec.txt']
770 elif '.pe32.txt' in MatchDict
:
771 FileList
= MatchDict
['.pe32.txt']
772 elif '.te.txt' in MatchDict
:
773 FileList
= MatchDict
['.te.txt']
774 elif '.pic.txt' in MatchDict
:
775 FileList
= MatchDict
['.pic.txt']
776 elif '.raw.txt' in MatchDict
:
777 FileList
= MatchDict
['.raw.txt']
778 elif '.ffs.txt' in MatchDict
:
779 FileList
= MatchDict
['.ffs.txt']
782 for File
in FileList
:
783 with
open(os
.path
.join(FfsPath
[0], File
), 'r') as F
:
784 Name
.append((F
.read().split()[-1]))
788 Name
= ' '.join(Name
) if isinstance(Name
, type([])) else Name
789 GuidXRefFile
.write("%s %s\n" %(FileStatementGuid
, Name
))
791 # Append GUIDs, Protocols, and PPIs to the Xref file
792 GuidXRefFile
.write("\n")
793 for key
, item
in GuidDict
.items():
794 GuidXRefFile
.write("%s %s\n" % (GuidStructureStringToGuidString(item
).upper(), key
))
796 if GuidXRefFile
.getvalue():
797 SaveFileOnChange(GuidXRefFileName
, GuidXRefFile
.getvalue(), False)
798 GenFdsGlobalVariable
.InfLogger("\nGUID cross reference file can be found at %s" % GuidXRefFileName
)
799 elif os
.path
.exists(GuidXRefFileName
):
800 os
.remove(GuidXRefFileName
)
803 ##Define GenFd as static function
804 GenFd
= staticmethod(GenFd
)
805 GetFvBlockSize
= staticmethod(GetFvBlockSize
)
806 DisplayFvSpaceInfo
= staticmethod(DisplayFvSpaceInfo
)
807 PreprocessImage
= staticmethod(PreprocessImage
)
808 GenerateGuidXRefFile
= staticmethod(GenerateGuidXRefFile
)
810 if __name__
== '__main__':
812 ## 0-127 is a safe return range, and 1 is a standard default error
813 if r
< 0 or r
> 127: r
= 1