1## @file
2# Global variables for GenFds
3#
4#  Copyright (c) 2007 - 2018, Intel Corporation. All rights reserved.<BR>
5#
6#  SPDX-License-Identifier: BSD-2-Clause-Patent
7#
8
9##
10# Import Modules
11#
12from __future__ import print_function
13from __future__ import absolute_import
14
15import Common.LongFilePathOs as os
16import sys
17from sys import stdout
18from subprocess import PIPE,Popen
19from struct import Struct
20from array import array
21
22from Common.BuildToolError import COMMAND_FAILURE,GENFDS_ERROR
23from Common import EdkLogger
24from Common.Misc import SaveFileOnChange
25
26from Common.TargetTxtClassObject import TargetTxtDict
27from Common.ToolDefClassObject import ToolDefDict
28from AutoGen.BuildEngine import ToolBuildRule
29import Common.DataType as DataType
30from Common.Misc import PathClass
31from Common.LongFilePathSupport import OpenLongFilePath as open
32from Common.MultipleWorkspace import MultipleWorkspace as mws
33import Common.GlobalData as GlobalData
34
35## Global variables
36#
37#
38class GenFdsGlobalVariable:
39    FvDir = ''
40    OutputDirDict = {}
41    BinDir = ''
42    # will be FvDir + os.sep + 'Ffs'
43    FfsDir = ''
44    FdfParser = None
45    LibDir = ''
46    WorkSpace = None
47    WorkSpaceDir = ''
48    ConfDir = ''
49    OutputDirFromDscDict = {}
50    TargetName = ''
51    ToolChainTag = ''
52    RuleDict = {}
53    ArchList = None
54    ActivePlatform = None
55    FvAddressFileName = ''
56    VerboseMode = False
57    DebugLevel = -1
58    SharpCounter = 0
59    SharpNumberPerLine = 40
60    FdfFile = ''
61    FdfFileTimeStamp = 0
62    FixedLoadAddress = False
63    PlatformName = ''
64
65    BuildRuleFamily = DataType.TAB_COMPILER_MSFT
66    ToolChainFamily = DataType.TAB_COMPILER_MSFT
67    __BuildRuleDatabase = None
68    GuidToolDefinition = {}
69    FfsCmdDict = {}
70    SecCmdList = []
71    CopyList   = []
72    ModuleFile = ''
73    EnableGenfdsMultiThread = True
74
75    #
76    # The list whose element are flags to indicate if large FFS or SECTION files exist in FV.
77    # At the beginning of each generation of FV, false flag is appended to the list,
78    # after the call to GenerateSection returns, check the size of the output file,
79    # if it is greater than 0xFFFFFF, the tail flag in list is set to true,
80    # and EFI_FIRMWARE_FILE_SYSTEM3_GUID is passed to C GenFv.
81    # At the end of generation of FV, pop the flag.
82    # List is used as a stack to handle nested FV generation.
83    #
84    LargeFileInFvFlags = []
85    EFI_FIRMWARE_FILE_SYSTEM3_GUID = '5473C07A-3DCB-4dca-BD6F-1E9689E7349A'
86    LARGE_FILE_SIZE = 0x1000000
87
88    SectionHeader = Struct("3B 1B")
89
90    # FvName, FdName, CapName in FDF, Image file name
91    ImageBinDict = {}
92
93    ## LoadBuildRule
94    #
95    @staticmethod
96    def _LoadBuildRule():
97        if GenFdsGlobalVariable.__BuildRuleDatabase:
98            return GenFdsGlobalVariable.__BuildRuleDatabase
99        BuildRule = ToolBuildRule()
100        GenFdsGlobalVariable.__BuildRuleDatabase = BuildRule.ToolBuildRule
101        TargetObj = TargetTxtDict()
102        ToolDefinitionFile = TargetObj.Target.TargetTxtDictionary[DataType.TAB_TAT_DEFINES_TOOL_CHAIN_CONF]
103        if ToolDefinitionFile == '':
104            ToolDefinitionFile = "Conf/tools_def.txt"
105        if os.path.isfile(ToolDefinitionFile):
106            ToolDefObj = ToolDefDict((os.path.join(os.getenv("WORKSPACE"), "Conf")))
107            ToolDefinition = ToolDefObj.ToolDef.ToolsDefTxtDatabase
108            if DataType.TAB_TOD_DEFINES_BUILDRULEFAMILY in ToolDefinition \
109               and GenFdsGlobalVariable.ToolChainTag in ToolDefinition[DataType.TAB_TOD_DEFINES_BUILDRULEFAMILY] \
110               and ToolDefinition[DataType.TAB_TOD_DEFINES_BUILDRULEFAMILY][GenFdsGlobalVariable.ToolChainTag]:
111                GenFdsGlobalVariable.BuildRuleFamily = ToolDefinition[DataType.TAB_TOD_DEFINES_BUILDRULEFAMILY][GenFdsGlobalVariable.ToolChainTag]
112
113            if DataType.TAB_TOD_DEFINES_FAMILY in ToolDefinition \
114               and GenFdsGlobalVariable.ToolChainTag in ToolDefinition[DataType.TAB_TOD_DEFINES_FAMILY] \
115               and ToolDefinition[DataType.TAB_TOD_DEFINES_FAMILY][GenFdsGlobalVariable.ToolChainTag]:
116                GenFdsGlobalVariable.ToolChainFamily = ToolDefinition[DataType.TAB_TOD_DEFINES_FAMILY][GenFdsGlobalVariable.ToolChainTag]
117        return GenFdsGlobalVariable.__BuildRuleDatabase
118
119    ## GetBuildRules
120    #    @param Inf: object of InfBuildData
121    #    @param Arch: current arch
122    #
123    @staticmethod
124    def GetBuildRules(Inf, Arch):
125        if not Arch:
126            Arch = DataType.TAB_COMMON
127
128        if not Arch in GenFdsGlobalVariable.OutputDirDict:
129            return {}
130
131        BuildRuleDatabase = GenFdsGlobalVariable._LoadBuildRule()
132        if not BuildRuleDatabase:
133            return {}
134
135        PathClassObj = PathClass(Inf.MetaFile.File,
136                                 GenFdsGlobalVariable.WorkSpaceDir)
137        BuildDir = os.path.join(
138            GenFdsGlobalVariable.OutputDirDict[Arch],
139            Arch,
140            PathClassObj.SubDir,
141            PathClassObj.BaseName
142        )
143        BinDir = os.path.join(GenFdsGlobalVariable.OutputDirDict[Arch], Arch)
144        Macro = {
145        "WORKSPACE":GenFdsGlobalVariable.WorkSpaceDir,
146        "MODULE_NAME":Inf.BaseName,
147        "MODULE_GUID":Inf.Guid,
148        "MODULE_VERSION":Inf.Version,
149        "MODULE_TYPE":Inf.ModuleType,
150        "MODULE_FILE":str(PathClassObj),
151        "MODULE_FILE_BASE_NAME":PathClassObj.BaseName,
152        "MODULE_RELATIVE_DIR":PathClassObj.SubDir,
153        "MODULE_DIR":PathClassObj.SubDir,
154        "BASE_NAME":Inf.BaseName,
155        "ARCH":Arch,
156        "TOOLCHAIN":GenFdsGlobalVariable.ToolChainTag,
157        "TOOLCHAIN_TAG":GenFdsGlobalVariable.ToolChainTag,
158        "TOOL_CHAIN_TAG":GenFdsGlobalVariable.ToolChainTag,
159        "TARGET":GenFdsGlobalVariable.TargetName,
160        "BUILD_DIR":GenFdsGlobalVariable.OutputDirDict[Arch],
161        "BIN_DIR":BinDir,
162        "LIB_DIR":BinDir,
163        "MODULE_BUILD_DIR":BuildDir,
164        "OUTPUT_DIR":os.path.join(BuildDir, "OUTPUT"),
165        "DEBUG_DIR":os.path.join(BuildDir, "DEBUG")
166        }
167
168        BuildRules = {}
169        for Type in BuildRuleDatabase.FileTypeList:
170            #first try getting build rule by BuildRuleFamily
171            RuleObject = BuildRuleDatabase[Type, Inf.BuildType, Arch, GenFdsGlobalVariable.BuildRuleFamily]
172            if not RuleObject:
173                # build type is always module type, but ...
174                if Inf.ModuleType != Inf.BuildType:
175                    RuleObject = BuildRuleDatabase[Type, Inf.ModuleType, Arch, GenFdsGlobalVariable.BuildRuleFamily]
176            #second try getting build rule by ToolChainFamily
177            if not RuleObject:
178                RuleObject = BuildRuleDatabase[Type, Inf.BuildType, Arch, GenFdsGlobalVariable.ToolChainFamily]
179                if not RuleObject:
180                    # build type is always module type, but ...
181                    if Inf.ModuleType != Inf.BuildType:
182                        RuleObject = BuildRuleDatabase[Type, Inf.ModuleType, Arch, GenFdsGlobalVariable.ToolChainFamily]
183            if not RuleObject:
184                continue
185            RuleObject = RuleObject.Instantiate(Macro)
186            BuildRules[Type] = RuleObject
187            for Ext in RuleObject.SourceFileExtList:
188                BuildRules[Ext] = RuleObject
189        return BuildRules
190
191    ## GetModuleCodaTargetList
192    #
193    #    @param Inf: object of InfBuildData
194    #    @param Arch: current arch
195    #
196    @staticmethod
197    def GetModuleCodaTargetList(Inf, Arch):
198        BuildRules = GenFdsGlobalVariable.GetBuildRules(Inf, Arch)
199        if not BuildRules:
200            return []
201
202        TargetList = set()
203        FileList = []
204
205        if not Inf.IsBinaryModule:
206            for File in Inf.Sources:
207                if File.TagName in {"", DataType.TAB_STAR, GenFdsGlobalVariable.ToolChainTag} and \
208                    File.ToolChainFamily in {"", DataType.TAB_STAR, GenFdsGlobalVariable.ToolChainFamily}:
209                    FileList.append((File, DataType.TAB_UNKNOWN_FILE))
210
211        for File in Inf.Binaries:
212            if File.Target in {DataType.TAB_COMMON, DataType.TAB_STAR, GenFdsGlobalVariable.TargetName}:
213                FileList.append((File, File.Type))
214
215        for File, FileType in FileList:
216            LastTarget = None
217            RuleChain = []
218            SourceList = [File]
219            Index = 0
220            while Index < len(SourceList):
221                Source = SourceList[Index]
222                Index = Index + 1
223
224                if File.IsBinary and File == Source and Inf.Binaries and File in Inf.Binaries:
225                    # Skip all files that are not binary libraries
226                    if not Inf.LibraryClass:
227                        continue
228                    RuleObject = BuildRules[DataType.TAB_DEFAULT_BINARY_FILE]
229                elif FileType in BuildRules:
230                    RuleObject = BuildRules[FileType]
231                elif Source.Ext in BuildRules:
232                    RuleObject = BuildRules[Source.Ext]
233                else:
234                    # stop at no more rules
235                    if LastTarget:
236                        TargetList.add(str(LastTarget))
237                    break
238
239                FileType = RuleObject.SourceFileType
240
241                # stop at STATIC_LIBRARY for library
242                if Inf.LibraryClass and FileType == DataType.TAB_STATIC_LIBRARY:
243                    if LastTarget:
244                        TargetList.add(str(LastTarget))
245                    break
246
247                Target = RuleObject.Apply(Source)
248                if not Target:
249                    if LastTarget:
250                        TargetList.add(str(LastTarget))
251                    break
252                elif not Target.Outputs:
253                    # Only do build for target with outputs
254                    TargetList.add(str(Target))
255
256                # to avoid cyclic rule
257                if FileType in RuleChain:
258                    break
259
260                RuleChain.append(FileType)
261                SourceList.extend(Target.Outputs)
262                LastTarget = Target
263                FileType = DataType.TAB_UNKNOWN_FILE
264                for Cmd in Target.Commands:
265                    if "$(CP)" == Cmd.split()[0]:
266                        CpTarget = Cmd.split()[2]
267                        TargetList.add(CpTarget)
268
269        return list(TargetList)
270
271    ## SetDir()
272    #
273    #   @param  OutputDir           Output directory
274    #   @param  FdfParser           FDF contents parser
275    #   @param  Workspace           The directory of workspace
276    #   @param  ArchList            The Arch list of platform
277    #
278    @staticmethod
279    def SetDir (OutputDir, FdfParser, WorkSpace, ArchList):
280        GenFdsGlobalVariable.VerboseLogger("GenFdsGlobalVariable.OutputDir:%s" % OutputDir)
281        GenFdsGlobalVariable.FdfParser = FdfParser
282        GenFdsGlobalVariable.WorkSpace = WorkSpace
283        GenFdsGlobalVariable.FvDir = os.path.join(GenFdsGlobalVariable.OutputDirDict[ArchList[0]], DataType.TAB_FV_DIRECTORY)
284        if not os.path.exists(GenFdsGlobalVariable.FvDir):
285            os.makedirs(GenFdsGlobalVariable.FvDir)
286        GenFdsGlobalVariable.FfsDir = os.path.join(GenFdsGlobalVariable.FvDir, 'Ffs')
287        if not os.path.exists(GenFdsGlobalVariable.FfsDir):
288            os.makedirs(GenFdsGlobalVariable.FfsDir)
289
290        #
291        # Create FV Address inf file
292        #
293        GenFdsGlobalVariable.FvAddressFileName = os.path.join(GenFdsGlobalVariable.FfsDir, 'FvAddress.inf')
294        FvAddressFile = open(GenFdsGlobalVariable.FvAddressFileName, 'w')
295        #
296        # Add [Options]
297        #
298        FvAddressFile.writelines("[options]" + DataType.TAB_LINE_BREAK)
299        BsAddress = '0'
300        for Arch in ArchList:
301            if GenFdsGlobalVariable.WorkSpace.BuildObject[GenFdsGlobalVariable.ActivePlatform, Arch, GenFdsGlobalVariable.TargetName, GenFdsGlobalVariable.ToolChainTag].BsBaseAddress:
302                BsAddress = GenFdsGlobalVariable.WorkSpace.BuildObject[GenFdsGlobalVariable.ActivePlatform, Arch, GenFdsGlobalVariable.TargetName, GenFdsGlobalVariable.ToolChainTag].BsBaseAddress
303                break
304
305        FvAddressFile.writelines("EFI_BOOT_DRIVER_BASE_ADDRESS = " + \
306                                       BsAddress + \
307                                       DataType.TAB_LINE_BREAK)
308
309        RtAddress = '0'
310        for Arch in reversed(ArchList):
311            temp = GenFdsGlobalVariable.WorkSpace.BuildObject[GenFdsGlobalVariable.ActivePlatform, Arch, GenFdsGlobalVariable.TargetName, GenFdsGlobalVariable.ToolChainTag].RtBaseAddress
312            if temp:
313                RtAddress = temp
314                break
315
316        FvAddressFile.writelines("EFI_RUNTIME_DRIVER_BASE_ADDRESS = " + \
317                                       RtAddress + \
318                                       DataType.TAB_LINE_BREAK)
319
320        FvAddressFile.close()
321
322    @staticmethod
323    def SetEnv(FdfParser, WorkSpace, ArchList, GlobalData):
324        GenFdsGlobalVariable.ModuleFile = WorkSpace.ModuleFile
325        GenFdsGlobalVariable.FdfParser = FdfParser
326        GenFdsGlobalVariable.WorkSpace = WorkSpace.Db
327        GenFdsGlobalVariable.ArchList = ArchList
328        GenFdsGlobalVariable.ToolChainTag = GlobalData.gGlobalDefines["TOOL_CHAIN_TAG"]
329        GenFdsGlobalVariable.TargetName = GlobalData.gGlobalDefines["TARGET"]
330        GenFdsGlobalVariable.ActivePlatform = GlobalData.gActivePlatform
331        GenFdsGlobalVariable.ConfDir  = GlobalData.gConfDirectory
332        GenFdsGlobalVariable.EnableGenfdsMultiThread = GlobalData.gEnableGenfdsMultiThread
333        for Arch in ArchList:
334            GenFdsGlobalVariable.OutputDirDict[Arch] = os.path.normpath(
335                os.path.join(GlobalData.gWorkspace,
336                             WorkSpace.Db.BuildObject[GenFdsGlobalVariable.ActivePlatform, Arch, GlobalData.gGlobalDefines['TARGET'],
337                             GlobalData.gGlobalDefines['TOOLCHAIN']].OutputDirectory,
338                             GlobalData.gGlobalDefines['TARGET'] +'_' + GlobalData.gGlobalDefines['TOOLCHAIN']))
339            GenFdsGlobalVariable.OutputDirFromDscDict[Arch] = os.path.normpath(
340                             WorkSpace.Db.BuildObject[GenFdsGlobalVariable.ActivePlatform, Arch,
341                             GlobalData.gGlobalDefines['TARGET'], GlobalData.gGlobalDefines['TOOLCHAIN']].OutputDirectory)
342            GenFdsGlobalVariable.PlatformName = WorkSpace.Db.BuildObject[GenFdsGlobalVariable.ActivePlatform, Arch,
343                                                                      GlobalData.gGlobalDefines['TARGET'],
344                                                                      GlobalData.gGlobalDefines['TOOLCHAIN']].PlatformName
345        GenFdsGlobalVariable.FvDir = os.path.join(GenFdsGlobalVariable.OutputDirDict[ArchList[0]], DataType.TAB_FV_DIRECTORY)
346        if not os.path.exists(GenFdsGlobalVariable.FvDir):
347            os.makedirs(GenFdsGlobalVariable.FvDir)
348        GenFdsGlobalVariable.FfsDir = os.path.join(GenFdsGlobalVariable.FvDir, 'Ffs')
349        if not os.path.exists(GenFdsGlobalVariable.FfsDir):
350            os.makedirs(GenFdsGlobalVariable.FfsDir)
351
352        #
353        # Create FV Address inf file
354        #
355        GenFdsGlobalVariable.FvAddressFileName = os.path.join(GenFdsGlobalVariable.FfsDir, 'FvAddress.inf')
356        FvAddressFile = open(GenFdsGlobalVariable.FvAddressFileName, 'w')
357        #
358        # Add [Options]
359        #
360        FvAddressFile.writelines("[options]" + DataType.TAB_LINE_BREAK)
361        BsAddress = '0'
362        for Arch in ArchList:
363            BsAddress = GenFdsGlobalVariable.WorkSpace.BuildObject[GenFdsGlobalVariable.ActivePlatform, Arch,
364                                                                   GlobalData.gGlobalDefines['TARGET'],
365                                                                   GlobalData.gGlobalDefines["TOOL_CHAIN_TAG"]].BsBaseAddress
366            if BsAddress:
367                break
368
369        FvAddressFile.writelines("EFI_BOOT_DRIVER_BASE_ADDRESS = " + \
370                                 BsAddress + \
371                                 DataType.TAB_LINE_BREAK)
372
373        RtAddress = '0'
374        for Arch in reversed(ArchList):
375            temp = GenFdsGlobalVariable.WorkSpace.BuildObject[
376                GenFdsGlobalVariable.ActivePlatform, Arch, GlobalData.gGlobalDefines['TARGET'],
377                GlobalData.gGlobalDefines["TOOL_CHAIN_TAG"]].RtBaseAddress
378            if temp:
379                RtAddress = temp
380                break
381
382        FvAddressFile.writelines("EFI_RUNTIME_DRIVER_BASE_ADDRESS = " + \
383                                 RtAddress + \
384                                 DataType.TAB_LINE_BREAK)
385
386        FvAddressFile.close()
387
388    ## ReplaceWorkspaceMacro()
389    #
390    #   @param  String           String that may contain macro
391    #
392    @staticmethod
393    def ReplaceWorkspaceMacro(String):
394        String = mws.handleWsMacro(String)
395        Str = String.replace('$(WORKSPACE)', GenFdsGlobalVariable.WorkSpaceDir)
396        if os.path.exists(Str):
397            if not os.path.isabs(Str):
398                Str = os.path.abspath(Str)
399        else:
400            Str = mws.join(GenFdsGlobalVariable.WorkSpaceDir, String)
401        return os.path.normpath(Str)
402
403    ## Check if the input files are newer than output files
404    #
405    #   @param  Output          Path of output file
406    #   @param  Input           Path list of input files
407    #
408    #   @retval True            if Output doesn't exist, or any Input is newer
409    #   @retval False           if all Input is older than Output
410    #
411    @staticmethod
412    def NeedsUpdate(Output, Input):
413        if not os.path.exists(Output):
414            return True
415        # always update "Output" if no "Input" given
416        if not Input:
417            return True
418
419        # if fdf file is changed after the 'Output" is generated, update the 'Output'
420        OutputTime = os.path.getmtime(Output)
421        if GenFdsGlobalVariable.FdfFileTimeStamp > OutputTime:
422            return True
423
424        for F in Input:
425            # always update "Output" if any "Input" doesn't exist
426            if not os.path.exists(F):
427                return True
428            # always update "Output" if any "Input" is newer than "Output"
429            if os.path.getmtime(F) > OutputTime:
430                return True
431        return False
432
433    @staticmethod
434    def GenerateSection(Output, Input, Type=None, CompressionType=None, Guid=None,
435                        GuidHdrLen=None, GuidAttr=[], Ui=None, Ver=None, InputAlign=[], BuildNumber=None, DummyFile=None, IsMakefile=False):
436        Cmd = ["GenSec"]
437        if Type:
438            Cmd += ("-s", Type)
439        if CompressionType:
440            Cmd += ("-c", CompressionType)
441        if Guid:
442            Cmd += ("-g", Guid)
443        if DummyFile:
444            Cmd += ("--dummy", DummyFile)
445        if GuidHdrLen:
446            Cmd += ("-l", GuidHdrLen)
447        #Add each guided attribute
448        for Attr in GuidAttr:
449            Cmd += ("-r", Attr)
450        #Section Align is only for dummy section without section type
451        for SecAlign in InputAlign:
452            Cmd += ("--sectionalign", SecAlign)
453
454        CommandFile = Output + '.txt'
455        if Ui:
456            if IsMakefile:
457                if Ui == "$(MODULE_NAME)":
458                    Cmd += ('-n', Ui)
459                else:
460                    Cmd += ("-n", '"' + Ui + '"')
461                Cmd += ("-o", Output)
462                if ' '.join(Cmd).strip() not in GenFdsGlobalVariable.SecCmdList:
463                    GenFdsGlobalVariable.SecCmdList.append(' '.join(Cmd).strip())
464            else:
465                SectionData = array('B', [0, 0, 0, 0])
466                SectionData.fromstring(Ui.encode("utf_16_le"))
467                SectionData.append(0)
468                SectionData.append(0)
469                Len = len(SectionData)
470                GenFdsGlobalVariable.SectionHeader.pack_into(SectionData, 0, Len & 0xff, (Len >> 8) & 0xff, (Len >> 16) & 0xff, 0x15)
471                SaveFileOnChange(Output, SectionData.tostring())
472
473        elif Ver:
474            Cmd += ("-n", Ver)
475            if BuildNumber:
476                Cmd += ("-j", BuildNumber)
477            Cmd += ("-o", Output)
478
479            SaveFileOnChange(CommandFile, ' '.join(Cmd), False)
480            if IsMakefile:
481                if ' '.join(Cmd).strip() not in GenFdsGlobalVariable.SecCmdList:
482                    GenFdsGlobalVariable.SecCmdList.append(' '.join(Cmd).strip())
483            else:
484                if not GenFdsGlobalVariable.NeedsUpdate(Output, list(Input) + [CommandFile]):
485                    return
486                GenFdsGlobalVariable.CallExternalTool(Cmd, "Failed to generate section")
487        else:
488            Cmd += ("-o", Output)
489            Cmd += Input
490
491            SaveFileOnChange(CommandFile, ' '.join(Cmd), False)
492            if IsMakefile:
493                if sys.platform == "win32":
494                    Cmd = ['if', 'exist', Input[0]] + Cmd
495                else:
496                    Cmd = ['-test', '-e', Input[0], "&&"] + Cmd
497                if ' '.join(Cmd).strip() not in GenFdsGlobalVariable.SecCmdList:
498                    GenFdsGlobalVariable.SecCmdList.append(' '.join(Cmd).strip())
499            elif GenFdsGlobalVariable.NeedsUpdate(Output, list(Input) + [CommandFile]):
500                GenFdsGlobalVariable.DebugLogger(EdkLogger.DEBUG_5, "%s needs update because of newer %s" % (Output, Input))
501                GenFdsGlobalVariable.CallExternalTool(Cmd, "Failed to generate section")
502                if (os.path.getsize(Output) >= GenFdsGlobalVariable.LARGE_FILE_SIZE and
503                    GenFdsGlobalVariable.LargeFileInFvFlags):
504                    GenFdsGlobalVariable.LargeFileInFvFlags[-1] = True
505
506    @staticmethod
507    def GetAlignment (AlignString):
508        if not AlignString:
509            return 0
510        if AlignString.endswith('K'):
511            return int (AlignString.rstrip('K')) * 1024
512        if AlignString.endswith('M'):
513            return int (AlignString.rstrip('M')) * 1024 * 1024
514        if AlignString.endswith('G'):
515            return int (AlignString.rstrip('G')) * 1024 * 1024 * 1024
516        return int (AlignString)
517
518    @staticmethod
519    def GenerateFfs(Output, Input, Type, Guid, Fixed=False, CheckSum=False, Align=None,
520                    SectionAlign=None, MakefilePath=None):
521        Cmd = ["GenFfs", "-t", Type, "-g", Guid]
522        mFfsValidAlign = ["0", "8", "16", "128", "512", "1K", "4K", "32K", "64K", "128K", "256K", "512K", "1M", "2M", "4M", "8M", "16M"]
523        if Fixed == True:
524            Cmd.append("-x")
525        if CheckSum:
526            Cmd.append("-s")
527        if Align:
528            if Align not in mFfsValidAlign:
529                Align = GenFdsGlobalVariable.GetAlignment (Align)
530                for index in range(0, len(mFfsValidAlign) - 1):
531                    if ((Align > GenFdsGlobalVariable.GetAlignment(mFfsValidAlign[index])) and (Align <= GenFdsGlobalVariable.GetAlignment(mFfsValidAlign[index + 1]))):
532                        break
533                Align = mFfsValidAlign[index + 1]
534            Cmd += ("-a", Align)
535
536        Cmd += ("-o", Output)
537        for I in range(0, len(Input)):
538            if MakefilePath:
539                Cmd += ("-oi", Input[I])
540            else:
541                Cmd += ("-i", Input[I])
542            if SectionAlign and SectionAlign[I]:
543                Cmd += ("-n", SectionAlign[I])
544
545        CommandFile = Output + '.txt'
546        SaveFileOnChange(CommandFile, ' '.join(Cmd), False)
547
548        GenFdsGlobalVariable.DebugLogger(EdkLogger.DEBUG_5, "%s needs update because of newer %s" % (Output, Input))
549        if MakefilePath:
550            if (tuple(Cmd), tuple(GenFdsGlobalVariable.SecCmdList), tuple(GenFdsGlobalVariable.CopyList)) not in GenFdsGlobalVariable.FfsCmdDict:
551                GenFdsGlobalVariable.FfsCmdDict[tuple(Cmd), tuple(GenFdsGlobalVariable.SecCmdList), tuple(GenFdsGlobalVariable.CopyList)] = MakefilePath
552            GenFdsGlobalVariable.SecCmdList = []
553            GenFdsGlobalVariable.CopyList = []
554        else:
555            if not GenFdsGlobalVariable.NeedsUpdate(Output, list(Input) + [CommandFile]):
556                return
557            GenFdsGlobalVariable.CallExternalTool(Cmd, "Failed to generate FFS")
558
559    @staticmethod
560    def GenerateFirmwareVolume(Output, Input, BaseAddress=None, ForceRebase=None, Capsule=False, Dump=False,
561                               AddressFile=None, MapFile=None, FfsList=[], FileSystemGuid=None):
562        if not GenFdsGlobalVariable.NeedsUpdate(Output, Input+FfsList):
563            return
564        GenFdsGlobalVariable.DebugLogger(EdkLogger.DEBUG_5, "%s needs update because of newer %s" % (Output, Input))
565
566        Cmd = ["GenFv"]
567        if BaseAddress:
568            Cmd += ("-r", BaseAddress)
569
570        if ForceRebase == False:
571            Cmd += ("-F", "FALSE")
572        elif ForceRebase == True:
573            Cmd += ("-F", "TRUE")
574
575        if Capsule:
576            Cmd.append("-c")
577        if Dump:
578            Cmd.append("-p")
579        if AddressFile:
580            Cmd += ("-a", AddressFile)
581        if MapFile:
582            Cmd += ("-m", MapFile)
583        if FileSystemGuid:
584            Cmd += ("-g", FileSystemGuid)
585        Cmd += ("-o", Output)
586        for I in Input:
587            Cmd += ("-i", I)
588
589        GenFdsGlobalVariable.CallExternalTool(Cmd, "Failed to generate FV")
590
591    @staticmethod
592    def GenerateFirmwareImage(Output, Input, Type="efi", SubType=None, Zero=False,
593                              Strip=False, Replace=False, TimeStamp=None, Join=False,
594                              Align=None, Padding=None, Convert=False, IsMakefile=False):
595        if not GenFdsGlobalVariable.NeedsUpdate(Output, Input) and not IsMakefile:
596            return
597        GenFdsGlobalVariable.DebugLogger(EdkLogger.DEBUG_5, "%s needs update because of newer %s" % (Output, Input))
598
599        Cmd = ["GenFw"]
600        if Type.lower() == "te":
601            Cmd.append("-t")
602        if SubType:
603            Cmd += ("-e", SubType)
604        if TimeStamp:
605            Cmd += ("-s", TimeStamp)
606        if Align:
607            Cmd += ("-a", Align)
608        if Padding:
609            Cmd += ("-p", Padding)
610        if Zero:
611            Cmd.append("-z")
612        if Strip:
613            Cmd.append("-l")
614        if Replace:
615            Cmd.append("-r")
616        if Join:
617            Cmd.append("-j")
618        if Convert:
619            Cmd.append("-m")
620        Cmd += ("-o", Output)
621        Cmd += Input
622        if IsMakefile:
623            if " ".join(Cmd).strip() not in GenFdsGlobalVariable.SecCmdList:
624                GenFdsGlobalVariable.SecCmdList.append(" ".join(Cmd).strip())
625        else:
626            GenFdsGlobalVariable.CallExternalTool(Cmd, "Failed to generate firmware image")
627
628    @staticmethod
629    def GenerateOptionRom(Output, EfiInput, BinaryInput, Compress=False, ClassCode=None,
630                        Revision=None, DeviceId=None, VendorId=None, IsMakefile=False):
631        InputList = []
632        Cmd = ["EfiRom"]
633        if EfiInput:
634
635            if Compress:
636                Cmd.append("-ec")
637            else:
638                Cmd.append("-e")
639
640            for EfiFile in EfiInput:
641                Cmd.append(EfiFile)
642                InputList.append (EfiFile)
643
644        if BinaryInput:
645            Cmd.append("-b")
646            for BinFile in BinaryInput:
647                Cmd.append(BinFile)
648                InputList.append (BinFile)
649
650        # Check List
651        if not GenFdsGlobalVariable.NeedsUpdate(Output, InputList) and not IsMakefile:
652            return
653        GenFdsGlobalVariable.DebugLogger(EdkLogger.DEBUG_5, "%s needs update because of newer %s" % (Output, InputList))
654
655        if ClassCode:
656            Cmd += ("-l", ClassCode)
657        if Revision:
658            Cmd += ("-r", Revision)
659        if DeviceId:
660            Cmd += ("-i", DeviceId)
661        if VendorId:
662            Cmd += ("-f", VendorId)
663
664        Cmd += ("-o", Output)
665        if IsMakefile:
666            if " ".join(Cmd).strip() not in GenFdsGlobalVariable.SecCmdList:
667                GenFdsGlobalVariable.SecCmdList.append(" ".join(Cmd).strip())
668        else:
669            GenFdsGlobalVariable.CallExternalTool(Cmd, "Failed to generate option rom")
670
671    @staticmethod
672    def GuidTool(Output, Input, ToolPath, Options='', returnValue=[], IsMakefile=False):
673        if not GenFdsGlobalVariable.NeedsUpdate(Output, Input) and not IsMakefile:
674            return
675        GenFdsGlobalVariable.DebugLogger(EdkLogger.DEBUG_5, "%s needs update because of newer %s" % (Output, Input))
676
677        Cmd = [ToolPath, ]
678        Cmd += Options.split(' ')
679        Cmd += ("-o", Output)
680        Cmd += Input
681        if IsMakefile:
682            if " ".join(Cmd).strip() not in GenFdsGlobalVariable.SecCmdList:
683                GenFdsGlobalVariable.SecCmdList.append(" ".join(Cmd).strip())
684        else:
685            GenFdsGlobalVariable.CallExternalTool(Cmd, "Failed to call " + ToolPath, returnValue)
686
687    @staticmethod
688    def CallExternalTool (cmd, errorMess, returnValue=[]):
689
690        if type(cmd) not in (tuple, list):
691            GenFdsGlobalVariable.ErrorLogger("ToolError!  Invalid parameter type in call to CallExternalTool")
692
693        if GenFdsGlobalVariable.DebugLevel != -1:
694            cmd += ('--debug', str(GenFdsGlobalVariable.DebugLevel))
695            GenFdsGlobalVariable.InfLogger (cmd)
696
697        if GenFdsGlobalVariable.VerboseMode:
698            cmd += ('-v',)
699            GenFdsGlobalVariable.InfLogger (cmd)
700        else:
701            stdout.write ('#')
702            stdout.flush()
703            GenFdsGlobalVariable.SharpCounter = GenFdsGlobalVariable.SharpCounter + 1
704            if GenFdsGlobalVariable.SharpCounter % GenFdsGlobalVariable.SharpNumberPerLine == 0:
705                stdout.write('\n')
706
707        try:
708            PopenObject = Popen(' '.join(cmd), stdout=PIPE, stderr=PIPE, shell=True)
709        except Exception as X:
710            EdkLogger.error("GenFds", COMMAND_FAILURE, ExtraData="%s: %s" % (str(X), cmd[0]))
711        (out, error) = PopenObject.communicate()
712
713        while PopenObject.returncode is None:
714            PopenObject.wait()
715        if returnValue != [] and returnValue[0] != 0:
716            #get command return value
717            returnValue[0] = PopenObject.returncode
718            return
719        if PopenObject.returncode != 0 or GenFdsGlobalVariable.VerboseMode or GenFdsGlobalVariable.DebugLevel != -1:
720            GenFdsGlobalVariable.InfLogger ("Return Value = %d" % PopenObject.returncode)
721            GenFdsGlobalVariable.InfLogger(out.decode(encoding='utf-8', errors='ignore'))
722            GenFdsGlobalVariable.InfLogger(error.decode(encoding='utf-8', errors='ignore'))
723            if PopenObject.returncode != 0:
724                print("###", cmd)
725                EdkLogger.error("GenFds", COMMAND_FAILURE, errorMess)
726
727    @staticmethod
728    def VerboseLogger (msg):
729        EdkLogger.verbose(msg)
730
731    @staticmethod
732    def InfLogger (msg):
733        EdkLogger.info(msg)
734
735    @staticmethod
736    def ErrorLogger (msg, File=None, Line=None, ExtraData=None):
737        EdkLogger.error('GenFds', GENFDS_ERROR, msg, File, Line, ExtraData)
738
739    @staticmethod
740    def DebugLogger (Level, msg):
741        EdkLogger.debug(Level, msg)
742
743    ## MacroExtend()
744    #
745    #   @param  Str           String that may contain macro
746    #   @param  MacroDict     Dictionary that contains macro value pair
747    #
748    @staticmethod
749    def MacroExtend (Str, MacroDict=None, Arch=DataType.TAB_COMMON):
750        if Str is None:
751            return None
752
753        Dict = {'$(WORKSPACE)': GenFdsGlobalVariable.WorkSpaceDir,
754#                '$(OUTPUT_DIRECTORY)': GenFdsGlobalVariable.OutputDirFromDsc,
755                '$(TARGET)': GenFdsGlobalVariable.TargetName,
756                '$(TOOL_CHAIN_TAG)': GenFdsGlobalVariable.ToolChainTag,
757                '$(SPACE)': ' '
758               }
759
760        if Arch != DataType.TAB_COMMON and Arch in GenFdsGlobalVariable.ArchList:
761            OutputDir = GenFdsGlobalVariable.OutputDirFromDscDict[Arch]
762        else:
763            OutputDir = GenFdsGlobalVariable.OutputDirFromDscDict[GenFdsGlobalVariable.ArchList[0]]
764
765        Dict['$(OUTPUT_DIRECTORY)'] = OutputDir
766
767        if MacroDict:
768            Dict.update(MacroDict)
769
770        for key in Dict:
771            if Str.find(key) >= 0:
772                Str = Str.replace (key, Dict[key])
773
774        if Str.find('$(ARCH)') >= 0:
775            if len(GenFdsGlobalVariable.ArchList) == 1:
776                Str = Str.replace('$(ARCH)', GenFdsGlobalVariable.ArchList[0])
777            else:
778                EdkLogger.error("GenFds", GENFDS_ERROR, "No way to determine $(ARCH) for %s" % Str)
779
780        return Str
781
782    ## GetPcdValue()
783    #
784    #   @param  PcdPattern           pattern that labels a PCD.
785    #
786    @staticmethod
787    def GetPcdValue (PcdPattern):
788        if PcdPattern is None:
789            return None
790        if PcdPattern.startswith('PCD('):
791            PcdPair = PcdPattern[4:].rstrip(')').strip().split('.')
792        else:
793            PcdPair = PcdPattern.strip().split('.')
794        TokenSpace = PcdPair[0]
795        TokenCName = PcdPair[1]
796
797        for Arch in GenFdsGlobalVariable.ArchList:
798            Platform = GenFdsGlobalVariable.WorkSpace.BuildObject[GenFdsGlobalVariable.ActivePlatform, Arch, GenFdsGlobalVariable.TargetName, GenFdsGlobalVariable.ToolChainTag]
799            PcdDict = Platform.Pcds
800            for Key in PcdDict:
801                PcdObj = PcdDict[Key]
802                if (PcdObj.TokenCName == TokenCName) and (PcdObj.TokenSpaceGuidCName == TokenSpace):
803                    if PcdObj.Type != DataType.TAB_PCDS_FIXED_AT_BUILD:
804                        EdkLogger.error("GenFds", GENFDS_ERROR, "%s is not FixedAtBuild type." % PcdPattern)
805                    if PcdObj.DatumType != DataType.TAB_VOID:
806                        EdkLogger.error("GenFds", GENFDS_ERROR, "%s is not VOID* datum type." % PcdPattern)
807
808                    return PcdObj.DefaultValue
809
810            for Package in GenFdsGlobalVariable.WorkSpace.GetPackageList(GenFdsGlobalVariable.ActivePlatform,
811                                                                         Arch,
812                                                                         GenFdsGlobalVariable.TargetName,
813                                                                         GenFdsGlobalVariable.ToolChainTag):
814                PcdDict = Package.Pcds
815                for Key in PcdDict:
816                    PcdObj = PcdDict[Key]
817                    if (PcdObj.TokenCName == TokenCName) and (PcdObj.TokenSpaceGuidCName == TokenSpace):
818                        if PcdObj.Type != DataType.TAB_PCDS_FIXED_AT_BUILD:
819                            EdkLogger.error("GenFds", GENFDS_ERROR, "%s is not FixedAtBuild type." % PcdPattern)
820                        if PcdObj.DatumType != DataType.TAB_VOID:
821                            EdkLogger.error("GenFds", GENFDS_ERROR, "%s is not VOID* datum type." % PcdPattern)
822
823                        return PcdObj.DefaultValue
824
825        return ''
826
827## FindExtendTool()
828#
829#  Find location of tools to process data
830#
831#  @param  KeyStringList    Filter for inputs of section generation
832#  @param  CurrentArchList  Arch list
833#  @param  NameGuid         The Guid name
834#
835def FindExtendTool(KeyStringList, CurrentArchList, NameGuid):
836    ToolDefObj = ToolDefDict((os.path.join(os.getenv("WORKSPACE"), "Conf")))
837    ToolDef = ToolDefObj.ToolDef
838    ToolDb = ToolDef.ToolsDefTxtDatabase
839    # if user not specify filter, try to deduce it from global data.
840    if KeyStringList is None or KeyStringList == []:
841        Target = GenFdsGlobalVariable.TargetName
842        ToolChain = GenFdsGlobalVariable.ToolChainTag
843        if ToolChain not in ToolDb['TOOL_CHAIN_TAG']:
844            EdkLogger.error("GenFds", GENFDS_ERROR, "Can not find external tool because tool tag %s is not defined in tools_def.txt!" % ToolChain)
845        KeyStringList = [Target + '_' + ToolChain + '_' + CurrentArchList[0]]
846        for Arch in CurrentArchList:
847            if Target + '_' + ToolChain + '_' + Arch not in KeyStringList:
848                KeyStringList.append(Target + '_' + ToolChain + '_' + Arch)
849
850    if GenFdsGlobalVariable.GuidToolDefinition:
851        if NameGuid in GenFdsGlobalVariable.GuidToolDefinition:
852            return GenFdsGlobalVariable.GuidToolDefinition[NameGuid]
853
854    ToolDefinition = ToolDef.ToolsDefTxtDictionary
855    ToolPathTmp = None
856    ToolOption = None
857    ToolPathKey = None
858    ToolOptionKey = None
859    KeyList = None
860    for tool_def in ToolDefinition.items():
861        if NameGuid.lower() == tool_def[1].lower():
862            KeyList = tool_def[0].split('_')
863            Key = KeyList[0] + \
864                  '_' + \
865                  KeyList[1] + \
866                  '_' + \
867                  KeyList[2]
868            if Key in KeyStringList and KeyList[4] == DataType.TAB_GUID:
869                ToolPathKey   = Key + '_' + KeyList[3] + '_PATH'
870                ToolOptionKey = Key + '_' + KeyList[3] + '_FLAGS'
871                ToolPath = ToolDefinition.get(ToolPathKey)
872                ToolOption = ToolDefinition.get(ToolOptionKey)
873                if ToolPathTmp is None:
874                    ToolPathTmp = ToolPath
875                else:
876                    if ToolPathTmp != ToolPath:
877                        EdkLogger.error("GenFds", GENFDS_ERROR, "Don't know which tool to use, %s or %s ?" % (ToolPathTmp, ToolPath))
878
879    BuildOption = {}
880    for Arch in CurrentArchList:
881        Platform = GenFdsGlobalVariable.WorkSpace.BuildObject[GenFdsGlobalVariable.ActivePlatform, Arch, GenFdsGlobalVariable.TargetName, GenFdsGlobalVariable.ToolChainTag]
882        # key is (ToolChainFamily, ToolChain, CodeBase)
883        for item in Platform.BuildOptions:
884            if '_PATH' in item[1] or '_FLAGS' in item[1] or '_GUID' in item[1]:
885                if not item[0] or (item[0] and GenFdsGlobalVariable.ToolChainFamily== item[0]):
886                    if item[1] not in BuildOption:
887                        BuildOption[item[1]] = Platform.BuildOptions[item]
888        if BuildOption:
889            ToolList = [DataType.TAB_TOD_DEFINES_TARGET, DataType.TAB_TOD_DEFINES_TOOL_CHAIN_TAG, DataType.TAB_TOD_DEFINES_TARGET_ARCH]
890            for Index in range(2, -1, -1):
891                for Key in list(BuildOption.keys()):
892                    List = Key.split('_')
893                    if List[Index] == DataType.TAB_STAR:
894                        for String in ToolDb[ToolList[Index]]:
895                            if String in [Arch, GenFdsGlobalVariable.TargetName, GenFdsGlobalVariable.ToolChainTag]:
896                                List[Index] = String
897                                NewKey = '%s_%s_%s_%s_%s' % tuple(List)
898                                if NewKey not in BuildOption:
899                                    BuildOption[NewKey] = BuildOption[Key]
900                                    continue
901                                del BuildOption[Key]
902                    elif List[Index] not in ToolDb[ToolList[Index]]:
903                        del BuildOption[Key]
904    if BuildOption:
905        if not KeyList:
906            for Op in BuildOption:
907                if NameGuid == BuildOption[Op]:
908                    KeyList = Op.split('_')
909                    Key = KeyList[0] + '_' + KeyList[1] +'_' + KeyList[2]
910                    if Key in KeyStringList and KeyList[4] == DataType.TAB_GUID:
911                        ToolPathKey   = Key + '_' + KeyList[3] + '_PATH'
912                        ToolOptionKey = Key + '_' + KeyList[3] + '_FLAGS'
913        if ToolPathKey in BuildOption:
914            ToolPathTmp = BuildOption[ToolPathKey]
915        if ToolOptionKey in BuildOption:
916            ToolOption = BuildOption[ToolOptionKey]
917
918    GenFdsGlobalVariable.GuidToolDefinition[NameGuid] = (ToolPathTmp, ToolOption)
919    return ToolPathTmp, ToolOption
920