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
.EdkSourceDir
= ''
79 GenFdsGlobalVariable
.OutputDirFromDscDict
= {}
80 GenFdsGlobalVariable
.TargetName
= ''
81 GenFdsGlobalVariable
.ToolChainTag
= ''
82 GenFdsGlobalVariable
.RuleDict
= {}
83 GenFdsGlobalVariable
.ArchList
= None
84 GenFdsGlobalVariable
.ActivePlatform
= None
85 GenFdsGlobalVariable
.FvAddressFileName
= ''
86 GenFdsGlobalVariable
.VerboseMode
= False
87 GenFdsGlobalVariable
.DebugLevel
= -1
88 GenFdsGlobalVariable
.SharpCounter
= 0
89 GenFdsGlobalVariable
.SharpNumberPerLine
= 40
90 GenFdsGlobalVariable
.FdfFile
= ''
91 GenFdsGlobalVariable
.FdfFileTimeStamp
= 0
92 GenFdsGlobalVariable
.FixedLoadAddress
= False
93 GenFdsGlobalVariable
.PlatformName
= ''
95 GenFdsGlobalVariable
.BuildRuleFamily
= DataType
.TAB_COMPILER_MSFT
96 GenFdsGlobalVariable
.ToolChainFamily
= DataType
.TAB_COMPILER_MSFT
97 GenFdsGlobalVariable
.__BuildRuleDatabase
= None
98 GenFdsGlobalVariable
.GuidToolDefinition
= {}
99 GenFdsGlobalVariable
.FfsCmdDict
= {}
100 GenFdsGlobalVariable
.SecCmdList
= []
101 GenFdsGlobalVariable
.CopyList
= []
102 GenFdsGlobalVariable
.ModuleFile
= ''
103 GenFdsGlobalVariable
.EnableGenfdsMultiThread
= False
105 GenFdsGlobalVariable
.LargeFileInFvFlags
= []
106 GenFdsGlobalVariable
.EFI_FIRMWARE_FILE_SYSTEM3_GUID
= '5473C07A-3DCB-4dca-BD6F-1E9689E7349A'
107 GenFdsGlobalVariable
.LARGE_FILE_SIZE
= 0x1000000
109 GenFdsGlobalVariable
.SectionHeader
= Struct("3B 1B")
111 # FvName, FdName, CapName in FDF, Image file name
112 GenFdsGlobalVariable
.ImageBinDict
= {}
114 def GenFdsApi(FdsCommandDict
, WorkSpaceDataBase
=None):
119 resetFdsGlobalVariable()
122 if FdsCommandDict
.get("verbose"):
123 EdkLogger
.SetLevel(EdkLogger
.VERBOSE
)
124 GenFdsGlobalVariable
.VerboseMode
= True
126 if FdsCommandDict
.get("FixedAddress"):
127 GenFdsGlobalVariable
.FixedLoadAddress
= True
129 if FdsCommandDict
.get("quiet"):
130 EdkLogger
.SetLevel(EdkLogger
.QUIET
)
131 if FdsCommandDict
.get("debug"):
132 EdkLogger
.SetLevel(FdsCommandDict
.get("debug") + 1)
133 GenFdsGlobalVariable
.DebugLevel
= FdsCommandDict
.get("debug")
135 EdkLogger
.SetLevel(EdkLogger
.INFO
)
137 if not FdsCommandDict
.get("Workspace",os
.environ
.get('WORKSPACE')):
138 EdkLogger
.error("GenFds", OPTION_MISSING
, "WORKSPACE not defined",
139 ExtraData
="Please use '-w' switch to pass it or set the WORKSPACE environment variable.")
140 elif not os
.path
.exists(FdsCommandDict
.get("Workspace",os
.environ
.get('WORKSPACE'))):
141 EdkLogger
.error("GenFds", PARAMETER_INVALID
, "WORKSPACE is invalid",
142 ExtraData
="Please use '-w' switch to pass it or set the WORKSPACE environment variable.")
144 Workspace
= os
.path
.normcase(FdsCommandDict
.get("Workspace",os
.environ
.get('WORKSPACE')))
145 GenFdsGlobalVariable
.WorkSpaceDir
= Workspace
146 if 'EDK_SOURCE' in os
.environ
:
147 GenFdsGlobalVariable
.EdkSourceDir
= os
.path
.normcase(os
.environ
['EDK_SOURCE'])
148 if FdsCommandDict
.get("debug"):
149 GenFdsGlobalVariable
.VerboseLogger("Using Workspace:" + Workspace
)
150 if FdsCommandDict
.get("GenfdsMultiThread"):
151 GenFdsGlobalVariable
.EnableGenfdsMultiThread
= True
152 os
.chdir(GenFdsGlobalVariable
.WorkSpaceDir
)
154 # set multiple workspace
155 PackagesPath
= os
.getenv("PACKAGES_PATH")
156 mws
.setWs(GenFdsGlobalVariable
.WorkSpaceDir
, PackagesPath
)
158 if FdsCommandDict
.get("fdf_file"):
159 FdfFilename
= FdsCommandDict
.get("fdf_file")[0].Path
160 FdfFilename
= GenFdsGlobalVariable
.ReplaceWorkspaceMacro(FdfFilename
)
162 if FdfFilename
[0:2] == '..':
163 FdfFilename
= os
.path
.realpath(FdfFilename
)
164 if not os
.path
.isabs(FdfFilename
):
165 FdfFilename
= mws
.join(GenFdsGlobalVariable
.WorkSpaceDir
, FdfFilename
)
166 if not os
.path
.exists(FdfFilename
):
167 EdkLogger
.error("GenFds", FILE_NOT_FOUND
, ExtraData
=FdfFilename
)
169 GenFdsGlobalVariable
.FdfFile
= FdfFilename
170 GenFdsGlobalVariable
.FdfFileTimeStamp
= os
.path
.getmtime(FdfFilename
)
172 EdkLogger
.error("GenFds", OPTION_MISSING
, "Missing FDF filename")
174 if FdsCommandDict
.get("build_target"):
175 GenFdsGlobalVariable
.TargetName
= FdsCommandDict
.get("build_target")
177 if FdsCommandDict
.get("toolchain_tag"):
178 GenFdsGlobalVariable
.ToolChainTag
= FdsCommandDict
.get("toolchain_tag")
180 if FdsCommandDict
.get("active_platform"):
181 ActivePlatform
= FdsCommandDict
.get("active_platform")
182 ActivePlatform
= GenFdsGlobalVariable
.ReplaceWorkspaceMacro(ActivePlatform
)
184 if ActivePlatform
[0:2] == '..':
185 ActivePlatform
= os
.path
.realpath(ActivePlatform
)
187 if not os
.path
.isabs (ActivePlatform
):
188 ActivePlatform
= mws
.join(GenFdsGlobalVariable
.WorkSpaceDir
, ActivePlatform
)
190 if not os
.path
.exists(ActivePlatform
):
191 EdkLogger
.error("GenFds", FILE_NOT_FOUND
, "ActivePlatform doesn't exist!")
193 EdkLogger
.error("GenFds", OPTION_MISSING
, "Missing active platform")
195 GlobalData
.BuildOptionPcd
= FdsCommandDict
.get("OptionPcd") if FdsCommandDict
.get("OptionPcd") else {}
196 GenFdsGlobalVariable
.ActivePlatform
= PathClass(NormPath(ActivePlatform
))
198 if FdsCommandDict
.get("conf_directory"):
199 # Get alternate Conf location, if it is absolute, then just use the absolute directory name
200 ConfDirectoryPath
= os
.path
.normpath(FdsCommandDict
.get("conf_directory"))
201 if ConfDirectoryPath
.startswith('"'):
202 ConfDirectoryPath
= ConfDirectoryPath
[1:]
203 if ConfDirectoryPath
.endswith('"'):
204 ConfDirectoryPath
= ConfDirectoryPath
[:-1]
205 if not os
.path
.isabs(ConfDirectoryPath
):
206 # Since alternate directory name is not absolute, the alternate directory is located within the WORKSPACE
207 # This also handles someone specifying the Conf directory in the workspace. Using --conf=Conf
208 ConfDirectoryPath
= os
.path
.join(GenFdsGlobalVariable
.WorkSpaceDir
, ConfDirectoryPath
)
210 if "CONF_PATH" in os
.environ
:
211 ConfDirectoryPath
= os
.path
.normcase(os
.environ
["CONF_PATH"])
213 # Get standard WORKSPACE/Conf, use the absolute path to the WORKSPACE/Conf
214 ConfDirectoryPath
= mws
.join(GenFdsGlobalVariable
.WorkSpaceDir
, 'Conf')
215 GenFdsGlobalVariable
.ConfDir
= ConfDirectoryPath
216 if not GlobalData
.gConfDirectory
:
217 GlobalData
.gConfDirectory
= GenFdsGlobalVariable
.ConfDir
218 BuildConfigurationFile
= os
.path
.normpath(os
.path
.join(ConfDirectoryPath
, "target.txt"))
219 if os
.path
.isfile(BuildConfigurationFile
) == True:
220 TargetTxt
= TargetTxtClassObject()
221 TargetTxt
.LoadTargetTxtFile(BuildConfigurationFile
)
222 # if no build target given in command line, get it from target.txt
223 if not GenFdsGlobalVariable
.TargetName
:
224 BuildTargetList
= TargetTxt
.TargetTxtDictionary
[TAB_TAT_DEFINES_TARGET
]
225 if len(BuildTargetList
) != 1:
226 EdkLogger
.error("GenFds", OPTION_VALUE_INVALID
, ExtraData
="Only allows one instance for Target.")
227 GenFdsGlobalVariable
.TargetName
= BuildTargetList
[0]
229 # if no tool chain given in command line, get it from target.txt
230 if not GenFdsGlobalVariable
.ToolChainTag
:
231 ToolChainList
= TargetTxt
.TargetTxtDictionary
[TAB_TAT_DEFINES_TOOL_CHAIN_TAG
]
232 if ToolChainList
is None or len(ToolChainList
) == 0:
233 EdkLogger
.error("GenFds", RESOURCE_NOT_AVAILABLE
, ExtraData
="No toolchain given. Don't know how to build.")
234 if len(ToolChainList
) != 1:
235 EdkLogger
.error("GenFds", OPTION_VALUE_INVALID
, ExtraData
="Only allows one instance for ToolChain.")
236 GenFdsGlobalVariable
.ToolChainTag
= ToolChainList
[0]
238 EdkLogger
.error("GenFds", FILE_NOT_FOUND
, ExtraData
=BuildConfigurationFile
)
240 #Set global flag for build mode
241 GlobalData
.gIgnoreSource
= FdsCommandDict
.get("IgnoreSources")
243 if FdsCommandDict
.get("macro"):
244 for Pair
in FdsCommandDict
.get("macro"):
245 if Pair
.startswith('"'):
247 if Pair
.endswith('"'):
249 List
= Pair
.split('=')
251 if not List
[1].strip():
252 EdkLogger
.error("GenFds", OPTION_VALUE_INVALID
, ExtraData
="No Value given for Macro %s" %List
[0])
253 if List
[0].strip() in ["WORKSPACE", "TARGET", "TOOLCHAIN"]:
254 GlobalData
.gGlobalDefines
[List
[0].strip()] = List
[1].strip()
256 GlobalData
.gCommandLineDefines
[List
[0].strip()] = List
[1].strip()
258 GlobalData
.gCommandLineDefines
[List
[0].strip()] = "TRUE"
259 os
.environ
["WORKSPACE"] = Workspace
261 # Use the -t and -b option as gGlobalDefines's TOOLCHAIN and TARGET if they are not defined
262 if "TARGET" not in GlobalData
.gGlobalDefines
:
263 GlobalData
.gGlobalDefines
["TARGET"] = GenFdsGlobalVariable
.TargetName
264 if "TOOLCHAIN" not in GlobalData
.gGlobalDefines
:
265 GlobalData
.gGlobalDefines
["TOOLCHAIN"] = GenFdsGlobalVariable
.ToolChainTag
266 if "TOOL_CHAIN_TAG" not in GlobalData
.gGlobalDefines
:
267 GlobalData
.gGlobalDefines
['TOOL_CHAIN_TAG'] = GenFdsGlobalVariable
.ToolChainTag
269 """call Workspace build create database"""
270 GlobalData
.gDatabasePath
= os
.path
.normpath(os
.path
.join(ConfDirectoryPath
, GlobalData
.gDatabasePath
))
272 if WorkSpaceDataBase
:
273 BuildWorkSpace
= WorkSpaceDataBase
275 BuildWorkSpace
= WorkspaceDatabase()
277 # Get files real name in workspace dir
279 GlobalData
.gAllFiles
= DirCache(Workspace
)
280 GlobalData
.gWorkspace
= Workspace
282 if FdsCommandDict
.get("build_architecture_list"):
283 ArchList
= FdsCommandDict
.get("build_architecture_list").split(',')
285 ArchList
= BuildWorkSpace
.BuildObject
[GenFdsGlobalVariable
.ActivePlatform
, TAB_COMMON
, FdsCommandDict
.get("build_target"), FdsCommandDict
.get("toolchain_tag")].SupArchList
287 TargetArchList
= set(BuildWorkSpace
.BuildObject
[GenFdsGlobalVariable
.ActivePlatform
, TAB_COMMON
, FdsCommandDict
.get("build_target"), FdsCommandDict
.get("toolchain_tag")].SupArchList
) & set(ArchList
)
288 if len(TargetArchList
) == 0:
289 EdkLogger
.error("GenFds", GENFDS_ERROR
, "Target ARCH %s not in platform supported ARCH %s" % (str(ArchList
), str(BuildWorkSpace
.BuildObject
[GenFdsGlobalVariable
.ActivePlatform
, TAB_COMMON
].SupArchList
)))
291 for Arch
in ArchList
:
292 GenFdsGlobalVariable
.OutputDirFromDscDict
[Arch
] = NormPath(BuildWorkSpace
.BuildObject
[GenFdsGlobalVariable
.ActivePlatform
, Arch
, FdsCommandDict
.get("build_target"), FdsCommandDict
.get("toolchain_tag")].OutputDirectory
)
294 # assign platform name based on last entry in ArchList
295 GenFdsGlobalVariable
.PlatformName
= BuildWorkSpace
.BuildObject
[GenFdsGlobalVariable
.ActivePlatform
, ArchList
[-1], FdsCommandDict
.get("build_target"), FdsCommandDict
.get("toolchain_tag")].PlatformName
297 if FdsCommandDict
.get("platform_build_directory"):
298 OutputDirFromCommandLine
= GenFdsGlobalVariable
.ReplaceWorkspaceMacro(FdsCommandDict
.get("platform_build_directory"))
299 if not os
.path
.isabs (OutputDirFromCommandLine
):
300 OutputDirFromCommandLine
= os
.path
.join(GenFdsGlobalVariable
.WorkSpaceDir
, OutputDirFromCommandLine
)
301 for Arch
in ArchList
:
302 GenFdsGlobalVariable
.OutputDirDict
[Arch
] = OutputDirFromCommandLine
304 for Arch
in ArchList
:
305 GenFdsGlobalVariable
.OutputDirDict
[Arch
] = os
.path
.join(GenFdsGlobalVariable
.OutputDirFromDscDict
[Arch
], GenFdsGlobalVariable
.TargetName
+ '_' + GenFdsGlobalVariable
.ToolChainTag
)
307 for Key
in GenFdsGlobalVariable
.OutputDirDict
:
308 OutputDir
= GenFdsGlobalVariable
.OutputDirDict
[Key
]
309 if OutputDir
[0:2] == '..':
310 OutputDir
= os
.path
.realpath(OutputDir
)
312 if OutputDir
[1] != ':':
313 OutputDir
= os
.path
.join (GenFdsGlobalVariable
.WorkSpaceDir
, OutputDir
)
315 if not os
.path
.exists(OutputDir
):
316 EdkLogger
.error("GenFds", FILE_NOT_FOUND
, ExtraData
=OutputDir
)
317 GenFdsGlobalVariable
.OutputDirDict
[Key
] = OutputDir
319 """ Parse Fdf file, has to place after build Workspace as FDF may contain macros from DSC file """
320 if WorkSpaceDataBase
:
321 FdfParserObj
= GlobalData
.gFdfParser
323 FdfParserObj
= FdfParser(FdfFilename
)
324 FdfParserObj
.ParseFile()
326 if FdfParserObj
.CycleReferenceCheck():
327 EdkLogger
.error("GenFds", FORMAT_NOT_SUPPORTED
, "Cycle Reference Detected in FDF file")
329 if FdsCommandDict
.get("fd"):
330 if FdsCommandDict
.get("fd")[0].upper() in FdfParserObj
.Profile
.FdDict
:
331 GenFds
.OnlyGenerateThisFd
= FdsCommandDict
.get("fd")[0]
333 EdkLogger
.error("GenFds", OPTION_VALUE_INVALID
,
334 "No such an FD in FDF file: %s" % FdsCommandDict
.get("fd")[0])
336 if FdsCommandDict
.get("fv"):
337 if FdsCommandDict
.get("fv")[0].upper() in FdfParserObj
.Profile
.FvDict
:
338 GenFds
.OnlyGenerateThisFv
= FdsCommandDict
.get("fv")[0]
340 EdkLogger
.error("GenFds", OPTION_VALUE_INVALID
,
341 "No such an FV in FDF file: %s" % FdsCommandDict
.get("fv")[0])
343 if FdsCommandDict
.get("cap"):
344 if FdsCommandDict
.get("cap")[0].upper() in FdfParserObj
.Profile
.CapsuleDict
:
345 GenFds
.OnlyGenerateThisCap
= FdsCommandDict
.get("cap")[0]
347 EdkLogger
.error("GenFds", OPTION_VALUE_INVALID
,
348 "No such a Capsule in FDF file: %s" % FdsCommandDict
.get("cap")[0])
350 GenFdsGlobalVariable
.WorkSpace
= BuildWorkSpace
352 GenFdsGlobalVariable
.ArchList
= ArchList
354 # Dsc Build Data will handle Pcd Settings from CommandLine.
356 """Modify images from build output if the feature of loading driver at fixed address is on."""
357 if GenFdsGlobalVariable
.FixedLoadAddress
:
358 GenFds
.PreprocessImage(BuildWorkSpace
, GenFdsGlobalVariable
.ActivePlatform
)
360 # Record the FV Region info that may specific in the FD
361 if FdfParserObj
.Profile
.FvDict
and FdfParserObj
.Profile
.FdDict
:
362 for FvObj
in FdfParserObj
.Profile
.FvDict
.values():
363 for FdObj
in FdfParserObj
.Profile
.FdDict
.values():
364 for RegionObj
in FdObj
.RegionList
:
365 if RegionObj
.RegionType
!= BINARY_FILE_TYPE_FV
:
367 for RegionData
in RegionObj
.RegionDataList
:
368 if FvObj
.UiFvName
.upper() == RegionData
.upper():
369 if FvObj
.FvRegionInFD
:
370 if FvObj
.FvRegionInFD
!= RegionObj
.Size
:
371 EdkLogger
.error("GenFds", FORMAT_INVALID
, "The FV %s's region is specified in multiple FD with different value." %FvObj
.UiFvName
)
373 FvObj
.FvRegionInFD
= RegionObj
.Size
374 RegionObj
.BlockInfoOfRegion(FdObj
.BlockSizeList
, FvObj
)
377 GenFds
.GenFd('', FdfParserObj
, BuildWorkSpace
, ArchList
)
379 """Generate GUID cross reference file"""
380 GenFds
.GenerateGuidXRefFile(BuildWorkSpace
, ArchList
, FdfParserObj
)
382 """Display FV space info."""
383 GenFds
.DisplayFvSpaceInfo(FdfParserObj
)
386 EdkLogger
.error(X
.ToolName
, FORMAT_INVALID
, File
=X
.FileName
, Line
=X
.LineNumber
, ExtraData
=X
.Message
, RaiseError
=False)
387 ReturnCode
= FORMAT_INVALID
388 except FatalError
as X
:
389 if FdsCommandDict
.get("debug") is not None:
391 EdkLogger
.quiet(traceback
.format_exc())
392 ReturnCode
= X
.args
[0]
398 "Tools code failure",
399 ExtraData
="Please send email to edk2-devel@lists.01.org for help, attaching following call stack trace!\n",
402 EdkLogger
.quiet(traceback
.format_exc())
403 ReturnCode
= CODE_ERROR
408 def OptionsToCommandDict(Options
):
410 FdsCommandDict
["verbose"] = Options
.verbose
411 FdsCommandDict
["FixedAddress"] = Options
.FixedAddress
412 FdsCommandDict
["quiet"] = Options
.quiet
413 FdsCommandDict
["debug"] = Options
.debug
414 FdsCommandDict
["Workspace"] = Options
.Workspace
415 FdsCommandDict
["GenfdsMultiThread"] = Options
.GenfdsMultiThread
416 FdsCommandDict
["fdf_file"] = [PathClass(Options
.filename
)] if Options
.filename
else []
417 FdsCommandDict
["build_target"] = Options
.BuildTarget
418 FdsCommandDict
["toolchain_tag"] = Options
.ToolChain
419 FdsCommandDict
["active_platform"] = Options
.activePlatform
420 FdsCommandDict
["OptionPcd"] = Options
.OptionPcd
421 FdsCommandDict
["conf_directory"] = Options
.ConfDirectory
422 FdsCommandDict
["IgnoreSources"] = Options
.IgnoreSources
423 FdsCommandDict
["macro"] = Options
.Macros
424 FdsCommandDict
["build_architecture_list"] = Options
.archList
425 FdsCommandDict
["platform_build_directory"] = Options
.outputDir
426 FdsCommandDict
["fd"] = [Options
.uiFdName
] if Options
.uiFdName
else []
427 FdsCommandDict
["fv"] = [Options
.uiFvName
] if Options
.uiFvName
else []
428 FdsCommandDict
["cap"] = [Options
.uiCapName
] if Options
.uiCapName
else []
429 return FdsCommandDict
433 def SingleCheckCallback(option
, opt_str
, value
, parser
):
434 if option
not in gParamCheck
:
435 setattr(parser
.values
, option
.dest
, value
)
436 gParamCheck
.append(option
)
438 parser
.error("Option %s only allows one instance in command line!" % option
)
440 ## Parse command line options
442 # Using standard Python module optparse to parse command line option of this tool.
444 # @retval Opt A optparse.Values object containing the parsed options
446 def myOptionParser():
447 usage
= "%prog [options] -f input_file -a arch_list -b build_target -p active_platform -t tool_chain_tag -D \"MacroName [= MacroValue]\""
448 Parser
= OptionParser(usage
=usage
, description
=__copyright__
, version
="%prog " + str(versionNumber
))
449 Parser
.add_option("-f", "--file", dest
="filename", type="string", help="Name of FDF file to convert", action
="callback", callback
=SingleCheckCallback
)
450 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")
451 Parser
.add_option("-q", "--quiet", action
="store_true", type=None, help="Disable all messages except FATAL ERRORS.")
452 Parser
.add_option("-v", "--verbose", action
="store_true", type=None, help="Turn on verbose output with informational messages printed.")
453 Parser
.add_option("-d", "--debug", action
="store", type="int", help="Enable debug messages at specified level.")
454 Parser
.add_option("-p", "--platform", type="string", dest
="activePlatform", help="Set the ACTIVE_PLATFORM, overrides target.txt ACTIVE_PLATFORM setting.",
455 action
="callback", callback
=SingleCheckCallback
)
456 Parser
.add_option("-w", "--workspace", type="string", dest
="Workspace", default
=os
.environ
.get('WORKSPACE'), help="Set the WORKSPACE",
457 action
="callback", callback
=SingleCheckCallback
)
458 Parser
.add_option("-o", "--outputDir", type="string", dest
="outputDir", help="Name of Build Output directory",
459 action
="callback", callback
=SingleCheckCallback
)
460 Parser
.add_option("-r", "--rom_image", dest
="uiFdName", help="Build the image using the [FD] section named by FdUiName.")
461 Parser
.add_option("-i", "--FvImage", dest
="uiFvName", help="Build the FV image using the [FV] section named by UiFvName")
462 Parser
.add_option("-C", "--CapsuleImage", dest
="uiCapName", help="Build the Capsule image using the [Capsule] section named by UiCapName")
463 Parser
.add_option("-b", "--buildtarget", type="string", dest
="BuildTarget", help="Set the build TARGET, overrides target.txt TARGET setting.",
464 action
="callback", callback
=SingleCheckCallback
)
465 Parser
.add_option("-t", "--tagname", type="string", dest
="ToolChain", help="Using the tools: TOOL_CHAIN_TAG name to build the platform.",
466 action
="callback", callback
=SingleCheckCallback
)
467 Parser
.add_option("-D", "--define", action
="append", type="string", dest
="Macros", help="Macro: \"Name [= Value]\".")
468 Parser
.add_option("-s", "--specifyaddress", dest
="FixedAddress", action
="store_true", type=None, help="Specify driver load address.")
469 Parser
.add_option("--conf", action
="store", type="string", dest
="ConfDirectory", help="Specify the customized Conf directory.")
470 Parser
.add_option("--ignore-sources", action
="store_true", dest
="IgnoreSources", default
=False, help="Focus to a binary build and ignore all source files")
471 Parser
.add_option("--pcd", action
="append", dest
="OptionPcd", help="Set PCD value by command line. Format: \"PcdName=Value\" ")
472 Parser
.add_option("--genfds-multi-thread", action
="store_true", dest
="GenfdsMultiThread", default
=False, help="Enable GenFds multi thread to generate ffs file.")
474 Options
, _
= Parser
.parse_args()
477 ## The class implementing the EDK2 flash image generation process
479 # This process includes:
480 # 1. Collect workspace information, includes platform and module information
481 # 2. Call methods of Fd class to generate FD
482 # 3. Call methods of Fv class to generate FV that not belong to FD
484 class GenFds(object):
486 OnlyGenerateThisFd
= None
487 OnlyGenerateThisFv
= None
488 OnlyGenerateThisCap
= None
492 # @param OutputDir Output directory
493 # @param FdfParserObject FDF contents parser
494 # @param Workspace The directory of workspace
495 # @param ArchList The Arch list of platform
498 def GenFd (OutputDir
, FdfParserObject
, WorkSpace
, ArchList
):
499 GenFdsGlobalVariable
.SetDir ('', FdfParserObject
, WorkSpace
, ArchList
)
501 GenFdsGlobalVariable
.VerboseLogger(" Generate all Fd images and their required FV and Capsule images!")
502 if GenFds
.OnlyGenerateThisCap
is not None and GenFds
.OnlyGenerateThisCap
.upper() in GenFdsGlobalVariable
.FdfParser
.Profile
.CapsuleDict
:
503 CapsuleObj
= GenFdsGlobalVariable
.FdfParser
.Profile
.CapsuleDict
[GenFds
.OnlyGenerateThisCap
.upper()]
504 if CapsuleObj
is not None:
505 CapsuleObj
.GenCapsule()
508 if GenFds
.OnlyGenerateThisFd
is not None and GenFds
.OnlyGenerateThisFd
.upper() in GenFdsGlobalVariable
.FdfParser
.Profile
.FdDict
:
509 FdObj
= GenFdsGlobalVariable
.FdfParser
.Profile
.FdDict
[GenFds
.OnlyGenerateThisFd
.upper()]
510 if FdObj
is not None:
513 elif GenFds
.OnlyGenerateThisFd
is None and GenFds
.OnlyGenerateThisFv
is None:
514 for FdObj
in GenFdsGlobalVariable
.FdfParser
.Profile
.FdDict
.values():
517 GenFdsGlobalVariable
.VerboseLogger("\n Generate other FV images! ")
518 if GenFds
.OnlyGenerateThisFv
is not None and GenFds
.OnlyGenerateThisFv
.upper() in GenFdsGlobalVariable
.FdfParser
.Profile
.FvDict
:
519 FvObj
= GenFdsGlobalVariable
.FdfParser
.Profile
.FvDict
[GenFds
.OnlyGenerateThisFv
.upper()]
520 if FvObj
is not None:
522 FvObj
.AddToBuffer(Buffer
)
525 elif GenFds
.OnlyGenerateThisFv
is None:
526 for FvObj
in GenFdsGlobalVariable
.FdfParser
.Profile
.FvDict
.values():
528 FvObj
.AddToBuffer(Buffer
)
531 if GenFds
.OnlyGenerateThisFv
is None and GenFds
.OnlyGenerateThisFd
is None and GenFds
.OnlyGenerateThisCap
is None:
532 if GenFdsGlobalVariable
.FdfParser
.Profile
.CapsuleDict
!= {}:
533 GenFdsGlobalVariable
.VerboseLogger("\n Generate other Capsule images!")
534 for CapsuleObj
in GenFdsGlobalVariable
.FdfParser
.Profile
.CapsuleDict
.values():
535 CapsuleObj
.GenCapsule()
537 if GenFdsGlobalVariable
.FdfParser
.Profile
.OptRomDict
!= {}:
538 GenFdsGlobalVariable
.VerboseLogger("\n Generate all Option ROM!")
539 for OptRomObj
in GenFdsGlobalVariable
.FdfParser
.Profile
.OptRomDict
.values():
540 OptRomObj
.AddToBuffer(None)
543 def GenFfsMakefile(OutputDir
, FdfParserObject
, WorkSpace
, ArchList
, GlobalData
):
544 GenFdsGlobalVariable
.SetEnv(FdfParserObject
, WorkSpace
, ArchList
, GlobalData
)
545 for FdObj
in GenFdsGlobalVariable
.FdfParser
.Profile
.FdDict
.values():
546 FdObj
.GenFd(Flag
=True)
548 for FvObj
in GenFdsGlobalVariable
.FdfParser
.Profile
.FvDict
.values():
549 FvObj
.AddToBuffer(Buffer
=None, Flag
=True)
551 if GenFdsGlobalVariable
.FdfParser
.Profile
.OptRomDict
!= {}:
552 for OptRomObj
in GenFdsGlobalVariable
.FdfParser
.Profile
.OptRomDict
.values():
553 OptRomObj
.AddToBuffer(Buffer
=None, Flag
=True)
555 return GenFdsGlobalVariable
.FfsCmdDict
559 # @param FvObj Whose block size to get
560 # @retval int Block size value
563 def GetFvBlockSize(FvObj
):
564 DefaultBlockSize
= 0x1
566 if GenFds
.OnlyGenerateThisFd
is not None and GenFds
.OnlyGenerateThisFd
.upper() in GenFdsGlobalVariable
.FdfParser
.Profile
.FdDict
:
567 FdObj
= GenFdsGlobalVariable
.FdfParser
.Profile
.FdDict
[GenFds
.OnlyGenerateThisFd
.upper()]
569 for ElementFd
in GenFdsGlobalVariable
.FdfParser
.Profile
.FdDict
.values():
570 for ElementRegion
in ElementFd
.RegionList
:
571 if ElementRegion
.RegionType
== BINARY_FILE_TYPE_FV
:
572 for ElementRegionData
in ElementRegion
.RegionDataList
:
573 if ElementRegionData
is not None and ElementRegionData
.upper() == FvObj
.UiFvName
:
574 if FvObj
.BlockSizeList
!= []:
575 return FvObj
.BlockSizeList
[0][0]
577 return ElementRegion
.BlockSizeOfRegion(ElementFd
.BlockSizeList
)
578 if FvObj
.BlockSizeList
!= []:
579 return FvObj
.BlockSizeList
[0][0]
580 return DefaultBlockSize
582 for ElementRegion
in FdObj
.RegionList
:
583 if ElementRegion
.RegionType
== BINARY_FILE_TYPE_FV
:
584 for ElementRegionData
in ElementRegion
.RegionDataList
:
585 if ElementRegionData
is not None and ElementRegionData
.upper() == FvObj
.UiFvName
:
586 if FvObj
.BlockSizeList
!= []:
587 return FvObj
.BlockSizeList
[0][0]
589 return ElementRegion
.BlockSizeOfRegion(ElementFd
.BlockSizeList
)
590 return DefaultBlockSize
592 ## DisplayFvSpaceInfo()
594 # @param FvObj Whose block size to get
598 def DisplayFvSpaceInfo(FdfParserObject
):
602 for FvName
in FdfParserObject
.Profile
.FvDict
:
603 if len(FvName
) > MaxFvNameLength
:
604 MaxFvNameLength
= len(FvName
)
605 FvSpaceInfoFileName
= os
.path
.join(GenFdsGlobalVariable
.FvDir
, FvName
.upper() + '.Fv.map')
606 if os
.path
.exists(FvSpaceInfoFileName
):
607 FileLinesList
= getlines(FvSpaceInfoFileName
)
614 for Line
in FileLinesList
:
615 NameValue
= Line
.split('=')
616 if len(NameValue
) == 2:
617 if NameValue
[0].strip() == 'EFI_FV_TOTAL_SIZE':
619 Total
= NameValue
[1].strip()
620 if NameValue
[0].strip() == 'EFI_FV_TAKEN_SIZE':
622 Used
= NameValue
[1].strip()
623 if NameValue
[0].strip() == 'EFI_FV_SPACE_SIZE':
625 Free
= NameValue
[1].strip()
627 if TotalFound
and UsedFound
and FreeFound
:
628 FvSpaceInfoList
.append((FvName
, Total
, Used
, Free
))
630 GenFdsGlobalVariable
.InfLogger('\nFV Space Information')
631 for FvSpaceInfo
in FvSpaceInfoList
:
632 Name
= FvSpaceInfo
[0]
633 TotalSizeValue
= long(FvSpaceInfo
[1], 0)
634 UsedSizeValue
= long(FvSpaceInfo
[2], 0)
635 FreeSizeValue
= long(FvSpaceInfo
[3], 0)
636 if UsedSizeValue
== TotalSizeValue
:
639 Percentage
= str((UsedSizeValue
+ 0.0) / TotalSizeValue
)[0:4].lstrip('0.')
641 GenFdsGlobalVariable
.InfLogger(Name
+ ' ' + '[' + Percentage
+ '%Full] ' + str(TotalSizeValue
) + ' total, ' + str(UsedSizeValue
) + ' used, ' + str(FreeSizeValue
) + ' free')
645 # @param BuildDb Database from build meta data files
646 # @param DscFile modules from dsc file will be preprocessed
650 def PreprocessImage(BuildDb
, DscFile
):
651 PcdDict
= BuildDb
.BuildObject
[DscFile
, TAB_COMMON
, GenFdsGlobalVariable
.TargetName
, GenFdsGlobalVariable
.ToolChainTag
].Pcds
654 PcdObj
= PcdDict
[Key
]
655 if PcdObj
.TokenCName
== 'PcdBsBaseAddress':
656 PcdValue
= PcdObj
.DefaultValue
662 Int64PcdValue
= long(PcdValue
, 0)
663 if Int64PcdValue
== 0 or Int64PcdValue
< -1:
667 if Int64PcdValue
> 0:
668 TopAddress
= Int64PcdValue
670 ModuleDict
= BuildDb
.BuildObject
[DscFile
, TAB_COMMON
, GenFdsGlobalVariable
.TargetName
, GenFdsGlobalVariable
.ToolChainTag
].Modules
671 for Key
in ModuleDict
:
672 ModuleObj
= BuildDb
.BuildObject
[Key
, TAB_COMMON
, GenFdsGlobalVariable
.TargetName
, GenFdsGlobalVariable
.ToolChainTag
]
673 print(ModuleObj
.BaseName
+ ' ' + ModuleObj
.ModuleType
)
676 def GenerateGuidXRefFile(BuildDb
, ArchList
, FdfParserObj
):
677 GuidXRefFileName
= os
.path
.join(GenFdsGlobalVariable
.FvDir
, "Guid.xref")
678 GuidXRefFile
= BytesIO('')
683 for Arch
in ArchList
:
684 PlatformDataBase
= BuildDb
.BuildObject
[GenFdsGlobalVariable
.ActivePlatform
, Arch
, GenFdsGlobalVariable
.TargetName
, GenFdsGlobalVariable
.ToolChainTag
]
685 PkgList
= GenFdsGlobalVariable
.WorkSpace
.GetPackageList(GenFdsGlobalVariable
.ActivePlatform
, Arch
, GenFdsGlobalVariable
.TargetName
, GenFdsGlobalVariable
.ToolChainTag
)
687 PkgGuidDict
.update(P
.Guids
)
688 for Name
, Guid
in PlatformDataBase
.Pcds
:
689 Pcd
= PlatformDataBase
.Pcds
[Name
, Guid
]
690 if Pcd
.Type
in [TAB_PCDS_DYNAMIC_HII
, TAB_PCDS_DYNAMIC_EX_HII
]:
691 for SkuId
in Pcd
.SkuInfoList
:
692 Sku
= Pcd
.SkuInfoList
[SkuId
]
693 if Sku
.VariableGuid
and Sku
.VariableGuid
in PkgGuidDict
.keys():
694 GuidDict
[Sku
.VariableGuid
] = PkgGuidDict
[Sku
.VariableGuid
]
695 for ModuleFile
in PlatformDataBase
.Modules
:
696 Module
= BuildDb
.BuildObject
[ModuleFile
, Arch
, GenFdsGlobalVariable
.TargetName
, GenFdsGlobalVariable
.ToolChainTag
]
697 if Module
in ModuleList
:
700 ModuleList
.append(Module
)
701 if GlobalData
.gGuidPattern
.match(ModuleFile
.BaseName
):
702 GuidXRefFile
.write("%s %s\n" % (ModuleFile
.BaseName
, Module
.BaseName
))
704 GuidXRefFile
.write("%s %s\n" % (Module
.Guid
, Module
.BaseName
))
705 GuidDict
.update(Module
.Protocols
)
706 GuidDict
.update(Module
.Guids
)
707 GuidDict
.update(Module
.Ppis
)
708 for FvName
in FdfParserObj
.Profile
.FvDict
:
709 for FfsObj
in FdfParserObj
.Profile
.FvDict
[FvName
].FfsList
:
710 if not isinstance(FfsObj
, FileStatement
):
711 InfPath
= PathClass(NormPath(mws
.join(GenFdsGlobalVariable
.WorkSpaceDir
, FfsObj
.InfFileName
)))
712 FdfModule
= BuildDb
.BuildObject
[InfPath
, Arch
, GenFdsGlobalVariable
.TargetName
, GenFdsGlobalVariable
.ToolChainTag
]
713 if FdfModule
in ModuleList
:
716 ModuleList
.append(FdfModule
)
717 GuidXRefFile
.write("%s %s\n" % (FdfModule
.Guid
, FdfModule
.BaseName
))
718 GuidDict
.update(FdfModule
.Protocols
)
719 GuidDict
.update(FdfModule
.Guids
)
720 GuidDict
.update(FdfModule
.Ppis
)
722 FileStatementGuid
= FfsObj
.NameGuid
723 if FileStatementGuid
in FileGuidList
:
726 FileGuidList
.append(FileStatementGuid
)
728 FfsPath
= os
.path
.join(GenFdsGlobalVariable
.FvDir
, 'Ffs')
729 FfsPath
= glob(os
.path
.join(FfsPath
, FileStatementGuid
) + TAB_STAR
)
732 if not os
.path
.exists(FfsPath
[0]):
735 ReFileEnds
= compile('\S+(.ui)$|\S+(fv.sec.txt)$|\S+(.pe32.txt)$|\S+(.te.txt)$|\S+(.pic.txt)$|\S+(.raw.txt)$|\S+(.ffs.txt)$')
736 FileList
= os
.listdir(FfsPath
[0])
737 for File
in FileList
:
738 Match
= ReFileEnds
.search(File
)
740 for Index
in range(1, 8):
741 if Match
.group(Index
) and Match
.group(Index
) in MatchDict
:
742 MatchDict
[Match
.group(Index
)].append(File
)
743 elif Match
.group(Index
):
744 MatchDict
[Match
.group(Index
)] = [File
]
747 if '.ui' in MatchDict
:
748 for File
in MatchDict
['.ui']:
749 with
open(os
.path
.join(FfsPath
[0], File
), 'rb') as F
:
753 TmpStr
= unpack('%dh' % ((length
- 4) / 2), F
.read())
754 Name
= ''.join(chr(c
) for c
in TmpStr
[:-1])
757 if 'fv.sec.txt' in MatchDict
:
758 FileList
= MatchDict
['fv.sec.txt']
759 elif '.pe32.txt' in MatchDict
:
760 FileList
= MatchDict
['.pe32.txt']
761 elif '.te.txt' in MatchDict
:
762 FileList
= MatchDict
['.te.txt']
763 elif '.pic.txt' in MatchDict
:
764 FileList
= MatchDict
['.pic.txt']
765 elif '.raw.txt' in MatchDict
:
766 FileList
= MatchDict
['.raw.txt']
767 elif '.ffs.txt' in MatchDict
:
768 FileList
= MatchDict
['.ffs.txt']
771 for File
in FileList
:
772 with
open(os
.path
.join(FfsPath
[0], File
), 'r') as F
:
773 Name
.append((F
.read().split()[-1]))
777 Name
= ' '.join(Name
) if isinstance(Name
, type([])) else Name
778 GuidXRefFile
.write("%s %s\n" %(FileStatementGuid
, Name
))
780 # Append GUIDs, Protocols, and PPIs to the Xref file
781 GuidXRefFile
.write("\n")
782 for key
, item
in GuidDict
.items():
783 GuidXRefFile
.write("%s %s\n" % (GuidStructureStringToGuidString(item
).upper(), key
))
785 if GuidXRefFile
.getvalue():
786 SaveFileOnChange(GuidXRefFileName
, GuidXRefFile
.getvalue(), False)
787 GenFdsGlobalVariable
.InfLogger("\nGUID cross reference file can be found at %s" % GuidXRefFileName
)
788 elif os
.path
.exists(GuidXRefFileName
):
789 os
.remove(GuidXRefFileName
)
793 if __name__
== '__main__':
795 ## 0-127 is a safe return range, and 1 is a standard default error