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 GlobalData
.BuildOptionPcd
= FdsCommandDict
.get("OptionPcd") if FdsCommandDict
.get("OptionPcd") else {}
193 GenFdsGlobalVariable
.ActivePlatform
= PathClass(NormPath(ActivePlatform
))
195 if FdsCommandDict
.get("conf_directory"):
196 # Get alternate Conf location, if it is absolute, then just use the absolute directory name
197 ConfDirectoryPath
= os
.path
.normpath(FdsCommandDict
.get("conf_directory"))
198 if ConfDirectoryPath
.startswith('"'):
199 ConfDirectoryPath
= ConfDirectoryPath
[1:]
200 if ConfDirectoryPath
.endswith('"'):
201 ConfDirectoryPath
= ConfDirectoryPath
[:-1]
202 if not os
.path
.isabs(ConfDirectoryPath
):
203 # Since alternate directory name is not absolute, the alternate directory is located within the WORKSPACE
204 # This also handles someone specifying the Conf directory in the workspace. Using --conf=Conf
205 ConfDirectoryPath
= os
.path
.join(GenFdsGlobalVariable
.WorkSpaceDir
, ConfDirectoryPath
)
207 if "CONF_PATH" in os
.environ
:
208 ConfDirectoryPath
= os
.path
.normcase(os
.environ
["CONF_PATH"])
210 # Get standard WORKSPACE/Conf, use the absolute path to the WORKSPACE/Conf
211 ConfDirectoryPath
= mws
.join(GenFdsGlobalVariable
.WorkSpaceDir
, 'Conf')
212 GenFdsGlobalVariable
.ConfDir
= ConfDirectoryPath
213 if not GlobalData
.gConfDirectory
:
214 GlobalData
.gConfDirectory
= GenFdsGlobalVariable
.ConfDir
215 BuildConfigurationFile
= os
.path
.normpath(os
.path
.join(ConfDirectoryPath
, "target.txt"))
216 if os
.path
.isfile(BuildConfigurationFile
) == True:
217 TargetTxt
= TargetTxtClassObject()
218 TargetTxt
.LoadTargetTxtFile(BuildConfigurationFile
)
219 # if no build target given in command line, get it from target.txt
220 if not GenFdsGlobalVariable
.TargetName
:
221 BuildTargetList
= TargetTxt
.TargetTxtDictionary
[TAB_TAT_DEFINES_TARGET
]
222 if len(BuildTargetList
) != 1:
223 EdkLogger
.error("GenFds", OPTION_VALUE_INVALID
, ExtraData
="Only allows one instance for Target.")
224 GenFdsGlobalVariable
.TargetName
= BuildTargetList
[0]
226 # if no tool chain given in command line, get it from target.txt
227 if not GenFdsGlobalVariable
.ToolChainTag
:
228 ToolChainList
= TargetTxt
.TargetTxtDictionary
[TAB_TAT_DEFINES_TOOL_CHAIN_TAG
]
229 if ToolChainList
is None or len(ToolChainList
) == 0:
230 EdkLogger
.error("GenFds", RESOURCE_NOT_AVAILABLE
, ExtraData
="No toolchain given. Don't know how to build.")
231 if len(ToolChainList
) != 1:
232 EdkLogger
.error("GenFds", OPTION_VALUE_INVALID
, ExtraData
="Only allows one instance for ToolChain.")
233 GenFdsGlobalVariable
.ToolChainTag
= ToolChainList
[0]
235 EdkLogger
.error("GenFds", FILE_NOT_FOUND
, ExtraData
=BuildConfigurationFile
)
237 #Set global flag for build mode
238 GlobalData
.gIgnoreSource
= FdsCommandDict
.get("IgnoreSources")
240 if FdsCommandDict
.get("macro"):
241 for Pair
in FdsCommandDict
.get("macro"):
242 if Pair
.startswith('"'):
244 if Pair
.endswith('"'):
246 List
= Pair
.split('=')
248 if not List
[1].strip():
249 EdkLogger
.error("GenFds", OPTION_VALUE_INVALID
, ExtraData
="No Value given for Macro %s" %List
[0])
250 if List
[0].strip() in ["WORKSPACE", "TARGET", "TOOLCHAIN"]:
251 GlobalData
.gGlobalDefines
[List
[0].strip()] = List
[1].strip()
253 GlobalData
.gCommandLineDefines
[List
[0].strip()] = List
[1].strip()
255 GlobalData
.gCommandLineDefines
[List
[0].strip()] = "TRUE"
256 os
.environ
["WORKSPACE"] = Workspace
258 # Use the -t and -b option as gGlobalDefines's TOOLCHAIN and TARGET if they are not defined
259 if "TARGET" not in GlobalData
.gGlobalDefines
:
260 GlobalData
.gGlobalDefines
["TARGET"] = GenFdsGlobalVariable
.TargetName
261 if "TOOLCHAIN" not in GlobalData
.gGlobalDefines
:
262 GlobalData
.gGlobalDefines
["TOOLCHAIN"] = GenFdsGlobalVariable
.ToolChainTag
263 if "TOOL_CHAIN_TAG" not in GlobalData
.gGlobalDefines
:
264 GlobalData
.gGlobalDefines
['TOOL_CHAIN_TAG'] = GenFdsGlobalVariable
.ToolChainTag
266 """call Workspace build create database"""
267 GlobalData
.gDatabasePath
= os
.path
.normpath(os
.path
.join(ConfDirectoryPath
, GlobalData
.gDatabasePath
))
269 if WorkSpaceDataBase
:
270 BuildWorkSpace
= WorkSpaceDataBase
272 BuildWorkSpace
= WorkspaceDatabase()
274 # Get files real name in workspace dir
276 GlobalData
.gAllFiles
= DirCache(Workspace
)
277 GlobalData
.gWorkspace
= Workspace
279 if FdsCommandDict
.get("build_architecture_list"):
280 ArchList
= FdsCommandDict
.get("build_architecture_list").split(',')
282 ArchList
= BuildWorkSpace
.BuildObject
[GenFdsGlobalVariable
.ActivePlatform
, TAB_COMMON
, FdsCommandDict
.get("build_target"), FdsCommandDict
.get("toolchain_tag")].SupArchList
284 TargetArchList
= set(BuildWorkSpace
.BuildObject
[GenFdsGlobalVariable
.ActivePlatform
, TAB_COMMON
, FdsCommandDict
.get("build_target"), FdsCommandDict
.get("toolchain_tag")].SupArchList
) & set(ArchList
)
285 if len(TargetArchList
) == 0:
286 EdkLogger
.error("GenFds", GENFDS_ERROR
, "Target ARCH %s not in platform supported ARCH %s" % (str(ArchList
), str(BuildWorkSpace
.BuildObject
[GenFdsGlobalVariable
.ActivePlatform
, TAB_COMMON
].SupArchList
)))
288 for Arch
in ArchList
:
289 GenFdsGlobalVariable
.OutputDirFromDscDict
[Arch
] = NormPath(BuildWorkSpace
.BuildObject
[GenFdsGlobalVariable
.ActivePlatform
, Arch
, FdsCommandDict
.get("build_target"), FdsCommandDict
.get("toolchain_tag")].OutputDirectory
)
291 # assign platform name based on last entry in ArchList
292 GenFdsGlobalVariable
.PlatformName
= BuildWorkSpace
.BuildObject
[GenFdsGlobalVariable
.ActivePlatform
, ArchList
[-1], FdsCommandDict
.get("build_target"), FdsCommandDict
.get("toolchain_tag")].PlatformName
294 if FdsCommandDict
.get("platform_build_directory"):
295 OutputDirFromCommandLine
= GenFdsGlobalVariable
.ReplaceWorkspaceMacro(FdsCommandDict
.get("platform_build_directory"))
296 if not os
.path
.isabs (OutputDirFromCommandLine
):
297 OutputDirFromCommandLine
= os
.path
.join(GenFdsGlobalVariable
.WorkSpaceDir
, OutputDirFromCommandLine
)
298 for Arch
in ArchList
:
299 GenFdsGlobalVariable
.OutputDirDict
[Arch
] = OutputDirFromCommandLine
301 for Arch
in ArchList
:
302 GenFdsGlobalVariable
.OutputDirDict
[Arch
] = os
.path
.join(GenFdsGlobalVariable
.OutputDirFromDscDict
[Arch
], GenFdsGlobalVariable
.TargetName
+ '_' + GenFdsGlobalVariable
.ToolChainTag
)
304 for Key
in GenFdsGlobalVariable
.OutputDirDict
:
305 OutputDir
= GenFdsGlobalVariable
.OutputDirDict
[Key
]
306 if OutputDir
[0:2] == '..':
307 OutputDir
= os
.path
.realpath(OutputDir
)
309 if OutputDir
[1] != ':':
310 OutputDir
= os
.path
.join (GenFdsGlobalVariable
.WorkSpaceDir
, OutputDir
)
312 if not os
.path
.exists(OutputDir
):
313 EdkLogger
.error("GenFds", FILE_NOT_FOUND
, ExtraData
=OutputDir
)
314 GenFdsGlobalVariable
.OutputDirDict
[Key
] = OutputDir
316 """ Parse Fdf file, has to place after build Workspace as FDF may contain macros from DSC file """
317 if WorkSpaceDataBase
:
318 FdfParserObj
= GlobalData
.gFdfParser
320 FdfParserObj
= FdfParser(FdfFilename
)
321 FdfParserObj
.ParseFile()
323 if FdfParserObj
.CycleReferenceCheck():
324 EdkLogger
.error("GenFds", FORMAT_NOT_SUPPORTED
, "Cycle Reference Detected in FDF file")
326 if FdsCommandDict
.get("fd"):
327 if FdsCommandDict
.get("fd")[0].upper() in FdfParserObj
.Profile
.FdDict
:
328 GenFds
.OnlyGenerateThisFd
= FdsCommandDict
.get("fd")[0]
330 EdkLogger
.error("GenFds", OPTION_VALUE_INVALID
,
331 "No such an FD in FDF file: %s" % FdsCommandDict
.get("fd")[0])
333 if FdsCommandDict
.get("fv"):
334 if FdsCommandDict
.get("fv")[0].upper() in FdfParserObj
.Profile
.FvDict
:
335 GenFds
.OnlyGenerateThisFv
= FdsCommandDict
.get("fv")[0]
337 EdkLogger
.error("GenFds", OPTION_VALUE_INVALID
,
338 "No such an FV in FDF file: %s" % FdsCommandDict
.get("fv")[0])
340 if FdsCommandDict
.get("cap"):
341 if FdsCommandDict
.get("cap")[0].upper() in FdfParserObj
.Profile
.CapsuleDict
:
342 GenFds
.OnlyGenerateThisCap
= FdsCommandDict
.get("cap")[0]
344 EdkLogger
.error("GenFds", OPTION_VALUE_INVALID
,
345 "No such a Capsule in FDF file: %s" % FdsCommandDict
.get("cap")[0])
347 GenFdsGlobalVariable
.WorkSpace
= BuildWorkSpace
349 GenFdsGlobalVariable
.ArchList
= ArchList
351 # Dsc Build Data will handle Pcd Settings from CommandLine.
353 """Modify images from build output if the feature of loading driver at fixed address is on."""
354 if GenFdsGlobalVariable
.FixedLoadAddress
:
355 GenFds
.PreprocessImage(BuildWorkSpace
, GenFdsGlobalVariable
.ActivePlatform
)
357 # Record the FV Region info that may specific in the FD
358 if FdfParserObj
.Profile
.FvDict
and FdfParserObj
.Profile
.FdDict
:
359 for FvObj
in FdfParserObj
.Profile
.FvDict
.values():
360 for FdObj
in FdfParserObj
.Profile
.FdDict
.values():
361 for RegionObj
in FdObj
.RegionList
:
362 if RegionObj
.RegionType
!= BINARY_FILE_TYPE_FV
:
364 for RegionData
in RegionObj
.RegionDataList
:
365 if FvObj
.UiFvName
.upper() == RegionData
.upper():
366 if FvObj
.FvRegionInFD
:
367 if FvObj
.FvRegionInFD
!= RegionObj
.Size
:
368 EdkLogger
.error("GenFds", FORMAT_INVALID
, "The FV %s's region is specified in multiple FD with different value." %FvObj
.UiFvName
)
370 FvObj
.FvRegionInFD
= RegionObj
.Size
371 RegionObj
.BlockInfoOfRegion(FdObj
.BlockSizeList
, FvObj
)
374 GenFds
.GenFd('', FdfParserObj
, BuildWorkSpace
, ArchList
)
376 """Generate GUID cross reference file"""
377 GenFds
.GenerateGuidXRefFile(BuildWorkSpace
, ArchList
, FdfParserObj
)
379 """Display FV space info."""
380 GenFds
.DisplayFvSpaceInfo(FdfParserObj
)
383 EdkLogger
.error(X
.ToolName
, FORMAT_INVALID
, File
=X
.FileName
, Line
=X
.LineNumber
, ExtraData
=X
.Message
, RaiseError
=False)
384 ReturnCode
= FORMAT_INVALID
385 except FatalError
as X
:
386 if FdsCommandDict
.get("debug") is not None:
388 EdkLogger
.quiet(traceback
.format_exc())
389 ReturnCode
= X
.args
[0]
395 "Tools code failure",
396 ExtraData
="Please send email to edk2-devel@lists.01.org for help, attaching following call stack trace!\n",
399 EdkLogger
.quiet(traceback
.format_exc())
400 ReturnCode
= CODE_ERROR
405 def OptionsToCommandDict(Options
):
407 FdsCommandDict
["verbose"] = Options
.verbose
408 FdsCommandDict
["FixedAddress"] = Options
.FixedAddress
409 FdsCommandDict
["quiet"] = Options
.quiet
410 FdsCommandDict
["debug"] = Options
.debug
411 FdsCommandDict
["Workspace"] = Options
.Workspace
412 FdsCommandDict
["GenfdsMultiThread"] = Options
.GenfdsMultiThread
413 FdsCommandDict
["fdf_file"] = [PathClass(Options
.filename
)] if Options
.filename
else []
414 FdsCommandDict
["build_target"] = Options
.BuildTarget
415 FdsCommandDict
["toolchain_tag"] = Options
.ToolChain
416 FdsCommandDict
["active_platform"] = Options
.activePlatform
417 FdsCommandDict
["OptionPcd"] = Options
.OptionPcd
418 FdsCommandDict
["conf_directory"] = Options
.ConfDirectory
419 FdsCommandDict
["IgnoreSources"] = Options
.IgnoreSources
420 FdsCommandDict
["macro"] = Options
.Macros
421 FdsCommandDict
["build_architecture_list"] = Options
.archList
422 FdsCommandDict
["platform_build_directory"] = Options
.outputDir
423 FdsCommandDict
["fd"] = [Options
.uiFdName
] if Options
.uiFdName
else []
424 FdsCommandDict
["fv"] = [Options
.uiFvName
] if Options
.uiFvName
else []
425 FdsCommandDict
["cap"] = [Options
.uiCapName
] if Options
.uiCapName
else []
426 return FdsCommandDict
430 def SingleCheckCallback(option
, opt_str
, value
, parser
):
431 if option
not in gParamCheck
:
432 setattr(parser
.values
, option
.dest
, value
)
433 gParamCheck
.append(option
)
435 parser
.error("Option %s only allows one instance in command line!" % option
)
437 ## Parse command line options
439 # Using standard Python module optparse to parse command line option of this tool.
441 # @retval Opt A optparse.Values object containing the parsed options
443 def myOptionParser():
444 usage
= "%prog [options] -f input_file -a arch_list -b build_target -p active_platform -t tool_chain_tag -D \"MacroName [= MacroValue]\""
445 Parser
= OptionParser(usage
=usage
, description
=__copyright__
, version
="%prog " + str(versionNumber
))
446 Parser
.add_option("-f", "--file", dest
="filename", type="string", help="Name of FDF file to convert", action
="callback", callback
=SingleCheckCallback
)
447 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")
448 Parser
.add_option("-q", "--quiet", action
="store_true", type=None, help="Disable all messages except FATAL ERRORS.")
449 Parser
.add_option("-v", "--verbose", action
="store_true", type=None, help="Turn on verbose output with informational messages printed.")
450 Parser
.add_option("-d", "--debug", action
="store", type="int", help="Enable debug messages at specified level.")
451 Parser
.add_option("-p", "--platform", type="string", dest
="activePlatform", help="Set the ACTIVE_PLATFORM, overrides target.txt ACTIVE_PLATFORM setting.",
452 action
="callback", callback
=SingleCheckCallback
)
453 Parser
.add_option("-w", "--workspace", type="string", dest
="Workspace", default
=os
.environ
.get('WORKSPACE'), help="Set the WORKSPACE",
454 action
="callback", callback
=SingleCheckCallback
)
455 Parser
.add_option("-o", "--outputDir", type="string", dest
="outputDir", help="Name of Build Output directory",
456 action
="callback", callback
=SingleCheckCallback
)
457 Parser
.add_option("-r", "--rom_image", dest
="uiFdName", help="Build the image using the [FD] section named by FdUiName.")
458 Parser
.add_option("-i", "--FvImage", dest
="uiFvName", help="Build the FV image using the [FV] section named by UiFvName")
459 Parser
.add_option("-C", "--CapsuleImage", dest
="uiCapName", help="Build the Capsule image using the [Capsule] section named by UiCapName")
460 Parser
.add_option("-b", "--buildtarget", type="string", dest
="BuildTarget", help="Set the build TARGET, overrides target.txt TARGET setting.",
461 action
="callback", callback
=SingleCheckCallback
)
462 Parser
.add_option("-t", "--tagname", type="string", dest
="ToolChain", help="Using the tools: TOOL_CHAIN_TAG name to build the platform.",
463 action
="callback", callback
=SingleCheckCallback
)
464 Parser
.add_option("-D", "--define", action
="append", type="string", dest
="Macros", help="Macro: \"Name [= Value]\".")
465 Parser
.add_option("-s", "--specifyaddress", dest
="FixedAddress", action
="store_true", type=None, help="Specify driver load address.")
466 Parser
.add_option("--conf", action
="store", type="string", dest
="ConfDirectory", help="Specify the customized Conf directory.")
467 Parser
.add_option("--ignore-sources", action
="store_true", dest
="IgnoreSources", default
=False, help="Focus to a binary build and ignore all source files")
468 Parser
.add_option("--pcd", action
="append", dest
="OptionPcd", help="Set PCD value by command line. Format: \"PcdName=Value\" ")
469 Parser
.add_option("--genfds-multi-thread", action
="store_true", dest
="GenfdsMultiThread", default
=False, help="Enable GenFds multi thread to generate ffs file.")
471 Options
, _
= Parser
.parse_args()
474 ## The class implementing the EDK2 flash image generation process
476 # This process includes:
477 # 1. Collect workspace information, includes platform and module information
478 # 2. Call methods of Fd class to generate FD
479 # 3. Call methods of Fv class to generate FV that not belong to FD
481 class GenFds(object):
483 OnlyGenerateThisFd
= None
484 OnlyGenerateThisFv
= None
485 OnlyGenerateThisCap
= None
489 # @param OutputDir Output directory
490 # @param FdfParserObject FDF contents parser
491 # @param Workspace The directory of workspace
492 # @param ArchList The Arch list of platform
495 def GenFd (OutputDir
, FdfParserObject
, WorkSpace
, ArchList
):
496 GenFdsGlobalVariable
.SetDir ('', FdfParserObject
, WorkSpace
, ArchList
)
498 GenFdsGlobalVariable
.VerboseLogger(" Generate all Fd images and their required FV and Capsule images!")
499 if GenFds
.OnlyGenerateThisCap
is not None and GenFds
.OnlyGenerateThisCap
.upper() in GenFdsGlobalVariable
.FdfParser
.Profile
.CapsuleDict
:
500 CapsuleObj
= GenFdsGlobalVariable
.FdfParser
.Profile
.CapsuleDict
[GenFds
.OnlyGenerateThisCap
.upper()]
501 if CapsuleObj
is not None:
502 CapsuleObj
.GenCapsule()
505 if GenFds
.OnlyGenerateThisFd
is not None and GenFds
.OnlyGenerateThisFd
.upper() in GenFdsGlobalVariable
.FdfParser
.Profile
.FdDict
:
506 FdObj
= GenFdsGlobalVariable
.FdfParser
.Profile
.FdDict
[GenFds
.OnlyGenerateThisFd
.upper()]
507 if FdObj
is not None:
510 elif GenFds
.OnlyGenerateThisFd
is None and GenFds
.OnlyGenerateThisFv
is None:
511 for FdObj
in GenFdsGlobalVariable
.FdfParser
.Profile
.FdDict
.values():
514 GenFdsGlobalVariable
.VerboseLogger("\n Generate other FV images! ")
515 if GenFds
.OnlyGenerateThisFv
is not None and GenFds
.OnlyGenerateThisFv
.upper() in GenFdsGlobalVariable
.FdfParser
.Profile
.FvDict
:
516 FvObj
= GenFdsGlobalVariable
.FdfParser
.Profile
.FvDict
[GenFds
.OnlyGenerateThisFv
.upper()]
517 if FvObj
is not None:
519 FvObj
.AddToBuffer(Buffer
)
522 elif GenFds
.OnlyGenerateThisFv
is None:
523 for FvObj
in GenFdsGlobalVariable
.FdfParser
.Profile
.FvDict
.values():
525 FvObj
.AddToBuffer(Buffer
)
528 if GenFds
.OnlyGenerateThisFv
is None and GenFds
.OnlyGenerateThisFd
is None and GenFds
.OnlyGenerateThisCap
is None:
529 if GenFdsGlobalVariable
.FdfParser
.Profile
.CapsuleDict
!= {}:
530 GenFdsGlobalVariable
.VerboseLogger("\n Generate other Capsule images!")
531 for CapsuleObj
in GenFdsGlobalVariable
.FdfParser
.Profile
.CapsuleDict
.values():
532 CapsuleObj
.GenCapsule()
534 if GenFdsGlobalVariable
.FdfParser
.Profile
.OptRomDict
!= {}:
535 GenFdsGlobalVariable
.VerboseLogger("\n Generate all Option ROM!")
536 for OptRomObj
in GenFdsGlobalVariable
.FdfParser
.Profile
.OptRomDict
.values():
537 OptRomObj
.AddToBuffer(None)
540 def GenFfsMakefile(OutputDir
, FdfParserObject
, WorkSpace
, ArchList
, GlobalData
):
541 GenFdsGlobalVariable
.SetEnv(FdfParserObject
, WorkSpace
, ArchList
, GlobalData
)
542 for FdObj
in GenFdsGlobalVariable
.FdfParser
.Profile
.FdDict
.values():
543 FdObj
.GenFd(Flag
=True)
545 for FvObj
in GenFdsGlobalVariable
.FdfParser
.Profile
.FvDict
.values():
546 FvObj
.AddToBuffer(Buffer
=None, Flag
=True)
548 if GenFdsGlobalVariable
.FdfParser
.Profile
.OptRomDict
!= {}:
549 for OptRomObj
in GenFdsGlobalVariable
.FdfParser
.Profile
.OptRomDict
.values():
550 OptRomObj
.AddToBuffer(Buffer
=None, Flag
=True)
552 return GenFdsGlobalVariable
.FfsCmdDict
556 # @param FvObj Whose block size to get
557 # @retval int Block size value
560 def GetFvBlockSize(FvObj
):
561 DefaultBlockSize
= 0x1
563 if GenFds
.OnlyGenerateThisFd
is not None and GenFds
.OnlyGenerateThisFd
.upper() in GenFdsGlobalVariable
.FdfParser
.Profile
.FdDict
:
564 FdObj
= GenFdsGlobalVariable
.FdfParser
.Profile
.FdDict
[GenFds
.OnlyGenerateThisFd
.upper()]
566 for ElementFd
in GenFdsGlobalVariable
.FdfParser
.Profile
.FdDict
.values():
567 for ElementRegion
in ElementFd
.RegionList
:
568 if ElementRegion
.RegionType
== BINARY_FILE_TYPE_FV
:
569 for ElementRegionData
in ElementRegion
.RegionDataList
:
570 if ElementRegionData
is not None and ElementRegionData
.upper() == FvObj
.UiFvName
:
571 if FvObj
.BlockSizeList
!= []:
572 return FvObj
.BlockSizeList
[0][0]
574 return ElementRegion
.BlockSizeOfRegion(ElementFd
.BlockSizeList
)
575 if FvObj
.BlockSizeList
!= []:
576 return FvObj
.BlockSizeList
[0][0]
577 return DefaultBlockSize
579 for ElementRegion
in FdObj
.RegionList
:
580 if ElementRegion
.RegionType
== BINARY_FILE_TYPE_FV
:
581 for ElementRegionData
in ElementRegion
.RegionDataList
:
582 if ElementRegionData
is not None and ElementRegionData
.upper() == FvObj
.UiFvName
:
583 if FvObj
.BlockSizeList
!= []:
584 return FvObj
.BlockSizeList
[0][0]
586 return ElementRegion
.BlockSizeOfRegion(ElementFd
.BlockSizeList
)
587 return DefaultBlockSize
589 ## DisplayFvSpaceInfo()
591 # @param FvObj Whose block size to get
595 def DisplayFvSpaceInfo(FdfParserObject
):
599 for FvName
in FdfParserObject
.Profile
.FvDict
:
600 if len(FvName
) > MaxFvNameLength
:
601 MaxFvNameLength
= len(FvName
)
602 FvSpaceInfoFileName
= os
.path
.join(GenFdsGlobalVariable
.FvDir
, FvName
.upper() + '.Fv.map')
603 if os
.path
.exists(FvSpaceInfoFileName
):
604 FileLinesList
= getlines(FvSpaceInfoFileName
)
611 for Line
in FileLinesList
:
612 NameValue
= Line
.split('=')
613 if len(NameValue
) == 2:
614 if NameValue
[0].strip() == 'EFI_FV_TOTAL_SIZE':
616 Total
= NameValue
[1].strip()
617 if NameValue
[0].strip() == 'EFI_FV_TAKEN_SIZE':
619 Used
= NameValue
[1].strip()
620 if NameValue
[0].strip() == 'EFI_FV_SPACE_SIZE':
622 Free
= NameValue
[1].strip()
624 if TotalFound
and UsedFound
and FreeFound
:
625 FvSpaceInfoList
.append((FvName
, Total
, Used
, Free
))
627 GenFdsGlobalVariable
.InfLogger('\nFV Space Information')
628 for FvSpaceInfo
in FvSpaceInfoList
:
629 Name
= FvSpaceInfo
[0]
630 TotalSizeValue
= long(FvSpaceInfo
[1], 0)
631 UsedSizeValue
= long(FvSpaceInfo
[2], 0)
632 FreeSizeValue
= long(FvSpaceInfo
[3], 0)
633 if UsedSizeValue
== TotalSizeValue
:
636 Percentage
= str((UsedSizeValue
+ 0.0) / TotalSizeValue
)[0:4].lstrip('0.')
638 GenFdsGlobalVariable
.InfLogger(Name
+ ' ' + '[' + Percentage
+ '%Full] ' + str(TotalSizeValue
) + ' total, ' + str(UsedSizeValue
) + ' used, ' + str(FreeSizeValue
) + ' free')
642 # @param BuildDb Database from build meta data files
643 # @param DscFile modules from dsc file will be preprocessed
647 def PreprocessImage(BuildDb
, DscFile
):
648 PcdDict
= BuildDb
.BuildObject
[DscFile
, TAB_COMMON
, GenFdsGlobalVariable
.TargetName
, GenFdsGlobalVariable
.ToolChainTag
].Pcds
651 PcdObj
= PcdDict
[Key
]
652 if PcdObj
.TokenCName
== 'PcdBsBaseAddress':
653 PcdValue
= PcdObj
.DefaultValue
659 Int64PcdValue
= long(PcdValue
, 0)
660 if Int64PcdValue
== 0 or Int64PcdValue
< -1:
664 if Int64PcdValue
> 0:
665 TopAddress
= Int64PcdValue
667 ModuleDict
= BuildDb
.BuildObject
[DscFile
, TAB_COMMON
, GenFdsGlobalVariable
.TargetName
, GenFdsGlobalVariable
.ToolChainTag
].Modules
668 for Key
in ModuleDict
:
669 ModuleObj
= BuildDb
.BuildObject
[Key
, TAB_COMMON
, GenFdsGlobalVariable
.TargetName
, GenFdsGlobalVariable
.ToolChainTag
]
670 print(ModuleObj
.BaseName
+ ' ' + ModuleObj
.ModuleType
)
673 def GenerateGuidXRefFile(BuildDb
, ArchList
, FdfParserObj
):
674 GuidXRefFileName
= os
.path
.join(GenFdsGlobalVariable
.FvDir
, "Guid.xref")
675 GuidXRefFile
= BytesIO('')
680 for Arch
in ArchList
:
681 PlatformDataBase
= BuildDb
.BuildObject
[GenFdsGlobalVariable
.ActivePlatform
, Arch
, GenFdsGlobalVariable
.TargetName
, GenFdsGlobalVariable
.ToolChainTag
]
682 PkgList
= GenFdsGlobalVariable
.WorkSpace
.GetPackageList(GenFdsGlobalVariable
.ActivePlatform
, Arch
, GenFdsGlobalVariable
.TargetName
, GenFdsGlobalVariable
.ToolChainTag
)
684 PkgGuidDict
.update(P
.Guids
)
685 for Name
, Guid
in PlatformDataBase
.Pcds
:
686 Pcd
= PlatformDataBase
.Pcds
[Name
, Guid
]
687 if Pcd
.Type
in [TAB_PCDS_DYNAMIC_HII
, TAB_PCDS_DYNAMIC_EX_HII
]:
688 for SkuId
in Pcd
.SkuInfoList
:
689 Sku
= Pcd
.SkuInfoList
[SkuId
]
690 if Sku
.VariableGuid
and Sku
.VariableGuid
in PkgGuidDict
.keys():
691 GuidDict
[Sku
.VariableGuid
] = PkgGuidDict
[Sku
.VariableGuid
]
692 for ModuleFile
in PlatformDataBase
.Modules
:
693 Module
= BuildDb
.BuildObject
[ModuleFile
, Arch
, GenFdsGlobalVariable
.TargetName
, GenFdsGlobalVariable
.ToolChainTag
]
694 if Module
in ModuleList
:
697 ModuleList
.append(Module
)
698 if GlobalData
.gGuidPattern
.match(ModuleFile
.BaseName
):
699 GuidXRefFile
.write("%s %s\n" % (ModuleFile
.BaseName
, Module
.BaseName
))
701 GuidXRefFile
.write("%s %s\n" % (Module
.Guid
, Module
.BaseName
))
702 GuidDict
.update(Module
.Protocols
)
703 GuidDict
.update(Module
.Guids
)
704 GuidDict
.update(Module
.Ppis
)
705 for FvName
in FdfParserObj
.Profile
.FvDict
:
706 for FfsObj
in FdfParserObj
.Profile
.FvDict
[FvName
].FfsList
:
707 if not isinstance(FfsObj
, FileStatement
):
708 InfPath
= PathClass(NormPath(mws
.join(GenFdsGlobalVariable
.WorkSpaceDir
, FfsObj
.InfFileName
)))
709 FdfModule
= BuildDb
.BuildObject
[InfPath
, Arch
, GenFdsGlobalVariable
.TargetName
, GenFdsGlobalVariable
.ToolChainTag
]
710 if FdfModule
in ModuleList
:
713 ModuleList
.append(FdfModule
)
714 GuidXRefFile
.write("%s %s\n" % (FdfModule
.Guid
, FdfModule
.BaseName
))
715 GuidDict
.update(FdfModule
.Protocols
)
716 GuidDict
.update(FdfModule
.Guids
)
717 GuidDict
.update(FdfModule
.Ppis
)
719 FileStatementGuid
= FfsObj
.NameGuid
720 if FileStatementGuid
in FileGuidList
:
723 FileGuidList
.append(FileStatementGuid
)
725 FfsPath
= os
.path
.join(GenFdsGlobalVariable
.FvDir
, 'Ffs')
726 FfsPath
= glob(os
.path
.join(FfsPath
, FileStatementGuid
) + TAB_STAR
)
729 if not os
.path
.exists(FfsPath
[0]):
732 ReFileEnds
= compile('\S+(.ui)$|\S+(fv.sec.txt)$|\S+(.pe32.txt)$|\S+(.te.txt)$|\S+(.pic.txt)$|\S+(.raw.txt)$|\S+(.ffs.txt)$')
733 FileList
= os
.listdir(FfsPath
[0])
734 for File
in FileList
:
735 Match
= ReFileEnds
.search(File
)
737 for Index
in range(1, 8):
738 if Match
.group(Index
) and Match
.group(Index
) in MatchDict
:
739 MatchDict
[Match
.group(Index
)].append(File
)
740 elif Match
.group(Index
):
741 MatchDict
[Match
.group(Index
)] = [File
]
744 if '.ui' in MatchDict
:
745 for File
in MatchDict
['.ui']:
746 with
open(os
.path
.join(FfsPath
[0], File
), 'rb') as F
:
750 TmpStr
= unpack('%dh' % ((length
- 4) / 2), F
.read())
751 Name
= ''.join(chr(c
) for c
in TmpStr
[:-1])
754 if 'fv.sec.txt' in MatchDict
:
755 FileList
= MatchDict
['fv.sec.txt']
756 elif '.pe32.txt' in MatchDict
:
757 FileList
= MatchDict
['.pe32.txt']
758 elif '.te.txt' in MatchDict
:
759 FileList
= MatchDict
['.te.txt']
760 elif '.pic.txt' in MatchDict
:
761 FileList
= MatchDict
['.pic.txt']
762 elif '.raw.txt' in MatchDict
:
763 FileList
= MatchDict
['.raw.txt']
764 elif '.ffs.txt' in MatchDict
:
765 FileList
= MatchDict
['.ffs.txt']
768 for File
in FileList
:
769 with
open(os
.path
.join(FfsPath
[0], File
), 'r') as F
:
770 Name
.append((F
.read().split()[-1]))
774 Name
= ' '.join(Name
) if isinstance(Name
, type([])) else Name
775 GuidXRefFile
.write("%s %s\n" %(FileStatementGuid
, Name
))
777 # Append GUIDs, Protocols, and PPIs to the Xref file
778 GuidXRefFile
.write("\n")
779 for key
, item
in GuidDict
.items():
780 GuidXRefFile
.write("%s %s\n" % (GuidStructureStringToGuidString(item
).upper(), key
))
782 if GuidXRefFile
.getvalue():
783 SaveFileOnChange(GuidXRefFileName
, GuidXRefFile
.getvalue(), False)
784 GenFdsGlobalVariable
.InfLogger("\nGUID cross reference file can be found at %s" % GuidXRefFileName
)
785 elif os
.path
.exists(GuidXRefFileName
):
786 os
.remove(GuidXRefFileName
)
790 if __name__
== '__main__':
792 ## 0-127 is a safe return range, and 1 is a standard default error