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