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