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 optparse
import OptionParser
20 import Common
.LongFilePathOs
as os
23 import Common
.BuildToolError
as BuildToolError
24 from GenFdsGlobalVariable
import GenFdsGlobalVariable
25 from Workspace
.WorkspaceDatabase
import WorkspaceDatabase
26 from Workspace
.BuildClassObject
import PcdClassObject
27 from Workspace
.BuildClassObject
import ModuleBuildClassObject
28 import RuleComplexFile
29 from EfiSection
import EfiSection
31 import Common
.TargetTxtClassObject
as TargetTxtClassObject
32 import Common
.ToolDefClassObject
as ToolDefClassObject
33 from Common
.DataType
import *
34 import Common
.GlobalData
as GlobalData
35 from Common
import EdkLogger
36 from Common
.String
import *
37 from Common
.Misc
import DirCache
, PathClass
38 from Common
.Misc
import SaveFileOnChange
39 from Common
.Misc
import ClearDuplicatedInf
40 from Common
.Misc
import GuidStructureStringToGuidString
41 from Common
.Misc
import CheckPcdDatum
42 from Common
.Misc
import BuildOptionPcdValueFormat
43 from Common
.BuildVersion
import gBUILD_VERSION
44 from Common
.MultipleWorkspace
import MultipleWorkspace
as mws
45 import FfsFileStatement
47 from struct
import unpack
49 ## Version and Copyright
50 versionNumber
= "1.0" + ' ' + gBUILD_VERSION
51 __version__
= "%prog Version " + versionNumber
52 __copyright__
= "Copyright (c) 2007 - 2017, Intel Corporation All rights reserved."
54 ## Tool entrance method
56 # This method mainly dispatch specific methods per the command line options.
57 # If no error found, return zero value so the caller of this tool can know
58 # if it's executed successfully or not.
60 # @retval 0 Tool was successful
61 # @retval 1 Tool failed
65 Options
= myOptionParser()
72 EdkLogger
.Initialize()
74 if Options
.verbose
!= None:
75 EdkLogger
.SetLevel(EdkLogger
.VERBOSE
)
76 GenFdsGlobalVariable
.VerboseMode
= True
78 if Options
.FixedAddress
!= None:
79 GenFdsGlobalVariable
.FixedLoadAddress
= True
81 if Options
.quiet
!= None:
82 EdkLogger
.SetLevel(EdkLogger
.QUIET
)
83 if Options
.debug
!= None:
84 EdkLogger
.SetLevel(Options
.debug
+ 1)
85 GenFdsGlobalVariable
.DebugLevel
= Options
.debug
87 EdkLogger
.SetLevel(EdkLogger
.INFO
)
89 if (Options
.Workspace
== None):
90 EdkLogger
.error("GenFds", OPTION_MISSING
, "WORKSPACE not defined",
91 ExtraData
="Please use '-w' switch to pass it or set the WORKSPACE environment variable.")
92 elif not os
.path
.exists(Options
.Workspace
):
93 EdkLogger
.error("GenFds", PARAMETER_INVALID
, "WORKSPACE is invalid",
94 ExtraData
="Please use '-w' switch to pass it or set the WORKSPACE environment variable.")
96 Workspace
= os
.path
.normcase(Options
.Workspace
)
97 GenFdsGlobalVariable
.WorkSpaceDir
= Workspace
98 if 'EDK_SOURCE' in os
.environ
.keys():
99 GenFdsGlobalVariable
.EdkSourceDir
= os
.path
.normcase(os
.environ
['EDK_SOURCE'])
101 GenFdsGlobalVariable
.VerboseLogger("Using Workspace:" + Workspace
)
102 if Options
.GenfdsMultiThread
:
103 GenFdsGlobalVariable
.EnableGenfdsMultiThread
= True
104 os
.chdir(GenFdsGlobalVariable
.WorkSpaceDir
)
106 # set multiple workspace
107 PackagesPath
= os
.getenv("PACKAGES_PATH")
108 mws
.setWs(GenFdsGlobalVariable
.WorkSpaceDir
, PackagesPath
)
110 if (Options
.filename
):
111 FdfFilename
= Options
.filename
112 FdfFilename
= GenFdsGlobalVariable
.ReplaceWorkspaceMacro(FdfFilename
)
114 if FdfFilename
[0:2] == '..':
115 FdfFilename
= os
.path
.realpath(FdfFilename
)
116 if not os
.path
.isabs(FdfFilename
):
117 FdfFilename
= mws
.join(GenFdsGlobalVariable
.WorkSpaceDir
, FdfFilename
)
118 if not os
.path
.exists(FdfFilename
):
119 EdkLogger
.error("GenFds", FILE_NOT_FOUND
, ExtraData
=FdfFilename
)
121 GenFdsGlobalVariable
.FdfFile
= FdfFilename
122 GenFdsGlobalVariable
.FdfFileTimeStamp
= os
.path
.getmtime(FdfFilename
)
124 EdkLogger
.error("GenFds", OPTION_MISSING
, "Missing FDF filename")
126 if (Options
.BuildTarget
):
127 GenFdsGlobalVariable
.TargetName
= Options
.BuildTarget
129 if (Options
.ToolChain
):
130 GenFdsGlobalVariable
.ToolChainTag
= Options
.ToolChain
132 if (Options
.activePlatform
):
133 ActivePlatform
= Options
.activePlatform
134 ActivePlatform
= GenFdsGlobalVariable
.ReplaceWorkspaceMacro(ActivePlatform
)
136 if ActivePlatform
[0:2] == '..':
137 ActivePlatform
= os
.path
.realpath(ActivePlatform
)
139 if not os
.path
.isabs (ActivePlatform
):
140 ActivePlatform
= mws
.join(GenFdsGlobalVariable
.WorkSpaceDir
, ActivePlatform
)
142 if not os
.path
.exists(ActivePlatform
) :
143 EdkLogger
.error("GenFds", FILE_NOT_FOUND
, "ActivePlatform doesn't exist!")
145 EdkLogger
.error("GenFds", OPTION_MISSING
, "Missing active platform")
147 GenFdsGlobalVariable
.ActivePlatform
= PathClass(NormPath(ActivePlatform
))
149 if (Options
.ConfDirectory
):
150 # Get alternate Conf location, if it is absolute, then just use the absolute directory name
151 ConfDirectoryPath
= os
.path
.normpath(Options
.ConfDirectory
)
152 if ConfDirectoryPath
.startswith('"'):
153 ConfDirectoryPath
= ConfDirectoryPath
[1:]
154 if ConfDirectoryPath
.endswith('"'):
155 ConfDirectoryPath
= ConfDirectoryPath
[:-1]
156 if not os
.path
.isabs(ConfDirectoryPath
):
157 # Since alternate directory name is not absolute, the alternate directory is located within the WORKSPACE
158 # This also handles someone specifying the Conf directory in the workspace. Using --conf=Conf
159 ConfDirectoryPath
= os
.path
.join(GenFdsGlobalVariable
.WorkSpaceDir
, ConfDirectoryPath
)
161 if "CONF_PATH" in os
.environ
.keys():
162 ConfDirectoryPath
= os
.path
.normcase(os
.environ
["CONF_PATH"])
164 # Get standard WORKSPACE/Conf, use the absolute path to the WORKSPACE/Conf
165 ConfDirectoryPath
= mws
.join(GenFdsGlobalVariable
.WorkSpaceDir
, 'Conf')
166 GenFdsGlobalVariable
.ConfDir
= ConfDirectoryPath
167 if not GlobalData
.gConfDirectory
:
168 GlobalData
.gConfDirectory
= GenFdsGlobalVariable
.ConfDir
169 BuildConfigurationFile
= os
.path
.normpath(os
.path
.join(ConfDirectoryPath
, "target.txt"))
170 if os
.path
.isfile(BuildConfigurationFile
) == True:
171 TargetTxt
= TargetTxtClassObject
.TargetTxtClassObject()
172 TargetTxt
.LoadTargetTxtFile(BuildConfigurationFile
)
173 # if no build target given in command line, get it from target.txt
174 if not GenFdsGlobalVariable
.TargetName
:
175 BuildTargetList
= TargetTxt
.TargetTxtDictionary
[DataType
.TAB_TAT_DEFINES_TARGET
]
176 if len(BuildTargetList
) != 1:
177 EdkLogger
.error("GenFds", OPTION_VALUE_INVALID
, ExtraData
="Only allows one instance for Target.")
178 GenFdsGlobalVariable
.TargetName
= BuildTargetList
[0]
180 # if no tool chain given in command line, get it from target.txt
181 if not GenFdsGlobalVariable
.ToolChainTag
:
182 ToolChainList
= TargetTxt
.TargetTxtDictionary
[DataType
.TAB_TAT_DEFINES_TOOL_CHAIN_TAG
]
183 if ToolChainList
== None or len(ToolChainList
) == 0:
184 EdkLogger
.error("GenFds", RESOURCE_NOT_AVAILABLE
, ExtraData
="No toolchain given. Don't know how to build.")
185 if len(ToolChainList
) != 1:
186 EdkLogger
.error("GenFds", OPTION_VALUE_INVALID
, ExtraData
="Only allows one instance for ToolChain.")
187 GenFdsGlobalVariable
.ToolChainTag
= ToolChainList
[0]
189 EdkLogger
.error("GenFds", FILE_NOT_FOUND
, ExtraData
=BuildConfigurationFile
)
191 #Set global flag for build mode
192 GlobalData
.gIgnoreSource
= Options
.IgnoreSources
195 for Pair
in Options
.Macros
:
196 if Pair
.startswith('"'):
198 if Pair
.endswith('"'):
200 List
= Pair
.split('=')
202 if not List
[1].strip():
203 EdkLogger
.error("GenFds", OPTION_VALUE_INVALID
, ExtraData
="No Value given for Macro %s" %List
[0])
204 if List
[0].strip() == "EFI_SOURCE":
205 GlobalData
.gEfiSource
= List
[1].strip()
206 GlobalData
.gGlobalDefines
["EFI_SOURCE"] = GlobalData
.gEfiSource
208 elif List
[0].strip() == "EDK_SOURCE":
209 GlobalData
.gEdkSource
= List
[1].strip()
210 GlobalData
.gGlobalDefines
["EDK_SOURCE"] = GlobalData
.gEdkSource
212 elif List
[0].strip() in ["WORKSPACE", "TARGET", "TOOLCHAIN"]:
213 GlobalData
.gGlobalDefines
[List
[0].strip()] = List
[1].strip()
215 GlobalData
.gCommandLineDefines
[List
[0].strip()] = List
[1].strip()
217 GlobalData
.gCommandLineDefines
[List
[0].strip()] = "TRUE"
218 os
.environ
["WORKSPACE"] = Workspace
220 # Use the -t and -b option as gGlobalDefines's TOOLCHAIN and TARGET if they are not defined
221 if "TARGET" not in GlobalData
.gGlobalDefines
.keys():
222 GlobalData
.gGlobalDefines
["TARGET"] = GenFdsGlobalVariable
.TargetName
223 if "TOOLCHAIN" not in GlobalData
.gGlobalDefines
.keys():
224 GlobalData
.gGlobalDefines
["TOOLCHAIN"] = GenFdsGlobalVariable
.ToolChainTag
225 if "TOOL_CHAIN_TAG" not in GlobalData
.gGlobalDefines
.keys():
226 GlobalData
.gGlobalDefines
['TOOL_CHAIN_TAG'] = GenFdsGlobalVariable
.ToolChainTag
228 """call Workspace build create database"""
229 GlobalData
.gDatabasePath
= os
.path
.normpath(os
.path
.join(ConfDirectoryPath
, GlobalData
.gDatabasePath
))
230 BuildWorkSpace
= WorkspaceDatabase(GlobalData
.gDatabasePath
)
231 BuildWorkSpace
.InitDatabase()
234 # Get files real name in workspace dir
236 GlobalData
.gAllFiles
= DirCache(Workspace
)
237 GlobalData
.gWorkspace
= Workspace
239 if (Options
.archList
) :
240 ArchList
= Options
.archList
.split(',')
242 # EdkLogger.error("GenFds", OPTION_MISSING, "Missing build ARCH")
243 ArchList
= BuildWorkSpace
.BuildObject
[GenFdsGlobalVariable
.ActivePlatform
, 'COMMON', Options
.BuildTarget
, Options
.ToolChain
].SupArchList
245 TargetArchList
= set(BuildWorkSpace
.BuildObject
[GenFdsGlobalVariable
.ActivePlatform
, 'COMMON', Options
.BuildTarget
, Options
.ToolChain
].SupArchList
) & set(ArchList
)
246 if len(TargetArchList
) == 0:
247 EdkLogger
.error("GenFds", GENFDS_ERROR
, "Target ARCH %s not in platform supported ARCH %s" % (str(ArchList
), str(BuildWorkSpace
.BuildObject
[GenFdsGlobalVariable
.ActivePlatform
, 'COMMON'].SupArchList
)))
249 for Arch
in ArchList
:
250 GenFdsGlobalVariable
.OutputDirFromDscDict
[Arch
] = NormPath(BuildWorkSpace
.BuildObject
[GenFdsGlobalVariable
.ActivePlatform
, Arch
, Options
.BuildTarget
, Options
.ToolChain
].OutputDirectory
)
251 GenFdsGlobalVariable
.PlatformName
= BuildWorkSpace
.BuildObject
[GenFdsGlobalVariable
.ActivePlatform
, Arch
, Options
.BuildTarget
, Options
.ToolChain
].PlatformName
253 if (Options
.outputDir
):
254 OutputDirFromCommandLine
= GenFdsGlobalVariable
.ReplaceWorkspaceMacro(Options
.outputDir
)
255 if not os
.path
.isabs (OutputDirFromCommandLine
):
256 OutputDirFromCommandLine
= os
.path
.join(GenFdsGlobalVariable
.WorkSpaceDir
, OutputDirFromCommandLine
)
257 for Arch
in ArchList
:
258 GenFdsGlobalVariable
.OutputDirDict
[Arch
] = OutputDirFromCommandLine
260 for Arch
in ArchList
:
261 GenFdsGlobalVariable
.OutputDirDict
[Arch
] = os
.path
.join(GenFdsGlobalVariable
.OutputDirFromDscDict
[Arch
], GenFdsGlobalVariable
.TargetName
+ '_' + GenFdsGlobalVariable
.ToolChainTag
)
263 for Key
in GenFdsGlobalVariable
.OutputDirDict
:
264 OutputDir
= GenFdsGlobalVariable
.OutputDirDict
[Key
]
265 if OutputDir
[0:2] == '..':
266 OutputDir
= os
.path
.realpath(OutputDir
)
268 if OutputDir
[1] != ':':
269 OutputDir
= os
.path
.join (GenFdsGlobalVariable
.WorkSpaceDir
, OutputDir
)
271 if not os
.path
.exists(OutputDir
):
272 EdkLogger
.error("GenFds", FILE_NOT_FOUND
, ExtraData
=OutputDir
)
273 GenFdsGlobalVariable
.OutputDirDict
[Key
] = OutputDir
275 """ Parse Fdf file, has to place after build Workspace as FDF may contain macros from DSC file """
276 FdfParserObj
= FdfParser
.FdfParser(FdfFilename
)
277 FdfParserObj
.ParseFile()
279 if FdfParserObj
.CycleReferenceCheck():
280 EdkLogger
.error("GenFds", FORMAT_NOT_SUPPORTED
, "Cycle Reference Detected in FDF file")
282 if (Options
.uiFdName
) :
283 if Options
.uiFdName
.upper() in FdfParserObj
.Profile
.FdDict
.keys():
284 GenFds
.OnlyGenerateThisFd
= Options
.uiFdName
286 EdkLogger
.error("GenFds", OPTION_VALUE_INVALID
,
287 "No such an FD in FDF file: %s" % Options
.uiFdName
)
289 if (Options
.uiFvName
) :
290 if Options
.uiFvName
.upper() in FdfParserObj
.Profile
.FvDict
.keys():
291 GenFds
.OnlyGenerateThisFv
= Options
.uiFvName
293 EdkLogger
.error("GenFds", OPTION_VALUE_INVALID
,
294 "No such an FV in FDF file: %s" % Options
.uiFvName
)
296 if (Options
.uiCapName
) :
297 if Options
.uiCapName
.upper() in FdfParserObj
.Profile
.CapsuleDict
.keys():
298 GenFds
.OnlyGenerateThisCap
= Options
.uiCapName
300 EdkLogger
.error("GenFds", OPTION_VALUE_INVALID
,
301 "No such a Capsule in FDF file: %s" % Options
.uiCapName
)
303 GenFdsGlobalVariable
.WorkSpace
= BuildWorkSpace
305 GenFdsGlobalVariable
.ArchList
= ArchList
307 # Dsc Build Data will handle Pcd Settings from CommandLine.
309 """Modify images from build output if the feature of loading driver at fixed address is on."""
310 if GenFdsGlobalVariable
.FixedLoadAddress
:
311 GenFds
.PreprocessImage(BuildWorkSpace
, GenFdsGlobalVariable
.ActivePlatform
)
313 # Record the FV Region info that may specific in the FD
314 if FdfParserObj
.Profile
.FvDict
and FdfParserObj
.Profile
.FdDict
:
315 for Fv
in FdfParserObj
.Profile
.FvDict
:
316 FvObj
= FdfParserObj
.Profile
.FvDict
[Fv
]
317 for Fd
in FdfParserObj
.Profile
.FdDict
:
318 FdObj
= FdfParserObj
.Profile
.FdDict
[Fd
]
319 for RegionObj
in FdObj
.RegionList
:
320 if RegionObj
.RegionType
!= 'FV':
322 for RegionData
in RegionObj
.RegionDataList
:
323 if FvObj
.UiFvName
.upper() == RegionData
.upper():
324 if FvObj
.FvRegionInFD
:
325 if FvObj
.FvRegionInFD
!= RegionObj
.Size
:
326 EdkLogger
.error("GenFds", FORMAT_INVALID
, "The FV %s's region is specified in multiple FD with different value." %FvObj
.UiFvName
)
328 FvObj
.FvRegionInFD
= RegionObj
.Size
329 RegionObj
.BlockInfoOfRegion(FdObj
.BlockSizeList
, FvObj
)
331 GlobalData
.BuildOptionPcd
= Options
.OptionPcd
if Options
.OptionPcd
else {}
333 GenFds
.GenFd('', FdfParserObj
, BuildWorkSpace
, ArchList
)
335 """Generate GUID cross reference file"""
336 GenFds
.GenerateGuidXRefFile(BuildWorkSpace
, ArchList
, FdfParserObj
)
338 """Display FV space info."""
339 GenFds
.DisplayFvSpaceInfo(FdfParserObj
)
341 except FdfParser
.Warning, X
:
342 EdkLogger
.error(X
.ToolName
, FORMAT_INVALID
, File
=X
.FileName
, Line
=X
.LineNumber
, ExtraData
=X
.Message
, RaiseError
=False)
343 ReturnCode
= FORMAT_INVALID
344 except FatalError
, X
:
345 if Options
.debug
!= None:
347 EdkLogger
.quiet(traceback
.format_exc())
348 ReturnCode
= X
.args
[0]
354 "Tools code failure",
355 ExtraData
="Please send email to edk2-devel@lists.01.org for help, attaching following call stack trace!\n",
358 EdkLogger
.quiet(traceback
.format_exc())
359 ReturnCode
= CODE_ERROR
365 def SingleCheckCallback(option
, opt_str
, value
, parser
):
366 if option
not in gParamCheck
:
367 setattr(parser
.values
, option
.dest
, value
)
368 gParamCheck
.append(option
)
370 parser
.error("Option %s only allows one instance in command line!" % option
)
372 def CheckBuildOptionPcd():
373 for Arch
in GenFdsGlobalVariable
.ArchList
:
374 PkgList
= GenFdsGlobalVariable
.WorkSpace
.GetPackageList(GenFdsGlobalVariable
.ActivePlatform
, Arch
, GenFdsGlobalVariable
.TargetName
, GenFdsGlobalVariable
.ToolChainTag
)
375 for i
, pcd
in enumerate(GlobalData
.BuildOptionPcd
):
376 if type(pcd
) is tuple:
378 (pcdname
, pcdvalue
) = pcd
.split('=')
380 EdkLogger
.error('GenFds', OPTION_MISSING
, "No Value specified for the PCD %s." % (pcdname
))
382 (TokenSpaceGuidCName
, TokenCName
) = pcdname
.split('.')
386 TokenSpaceGuidCName
= ''
387 HasTokenSpace
= False
388 TokenSpaceGuidCNameList
= []
392 for package
in PkgList
:
393 for key
in package
.Pcds
:
394 PcdItem
= package
.Pcds
[key
]
396 if (PcdItem
.TokenCName
, PcdItem
.TokenSpaceGuidCName
) == (TokenCName
, TokenSpaceGuidCName
):
397 PcdDatumType
= PcdItem
.DatumType
398 NewValue
= BuildOptionPcdValueFormat(TokenSpaceGuidCName
, TokenCName
, PcdDatumType
, pcdvalue
)
401 if PcdItem
.TokenCName
== TokenCName
:
402 if not PcdItem
.TokenSpaceGuidCName
in TokenSpaceGuidCNameList
:
403 if len (TokenSpaceGuidCNameList
) < 1:
404 TokenSpaceGuidCNameList
.append(PcdItem
.TokenSpaceGuidCName
)
405 PcdDatumType
= PcdItem
.DatumType
406 TokenSpaceGuidCName
= PcdItem
.TokenSpaceGuidCName
407 NewValue
= BuildOptionPcdValueFormat(TokenSpaceGuidCName
, TokenCName
, PcdDatumType
, pcdvalue
)
412 PCD_VALIDATION_INFO_ERROR
,
413 "The Pcd %s is found under multiple different TokenSpaceGuid: %s and %s." % (TokenCName
, PcdItem
.TokenSpaceGuidCName
, TokenSpaceGuidCNameList
[0])
416 GlobalData
.BuildOptionPcd
[i
] = (TokenSpaceGuidCName
, TokenCName
, NewValue
)
421 # Find location of tools to process data
423 # @param KeyStringList Filter for inputs of section generation
424 # @param CurrentArchList Arch list
425 # @param NameGuid The Guid name
427 def FindExtendTool(KeyStringList
, CurrentArchList
, NameGuid
):
428 ToolDb
= ToolDefClassObject
.ToolDefDict(GenFdsGlobalVariable
.ConfDir
).ToolsDefTxtDatabase
429 # if user not specify filter, try to deduce it from global data.
430 if KeyStringList
== None or KeyStringList
== []:
431 Target
= GenFdsGlobalVariable
.TargetName
432 ToolChain
= GenFdsGlobalVariable
.ToolChainTag
433 if ToolChain
not in ToolDb
['TOOL_CHAIN_TAG']:
434 EdkLogger
.error("GenFds", GENFDS_ERROR
, "Can not find external tool because tool tag %s is not defined in tools_def.txt!" % ToolChain
)
435 KeyStringList
= [Target
+ '_' + ToolChain
+ '_' + CurrentArchList
[0]]
436 for Arch
in CurrentArchList
:
437 if Target
+ '_' + ToolChain
+ '_' + Arch
not in KeyStringList
:
438 KeyStringList
.append(Target
+ '_' + ToolChain
+ '_' + Arch
)
440 if GenFdsGlobalVariable
.GuidToolDefinition
:
441 if NameGuid
in GenFdsGlobalVariable
.GuidToolDefinition
.keys():
442 return GenFdsGlobalVariable
.GuidToolDefinition
[NameGuid
]
444 ToolDefinition
= ToolDefClassObject
.ToolDefDict(GenFdsGlobalVariable
.ConfDir
).ToolsDefTxtDictionary
450 for ToolDef
in ToolDefinition
.items():
451 if NameGuid
== ToolDef
[1]:
452 KeyList
= ToolDef
[0].split('_')
458 if Key
in KeyStringList
and KeyList
[4] == 'GUID':
459 ToolPathKey
= Key
+ '_' + KeyList
[3] + '_PATH'
460 ToolOptionKey
= Key
+ '_' + KeyList
[3] + '_FLAGS'
461 ToolPath
= ToolDefinition
.get(ToolPathKey
)
462 ToolOption
= ToolDefinition
.get(ToolOptionKey
)
463 if ToolPathTmp
== None:
464 ToolPathTmp
= ToolPath
466 if ToolPathTmp
!= ToolPath
:
467 EdkLogger
.error("GenFds", GENFDS_ERROR
, "Don't know which tool to use, %s or %s ?" % (ToolPathTmp
, ToolPath
))
470 for Arch
in CurrentArchList
:
471 Platform
= GenFdsGlobalVariable
.WorkSpace
.BuildObject
[GenFdsGlobalVariable
.ActivePlatform
, Arch
, GenFdsGlobalVariable
.TargetName
, GenFdsGlobalVariable
.ToolChainTag
]
472 # key is (ToolChainFamily, ToolChain, CodeBase)
473 for item
in Platform
.BuildOptions
:
474 if '_PATH' in item
[1] or '_FLAGS' in item
[1] or '_GUID' in item
[1]:
475 if not item
[0] or (item
[0] and GenFdsGlobalVariable
.ToolChainFamily
== item
[0]):
476 if item
[1] not in BuildOption
:
477 BuildOption
[item
[1]] = Platform
.BuildOptions
[item
]
479 ToolList
= [TAB_TOD_DEFINES_TARGET
, TAB_TOD_DEFINES_TOOL_CHAIN_TAG
, TAB_TOD_DEFINES_TARGET_ARCH
]
480 for Index
in range(2, -1, -1):
481 for Key
in dict(BuildOption
):
482 List
= Key
.split('_')
483 if List
[Index
] == '*':
484 for String
in ToolDb
[ToolList
[Index
]]:
485 if String
in [Arch
, GenFdsGlobalVariable
.TargetName
, GenFdsGlobalVariable
.ToolChainTag
]:
487 NewKey
= '%s_%s_%s_%s_%s' % tuple(List
)
488 if NewKey
not in BuildOption
:
489 BuildOption
[NewKey
] = BuildOption
[Key
]
492 elif List
[Index
] not in ToolDb
[ToolList
[Index
]]:
496 for Op
in BuildOption
:
497 if NameGuid
== BuildOption
[Op
]:
498 KeyList
= Op
.split('_')
499 Key
= KeyList
[0] + '_' + KeyList
[1] +'_' + KeyList
[2]
500 if Key
in KeyStringList
and KeyList
[4] == 'GUID':
501 ToolPathKey
= Key
+ '_' + KeyList
[3] + '_PATH'
502 ToolOptionKey
= Key
+ '_' + KeyList
[3] + '_FLAGS'
503 if ToolPathKey
in BuildOption
.keys():
504 ToolPathTmp
= BuildOption
.get(ToolPathKey
)
505 if ToolOptionKey
in BuildOption
.keys():
506 ToolOption
= BuildOption
.get(ToolOptionKey
)
508 GenFdsGlobalVariable
.GuidToolDefinition
[NameGuid
] = (ToolPathTmp
, ToolOption
)
509 return ToolPathTmp
, ToolOption
511 ## Parse command line options
513 # Using standard Python module optparse to parse command line option of this tool.
515 # @retval Opt A optparse.Values object containing the parsed options
516 # @retval Args Target of build command
518 def myOptionParser():
519 usage
= "%prog [options] -f input_file -a arch_list -b build_target -p active_platform -t tool_chain_tag -D \"MacroName [= MacroValue]\""
520 Parser
= OptionParser(usage
=usage
, description
=__copyright__
, version
="%prog " + str(versionNumber
))
521 Parser
.add_option("-f", "--file", dest
="filename", type="string", help="Name of FDF file to convert", action
="callback", callback
=SingleCheckCallback
)
522 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")
523 Parser
.add_option("-q", "--quiet", action
="store_true", type=None, help="Disable all messages except FATAL ERRORS.")
524 Parser
.add_option("-v", "--verbose", action
="store_true", type=None, help="Turn on verbose output with informational messages printed.")
525 Parser
.add_option("-d", "--debug", action
="store", type="int", help="Enable debug messages at specified level.")
526 Parser
.add_option("-p", "--platform", type="string", dest
="activePlatform", help="Set the ACTIVE_PLATFORM, overrides target.txt ACTIVE_PLATFORM setting.",
527 action
="callback", callback
=SingleCheckCallback
)
528 Parser
.add_option("-w", "--workspace", type="string", dest
="Workspace", default
=os
.environ
.get('WORKSPACE'), help="Set the WORKSPACE",
529 action
="callback", callback
=SingleCheckCallback
)
530 Parser
.add_option("-o", "--outputDir", type="string", dest
="outputDir", help="Name of Build Output directory",
531 action
="callback", callback
=SingleCheckCallback
)
532 Parser
.add_option("-r", "--rom_image", dest
="uiFdName", help="Build the image using the [FD] section named by FdUiName.")
533 Parser
.add_option("-i", "--FvImage", dest
="uiFvName", help="Build the FV image using the [FV] section named by UiFvName")
534 Parser
.add_option("-C", "--CapsuleImage", dest
="uiCapName", help="Build the Capsule image using the [Capsule] section named by UiCapName")
535 Parser
.add_option("-b", "--buildtarget", type="string", dest
="BuildTarget", help="Set the build TARGET, overrides target.txt TARGET setting.",
536 action
="callback", callback
=SingleCheckCallback
)
537 Parser
.add_option("-t", "--tagname", type="string", dest
="ToolChain", help="Using the tools: TOOL_CHAIN_TAG name to build the platform.",
538 action
="callback", callback
=SingleCheckCallback
)
539 Parser
.add_option("-D", "--define", action
="append", type="string", dest
="Macros", help="Macro: \"Name [= Value]\".")
540 Parser
.add_option("-s", "--specifyaddress", dest
="FixedAddress", action
="store_true", type=None, help="Specify driver load address.")
541 Parser
.add_option("--conf", action
="store", type="string", dest
="ConfDirectory", help="Specify the customized Conf directory.")
542 Parser
.add_option("--ignore-sources", action
="store_true", dest
="IgnoreSources", default
=False, help="Focus to a binary build and ignore all source files")
543 Parser
.add_option("--pcd", action
="append", dest
="OptionPcd", help="Set PCD value by command line. Format: \"PcdName=Value\" ")
544 Parser
.add_option("--genfds-multi-thread", action
="store_true", dest
="GenfdsMultiThread", default
=False, help="Enable GenFds multi thread to generate ffs file.")
546 (Options
, args
) = Parser
.parse_args()
549 ## The class implementing the EDK2 flash image generation process
551 # This process includes:
552 # 1. Collect workspace information, includes platform and module information
553 # 2. Call methods of Fd class to generate FD
554 # 3. Call methods of Fv class to generate FV that not belong to FD
558 # FvName, FdName, CapName in FDF, Image file name
560 OnlyGenerateThisFd
= None
561 OnlyGenerateThisFv
= None
562 OnlyGenerateThisCap
= None
566 # @param OutputDir Output directory
567 # @param FdfParser FDF contents parser
568 # @param Workspace The directory of workspace
569 # @param ArchList The Arch list of platform
571 def GenFd (OutputDir
, FdfParser
, WorkSpace
, ArchList
):
572 GenFdsGlobalVariable
.SetDir ('', FdfParser
, WorkSpace
, ArchList
)
574 GenFdsGlobalVariable
.VerboseLogger(" Generate all Fd images and their required FV and Capsule images!")
575 if GenFds
.OnlyGenerateThisCap
!= None and GenFds
.OnlyGenerateThisCap
.upper() in GenFdsGlobalVariable
.FdfParser
.Profile
.CapsuleDict
.keys():
576 CapsuleObj
= GenFdsGlobalVariable
.FdfParser
.Profile
.CapsuleDict
.get(GenFds
.OnlyGenerateThisCap
.upper())
577 if CapsuleObj
!= None:
578 CapsuleObj
.GenCapsule()
581 if GenFds
.OnlyGenerateThisFd
!= None and GenFds
.OnlyGenerateThisFd
.upper() in GenFdsGlobalVariable
.FdfParser
.Profile
.FdDict
.keys():
582 FdObj
= GenFdsGlobalVariable
.FdfParser
.Profile
.FdDict
.get(GenFds
.OnlyGenerateThisFd
.upper())
586 elif GenFds
.OnlyGenerateThisFd
== None and GenFds
.OnlyGenerateThisFv
== None:
587 for FdName
in GenFdsGlobalVariable
.FdfParser
.Profile
.FdDict
.keys():
588 FdObj
= GenFdsGlobalVariable
.FdfParser
.Profile
.FdDict
[FdName
]
591 GenFdsGlobalVariable
.VerboseLogger("\n Generate other FV images! ")
592 if GenFds
.OnlyGenerateThisFv
!= None and GenFds
.OnlyGenerateThisFv
.upper() in GenFdsGlobalVariable
.FdfParser
.Profile
.FvDict
.keys():
593 FvObj
= GenFdsGlobalVariable
.FdfParser
.Profile
.FvDict
.get(GenFds
.OnlyGenerateThisFv
.upper())
595 Buffer
= StringIO
.StringIO()
596 FvObj
.AddToBuffer(Buffer
)
599 elif GenFds
.OnlyGenerateThisFv
== None:
600 for FvName
in GenFdsGlobalVariable
.FdfParser
.Profile
.FvDict
.keys():
601 Buffer
= StringIO
.StringIO('')
602 FvObj
= GenFdsGlobalVariable
.FdfParser
.Profile
.FvDict
[FvName
]
603 FvObj
.AddToBuffer(Buffer
)
606 if GenFds
.OnlyGenerateThisFv
== None and GenFds
.OnlyGenerateThisFd
== None and GenFds
.OnlyGenerateThisCap
== None:
607 if GenFdsGlobalVariable
.FdfParser
.Profile
.CapsuleDict
!= {}:
608 GenFdsGlobalVariable
.VerboseLogger("\n Generate other Capsule images!")
609 for CapsuleName
in GenFdsGlobalVariable
.FdfParser
.Profile
.CapsuleDict
.keys():
610 CapsuleObj
= GenFdsGlobalVariable
.FdfParser
.Profile
.CapsuleDict
[CapsuleName
]
611 CapsuleObj
.GenCapsule()
613 if GenFdsGlobalVariable
.FdfParser
.Profile
.OptRomDict
!= {}:
614 GenFdsGlobalVariable
.VerboseLogger("\n Generate all Option ROM!")
615 for DriverName
in GenFdsGlobalVariable
.FdfParser
.Profile
.OptRomDict
.keys():
616 OptRomObj
= GenFdsGlobalVariable
.FdfParser
.Profile
.OptRomDict
[DriverName
]
617 OptRomObj
.AddToBuffer(None)
619 def GenFfsMakefile(OutputDir
, FdfParser
, WorkSpace
, ArchList
, GlobalData
):
620 GenFdsGlobalVariable
.SetEnv(FdfParser
, WorkSpace
, ArchList
, GlobalData
)
621 for FdName
in GenFdsGlobalVariable
.FdfParser
.Profile
.FdDict
.keys():
622 FdObj
= GenFdsGlobalVariable
.FdfParser
.Profile
.FdDict
[FdName
]
623 FdObj
.GenFd(Flag
=True)
625 for FvName
in GenFdsGlobalVariable
.FdfParser
.Profile
.FvDict
.keys():
626 FvObj
= GenFdsGlobalVariable
.FdfParser
.Profile
.FvDict
[FvName
]
627 FvObj
.AddToBuffer(Buffer
=None, Flag
=True)
629 if GenFdsGlobalVariable
.FdfParser
.Profile
.OptRomDict
!= {}:
630 for DriverName
in GenFdsGlobalVariable
.FdfParser
.Profile
.OptRomDict
.keys():
631 OptRomObj
= GenFdsGlobalVariable
.FdfParser
.Profile
.OptRomDict
[DriverName
]
632 OptRomObj
.AddToBuffer(Buffer
=None, Flag
=True)
634 return GenFdsGlobalVariable
.FfsCmdDict
638 # @param FvObj Whose block size to get
639 # @retval int Block size value
641 def GetFvBlockSize(FvObj
):
642 DefaultBlockSize
= 0x1
644 if GenFds
.OnlyGenerateThisFd
!= None and GenFds
.OnlyGenerateThisFd
.upper() in GenFdsGlobalVariable
.FdfParser
.Profile
.FdDict
.keys():
645 FdObj
= GenFdsGlobalVariable
.FdfParser
.Profile
.FdDict
[GenFds
.OnlyGenerateThisFd
.upper()]
647 for ElementFd
in GenFdsGlobalVariable
.FdfParser
.Profile
.FdDict
.values():
648 for ElementRegion
in ElementFd
.RegionList
:
649 if ElementRegion
.RegionType
== 'FV':
650 for ElementRegionData
in ElementRegion
.RegionDataList
:
651 if ElementRegionData
!= None and ElementRegionData
.upper() == FvObj
.UiFvName
:
652 if FvObj
.BlockSizeList
!= []:
653 return FvObj
.BlockSizeList
[0][0]
655 return ElementRegion
.BlockSizeOfRegion(ElementFd
.BlockSizeList
)
656 if FvObj
.BlockSizeList
!= []:
657 return FvObj
.BlockSizeList
[0][0]
658 return DefaultBlockSize
660 for ElementRegion
in FdObj
.RegionList
:
661 if ElementRegion
.RegionType
== 'FV':
662 for ElementRegionData
in ElementRegion
.RegionDataList
:
663 if ElementRegionData
!= None and ElementRegionData
.upper() == FvObj
.UiFvName
:
664 if FvObj
.BlockSizeList
!= []:
665 return FvObj
.BlockSizeList
[0][0]
667 return ElementRegion
.BlockSizeOfRegion(ElementFd
.BlockSizeList
)
668 return DefaultBlockSize
670 ## DisplayFvSpaceInfo()
672 # @param FvObj Whose block size to get
675 def DisplayFvSpaceInfo(FdfParser
):
679 for FvName
in FdfParser
.Profile
.FvDict
:
680 if len(FvName
) > MaxFvNameLength
:
681 MaxFvNameLength
= len(FvName
)
682 FvSpaceInfoFileName
= os
.path
.join(GenFdsGlobalVariable
.FvDir
, FvName
.upper() + '.Fv.map')
683 if os
.path
.exists(FvSpaceInfoFileName
):
684 FileLinesList
= linecache
.getlines(FvSpaceInfoFileName
)
691 for Line
in FileLinesList
:
692 NameValue
= Line
.split('=')
693 if len(NameValue
) == 2:
694 if NameValue
[0].strip() == 'EFI_FV_TOTAL_SIZE':
696 Total
= NameValue
[1].strip()
697 if NameValue
[0].strip() == 'EFI_FV_TAKEN_SIZE':
699 Used
= NameValue
[1].strip()
700 if NameValue
[0].strip() == 'EFI_FV_SPACE_SIZE':
702 Free
= NameValue
[1].strip()
704 if TotalFound
and UsedFound
and FreeFound
:
705 FvSpaceInfoList
.append((FvName
, Total
, Used
, Free
))
707 GenFdsGlobalVariable
.InfLogger('\nFV Space Information')
708 for FvSpaceInfo
in FvSpaceInfoList
:
709 Name
= FvSpaceInfo
[0]
710 TotalSizeValue
= long(FvSpaceInfo
[1], 0)
711 UsedSizeValue
= long(FvSpaceInfo
[2], 0)
712 FreeSizeValue
= long(FvSpaceInfo
[3], 0)
713 if UsedSizeValue
== TotalSizeValue
:
716 Percentage
= str((UsedSizeValue
+ 0.0) / TotalSizeValue
)[0:4].lstrip('0.')
718 GenFdsGlobalVariable
.InfLogger(Name
+ ' ' + '[' + Percentage
+ '%Full] ' + str(TotalSizeValue
) + ' total, ' + str(UsedSizeValue
) + ' used, ' + str(FreeSizeValue
) + ' free')
722 # @param BuildDb Database from build meta data files
723 # @param DscFile modules from dsc file will be preprocessed
726 def PreprocessImage(BuildDb
, DscFile
):
727 PcdDict
= BuildDb
.BuildObject
[DscFile
, 'COMMON', GenFdsGlobalVariable
.TargetName
, GenFdsGlobalVariable
.ToolChainTag
].Pcds
730 PcdObj
= PcdDict
[Key
]
731 if PcdObj
.TokenCName
== 'PcdBsBaseAddress':
732 PcdValue
= PcdObj
.DefaultValue
738 Int64PcdValue
= long(PcdValue
, 0)
739 if Int64PcdValue
== 0 or Int64PcdValue
< -1:
743 if Int64PcdValue
> 0:
744 TopAddress
= Int64PcdValue
746 ModuleDict
= BuildDb
.BuildObject
[DscFile
, 'COMMON', GenFdsGlobalVariable
.TargetName
, GenFdsGlobalVariable
.ToolChainTag
].Modules
747 for Key
in ModuleDict
:
748 ModuleObj
= BuildDb
.BuildObject
[Key
, 'COMMON', GenFdsGlobalVariable
.TargetName
, GenFdsGlobalVariable
.ToolChainTag
]
749 print ModuleObj
.BaseName
+ ' ' + ModuleObj
.ModuleType
751 def GenerateGuidXRefFile(BuildDb
, ArchList
, FdfParserObj
):
752 GuidXRefFileName
= os
.path
.join(GenFdsGlobalVariable
.FvDir
, "Guid.xref")
753 GuidXRefFile
= StringIO
.StringIO('')
757 for Arch
in ArchList
:
758 PlatformDataBase
= BuildDb
.BuildObject
[GenFdsGlobalVariable
.ActivePlatform
, Arch
, GenFdsGlobalVariable
.TargetName
, GenFdsGlobalVariable
.ToolChainTag
]
759 for ModuleFile
in PlatformDataBase
.Modules
:
760 Module
= BuildDb
.BuildObject
[ModuleFile
, Arch
, GenFdsGlobalVariable
.TargetName
, GenFdsGlobalVariable
.ToolChainTag
]
761 if Module
in ModuleList
:
764 ModuleList
.append(Module
)
765 GuidXRefFile
.write("%s %s\n" % (Module
.Guid
, Module
.BaseName
))
766 for key
, item
in Module
.Protocols
.items():
768 for key
, item
in Module
.Guids
.items():
770 for key
, item
in Module
.Ppis
.items():
772 for FvName
in FdfParserObj
.Profile
.FvDict
:
773 for FfsObj
in FdfParserObj
.Profile
.FvDict
[FvName
].FfsList
:
774 if not isinstance(FfsObj
, FfsFileStatement
.FileStatement
):
775 InfPath
= PathClass(NormPath(mws
.join(GenFdsGlobalVariable
.WorkSpaceDir
, FfsObj
.InfFileName
)))
776 FdfModule
= BuildDb
.BuildObject
[InfPath
, Arch
, GenFdsGlobalVariable
.TargetName
, GenFdsGlobalVariable
.ToolChainTag
]
777 if FdfModule
in ModuleList
:
780 ModuleList
.append(FdfModule
)
781 GuidXRefFile
.write("%s %s\n" % (FdfModule
.Guid
, FdfModule
.BaseName
))
782 for key
, item
in FdfModule
.Protocols
.items():
784 for key
, item
in FdfModule
.Guids
.items():
786 for key
, item
in FdfModule
.Ppis
.items():
789 FileStatementGuid
= FfsObj
.NameGuid
790 if FileStatementGuid
in FileGuidList
:
793 FileGuidList
.append(FileStatementGuid
)
795 FfsPath
= os
.path
.join(GenFdsGlobalVariable
.FvDir
, 'Ffs')
796 FfsPath
= glob
.glob(os
.path
.join(FfsPath
, FileStatementGuid
) + '*')
799 if not os
.path
.exists(FfsPath
[0]):
802 ReFileEnds
= re
.compile('\S+(.ui)$|\S+(fv.sec.txt)$|\S+(.pe32.txt)$|\S+(.te.txt)$|\S+(.pic.txt)$|\S+(.raw.txt)$|\S+(.ffs.txt)$')
803 FileList
= os
.listdir(FfsPath
[0])
804 for File
in FileList
:
805 Match
= ReFileEnds
.search(File
)
807 for Index
in range(1, 8):
808 if Match
.group(Index
) and Match
.group(Index
) in MatchDict
:
809 MatchDict
[Match
.group(Index
)].append(File
)
810 elif Match
.group(Index
):
811 MatchDict
[Match
.group(Index
)] = [File
]
814 if '.ui' in MatchDict
:
815 for File
in MatchDict
['.ui']:
816 with
open(os
.path
.join(FfsPath
[0], File
), 'rb') as F
:
820 TmpStr
= unpack('%dh' % ((length
- 4) / 2), F
.read())
821 Name
= ''.join([chr(c
) for c
in TmpStr
[:-1]])
824 if 'fv.sec.txt' in MatchDict
:
825 FileList
= MatchDict
['fv.sec.txt']
826 elif '.pe32.txt' in MatchDict
:
827 FileList
= MatchDict
['.pe32.txt']
828 elif '.te.txt' in MatchDict
:
829 FileList
= MatchDict
['.te.txt']
830 elif '.pic.txt' in MatchDict
:
831 FileList
= MatchDict
['.pic.txt']
832 elif '.raw.txt' in MatchDict
:
833 FileList
= MatchDict
['.raw.txt']
834 elif '.ffs.txt' in MatchDict
:
835 FileList
= MatchDict
['.ffs.txt']
838 for File
in FileList
:
839 with
open(os
.path
.join(FfsPath
[0], File
), 'r') as F
:
840 Name
.append((F
.read().split()[-1]))
844 Name
= ' '.join(Name
) if type(Name
) == type([]) else Name
845 GuidXRefFile
.write("%s %s\n" %(FileStatementGuid
, Name
))
847 # Append GUIDs, Protocols, and PPIs to the Xref file
848 GuidXRefFile
.write("\n")
849 for key
, item
in GuidDict
.items():
850 GuidXRefFile
.write("%s %s\n" % (GuidStructureStringToGuidString(item
).upper(), key
))
852 if GuidXRefFile
.getvalue():
853 SaveFileOnChange(GuidXRefFileName
, GuidXRefFile
.getvalue(), False)
854 GenFdsGlobalVariable
.InfLogger("\nGUID cross reference file can be found at %s" % GuidXRefFileName
)
855 elif os
.path
.exists(GuidXRefFileName
):
856 os
.remove(GuidXRefFileName
)
859 ##Define GenFd as static function
860 GenFd
= staticmethod(GenFd
)
861 GetFvBlockSize
= staticmethod(GetFvBlockSize
)
862 DisplayFvSpaceInfo
= staticmethod(DisplayFvSpaceInfo
)
863 PreprocessImage
= staticmethod(PreprocessImage
)
864 GenerateGuidXRefFile
= staticmethod(GenerateGuidXRefFile
)
866 if __name__
== '__main__':
868 ## 0-127 is a safe return range, and 1 is a standard default error
869 if r
< 0 or r
> 127: r
= 1