4 # Copyright (c) 2007 - 2019, Intel Corporation. All rights reserved.<BR>
6 # SPDX-License-Identifier: BSD-2-Clause-Patent
12 from __future__
import print_function
13 from __future__
import absolute_import
14 from re
import compile
15 from optparse
import OptionParser
18 from struct
import unpack
19 from linecache
import getlines
20 from io
import BytesIO
22 import Common
.LongFilePathOs
as os
23 from Common
.TargetTxtClassObject
import TargetTxtDict
24 from Common
.DataType
import *
25 import Common
.GlobalData
as GlobalData
26 from Common
import EdkLogger
27 from Common
.StringUtils
import NormPath
28 from Common
.Misc
import DirCache
, PathClass
, GuidStructureStringToGuidString
29 from Common
.Misc
import SaveFileOnChange
, ClearDuplicatedInf
30 from Common
.BuildVersion
import gBUILD_VERSION
31 from Common
.MultipleWorkspace
import MultipleWorkspace
as mws
32 from Common
.BuildToolError
import FatalError
, GENFDS_ERROR
, CODE_ERROR
, FORMAT_INVALID
, RESOURCE_NOT_AVAILABLE
, FILE_NOT_FOUND
, OPTION_MISSING
, FORMAT_NOT_SUPPORTED
, OPTION_VALUE_INVALID
, PARAMETER_INVALID
33 from Workspace
.WorkspaceDatabase
import WorkspaceDatabase
35 from .FdfParser
import FdfParser
, Warning
36 from .GenFdsGlobalVariable
import GenFdsGlobalVariable
37 from .FfsFileStatement
import FileStatement
38 import Common
.DataType
as DataType
39 from struct
import Struct
41 ## Version and Copyright
42 versionNumber
= "1.0" + ' ' + gBUILD_VERSION
43 __version__
= "%prog Version " + versionNumber
44 __copyright__
= "Copyright (c) 2007 - 2018, Intel Corporation All rights reserved."
46 ## Tool entrance method
48 # This method mainly dispatch specific methods per the command line options.
49 # If no error found, return zero value so the caller of this tool can know
50 # if it's executed successfully or not.
52 # @retval 0 Tool was successful
53 # @retval 1 Tool failed
57 Options
= myOptionParser()
58 EdkLogger
.Initialize()
59 return GenFdsApi(OptionsToCommandDict(Options
))
61 def resetFdsGlobalVariable():
62 GenFdsGlobalVariable
.FvDir
= ''
63 GenFdsGlobalVariable
.OutputDirDict
= {}
64 GenFdsGlobalVariable
.BinDir
= ''
65 # will be FvDir + os.sep + 'Ffs'
66 GenFdsGlobalVariable
.FfsDir
= ''
67 GenFdsGlobalVariable
.FdfParser
= None
68 GenFdsGlobalVariable
.LibDir
= ''
69 GenFdsGlobalVariable
.WorkSpace
= None
70 GenFdsGlobalVariable
.WorkSpaceDir
= ''
71 GenFdsGlobalVariable
.ConfDir
= ''
72 GenFdsGlobalVariable
.OutputDirFromDscDict
= {}
73 GenFdsGlobalVariable
.TargetName
= ''
74 GenFdsGlobalVariable
.ToolChainTag
= ''
75 GenFdsGlobalVariable
.RuleDict
= {}
76 GenFdsGlobalVariable
.ArchList
= None
77 GenFdsGlobalVariable
.ActivePlatform
= None
78 GenFdsGlobalVariable
.FvAddressFileName
= ''
79 GenFdsGlobalVariable
.VerboseMode
= False
80 GenFdsGlobalVariable
.DebugLevel
= -1
81 GenFdsGlobalVariable
.SharpCounter
= 0
82 GenFdsGlobalVariable
.SharpNumberPerLine
= 40
83 GenFdsGlobalVariable
.FdfFile
= ''
84 GenFdsGlobalVariable
.FdfFileTimeStamp
= 0
85 GenFdsGlobalVariable
.FixedLoadAddress
= False
86 GenFdsGlobalVariable
.PlatformName
= ''
88 GenFdsGlobalVariable
.BuildRuleFamily
= DataType
.TAB_COMPILER_MSFT
89 GenFdsGlobalVariable
.ToolChainFamily
= DataType
.TAB_COMPILER_MSFT
90 GenFdsGlobalVariable
.__BuildRuleDatabase
= None
91 GenFdsGlobalVariable
.GuidToolDefinition
= {}
92 GenFdsGlobalVariable
.FfsCmdDict
= {}
93 GenFdsGlobalVariable
.SecCmdList
= []
94 GenFdsGlobalVariable
.CopyList
= []
95 GenFdsGlobalVariable
.ModuleFile
= ''
96 GenFdsGlobalVariable
.EnableGenfdsMultiThread
= True
98 GenFdsGlobalVariable
.LargeFileInFvFlags
= []
99 GenFdsGlobalVariable
.EFI_FIRMWARE_FILE_SYSTEM3_GUID
= '5473C07A-3DCB-4dca-BD6F-1E9689E7349A'
100 GenFdsGlobalVariable
.LARGE_FILE_SIZE
= 0x1000000
102 GenFdsGlobalVariable
.SectionHeader
= Struct("3B 1B")
104 # FvName, FdName, CapName in FDF, Image file name
105 GenFdsGlobalVariable
.ImageBinDict
= {}
107 def GenFdsApi(FdsCommandDict
, WorkSpaceDataBase
=None):
112 resetFdsGlobalVariable()
115 if FdsCommandDict
.get("verbose"):
116 EdkLogger
.SetLevel(EdkLogger
.VERBOSE
)
117 GenFdsGlobalVariable
.VerboseMode
= True
119 if FdsCommandDict
.get("FixedAddress"):
120 GenFdsGlobalVariable
.FixedLoadAddress
= True
122 if FdsCommandDict
.get("quiet"):
123 EdkLogger
.SetLevel(EdkLogger
.QUIET
)
124 if FdsCommandDict
.get("debug"):
125 EdkLogger
.SetLevel(FdsCommandDict
.get("debug") + 1)
126 GenFdsGlobalVariable
.DebugLevel
= FdsCommandDict
.get("debug")
128 EdkLogger
.SetLevel(EdkLogger
.INFO
)
130 if not FdsCommandDict
.get("Workspace",os
.environ
.get('WORKSPACE')):
131 EdkLogger
.error("GenFds", OPTION_MISSING
, "WORKSPACE not defined",
132 ExtraData
="Please use '-w' switch to pass it or set the WORKSPACE environment variable.")
133 elif not os
.path
.exists(FdsCommandDict
.get("Workspace",os
.environ
.get('WORKSPACE'))):
134 EdkLogger
.error("GenFds", PARAMETER_INVALID
, "WORKSPACE is invalid",
135 ExtraData
="Please use '-w' switch to pass it or set the WORKSPACE environment variable.")
137 Workspace
= os
.path
.normcase(FdsCommandDict
.get("Workspace",os
.environ
.get('WORKSPACE')))
138 GenFdsGlobalVariable
.WorkSpaceDir
= Workspace
139 if FdsCommandDict
.get("debug"):
140 GenFdsGlobalVariable
.VerboseLogger("Using Workspace:" + Workspace
)
141 if FdsCommandDict
.get("GenfdsMultiThread"):
142 GenFdsGlobalVariable
.EnableGenfdsMultiThread
= True
144 GenFdsGlobalVariable
.EnableGenfdsMultiThread
= False
145 os
.chdir(GenFdsGlobalVariable
.WorkSpaceDir
)
147 # set multiple workspace
148 PackagesPath
= os
.getenv("PACKAGES_PATH")
149 mws
.setWs(GenFdsGlobalVariable
.WorkSpaceDir
, PackagesPath
)
151 if FdsCommandDict
.get("fdf_file"):
152 FdfFilename
= FdsCommandDict
.get("fdf_file")[0].Path
153 FdfFilename
= GenFdsGlobalVariable
.ReplaceWorkspaceMacro(FdfFilename
)
155 if FdfFilename
[0:2] == '..':
156 FdfFilename
= os
.path
.realpath(FdfFilename
)
157 if not os
.path
.isabs(FdfFilename
):
158 FdfFilename
= mws
.join(GenFdsGlobalVariable
.WorkSpaceDir
, FdfFilename
)
159 if not os
.path
.exists(FdfFilename
):
160 EdkLogger
.error("GenFds", FILE_NOT_FOUND
, ExtraData
=FdfFilename
)
162 GenFdsGlobalVariable
.FdfFile
= FdfFilename
163 GenFdsGlobalVariable
.FdfFileTimeStamp
= os
.path
.getmtime(FdfFilename
)
165 EdkLogger
.error("GenFds", OPTION_MISSING
, "Missing FDF filename")
167 if FdsCommandDict
.get("build_target"):
168 GenFdsGlobalVariable
.TargetName
= FdsCommandDict
.get("build_target")
170 if FdsCommandDict
.get("toolchain_tag"):
171 GenFdsGlobalVariable
.ToolChainTag
= FdsCommandDict
.get("toolchain_tag")
173 if FdsCommandDict
.get("active_platform"):
174 ActivePlatform
= FdsCommandDict
.get("active_platform")
175 ActivePlatform
= GenFdsGlobalVariable
.ReplaceWorkspaceMacro(ActivePlatform
)
177 if ActivePlatform
[0:2] == '..':
178 ActivePlatform
= os
.path
.realpath(ActivePlatform
)
180 if not os
.path
.isabs (ActivePlatform
):
181 ActivePlatform
= mws
.join(GenFdsGlobalVariable
.WorkSpaceDir
, ActivePlatform
)
183 if not os
.path
.exists(ActivePlatform
):
184 EdkLogger
.error("GenFds", FILE_NOT_FOUND
, "ActivePlatform doesn't exist!")
186 EdkLogger
.error("GenFds", OPTION_MISSING
, "Missing active platform")
188 GenFdsGlobalVariable
.ActivePlatform
= PathClass(NormPath(ActivePlatform
))
190 if FdsCommandDict
.get("conf_directory"):
191 # Get alternate Conf location, if it is absolute, then just use the absolute directory name
192 ConfDirectoryPath
= os
.path
.normpath(FdsCommandDict
.get("conf_directory"))
193 if ConfDirectoryPath
.startswith('"'):
194 ConfDirectoryPath
= ConfDirectoryPath
[1:]
195 if ConfDirectoryPath
.endswith('"'):
196 ConfDirectoryPath
= ConfDirectoryPath
[:-1]
197 if not os
.path
.isabs(ConfDirectoryPath
):
198 # Since alternate directory name is not absolute, the alternate directory is located within the WORKSPACE
199 # This also handles someone specifying the Conf directory in the workspace. Using --conf=Conf
200 ConfDirectoryPath
= os
.path
.join(GenFdsGlobalVariable
.WorkSpaceDir
, ConfDirectoryPath
)
202 if "CONF_PATH" in os
.environ
:
203 ConfDirectoryPath
= os
.path
.normcase(os
.environ
["CONF_PATH"])
205 # Get standard WORKSPACE/Conf, use the absolute path to the WORKSPACE/Conf
206 ConfDirectoryPath
= mws
.join(GenFdsGlobalVariable
.WorkSpaceDir
, 'Conf')
207 GenFdsGlobalVariable
.ConfDir
= ConfDirectoryPath
208 if not GlobalData
.gConfDirectory
:
209 GlobalData
.gConfDirectory
= GenFdsGlobalVariable
.ConfDir
210 BuildConfigurationFile
= os
.path
.normpath(os
.path
.join(ConfDirectoryPath
, "target.txt"))
211 if os
.path
.isfile(BuildConfigurationFile
) == True:
212 # if no build target given in command line, get it from target.txt
213 TargetObj
= TargetTxtDict()
214 TargetTxt
= TargetObj
.Target
215 if not GenFdsGlobalVariable
.TargetName
:
216 BuildTargetList
= TargetTxt
.TargetTxtDictionary
[TAB_TAT_DEFINES_TARGET
]
217 if len(BuildTargetList
) != 1:
218 EdkLogger
.error("GenFds", OPTION_VALUE_INVALID
, ExtraData
="Only allows one instance for Target.")
219 GenFdsGlobalVariable
.TargetName
= BuildTargetList
[0]
221 # if no tool chain given in command line, get it from target.txt
222 if not GenFdsGlobalVariable
.ToolChainTag
:
223 ToolChainList
= TargetTxt
.TargetTxtDictionary
[TAB_TAT_DEFINES_TOOL_CHAIN_TAG
]
224 if ToolChainList
is None or len(ToolChainList
) == 0:
225 EdkLogger
.error("GenFds", RESOURCE_NOT_AVAILABLE
, ExtraData
="No toolchain given. Don't know how to build.")
226 if len(ToolChainList
) != 1:
227 EdkLogger
.error("GenFds", OPTION_VALUE_INVALID
, ExtraData
="Only allows one instance for ToolChain.")
228 GenFdsGlobalVariable
.ToolChainTag
= ToolChainList
[0]
230 EdkLogger
.error("GenFds", FILE_NOT_FOUND
, ExtraData
=BuildConfigurationFile
)
232 #Set global flag for build mode
233 GlobalData
.gIgnoreSource
= FdsCommandDict
.get("IgnoreSources")
235 if FdsCommandDict
.get("macro"):
236 for Pair
in FdsCommandDict
.get("macro"):
237 if Pair
.startswith('"'):
239 if Pair
.endswith('"'):
241 List
= Pair
.split('=')
243 if not List
[1].strip():
244 EdkLogger
.error("GenFds", OPTION_VALUE_INVALID
, ExtraData
="No Value given for Macro %s" %List
[0])
245 if List
[0].strip() in ["WORKSPACE", "TARGET", "TOOLCHAIN"]:
246 GlobalData
.gGlobalDefines
[List
[0].strip()] = List
[1].strip()
248 GlobalData
.gCommandLineDefines
[List
[0].strip()] = List
[1].strip()
250 GlobalData
.gCommandLineDefines
[List
[0].strip()] = "TRUE"
251 os
.environ
["WORKSPACE"] = Workspace
253 # Use the -t and -b option as gGlobalDefines's TOOLCHAIN and TARGET if they are not defined
254 if "TARGET" not in GlobalData
.gGlobalDefines
:
255 GlobalData
.gGlobalDefines
["TARGET"] = GenFdsGlobalVariable
.TargetName
256 if "TOOLCHAIN" not in GlobalData
.gGlobalDefines
:
257 GlobalData
.gGlobalDefines
["TOOLCHAIN"] = GenFdsGlobalVariable
.ToolChainTag
258 if "TOOL_CHAIN_TAG" not in GlobalData
.gGlobalDefines
:
259 GlobalData
.gGlobalDefines
['TOOL_CHAIN_TAG'] = GenFdsGlobalVariable
.ToolChainTag
261 """call Workspace build create database"""
262 GlobalData
.gDatabasePath
= os
.path
.normpath(os
.path
.join(ConfDirectoryPath
, GlobalData
.gDatabasePath
))
264 if WorkSpaceDataBase
:
265 BuildWorkSpace
= WorkSpaceDataBase
267 BuildWorkSpace
= WorkspaceDatabase()
269 # Get files real name in workspace dir
271 GlobalData
.gAllFiles
= DirCache(Workspace
)
272 GlobalData
.gWorkspace
= Workspace
274 if FdsCommandDict
.get("build_architecture_list"):
275 ArchList
= FdsCommandDict
.get("build_architecture_list").split(',')
277 ArchList
= BuildWorkSpace
.BuildObject
[GenFdsGlobalVariable
.ActivePlatform
, TAB_COMMON
, FdsCommandDict
.get("build_target"), FdsCommandDict
.get("toolchain_tag")].SupArchList
279 TargetArchList
= set(BuildWorkSpace
.BuildObject
[GenFdsGlobalVariable
.ActivePlatform
, TAB_COMMON
, FdsCommandDict
.get("build_target"), FdsCommandDict
.get("toolchain_tag")].SupArchList
) & set(ArchList
)
280 if len(TargetArchList
) == 0:
281 EdkLogger
.error("GenFds", GENFDS_ERROR
, "Target ARCH %s not in platform supported ARCH %s" % (str(ArchList
), str(BuildWorkSpace
.BuildObject
[GenFdsGlobalVariable
.ActivePlatform
, TAB_COMMON
].SupArchList
)))
283 for Arch
in ArchList
:
284 GenFdsGlobalVariable
.OutputDirFromDscDict
[Arch
] = NormPath(BuildWorkSpace
.BuildObject
[GenFdsGlobalVariable
.ActivePlatform
, Arch
, FdsCommandDict
.get("build_target"), FdsCommandDict
.get("toolchain_tag")].OutputDirectory
)
286 # assign platform name based on last entry in ArchList
287 GenFdsGlobalVariable
.PlatformName
= BuildWorkSpace
.BuildObject
[GenFdsGlobalVariable
.ActivePlatform
, ArchList
[-1], FdsCommandDict
.get("build_target"), FdsCommandDict
.get("toolchain_tag")].PlatformName
289 if FdsCommandDict
.get("platform_build_directory"):
290 OutputDirFromCommandLine
= GenFdsGlobalVariable
.ReplaceWorkspaceMacro(FdsCommandDict
.get("platform_build_directory"))
291 if not os
.path
.isabs (OutputDirFromCommandLine
):
292 OutputDirFromCommandLine
= os
.path
.join(GenFdsGlobalVariable
.WorkSpaceDir
, OutputDirFromCommandLine
)
293 for Arch
in ArchList
:
294 GenFdsGlobalVariable
.OutputDirDict
[Arch
] = OutputDirFromCommandLine
296 for Arch
in ArchList
:
297 GenFdsGlobalVariable
.OutputDirDict
[Arch
] = os
.path
.join(GenFdsGlobalVariable
.OutputDirFromDscDict
[Arch
], GenFdsGlobalVariable
.TargetName
+ '_' + GenFdsGlobalVariable
.ToolChainTag
)
299 for Key
in GenFdsGlobalVariable
.OutputDirDict
:
300 OutputDir
= GenFdsGlobalVariable
.OutputDirDict
[Key
]
301 if OutputDir
[0:2] == '..':
302 OutputDir
= os
.path
.realpath(OutputDir
)
304 if OutputDir
[1] != ':':
305 OutputDir
= os
.path
.join (GenFdsGlobalVariable
.WorkSpaceDir
, OutputDir
)
307 if not os
.path
.exists(OutputDir
):
308 EdkLogger
.error("GenFds", FILE_NOT_FOUND
, ExtraData
=OutputDir
)
309 GenFdsGlobalVariable
.OutputDirDict
[Key
] = OutputDir
311 """ Parse Fdf file, has to place after build Workspace as FDF may contain macros from DSC file """
312 if WorkSpaceDataBase
:
313 FdfParserObj
= GlobalData
.gFdfParser
315 FdfParserObj
= FdfParser(FdfFilename
)
316 FdfParserObj
.ParseFile()
318 if FdfParserObj
.CycleReferenceCheck():
319 EdkLogger
.error("GenFds", FORMAT_NOT_SUPPORTED
, "Cycle Reference Detected in FDF file")
321 if FdsCommandDict
.get("fd"):
322 if FdsCommandDict
.get("fd")[0].upper() in FdfParserObj
.Profile
.FdDict
:
323 GenFds
.OnlyGenerateThisFd
= FdsCommandDict
.get("fd")[0]
325 EdkLogger
.error("GenFds", OPTION_VALUE_INVALID
,
326 "No such an FD in FDF file: %s" % FdsCommandDict
.get("fd")[0])
328 if FdsCommandDict
.get("fv"):
329 if FdsCommandDict
.get("fv")[0].upper() in FdfParserObj
.Profile
.FvDict
:
330 GenFds
.OnlyGenerateThisFv
= FdsCommandDict
.get("fv")[0]
332 EdkLogger
.error("GenFds", OPTION_VALUE_INVALID
,
333 "No such an FV in FDF file: %s" % FdsCommandDict
.get("fv")[0])
335 if FdsCommandDict
.get("cap"):
336 if FdsCommandDict
.get("cap")[0].upper() in FdfParserObj
.Profile
.CapsuleDict
:
337 GenFds
.OnlyGenerateThisCap
= FdsCommandDict
.get("cap")[0]
339 EdkLogger
.error("GenFds", OPTION_VALUE_INVALID
,
340 "No such a Capsule in FDF file: %s" % FdsCommandDict
.get("cap")[0])
342 GenFdsGlobalVariable
.WorkSpace
= BuildWorkSpace
344 GenFdsGlobalVariable
.ArchList
= ArchList
346 # Dsc Build Data will handle Pcd Settings from CommandLine.
348 """Modify images from build output if the feature of loading driver at fixed address is on."""
349 if GenFdsGlobalVariable
.FixedLoadAddress
:
350 GenFds
.PreprocessImage(BuildWorkSpace
, GenFdsGlobalVariable
.ActivePlatform
)
352 # Record the FV Region info that may specific in the FD
353 if FdfParserObj
.Profile
.FvDict
and FdfParserObj
.Profile
.FdDict
:
354 for FvObj
in FdfParserObj
.Profile
.FvDict
.values():
355 for FdObj
in FdfParserObj
.Profile
.FdDict
.values():
356 for RegionObj
in FdObj
.RegionList
:
357 if RegionObj
.RegionType
!= BINARY_FILE_TYPE_FV
:
359 for RegionData
in RegionObj
.RegionDataList
:
360 if FvObj
.UiFvName
.upper() == RegionData
.upper():
361 if not FvObj
.BaseAddress
:
362 FvObj
.BaseAddress
= '0x%x' % (int(FdObj
.BaseAddress
, 0) + RegionObj
.Offset
)
363 if FvObj
.FvRegionInFD
:
364 if FvObj
.FvRegionInFD
!= RegionObj
.Size
:
365 EdkLogger
.error("GenFds", FORMAT_INVALID
, "The FV %s's region is specified in multiple FD with different value." %FvObj
.UiFvName
)
367 FvObj
.FvRegionInFD
= RegionObj
.Size
368 RegionObj
.BlockInfoOfRegion(FdObj
.BlockSizeList
, FvObj
)
371 GenFds
.GenFd('', FdfParserObj
, BuildWorkSpace
, ArchList
)
373 """Generate GUID cross reference file"""
374 GenFds
.GenerateGuidXRefFile(BuildWorkSpace
, ArchList
, FdfParserObj
)
376 """Display FV space info."""
377 GenFds
.DisplayFvSpaceInfo(FdfParserObj
)
380 EdkLogger
.error(X
.ToolName
, FORMAT_INVALID
, File
=X
.FileName
, Line
=X
.LineNumber
, ExtraData
=X
.Message
, RaiseError
=False)
381 ReturnCode
= FORMAT_INVALID
382 except FatalError
as X
:
383 if FdsCommandDict
.get("debug") is not None:
385 EdkLogger
.quiet(traceback
.format_exc())
386 ReturnCode
= X
.args
[0]
392 "Tools code failure",
393 ExtraData
="Please send email to %s for help, attaching following call stack trace!\n" % MSG_EDKII_MAIL_ADDR
,
396 EdkLogger
.quiet(traceback
.format_exc())
397 ReturnCode
= CODE_ERROR
402 def OptionsToCommandDict(Options
):
404 FdsCommandDict
["verbose"] = Options
.verbose
405 FdsCommandDict
["FixedAddress"] = Options
.FixedAddress
406 FdsCommandDict
["quiet"] = Options
.quiet
407 FdsCommandDict
["debug"] = Options
.debug
408 FdsCommandDict
["Workspace"] = Options
.Workspace
409 FdsCommandDict
["GenfdsMultiThread"] = not Options
.NoGenfdsMultiThread
410 FdsCommandDict
["fdf_file"] = [PathClass(Options
.filename
)] if Options
.filename
else []
411 FdsCommandDict
["build_target"] = Options
.BuildTarget
412 FdsCommandDict
["toolchain_tag"] = Options
.ToolChain
413 FdsCommandDict
["active_platform"] = Options
.activePlatform
414 FdsCommandDict
["OptionPcd"] = Options
.OptionPcd
415 FdsCommandDict
["conf_directory"] = Options
.ConfDirectory
416 FdsCommandDict
["IgnoreSources"] = Options
.IgnoreSources
417 FdsCommandDict
["macro"] = Options
.Macros
418 FdsCommandDict
["build_architecture_list"] = Options
.archList
419 FdsCommandDict
["platform_build_directory"] = Options
.outputDir
420 FdsCommandDict
["fd"] = [Options
.uiFdName
] if Options
.uiFdName
else []
421 FdsCommandDict
["fv"] = [Options
.uiFvName
] if Options
.uiFvName
else []
422 FdsCommandDict
["cap"] = [Options
.uiCapName
] if Options
.uiCapName
else []
423 return FdsCommandDict
427 def SingleCheckCallback(option
, opt_str
, value
, parser
):
428 if option
not in gParamCheck
:
429 setattr(parser
.values
, option
.dest
, value
)
430 gParamCheck
.append(option
)
432 parser
.error("Option %s only allows one instance in command line!" % option
)
434 ## Parse command line options
436 # Using standard Python module optparse to parse command line option of this tool.
438 # @retval Opt A optparse.Values object containing the parsed options
440 def myOptionParser():
441 usage
= "%prog [options] -f input_file -a arch_list -b build_target -p active_platform -t tool_chain_tag -D \"MacroName [= MacroValue]\""
442 Parser
= OptionParser(usage
=usage
, description
=__copyright__
, version
="%prog " + str(versionNumber
))
443 Parser
.add_option("-f", "--file", dest
="filename", type="string", help="Name of FDF file to convert", action
="callback", callback
=SingleCheckCallback
)
444 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")
445 Parser
.add_option("-q", "--quiet", action
="store_true", type=None, help="Disable all messages except FATAL ERRORS.")
446 Parser
.add_option("-v", "--verbose", action
="store_true", type=None, help="Turn on verbose output with informational messages printed.")
447 Parser
.add_option("-d", "--debug", action
="store", type="int", help="Enable debug messages at specified level.")
448 Parser
.add_option("-p", "--platform", type="string", dest
="activePlatform", help="Set the ACTIVE_PLATFORM, overrides target.txt ACTIVE_PLATFORM setting.",
449 action
="callback", callback
=SingleCheckCallback
)
450 Parser
.add_option("-w", "--workspace", type="string", dest
="Workspace", default
=os
.environ
.get('WORKSPACE'), help="Set the WORKSPACE",
451 action
="callback", callback
=SingleCheckCallback
)
452 Parser
.add_option("-o", "--outputDir", type="string", dest
="outputDir", help="Name of Build Output directory",
453 action
="callback", callback
=SingleCheckCallback
)
454 Parser
.add_option("-r", "--rom_image", dest
="uiFdName", help="Build the image using the [FD] section named by FdUiName.")
455 Parser
.add_option("-i", "--FvImage", dest
="uiFvName", help="Build the FV image using the [FV] section named by UiFvName")
456 Parser
.add_option("-C", "--CapsuleImage", dest
="uiCapName", help="Build the Capsule image using the [Capsule] section named by UiCapName")
457 Parser
.add_option("-b", "--buildtarget", type="string", dest
="BuildTarget", help="Set the build TARGET, overrides target.txt TARGET setting.",
458 action
="callback", callback
=SingleCheckCallback
)
459 Parser
.add_option("-t", "--tagname", type="string", dest
="ToolChain", help="Using the tools: TOOL_CHAIN_TAG name to build the platform.",
460 action
="callback", callback
=SingleCheckCallback
)
461 Parser
.add_option("-D", "--define", action
="append", type="string", dest
="Macros", help="Macro: \"Name [= Value]\".")
462 Parser
.add_option("-s", "--specifyaddress", dest
="FixedAddress", action
="store_true", type=None, help="Specify driver load address.")
463 Parser
.add_option("--conf", action
="store", type="string", dest
="ConfDirectory", help="Specify the customized Conf directory.")
464 Parser
.add_option("--ignore-sources", action
="store_true", dest
="IgnoreSources", default
=False, help="Focus to a binary build and ignore all source files")
465 Parser
.add_option("--pcd", action
="append", dest
="OptionPcd", help="Set PCD value by command line. Format: \"PcdName=Value\" ")
466 Parser
.add_option("--genfds-multi-thread", action
="store_true", dest
="GenfdsMultiThread", default
=True, help="Enable GenFds multi thread to generate ffs file.")
467 Parser
.add_option("--no-genfds-multi-thread", action
="store_true", dest
="NoGenfdsMultiThread", default
=False, help="Disable GenFds multi thread to generate ffs file.")
469 Options
, _
= Parser
.parse_args()
472 ## The class implementing the EDK2 flash image generation process
474 # This process includes:
475 # 1. Collect workspace information, includes platform and module information
476 # 2. Call methods of Fd class to generate FD
477 # 3. Call methods of Fv class to generate FV that not belong to FD
479 class GenFds(object):
481 OnlyGenerateThisFd
= None
482 OnlyGenerateThisFv
= None
483 OnlyGenerateThisCap
= None
487 # @param OutputDir Output directory
488 # @param FdfParserObject FDF contents parser
489 # @param Workspace The directory of workspace
490 # @param ArchList The Arch list of platform
493 def GenFd (OutputDir
, FdfParserObject
, WorkSpace
, ArchList
):
494 GenFdsGlobalVariable
.SetDir ('', FdfParserObject
, WorkSpace
, ArchList
)
496 GenFdsGlobalVariable
.VerboseLogger(" Generate all Fd images and their required FV and Capsule images!")
497 if GenFds
.OnlyGenerateThisCap
is not None and GenFds
.OnlyGenerateThisCap
.upper() in GenFdsGlobalVariable
.FdfParser
.Profile
.CapsuleDict
:
498 CapsuleObj
= GenFdsGlobalVariable
.FdfParser
.Profile
.CapsuleDict
[GenFds
.OnlyGenerateThisCap
.upper()]
499 if CapsuleObj
is not None:
500 CapsuleObj
.GenCapsule()
503 if GenFds
.OnlyGenerateThisFd
is not None and GenFds
.OnlyGenerateThisFd
.upper() in GenFdsGlobalVariable
.FdfParser
.Profile
.FdDict
:
504 FdObj
= GenFdsGlobalVariable
.FdfParser
.Profile
.FdDict
[GenFds
.OnlyGenerateThisFd
.upper()]
505 if FdObj
is not None:
508 elif GenFds
.OnlyGenerateThisFd
is None and GenFds
.OnlyGenerateThisFv
is None:
509 for FdObj
in GenFdsGlobalVariable
.FdfParser
.Profile
.FdDict
.values():
512 GenFdsGlobalVariable
.VerboseLogger("\n Generate other FV images! ")
513 if GenFds
.OnlyGenerateThisFv
is not None and GenFds
.OnlyGenerateThisFv
.upper() in GenFdsGlobalVariable
.FdfParser
.Profile
.FvDict
:
514 FvObj
= GenFdsGlobalVariable
.FdfParser
.Profile
.FvDict
[GenFds
.OnlyGenerateThisFv
.upper()]
515 if FvObj
is not None:
517 FvObj
.AddToBuffer(Buffer
)
520 elif GenFds
.OnlyGenerateThisFv
is None:
521 for FvObj
in GenFdsGlobalVariable
.FdfParser
.Profile
.FvDict
.values():
523 FvObj
.AddToBuffer(Buffer
)
526 if GenFds
.OnlyGenerateThisFv
is None and GenFds
.OnlyGenerateThisFd
is None and GenFds
.OnlyGenerateThisCap
is None:
527 if GenFdsGlobalVariable
.FdfParser
.Profile
.CapsuleDict
!= {}:
528 GenFdsGlobalVariable
.VerboseLogger("\n Generate other Capsule images!")
529 for CapsuleObj
in GenFdsGlobalVariable
.FdfParser
.Profile
.CapsuleDict
.values():
530 CapsuleObj
.GenCapsule()
532 if GenFdsGlobalVariable
.FdfParser
.Profile
.OptRomDict
!= {}:
533 GenFdsGlobalVariable
.VerboseLogger("\n Generate all Option ROM!")
534 for OptRomObj
in GenFdsGlobalVariable
.FdfParser
.Profile
.OptRomDict
.values():
535 OptRomObj
.AddToBuffer(None)
538 def GenFfsMakefile(OutputDir
, FdfParserObject
, WorkSpace
, ArchList
, GlobalData
):
539 GenFdsGlobalVariable
.SetEnv(FdfParserObject
, WorkSpace
, ArchList
, GlobalData
)
540 for FdObj
in GenFdsGlobalVariable
.FdfParser
.Profile
.FdDict
.values():
541 FdObj
.GenFd(Flag
=True)
543 for FvObj
in GenFdsGlobalVariable
.FdfParser
.Profile
.FvDict
.values():
544 FvObj
.AddToBuffer(Buffer
=None, Flag
=True)
546 if GenFdsGlobalVariable
.FdfParser
.Profile
.OptRomDict
!= {}:
547 for OptRomObj
in GenFdsGlobalVariable
.FdfParser
.Profile
.OptRomDict
.values():
548 OptRomObj
.AddToBuffer(Buffer
=None, Flag
=True)
550 return GenFdsGlobalVariable
.FfsCmdDict
554 # @param FvObj Whose block size to get
555 # @retval int Block size value
558 def GetFvBlockSize(FvObj
):
559 DefaultBlockSize
= 0x1
561 if GenFds
.OnlyGenerateThisFd
is not None and GenFds
.OnlyGenerateThisFd
.upper() in GenFdsGlobalVariable
.FdfParser
.Profile
.FdDict
:
562 FdObj
= GenFdsGlobalVariable
.FdfParser
.Profile
.FdDict
[GenFds
.OnlyGenerateThisFd
.upper()]
564 for ElementFd
in GenFdsGlobalVariable
.FdfParser
.Profile
.FdDict
.values():
565 for ElementRegion
in ElementFd
.RegionList
:
566 if ElementRegion
.RegionType
== BINARY_FILE_TYPE_FV
:
567 for ElementRegionData
in ElementRegion
.RegionDataList
:
568 if ElementRegionData
is not None and ElementRegionData
.upper() == FvObj
.UiFvName
:
569 if FvObj
.BlockSizeList
!= []:
570 return FvObj
.BlockSizeList
[0][0]
572 return ElementRegion
.BlockSizeOfRegion(ElementFd
.BlockSizeList
)
573 if FvObj
.BlockSizeList
!= []:
574 return FvObj
.BlockSizeList
[0][0]
575 return DefaultBlockSize
577 for ElementRegion
in FdObj
.RegionList
:
578 if ElementRegion
.RegionType
== BINARY_FILE_TYPE_FV
:
579 for ElementRegionData
in ElementRegion
.RegionDataList
:
580 if ElementRegionData
is not None and ElementRegionData
.upper() == FvObj
.UiFvName
:
581 if FvObj
.BlockSizeList
!= []:
582 return FvObj
.BlockSizeList
[0][0]
584 return ElementRegion
.BlockSizeOfRegion(ElementFd
.BlockSizeList
)
585 return DefaultBlockSize
587 ## DisplayFvSpaceInfo()
589 # @param FvObj Whose block size to get
593 def DisplayFvSpaceInfo(FdfParserObject
):
597 for FvName
in FdfParserObject
.Profile
.FvDict
:
598 if len(FvName
) > MaxFvNameLength
:
599 MaxFvNameLength
= len(FvName
)
600 FvSpaceInfoFileName
= os
.path
.join(GenFdsGlobalVariable
.FvDir
, FvName
.upper() + '.Fv.map')
601 if os
.path
.exists(FvSpaceInfoFileName
):
602 FileLinesList
= getlines(FvSpaceInfoFileName
)
609 for Line
in FileLinesList
:
610 NameValue
= Line
.split('=')
611 if len(NameValue
) == 2:
612 if NameValue
[0].strip() == 'EFI_FV_TOTAL_SIZE':
614 Total
= NameValue
[1].strip()
615 if NameValue
[0].strip() == 'EFI_FV_TAKEN_SIZE':
617 Used
= NameValue
[1].strip()
618 if NameValue
[0].strip() == 'EFI_FV_SPACE_SIZE':
620 Free
= NameValue
[1].strip()
622 if TotalFound
and UsedFound
and FreeFound
:
623 FvSpaceInfoList
.append((FvName
, Total
, Used
, Free
))
625 GenFdsGlobalVariable
.InfLogger('\nFV Space Information')
626 for FvSpaceInfo
in FvSpaceInfoList
:
627 Name
= FvSpaceInfo
[0]
628 TotalSizeValue
= int(FvSpaceInfo
[1], 0)
629 UsedSizeValue
= int(FvSpaceInfo
[2], 0)
630 FreeSizeValue
= int(FvSpaceInfo
[3], 0)
631 if UsedSizeValue
== TotalSizeValue
:
634 Percentage
= str((UsedSizeValue
+ 0.0) / TotalSizeValue
)[0:4].lstrip('0.')
636 GenFdsGlobalVariable
.InfLogger(Name
+ ' ' + '[' + Percentage
+ '%Full] ' + str(TotalSizeValue
) + ' total, ' + str(UsedSizeValue
) + ' used, ' + str(FreeSizeValue
) + ' free')
640 # @param BuildDb Database from build meta data files
641 # @param DscFile modules from dsc file will be preprocessed
645 def PreprocessImage(BuildDb
, DscFile
):
646 PcdDict
= BuildDb
.BuildObject
[DscFile
, TAB_COMMON
, GenFdsGlobalVariable
.TargetName
, GenFdsGlobalVariable
.ToolChainTag
].Pcds
649 PcdObj
= PcdDict
[Key
]
650 if PcdObj
.TokenCName
== 'PcdBsBaseAddress':
651 PcdValue
= PcdObj
.DefaultValue
657 Int64PcdValue
= int(PcdValue
, 0)
658 if Int64PcdValue
== 0 or Int64PcdValue
< -1:
662 if Int64PcdValue
> 0:
663 TopAddress
= Int64PcdValue
665 ModuleDict
= BuildDb
.BuildObject
[DscFile
, TAB_COMMON
, GenFdsGlobalVariable
.TargetName
, GenFdsGlobalVariable
.ToolChainTag
].Modules
666 for Key
in ModuleDict
:
667 ModuleObj
= BuildDb
.BuildObject
[Key
, TAB_COMMON
, GenFdsGlobalVariable
.TargetName
, GenFdsGlobalVariable
.ToolChainTag
]
668 print(ModuleObj
.BaseName
+ ' ' + ModuleObj
.ModuleType
)
671 def GenerateGuidXRefFile(BuildDb
, ArchList
, FdfParserObj
):
672 GuidXRefFileName
= os
.path
.join(GenFdsGlobalVariable
.FvDir
, "Guid.xref")
678 VariableGuidSet
= set()
679 for Arch
in ArchList
:
680 PlatformDataBase
= BuildDb
.BuildObject
[GenFdsGlobalVariable
.ActivePlatform
, Arch
, GenFdsGlobalVariable
.TargetName
, GenFdsGlobalVariable
.ToolChainTag
]
681 PkgList
= GenFdsGlobalVariable
.WorkSpace
.GetPackageList(GenFdsGlobalVariable
.ActivePlatform
, Arch
, GenFdsGlobalVariable
.TargetName
, GenFdsGlobalVariable
.ToolChainTag
)
683 PkgGuidDict
.update(P
.Guids
)
684 for Name
, Guid
in PlatformDataBase
.Pcds
:
685 Pcd
= PlatformDataBase
.Pcds
[Name
, Guid
]
686 if Pcd
.Type
in [TAB_PCDS_DYNAMIC_HII
, TAB_PCDS_DYNAMIC_EX_HII
]:
687 for SkuId
in Pcd
.SkuInfoList
:
688 Sku
= Pcd
.SkuInfoList
[SkuId
]
689 if Sku
.VariableGuid
in VariableGuidSet
:continue
690 VariableGuidSet
.add(Sku
.VariableGuid
)
691 if Sku
.VariableGuid
and Sku
.VariableGuid
in PkgGuidDict
.keys():
692 GuidDict
[Sku
.VariableGuid
] = PkgGuidDict
[Sku
.VariableGuid
]
693 for ModuleFile
in PlatformDataBase
.Modules
:
694 Module
= BuildDb
.BuildObject
[ModuleFile
, Arch
, GenFdsGlobalVariable
.TargetName
, GenFdsGlobalVariable
.ToolChainTag
]
695 if Module
in ModuleList
:
698 ModuleList
.append(Module
)
699 if GlobalData
.gGuidPattern
.match(ModuleFile
.BaseName
):
700 GuidXRefFile
.append("%s %s\n" % (ModuleFile
.BaseName
, Module
.BaseName
))
702 GuidXRefFile
.append("%s %s\n" % (Module
.Guid
, Module
.BaseName
))
703 GuidDict
.update(Module
.Protocols
)
704 GuidDict
.update(Module
.Guids
)
705 GuidDict
.update(Module
.Ppis
)
706 for FvName
in FdfParserObj
.Profile
.FvDict
:
707 for FfsObj
in FdfParserObj
.Profile
.FvDict
[FvName
].FfsList
:
708 if not isinstance(FfsObj
, FileStatement
):
709 InfPath
= PathClass(NormPath(mws
.join(GenFdsGlobalVariable
.WorkSpaceDir
, FfsObj
.InfFileName
)))
710 FdfModule
= BuildDb
.BuildObject
[InfPath
, Arch
, GenFdsGlobalVariable
.TargetName
, GenFdsGlobalVariable
.ToolChainTag
]
711 if FdfModule
in ModuleList
:
714 ModuleList
.append(FdfModule
)
715 GuidXRefFile
.append("%s %s\n" % (FdfModule
.Guid
, FdfModule
.BaseName
))
716 GuidDict
.update(FdfModule
.Protocols
)
717 GuidDict
.update(FdfModule
.Guids
)
718 GuidDict
.update(FdfModule
.Ppis
)
720 FileStatementGuid
= FfsObj
.NameGuid
721 if FileStatementGuid
in FileGuidList
:
724 FileGuidList
.append(FileStatementGuid
)
726 FfsPath
= os
.path
.join(GenFdsGlobalVariable
.FvDir
, 'Ffs')
727 FfsPath
= glob(os
.path
.join(FfsPath
, FileStatementGuid
) + TAB_STAR
)
730 if not os
.path
.exists(FfsPath
[0]):
733 ReFileEnds
= compile('\S+(.ui)$|\S+(fv.sec.txt)$|\S+(.pe32.txt)$|\S+(.te.txt)$|\S+(.pic.txt)$|\S+(.raw.txt)$|\S+(.ffs.txt)$')
734 FileList
= os
.listdir(FfsPath
[0])
735 for File
in FileList
:
736 Match
= ReFileEnds
.search(File
)
738 for Index
in range(1, 8):
739 if Match
.group(Index
) and Match
.group(Index
) in MatchDict
:
740 MatchDict
[Match
.group(Index
)].append(File
)
741 elif Match
.group(Index
):
742 MatchDict
[Match
.group(Index
)] = [File
]
745 if '.ui' in MatchDict
:
746 for File
in MatchDict
['.ui']:
747 with
open(os
.path
.join(FfsPath
[0], File
), 'rb') as F
:
751 TmpStr
= unpack('%dh' % ((length
- 4) // 2), F
.read())
752 Name
= ''.join(chr(c
) for c
in TmpStr
[:-1])
755 if 'fv.sec.txt' in MatchDict
:
756 FileList
= MatchDict
['fv.sec.txt']
757 elif '.pe32.txt' in MatchDict
:
758 FileList
= MatchDict
['.pe32.txt']
759 elif '.te.txt' in MatchDict
:
760 FileList
= MatchDict
['.te.txt']
761 elif '.pic.txt' in MatchDict
:
762 FileList
= MatchDict
['.pic.txt']
763 elif '.raw.txt' in MatchDict
:
764 FileList
= MatchDict
['.raw.txt']
765 elif '.ffs.txt' in MatchDict
:
766 FileList
= MatchDict
['.ffs.txt']
769 for File
in FileList
:
770 with
open(os
.path
.join(FfsPath
[0], File
), 'r') as F
:
771 Name
.append((F
.read().split()[-1]))
775 Name
= ' '.join(Name
) if isinstance(Name
, type([])) else Name
776 GuidXRefFile
.append("%s %s\n" %(FileStatementGuid
, Name
))
778 # Append GUIDs, Protocols, and PPIs to the Xref file
779 GuidXRefFile
.append("\n")
780 for key
, item
in GuidDict
.items():
781 GuidXRefFile
.append("%s %s\n" % (GuidStructureStringToGuidString(item
).upper(), key
))
784 GuidXRefFile
= ''.join(GuidXRefFile
)
785 SaveFileOnChange(GuidXRefFileName
, GuidXRefFile
, False)
786 GenFdsGlobalVariable
.InfLogger("\nGUID cross reference file can be found at %s" % GuidXRefFileName
)
787 elif os
.path
.exists(GuidXRefFileName
):
788 os
.remove(GuidXRefFileName
)
791 if __name__
== '__main__':
793 ## 0-127 is a safe return range, and 1 is a standard default error