4 # Copyright (c) 2007 - 2018, Intel Corporation. All rights reserved.<BR>
6 # This program and the accompanying materials
7 # are licensed and made available under the terms and conditions of the BSD License
8 # which accompanies this distribution. The full text of the license may be found at
9 # http://opensource.org/licenses/bsd-license.php
11 # THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
12 # WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
18 from __future__
import print_function
19 from __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
.VtfDict
= {}
85 GenFdsGlobalVariable
.ActivePlatform
= None
86 GenFdsGlobalVariable
.FvAddressFileName
= ''
87 GenFdsGlobalVariable
.VerboseMode
= False
88 GenFdsGlobalVariable
.DebugLevel
= -1
89 GenFdsGlobalVariable
.SharpCounter
= 0
90 GenFdsGlobalVariable
.SharpNumberPerLine
= 40
91 GenFdsGlobalVariable
.FdfFile
= ''
92 GenFdsGlobalVariable
.FdfFileTimeStamp
= 0
93 GenFdsGlobalVariable
.FixedLoadAddress
= False
94 GenFdsGlobalVariable
.PlatformName
= ''
96 GenFdsGlobalVariable
.BuildRuleFamily
= DataType
.TAB_COMPILER_MSFT
97 GenFdsGlobalVariable
.ToolChainFamily
= DataType
.TAB_COMPILER_MSFT
98 GenFdsGlobalVariable
.__BuildRuleDatabase
= None
99 GenFdsGlobalVariable
.GuidToolDefinition
= {}
100 GenFdsGlobalVariable
.FfsCmdDict
= {}
101 GenFdsGlobalVariable
.SecCmdList
= []
102 GenFdsGlobalVariable
.CopyList
= []
103 GenFdsGlobalVariable
.ModuleFile
= ''
104 GenFdsGlobalVariable
.EnableGenfdsMultiThread
= False
106 GenFdsGlobalVariable
.LargeFileInFvFlags
= []
107 GenFdsGlobalVariable
.EFI_FIRMWARE_FILE_SYSTEM3_GUID
= '5473C07A-3DCB-4dca-BD6F-1E9689E7349A'
108 GenFdsGlobalVariable
.LARGE_FILE_SIZE
= 0x1000000
110 GenFdsGlobalVariable
.SectionHeader
= Struct("3B 1B")
112 # FvName, FdName, CapName in FDF, Image file name
113 GenFdsGlobalVariable
.ImageBinDict
= {}
115 def GenFdsApi(FdsCommandDict
, WorkSpaceDataBase
=None):
120 resetFdsGlobalVariable()
123 if FdsCommandDict
.get("verbose"):
124 EdkLogger
.SetLevel(EdkLogger
.VERBOSE
)
125 GenFdsGlobalVariable
.VerboseMode
= True
127 if FdsCommandDict
.get("FixedAddress"):
128 GenFdsGlobalVariable
.FixedLoadAddress
= True
130 if FdsCommandDict
.get("quiet"):
131 EdkLogger
.SetLevel(EdkLogger
.QUIET
)
132 if FdsCommandDict
.get("debug"):
133 EdkLogger
.SetLevel(FdsCommandDict
.get("debug") + 1)
134 GenFdsGlobalVariable
.DebugLevel
= FdsCommandDict
.get("debug")
136 EdkLogger
.SetLevel(EdkLogger
.INFO
)
138 if not FdsCommandDict
.get("Workspace",os
.environ
.get('WORKSPACE')):
139 EdkLogger
.error("GenFds", OPTION_MISSING
, "WORKSPACE not defined",
140 ExtraData
="Please use '-w' switch to pass it or set the WORKSPACE environment variable.")
141 elif not os
.path
.exists(FdsCommandDict
.get("Workspace",os
.environ
.get('WORKSPACE'))):
142 EdkLogger
.error("GenFds", PARAMETER_INVALID
, "WORKSPACE is invalid",
143 ExtraData
="Please use '-w' switch to pass it or set the WORKSPACE environment variable.")
145 Workspace
= os
.path
.normcase(FdsCommandDict
.get("Workspace",os
.environ
.get('WORKSPACE')))
146 GenFdsGlobalVariable
.WorkSpaceDir
= Workspace
147 if 'EDK_SOURCE' in os
.environ
:
148 GenFdsGlobalVariable
.EdkSourceDir
= os
.path
.normcase(os
.environ
['EDK_SOURCE'])
149 if FdsCommandDict
.get("debug"):
150 GenFdsGlobalVariable
.VerboseLogger("Using Workspace:" + Workspace
)
151 if FdsCommandDict
.get("GenfdsMultiThread"):
152 GenFdsGlobalVariable
.EnableGenfdsMultiThread
= True
153 os
.chdir(GenFdsGlobalVariable
.WorkSpaceDir
)
155 # set multiple workspace
156 PackagesPath
= os
.getenv("PACKAGES_PATH")
157 mws
.setWs(GenFdsGlobalVariable
.WorkSpaceDir
, PackagesPath
)
159 if FdsCommandDict
.get("fdf_file"):
160 FdfFilename
= FdsCommandDict
.get("fdf_file")[0].Path
161 FdfFilename
= GenFdsGlobalVariable
.ReplaceWorkspaceMacro(FdfFilename
)
163 if FdfFilename
[0:2] == '..':
164 FdfFilename
= os
.path
.realpath(FdfFilename
)
165 if not os
.path
.isabs(FdfFilename
):
166 FdfFilename
= mws
.join(GenFdsGlobalVariable
.WorkSpaceDir
, FdfFilename
)
167 if not os
.path
.exists(FdfFilename
):
168 EdkLogger
.error("GenFds", FILE_NOT_FOUND
, ExtraData
=FdfFilename
)
170 GenFdsGlobalVariable
.FdfFile
= FdfFilename
171 GenFdsGlobalVariable
.FdfFileTimeStamp
= os
.path
.getmtime(FdfFilename
)
173 EdkLogger
.error("GenFds", OPTION_MISSING
, "Missing FDF filename")
175 if FdsCommandDict
.get("build_target"):
176 GenFdsGlobalVariable
.TargetName
= FdsCommandDict
.get("build_target")
178 if FdsCommandDict
.get("toolchain_tag"):
179 GenFdsGlobalVariable
.ToolChainTag
= FdsCommandDict
.get("toolchain_tag")
181 if FdsCommandDict
.get("active_platform"):
182 ActivePlatform
= FdsCommandDict
.get("active_platform")
183 ActivePlatform
= GenFdsGlobalVariable
.ReplaceWorkspaceMacro(ActivePlatform
)
185 if ActivePlatform
[0:2] == '..':
186 ActivePlatform
= os
.path
.realpath(ActivePlatform
)
188 if not os
.path
.isabs (ActivePlatform
):
189 ActivePlatform
= mws
.join(GenFdsGlobalVariable
.WorkSpaceDir
, ActivePlatform
)
191 if not os
.path
.exists(ActivePlatform
):
192 EdkLogger
.error("GenFds", FILE_NOT_FOUND
, "ActivePlatform doesn't exist!")
194 EdkLogger
.error("GenFds", OPTION_MISSING
, "Missing active platform")
196 GlobalData
.BuildOptionPcd
= FdsCommandDict
.get("OptionPcd") if FdsCommandDict
.get("OptionPcd") else {}
197 GenFdsGlobalVariable
.ActivePlatform
= PathClass(NormPath(ActivePlatform
))
199 if FdsCommandDict
.get("conf_directory"):
200 # Get alternate Conf location, if it is absolute, then just use the absolute directory name
201 ConfDirectoryPath
= os
.path
.normpath(FdsCommandDict
.get("conf_directory"))
202 if ConfDirectoryPath
.startswith('"'):
203 ConfDirectoryPath
= ConfDirectoryPath
[1:]
204 if ConfDirectoryPath
.endswith('"'):
205 ConfDirectoryPath
= ConfDirectoryPath
[:-1]
206 if not os
.path
.isabs(ConfDirectoryPath
):
207 # Since alternate directory name is not absolute, the alternate directory is located within the WORKSPACE
208 # This also handles someone specifying the Conf directory in the workspace. Using --conf=Conf
209 ConfDirectoryPath
= os
.path
.join(GenFdsGlobalVariable
.WorkSpaceDir
, ConfDirectoryPath
)
211 if "CONF_PATH" in os
.environ
:
212 ConfDirectoryPath
= os
.path
.normcase(os
.environ
["CONF_PATH"])
214 # Get standard WORKSPACE/Conf, use the absolute path to the WORKSPACE/Conf
215 ConfDirectoryPath
= mws
.join(GenFdsGlobalVariable
.WorkSpaceDir
, 'Conf')
216 GenFdsGlobalVariable
.ConfDir
= ConfDirectoryPath
217 if not GlobalData
.gConfDirectory
:
218 GlobalData
.gConfDirectory
= GenFdsGlobalVariable
.ConfDir
219 BuildConfigurationFile
= os
.path
.normpath(os
.path
.join(ConfDirectoryPath
, "target.txt"))
220 if os
.path
.isfile(BuildConfigurationFile
) == True:
221 TargetTxt
= TargetTxtClassObject()
222 TargetTxt
.LoadTargetTxtFile(BuildConfigurationFile
)
223 # if no build target given in command line, get it from target.txt
224 if not GenFdsGlobalVariable
.TargetName
:
225 BuildTargetList
= TargetTxt
.TargetTxtDictionary
[TAB_TAT_DEFINES_TARGET
]
226 if len(BuildTargetList
) != 1:
227 EdkLogger
.error("GenFds", OPTION_VALUE_INVALID
, ExtraData
="Only allows one instance for Target.")
228 GenFdsGlobalVariable
.TargetName
= BuildTargetList
[0]
230 # if no tool chain given in command line, get it from target.txt
231 if not GenFdsGlobalVariable
.ToolChainTag
:
232 ToolChainList
= TargetTxt
.TargetTxtDictionary
[TAB_TAT_DEFINES_TOOL_CHAIN_TAG
]
233 if ToolChainList
is None or len(ToolChainList
) == 0:
234 EdkLogger
.error("GenFds", RESOURCE_NOT_AVAILABLE
, ExtraData
="No toolchain given. Don't know how to build.")
235 if len(ToolChainList
) != 1:
236 EdkLogger
.error("GenFds", OPTION_VALUE_INVALID
, ExtraData
="Only allows one instance for ToolChain.")
237 GenFdsGlobalVariable
.ToolChainTag
= ToolChainList
[0]
239 EdkLogger
.error("GenFds", FILE_NOT_FOUND
, ExtraData
=BuildConfigurationFile
)
241 #Set global flag for build mode
242 GlobalData
.gIgnoreSource
= FdsCommandDict
.get("IgnoreSources")
244 if FdsCommandDict
.get("macro"):
245 for Pair
in FdsCommandDict
.get("macro"):
246 if Pair
.startswith('"'):
248 if Pair
.endswith('"'):
250 List
= Pair
.split('=')
252 if not List
[1].strip():
253 EdkLogger
.error("GenFds", OPTION_VALUE_INVALID
, ExtraData
="No Value given for Macro %s" %List
[0])
254 if List
[0].strip() == "EFI_SOURCE":
255 GlobalData
.gEfiSource
= List
[1].strip()
256 GlobalData
.gGlobalDefines
["EFI_SOURCE"] = GlobalData
.gEfiSource
258 elif List
[0].strip() == "EDK_SOURCE":
259 GlobalData
.gEdkSource
= List
[1].strip()
260 GlobalData
.gGlobalDefines
["EDK_SOURCE"] = GlobalData
.gEdkSource
262 elif List
[0].strip() in ["WORKSPACE", "TARGET", "TOOLCHAIN"]:
263 GlobalData
.gGlobalDefines
[List
[0].strip()] = List
[1].strip()
265 GlobalData
.gCommandLineDefines
[List
[0].strip()] = List
[1].strip()
267 GlobalData
.gCommandLineDefines
[List
[0].strip()] = "TRUE"
268 os
.environ
["WORKSPACE"] = Workspace
270 # Use the -t and -b option as gGlobalDefines's TOOLCHAIN and TARGET if they are not defined
271 if "TARGET" not in GlobalData
.gGlobalDefines
:
272 GlobalData
.gGlobalDefines
["TARGET"] = GenFdsGlobalVariable
.TargetName
273 if "TOOLCHAIN" not in GlobalData
.gGlobalDefines
:
274 GlobalData
.gGlobalDefines
["TOOLCHAIN"] = GenFdsGlobalVariable
.ToolChainTag
275 if "TOOL_CHAIN_TAG" not in GlobalData
.gGlobalDefines
:
276 GlobalData
.gGlobalDefines
['TOOL_CHAIN_TAG'] = GenFdsGlobalVariable
.ToolChainTag
278 """call Workspace build create database"""
279 GlobalData
.gDatabasePath
= os
.path
.normpath(os
.path
.join(ConfDirectoryPath
, GlobalData
.gDatabasePath
))
281 if WorkSpaceDataBase
:
282 BuildWorkSpace
= WorkSpaceDataBase
284 BuildWorkSpace
= WorkspaceDatabase()
286 # Get files real name in workspace dir
288 GlobalData
.gAllFiles
= DirCache(Workspace
)
289 GlobalData
.gWorkspace
= Workspace
291 if FdsCommandDict
.get("build_architecture_list"):
292 ArchList
= FdsCommandDict
.get("build_architecture_list").split(',')
294 ArchList
= BuildWorkSpace
.BuildObject
[GenFdsGlobalVariable
.ActivePlatform
, TAB_COMMON
, FdsCommandDict
.get("build_target"), FdsCommandDict
.get("toolchain_tag")].SupArchList
296 TargetArchList
= set(BuildWorkSpace
.BuildObject
[GenFdsGlobalVariable
.ActivePlatform
, TAB_COMMON
, FdsCommandDict
.get("build_target"), FdsCommandDict
.get("toolchain_tag")].SupArchList
) & set(ArchList
)
297 if len(TargetArchList
) == 0:
298 EdkLogger
.error("GenFds", GENFDS_ERROR
, "Target ARCH %s not in platform supported ARCH %s" % (str(ArchList
), str(BuildWorkSpace
.BuildObject
[GenFdsGlobalVariable
.ActivePlatform
, TAB_COMMON
].SupArchList
)))
300 for Arch
in ArchList
:
301 GenFdsGlobalVariable
.OutputDirFromDscDict
[Arch
] = NormPath(BuildWorkSpace
.BuildObject
[GenFdsGlobalVariable
.ActivePlatform
, Arch
, FdsCommandDict
.get("build_target"), FdsCommandDict
.get("toolchain_tag")].OutputDirectory
)
303 # assign platform name based on last entry in ArchList
304 GenFdsGlobalVariable
.PlatformName
= BuildWorkSpace
.BuildObject
[GenFdsGlobalVariable
.ActivePlatform
, ArchList
[-1], FdsCommandDict
.get("build_target"), FdsCommandDict
.get("toolchain_tag")].PlatformName
306 if FdsCommandDict
.get("platform_build_directory"):
307 OutputDirFromCommandLine
= GenFdsGlobalVariable
.ReplaceWorkspaceMacro(FdsCommandDict
.get("platform_build_directory"))
308 if not os
.path
.isabs (OutputDirFromCommandLine
):
309 OutputDirFromCommandLine
= os
.path
.join(GenFdsGlobalVariable
.WorkSpaceDir
, OutputDirFromCommandLine
)
310 for Arch
in ArchList
:
311 GenFdsGlobalVariable
.OutputDirDict
[Arch
] = OutputDirFromCommandLine
313 for Arch
in ArchList
:
314 GenFdsGlobalVariable
.OutputDirDict
[Arch
] = os
.path
.join(GenFdsGlobalVariable
.OutputDirFromDscDict
[Arch
], GenFdsGlobalVariable
.TargetName
+ '_' + GenFdsGlobalVariable
.ToolChainTag
)
316 for Key
in GenFdsGlobalVariable
.OutputDirDict
:
317 OutputDir
= GenFdsGlobalVariable
.OutputDirDict
[Key
]
318 if OutputDir
[0:2] == '..':
319 OutputDir
= os
.path
.realpath(OutputDir
)
321 if OutputDir
[1] != ':':
322 OutputDir
= os
.path
.join (GenFdsGlobalVariable
.WorkSpaceDir
, OutputDir
)
324 if not os
.path
.exists(OutputDir
):
325 EdkLogger
.error("GenFds", FILE_NOT_FOUND
, ExtraData
=OutputDir
)
326 GenFdsGlobalVariable
.OutputDirDict
[Key
] = OutputDir
328 """ Parse Fdf file, has to place after build Workspace as FDF may contain macros from DSC file """
329 if WorkSpaceDataBase
:
330 FdfParserObj
= GlobalData
.gFdfParser
332 FdfParserObj
= FdfParser(FdfFilename
)
333 FdfParserObj
.ParseFile()
335 if FdfParserObj
.CycleReferenceCheck():
336 EdkLogger
.error("GenFds", FORMAT_NOT_SUPPORTED
, "Cycle Reference Detected in FDF file")
338 if FdsCommandDict
.get("fd"):
339 if FdsCommandDict
.get("fd")[0].upper() in FdfParserObj
.Profile
.FdDict
:
340 GenFds
.OnlyGenerateThisFd
= FdsCommandDict
.get("fd")[0]
342 EdkLogger
.error("GenFds", OPTION_VALUE_INVALID
,
343 "No such an FD in FDF file: %s" % FdsCommandDict
.get("fd")[0])
345 if FdsCommandDict
.get("fv"):
346 if FdsCommandDict
.get("fv")[0].upper() in FdfParserObj
.Profile
.FvDict
:
347 GenFds
.OnlyGenerateThisFv
= FdsCommandDict
.get("fv")[0]
349 EdkLogger
.error("GenFds", OPTION_VALUE_INVALID
,
350 "No such an FV in FDF file: %s" % FdsCommandDict
.get("fv")[0])
352 if FdsCommandDict
.get("cap"):
353 if FdsCommandDict
.get("cap")[0].upper() in FdfParserObj
.Profile
.CapsuleDict
:
354 GenFds
.OnlyGenerateThisCap
= FdsCommandDict
.get("cap")[0]
356 EdkLogger
.error("GenFds", OPTION_VALUE_INVALID
,
357 "No such a Capsule in FDF file: %s" % FdsCommandDict
.get("cap")[0])
359 GenFdsGlobalVariable
.WorkSpace
= BuildWorkSpace
361 GenFdsGlobalVariable
.ArchList
= ArchList
363 # Dsc Build Data will handle Pcd Settings from CommandLine.
365 """Modify images from build output if the feature of loading driver at fixed address is on."""
366 if GenFdsGlobalVariable
.FixedLoadAddress
:
367 GenFds
.PreprocessImage(BuildWorkSpace
, GenFdsGlobalVariable
.ActivePlatform
)
369 # Record the FV Region info that may specific in the FD
370 if FdfParserObj
.Profile
.FvDict
and FdfParserObj
.Profile
.FdDict
:
371 for FvObj
in FdfParserObj
.Profile
.FvDict
.values():
372 for FdObj
in FdfParserObj
.Profile
.FdDict
.values():
373 for RegionObj
in FdObj
.RegionList
:
374 if RegionObj
.RegionType
!= BINARY_FILE_TYPE_FV
:
376 for RegionData
in RegionObj
.RegionDataList
:
377 if FvObj
.UiFvName
.upper() == RegionData
.upper():
378 if FvObj
.FvRegionInFD
:
379 if FvObj
.FvRegionInFD
!= RegionObj
.Size
:
380 EdkLogger
.error("GenFds", FORMAT_INVALID
, "The FV %s's region is specified in multiple FD with different value." %FvObj
.UiFvName
)
382 FvObj
.FvRegionInFD
= RegionObj
.Size
383 RegionObj
.BlockInfoOfRegion(FdObj
.BlockSizeList
, FvObj
)
386 GenFds
.GenFd('', FdfParserObj
, BuildWorkSpace
, ArchList
)
388 """Generate GUID cross reference file"""
389 GenFds
.GenerateGuidXRefFile(BuildWorkSpace
, ArchList
, FdfParserObj
)
391 """Display FV space info."""
392 GenFds
.DisplayFvSpaceInfo(FdfParserObj
)
395 EdkLogger
.error(X
.ToolName
, FORMAT_INVALID
, File
=X
.FileName
, Line
=X
.LineNumber
, ExtraData
=X
.Message
, RaiseError
=False)
396 ReturnCode
= FORMAT_INVALID
397 except FatalError
as X
:
398 if FdsCommandDict
.get("debug") is not None:
400 EdkLogger
.quiet(traceback
.format_exc())
401 ReturnCode
= X
.args
[0]
407 "Tools code failure",
408 ExtraData
="Please send email to edk2-devel@lists.01.org for help, attaching following call stack trace!\n",
411 EdkLogger
.quiet(traceback
.format_exc())
412 ReturnCode
= CODE_ERROR
417 def OptionsToCommandDict(Options
):
419 FdsCommandDict
["verbose"] = Options
.verbose
420 FdsCommandDict
["FixedAddress"] = Options
.FixedAddress
421 FdsCommandDict
["quiet"] = Options
.quiet
422 FdsCommandDict
["debug"] = Options
.debug
423 FdsCommandDict
["Workspace"] = Options
.Workspace
424 FdsCommandDict
["GenfdsMultiThread"] = Options
.GenfdsMultiThread
425 FdsCommandDict
["fdf_file"] = [PathClass(Options
.filename
)] if Options
.filename
else []
426 FdsCommandDict
["build_target"] = Options
.BuildTarget
427 FdsCommandDict
["toolchain_tag"] = Options
.ToolChain
428 FdsCommandDict
["active_platform"] = Options
.activePlatform
429 FdsCommandDict
["OptionPcd"] = Options
.OptionPcd
430 FdsCommandDict
["conf_directory"] = Options
.ConfDirectory
431 FdsCommandDict
["IgnoreSources"] = Options
.IgnoreSources
432 FdsCommandDict
["macro"] = Options
.Macros
433 FdsCommandDict
["build_architecture_list"] = Options
.archList
434 FdsCommandDict
["platform_build_directory"] = Options
.outputDir
435 FdsCommandDict
["fd"] = [Options
.uiFdName
] if Options
.uiFdName
else []
436 FdsCommandDict
["fv"] = [Options
.uiFvName
] if Options
.uiFvName
else []
437 FdsCommandDict
["cap"] = [Options
.uiCapName
] if Options
.uiCapName
else []
438 return FdsCommandDict
442 def SingleCheckCallback(option
, opt_str
, value
, parser
):
443 if option
not in gParamCheck
:
444 setattr(parser
.values
, option
.dest
, value
)
445 gParamCheck
.append(option
)
447 parser
.error("Option %s only allows one instance in command line!" % option
)
449 ## Parse command line options
451 # Using standard Python module optparse to parse command line option of this tool.
453 # @retval Opt A optparse.Values object containing the parsed options
455 def myOptionParser():
456 usage
= "%prog [options] -f input_file -a arch_list -b build_target -p active_platform -t tool_chain_tag -D \"MacroName [= MacroValue]\""
457 Parser
= OptionParser(usage
=usage
, description
=__copyright__
, version
="%prog " + str(versionNumber
))
458 Parser
.add_option("-f", "--file", dest
="filename", type="string", help="Name of FDF file to convert", action
="callback", callback
=SingleCheckCallback
)
459 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")
460 Parser
.add_option("-q", "--quiet", action
="store_true", type=None, help="Disable all messages except FATAL ERRORS.")
461 Parser
.add_option("-v", "--verbose", action
="store_true", type=None, help="Turn on verbose output with informational messages printed.")
462 Parser
.add_option("-d", "--debug", action
="store", type="int", help="Enable debug messages at specified level.")
463 Parser
.add_option("-p", "--platform", type="string", dest
="activePlatform", help="Set the ACTIVE_PLATFORM, overrides target.txt ACTIVE_PLATFORM setting.",
464 action
="callback", callback
=SingleCheckCallback
)
465 Parser
.add_option("-w", "--workspace", type="string", dest
="Workspace", default
=os
.environ
.get('WORKSPACE'), help="Set the WORKSPACE",
466 action
="callback", callback
=SingleCheckCallback
)
467 Parser
.add_option("-o", "--outputDir", type="string", dest
="outputDir", help="Name of Build Output directory",
468 action
="callback", callback
=SingleCheckCallback
)
469 Parser
.add_option("-r", "--rom_image", dest
="uiFdName", help="Build the image using the [FD] section named by FdUiName.")
470 Parser
.add_option("-i", "--FvImage", dest
="uiFvName", help="Build the FV image using the [FV] section named by UiFvName")
471 Parser
.add_option("-C", "--CapsuleImage", dest
="uiCapName", help="Build the Capsule image using the [Capsule] section named by UiCapName")
472 Parser
.add_option("-b", "--buildtarget", type="string", dest
="BuildTarget", help="Set the build TARGET, overrides target.txt TARGET setting.",
473 action
="callback", callback
=SingleCheckCallback
)
474 Parser
.add_option("-t", "--tagname", type="string", dest
="ToolChain", help="Using the tools: TOOL_CHAIN_TAG name to build the platform.",
475 action
="callback", callback
=SingleCheckCallback
)
476 Parser
.add_option("-D", "--define", action
="append", type="string", dest
="Macros", help="Macro: \"Name [= Value]\".")
477 Parser
.add_option("-s", "--specifyaddress", dest
="FixedAddress", action
="store_true", type=None, help="Specify driver load address.")
478 Parser
.add_option("--conf", action
="store", type="string", dest
="ConfDirectory", help="Specify the customized Conf directory.")
479 Parser
.add_option("--ignore-sources", action
="store_true", dest
="IgnoreSources", default
=False, help="Focus to a binary build and ignore all source files")
480 Parser
.add_option("--pcd", action
="append", dest
="OptionPcd", help="Set PCD value by command line. Format: \"PcdName=Value\" ")
481 Parser
.add_option("--genfds-multi-thread", action
="store_true", dest
="GenfdsMultiThread", default
=False, help="Enable GenFds multi thread to generate ffs file.")
483 Options
, _
= Parser
.parse_args()
486 ## The class implementing the EDK2 flash image generation process
488 # This process includes:
489 # 1. Collect workspace information, includes platform and module information
490 # 2. Call methods of Fd class to generate FD
491 # 3. Call methods of Fv class to generate FV that not belong to FD
493 class GenFds(object):
495 OnlyGenerateThisFd
= None
496 OnlyGenerateThisFv
= None
497 OnlyGenerateThisCap
= None
501 # @param OutputDir Output directory
502 # @param FdfParserObject FDF contents parser
503 # @param Workspace The directory of workspace
504 # @param ArchList The Arch list of platform
507 def GenFd (OutputDir
, FdfParserObject
, WorkSpace
, ArchList
):
508 GenFdsGlobalVariable
.SetDir ('', FdfParserObject
, WorkSpace
, ArchList
)
510 GenFdsGlobalVariable
.VerboseLogger(" Generate all Fd images and their required FV and Capsule images!")
511 if GenFds
.OnlyGenerateThisCap
is not None and GenFds
.OnlyGenerateThisCap
.upper() in GenFdsGlobalVariable
.FdfParser
.Profile
.CapsuleDict
:
512 CapsuleObj
= GenFdsGlobalVariable
.FdfParser
.Profile
.CapsuleDict
[GenFds
.OnlyGenerateThisCap
.upper()]
513 if CapsuleObj
is not None:
514 CapsuleObj
.GenCapsule()
517 if GenFds
.OnlyGenerateThisFd
is not None and GenFds
.OnlyGenerateThisFd
.upper() in GenFdsGlobalVariable
.FdfParser
.Profile
.FdDict
:
518 FdObj
= GenFdsGlobalVariable
.FdfParser
.Profile
.FdDict
[GenFds
.OnlyGenerateThisFd
.upper()]
519 if FdObj
is not None:
522 elif GenFds
.OnlyGenerateThisFd
is None and GenFds
.OnlyGenerateThisFv
is None:
523 for FdObj
in GenFdsGlobalVariable
.FdfParser
.Profile
.FdDict
.values():
526 GenFdsGlobalVariable
.VerboseLogger("\n Generate other FV images! ")
527 if GenFds
.OnlyGenerateThisFv
is not None and GenFds
.OnlyGenerateThisFv
.upper() in GenFdsGlobalVariable
.FdfParser
.Profile
.FvDict
:
528 FvObj
= GenFdsGlobalVariable
.FdfParser
.Profile
.FvDict
[GenFds
.OnlyGenerateThisFv
.upper()]
529 if FvObj
is not None:
531 FvObj
.AddToBuffer(Buffer
)
534 elif GenFds
.OnlyGenerateThisFv
is None:
535 for FvObj
in GenFdsGlobalVariable
.FdfParser
.Profile
.FvDict
.values():
537 FvObj
.AddToBuffer(Buffer
)
540 if GenFds
.OnlyGenerateThisFv
is None and GenFds
.OnlyGenerateThisFd
is None and GenFds
.OnlyGenerateThisCap
is None:
541 if GenFdsGlobalVariable
.FdfParser
.Profile
.CapsuleDict
!= {}:
542 GenFdsGlobalVariable
.VerboseLogger("\n Generate other Capsule images!")
543 for CapsuleObj
in GenFdsGlobalVariable
.FdfParser
.Profile
.CapsuleDict
.values():
544 CapsuleObj
.GenCapsule()
546 if GenFdsGlobalVariable
.FdfParser
.Profile
.OptRomDict
!= {}:
547 GenFdsGlobalVariable
.VerboseLogger("\n Generate all Option ROM!")
548 for OptRomObj
in GenFdsGlobalVariable
.FdfParser
.Profile
.OptRomDict
.values():
549 OptRomObj
.AddToBuffer(None)
552 def GenFfsMakefile(OutputDir
, FdfParserObject
, WorkSpace
, ArchList
, GlobalData
):
553 GenFdsGlobalVariable
.SetEnv(FdfParserObject
, WorkSpace
, ArchList
, GlobalData
)
554 for FdObj
in GenFdsGlobalVariable
.FdfParser
.Profile
.FdDict
.values():
555 FdObj
.GenFd(Flag
=True)
557 for FvObj
in GenFdsGlobalVariable
.FdfParser
.Profile
.FvDict
.values():
558 FvObj
.AddToBuffer(Buffer
=None, Flag
=True)
560 if GenFdsGlobalVariable
.FdfParser
.Profile
.OptRomDict
!= {}:
561 for OptRomObj
in GenFdsGlobalVariable
.FdfParser
.Profile
.OptRomDict
.values():
562 OptRomObj
.AddToBuffer(Buffer
=None, Flag
=True)
564 return GenFdsGlobalVariable
.FfsCmdDict
568 # @param FvObj Whose block size to get
569 # @retval int Block size value
572 def GetFvBlockSize(FvObj
):
573 DefaultBlockSize
= 0x1
575 if GenFds
.OnlyGenerateThisFd
is not None and GenFds
.OnlyGenerateThisFd
.upper() in GenFdsGlobalVariable
.FdfParser
.Profile
.FdDict
:
576 FdObj
= GenFdsGlobalVariable
.FdfParser
.Profile
.FdDict
[GenFds
.OnlyGenerateThisFd
.upper()]
578 for ElementFd
in GenFdsGlobalVariable
.FdfParser
.Profile
.FdDict
.values():
579 for ElementRegion
in ElementFd
.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 if FvObj
.BlockSizeList
!= []:
588 return FvObj
.BlockSizeList
[0][0]
589 return DefaultBlockSize
591 for ElementRegion
in FdObj
.RegionList
:
592 if ElementRegion
.RegionType
== BINARY_FILE_TYPE_FV
:
593 for ElementRegionData
in ElementRegion
.RegionDataList
:
594 if ElementRegionData
is not None and ElementRegionData
.upper() == FvObj
.UiFvName
:
595 if FvObj
.BlockSizeList
!= []:
596 return FvObj
.BlockSizeList
[0][0]
598 return ElementRegion
.BlockSizeOfRegion(ElementFd
.BlockSizeList
)
599 return DefaultBlockSize
601 ## DisplayFvSpaceInfo()
603 # @param FvObj Whose block size to get
607 def DisplayFvSpaceInfo(FdfParserObject
):
611 for FvName
in FdfParserObject
.Profile
.FvDict
:
612 if len(FvName
) > MaxFvNameLength
:
613 MaxFvNameLength
= len(FvName
)
614 FvSpaceInfoFileName
= os
.path
.join(GenFdsGlobalVariable
.FvDir
, FvName
.upper() + '.Fv.map')
615 if os
.path
.exists(FvSpaceInfoFileName
):
616 FileLinesList
= getlines(FvSpaceInfoFileName
)
623 for Line
in FileLinesList
:
624 NameValue
= Line
.split('=')
625 if len(NameValue
) == 2:
626 if NameValue
[0].strip() == 'EFI_FV_TOTAL_SIZE':
628 Total
= NameValue
[1].strip()
629 if NameValue
[0].strip() == 'EFI_FV_TAKEN_SIZE':
631 Used
= NameValue
[1].strip()
632 if NameValue
[0].strip() == 'EFI_FV_SPACE_SIZE':
634 Free
= NameValue
[1].strip()
636 if TotalFound
and UsedFound
and FreeFound
:
637 FvSpaceInfoList
.append((FvName
, Total
, Used
, Free
))
639 GenFdsGlobalVariable
.InfLogger('\nFV Space Information')
640 for FvSpaceInfo
in FvSpaceInfoList
:
641 Name
= FvSpaceInfo
[0]
642 TotalSizeValue
= long(FvSpaceInfo
[1], 0)
643 UsedSizeValue
= long(FvSpaceInfo
[2], 0)
644 FreeSizeValue
= long(FvSpaceInfo
[3], 0)
645 if UsedSizeValue
== TotalSizeValue
:
648 Percentage
= str((UsedSizeValue
+ 0.0) / TotalSizeValue
)[0:4].lstrip('0.')
650 GenFdsGlobalVariable
.InfLogger(Name
+ ' ' + '[' + Percentage
+ '%Full] ' + str(TotalSizeValue
) + ' total, ' + str(UsedSizeValue
) + ' used, ' + str(FreeSizeValue
) + ' free')
654 # @param BuildDb Database from build meta data files
655 # @param DscFile modules from dsc file will be preprocessed
659 def PreprocessImage(BuildDb
, DscFile
):
660 PcdDict
= BuildDb
.BuildObject
[DscFile
, TAB_COMMON
, GenFdsGlobalVariable
.TargetName
, GenFdsGlobalVariable
.ToolChainTag
].Pcds
663 PcdObj
= PcdDict
[Key
]
664 if PcdObj
.TokenCName
== 'PcdBsBaseAddress':
665 PcdValue
= PcdObj
.DefaultValue
671 Int64PcdValue
= long(PcdValue
, 0)
672 if Int64PcdValue
== 0 or Int64PcdValue
< -1:
676 if Int64PcdValue
> 0:
677 TopAddress
= Int64PcdValue
679 ModuleDict
= BuildDb
.BuildObject
[DscFile
, TAB_COMMON
, GenFdsGlobalVariable
.TargetName
, GenFdsGlobalVariable
.ToolChainTag
].Modules
680 for Key
in ModuleDict
:
681 ModuleObj
= BuildDb
.BuildObject
[Key
, TAB_COMMON
, GenFdsGlobalVariable
.TargetName
, GenFdsGlobalVariable
.ToolChainTag
]
682 print(ModuleObj
.BaseName
+ ' ' + ModuleObj
.ModuleType
)
685 def GenerateGuidXRefFile(BuildDb
, ArchList
, FdfParserObj
):
686 GuidXRefFileName
= os
.path
.join(GenFdsGlobalVariable
.FvDir
, "Guid.xref")
687 GuidXRefFile
= BytesIO('')
692 for Arch
in ArchList
:
693 PlatformDataBase
= BuildDb
.BuildObject
[GenFdsGlobalVariable
.ActivePlatform
, Arch
, GenFdsGlobalVariable
.TargetName
, GenFdsGlobalVariable
.ToolChainTag
]
694 PkgList
= GenFdsGlobalVariable
.WorkSpace
.GetPackageList(GenFdsGlobalVariable
.ActivePlatform
, Arch
, GenFdsGlobalVariable
.TargetName
, GenFdsGlobalVariable
.ToolChainTag
)
696 PkgGuidDict
.update(P
.Guids
)
697 for Name
, Guid
in PlatformDataBase
.Pcds
:
698 Pcd
= PlatformDataBase
.Pcds
[Name
, Guid
]
699 if Pcd
.Type
in [TAB_PCDS_DYNAMIC_HII
, TAB_PCDS_DYNAMIC_EX_HII
]:
700 for SkuId
in Pcd
.SkuInfoList
:
701 Sku
= Pcd
.SkuInfoList
[SkuId
]
702 if Sku
.VariableGuid
and Sku
.VariableGuid
in PkgGuidDict
.keys():
703 GuidDict
[Sku
.VariableGuid
] = PkgGuidDict
[Sku
.VariableGuid
]
704 for ModuleFile
in PlatformDataBase
.Modules
:
705 Module
= BuildDb
.BuildObject
[ModuleFile
, Arch
, GenFdsGlobalVariable
.TargetName
, GenFdsGlobalVariable
.ToolChainTag
]
706 if Module
in ModuleList
:
709 ModuleList
.append(Module
)
710 if GlobalData
.gGuidPattern
.match(ModuleFile
.BaseName
):
711 GuidXRefFile
.write("%s %s\n" % (ModuleFile
.BaseName
, Module
.BaseName
))
713 GuidXRefFile
.write("%s %s\n" % (Module
.Guid
, Module
.BaseName
))
714 GuidDict
.update(Module
.Protocols
)
715 GuidDict
.update(Module
.Guids
)
716 GuidDict
.update(Module
.Ppis
)
717 for FvName
in FdfParserObj
.Profile
.FvDict
:
718 for FfsObj
in FdfParserObj
.Profile
.FvDict
[FvName
].FfsList
:
719 if not isinstance(FfsObj
, FileStatement
):
720 InfPath
= PathClass(NormPath(mws
.join(GenFdsGlobalVariable
.WorkSpaceDir
, FfsObj
.InfFileName
)))
721 FdfModule
= BuildDb
.BuildObject
[InfPath
, Arch
, GenFdsGlobalVariable
.TargetName
, GenFdsGlobalVariable
.ToolChainTag
]
722 if FdfModule
in ModuleList
:
725 ModuleList
.append(FdfModule
)
726 GuidXRefFile
.write("%s %s\n" % (FdfModule
.Guid
, FdfModule
.BaseName
))
727 GuidDict
.update(FdfModule
.Protocols
)
728 GuidDict
.update(FdfModule
.Guids
)
729 GuidDict
.update(FdfModule
.Ppis
)
731 FileStatementGuid
= FfsObj
.NameGuid
732 if FileStatementGuid
in FileGuidList
:
735 FileGuidList
.append(FileStatementGuid
)
737 FfsPath
= os
.path
.join(GenFdsGlobalVariable
.FvDir
, 'Ffs')
738 FfsPath
= glob(os
.path
.join(FfsPath
, FileStatementGuid
) + TAB_STAR
)
741 if not os
.path
.exists(FfsPath
[0]):
744 ReFileEnds
= compile('\S+(.ui)$|\S+(fv.sec.txt)$|\S+(.pe32.txt)$|\S+(.te.txt)$|\S+(.pic.txt)$|\S+(.raw.txt)$|\S+(.ffs.txt)$')
745 FileList
= os
.listdir(FfsPath
[0])
746 for File
in FileList
:
747 Match
= ReFileEnds
.search(File
)
749 for Index
in range(1, 8):
750 if Match
.group(Index
) and Match
.group(Index
) in MatchDict
:
751 MatchDict
[Match
.group(Index
)].append(File
)
752 elif Match
.group(Index
):
753 MatchDict
[Match
.group(Index
)] = [File
]
756 if '.ui' in MatchDict
:
757 for File
in MatchDict
['.ui']:
758 with
open(os
.path
.join(FfsPath
[0], File
), 'rb') as F
:
762 TmpStr
= unpack('%dh' % ((length
- 4) / 2), F
.read())
763 Name
= ''.join(chr(c
) for c
in TmpStr
[:-1])
766 if 'fv.sec.txt' in MatchDict
:
767 FileList
= MatchDict
['fv.sec.txt']
768 elif '.pe32.txt' in MatchDict
:
769 FileList
= MatchDict
['.pe32.txt']
770 elif '.te.txt' in MatchDict
:
771 FileList
= MatchDict
['.te.txt']
772 elif '.pic.txt' in MatchDict
:
773 FileList
= MatchDict
['.pic.txt']
774 elif '.raw.txt' in MatchDict
:
775 FileList
= MatchDict
['.raw.txt']
776 elif '.ffs.txt' in MatchDict
:
777 FileList
= MatchDict
['.ffs.txt']
780 for File
in FileList
:
781 with
open(os
.path
.join(FfsPath
[0], File
), 'r') as F
:
782 Name
.append((F
.read().split()[-1]))
786 Name
= ' '.join(Name
) if isinstance(Name
, type([])) else Name
787 GuidXRefFile
.write("%s %s\n" %(FileStatementGuid
, Name
))
789 # Append GUIDs, Protocols, and PPIs to the Xref file
790 GuidXRefFile
.write("\n")
791 for key
, item
in GuidDict
.items():
792 GuidXRefFile
.write("%s %s\n" % (GuidStructureStringToGuidString(item
).upper(), key
))
794 if GuidXRefFile
.getvalue():
795 SaveFileOnChange(GuidXRefFileName
, GuidXRefFile
.getvalue(), False)
796 GenFdsGlobalVariable
.InfLogger("\nGUID cross reference file can be found at %s" % GuidXRefFileName
)
797 elif os
.path
.exists(GuidXRefFileName
):
798 os
.remove(GuidXRefFileName
)
802 if __name__
== '__main__':
804 ## 0-127 is a safe return range, and 1 is a standard default error