Home | History | Annotate | Download | only in GenFds
      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 #

     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 from Workspace.BuildClassObject import ModuleBuildClassObject
     28 import RuleComplexFile
     29 from EfiSection import EfiSection
     30 import StringIO
     31 import Common.TargetTxtClassObject as TargetTxtClassObject
     32 import Common.ToolDefClassObject as ToolDefClassObject
     33 import Common.DataType
     34 import Common.GlobalData as GlobalData
     35 from Common import EdkLogger
     36 from Common.String import *
     37 from Common.Misc import DirCache, PathClass
     38 from Common.Misc import SaveFileOnChange
     39 from Common.Misc import ClearDuplicatedInf
     40 from Common.Misc import GuidStructureStringToGuidString
     41 from Common.Misc import CheckPcdDatum
     42 from Common.BuildVersion import gBUILD_VERSION
     43 from Common.MultipleWorkspace import MultipleWorkspace as mws
     44 
     45 ## Version and Copyright

     46 versionNumber = "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 #

     59 def 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 (at] 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 
    338 gParamCheck = []
    339 def 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 
    346 def 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 
    392 def 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 #

    426 def 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 #

    483 def 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 #

    520 class 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 
    732 if __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