BaseTools: refactor and remove un-needed use of .keys() on dictionaries
[mirror_edk2.git] / BaseTools / Source / Python / GenFds / GenFds.py
1 ## @file
2 # generate flash image
3 #
4 # Copyright (c) 2007 - 2018, Intel Corporation. All rights reserved.<BR>
5 #
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
10 #
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.
13 #
14
15 ##
16 # Import Modules
17 #
18 from optparse import OptionParser
19 import sys
20 import Common.LongFilePathOs as os
21 import linecache
22 import FdfParser
23 import Common.BuildToolError as BuildToolError
24 from GenFdsGlobalVariable import GenFdsGlobalVariable
25 from Workspace.WorkspaceDatabase import WorkspaceDatabase
26 from Workspace.BuildClassObject import PcdClassObject
27 import RuleComplexFile
28 from EfiSection import EfiSection
29 import StringIO
30 import Common.TargetTxtClassObject as TargetTxtClassObject
31 import Common.ToolDefClassObject as ToolDefClassObject
32 from Common.DataType import *
33 import Common.GlobalData as GlobalData
34 from Common import EdkLogger
35 from Common.String import *
36 from Common.Misc import DirCache, PathClass
37 from Common.Misc import SaveFileOnChange
38 from Common.Misc import ClearDuplicatedInf
39 from Common.Misc import GuidStructureStringToGuidString
40 from Common.BuildVersion import gBUILD_VERSION
41 from Common.MultipleWorkspace import MultipleWorkspace as mws
42 import FfsFileStatement
43 import glob
44 from struct import unpack
45
46 ## Version and Copyright
47 versionNumber = "1.0" + ' ' + gBUILD_VERSION
48 __version__ = "%prog Version " + versionNumber
49 __copyright__ = "Copyright (c) 2007 - 2017, Intel Corporation All rights reserved."
50
51 ## Tool entrance method
52 #
53 # This method mainly dispatch specific methods per the command line options.
54 # If no error found, return zero value so the caller of this tool can know
55 # if it's executed successfully or not.
56 #
57 # @retval 0 Tool was successful
58 # @retval 1 Tool failed
59 #
60 def main():
61 global Options
62 Options = myOptionParser()
63
64 global Workspace
65 Workspace = ""
66 ArchList = None
67 ReturnCode = 0
68
69 EdkLogger.Initialize()
70 try:
71 if Options.verbose is not None:
72 EdkLogger.SetLevel(EdkLogger.VERBOSE)
73 GenFdsGlobalVariable.VerboseMode = True
74
75 if Options.FixedAddress is not None:
76 GenFdsGlobalVariable.FixedLoadAddress = True
77
78 if Options.quiet is not None:
79 EdkLogger.SetLevel(EdkLogger.QUIET)
80 if Options.debug is not None:
81 EdkLogger.SetLevel(Options.debug + 1)
82 GenFdsGlobalVariable.DebugLevel = Options.debug
83 else:
84 EdkLogger.SetLevel(EdkLogger.INFO)
85
86 if (Options.Workspace is None):
87 EdkLogger.error("GenFds", OPTION_MISSING, "WORKSPACE not defined",
88 ExtraData="Please use '-w' switch to pass it or set the WORKSPACE environment variable.")
89 elif not os.path.exists(Options.Workspace):
90 EdkLogger.error("GenFds", PARAMETER_INVALID, "WORKSPACE is invalid",
91 ExtraData="Please use '-w' switch to pass it or set the WORKSPACE environment variable.")
92 else:
93 Workspace = os.path.normcase(Options.Workspace)
94 GenFdsGlobalVariable.WorkSpaceDir = Workspace
95 if 'EDK_SOURCE' in os.environ:
96 GenFdsGlobalVariable.EdkSourceDir = os.path.normcase(os.environ['EDK_SOURCE'])
97 if (Options.debug):
98 GenFdsGlobalVariable.VerboseLogger("Using Workspace:" + Workspace)
99 if Options.GenfdsMultiThread:
100 GenFdsGlobalVariable.EnableGenfdsMultiThread = True
101 os.chdir(GenFdsGlobalVariable.WorkSpaceDir)
102
103 # set multiple workspace
104 PackagesPath = os.getenv("PACKAGES_PATH")
105 mws.setWs(GenFdsGlobalVariable.WorkSpaceDir, PackagesPath)
106
107 if (Options.filename):
108 FdfFilename = Options.filename
109 FdfFilename = GenFdsGlobalVariable.ReplaceWorkspaceMacro(FdfFilename)
110
111 if FdfFilename[0:2] == '..':
112 FdfFilename = os.path.realpath(FdfFilename)
113 if not os.path.isabs(FdfFilename):
114 FdfFilename = mws.join(GenFdsGlobalVariable.WorkSpaceDir, FdfFilename)
115 if not os.path.exists(FdfFilename):
116 EdkLogger.error("GenFds", FILE_NOT_FOUND, ExtraData=FdfFilename)
117
118 GenFdsGlobalVariable.FdfFile = FdfFilename
119 GenFdsGlobalVariable.FdfFileTimeStamp = os.path.getmtime(FdfFilename)
120 else:
121 EdkLogger.error("GenFds", OPTION_MISSING, "Missing FDF filename")
122
123 if (Options.BuildTarget):
124 GenFdsGlobalVariable.TargetName = Options.BuildTarget
125
126 if (Options.ToolChain):
127 GenFdsGlobalVariable.ToolChainTag = Options.ToolChain
128
129 if (Options.activePlatform):
130 ActivePlatform = Options.activePlatform
131 ActivePlatform = GenFdsGlobalVariable.ReplaceWorkspaceMacro(ActivePlatform)
132
133 if ActivePlatform[0:2] == '..':
134 ActivePlatform = os.path.realpath(ActivePlatform)
135
136 if not os.path.isabs (ActivePlatform):
137 ActivePlatform = mws.join(GenFdsGlobalVariable.WorkSpaceDir, ActivePlatform)
138
139 if not os.path.exists(ActivePlatform) :
140 EdkLogger.error("GenFds", FILE_NOT_FOUND, "ActivePlatform doesn't exist!")
141 else:
142 EdkLogger.error("GenFds", OPTION_MISSING, "Missing active platform")
143
144 GlobalData.BuildOptionPcd = Options.OptionPcd if Options.OptionPcd else {}
145 GenFdsGlobalVariable.ActivePlatform = PathClass(NormPath(ActivePlatform))
146
147 if (Options.ConfDirectory):
148 # Get alternate Conf location, if it is absolute, then just use the absolute directory name
149 ConfDirectoryPath = os.path.normpath(Options.ConfDirectory)
150 if ConfDirectoryPath.startswith('"'):
151 ConfDirectoryPath = ConfDirectoryPath[1:]
152 if ConfDirectoryPath.endswith('"'):
153 ConfDirectoryPath = ConfDirectoryPath[:-1]
154 if not os.path.isabs(ConfDirectoryPath):
155 # Since alternate directory name is not absolute, the alternate directory is located within the WORKSPACE
156 # This also handles someone specifying the Conf directory in the workspace. Using --conf=Conf
157 ConfDirectoryPath = os.path.join(GenFdsGlobalVariable.WorkSpaceDir, ConfDirectoryPath)
158 else:
159 if "CONF_PATH" in os.environ:
160 ConfDirectoryPath = os.path.normcase(os.environ["CONF_PATH"])
161 else:
162 # Get standard WORKSPACE/Conf, use the absolute path to the WORKSPACE/Conf
163 ConfDirectoryPath = mws.join(GenFdsGlobalVariable.WorkSpaceDir, 'Conf')
164 GenFdsGlobalVariable.ConfDir = ConfDirectoryPath
165 if not GlobalData.gConfDirectory:
166 GlobalData.gConfDirectory = GenFdsGlobalVariable.ConfDir
167 BuildConfigurationFile = os.path.normpath(os.path.join(ConfDirectoryPath, "target.txt"))
168 if os.path.isfile(BuildConfigurationFile) == True:
169 TargetTxt = TargetTxtClassObject.TargetTxtClassObject()
170 TargetTxt.LoadTargetTxtFile(BuildConfigurationFile)
171 # if no build target given in command line, get it from target.txt
172 if not GenFdsGlobalVariable.TargetName:
173 BuildTargetList = TargetTxt.TargetTxtDictionary[DataType.TAB_TAT_DEFINES_TARGET]
174 if len(BuildTargetList) != 1:
175 EdkLogger.error("GenFds", OPTION_VALUE_INVALID, ExtraData="Only allows one instance for Target.")
176 GenFdsGlobalVariable.TargetName = BuildTargetList[0]
177
178 # if no tool chain given in command line, get it from target.txt
179 if not GenFdsGlobalVariable.ToolChainTag:
180 ToolChainList = TargetTxt.TargetTxtDictionary[DataType.TAB_TAT_DEFINES_TOOL_CHAIN_TAG]
181 if ToolChainList is None or len(ToolChainList) == 0:
182 EdkLogger.error("GenFds", RESOURCE_NOT_AVAILABLE, ExtraData="No toolchain given. Don't know how to build.")
183 if len(ToolChainList) != 1:
184 EdkLogger.error("GenFds", OPTION_VALUE_INVALID, ExtraData="Only allows one instance for ToolChain.")
185 GenFdsGlobalVariable.ToolChainTag = ToolChainList[0]
186 else:
187 EdkLogger.error("GenFds", FILE_NOT_FOUND, ExtraData=BuildConfigurationFile)
188
189 #Set global flag for build mode
190 GlobalData.gIgnoreSource = Options.IgnoreSources
191
192 if Options.Macros:
193 for Pair in Options.Macros:
194 if Pair.startswith('"'):
195 Pair = Pair[1:]
196 if Pair.endswith('"'):
197 Pair = Pair[:-1]
198 List = Pair.split('=')
199 if len(List) == 2:
200 if not List[1].strip():
201 EdkLogger.error("GenFds", OPTION_VALUE_INVALID, ExtraData="No Value given for Macro %s" %List[0])
202 if List[0].strip() == "EFI_SOURCE":
203 GlobalData.gEfiSource = List[1].strip()
204 GlobalData.gGlobalDefines["EFI_SOURCE"] = GlobalData.gEfiSource
205 continue
206 elif List[0].strip() == "EDK_SOURCE":
207 GlobalData.gEdkSource = List[1].strip()
208 GlobalData.gGlobalDefines["EDK_SOURCE"] = GlobalData.gEdkSource
209 continue
210 elif List[0].strip() in ["WORKSPACE", "TARGET", "TOOLCHAIN"]:
211 GlobalData.gGlobalDefines[List[0].strip()] = List[1].strip()
212 else:
213 GlobalData.gCommandLineDefines[List[0].strip()] = List[1].strip()
214 else:
215 GlobalData.gCommandLineDefines[List[0].strip()] = "TRUE"
216 os.environ["WORKSPACE"] = Workspace
217
218 # Use the -t and -b option as gGlobalDefines's TOOLCHAIN and TARGET if they are not defined
219 if "TARGET" not in GlobalData.gGlobalDefines:
220 GlobalData.gGlobalDefines["TARGET"] = GenFdsGlobalVariable.TargetName
221 if "TOOLCHAIN" not in GlobalData.gGlobalDefines:
222 GlobalData.gGlobalDefines["TOOLCHAIN"] = GenFdsGlobalVariable.ToolChainTag
223 if "TOOL_CHAIN_TAG" not in GlobalData.gGlobalDefines:
224 GlobalData.gGlobalDefines['TOOL_CHAIN_TAG'] = GenFdsGlobalVariable.ToolChainTag
225
226 """call Workspace build create database"""
227 GlobalData.gDatabasePath = os.path.normpath(os.path.join(ConfDirectoryPath, GlobalData.gDatabasePath))
228 BuildWorkSpace = WorkspaceDatabase(GlobalData.gDatabasePath)
229 BuildWorkSpace.InitDatabase()
230
231 #
232 # Get files real name in workspace dir
233 #
234 GlobalData.gAllFiles = DirCache(Workspace)
235 GlobalData.gWorkspace = Workspace
236
237 if (Options.archList) :
238 ArchList = Options.archList.split(',')
239 else:
240 # EdkLogger.error("GenFds", OPTION_MISSING, "Missing build ARCH")
241 ArchList = BuildWorkSpace.BuildObject[GenFdsGlobalVariable.ActivePlatform, TAB_COMMON, Options.BuildTarget, Options.ToolChain].SupArchList
242
243 TargetArchList = set(BuildWorkSpace.BuildObject[GenFdsGlobalVariable.ActivePlatform, TAB_COMMON, Options.BuildTarget, Options.ToolChain].SupArchList) & set(ArchList)
244 if len(TargetArchList) == 0:
245 EdkLogger.error("GenFds", GENFDS_ERROR, "Target ARCH %s not in platform supported ARCH %s" % (str(ArchList), str(BuildWorkSpace.BuildObject[GenFdsGlobalVariable.ActivePlatform, TAB_COMMON].SupArchList)))
246
247 for Arch in ArchList:
248 GenFdsGlobalVariable.OutputDirFromDscDict[Arch] = NormPath(BuildWorkSpace.BuildObject[GenFdsGlobalVariable.ActivePlatform, Arch, Options.BuildTarget, Options.ToolChain].OutputDirectory)
249 GenFdsGlobalVariable.PlatformName = BuildWorkSpace.BuildObject[GenFdsGlobalVariable.ActivePlatform, Arch, Options.BuildTarget, Options.ToolChain].PlatformName
250
251 if (Options.outputDir):
252 OutputDirFromCommandLine = GenFdsGlobalVariable.ReplaceWorkspaceMacro(Options.outputDir)
253 if not os.path.isabs (OutputDirFromCommandLine):
254 OutputDirFromCommandLine = os.path.join(GenFdsGlobalVariable.WorkSpaceDir, OutputDirFromCommandLine)
255 for Arch in ArchList:
256 GenFdsGlobalVariable.OutputDirDict[Arch] = OutputDirFromCommandLine
257 else:
258 for Arch in ArchList:
259 GenFdsGlobalVariable.OutputDirDict[Arch] = os.path.join(GenFdsGlobalVariable.OutputDirFromDscDict[Arch], GenFdsGlobalVariable.TargetName + '_' + GenFdsGlobalVariable.ToolChainTag)
260
261 for Key in GenFdsGlobalVariable.OutputDirDict:
262 OutputDir = GenFdsGlobalVariable.OutputDirDict[Key]
263 if OutputDir[0:2] == '..':
264 OutputDir = os.path.realpath(OutputDir)
265
266 if OutputDir[1] != ':':
267 OutputDir = os.path.join (GenFdsGlobalVariable.WorkSpaceDir, OutputDir)
268
269 if not os.path.exists(OutputDir):
270 EdkLogger.error("GenFds", FILE_NOT_FOUND, ExtraData=OutputDir)
271 GenFdsGlobalVariable.OutputDirDict[Key] = OutputDir
272
273 """ Parse Fdf file, has to place after build Workspace as FDF may contain macros from DSC file """
274 FdfParserObj = FdfParser.FdfParser(FdfFilename)
275 FdfParserObj.ParseFile()
276
277 if FdfParserObj.CycleReferenceCheck():
278 EdkLogger.error("GenFds", FORMAT_NOT_SUPPORTED, "Cycle Reference Detected in FDF file")
279
280 if (Options.uiFdName) :
281 if Options.uiFdName.upper() in FdfParserObj.Profile.FdDict:
282 GenFds.OnlyGenerateThisFd = Options.uiFdName
283 else:
284 EdkLogger.error("GenFds", OPTION_VALUE_INVALID,
285 "No such an FD in FDF file: %s" % Options.uiFdName)
286
287 if (Options.uiFvName) :
288 if Options.uiFvName.upper() in FdfParserObj.Profile.FvDict:
289 GenFds.OnlyGenerateThisFv = Options.uiFvName
290 else:
291 EdkLogger.error("GenFds", OPTION_VALUE_INVALID,
292 "No such an FV in FDF file: %s" % Options.uiFvName)
293
294 if (Options.uiCapName) :
295 if Options.uiCapName.upper() in FdfParserObj.Profile.CapsuleDict:
296 GenFds.OnlyGenerateThisCap = Options.uiCapName
297 else:
298 EdkLogger.error("GenFds", OPTION_VALUE_INVALID,
299 "No such a Capsule in FDF file: %s" % Options.uiCapName)
300
301 GenFdsGlobalVariable.WorkSpace = BuildWorkSpace
302 if ArchList is not None:
303 GenFdsGlobalVariable.ArchList = ArchList
304
305 # Dsc Build Data will handle Pcd Settings from CommandLine.
306
307 """Modify images from build output if the feature of loading driver at fixed address is on."""
308 if GenFdsGlobalVariable.FixedLoadAddress:
309 GenFds.PreprocessImage(BuildWorkSpace, GenFdsGlobalVariable.ActivePlatform)
310
311 # Record the FV Region info that may specific in the FD
312 if FdfParserObj.Profile.FvDict and FdfParserObj.Profile.FdDict:
313 for Fv in FdfParserObj.Profile.FvDict:
314 FvObj = FdfParserObj.Profile.FvDict[Fv]
315 for Fd in FdfParserObj.Profile.FdDict:
316 FdObj = FdfParserObj.Profile.FdDict[Fd]
317 for RegionObj in FdObj.RegionList:
318 if RegionObj.RegionType != 'FV':
319 continue
320 for RegionData in RegionObj.RegionDataList:
321 if FvObj.UiFvName.upper() == RegionData.upper():
322 if FvObj.FvRegionInFD:
323 if FvObj.FvRegionInFD != RegionObj.Size:
324 EdkLogger.error("GenFds", FORMAT_INVALID, "The FV %s's region is specified in multiple FD with different value." %FvObj.UiFvName)
325 else:
326 FvObj.FvRegionInFD = RegionObj.Size
327 RegionObj.BlockInfoOfRegion(FdObj.BlockSizeList, FvObj)
328
329 """Call GenFds"""
330 GenFds.GenFd('', FdfParserObj, BuildWorkSpace, ArchList)
331
332 """Generate GUID cross reference file"""
333 GenFds.GenerateGuidXRefFile(BuildWorkSpace, ArchList, FdfParserObj)
334
335 """Display FV space info."""
336 GenFds.DisplayFvSpaceInfo(FdfParserObj)
337
338 except FdfParser.Warning, X:
339 EdkLogger.error(X.ToolName, FORMAT_INVALID, File=X.FileName, Line=X.LineNumber, ExtraData=X.Message, RaiseError=False)
340 ReturnCode = FORMAT_INVALID
341 except FatalError, X:
342 if Options.debug is not None:
343 import traceback
344 EdkLogger.quiet(traceback.format_exc())
345 ReturnCode = X.args[0]
346 except:
347 import traceback
348 EdkLogger.error(
349 "\nPython",
350 CODE_ERROR,
351 "Tools code failure",
352 ExtraData="Please send email to edk2-devel@lists.01.org for help, attaching following call stack trace!\n",
353 RaiseError=False
354 )
355 EdkLogger.quiet(traceback.format_exc())
356 ReturnCode = CODE_ERROR
357 finally:
358 ClearDuplicatedInf()
359 return ReturnCode
360
361 gParamCheck = []
362 def SingleCheckCallback(option, opt_str, value, parser):
363 if option not in gParamCheck:
364 setattr(parser.values, option.dest, value)
365 gParamCheck.append(option)
366 else:
367 parser.error("Option %s only allows one instance in command line!" % option)
368
369 ## FindExtendTool()
370 #
371 # Find location of tools to process data
372 #
373 # @param KeyStringList Filter for inputs of section generation
374 # @param CurrentArchList Arch list
375 # @param NameGuid The Guid name
376 #
377 def FindExtendTool(KeyStringList, CurrentArchList, NameGuid):
378 ToolDb = ToolDefClassObject.ToolDefDict(GenFdsGlobalVariable.ConfDir).ToolsDefTxtDatabase
379 # if user not specify filter, try to deduce it from global data.
380 if KeyStringList is None or KeyStringList == []:
381 Target = GenFdsGlobalVariable.TargetName
382 ToolChain = GenFdsGlobalVariable.ToolChainTag
383 if ToolChain not in ToolDb['TOOL_CHAIN_TAG']:
384 EdkLogger.error("GenFds", GENFDS_ERROR, "Can not find external tool because tool tag %s is not defined in tools_def.txt!" % ToolChain)
385 KeyStringList = [Target + '_' + ToolChain + '_' + CurrentArchList[0]]
386 for Arch in CurrentArchList:
387 if Target + '_' + ToolChain + '_' + Arch not in KeyStringList:
388 KeyStringList.append(Target + '_' + ToolChain + '_' + Arch)
389
390 if GenFdsGlobalVariable.GuidToolDefinition:
391 if NameGuid in GenFdsGlobalVariable.GuidToolDefinition:
392 return GenFdsGlobalVariable.GuidToolDefinition[NameGuid]
393
394 ToolDefinition = ToolDefClassObject.ToolDefDict(GenFdsGlobalVariable.ConfDir).ToolsDefTxtDictionary
395 ToolPathTmp = None
396 ToolOption = None
397 ToolPathKey = None
398 ToolOptionKey = None
399 KeyList = None
400 for ToolDef in ToolDefinition.items():
401 if NameGuid.lower() == ToolDef[1].lower() :
402 KeyList = ToolDef[0].split('_')
403 Key = KeyList[0] + \
404 '_' + \
405 KeyList[1] + \
406 '_' + \
407 KeyList[2]
408 if Key in KeyStringList and KeyList[4] == 'GUID':
409 ToolPathKey = Key + '_' + KeyList[3] + '_PATH'
410 ToolOptionKey = Key + '_' + KeyList[3] + '_FLAGS'
411 ToolPath = ToolDefinition.get(ToolPathKey)
412 ToolOption = ToolDefinition.get(ToolOptionKey)
413 if ToolPathTmp is None:
414 ToolPathTmp = ToolPath
415 else:
416 if ToolPathTmp != ToolPath:
417 EdkLogger.error("GenFds", GENFDS_ERROR, "Don't know which tool to use, %s or %s ?" % (ToolPathTmp, ToolPath))
418
419 BuildOption = {}
420 for Arch in CurrentArchList:
421 Platform = GenFdsGlobalVariable.WorkSpace.BuildObject[GenFdsGlobalVariable.ActivePlatform, Arch, GenFdsGlobalVariable.TargetName, GenFdsGlobalVariable.ToolChainTag]
422 # key is (ToolChainFamily, ToolChain, CodeBase)
423 for item in Platform.BuildOptions:
424 if '_PATH' in item[1] or '_FLAGS' in item[1] or '_GUID' in item[1]:
425 if not item[0] or (item[0] and GenFdsGlobalVariable.ToolChainFamily== item[0]):
426 if item[1] not in BuildOption:
427 BuildOption[item[1]] = Platform.BuildOptions[item]
428 if BuildOption:
429 ToolList = [TAB_TOD_DEFINES_TARGET, TAB_TOD_DEFINES_TOOL_CHAIN_TAG, TAB_TOD_DEFINES_TARGET_ARCH]
430 for Index in range(2, -1, -1):
431 for Key in dict(BuildOption):
432 List = Key.split('_')
433 if List[Index] == '*':
434 for String in ToolDb[ToolList[Index]]:
435 if String in [Arch, GenFdsGlobalVariable.TargetName, GenFdsGlobalVariable.ToolChainTag]:
436 List[Index] = String
437 NewKey = '%s_%s_%s_%s_%s' % tuple(List)
438 if NewKey not in BuildOption:
439 BuildOption[NewKey] = BuildOption[Key]
440 continue
441 del BuildOption[Key]
442 elif List[Index] not in ToolDb[ToolList[Index]]:
443 del BuildOption[Key]
444 if BuildOption:
445 if not KeyList:
446 for Op in BuildOption:
447 if NameGuid == BuildOption[Op]:
448 KeyList = Op.split('_')
449 Key = KeyList[0] + '_' + KeyList[1] +'_' + KeyList[2]
450 if Key in KeyStringList and KeyList[4] == 'GUID':
451 ToolPathKey = Key + '_' + KeyList[3] + '_PATH'
452 ToolOptionKey = Key + '_' + KeyList[3] + '_FLAGS'
453 if ToolPathKey in BuildOption:
454 ToolPathTmp = BuildOption[ToolPathKey]
455 if ToolOptionKey in BuildOption:
456 ToolOption = BuildOption[ToolOptionKey]
457
458 GenFdsGlobalVariable.GuidToolDefinition[NameGuid] = (ToolPathTmp, ToolOption)
459 return ToolPathTmp, ToolOption
460
461 ## Parse command line options
462 #
463 # Using standard Python module optparse to parse command line option of this tool.
464 #
465 # @retval Opt A optparse.Values object containing the parsed options
466 # @retval Args Target of build command
467 #
468 def myOptionParser():
469 usage = "%prog [options] -f input_file -a arch_list -b build_target -p active_platform -t tool_chain_tag -D \"MacroName [= MacroValue]\""
470 Parser = OptionParser(usage=usage, description=__copyright__, version="%prog " + str(versionNumber))
471 Parser.add_option("-f", "--file", dest="filename", type="string", help="Name of FDF file to convert", action="callback", callback=SingleCheckCallback)
472 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")
473 Parser.add_option("-q", "--quiet", action="store_true", type=None, help="Disable all messages except FATAL ERRORS.")
474 Parser.add_option("-v", "--verbose", action="store_true", type=None, help="Turn on verbose output with informational messages printed.")
475 Parser.add_option("-d", "--debug", action="store", type="int", help="Enable debug messages at specified level.")
476 Parser.add_option("-p", "--platform", type="string", dest="activePlatform", help="Set the ACTIVE_PLATFORM, overrides target.txt ACTIVE_PLATFORM setting.",
477 action="callback", callback=SingleCheckCallback)
478 Parser.add_option("-w", "--workspace", type="string", dest="Workspace", default=os.environ.get('WORKSPACE'), help="Set the WORKSPACE",
479 action="callback", callback=SingleCheckCallback)
480 Parser.add_option("-o", "--outputDir", type="string", dest="outputDir", help="Name of Build Output directory",
481 action="callback", callback=SingleCheckCallback)
482 Parser.add_option("-r", "--rom_image", dest="uiFdName", help="Build the image using the [FD] section named by FdUiName.")
483 Parser.add_option("-i", "--FvImage", dest="uiFvName", help="Build the FV image using the [FV] section named by UiFvName")
484 Parser.add_option("-C", "--CapsuleImage", dest="uiCapName", help="Build the Capsule image using the [Capsule] section named by UiCapName")
485 Parser.add_option("-b", "--buildtarget", type="string", dest="BuildTarget", help="Set the build TARGET, overrides target.txt TARGET setting.",
486 action="callback", callback=SingleCheckCallback)
487 Parser.add_option("-t", "--tagname", type="string", dest="ToolChain", help="Using the tools: TOOL_CHAIN_TAG name to build the platform.",
488 action="callback", callback=SingleCheckCallback)
489 Parser.add_option("-D", "--define", action="append", type="string", dest="Macros", help="Macro: \"Name [= Value]\".")
490 Parser.add_option("-s", "--specifyaddress", dest="FixedAddress", action="store_true", type=None, help="Specify driver load address.")
491 Parser.add_option("--conf", action="store", type="string", dest="ConfDirectory", help="Specify the customized Conf directory.")
492 Parser.add_option("--ignore-sources", action="store_true", dest="IgnoreSources", default=False, help="Focus to a binary build and ignore all source files")
493 Parser.add_option("--pcd", action="append", dest="OptionPcd", help="Set PCD value by command line. Format: \"PcdName=Value\" ")
494 Parser.add_option("--genfds-multi-thread", action="store_true", dest="GenfdsMultiThread", default=False, help="Enable GenFds multi thread to generate ffs file.")
495
496 (Options, args) = Parser.parse_args()
497 return Options
498
499 ## The class implementing the EDK2 flash image generation process
500 #
501 # This process includes:
502 # 1. Collect workspace information, includes platform and module information
503 # 2. Call methods of Fd class to generate FD
504 # 3. Call methods of Fv class to generate FV that not belong to FD
505 #
506 class GenFds :
507 FdfParsef = None
508 # FvName, FdName, CapName in FDF, Image file name
509 ImageBinDict = {}
510 OnlyGenerateThisFd = None
511 OnlyGenerateThisFv = None
512 OnlyGenerateThisCap = None
513
514 ## GenFd()
515 #
516 # @param OutputDir Output directory
517 # @param FdfParser FDF contents parser
518 # @param Workspace The directory of workspace
519 # @param ArchList The Arch list of platform
520 #
521 def GenFd (OutputDir, FdfParser, WorkSpace, ArchList):
522 GenFdsGlobalVariable.SetDir ('', FdfParser, WorkSpace, ArchList)
523
524 GenFdsGlobalVariable.VerboseLogger(" Generate all Fd images and their required FV and Capsule images!")
525 if GenFds.OnlyGenerateThisCap is not None and GenFds.OnlyGenerateThisCap.upper() in GenFdsGlobalVariable.FdfParser.Profile.CapsuleDict:
526 CapsuleObj = GenFdsGlobalVariable.FdfParser.Profile.CapsuleDict[GenFds.OnlyGenerateThisCap.upper()]
527 if CapsuleObj is not None:
528 CapsuleObj.GenCapsule()
529 return
530
531 if GenFds.OnlyGenerateThisFd is not None and GenFds.OnlyGenerateThisFd.upper() in GenFdsGlobalVariable.FdfParser.Profile.FdDict:
532 FdObj = GenFdsGlobalVariable.FdfParser.Profile.FdDict[GenFds.OnlyGenerateThisFd.upper()]
533 if FdObj is not None:
534 FdObj.GenFd()
535 return
536 elif GenFds.OnlyGenerateThisFd is None and GenFds.OnlyGenerateThisFv is None:
537 for FdObj in GenFdsGlobalVariable.FdfParser.Profile.FdDict.values():
538 FdObj.GenFd()
539
540 GenFdsGlobalVariable.VerboseLogger("\n Generate other FV images! ")
541 if GenFds.OnlyGenerateThisFv is not None and GenFds.OnlyGenerateThisFv.upper() in GenFdsGlobalVariable.FdfParser.Profile.FvDict:
542 FvObj = GenFdsGlobalVariable.FdfParser.Profile.FvDict[GenFds.OnlyGenerateThisFv.upper()]
543 if FvObj is not None:
544 Buffer = StringIO.StringIO()
545 FvObj.AddToBuffer(Buffer)
546 Buffer.close()
547 return
548 elif GenFds.OnlyGenerateThisFv is None:
549 for FvObj in GenFdsGlobalVariable.FdfParser.Profile.FvDict.values():
550 Buffer = StringIO.StringIO('')
551 FvObj.AddToBuffer(Buffer)
552 Buffer.close()
553
554 if GenFds.OnlyGenerateThisFv is None and GenFds.OnlyGenerateThisFd is None and GenFds.OnlyGenerateThisCap is None:
555 if GenFdsGlobalVariable.FdfParser.Profile.CapsuleDict != {}:
556 GenFdsGlobalVariable.VerboseLogger("\n Generate other Capsule images!")
557 for CapsuleObj in GenFdsGlobalVariable.FdfParser.Profile.CapsuleDict.values():
558 CapsuleObj.GenCapsule()
559
560 if GenFdsGlobalVariable.FdfParser.Profile.OptRomDict != {}:
561 GenFdsGlobalVariable.VerboseLogger("\n Generate all Option ROM!")
562 for OptRomObj in GenFdsGlobalVariable.FdfParser.Profile.OptRomDict.values():
563 OptRomObj.AddToBuffer(None)
564 @staticmethod
565 def GenFfsMakefile(OutputDir, FdfParser, WorkSpace, ArchList, GlobalData):
566 GenFdsGlobalVariable.SetEnv(FdfParser, WorkSpace, ArchList, GlobalData)
567 for FdObj in GenFdsGlobalVariable.FdfParser.Profile.FdDict.values():
568 FdObj.GenFd(Flag=True)
569
570 for FvObj in GenFdsGlobalVariable.FdfParser.Profile.FvDict.values():
571 FvObj.AddToBuffer(Buffer=None, Flag=True)
572
573 if GenFdsGlobalVariable.FdfParser.Profile.OptRomDict != {}:
574 for OptRomObj in GenFdsGlobalVariable.FdfParser.Profile.OptRomDict.values():
575 OptRomObj.AddToBuffer(Buffer=None, Flag=True)
576
577 return GenFdsGlobalVariable.FfsCmdDict
578
579 ## GetFvBlockSize()
580 #
581 # @param FvObj Whose block size to get
582 # @retval int Block size value
583 #
584 def GetFvBlockSize(FvObj):
585 DefaultBlockSize = 0x1
586 FdObj = None
587 if GenFds.OnlyGenerateThisFd is not None and GenFds.OnlyGenerateThisFd.upper() in GenFdsGlobalVariable.FdfParser.Profile.FdDict:
588 FdObj = GenFdsGlobalVariable.FdfParser.Profile.FdDict[GenFds.OnlyGenerateThisFd.upper()]
589 if FdObj is None:
590 for ElementFd in GenFdsGlobalVariable.FdfParser.Profile.FdDict.values():
591 for ElementRegion in ElementFd.RegionList:
592 if ElementRegion.RegionType == '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]
597 else:
598 return ElementRegion.BlockSizeOfRegion(ElementFd.BlockSizeList)
599 if FvObj.BlockSizeList != []:
600 return FvObj.BlockSizeList[0][0]
601 return DefaultBlockSize
602 else:
603 for ElementRegion in FdObj.RegionList:
604 if ElementRegion.RegionType == 'FV':
605 for ElementRegionData in ElementRegion.RegionDataList:
606 if ElementRegionData is not None and ElementRegionData.upper() == FvObj.UiFvName:
607 if FvObj.BlockSizeList != []:
608 return FvObj.BlockSizeList[0][0]
609 else:
610 return ElementRegion.BlockSizeOfRegion(ElementFd.BlockSizeList)
611 return DefaultBlockSize
612
613 ## DisplayFvSpaceInfo()
614 #
615 # @param FvObj Whose block size to get
616 # @retval None
617 #
618 def DisplayFvSpaceInfo(FdfParser):
619
620 FvSpaceInfoList = []
621 MaxFvNameLength = 0
622 for FvName in FdfParser.Profile.FvDict:
623 if len(FvName) > MaxFvNameLength:
624 MaxFvNameLength = len(FvName)
625 FvSpaceInfoFileName = os.path.join(GenFdsGlobalVariable.FvDir, FvName.upper() + '.Fv.map')
626 if os.path.exists(FvSpaceInfoFileName):
627 FileLinesList = linecache.getlines(FvSpaceInfoFileName)
628 TotalFound = False
629 Total = ''
630 UsedFound = False
631 Used = ''
632 FreeFound = False
633 Free = ''
634 for Line in FileLinesList:
635 NameValue = Line.split('=')
636 if len(NameValue) == 2:
637 if NameValue[0].strip() == 'EFI_FV_TOTAL_SIZE':
638 TotalFound = True
639 Total = NameValue[1].strip()
640 if NameValue[0].strip() == 'EFI_FV_TAKEN_SIZE':
641 UsedFound = True
642 Used = NameValue[1].strip()
643 if NameValue[0].strip() == 'EFI_FV_SPACE_SIZE':
644 FreeFound = True
645 Free = NameValue[1].strip()
646
647 if TotalFound and UsedFound and FreeFound:
648 FvSpaceInfoList.append((FvName, Total, Used, Free))
649
650 GenFdsGlobalVariable.InfLogger('\nFV Space Information')
651 for FvSpaceInfo in FvSpaceInfoList:
652 Name = FvSpaceInfo[0]
653 TotalSizeValue = long(FvSpaceInfo[1], 0)
654 UsedSizeValue = long(FvSpaceInfo[2], 0)
655 FreeSizeValue = long(FvSpaceInfo[3], 0)
656 if UsedSizeValue == TotalSizeValue:
657 Percentage = '100'
658 else:
659 Percentage = str((UsedSizeValue + 0.0) / TotalSizeValue)[0:4].lstrip('0.')
660
661 GenFdsGlobalVariable.InfLogger(Name + ' ' + '[' + Percentage + '%Full] ' + str(TotalSizeValue) + ' total, ' + str(UsedSizeValue) + ' used, ' + str(FreeSizeValue) + ' free')
662
663 ## PreprocessImage()
664 #
665 # @param BuildDb Database from build meta data files
666 # @param DscFile modules from dsc file will be preprocessed
667 # @retval None
668 #
669 def PreprocessImage(BuildDb, DscFile):
670 PcdDict = BuildDb.BuildObject[DscFile, TAB_COMMON, GenFdsGlobalVariable.TargetName, GenFdsGlobalVariable.ToolChainTag].Pcds
671 PcdValue = ''
672 for Key in PcdDict:
673 PcdObj = PcdDict[Key]
674 if PcdObj.TokenCName == 'PcdBsBaseAddress':
675 PcdValue = PcdObj.DefaultValue
676 break
677
678 if PcdValue == '':
679 return
680
681 Int64PcdValue = long(PcdValue, 0)
682 if Int64PcdValue == 0 or Int64PcdValue < -1:
683 return
684
685 TopAddress = 0
686 if Int64PcdValue > 0:
687 TopAddress = Int64PcdValue
688
689 ModuleDict = BuildDb.BuildObject[DscFile, TAB_COMMON, GenFdsGlobalVariable.TargetName, GenFdsGlobalVariable.ToolChainTag].Modules
690 for Key in ModuleDict:
691 ModuleObj = BuildDb.BuildObject[Key, TAB_COMMON, GenFdsGlobalVariable.TargetName, GenFdsGlobalVariable.ToolChainTag]
692 print ModuleObj.BaseName + ' ' + ModuleObj.ModuleType
693
694 def GenerateGuidXRefFile(BuildDb, ArchList, FdfParserObj):
695 GuidXRefFileName = os.path.join(GenFdsGlobalVariable.FvDir, "Guid.xref")
696 GuidXRefFile = StringIO.StringIO('')
697 GuidDict = {}
698 ModuleList = []
699 FileGuidList = []
700 for Arch in ArchList:
701 PlatformDataBase = BuildDb.BuildObject[GenFdsGlobalVariable.ActivePlatform, Arch, GenFdsGlobalVariable.TargetName, GenFdsGlobalVariable.ToolChainTag]
702 for ModuleFile in PlatformDataBase.Modules:
703 Module = BuildDb.BuildObject[ModuleFile, Arch, GenFdsGlobalVariable.TargetName, GenFdsGlobalVariable.ToolChainTag]
704 if Module in ModuleList:
705 continue
706 else:
707 ModuleList.append(Module)
708 GuidXRefFile.write("%s %s\n" % (Module.Guid, Module.BaseName))
709 for key, item in Module.Protocols.items():
710 GuidDict[key] = item
711 for key, item in Module.Guids.items():
712 GuidDict[key] = item
713 for key, item in Module.Ppis.items():
714 GuidDict[key] = item
715 for FvName in FdfParserObj.Profile.FvDict:
716 for FfsObj in FdfParserObj.Profile.FvDict[FvName].FfsList:
717 if not isinstance(FfsObj, FfsFileStatement.FileStatement):
718 InfPath = PathClass(NormPath(mws.join(GenFdsGlobalVariable.WorkSpaceDir, FfsObj.InfFileName)))
719 FdfModule = BuildDb.BuildObject[InfPath, Arch, GenFdsGlobalVariable.TargetName, GenFdsGlobalVariable.ToolChainTag]
720 if FdfModule in ModuleList:
721 continue
722 else:
723 ModuleList.append(FdfModule)
724 GuidXRefFile.write("%s %s\n" % (FdfModule.Guid, FdfModule.BaseName))
725 for key, item in FdfModule.Protocols.items():
726 GuidDict[key] = item
727 for key, item in FdfModule.Guids.items():
728 GuidDict[key] = item
729 for key, item in FdfModule.Ppis.items():
730 GuidDict[key] = item
731 else:
732 FileStatementGuid = FfsObj.NameGuid
733 if FileStatementGuid in FileGuidList:
734 continue
735 else:
736 FileGuidList.append(FileStatementGuid)
737 Name = []
738 FfsPath = os.path.join(GenFdsGlobalVariable.FvDir, 'Ffs')
739 FfsPath = glob.glob(os.path.join(FfsPath, FileStatementGuid) + '*')
740 if not FfsPath:
741 continue
742 if not os.path.exists(FfsPath[0]):
743 continue
744 MatchDict = {}
745 ReFileEnds = re.compile('\S+(.ui)$|\S+(fv.sec.txt)$|\S+(.pe32.txt)$|\S+(.te.txt)$|\S+(.pic.txt)$|\S+(.raw.txt)$|\S+(.ffs.txt)$')
746 FileList = os.listdir(FfsPath[0])
747 for File in FileList:
748 Match = ReFileEnds.search(File)
749 if Match:
750 for Index in range(1, 8):
751 if Match.group(Index) and Match.group(Index) in MatchDict:
752 MatchDict[Match.group(Index)].append(File)
753 elif Match.group(Index):
754 MatchDict[Match.group(Index)] = [File]
755 if not MatchDict:
756 continue
757 if '.ui' in MatchDict:
758 for File in MatchDict['.ui']:
759 with open(os.path.join(FfsPath[0], File), 'rb') as F:
760 F.read()
761 length = F.tell()
762 F.seek(4)
763 TmpStr = unpack('%dh' % ((length - 4) / 2), F.read())
764 Name = ''.join([chr(c) for c in TmpStr[:-1]])
765 else:
766 FileList = []
767 if 'fv.sec.txt' in MatchDict:
768 FileList = MatchDict['fv.sec.txt']
769 elif '.pe32.txt' in MatchDict:
770 FileList = MatchDict['.pe32.txt']
771 elif '.te.txt' in MatchDict:
772 FileList = MatchDict['.te.txt']
773 elif '.pic.txt' in MatchDict:
774 FileList = MatchDict['.pic.txt']
775 elif '.raw.txt' in MatchDict:
776 FileList = MatchDict['.raw.txt']
777 elif '.ffs.txt' in MatchDict:
778 FileList = MatchDict['.ffs.txt']
779 else:
780 pass
781 for File in FileList:
782 with open(os.path.join(FfsPath[0], File), 'r') as F:
783 Name.append((F.read().split()[-1]))
784 if not Name:
785 continue
786
787 Name = ' '.join(Name) if type(Name) == type([]) else Name
788 GuidXRefFile.write("%s %s\n" %(FileStatementGuid, Name))
789
790 # Append GUIDs, Protocols, and PPIs to the Xref file
791 GuidXRefFile.write("\n")
792 for key, item in GuidDict.items():
793 GuidXRefFile.write("%s %s\n" % (GuidStructureStringToGuidString(item).upper(), key))
794
795 if GuidXRefFile.getvalue():
796 SaveFileOnChange(GuidXRefFileName, GuidXRefFile.getvalue(), False)
797 GenFdsGlobalVariable.InfLogger("\nGUID cross reference file can be found at %s" % GuidXRefFileName)
798 elif os.path.exists(GuidXRefFileName):
799 os.remove(GuidXRefFileName)
800 GuidXRefFile.close()
801
802 ##Define GenFd as static function
803 GenFd = staticmethod(GenFd)
804 GetFvBlockSize = staticmethod(GetFvBlockSize)
805 DisplayFvSpaceInfo = staticmethod(DisplayFvSpaceInfo)
806 PreprocessImage = staticmethod(PreprocessImage)
807 GenerateGuidXRefFile = staticmethod(GenerateGuidXRefFile)
808
809 if __name__ == '__main__':
810 r = main()
811 ## 0-127 is a safe return range, and 1 is a standard default error
812 if r < 0 or r > 127: r = 1
813 sys.exit(r)
814