1## @file
2# Global variables for GenFds
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#
18import Common.LongFilePathOs as os
19import sys
20import subprocess
21import struct
22import array
23
24from Common.BuildToolError import *
25from Common import EdkLogger
26from Common.Misc import SaveFileOnChange
27
28from Common.TargetTxtClassObject import TargetTxtClassObject
29from Common.ToolDefClassObject import ToolDefClassObject
30from AutoGen.BuildEngine import BuildRule
31import Common.DataType as DataType
32from Common.Misc import PathClass
33from Common.LongFilePathSupport import OpenLongFilePath as open
34from Common.MultipleWorkspace import MultipleWorkspace as mws
35
36## Global variables
37#
38#
39class GenFdsGlobalVariable:
40    FvDir = ''
41    OutputDirDict = {}
42    BinDir = ''
43    # will be FvDir + os.sep + 'Ffs'
44    FfsDir = ''
45    FdfParser = None
46    LibDir = ''
47    WorkSpace = None
48    WorkSpaceDir = ''
49    ConfDir = ''
50    EdkSourceDir = ''
51    OutputDirFromDscDict = {}
52    TargetName = ''
53    ToolChainTag = ''
54    RuleDict = {}
55    ArchList = None
56    VtfDict = {}
57    ActivePlatform = None
58    FvAddressFileName = ''
59    VerboseMode = False
60    DebugLevel = -1
61    SharpCounter = 0
62    SharpNumberPerLine = 40
63    FdfFile = ''
64    FdfFileTimeStamp = 0
65    FixedLoadAddress = False
66    PlatformName = ''
67
68    BuildRuleFamily = "MSFT"
69    ToolChainFamily = "MSFT"
70    __BuildRuleDatabase = None
71    GuidToolDefinition = {}
72
73    #
74    # The list whose element are flags to indicate if large FFS or SECTION files exist in FV.
75    # At the beginning of each generation of FV, false flag is appended to the list,
76    # after the call to GenerateSection returns, check the size of the output file,
77    # if it is greater than 0xFFFFFF, the tail flag in list is set to true,
78    # and EFI_FIRMWARE_FILE_SYSTEM3_GUID is passed to C GenFv.
79    # At the end of generation of FV, pop the flag.
80    # List is used as a stack to handle nested FV generation.
81    #
82    LargeFileInFvFlags = []
83    EFI_FIRMWARE_FILE_SYSTEM3_GUID = '5473C07A-3DCB-4dca-BD6F-1E9689E7349A'
84    LARGE_FILE_SIZE = 0x1000000
85
86    SectionHeader = struct.Struct("3B 1B")
87
88    ## LoadBuildRule
89    #
90    @staticmethod
91    def __LoadBuildRule():
92        if GenFdsGlobalVariable.__BuildRuleDatabase:
93            return GenFdsGlobalVariable.__BuildRuleDatabase
94        BuildConfigurationFile = os.path.normpath(os.path.join(GenFdsGlobalVariable.ConfDir, "target.txt"))
95        TargetTxt = TargetTxtClassObject()
96        if os.path.isfile(BuildConfigurationFile) == True:
97            TargetTxt.LoadTargetTxtFile(BuildConfigurationFile)
98            if DataType.TAB_TAT_DEFINES_BUILD_RULE_CONF in TargetTxt.TargetTxtDictionary:
99                BuildRuleFile = TargetTxt.TargetTxtDictionary[DataType.TAB_TAT_DEFINES_BUILD_RULE_CONF]
100            if BuildRuleFile in [None, '']:
101                BuildRuleFile = 'Conf/build_rule.txt'
102            GenFdsGlobalVariable.__BuildRuleDatabase = BuildRule(BuildRuleFile)
103            ToolDefinitionFile = TargetTxt.TargetTxtDictionary[DataType.TAB_TAT_DEFINES_TOOL_CHAIN_CONF]
104            if ToolDefinitionFile == '':
105                ToolDefinitionFile = "Conf/tools_def.txt"
106            if os.path.isfile(ToolDefinitionFile):
107                ToolDef = ToolDefClassObject()
108                ToolDef.LoadToolDefFile(ToolDefinitionFile)
109                ToolDefinition = ToolDef.ToolsDefTxtDatabase
110                if DataType.TAB_TOD_DEFINES_BUILDRULEFAMILY in ToolDefinition \
111                   and GenFdsGlobalVariable.ToolChainTag in ToolDefinition[DataType.TAB_TOD_DEFINES_BUILDRULEFAMILY] \
112                   and ToolDefinition[DataType.TAB_TOD_DEFINES_BUILDRULEFAMILY][GenFdsGlobalVariable.ToolChainTag]:
113                    GenFdsGlobalVariable.BuildRuleFamily = ToolDefinition[DataType.TAB_TOD_DEFINES_BUILDRULEFAMILY][GenFdsGlobalVariable.ToolChainTag]
114
115                if DataType.TAB_TOD_DEFINES_FAMILY in ToolDefinition \
116                   and GenFdsGlobalVariable.ToolChainTag in ToolDefinition[DataType.TAB_TOD_DEFINES_FAMILY] \
117                   and ToolDefinition[DataType.TAB_TOD_DEFINES_FAMILY][GenFdsGlobalVariable.ToolChainTag]:
118                    GenFdsGlobalVariable.ToolChainFamily = ToolDefinition[DataType.TAB_TOD_DEFINES_FAMILY][GenFdsGlobalVariable.ToolChainTag]
119        return GenFdsGlobalVariable.__BuildRuleDatabase
120
121    ## GetBuildRules
122    #    @param Inf: object of InfBuildData
123    #    @param Arch: current arch
124    #
125    @staticmethod
126    def GetBuildRules(Inf, Arch):
127        if not Arch:
128            Arch = 'COMMON'
129
130        if not Arch in GenFdsGlobalVariable.OutputDirDict:
131            return {}
132
133        BuildRuleDatabase = GenFdsGlobalVariable.__LoadBuildRule()
134        if not BuildRuleDatabase:
135            return {}
136
137        PathClassObj = PathClass(Inf.MetaFile.File,
138                                 GenFdsGlobalVariable.WorkSpaceDir)
139        Macro = {}
140        Macro["WORKSPACE"             ] = GenFdsGlobalVariable.WorkSpaceDir
141        Macro["MODULE_NAME"           ] = Inf.BaseName
142        Macro["MODULE_GUID"           ] = Inf.Guid
143        Macro["MODULE_VERSION"        ] = Inf.Version
144        Macro["MODULE_TYPE"           ] = Inf.ModuleType
145        Macro["MODULE_FILE"           ] = str(PathClassObj)
146        Macro["MODULE_FILE_BASE_NAME" ] = PathClassObj.BaseName
147        Macro["MODULE_RELATIVE_DIR"   ] = PathClassObj.SubDir
148        Macro["MODULE_DIR"            ] = PathClassObj.SubDir
149
150        Macro["BASE_NAME"             ] = Inf.BaseName
151
152        Macro["ARCH"                  ] = Arch
153        Macro["TOOLCHAIN"             ] = GenFdsGlobalVariable.ToolChainTag
154        Macro["TOOLCHAIN_TAG"         ] = GenFdsGlobalVariable.ToolChainTag
155        Macro["TOOL_CHAIN_TAG"        ] = GenFdsGlobalVariable.ToolChainTag
156        Macro["TARGET"                ] = GenFdsGlobalVariable.TargetName
157
158        Macro["BUILD_DIR"             ] = GenFdsGlobalVariable.OutputDirDict[Arch]
159        Macro["BIN_DIR"               ] = os.path.join(GenFdsGlobalVariable.OutputDirDict[Arch], Arch)
160        Macro["LIB_DIR"               ] = os.path.join(GenFdsGlobalVariable.OutputDirDict[Arch], Arch)
161        BuildDir = os.path.join(
162            GenFdsGlobalVariable.OutputDirDict[Arch],
163            Arch,
164            PathClassObj.SubDir,
165            PathClassObj.BaseName
166        )
167        Macro["MODULE_BUILD_DIR"      ] = BuildDir
168        Macro["OUTPUT_DIR"            ] = os.path.join(BuildDir, "OUTPUT")
169        Macro["DEBUG_DIR"             ] = os.path.join(BuildDir, "DEBUG")
170
171        BuildRules = {}
172        for Type in BuildRuleDatabase.FileTypeList:
173            #first try getting build rule by BuildRuleFamily
174            RuleObject = BuildRuleDatabase[Type, Inf.BuildType, Arch, GenFdsGlobalVariable.BuildRuleFamily]
175            if not RuleObject:
176                # build type is always module type, but ...
177                if Inf.ModuleType != Inf.BuildType:
178                    RuleObject = BuildRuleDatabase[Type, Inf.ModuleType, Arch, GenFdsGlobalVariable.BuildRuleFamily]
179            #second try getting build rule by ToolChainFamily
180            if not RuleObject:
181                RuleObject = BuildRuleDatabase[Type, Inf.BuildType, Arch, GenFdsGlobalVariable.ToolChainFamily]
182                if not RuleObject:
183                    # build type is always module type, but ...
184                    if Inf.ModuleType != Inf.BuildType:
185                        RuleObject = BuildRuleDatabase[Type, Inf.ModuleType, Arch, GenFdsGlobalVariable.ToolChainFamily]
186            if not RuleObject:
187                continue
188            RuleObject = RuleObject.Instantiate(Macro)
189            BuildRules[Type] = RuleObject
190            for Ext in RuleObject.SourceFileExtList:
191                BuildRules[Ext] = RuleObject
192        return BuildRules
193
194    ## GetModuleCodaTargetList
195    #
196    #    @param Inf: object of InfBuildData
197    #    @param Arch: current arch
198    #
199    @staticmethod
200    def GetModuleCodaTargetList(Inf, Arch):
201        BuildRules = GenFdsGlobalVariable.GetBuildRules(Inf, Arch)
202        if not BuildRules:
203            return []
204
205        TargetList = set()
206        FileList = []
207
208        if not Inf.IsBinaryModule:
209            for File in Inf.Sources:
210                if File.TagName in ("", "*", GenFdsGlobalVariable.ToolChainTag) and \
211                    File.ToolChainFamily in ("", "*", GenFdsGlobalVariable.ToolChainFamily):
212                    FileList.append((File, DataType.TAB_UNKNOWN_FILE))
213
214        for File in Inf.Binaries:
215            if File.Target in ['COMMON', '*', GenFdsGlobalVariable.TargetName]:
216                FileList.append((File, File.Type))
217
218        for File, FileType in FileList:
219            LastTarget = None
220            RuleChain = []
221            SourceList = [File]
222            Index = 0
223            while Index < len(SourceList):
224                Source = SourceList[Index]
225                Index = Index + 1
226
227                if File.IsBinary and File == Source and Inf.Binaries != None and File in Inf.Binaries:
228                    # Skip all files that are not binary libraries
229                    if not Inf.LibraryClass:
230                        continue
231                    RuleObject = BuildRules[DataType.TAB_DEFAULT_BINARY_FILE]
232                elif FileType in BuildRules:
233                    RuleObject = BuildRules[FileType]
234                elif Source.Ext in BuildRules:
235                    RuleObject = BuildRules[Source.Ext]
236                else:
237                    # stop at no more rules
238                    if LastTarget:
239                        TargetList.add(str(LastTarget))
240                    break
241
242                FileType = RuleObject.SourceFileType
243
244                # stop at STATIC_LIBRARY for library
245                if Inf.LibraryClass and FileType == DataType.TAB_STATIC_LIBRARY:
246                    if LastTarget:
247                        TargetList.add(str(LastTarget))
248                    break
249
250                Target = RuleObject.Apply(Source)
251                if not Target:
252                    if LastTarget:
253                        TargetList.add(str(LastTarget))
254                    break
255                elif not Target.Outputs:
256                    # Only do build for target with outputs
257                    TargetList.add(str(Target))
258
259                # to avoid cyclic rule
260                if FileType in RuleChain:
261                    break
262
263                RuleChain.append(FileType)
264                SourceList.extend(Target.Outputs)
265                LastTarget = Target
266                FileType = DataType.TAB_UNKNOWN_FILE
267
268        return list(TargetList)
269
270    ## SetDir()
271    #
272    #   @param  OutputDir           Output directory
273    #   @param  FdfParser           FDF contents parser
274    #   @param  Workspace           The directory of workspace
275    #   @param  ArchList            The Arch list of platform
276    #
277    def SetDir (OutputDir, FdfParser, WorkSpace, ArchList):
278        GenFdsGlobalVariable.VerboseLogger("GenFdsGlobalVariable.OutputDir :%s" % OutputDir)
279#        GenFdsGlobalVariable.OutputDirDict = OutputDir
280        GenFdsGlobalVariable.FdfParser = FdfParser
281        GenFdsGlobalVariable.WorkSpace = WorkSpace
282        GenFdsGlobalVariable.FvDir = os.path.join(GenFdsGlobalVariable.OutputDirDict[ArchList[0]], 'FV')
283        if not os.path.exists(GenFdsGlobalVariable.FvDir) :
284            os.makedirs(GenFdsGlobalVariable.FvDir)
285        GenFdsGlobalVariable.FfsDir = os.path.join(GenFdsGlobalVariable.FvDir, 'Ffs')
286        if not os.path.exists(GenFdsGlobalVariable.FfsDir) :
287            os.makedirs(GenFdsGlobalVariable.FfsDir)
288
289        T_CHAR_LF = '\n'
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]" + T_CHAR_LF)
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                                       T_CHAR_LF)
308
309        RtAddress = '0'
310        for Arch in ArchList:
311            if GenFdsGlobalVariable.WorkSpace.BuildObject[GenFdsGlobalVariable.ActivePlatform, Arch, GenFdsGlobalVariable.TargetName, GenFdsGlobalVariable.ToolChainTag].RtBaseAddress:
312                RtAddress = GenFdsGlobalVariable.WorkSpace.BuildObject[GenFdsGlobalVariable.ActivePlatform, Arch, GenFdsGlobalVariable.TargetName, GenFdsGlobalVariable.ToolChainTag].RtBaseAddress
313
314        FvAddressFile.writelines("EFI_RUNTIME_DRIVER_BASE_ADDRESS = " + \
315                                       RtAddress + \
316                                       T_CHAR_LF)
317
318        FvAddressFile.close()
319
320    ## ReplaceWorkspaceMacro()
321    #
322    #   @param  String           String that may contain macro
323    #
324    def ReplaceWorkspaceMacro(String):
325        String = mws.handleWsMacro(String)
326        Str = String.replace('$(WORKSPACE)', GenFdsGlobalVariable.WorkSpaceDir)
327        if os.path.exists(Str):
328            if not os.path.isabs(Str):
329                Str = os.path.abspath(Str)
330        else:
331            Str = mws.join(GenFdsGlobalVariable.WorkSpaceDir, String)
332        return os.path.normpath(Str)
333
334    ## Check if the input files are newer than output files
335    #
336    #   @param  Output          Path of output file
337    #   @param  Input           Path list of input files
338    #
339    #   @retval True            if Output doesn't exist, or any Input is newer
340    #   @retval False           if all Input is older than Output
341    #
342    @staticmethod
343    def NeedsUpdate(Output, Input):
344        if not os.path.exists(Output):
345            return True
346        # always update "Output" if no "Input" given
347        if Input == None or len(Input) == 0:
348            return True
349
350        # if fdf file is changed after the 'Output" is generated, update the 'Output'
351        OutputTime = os.path.getmtime(Output)
352        if GenFdsGlobalVariable.FdfFileTimeStamp > OutputTime:
353            return True
354
355        for F in Input:
356            # always update "Output" if any "Input" doesn't exist
357            if not os.path.exists(F):
358                return True
359            # always update "Output" if any "Input" is newer than "Output"
360            if os.path.getmtime(F) > OutputTime:
361                return True
362        return False
363
364    @staticmethod
365    def GenerateSection(Output, Input, Type=None, CompressionType=None, Guid=None,
366                        GuidHdrLen=None, GuidAttr=[], Ui=None, Ver=None, InputAlign=None, BuildNumber=None):
367        Cmd = ["GenSec"]
368        if Type not in [None, '']:
369            Cmd += ["-s", Type]
370        if CompressionType not in [None, '']:
371            Cmd += ["-c", CompressionType]
372        if Guid != None:
373            Cmd += ["-g", Guid]
374        if GuidHdrLen not in [None, '']:
375            Cmd += ["-l", GuidHdrLen]
376        if len(GuidAttr) != 0:
377            #Add each guided attribute
378            for Attr in GuidAttr:
379                Cmd += ["-r", Attr]
380        if InputAlign != None:
381            #Section Align is only for dummy section without section type
382            for SecAlign in InputAlign:
383                Cmd += ["--sectionalign", SecAlign]
384
385        CommandFile = Output + '.txt'
386        if Ui not in [None, '']:
387            #Cmd += ["-n", '"' + Ui + '"']
388            SectionData = array.array('B', [0, 0, 0, 0])
389            SectionData.fromstring(Ui.encode("utf_16_le"))
390            SectionData.append(0)
391            SectionData.append(0)
392            Len = len(SectionData)
393            GenFdsGlobalVariable.SectionHeader.pack_into(SectionData, 0, Len & 0xff, (Len >> 8) & 0xff, (Len >> 16) & 0xff, 0x15)
394            SaveFileOnChange(Output, SectionData.tostring())
395        elif Ver not in [None, '']:
396            Cmd += ["-n", Ver]
397            if BuildNumber:
398                Cmd += ["-j", BuildNumber]
399            Cmd += ["-o", Output]
400
401            SaveFileOnChange(CommandFile, ' '.join(Cmd), False)
402            if not GenFdsGlobalVariable.NeedsUpdate(Output, list(Input) + [CommandFile]):
403                return
404
405            GenFdsGlobalVariable.CallExternalTool(Cmd, "Failed to generate section")
406        else:
407            Cmd += ["-o", Output]
408            Cmd += Input
409
410            SaveFileOnChange(CommandFile, ' '.join(Cmd), False)
411            if GenFdsGlobalVariable.NeedsUpdate(Output, list(Input) + [CommandFile]):
412                GenFdsGlobalVariable.DebugLogger(EdkLogger.DEBUG_5, "%s needs update because of newer %s" % (Output, Input))
413                GenFdsGlobalVariable.CallExternalTool(Cmd, "Failed to generate section")
414
415            if (os.path.getsize(Output) >= GenFdsGlobalVariable.LARGE_FILE_SIZE and
416                GenFdsGlobalVariable.LargeFileInFvFlags):
417                GenFdsGlobalVariable.LargeFileInFvFlags[-1] = True
418
419    @staticmethod
420    def GetAlignment (AlignString):
421        if AlignString == None:
422            return 0
423        if AlignString in ("1K", "2K", "4K", "8K", "16K", "32K", "64K"):
424            return int (AlignString.rstrip('K')) * 1024
425        else:
426            return int (AlignString)
427
428    @staticmethod
429    def GenerateFfs(Output, Input, Type, Guid, Fixed=False, CheckSum=False, Align=None,
430                    SectionAlign=None):
431        Cmd = ["GenFfs", "-t", Type, "-g", Guid]
432        mFfsValidAlign = ["0", "8", "16", "128", "512", "1K", "4K", "32K", "64K"]
433        if Fixed == True:
434            Cmd += ["-x"]
435        if CheckSum:
436            Cmd += ["-s"]
437        if Align not in [None, '']:
438            if Align not in mFfsValidAlign:
439                Align = GenFdsGlobalVariable.GetAlignment (Align)
440                for index in range(0, len(mFfsValidAlign) - 1):
441                    if ((Align > GenFdsGlobalVariable.GetAlignment(mFfsValidAlign[index])) and (Align <= GenFdsGlobalVariable.GetAlignment(mFfsValidAlign[index + 1]))):
442                        break
443                Align = mFfsValidAlign[index + 1]
444            Cmd += ["-a", Align]
445
446        Cmd += ["-o", Output]
447        for I in range(0, len(Input)):
448            Cmd += ("-i", Input[I])
449            if SectionAlign not in [None, '', []] and SectionAlign[I] not in [None, '']:
450                Cmd += ("-n", SectionAlign[I])
451
452        CommandFile = Output + '.txt'
453        SaveFileOnChange(CommandFile, ' '.join(Cmd), False)
454        if not GenFdsGlobalVariable.NeedsUpdate(Output, list(Input) + [CommandFile]):
455            return
456        GenFdsGlobalVariable.DebugLogger(EdkLogger.DEBUG_5, "%s needs update because of newer %s" % (Output, Input))
457
458        GenFdsGlobalVariable.CallExternalTool(Cmd, "Failed to generate FFS")
459
460    @staticmethod
461    def GenerateFirmwareVolume(Output, Input, BaseAddress=None, ForceRebase=None, Capsule=False, Dump=False,
462                               AddressFile=None, MapFile=None, FfsList=[], FileSystemGuid=None):
463        if not GenFdsGlobalVariable.NeedsUpdate(Output, Input+FfsList):
464            return
465        GenFdsGlobalVariable.DebugLogger(EdkLogger.DEBUG_5, "%s needs update because of newer %s" % (Output, Input))
466
467        Cmd = ["GenFv"]
468        if BaseAddress not in [None, '']:
469            Cmd += ["-r", BaseAddress]
470
471        if ForceRebase == False:
472            Cmd += ["-F", "FALSE"]
473        elif ForceRebase == True:
474            Cmd += ["-F", "TRUE"]
475
476        if Capsule:
477            Cmd += ["-c"]
478        if Dump:
479            Cmd += ["-p"]
480        if AddressFile not in [None, '']:
481            Cmd += ["-a", AddressFile]
482        if MapFile not in [None, '']:
483            Cmd += ["-m", MapFile]
484        if FileSystemGuid:
485            Cmd += ["-g", FileSystemGuid]
486        Cmd += ["-o", Output]
487        for I in Input:
488            Cmd += ["-i", I]
489
490        GenFdsGlobalVariable.CallExternalTool(Cmd, "Failed to generate FV")
491
492    @staticmethod
493    def GenerateVtf(Output, Input, BaseAddress=None, FvSize=None):
494        if not GenFdsGlobalVariable.NeedsUpdate(Output, Input):
495            return
496        GenFdsGlobalVariable.DebugLogger(EdkLogger.DEBUG_5, "%s needs update because of newer %s" % (Output, Input))
497
498        Cmd = ["GenVtf"]
499        if BaseAddress not in [None, ''] and FvSize not in [None, ''] \
500            and len(BaseAddress) == len(FvSize):
501            for I in range(0, len(BaseAddress)):
502                Cmd += ["-r", BaseAddress[I], "-s", FvSize[I]]
503        Cmd += ["-o", Output]
504        for F in Input:
505            Cmd += ["-f", F]
506
507        GenFdsGlobalVariable.CallExternalTool(Cmd, "Failed to generate VTF")
508
509    @staticmethod
510    def GenerateFirmwareImage(Output, Input, Type="efi", SubType=None, Zero=False,
511                              Strip=False, Replace=False, TimeStamp=None, Join=False,
512                              Align=None, Padding=None, Convert=False):
513        if not GenFdsGlobalVariable.NeedsUpdate(Output, Input):
514            return
515        GenFdsGlobalVariable.DebugLogger(EdkLogger.DEBUG_5, "%s needs update because of newer %s" % (Output, Input))
516
517        Cmd = ["GenFw"]
518        if Type.lower() == "te":
519            Cmd += ["-t"]
520        if SubType not in [None, '']:
521            Cmd += ["-e", SubType]
522        if TimeStamp not in [None, '']:
523            Cmd += ["-s", TimeStamp]
524        if Align not in [None, '']:
525            Cmd += ["-a", Align]
526        if Padding not in [None, '']:
527            Cmd += ["-p", Padding]
528        if Zero:
529            Cmd += ["-z"]
530        if Strip:
531            Cmd += ["-l"]
532        if Replace:
533            Cmd += ["-r"]
534        if Join:
535            Cmd += ["-j"]
536        if Convert:
537            Cmd += ["-m"]
538        Cmd += ["-o", Output]
539        Cmd += Input
540
541        GenFdsGlobalVariable.CallExternalTool(Cmd, "Failed to generate firmware image")
542
543    @staticmethod
544    def GenerateOptionRom(Output, EfiInput, BinaryInput, Compress=False, ClassCode=None,
545                        Revision=None, DeviceId=None, VendorId=None):
546        InputList = []
547        Cmd = ["EfiRom"]
548        if len(EfiInput) > 0:
549
550            if Compress:
551                Cmd += ["-ec"]
552            else:
553                Cmd += ["-e"]
554
555            for EfiFile in EfiInput:
556                Cmd += [EfiFile]
557                InputList.append (EfiFile)
558
559        if len(BinaryInput) > 0:
560            Cmd += ["-b"]
561            for BinFile in BinaryInput:
562                Cmd += [BinFile]
563                InputList.append (BinFile)
564
565        # Check List
566        if not GenFdsGlobalVariable.NeedsUpdate(Output, InputList):
567            return
568        GenFdsGlobalVariable.DebugLogger(EdkLogger.DEBUG_5, "%s needs update because of newer %s" % (Output, InputList))
569
570        if ClassCode != None:
571            Cmd += ["-l", ClassCode]
572        if Revision != None:
573            Cmd += ["-r", Revision]
574        if DeviceId != None:
575            Cmd += ["-i", DeviceId]
576        if VendorId != None:
577            Cmd += ["-f", VendorId]
578
579        Cmd += ["-o", Output]
580        GenFdsGlobalVariable.CallExternalTool(Cmd, "Failed to generate option rom")
581
582    @staticmethod
583    def GuidTool(Output, Input, ToolPath, Options='', returnValue=[]):
584        if not GenFdsGlobalVariable.NeedsUpdate(Output, Input):
585            return
586        GenFdsGlobalVariable.DebugLogger(EdkLogger.DEBUG_5, "%s needs update because of newer %s" % (Output, Input))
587
588        Cmd = [ToolPath, ]
589        Cmd += Options.split(' ')
590        Cmd += ["-o", Output]
591        Cmd += Input
592
593        GenFdsGlobalVariable.CallExternalTool(Cmd, "Failed to call " + ToolPath, returnValue)
594
595    def CallExternalTool (cmd, errorMess, returnValue=[]):
596
597        if type(cmd) not in (tuple, list):
598            GenFdsGlobalVariable.ErrorLogger("ToolError!  Invalid parameter type in call to CallExternalTool")
599
600        if GenFdsGlobalVariable.DebugLevel != -1:
601            cmd += ('--debug', str(GenFdsGlobalVariable.DebugLevel))
602            GenFdsGlobalVariable.InfLogger (cmd)
603
604        if GenFdsGlobalVariable.VerboseMode:
605            cmd += ('-v',)
606            GenFdsGlobalVariable.InfLogger (cmd)
607        else:
608            sys.stdout.write ('#')
609            sys.stdout.flush()
610            GenFdsGlobalVariable.SharpCounter = GenFdsGlobalVariable.SharpCounter + 1
611            if GenFdsGlobalVariable.SharpCounter % GenFdsGlobalVariable.SharpNumberPerLine == 0:
612                sys.stdout.write('\n')
613
614        try:
615            PopenObject = subprocess.Popen(' '.join(cmd), stdout=subprocess.PIPE, stderr=subprocess.PIPE, shell=True)
616        except Exception, X:
617            EdkLogger.error("GenFds", COMMAND_FAILURE, ExtraData="%s: %s" % (str(X), cmd[0]))
618        (out, error) = PopenObject.communicate()
619
620        while PopenObject.returncode == None :
621            PopenObject.wait()
622        if returnValue != [] and returnValue[0] != 0:
623            #get command return value
624            returnValue[0] = PopenObject.returncode
625            return
626        if PopenObject.returncode != 0 or GenFdsGlobalVariable.VerboseMode or GenFdsGlobalVariable.DebugLevel != -1:
627            GenFdsGlobalVariable.InfLogger ("Return Value = %d" % PopenObject.returncode)
628            GenFdsGlobalVariable.InfLogger (out)
629            GenFdsGlobalVariable.InfLogger (error)
630            if PopenObject.returncode != 0:
631                print "###", cmd
632                EdkLogger.error("GenFds", COMMAND_FAILURE, errorMess)
633
634    def VerboseLogger (msg):
635        EdkLogger.verbose(msg)
636
637    def InfLogger (msg):
638        EdkLogger.info(msg)
639
640    def ErrorLogger (msg, File=None, Line=None, ExtraData=None):
641        EdkLogger.error('GenFds', GENFDS_ERROR, msg, File, Line, ExtraData)
642
643    def DebugLogger (Level, msg):
644        EdkLogger.debug(Level, msg)
645
646    ## ReplaceWorkspaceMacro()
647    #
648    #   @param  Str           String that may contain macro
649    #   @param  MacroDict     Dictionary that contains macro value pair
650    #
651    def MacroExtend (Str, MacroDict={}, Arch='COMMON'):
652        if Str == None :
653            return None
654
655        Dict = {'$(WORKSPACE)'   : GenFdsGlobalVariable.WorkSpaceDir,
656                '$(EDK_SOURCE)'  : GenFdsGlobalVariable.EdkSourceDir,
657#                '$(OUTPUT_DIRECTORY)': GenFdsGlobalVariable.OutputDirFromDsc,
658                '$(TARGET)' : GenFdsGlobalVariable.TargetName,
659                '$(TOOL_CHAIN_TAG)' : GenFdsGlobalVariable.ToolChainTag,
660                '$(SPACE)' : ' '
661               }
662        OutputDir = GenFdsGlobalVariable.OutputDirFromDscDict[GenFdsGlobalVariable.ArchList[0]]
663        if Arch != 'COMMON' and Arch in GenFdsGlobalVariable.ArchList:
664            OutputDir = GenFdsGlobalVariable.OutputDirFromDscDict[Arch]
665
666        Dict['$(OUTPUT_DIRECTORY)'] = OutputDir
667
668        if MacroDict != None  and len (MacroDict) != 0:
669            Dict.update(MacroDict)
670
671        for key in Dict.keys():
672            if Str.find(key) >= 0 :
673                Str = Str.replace (key, Dict[key])
674
675        if Str.find('$(ARCH)') >= 0:
676            if len(GenFdsGlobalVariable.ArchList) == 1:
677                Str = Str.replace('$(ARCH)', GenFdsGlobalVariable.ArchList[0])
678            else:
679                EdkLogger.error("GenFds", GENFDS_ERROR, "No way to determine $(ARCH) for %s" % Str)
680
681        return Str
682
683    ## GetPcdValue()
684    #
685    #   @param  PcdPattern           pattern that labels a PCD.
686    #
687    def GetPcdValue (PcdPattern):
688        if PcdPattern == None :
689            return None
690        PcdPair = PcdPattern.lstrip('PCD(').rstrip(')').strip().split('.')
691        TokenSpace = PcdPair[0]
692        TokenCName = PcdPair[1]
693
694        PcdValue = ''
695        for Arch in GenFdsGlobalVariable.ArchList:
696            Platform = GenFdsGlobalVariable.WorkSpace.BuildObject[GenFdsGlobalVariable.ActivePlatform, Arch, GenFdsGlobalVariable.TargetName, GenFdsGlobalVariable.ToolChainTag]
697            PcdDict = Platform.Pcds
698            for Key in PcdDict:
699                PcdObj = PcdDict[Key]
700                if (PcdObj.TokenCName == TokenCName) and (PcdObj.TokenSpaceGuidCName == TokenSpace):
701                    if PcdObj.Type != 'FixedAtBuild':
702                        EdkLogger.error("GenFds", GENFDS_ERROR, "%s is not FixedAtBuild type." % PcdPattern)
703                    if PcdObj.DatumType != 'VOID*':
704                        EdkLogger.error("GenFds", GENFDS_ERROR, "%s is not VOID* datum type." % PcdPattern)
705
706                    PcdValue = PcdObj.DefaultValue
707                    return PcdValue
708
709            for Package in GenFdsGlobalVariable.WorkSpace.GetPackageList(GenFdsGlobalVariable.ActivePlatform,
710                                                                         Arch,
711                                                                         GenFdsGlobalVariable.TargetName,
712                                                                         GenFdsGlobalVariable.ToolChainTag):
713                PcdDict = Package.Pcds
714                for Key in PcdDict:
715                    PcdObj = PcdDict[Key]
716                    if (PcdObj.TokenCName == TokenCName) and (PcdObj.TokenSpaceGuidCName == TokenSpace):
717                        if PcdObj.Type != 'FixedAtBuild':
718                            EdkLogger.error("GenFds", GENFDS_ERROR, "%s is not FixedAtBuild type." % PcdPattern)
719                        if PcdObj.DatumType != 'VOID*':
720                            EdkLogger.error("GenFds", GENFDS_ERROR, "%s is not VOID* datum type." % PcdPattern)
721
722                        PcdValue = PcdObj.DefaultValue
723                        return PcdValue
724
725        return PcdValue
726
727    SetDir = staticmethod(SetDir)
728    ReplaceWorkspaceMacro = staticmethod(ReplaceWorkspaceMacro)
729    CallExternalTool = staticmethod(CallExternalTool)
730    VerboseLogger = staticmethod(VerboseLogger)
731    InfLogger = staticmethod(InfLogger)
732    ErrorLogger = staticmethod(ErrorLogger)
733    DebugLogger = staticmethod(DebugLogger)
734    MacroExtend = staticmethod (MacroExtend)
735    GetPcdValue = staticmethod(GetPcdValue)
736