4 # Copyright (c) 2007 - 2019, 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 __future__
import absolute_import
20 from re
import compile
21 from optparse
import OptionParser
24 from struct
import unpack
25 from linecache
import getlines
26 from io
import BytesIO
28 import Common
.LongFilePathOs
as os
29 from Common
.TargetTxtClassObject
import TargetTxtClassObject
30 from Common
.DataType
import *
31 import Common
.GlobalData
as GlobalData
32 from Common
import EdkLogger
33 from Common
.StringUtils
import NormPath
34 from Common
.Misc
import DirCache
, PathClass
, GuidStructureStringToGuidString
35 from Common
.Misc
import SaveFileOnChange
, ClearDuplicatedInf
36 from Common
.BuildVersion
import gBUILD_VERSION
37 from Common
.MultipleWorkspace
import MultipleWorkspace
as mws
38 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
39 from Workspace
.WorkspaceDatabase
import WorkspaceDatabase
41 from .FdfParser
import FdfParser
, Warning
42 from .GenFdsGlobalVariable
import GenFdsGlobalVariable
43 from .FfsFileStatement
import FileStatement
44 import Common
.DataType
as DataType
45 from struct
import Struct
47 ## Version and Copyright
48 versionNumber
= "1.0" + ' ' + gBUILD_VERSION
49 __version__
= "%prog Version " + versionNumber
50 __copyright__
= "Copyright (c) 2007 - 2018, 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()
64 EdkLogger
.Initialize()
65 return GenFdsApi(OptionsToCommandDict(Options
))
67 def resetFdsGlobalVariable():
68 GenFdsGlobalVariable
.FvDir
= ''
69 GenFdsGlobalVariable
.OutputDirDict
= {}
70 GenFdsGlobalVariable
.BinDir
= ''
71 # will be FvDir + os.sep + 'Ffs'
72 GenFdsGlobalVariable
.FfsDir
= ''
73 GenFdsGlobalVariable
.FdfParser
= None
74 GenFdsGlobalVariable
.LibDir
= ''
75 GenFdsGlobalVariable
.WorkSpace
= None
76 GenFdsGlobalVariable
.WorkSpaceDir
= ''
77 GenFdsGlobalVariable
.ConfDir
= ''
78 GenFdsGlobalVariable
.OutputDirFromDscDict
= {}
79 GenFdsGlobalVariable
.TargetName
= ''
80 GenFdsGlobalVariable
.ToolChainTag
= ''
81 GenFdsGlobalVariable
.RuleDict
= {}
82 GenFdsGlobalVariable
.ArchList
= None
83 GenFdsGlobalVariable
.ActivePlatform
= None
84 GenFdsGlobalVariable
.FvAddressFileName
= ''
85 GenFdsGlobalVariable
.VerboseMode
= False
86 GenFdsGlobalVariable
.DebugLevel
= -1
87 GenFdsGlobalVariable
.SharpCounter
= 0
88 GenFdsGlobalVariable
.SharpNumberPerLine
= 40
89 GenFdsGlobalVariable
.FdfFile
= ''
90 GenFdsGlobalVariable
.FdfFileTimeStamp
= 0
91 GenFdsGlobalVariable
.FixedLoadAddress
= False
92 GenFdsGlobalVariable
.PlatformName
= ''
94 GenFdsGlobalVariable
.BuildRuleFamily
= DataType
.TAB_COMPILER_MSFT
95 GenFdsGlobalVariable
.ToolChainFamily
= DataType
.TAB_COMPILER_MSFT
96 GenFdsGlobalVariable
.__BuildRuleDatabase
= None
97 GenFdsGlobalVariable
.GuidToolDefinition
= {}
98 GenFdsGlobalVariable
.FfsCmdDict
= {}
99 GenFdsGlobalVariable
.SecCmdList
= []
100 GenFdsGlobalVariable
.CopyList
= []
101 GenFdsGlobalVariable
.ModuleFile
= ''
102 GenFdsGlobalVariable
.EnableGenfdsMultiThread
= False
104 GenFdsGlobalVariable
.LargeFileInFvFlags
= []
105 GenFdsGlobalVariable
.EFI_FIRMWARE_FILE_SYSTEM3_GUID
= '5473C07A-3DCB-4dca-BD6F-1E9689E7349A'
106 GenFdsGlobalVariable
.LARGE_FILE_SIZE
= 0x1000000
108 GenFdsGlobalVariable
.SectionHeader
= Struct("3B 1B")
110 # FvName, FdName, CapName in FDF, Image file name
111 GenFdsGlobalVariable
.ImageBinDict
= {}
113 def GenFdsApi(FdsCommandDict
, WorkSpaceDataBase
=None):
118 resetFdsGlobalVariable()
121 if FdsCommandDict
.get("verbose"):
122 EdkLogger
.SetLevel(EdkLogger
.VERBOSE
)
123 GenFdsGlobalVariable
.VerboseMode
= True
125 if FdsCommandDict
.get("FixedAddress"):
126 GenFdsGlobalVariable
.FixedLoadAddress
= True
128 if FdsCommandDict
.get("quiet"):
129 EdkLogger
.SetLevel(EdkLogger
.QUIET
)
130 if FdsCommandDict
.get("debug"):
131 EdkLogger
.SetLevel(FdsCommandDict
.get("debug") + 1)
132 GenFdsGlobalVariable
.DebugLevel
= FdsCommandDict
.get("debug")
134 EdkLogger
.SetLevel(EdkLogger
.INFO
)
136 if not FdsCommandDict
.get("Workspace",os
.environ
.get('WORKSPACE')):
137 EdkLogger
.error("GenFds", OPTION_MISSING
, "WORKSPACE not defined",
138 ExtraData
="Please use '-w' switch to pass it or set the WORKSPACE environment variable.")
139 elif not os
.path
.exists(FdsCommandDict
.get("Workspace",os
.environ
.get('WORKSPACE'))):
140 EdkLogger
.error("GenFds", PARAMETER_INVALID
, "WORKSPACE is invalid",
141 ExtraData
="Please use '-w' switch to pass it or set the WORKSPACE environment variable.")
143 Workspace
= os
.path
.normcase(FdsCommandDict
.get("Workspace",os
.environ
.get('WORKSPACE')))
144 GenFdsGlobalVariable
.WorkSpaceDir
= Workspace
145 if FdsCommandDict
.get("debug"):
146 GenFdsGlobalVariable
.VerboseLogger("Using Workspace:" + Workspace
)
147 if FdsCommandDict
.get("GenfdsMultiThread"):
148 GenFdsGlobalVariable
.EnableGenfdsMultiThread
= True
149 os
.chdir(GenFdsGlobalVariable
.WorkSpaceDir
)
151 # set multiple workspace
152 PackagesPath
= os
.getenv("PACKAGES_PATH")
153 mws
.setWs(GenFdsGlobalVariable
.WorkSpaceDir
, PackagesPath
)
155 if FdsCommandDict
.get("fdf_file"):
156 FdfFilename
= FdsCommandDict
.get("fdf_file")[0].Path
157 FdfFilename
= GenFdsGlobalVariable
.ReplaceWorkspaceMacro(FdfFilename
)
159 if FdfFilename
[0:2] == '..':
160 FdfFilename
= os
.path
.realpath(FdfFilename
)
161 if not os
.path
.isabs(FdfFilename
):
162 FdfFilename
= mws
.join(GenFdsGlobalVariable
.WorkSpaceDir
, FdfFilename
)
163 if not os
.path
.exists(FdfFilename
):
164 EdkLogger
.error("GenFds", FILE_NOT_FOUND
, ExtraData
=FdfFilename
)
166 GenFdsGlobalVariable
.FdfFile
= FdfFilename
167 GenFdsGlobalVariable
.FdfFileTimeStamp
= os
.path
.getmtime(FdfFilename
)
169 EdkLogger
.error("GenFds", OPTION_MISSING
, "Missing FDF filename")
171 if FdsCommandDict
.get("build_target"):
172 GenFdsGlobalVariable
.TargetName
= FdsCommandDict
.get("build_target")
174 if FdsCommandDict
.get("toolchain_tag"):
175 GenFdsGlobalVariable
.ToolChainTag
= FdsCommandDict
.get("toolchain_tag")
177 if FdsCommandDict
.get("active_platform"):
178 ActivePlatform
= FdsCommandDict
.get("active_platform")
179 ActivePlatform
= GenFdsGlobalVariable
.ReplaceWorkspaceMacro(ActivePlatform
)
181 if ActivePlatform
[0:2] == '..':
182 ActivePlatform
= os
.path
.realpath(ActivePlatform
)
184 if not os
.path
.isabs (ActivePlatform
):
185 ActivePlatform
= mws
.join(GenFdsGlobalVariable
.WorkSpaceDir
, ActivePlatform
)
187 if not os
.path
.exists(ActivePlatform
):
188 EdkLogger
.error("GenFds", FILE_NOT_FOUND
, "ActivePlatform doesn't exist!")
190 EdkLogger
.error("GenFds", OPTION_MISSING
, "Missing active platform")
192 GenFdsGlobalVariable
.ActivePlatform
= PathClass(NormPath(ActivePlatform
))
194 if FdsCommandDict
.get("conf_directory"):
195 # Get alternate Conf location, if it is absolute, then just use the absolute directory name
196 ConfDirectoryPath
= os
.path
.normpath(FdsCommandDict
.get("conf_directory"))
197 if ConfDirectoryPath
.startswith('"'):
198 ConfDirectoryPath
= ConfDirectoryPath
[1:]
199 if ConfDirectoryPath
.endswith('"'):
200 ConfDirectoryPath
= ConfDirectoryPath
[:-1]
201 if not os
.path
.isabs(ConfDirectoryPath
):
202 # Since alternate directory name is not absolute, the alternate directory is located within the WORKSPACE
203 # This also handles someone specifying the Conf directory in the workspace. Using --conf=Conf
204 ConfDirectoryPath
= os
.path
.join(GenFdsGlobalVariable
.WorkSpaceDir
, ConfDirectoryPath
)
206 if "CONF_PATH" in os
.environ
:
207 ConfDirectoryPath
= os
.path
.normcase(os
.environ
["CONF_PATH"])
209 # Get standard WORKSPACE/Conf, use the absolute path to the WORKSPACE/Conf
210 ConfDirectoryPath
= mws
.join(GenFdsGlobalVariable
.WorkSpaceDir
, 'Conf')
211 GenFdsGlobalVariable
.ConfDir
= ConfDirectoryPath
212 if not GlobalData
.gConfDirectory
:
213 GlobalData
.gConfDirectory
= GenFdsGlobalVariable
.ConfDir
214 BuildConfigurationFile
= os
.path
.normpath(os
.path
.join(ConfDirectoryPath
, "target.txt"))
215 if os
.path
.isfile(BuildConfigurationFile
) == True:
216 TargetTxt
= TargetTxtClassObject()
217 TargetTxt
.LoadTargetTxtFile(BuildConfigurationFile
)
218 # if no build target given in command line, get it from target.txt
219 if not GenFdsGlobalVariable
.TargetName
:
220 BuildTargetList
= TargetTxt
.TargetTxtDictionary
[TAB_TAT_DEFINES_TARGET
]
221 if len(BuildTargetList
) != 1:
222 EdkLogger
.error("GenFds", OPTION_VALUE_INVALID
, ExtraData
="Only allows one instance for Target.")
223 GenFdsGlobalVariable
.TargetName
= BuildTargetList
[0]
225 # if no tool chain given in command line, get it from target.txt
226 if not GenFdsGlobalVariable
.ToolChainTag
:
227 ToolChainList
= TargetTxt
.TargetTxtDictionary
[TAB_TAT_DEFINES_TOOL_CHAIN_TAG
]
228 if ToolChainList
is None or len(ToolChainList
) == 0:
229 EdkLogger
.error("GenFds", RESOURCE_NOT_AVAILABLE
, ExtraData
="No toolchain given. Don't know how to build.")
230 if len(ToolChainList
) != 1:
231 EdkLogger
.error("GenFds", OPTION_VALUE_INVALID
, ExtraData
="Only allows one instance for ToolChain.")
232 GenFdsGlobalVariable
.ToolChainTag
= ToolChainList
[0]
234 EdkLogger
.error("GenFds", FILE_NOT_FOUND
, ExtraData
=BuildConfigurationFile
)
236 #Set global flag for build mode
237 GlobalData
.gIgnoreSource
= FdsCommandDict
.get("IgnoreSources")
239 if FdsCommandDict
.get("macro"):
240 for Pair
in FdsCommandDict
.get("macro"):
241 if Pair
.startswith('"'):
243 if Pair
.endswith('"'):
245 List
= Pair
.split('=')
247 if not List
[1].strip():
248 EdkLogger
.error("GenFds", OPTION_VALUE_INVALID
, ExtraData
="No Value given for Macro %s" %List
[0])
249 if List
[0].strip() in ["WORKSPACE", "TARGET", "TOOLCHAIN"]:
250 GlobalData
.gGlobalDefines
[List
[0].strip()] = List
[1].strip()
252 GlobalData
.gCommandLineDefines
[List
[0].strip()] = List
[1].strip()
254 GlobalData
.gCommandLineDefines
[List
[0].strip()] = "TRUE"
255 os
.environ
["WORKSPACE"] = Workspace
257 # Use the -t and -b option as gGlobalDefines's TOOLCHAIN and TARGET if they are not defined
258 if "TARGET" not in GlobalData
.gGlobalDefines
:
259 GlobalData
.gGlobalDefines
["TARGET"] = GenFdsGlobalVariable
.TargetName
260 if "TOOLCHAIN" not in GlobalData
.gGlobalDefines
:
261 GlobalData
.gGlobalDefines
["TOOLCHAIN"] = GenFdsGlobalVariable
.ToolChainTag
262 if "TOOL_CHAIN_TAG" not in GlobalData
.gGlobalDefines
:
263 GlobalData
.gGlobalDefines
['TOOL_CHAIN_TAG'] = GenFdsGlobalVariable
.ToolChainTag
265 """call Workspace build create database"""
266 GlobalData
.gDatabasePath
= os
.path
.normpath(os
.path
.join(ConfDirectoryPath
, GlobalData
.gDatabasePath
))
268 if WorkSpaceDataBase
:
269 BuildWorkSpace
= WorkSpaceDataBase
271 BuildWorkSpace
= WorkspaceDatabase()
273 # Get files real name in workspace dir
275 GlobalData
.gAllFiles
= DirCache(Workspace
)
276 GlobalData
.gWorkspace
= Workspace
278 if FdsCommandDict
.get("build_architecture_list"):
279 ArchList
= FdsCommandDict
.get("build_architecture_list").split(',')
281 ArchList
= BuildWorkSpace
.BuildObject
[GenFdsGlobalVariable
.ActivePlatform
, TAB_COMMON
, FdsCommandDict
.get("build_target"), FdsCommandDict
.get("toolchain_tag")].SupArchList
283 TargetArchList
= set(BuildWorkSpace
.BuildObject
[GenFdsGlobalVariable
.ActivePlatform
, TAB_COMMON
, FdsCommandDict
.get("build_target"), FdsCommandDict
.get("toolchain_tag")].SupArchList
) & set(ArchList
)
284 if len(TargetArchList
) == 0:
285 EdkLogger
.error("GenFds", GENFDS_ERROR
, "Target ARCH %s not in platform supported ARCH %s" % (str(ArchList
), str(BuildWorkSpace
.BuildObject
[GenFdsGlobalVariable
.ActivePlatform
, TAB_COMMON
].SupArchList
)))
287 for Arch
in ArchList
:
288 GenFdsGlobalVariable
.OutputDirFromDscDict
[Arch
] = NormPath(BuildWorkSpace
.BuildObject
[GenFdsGlobalVariable
.ActivePlatform
, Arch
, FdsCommandDict
.get("build_target"), FdsCommandDict
.get("toolchain_tag")].OutputDirectory
)
290 # assign platform name based on last entry in ArchList
291 GenFdsGlobalVariable
.PlatformName
= BuildWorkSpace
.BuildObject
[GenFdsGlobalVariable
.ActivePlatform
, ArchList
[-1], FdsCommandDict
.get("build_target"), FdsCommandDict
.get("toolchain_tag")].PlatformName
293 if FdsCommandDict
.get("platform_build_directory"):
294 OutputDirFromCommandLine
= GenFdsGlobalVariable
.ReplaceWorkspaceMacro(FdsCommandDict
.get("platform_build_directory"))
295 if not os
.path
.isabs (OutputDirFromCommandLine
):
296 OutputDirFromCommandLine
= os
.path
.join(GenFdsGlobalVariable
.WorkSpaceDir
, OutputDirFromCommandLine
)
297 for Arch
in ArchList
:
298 GenFdsGlobalVariable
.OutputDirDict
[Arch
] = OutputDirFromCommandLine
300 for Arch
in ArchList
:
301 GenFdsGlobalVariable
.OutputDirDict
[Arch
] = os
.path
.join(GenFdsGlobalVariable
.OutputDirFromDscDict
[Arch
], GenFdsGlobalVariable
.TargetName
+ '_' + GenFdsGlobalVariable
.ToolChainTag
)
303 for Key
in GenFdsGlobalVariable
.OutputDirDict
:
304 OutputDir
= GenFdsGlobalVariable
.OutputDirDict
[Key
]
305 if OutputDir
[0:2] == '..':
306 OutputDir
= os
.path
.realpath(OutputDir
)
308 if OutputDir
[1] != ':':
309 OutputDir
= os
.path
.join (GenFdsGlobalVariable
.WorkSpaceDir
, OutputDir
)
311 if not os
.path
.exists(OutputDir
):
312 EdkLogger
.error("GenFds", FILE_NOT_FOUND
, ExtraData
=OutputDir
)
313 GenFdsGlobalVariable
.OutputDirDict
[Key
] = OutputDir
315 """ Parse Fdf file, has to place after build Workspace as FDF may contain macros from DSC file """
316 if WorkSpaceDataBase
:
317 FdfParserObj
= GlobalData
.gFdfParser
319 FdfParserObj
= FdfParser(FdfFilename
)
320 FdfParserObj
.ParseFile()
322 if FdfParserObj
.CycleReferenceCheck():
323 EdkLogger
.error("GenFds", FORMAT_NOT_SUPPORTED
, "Cycle Reference Detected in FDF file")
325 if FdsCommandDict
.get("fd"):
326 if FdsCommandDict
.get("fd")[0].upper() in FdfParserObj
.Profile
.FdDict
:
327 GenFds
.OnlyGenerateThisFd
= FdsCommandDict
.get("fd")[0]
329 EdkLogger
.error("GenFds", OPTION_VALUE_INVALID
,
330 "No such an FD in FDF file: %s" % FdsCommandDict
.get("fd")[0])
332 if FdsCommandDict
.get("fv"):
333 if FdsCommandDict
.get("fv")[0].upper() in FdfParserObj
.Profile
.FvDict
:
334 GenFds
.OnlyGenerateThisFv
= FdsCommandDict
.get("fv")[0]
336 EdkLogger
.error("GenFds", OPTION_VALUE_INVALID
,
337 "No such an FV in FDF file: %s" % FdsCommandDict
.get("fv")[0])
339 if FdsCommandDict
.get("cap"):
340 if FdsCommandDict
.get("cap")[0].upper() in FdfParserObj
.Profile
.CapsuleDict
:
341 GenFds
.OnlyGenerateThisCap
= FdsCommandDict
.get("cap")[0]
343 EdkLogger
.error("GenFds", OPTION_VALUE_INVALID
,
344 "No such a Capsule in FDF file: %s" % FdsCommandDict
.get("cap")[0])
346 GenFdsGlobalVariable
.WorkSpace
= BuildWorkSpace
348 GenFdsGlobalVariable
.ArchList
= ArchList
350 # Dsc Build Data will handle Pcd Settings from CommandLine.
352 """Modify images from build output if the feature of loading driver at fixed address is on."""
353 if GenFdsGlobalVariable
.FixedLoadAddress
:
354 GenFds
.PreprocessImage(BuildWorkSpace
, GenFdsGlobalVariable
.ActivePlatform
)
356 # Record the FV Region info that may specific in the FD
357 if FdfParserObj
.Profile
.FvDict
and FdfParserObj
.Profile
.FdDict
:
358 for FvObj
in FdfParserObj
.Profile
.FvDict
.values():
359 for FdObj
in FdfParserObj
.Profile
.FdDict
.values():
360 for RegionObj
in FdObj
.RegionList
:
361 if RegionObj
.RegionType
!= BINARY_FILE_TYPE_FV
:
363 for RegionData
in RegionObj
.RegionDataList
:
364 if FvObj
.UiFvName
.upper() == RegionData
.upper():
365 if FvObj
.FvRegionInFD
:
366 if FvObj
.FvRegionInFD
!= RegionObj
.Size
:
367 EdkLogger
.error("GenFds", FORMAT_INVALID
, "The FV %s's region is specified in multiple FD with different value." %FvObj
.UiFvName
)
369 FvObj
.FvRegionInFD
= RegionObj
.Size
370 RegionObj
.BlockInfoOfRegion(FdObj
.BlockSizeList
, FvObj
)
373 GenFds
.GenFd('', FdfParserObj
, BuildWorkSpace
, ArchList
)
375 """Generate GUID cross reference file"""
376 GenFds
.GenerateGuidXRefFile(BuildWorkSpace
, ArchList
, FdfParserObj
)
378 """Display FV space info."""
379 GenFds
.DisplayFvSpaceInfo(FdfParserObj
)
382 EdkLogger
.error(X
.ToolName
, FORMAT_INVALID
, File
=X
.FileName
, Line
=X
.LineNumber
, ExtraData
=X
.Message
, RaiseError
=False)
383 ReturnCode
= FORMAT_INVALID
384 except FatalError
as X
:
385 if FdsCommandDict
.get("debug") is not None:
387 EdkLogger
.quiet(traceback
.format_exc())
388 ReturnCode
= X
.args
[0]
394 "Tools code failure",
395 ExtraData
="Please send email to edk2-devel@lists.01.org for help, attaching following call stack trace!\n",
398 EdkLogger
.quiet(traceback
.format_exc())
399 ReturnCode
= CODE_ERROR
404 def OptionsToCommandDict(Options
):
406 FdsCommandDict
["verbose"] = Options
.verbose
407 FdsCommandDict
["FixedAddress"] = Options
.FixedAddress
408 FdsCommandDict
["quiet"] = Options
.quiet
409 FdsCommandDict
["debug"] = Options
.debug
410 FdsCommandDict
["Workspace"] = Options
.Workspace
411 FdsCommandDict
["GenfdsMultiThread"] = Options
.GenfdsMultiThread
412 FdsCommandDict
["fdf_file"] = [PathClass(Options
.filename
)] if Options
.filename
else []
413 FdsCommandDict
["build_target"] = Options
.BuildTarget
414 FdsCommandDict
["toolchain_tag"] = Options
.ToolChain
415 FdsCommandDict
["active_platform"] = Options
.activePlatform
416 FdsCommandDict
["OptionPcd"] = Options
.OptionPcd
417 FdsCommandDict
["conf_directory"] = Options
.ConfDirectory
418 FdsCommandDict
["IgnoreSources"] = Options
.IgnoreSources
419 FdsCommandDict
["macro"] = Options
.Macros
420 FdsCommandDict
["build_architecture_list"] = Options
.archList
421 FdsCommandDict
["platform_build_directory"] = Options
.outputDir
422 FdsCommandDict
["fd"] = [Options
.uiFdName
] if Options
.uiFdName
else []
423 FdsCommandDict
["fv"] = [Options
.uiFvName
] if Options
.uiFvName
else []
424 FdsCommandDict
["cap"] = [Options
.uiCapName
] if Options
.uiCapName
else []
425 return FdsCommandDict
429 def SingleCheckCallback(option
, opt_str
, value
, parser
):
430 if option
not in gParamCheck
:
431 setattr(parser
.values
, option
.dest
, value
)
432 gParamCheck
.append(option
)
434 parser
.error("Option %s only allows one instance in command line!" % option
)
436 ## Parse command line options
438 # Using standard Python module optparse to parse command line option of this tool.
440 # @retval Opt A optparse.Values object containing the parsed options
442 def myOptionParser():
443 usage
= "%prog [options] -f input_file -a arch_list -b build_target -p active_platform -t tool_chain_tag -D \"MacroName [= MacroValue]\""
444 Parser
= OptionParser(usage
=usage
, description
=__copyright__
, version
="%prog " + str(versionNumber
))
445 Parser
.add_option("-f", "--file", dest
="filename", type="string", help="Name of FDF file to convert", action
="callback", callback
=SingleCheckCallback
)
446 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")
447 Parser
.add_option("-q", "--quiet", action
="store_true", type=None, help="Disable all messages except FATAL ERRORS.")
448 Parser
.add_option("-v", "--verbose", action
="store_true", type=None, help="Turn on verbose output with informational messages printed.")
449 Parser
.add_option("-d", "--debug", action
="store", type="int", help="Enable debug messages at specified level.")
450 Parser
.add_option("-p", "--platform", type="string", dest
="activePlatform", help="Set the ACTIVE_PLATFORM, overrides target.txt ACTIVE_PLATFORM setting.",
451 action
="callback", callback
=SingleCheckCallback
)
452 Parser
.add_option("-w", "--workspace", type="string", dest
="Workspace", default
=os
.environ
.get('WORKSPACE'), help="Set the WORKSPACE",
453 action
="callback", callback
=SingleCheckCallback
)
454 Parser
.add_option("-o", "--outputDir", type="string", dest
="outputDir", help="Name of Build Output directory",
455 action
="callback", callback
=SingleCheckCallback
)
456 Parser
.add_option("-r", "--rom_image", dest
="uiFdName", help="Build the image using the [FD] section named by FdUiName.")
457 Parser
.add_option("-i", "--FvImage", dest
="uiFvName", help="Build the FV image using the [FV] section named by UiFvName")
458 Parser
.add_option("-C", "--CapsuleImage", dest
="uiCapName", help="Build the Capsule image using the [Capsule] section named by UiCapName")
459 Parser
.add_option("-b", "--buildtarget", type="string", dest
="BuildTarget", help="Set the build TARGET, overrides target.txt TARGET setting.",
460 action
="callback", callback
=SingleCheckCallback
)
461 Parser
.add_option("-t", "--tagname", type="string", dest
="ToolChain", help="Using the tools: TOOL_CHAIN_TAG name to build the platform.",
462 action
="callback", callback
=SingleCheckCallback
)
463 Parser
.add_option("-D", "--define", action
="append", type="string", dest
="Macros", help="Macro: \"Name [= Value]\".")
464 Parser
.add_option("-s", "--specifyaddress", dest
="FixedAddress", action
="store_true", type=None, help="Specify driver load address.")
465 Parser
.add_option("--conf", action
="store", type="string", dest
="ConfDirectory", help="Specify the customized Conf directory.")
466 Parser
.add_option("--ignore-sources", action
="store_true", dest
="IgnoreSources", default
=False, help="Focus to a binary build and ignore all source files")
467 Parser
.add_option("--pcd", action
="append", dest
="OptionPcd", help="Set PCD value by command line. Format: \"PcdName=Value\" ")
468 Parser
.add_option("--genfds-multi-thread", action
="store_true", dest
="GenfdsMultiThread", default
=False, help="Enable GenFds multi thread to generate ffs file.")
470 Options
, _
= Parser
.parse_args()
473 ## The class implementing the EDK2 flash image generation process
475 # This process includes:
476 # 1. Collect workspace information, includes platform and module information
477 # 2. Call methods of Fd class to generate FD
478 # 3. Call methods of Fv class to generate FV that not belong to FD
480 class GenFds(object):
482 OnlyGenerateThisFd
= None
483 OnlyGenerateThisFv
= None
484 OnlyGenerateThisCap
= None
488 # @param OutputDir Output directory
489 # @param FdfParserObject FDF contents parser
490 # @param Workspace The directory of workspace
491 # @param ArchList The Arch list of platform
494 def GenFd (OutputDir
, FdfParserObject
, WorkSpace
, ArchList
):
495 GenFdsGlobalVariable
.SetDir ('', FdfParserObject
, WorkSpace
, ArchList
)
497 GenFdsGlobalVariable
.VerboseLogger(" Generate all Fd images and their required FV and Capsule images!")
498 if GenFds
.OnlyGenerateThisCap
is not None and GenFds
.OnlyGenerateThisCap
.upper() in GenFdsGlobalVariable
.FdfParser
.Profile
.CapsuleDict
:
499 CapsuleObj
= GenFdsGlobalVariable
.FdfParser
.Profile
.CapsuleDict
[GenFds
.OnlyGenerateThisCap
.upper()]
500 if CapsuleObj
is not None:
501 CapsuleObj
.GenCapsule()
504 if GenFds
.OnlyGenerateThisFd
is not None and GenFds
.OnlyGenerateThisFd
.upper() in GenFdsGlobalVariable
.FdfParser
.Profile
.FdDict
:
505 FdObj
= GenFdsGlobalVariable
.FdfParser
.Profile
.FdDict
[GenFds
.OnlyGenerateThisFd
.upper()]
506 if FdObj
is not None:
509 elif GenFds
.OnlyGenerateThisFd
is None and GenFds
.OnlyGenerateThisFv
is None:
510 for FdObj
in GenFdsGlobalVariable
.FdfParser
.Profile
.FdDict
.values():
513 GenFdsGlobalVariable
.VerboseLogger("\n Generate other FV images! ")
514 if GenFds
.OnlyGenerateThisFv
is not None and GenFds
.OnlyGenerateThisFv
.upper() in GenFdsGlobalVariable
.FdfParser
.Profile
.FvDict
:
515 FvObj
= GenFdsGlobalVariable
.FdfParser
.Profile
.FvDict
[GenFds
.OnlyGenerateThisFv
.upper()]
516 if FvObj
is not None:
518 FvObj
.AddToBuffer(Buffer
)
521 elif GenFds
.OnlyGenerateThisFv
is None:
522 for FvObj
in GenFdsGlobalVariable
.FdfParser
.Profile
.FvDict
.values():
524 FvObj
.AddToBuffer(Buffer
)
527 if GenFds
.OnlyGenerateThisFv
is None and GenFds
.OnlyGenerateThisFd
is None and GenFds
.OnlyGenerateThisCap
is None:
528 if GenFdsGlobalVariable
.FdfParser
.Profile
.CapsuleDict
!= {}:
529 GenFdsGlobalVariable
.VerboseLogger("\n Generate other Capsule images!")
530 for CapsuleObj
in GenFdsGlobalVariable
.FdfParser
.Profile
.CapsuleDict
.values():
531 CapsuleObj
.GenCapsule()
533 if GenFdsGlobalVariable
.FdfParser
.Profile
.OptRomDict
!= {}:
534 GenFdsGlobalVariable
.VerboseLogger("\n Generate all Option ROM!")
535 for OptRomObj
in GenFdsGlobalVariable
.FdfParser
.Profile
.OptRomDict
.values():
536 OptRomObj
.AddToBuffer(None)
539 def GenFfsMakefile(OutputDir
, FdfParserObject
, WorkSpace
, ArchList
, GlobalData
):
540 GenFdsGlobalVariable
.SetEnv(FdfParserObject
, WorkSpace
, ArchList
, GlobalData
)
541 for FdObj
in GenFdsGlobalVariable
.FdfParser
.Profile
.FdDict
.values():
542 FdObj
.GenFd(Flag
=True)
544 for FvObj
in GenFdsGlobalVariable
.FdfParser
.Profile
.FvDict
.values():
545 FvObj
.AddToBuffer(Buffer
=None, Flag
=True)
547 if GenFdsGlobalVariable
.FdfParser
.Profile
.OptRomDict
!= {}:
548 for OptRomObj
in GenFdsGlobalVariable
.FdfParser
.Profile
.OptRomDict
.values():
549 OptRomObj
.AddToBuffer(Buffer
=None, Flag
=True)
551 return GenFdsGlobalVariable
.FfsCmdDict
555 # @param FvObj Whose block size to get
556 # @retval int Block size value
559 def GetFvBlockSize(FvObj
):
560 DefaultBlockSize
= 0x1
562 if GenFds
.OnlyGenerateThisFd
is not None and GenFds
.OnlyGenerateThisFd
.upper() in GenFdsGlobalVariable
.FdfParser
.Profile
.FdDict
:
563 FdObj
= GenFdsGlobalVariable
.FdfParser
.Profile
.FdDict
[GenFds
.OnlyGenerateThisFd
.upper()]
565 for ElementFd
in GenFdsGlobalVariable
.FdfParser
.Profile
.FdDict
.values():
566 for ElementRegion
in ElementFd
.RegionList
:
567 if ElementRegion
.RegionType
== BINARY_FILE_TYPE_FV
:
568 for ElementRegionData
in ElementRegion
.RegionDataList
:
569 if ElementRegionData
is not None and ElementRegionData
.upper() == FvObj
.UiFvName
:
570 if FvObj
.BlockSizeList
!= []:
571 return FvObj
.BlockSizeList
[0][0]
573 return ElementRegion
.BlockSizeOfRegion(ElementFd
.BlockSizeList
)
574 if FvObj
.BlockSizeList
!= []:
575 return FvObj
.BlockSizeList
[0][0]
576 return DefaultBlockSize
578 for ElementRegion
in FdObj
.RegionList
:
579 if ElementRegion
.RegionType
== BINARY_FILE_TYPE_FV
:
580 for ElementRegionData
in ElementRegion
.RegionDataList
:
581 if ElementRegionData
is not None and ElementRegionData
.upper() == FvObj
.UiFvName
:
582 if FvObj
.BlockSizeList
!= []:
583 return FvObj
.BlockSizeList
[0][0]
585 return ElementRegion
.BlockSizeOfRegion(ElementFd
.BlockSizeList
)
586 return DefaultBlockSize
588 ## DisplayFvSpaceInfo()
590 # @param FvObj Whose block size to get
594 def DisplayFvSpaceInfo(FdfParserObject
):
598 for FvName
in FdfParserObject
.Profile
.FvDict
:
599 if len(FvName
) > MaxFvNameLength
:
600 MaxFvNameLength
= len(FvName
)
601 FvSpaceInfoFileName
= os
.path
.join(GenFdsGlobalVariable
.FvDir
, FvName
.upper() + '.Fv.map')
602 if os
.path
.exists(FvSpaceInfoFileName
):
603 FileLinesList
= getlines(FvSpaceInfoFileName
)
610 for Line
in FileLinesList
:
611 NameValue
= Line
.split('=')
612 if len(NameValue
) == 2:
613 if NameValue
[0].strip() == 'EFI_FV_TOTAL_SIZE':
615 Total
= NameValue
[1].strip()
616 if NameValue
[0].strip() == 'EFI_FV_TAKEN_SIZE':
618 Used
= NameValue
[1].strip()
619 if NameValue
[0].strip() == 'EFI_FV_SPACE_SIZE':
621 Free
= NameValue
[1].strip()
623 if TotalFound
and UsedFound
and FreeFound
:
624 FvSpaceInfoList
.append((FvName
, Total
, Used
, Free
))
626 GenFdsGlobalVariable
.InfLogger('\nFV Space Information')
627 for FvSpaceInfo
in FvSpaceInfoList
:
628 Name
= FvSpaceInfo
[0]
629 TotalSizeValue
= int(FvSpaceInfo
[1], 0)
630 UsedSizeValue
= int(FvSpaceInfo
[2], 0)
631 FreeSizeValue
= int(FvSpaceInfo
[3], 0)
632 if UsedSizeValue
== TotalSizeValue
:
635 Percentage
= str((UsedSizeValue
+ 0.0) / TotalSizeValue
)[0:4].lstrip('0.')
637 GenFdsGlobalVariable
.InfLogger(Name
+ ' ' + '[' + Percentage
+ '%Full] ' + str(TotalSizeValue
) + ' total, ' + str(UsedSizeValue
) + ' used, ' + str(FreeSizeValue
) + ' free')
641 # @param BuildDb Database from build meta data files
642 # @param DscFile modules from dsc file will be preprocessed
646 def PreprocessImage(BuildDb
, DscFile
):
647 PcdDict
= BuildDb
.BuildObject
[DscFile
, TAB_COMMON
, GenFdsGlobalVariable
.TargetName
, GenFdsGlobalVariable
.ToolChainTag
].Pcds
650 PcdObj
= PcdDict
[Key
]
651 if PcdObj
.TokenCName
== 'PcdBsBaseAddress':
652 PcdValue
= PcdObj
.DefaultValue
658 Int64PcdValue
= int(PcdValue
, 0)
659 if Int64PcdValue
== 0 or Int64PcdValue
< -1:
663 if Int64PcdValue
> 0:
664 TopAddress
= Int64PcdValue
666 ModuleDict
= BuildDb
.BuildObject
[DscFile
, TAB_COMMON
, GenFdsGlobalVariable
.TargetName
, GenFdsGlobalVariable
.ToolChainTag
].Modules
667 for Key
in ModuleDict
:
668 ModuleObj
= BuildDb
.BuildObject
[Key
, TAB_COMMON
, GenFdsGlobalVariable
.TargetName
, GenFdsGlobalVariable
.ToolChainTag
]
669 print(ModuleObj
.BaseName
+ ' ' + ModuleObj
.ModuleType
)
672 def GenerateGuidXRefFile(BuildDb
, ArchList
, FdfParserObj
):
673 GuidXRefFileName
= os
.path
.join(GenFdsGlobalVariable
.FvDir
, "Guid.xref")
674 GuidXRefFile
= BytesIO('')
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
and Sku
.VariableGuid
in PkgGuidDict
.keys():
690 GuidDict
[Sku
.VariableGuid
] = PkgGuidDict
[Sku
.VariableGuid
]
691 for ModuleFile
in PlatformDataBase
.Modules
:
692 Module
= BuildDb
.BuildObject
[ModuleFile
, Arch
, GenFdsGlobalVariable
.TargetName
, GenFdsGlobalVariable
.ToolChainTag
]
693 if Module
in ModuleList
:
696 ModuleList
.append(Module
)
697 if GlobalData
.gGuidPattern
.match(ModuleFile
.BaseName
):
698 GuidXRefFile
.write("%s %s\n" % (ModuleFile
.BaseName
, Module
.BaseName
))
700 GuidXRefFile
.write("%s %s\n" % (Module
.Guid
, Module
.BaseName
))
701 GuidDict
.update(Module
.Protocols
)
702 GuidDict
.update(Module
.Guids
)
703 GuidDict
.update(Module
.Ppis
)
704 for FvName
in FdfParserObj
.Profile
.FvDict
:
705 for FfsObj
in FdfParserObj
.Profile
.FvDict
[FvName
].FfsList
:
706 if not isinstance(FfsObj
, FileStatement
):
707 InfPath
= PathClass(NormPath(mws
.join(GenFdsGlobalVariable
.WorkSpaceDir
, FfsObj
.InfFileName
)))
708 FdfModule
= BuildDb
.BuildObject
[InfPath
, Arch
, GenFdsGlobalVariable
.TargetName
, GenFdsGlobalVariable
.ToolChainTag
]
709 if FdfModule
in ModuleList
:
712 ModuleList
.append(FdfModule
)
713 GuidXRefFile
.write("%s %s\n" % (FdfModule
.Guid
, FdfModule
.BaseName
))
714 GuidDict
.update(FdfModule
.Protocols
)
715 GuidDict
.update(FdfModule
.Guids
)
716 GuidDict
.update(FdfModule
.Ppis
)
718 FileStatementGuid
= FfsObj
.NameGuid
719 if FileStatementGuid
in FileGuidList
:
722 FileGuidList
.append(FileStatementGuid
)
724 FfsPath
= os
.path
.join(GenFdsGlobalVariable
.FvDir
, 'Ffs')
725 FfsPath
= glob(os
.path
.join(FfsPath
, FileStatementGuid
) + TAB_STAR
)
728 if not os
.path
.exists(FfsPath
[0]):
731 ReFileEnds
= compile('\S+(.ui)$|\S+(fv.sec.txt)$|\S+(.pe32.txt)$|\S+(.te.txt)$|\S+(.pic.txt)$|\S+(.raw.txt)$|\S+(.ffs.txt)$')
732 FileList
= os
.listdir(FfsPath
[0])
733 for File
in FileList
:
734 Match
= ReFileEnds
.search(File
)
736 for Index
in range(1, 8):
737 if Match
.group(Index
) and Match
.group(Index
) in MatchDict
:
738 MatchDict
[Match
.group(Index
)].append(File
)
739 elif Match
.group(Index
):
740 MatchDict
[Match
.group(Index
)] = [File
]
743 if '.ui' in MatchDict
:
744 for File
in MatchDict
['.ui']:
745 with
open(os
.path
.join(FfsPath
[0], File
), 'rb') as F
:
749 TmpStr
= unpack('%dh' % ((length
- 4) / 2), F
.read())
750 Name
= ''.join(chr(c
) for c
in TmpStr
[:-1])
753 if 'fv.sec.txt' in MatchDict
:
754 FileList
= MatchDict
['fv.sec.txt']
755 elif '.pe32.txt' in MatchDict
:
756 FileList
= MatchDict
['.pe32.txt']
757 elif '.te.txt' in MatchDict
:
758 FileList
= MatchDict
['.te.txt']
759 elif '.pic.txt' in MatchDict
:
760 FileList
= MatchDict
['.pic.txt']
761 elif '.raw.txt' in MatchDict
:
762 FileList
= MatchDict
['.raw.txt']
763 elif '.ffs.txt' in MatchDict
:
764 FileList
= MatchDict
['.ffs.txt']
767 for File
in FileList
:
768 with
open(os
.path
.join(FfsPath
[0], File
), 'r') as F
:
769 Name
.append((F
.read().split()[-1]))
773 Name
= ' '.join(Name
) if isinstance(Name
, type([])) else Name
774 GuidXRefFile
.write("%s %s\n" %(FileStatementGuid
, Name
))
776 # Append GUIDs, Protocols, and PPIs to the Xref file
777 GuidXRefFile
.write("\n")
778 for key
, item
in GuidDict
.items():
779 GuidXRefFile
.write("%s %s\n" % (GuidStructureStringToGuidString(item
).upper(), key
))
781 if GuidXRefFile
.getvalue():
782 SaveFileOnChange(GuidXRefFileName
, GuidXRefFile
.getvalue(), False)
783 GenFdsGlobalVariable
.InfLogger("\nGUID cross reference file can be found at %s" % GuidXRefFileName
)
784 elif os
.path
.exists(GuidXRefFileName
):
785 os
.remove(GuidXRefFileName
)
789 if __name__
== '__main__':
791 ## 0-127 is a safe return range, and 1 is a standard default error