1## @file
2# process FFS generation from INF statement
3#
4#  Copyright (c) 2007 - 2018, Intel Corporation. All rights reserved.<BR>
5#  Copyright (c) 2014-2016 Hewlett-Packard Development Company, L.P.<BR>
6#
7#  SPDX-License-Identifier: BSD-2-Clause-Patent
8#
9
10##
11# Import Modules
12#
13from __future__ import absolute_import
14from . import Rule
15import Common.LongFilePathOs as os
16from io import BytesIO
17from struct import *
18from .GenFdsGlobalVariable import GenFdsGlobalVariable
19from .Ffs import SectionSuffix,FdfFvFileTypeToFileType
20import subprocess
21import sys
22from . import Section
23from . import RuleSimpleFile
24from . import RuleComplexFile
25from CommonDataClass.FdfClass import FfsInfStatementClassObject
26from Common.MultipleWorkspace import MultipleWorkspace as mws
27from Common.DataType import SUP_MODULE_USER_DEFINED
28from Common.DataType import SUP_MODULE_HOST_APPLICATION
29from Common.StringUtils import *
30from Common.Misc import PathClass
31from Common.Misc import GuidStructureByteArrayToGuidString
32from Common.Misc import ProcessDuplicatedInf
33from Common.Misc import GetVariableOffset
34from Common import EdkLogger
35from Common.BuildToolError import *
36from .GuidSection import GuidSection
37from .FvImageSection import FvImageSection
38from Common.Misc import PeImageClass
39from AutoGen.GenDepex import DependencyExpression
40from PatchPcdValue.PatchPcdValue import PatchBinaryFile
41from Common.LongFilePathSupport import CopyLongFilePath
42from Common.LongFilePathSupport import OpenLongFilePath as open
43import Common.GlobalData as GlobalData
44from .DepexSection import DepexSection
45from Common.Misc import SaveFileOnChange
46from Common.Expression import *
47from Common.DataType import *
48
49## generate FFS from INF
50#
51#
52class FfsInfStatement(FfsInfStatementClassObject):
53    ## The constructor
54    #
55    #   @param  self        The object pointer
56    #
57    def __init__(self):
58        FfsInfStatementClassObject.__init__(self)
59        self.TargetOverrideList = []
60        self.ShadowFromInfFile = None
61        self.KeepRelocFromRule = None
62        self.InDsc = True
63        self.OptRomDefs = {}
64        self.PiSpecVersion = '0x00000000'
65        self.InfModule = None
66        self.FinalTargetSuffixMap = {}
67        self.CurrentLineNum = None
68        self.CurrentLineContent = None
69        self.FileName = None
70        self.InfFileName = None
71        self.OverrideGuid = None
72        self.PatchedBinFile = ''
73        self.MacroDict = {}
74        self.Depex = False
75
76    ## GetFinalTargetSuffixMap() method
77    #
78    #    Get final build target list
79    def GetFinalTargetSuffixMap(self):
80        if not self.InfModule or not self.CurrentArch:
81            return []
82        if not self.FinalTargetSuffixMap:
83            FinalBuildTargetList = GenFdsGlobalVariable.GetModuleCodaTargetList(self.InfModule, self.CurrentArch)
84            for File in FinalBuildTargetList:
85                self.FinalTargetSuffixMap.setdefault(os.path.splitext(File)[1], []).append(File)
86
87            # Check if current INF module has DEPEX
88            if '.depex' not in self.FinalTargetSuffixMap and self.InfModule.ModuleType != SUP_MODULE_USER_DEFINED and self.InfModule.ModuleType != SUP_MODULE_HOST_APPLICATION \
89                and not self.InfModule.DxsFile and not self.InfModule.LibraryClass:
90                ModuleType = self.InfModule.ModuleType
91                PlatformDataBase = GenFdsGlobalVariable.WorkSpace.BuildObject[GenFdsGlobalVariable.ActivePlatform, self.CurrentArch, GenFdsGlobalVariable.TargetName, GenFdsGlobalVariable.ToolChainTag]
92
93                if ModuleType != SUP_MODULE_USER_DEFINED and ModuleType != SUP_MODULE_HOST_APPLICATION:
94                    for LibraryClass in PlatformDataBase.LibraryClasses.GetKeys():
95                        if LibraryClass.startswith("NULL") and PlatformDataBase.LibraryClasses[LibraryClass, ModuleType]:
96                            self.InfModule.LibraryClasses[LibraryClass] = PlatformDataBase.LibraryClasses[LibraryClass, ModuleType]
97
98                StrModule = str(self.InfModule)
99                PlatformModule = None
100                if StrModule in PlatformDataBase.Modules:
101                    PlatformModule = PlatformDataBase.Modules[StrModule]
102                    for LibraryClass in PlatformModule.LibraryClasses:
103                        if LibraryClass.startswith("NULL"):
104                            self.InfModule.LibraryClasses[LibraryClass] = PlatformModule.LibraryClasses[LibraryClass]
105
106                DependencyList = [self.InfModule]
107                LibraryInstance = {}
108                DepexList = []
109                while len(DependencyList) > 0:
110                    Module = DependencyList.pop(0)
111                    if not Module:
112                        continue
113                    for Dep in Module.Depex[self.CurrentArch, ModuleType]:
114                        if DepexList != []:
115                            DepexList.append('AND')
116                        DepexList.append('(')
117                        DepexList.extend(Dep)
118                        if DepexList[-1] == 'END':  # no need of a END at this time
119                            DepexList.pop()
120                        DepexList.append(')')
121                    if 'BEFORE' in DepexList or 'AFTER' in DepexList:
122                        break
123                    for LibName in Module.LibraryClasses:
124                        if LibName in LibraryInstance:
125                            continue
126                        if PlatformModule and LibName in PlatformModule.LibraryClasses:
127                            LibraryPath = PlatformModule.LibraryClasses[LibName]
128                        else:
129                            LibraryPath = PlatformDataBase.LibraryClasses[LibName, ModuleType]
130                        if not LibraryPath:
131                            LibraryPath = Module.LibraryClasses[LibName]
132                        if not LibraryPath:
133                            continue
134                        LibraryModule = GenFdsGlobalVariable.WorkSpace.BuildObject[LibraryPath, self.CurrentArch, GenFdsGlobalVariable.TargetName, GenFdsGlobalVariable.ToolChainTag]
135                        LibraryInstance[LibName] = LibraryModule
136                        DependencyList.append(LibraryModule)
137                if DepexList:
138                    Dpx = DependencyExpression(DepexList, ModuleType, True)
139                    if len(Dpx.PostfixNotation) != 0:
140                        # It means this module has DEPEX
141                        self.FinalTargetSuffixMap['.depex'] = [os.path.join(self.EfiOutputPath, self.BaseName) + '.depex']
142        return self.FinalTargetSuffixMap
143
144    ## __InfParse() method
145    #
146    #   Parse inf file to get module information
147    #
148    #   @param  self        The object pointer
149    #   @param  Dict        dictionary contains macro and value pair
150    #
151    def __InfParse__(self, Dict = None, IsGenFfs=False):
152
153        GenFdsGlobalVariable.VerboseLogger( " Begine parsing INf file : %s" %self.InfFileName)
154
155        self.InfFileName = self.InfFileName.replace('$(WORKSPACE)', '')
156        if len(self.InfFileName) > 1 and self.InfFileName[0] == '\\' and self.InfFileName[1] == '\\':
157            pass
158        elif self.InfFileName[0] == '\\' or self.InfFileName[0] == '/' :
159            self.InfFileName = self.InfFileName[1:]
160
161        if self.InfFileName.find('$') == -1:
162            InfPath = NormPath(self.InfFileName)
163            if not os.path.exists(InfPath):
164                InfPath = GenFdsGlobalVariable.ReplaceWorkspaceMacro(InfPath)
165                if not os.path.exists(InfPath):
166                    EdkLogger.error("GenFds", GENFDS_ERROR, "Non-existant Module %s !" % (self.InfFileName))
167
168        self.CurrentArch = self.GetCurrentArch()
169        #
170        # Get the InfClass object
171        #
172
173        PathClassObj = PathClass(self.InfFileName, GenFdsGlobalVariable.WorkSpaceDir)
174        ErrorCode, ErrorInfo = PathClassObj.Validate(".inf")
175        if ErrorCode != 0:
176            EdkLogger.error("GenFds", ErrorCode, ExtraData=ErrorInfo)
177
178        #
179        # Cache lower case version of INF path before processing FILE_GUID override
180        #
181        InfLowerPath = str(PathClassObj).lower()
182        if self.OverrideGuid:
183            PathClassObj = ProcessDuplicatedInf(PathClassObj, self.OverrideGuid, GenFdsGlobalVariable.WorkSpaceDir)
184        if self.CurrentArch is not None:
185
186            Inf = GenFdsGlobalVariable.WorkSpace.BuildObject[PathClassObj, self.CurrentArch, GenFdsGlobalVariable.TargetName, GenFdsGlobalVariable.ToolChainTag]
187            #
188            # Set Ffs BaseName, ModuleGuid, ModuleType, Version, OutputPath
189            #
190            self.BaseName = Inf.BaseName
191            self.ModuleGuid = Inf.Guid
192            self.ModuleType = Inf.ModuleType
193            if Inf.Specification is not None and 'PI_SPECIFICATION_VERSION' in Inf.Specification:
194                self.PiSpecVersion = Inf.Specification['PI_SPECIFICATION_VERSION']
195            if Inf.AutoGenVersion < 0x00010005:
196                self.ModuleType = Inf.ComponentType
197            self.VersionString = Inf.Version
198            self.BinFileList = Inf.Binaries
199            self.SourceFileList = Inf.Sources
200            if self.KeepReloc is None and Inf.Shadow:
201                self.ShadowFromInfFile = Inf.Shadow
202
203        else:
204            Inf = GenFdsGlobalVariable.WorkSpace.BuildObject[PathClassObj, TAB_COMMON, GenFdsGlobalVariable.TargetName, GenFdsGlobalVariable.ToolChainTag]
205            self.BaseName = Inf.BaseName
206            self.ModuleGuid = Inf.Guid
207            self.ModuleType = Inf.ModuleType
208            if Inf.Specification is not None and 'PI_SPECIFICATION_VERSION' in Inf.Specification:
209                self.PiSpecVersion = Inf.Specification['PI_SPECIFICATION_VERSION']
210            self.VersionString = Inf.Version
211            self.BinFileList = Inf.Binaries
212            self.SourceFileList = Inf.Sources
213            if self.BinFileList == []:
214                EdkLogger.error("GenFds", GENFDS_ERROR,
215                                "INF %s specified in FDF could not be found in build ARCH %s!" \
216                                % (self.InfFileName, GenFdsGlobalVariable.ArchList))
217
218        if self.OverrideGuid:
219            self.ModuleGuid = self.OverrideGuid
220
221        if len(self.SourceFileList) != 0 and not self.InDsc:
222            EdkLogger.warn("GenFds", GENFDS_ERROR, "Module %s NOT found in DSC file; Is it really a binary module?" % (self.InfFileName))
223
224        if self.ModuleType == SUP_MODULE_SMM_CORE and int(self.PiSpecVersion, 16) < 0x0001000A:
225            EdkLogger.error("GenFds", FORMAT_NOT_SUPPORTED, "SMM_CORE module type can't be used in the module with PI_SPECIFICATION_VERSION less than 0x0001000A", File=self.InfFileName)
226
227        if self.ModuleType == SUP_MODULE_MM_CORE_STANDALONE and int(self.PiSpecVersion, 16) < 0x00010032:
228            EdkLogger.error("GenFds", FORMAT_NOT_SUPPORTED, "MM_CORE_STANDALONE module type can't be used in the module with PI_SPECIFICATION_VERSION less than 0x00010032", File=self.InfFileName)
229
230        if Inf._Defs is not None and len(Inf._Defs) > 0:
231            self.OptRomDefs.update(Inf._Defs)
232
233        self.PatchPcds = []
234        InfPcds = Inf.Pcds
235        Platform = GenFdsGlobalVariable.WorkSpace.BuildObject[GenFdsGlobalVariable.ActivePlatform, self.CurrentArch, GenFdsGlobalVariable.TargetName, GenFdsGlobalVariable.ToolChainTag]
236        FdfPcdDict = GenFdsGlobalVariable.FdfParser.Profile.PcdDict
237        PlatformPcds = Platform.Pcds
238
239        # Workaround here: both build and GenFds tool convert the workspace path to lower case
240        # But INF file path in FDF and DSC file may have real case characters.
241        # Try to convert the path to lower case to see if PCDs value are override by DSC.
242        DscModules = {}
243        for DscModule in Platform.Modules:
244            DscModules[str(DscModule).lower()] = Platform.Modules[DscModule]
245        for PcdKey in InfPcds:
246            Pcd = InfPcds[PcdKey]
247            if not hasattr(Pcd, 'Offset'):
248                continue
249            if Pcd.Type != TAB_PCDS_PATCHABLE_IN_MODULE:
250                continue
251            # Override Patchable PCD value by the value from DSC
252            PatchPcd = None
253            if InfLowerPath in DscModules and PcdKey in DscModules[InfLowerPath].Pcds:
254                PatchPcd = DscModules[InfLowerPath].Pcds[PcdKey]
255            elif PcdKey in Platform.Pcds:
256                PatchPcd = Platform.Pcds[PcdKey]
257            DscOverride = False
258            if PatchPcd and Pcd.Type == PatchPcd.Type:
259                DefaultValue = PatchPcd.DefaultValue
260                DscOverride = True
261
262            # Override Patchable PCD value by the value from FDF
263            FdfOverride = False
264            if PcdKey in FdfPcdDict:
265                DefaultValue = FdfPcdDict[PcdKey]
266                FdfOverride = True
267
268            # Override Patchable PCD value by the value from Build Option
269            BuildOptionOverride = False
270            if GlobalData.BuildOptionPcd:
271                for pcd in GlobalData.BuildOptionPcd:
272                    if PcdKey == (pcd[1], pcd[0]):
273                        if pcd[2]:
274                            continue
275                        DefaultValue = pcd[3]
276                        BuildOptionOverride = True
277                        break
278
279            if not DscOverride and not FdfOverride and not BuildOptionOverride:
280                continue
281
282            # Support Flexible PCD format
283            if DefaultValue:
284                try:
285                    DefaultValue = ValueExpressionEx(DefaultValue, Pcd.DatumType, Platform._GuidDict)(True)
286                except BadExpression:
287                    EdkLogger.error("GenFds", GENFDS_ERROR, 'PCD [%s.%s] Value "%s"' %(Pcd.TokenSpaceGuidCName, Pcd.TokenCName, DefaultValue), File=self.InfFileName)
288
289            if Pcd.InfDefaultValue:
290                try:
291                    Pcd.InfDefaultValue = ValueExpressionEx(Pcd.InfDefaultValue, Pcd.DatumType, Platform._GuidDict)(True)
292                except BadExpression:
293                    EdkLogger.error("GenFds", GENFDS_ERROR, 'PCD [%s.%s] Value "%s"' %(Pcd.TokenSpaceGuidCName, Pcd.TokenCName, Pcd.DefaultValue), File=self.InfFileName)
294
295            # Check value, if value are equal, no need to patch
296            if Pcd.DatumType == TAB_VOID:
297                if Pcd.InfDefaultValue == DefaultValue or not DefaultValue:
298                    continue
299                # Get the string size from FDF or DSC
300                if DefaultValue[0] == 'L':
301                    # Remove L"", but the '\0' must be appended
302                    MaxDatumSize = str((len(DefaultValue) - 2) * 2)
303                elif DefaultValue[0] == '{':
304                    MaxDatumSize = str(len(DefaultValue.split(',')))
305                else:
306                    MaxDatumSize = str(len(DefaultValue) - 1)
307                if DscOverride:
308                    Pcd.MaxDatumSize = PatchPcd.MaxDatumSize
309                # If no defined the maximum size in DSC, try to get current size from INF
310                if not Pcd.MaxDatumSize:
311                    Pcd.MaxDatumSize = str(len(Pcd.InfDefaultValue.split(',')))
312            else:
313                Base1 = Base2 = 10
314                if Pcd.InfDefaultValue.upper().startswith('0X'):
315                    Base1 = 16
316                if DefaultValue.upper().startswith('0X'):
317                    Base2 = 16
318                try:
319                    PcdValueInImg = int(Pcd.InfDefaultValue, Base1)
320                    PcdValueInDscOrFdf = int(DefaultValue, Base2)
321                    if PcdValueInImg == PcdValueInDscOrFdf:
322                        continue
323                except:
324                    continue
325            # Check the Pcd size and data type
326            if Pcd.DatumType == TAB_VOID:
327                if int(MaxDatumSize) > int(Pcd.MaxDatumSize):
328                    EdkLogger.error("GenFds", GENFDS_ERROR, "The size of VOID* type PCD '%s.%s' exceeds its maximum size %d bytes." \
329                                    % (Pcd.TokenSpaceGuidCName, Pcd.TokenCName, int(MaxDatumSize) - int(Pcd.MaxDatumSize)))
330            else:
331                if PcdValueInDscOrFdf > MAX_VAL_TYPE[Pcd.DatumType] \
332                    or PcdValueInImg > MAX_VAL_TYPE[Pcd.DatumType]:
333                    EdkLogger.error("GenFds", GENFDS_ERROR, "The size of %s type PCD '%s.%s' doesn't match its data type." \
334                                    % (Pcd.DatumType, Pcd.TokenSpaceGuidCName, Pcd.TokenCName))
335            self.PatchPcds.append((Pcd, DefaultValue))
336
337        self.InfModule = Inf
338        self.PcdIsDriver = Inf.PcdIsDriver
339        self.IsBinaryModule = Inf.IsBinaryModule
340        if len(Inf.Depex.data) > 0 and len(Inf.DepexExpression.data) > 0:
341            self.Depex = True
342
343        GenFdsGlobalVariable.VerboseLogger("BaseName : %s" % self.BaseName)
344        GenFdsGlobalVariable.VerboseLogger("ModuleGuid : %s" % self.ModuleGuid)
345        GenFdsGlobalVariable.VerboseLogger("ModuleType : %s" % self.ModuleType)
346        GenFdsGlobalVariable.VerboseLogger("VersionString : %s" % self.VersionString)
347        GenFdsGlobalVariable.VerboseLogger("InfFileName :%s" % self.InfFileName)
348
349        #
350        # Set OutputPath = ${WorkSpace}\Build\Fv\Ffs\${ModuleGuid}+ ${ModuleName}\
351        #
352        if IsGenFfs:
353            Rule = self.__GetRule__()
354            if GlobalData.gGuidPatternEnd.match(Rule.NameGuid):
355                self.ModuleGuid = Rule.NameGuid
356        self.OutputPath = os.path.join(GenFdsGlobalVariable.FfsDir, \
357                                       self.ModuleGuid + self.BaseName)
358        if not os.path.exists(self.OutputPath) :
359            os.makedirs(self.OutputPath)
360
361        self.EfiOutputPath, self.EfiDebugPath = self.__GetEFIOutPutPath__()
362        GenFdsGlobalVariable.VerboseLogger( "ModuelEFIPath: " + self.EfiOutputPath)
363
364    ## PatchEfiFile
365    #
366    #  Patch EFI file with patch PCD
367    #
368    #  @param EfiFile: EFI file needs to be patched.
369    #  @retval: Full path of patched EFI file: self.OutputPath + EfiFile base name
370    #           If passed in file does not end with efi, return as is
371    #
372    def PatchEfiFile(self, EfiFile, FileType):
373        #
374        # If the module does not have any patches, then return path to input file
375        #
376        if not self.PatchPcds:
377            return EfiFile
378
379        #
380        # Only patch file if FileType is PE32 or ModuleType is USER_DEFINED
381        #
382        if FileType != BINARY_FILE_TYPE_PE32 and self.ModuleType != SUP_MODULE_USER_DEFINED and self.ModuleType != SUP_MODULE_HOST_APPLICATION:
383            return EfiFile
384
385        #
386        # Generate path to patched output file
387        #
388        Basename = os.path.basename(EfiFile)
389        Output = os.path.normpath (os.path.join(self.OutputPath, Basename))
390
391        #
392        # If this file has already been patched, then return the path to the patched file
393        #
394        if self.PatchedBinFile == Output:
395          return Output
396
397        #
398        # If a different file from the same module has already been patched, then generate an error
399        #
400        if self.PatchedBinFile:
401            EdkLogger.error("GenFds", GENFDS_ERROR,
402                            'Only one binary file can be patched:\n'
403                            '  a binary file has been patched: %s\n'
404                            '  current file: %s' % (self.PatchedBinFile, EfiFile),
405                            File=self.InfFileName)
406
407        #
408        # Copy unpatched file contents to output file location to perform patching
409        #
410        CopyLongFilePath(EfiFile, Output)
411
412        #
413        # Apply patches to patched output file
414        #
415        for Pcd, Value in self.PatchPcds:
416            RetVal, RetStr = PatchBinaryFile(Output, int(Pcd.Offset, 0), Pcd.DatumType, Value, Pcd.MaxDatumSize)
417            if RetVal:
418                EdkLogger.error("GenFds", GENFDS_ERROR, RetStr, File=self.InfFileName)
419
420        #
421        # Save the path of the patched output file
422        #
423        self.PatchedBinFile = Output
424
425        #
426        # Return path to patched output file
427        #
428        return Output
429
430    ## GenFfs() method
431    #
432    #   Generate FFS
433    #
434    #   @param  self         The object pointer
435    #   @param  Dict         dictionary contains macro and value pair
436    #   @param  FvChildAddr  Array of the inside FvImage base address
437    #   @param  FvParentAddr Parent Fv base address
438    #   @retval string       Generated FFS file name
439    #
440    def GenFfs(self, Dict = None, FvChildAddr = [], FvParentAddr=None, IsMakefile=False, FvName=None):
441        #
442        # Parse Inf file get Module related information
443        #
444        if Dict is None:
445            Dict = {}
446        self.__InfParse__(Dict, IsGenFfs=True)
447        Arch = self.GetCurrentArch()
448        SrcFile = mws.join( GenFdsGlobalVariable.WorkSpaceDir, self.InfFileName);
449        DestFile = os.path.join( self.OutputPath, self.ModuleGuid + '.ffs')
450
451        SrcFileDir = "."
452        SrcPath = os.path.dirname(SrcFile)
453        SrcFileName = os.path.basename(SrcFile)
454        SrcFileBase, SrcFileExt = os.path.splitext(SrcFileName)
455        DestPath = os.path.dirname(DestFile)
456        DestFileName = os.path.basename(DestFile)
457        DestFileBase, DestFileExt = os.path.splitext(DestFileName)
458        self.MacroDict = {
459            # source file
460            "${src}"      :   SrcFile,
461            "${s_path}"   :   SrcPath,
462            "${s_dir}"    :   SrcFileDir,
463            "${s_name}"   :   SrcFileName,
464            "${s_base}"   :   SrcFileBase,
465            "${s_ext}"    :   SrcFileExt,
466            # destination file
467            "${dst}"      :   DestFile,
468            "${d_path}"   :   DestPath,
469            "${d_name}"   :   DestFileName,
470            "${d_base}"   :   DestFileBase,
471            "${d_ext}"    :   DestFileExt
472        }
473        #
474        # Allow binary type module not specify override rule in FDF file.
475        #
476        if len(self.BinFileList) > 0:
477            if self.Rule is None or self.Rule == "":
478                self.Rule = "BINARY"
479
480        if not IsMakefile and GenFdsGlobalVariable.EnableGenfdsMultiThread and self.Rule != 'BINARY':
481            IsMakefile = True
482        #
483        # Get the rule of how to generate Ffs file
484        #
485        Rule = self.__GetRule__()
486        GenFdsGlobalVariable.VerboseLogger( "Packing binaries from inf file : %s" %self.InfFileName)
487        #
488        # Convert Fv File Type for PI1.1 SMM driver.
489        #
490        if self.ModuleType == SUP_MODULE_DXE_SMM_DRIVER and int(self.PiSpecVersion, 16) >= 0x0001000A:
491            if Rule.FvFileType == 'DRIVER':
492                Rule.FvFileType = 'SMM'
493        #
494        # Framework SMM Driver has no SMM FV file type
495        #
496        if self.ModuleType == SUP_MODULE_DXE_SMM_DRIVER and int(self.PiSpecVersion, 16) < 0x0001000A:
497            if Rule.FvFileType == 'SMM' or Rule.FvFileType == SUP_MODULE_SMM_CORE:
498                EdkLogger.error("GenFds", FORMAT_NOT_SUPPORTED, "Framework SMM module doesn't support SMM or SMM_CORE FV file type", File=self.InfFileName)
499        #
500        # For the rule only has simpleFile
501        #
502        MakefilePath = None
503        if self.IsBinaryModule:
504            IsMakefile = False
505        if IsMakefile:
506            PathClassObj = PathClass(self.InfFileName, GenFdsGlobalVariable.WorkSpaceDir)
507            if self.OverrideGuid:
508                PathClassObj = ProcessDuplicatedInf(PathClassObj, self.OverrideGuid, GenFdsGlobalVariable.WorkSpaceDir)
509            MakefilePath = PathClassObj.Path, Arch
510        if isinstance (Rule, RuleSimpleFile.RuleSimpleFile):
511            SectionOutputList = self.__GenSimpleFileSection__(Rule, IsMakefile=IsMakefile)
512            FfsOutput = self.__GenSimpleFileFfs__(Rule, SectionOutputList, MakefilePath=MakefilePath)
513            return FfsOutput
514        #
515        # For Rule has ComplexFile
516        #
517        elif isinstance(Rule, RuleComplexFile.RuleComplexFile):
518            InputSectList, InputSectAlignments = self.__GenComplexFileSection__(Rule, FvChildAddr, FvParentAddr, IsMakefile=IsMakefile)
519            FfsOutput = self.__GenComplexFileFfs__(Rule, InputSectList, InputSectAlignments, MakefilePath=MakefilePath)
520            return FfsOutput
521
522    ## __ExtendMacro__() method
523    #
524    #   Replace macro with its value
525    #
526    #   @param  self        The object pointer
527    #   @param  String      The string to be replaced
528    #   @retval string      Macro replaced string
529    #
530    def __ExtendMacro__ (self, String):
531        MacroDict = {
532            '$(INF_OUTPUT)'  : self.EfiOutputPath,
533            '$(MODULE_NAME)' : self.BaseName,
534            '$(BUILD_NUMBER)': self.BuildNum,
535            '$(INF_VERSION)' : self.VersionString,
536            '$(NAMED_GUID)'  : self.ModuleGuid
537        }
538        String = GenFdsGlobalVariable.MacroExtend(String, MacroDict)
539        String = GenFdsGlobalVariable.MacroExtend(String, self.MacroDict)
540        return String
541
542    ## __GetRule__() method
543    #
544    #   Get correct rule for generating FFS for this INF
545    #
546    #   @param  self        The object pointer
547    #   @retval Rule        Rule object
548    #
549    def __GetRule__ (self) :
550        CurrentArchList = []
551        if self.CurrentArch is None:
552            CurrentArchList = ['common']
553        else:
554            CurrentArchList.append(self.CurrentArch)
555
556        for CurrentArch in CurrentArchList:
557            RuleName = 'RULE'              + \
558                       '.'                 + \
559                       CurrentArch.upper() + \
560                       '.'                 + \
561                       self.ModuleType.upper()
562            if self.Rule is not None:
563                RuleName = RuleName + \
564                           '.'      + \
565                           self.Rule.upper()
566
567            Rule = GenFdsGlobalVariable.FdfParser.Profile.RuleDict.get(RuleName)
568            if Rule is not None:
569                GenFdsGlobalVariable.VerboseLogger ("Want To Find Rule Name is : " + RuleName)
570                return Rule
571
572        RuleName = 'RULE'      + \
573                   '.'         + \
574                   TAB_COMMON    + \
575                   '.'         + \
576                   self.ModuleType.upper()
577
578        if self.Rule is not None:
579            RuleName = RuleName + \
580                       '.'      + \
581                       self.Rule.upper()
582
583        GenFdsGlobalVariable.VerboseLogger ('Trying to apply common rule %s for INF %s' % (RuleName, self.InfFileName))
584
585        Rule = GenFdsGlobalVariable.FdfParser.Profile.RuleDict.get(RuleName)
586        if Rule is not None:
587            GenFdsGlobalVariable.VerboseLogger ("Want To Find Rule Name is : " + RuleName)
588            return Rule
589
590        if Rule is None :
591            EdkLogger.error("GenFds", GENFDS_ERROR, 'Don\'t Find common rule %s for INF %s' \
592                            % (RuleName, self.InfFileName))
593
594    ## __GetPlatformArchList__() method
595    #
596    #   Get Arch list this INF built under
597    #
598    #   @param  self        The object pointer
599    #   @retval list        Arch list
600    #
601    def __GetPlatformArchList__(self):
602
603        InfFileKey = os.path.normpath(mws.join(GenFdsGlobalVariable.WorkSpaceDir, self.InfFileName))
604        DscArchList = []
605        for Arch in GenFdsGlobalVariable.ArchList :
606            PlatformDataBase = GenFdsGlobalVariable.WorkSpace.BuildObject[GenFdsGlobalVariable.ActivePlatform, Arch, GenFdsGlobalVariable.TargetName, GenFdsGlobalVariable.ToolChainTag]
607            if  PlatformDataBase is not None:
608                if InfFileKey in PlatformDataBase.Modules:
609                    DscArchList.append (Arch)
610                else:
611                    #
612                    # BaseTools support build same module more than once, the module path with FILE_GUID overridden has
613                    # the file name FILE_GUIDmodule.inf, then PlatformDataBase.Modules use FILE_GUIDmodule.inf as key,
614                    # but the path (self.MetaFile.Path) is the real path
615                    #
616                    for key in PlatformDataBase.Modules:
617                        if InfFileKey == str((PlatformDataBase.Modules[key]).MetaFile.Path):
618                            DscArchList.append (Arch)
619                            break
620
621        return DscArchList
622
623    ## GetCurrentArch() method
624    #
625    #   Get Arch list of the module from this INF is to be placed into flash
626    #
627    #   @param  self        The object pointer
628    #   @retval list        Arch list
629    #
630    def GetCurrentArch(self) :
631
632        TargetArchList = GenFdsGlobalVariable.ArchList
633
634        PlatformArchList = self.__GetPlatformArchList__()
635
636        CurArchList = TargetArchList
637        if PlatformArchList != []:
638            CurArchList = list(set (TargetArchList) & set (PlatformArchList))
639        GenFdsGlobalVariable.VerboseLogger ("Valid target architecture(s) is : " + " ".join(CurArchList))
640
641        ArchList = []
642        if self.KeyStringList != []:
643            for Key in self.KeyStringList:
644                Key = GenFdsGlobalVariable.MacroExtend(Key)
645                Target, Tag, Arch = Key.split('_')
646                if Arch in CurArchList:
647                    ArchList.append(Arch)
648                if Target not in self.TargetOverrideList:
649                    self.TargetOverrideList.append(Target)
650        else:
651            ArchList = CurArchList
652
653        UseArchList = TargetArchList
654        if self.UseArch is not None:
655            UseArchList = []
656            UseArchList.append(self.UseArch)
657            ArchList = list(set (UseArchList) & set (ArchList))
658
659        self.InfFileName = NormPath(self.InfFileName)
660        if len(PlatformArchList) == 0:
661            self.InDsc = False
662            PathClassObj = PathClass(self.InfFileName, GenFdsGlobalVariable.WorkSpaceDir)
663            ErrorCode, ErrorInfo = PathClassObj.Validate(".inf")
664            if ErrorCode != 0:
665                EdkLogger.error("GenFds", ErrorCode, ExtraData=ErrorInfo)
666        if len(ArchList) == 1:
667            Arch = ArchList[0]
668            return Arch
669        elif len(ArchList) > 1:
670            if len(PlatformArchList) == 0:
671                EdkLogger.error("GenFds", GENFDS_ERROR, "GenFds command line option has multiple ARCHs %s. Not able to determine which ARCH is valid for Module %s !" % (str(ArchList), self.InfFileName))
672            else:
673                EdkLogger.error("GenFds", GENFDS_ERROR, "Module built under multiple ARCHs %s. Not able to determine which output to put into flash for Module %s !" % (str(ArchList), self.InfFileName))
674        else:
675            EdkLogger.error("GenFds", GENFDS_ERROR, "Module %s appears under ARCH %s in platform %s, but current deduced ARCH is %s, so NO build output could be put into flash." \
676                            % (self.InfFileName, str(PlatformArchList), GenFdsGlobalVariable.ActivePlatform, str(set (UseArchList) & set (TargetArchList))))
677
678    ## __GetEFIOutPutPath__() method
679    #
680    #   Get the output path for generated files
681    #
682    #   @param  self        The object pointer
683    #   @retval string      Path that output files from this INF go to
684    #
685    def __GetEFIOutPutPath__(self):
686        Arch = ''
687        OutputPath = ''
688        DebugPath = ''
689        (ModulePath, FileName) = os.path.split(self.InfFileName)
690        Index = FileName.rfind('.')
691        FileName = FileName[0:Index]
692        if self.OverrideGuid:
693            FileName = self.OverrideGuid
694        Arch = "NoneArch"
695        if self.CurrentArch is not None:
696            Arch = self.CurrentArch
697
698        OutputPath = os.path.join(GenFdsGlobalVariable.OutputDirDict[Arch],
699                                  Arch,
700                                  ModulePath,
701                                  FileName,
702                                  'OUTPUT'
703                                  )
704        DebugPath = os.path.join(GenFdsGlobalVariable.OutputDirDict[Arch],
705                                  Arch,
706                                  ModulePath,
707                                  FileName,
708                                  'DEBUG'
709                                  )
710        OutputPath = os.path.realpath(OutputPath)
711        DebugPath = os.path.realpath(DebugPath)
712        return OutputPath, DebugPath
713
714    ## __GenSimpleFileSection__() method
715    #
716    #   Generate section by specified file name or a list of files with file extension
717    #
718    #   @param  self        The object pointer
719    #   @param  Rule        The rule object used to generate section
720    #   @retval string      File name of the generated section file
721    #
722    def __GenSimpleFileSection__(self, Rule, IsMakefile = False):
723        #
724        # Prepare the parameter of GenSection
725        #
726        FileList = []
727        OutputFileList = []
728        GenSecInputFile = None
729        if Rule.FileName is not None:
730            GenSecInputFile = self.__ExtendMacro__(Rule.FileName)
731            if os.path.isabs(GenSecInputFile):
732                GenSecInputFile = os.path.normpath(GenSecInputFile)
733            else:
734                GenSecInputFile = os.path.normpath(os.path.join(self.EfiOutputPath, GenSecInputFile))
735        else:
736            FileList, IsSect = Section.Section.GetFileList(self, '', Rule.FileExtension)
737
738        Index = 1
739        SectionType = Rule.SectionType
740        #
741        # Convert Fv Section Type for PI1.1 SMM driver.
742        #
743        if self.ModuleType == SUP_MODULE_DXE_SMM_DRIVER and int(self.PiSpecVersion, 16) >= 0x0001000A:
744            if SectionType == BINARY_FILE_TYPE_DXE_DEPEX:
745                SectionType = BINARY_FILE_TYPE_SMM_DEPEX
746        #
747        # Framework SMM Driver has no SMM_DEPEX section type
748        #
749        if self.ModuleType == SUP_MODULE_DXE_SMM_DRIVER and int(self.PiSpecVersion, 16) < 0x0001000A:
750            if SectionType == BINARY_FILE_TYPE_SMM_DEPEX:
751                EdkLogger.error("GenFds", FORMAT_NOT_SUPPORTED, "Framework SMM module doesn't support SMM_DEPEX section type", File=self.InfFileName)
752        NoStrip = True
753        if self.ModuleType in (SUP_MODULE_SEC, SUP_MODULE_PEI_CORE, SUP_MODULE_PEIM):
754            if self.KeepReloc is not None:
755                NoStrip = self.KeepReloc
756            elif Rule.KeepReloc is not None:
757                NoStrip = Rule.KeepReloc
758            elif self.ShadowFromInfFile is not None:
759                NoStrip = self.ShadowFromInfFile
760
761        if FileList != [] :
762            for File in FileList:
763
764                SecNum = '%d' %Index
765                GenSecOutputFile= self.__ExtendMacro__(Rule.NameGuid) + \
766                              SectionSuffix[SectionType] + SUP_MODULE_SEC + SecNum
767                Index = Index + 1
768                OutputFile = os.path.join(self.OutputPath, GenSecOutputFile)
769                File = GenFdsGlobalVariable.MacroExtend(File, Dict, self.CurrentArch)
770
771                #Get PE Section alignment when align is set to AUTO
772                if self.Alignment == 'Auto' and (SectionType == BINARY_FILE_TYPE_PE32 or SectionType == BINARY_FILE_TYPE_TE):
773                    ImageObj = PeImageClass (File)
774                    if ImageObj.SectionAlignment < 0x400:
775                        self.Alignment = str (ImageObj.SectionAlignment)
776                    elif ImageObj.SectionAlignment < 0x100000:
777                        self.Alignment = str (ImageObj.SectionAlignment // 0x400) + 'K'
778                    else:
779                        self.Alignment = str (ImageObj.SectionAlignment // 0x100000) + 'M'
780
781                if not NoStrip:
782                    FileBeforeStrip = os.path.join(self.OutputPath, ModuleName + '.reloc')
783                    if not os.path.exists(FileBeforeStrip) or \
784                           (os.path.getmtime(File) > os.path.getmtime(FileBeforeStrip)):
785                        CopyLongFilePath(File, FileBeforeStrip)
786                    StrippedFile = os.path.join(self.OutputPath, ModuleName + '.stipped')
787                    GenFdsGlobalVariable.GenerateFirmwareImage(
788                            StrippedFile,
789                            [File],
790                            Strip=True,
791                            IsMakefile=IsMakefile
792                        )
793                    File = StrippedFile
794
795                if SectionType == BINARY_FILE_TYPE_TE:
796                    TeFile = os.path.join( self.OutputPath, self.ModuleGuid + 'Te.raw')
797                    GenFdsGlobalVariable.GenerateFirmwareImage(
798                            TeFile,
799                            [File],
800                            Type='te',
801                            IsMakefile=IsMakefile
802                        )
803                    File = TeFile
804                GenFdsGlobalVariable.GenerateSection(OutputFile, [File], Section.Section.SectionType[SectionType], IsMakefile=IsMakefile)
805                OutputFileList.append(OutputFile)
806        else:
807            SecNum = '%d' %Index
808            GenSecOutputFile= self.__ExtendMacro__(Rule.NameGuid) + \
809                              SectionSuffix[SectionType] + SUP_MODULE_SEC + SecNum
810            OutputFile = os.path.join(self.OutputPath, GenSecOutputFile)
811            GenSecInputFile = GenFdsGlobalVariable.MacroExtend(GenSecInputFile, Dict, self.CurrentArch)
812
813            #Get PE Section alignment when align is set to AUTO
814            if self.Alignment == 'Auto' and (SectionType == BINARY_FILE_TYPE_PE32 or SectionType == BINARY_FILE_TYPE_TE):
815                ImageObj = PeImageClass (GenSecInputFile)
816                if ImageObj.SectionAlignment < 0x400:
817                    self.Alignment = str (ImageObj.SectionAlignment)
818                elif ImageObj.SectionAlignment < 0x100000:
819                    self.Alignment = str (ImageObj.SectionAlignment // 0x400) + 'K'
820                else:
821                    self.Alignment = str (ImageObj.SectionAlignment // 0x100000) + 'M'
822
823            if not NoStrip:
824                FileBeforeStrip = os.path.join(self.OutputPath, ModuleName + '.reloc')
825                if not os.path.exists(FileBeforeStrip) or \
826                       (os.path.getmtime(GenSecInputFile) > os.path.getmtime(FileBeforeStrip)):
827                    CopyLongFilePath(GenSecInputFile, FileBeforeStrip)
828
829                StrippedFile = os.path.join(self.OutputPath, ModuleName + '.stipped')
830                GenFdsGlobalVariable.GenerateFirmwareImage(
831                        StrippedFile,
832                        [GenSecInputFile],
833                        Strip=True,
834                        IsMakefile=IsMakefile
835                    )
836                GenSecInputFile = StrippedFile
837
838            if SectionType == BINARY_FILE_TYPE_TE:
839                TeFile = os.path.join( self.OutputPath, self.ModuleGuid + 'Te.raw')
840                GenFdsGlobalVariable.GenerateFirmwareImage(
841                        TeFile,
842                        [GenSecInputFile],
843                        Type='te',
844                        IsMakefile=IsMakefile
845                    )
846                GenSecInputFile = TeFile
847            GenFdsGlobalVariable.GenerateSection(OutputFile, [GenSecInputFile], Section.Section.SectionType[SectionType], IsMakefile=IsMakefile)
848            OutputFileList.append(OutputFile)
849
850        return OutputFileList
851
852    ## __GenSimpleFileFfs__() method
853    #
854    #   Generate FFS
855    #
856    #   @param  self        The object pointer
857    #   @param  Rule        The rule object used to generate section
858    #   @param  InputFileList        The output file list from GenSection
859    #   @retval string      Generated FFS file name
860    #
861    def __GenSimpleFileFfs__(self, Rule, InputFileList, MakefilePath = None):
862        FfsOutput = self.OutputPath                     + \
863                    os.sep                              + \
864                    self.__ExtendMacro__(Rule.NameGuid) + \
865                    '.ffs'
866
867        GenFdsGlobalVariable.VerboseLogger(self.__ExtendMacro__(Rule.NameGuid))
868        InputSection = []
869        SectionAlignments = []
870        for InputFile in InputFileList:
871            InputSection.append(InputFile)
872            SectionAlignments.append(Rule.SectAlignment)
873
874        if Rule.NameGuid is not None and Rule.NameGuid.startswith('PCD('):
875            PcdValue = GenFdsGlobalVariable.GetPcdValue(Rule.NameGuid)
876            if len(PcdValue) == 0:
877                EdkLogger.error("GenFds", GENFDS_ERROR, '%s NOT defined.' \
878                            % (Rule.NameGuid))
879            if PcdValue.startswith('{'):
880                PcdValue = GuidStructureByteArrayToGuidString(PcdValue)
881            RegistryGuidStr = PcdValue
882            if len(RegistryGuidStr) == 0:
883                EdkLogger.error("GenFds", GENFDS_ERROR, 'GUID value for %s in wrong format.' \
884                            % (Rule.NameGuid))
885            self.ModuleGuid = RegistryGuidStr
886
887            GenFdsGlobalVariable.GenerateFfs(FfsOutput, InputSection,
888                                             FdfFvFileTypeToFileType[Rule.FvFileType],
889                                             self.ModuleGuid, Fixed=Rule.Fixed,
890                                             CheckSum=Rule.CheckSum, Align=Rule.Alignment,
891                                             SectionAlign=SectionAlignments,
892                                             MakefilePath=MakefilePath
893                                             )
894        return FfsOutput
895
896    ## __GenComplexFileSection__() method
897    #
898    #   Generate section by sections in Rule
899    #
900    #   @param  self         The object pointer
901    #   @param  Rule         The rule object used to generate section
902    #   @param  FvChildAddr  Array of the inside FvImage base address
903    #   @param  FvParentAddr Parent Fv base address
904    #   @retval string       File name of the generated section file
905    #
906    def __GenComplexFileSection__(self, Rule, FvChildAddr, FvParentAddr, IsMakefile = False):
907        if self.ModuleType in (SUP_MODULE_SEC, SUP_MODULE_PEI_CORE, SUP_MODULE_PEIM, SUP_MODULE_MM_CORE_STANDALONE):
908            if Rule.KeepReloc is not None:
909                self.KeepRelocFromRule = Rule.KeepReloc
910        SectFiles = []
911        SectAlignments = []
912        Index = 1
913        HasGeneratedFlag = False
914        if self.PcdIsDriver == 'PEI_PCD_DRIVER':
915            if self.IsBinaryModule:
916                PcdExDbFileName = os.path.join(GenFdsGlobalVariable.FvDir, "PEIPcdDataBase.raw")
917            else:
918                PcdExDbFileName = os.path.join(self.EfiOutputPath, "PEIPcdDataBase.raw")
919            PcdExDbSecName = os.path.join(self.OutputPath, "PEIPcdDataBaseSec.raw")
920            GenFdsGlobalVariable.GenerateSection(PcdExDbSecName,
921                                                 [PcdExDbFileName],
922                                                 "EFI_SECTION_RAW",
923                                                 IsMakefile = IsMakefile
924                                                 )
925            SectFiles.append(PcdExDbSecName)
926            SectAlignments.append(None)
927        elif self.PcdIsDriver == 'DXE_PCD_DRIVER':
928            if self.IsBinaryModule:
929                PcdExDbFileName = os.path.join(GenFdsGlobalVariable.FvDir, "DXEPcdDataBase.raw")
930            else:
931                PcdExDbFileName = os.path.join(self.EfiOutputPath, "DXEPcdDataBase.raw")
932            PcdExDbSecName = os.path.join(self.OutputPath, "DXEPcdDataBaseSec.raw")
933            GenFdsGlobalVariable.GenerateSection(PcdExDbSecName,
934                                                [PcdExDbFileName],
935                                                "EFI_SECTION_RAW",
936                                                IsMakefile = IsMakefile
937                                                )
938            SectFiles.append(PcdExDbSecName)
939            SectAlignments.append(None)
940        for Sect in Rule.SectionList:
941            SecIndex = '%d' %Index
942            SectList  = []
943            #
944            # Convert Fv Section Type for PI1.1 SMM driver.
945            #
946            if self.ModuleType == SUP_MODULE_DXE_SMM_DRIVER and int(self.PiSpecVersion, 16) >= 0x0001000A:
947                if Sect.SectionType == BINARY_FILE_TYPE_DXE_DEPEX:
948                    Sect.SectionType = BINARY_FILE_TYPE_SMM_DEPEX
949            #
950            # Framework SMM Driver has no SMM_DEPEX section type
951            #
952            if self.ModuleType == SUP_MODULE_DXE_SMM_DRIVER and int(self.PiSpecVersion, 16) < 0x0001000A:
953                if Sect.SectionType == BINARY_FILE_TYPE_SMM_DEPEX:
954                    EdkLogger.error("GenFds", FORMAT_NOT_SUPPORTED, "Framework SMM module doesn't support SMM_DEPEX section type", File=self.InfFileName)
955            #
956            # process the inside FvImage from FvSection or GuidSection
957            #
958            if FvChildAddr != []:
959                if isinstance(Sect, FvImageSection):
960                    Sect.FvAddr = FvChildAddr.pop(0)
961                elif isinstance(Sect, GuidSection):
962                    Sect.FvAddr = FvChildAddr
963            if FvParentAddr is not None and isinstance(Sect, GuidSection):
964                Sect.FvParentAddr = FvParentAddr
965
966            if Rule.KeyStringList != []:
967                SectList, Align = Sect.GenSection(self.OutputPath, self.ModuleGuid, SecIndex, Rule.KeyStringList, self, IsMakefile = IsMakefile)
968            else :
969                SectList, Align = Sect.GenSection(self.OutputPath, self.ModuleGuid, SecIndex, self.KeyStringList, self, IsMakefile = IsMakefile)
970
971            if not HasGeneratedFlag:
972                UniVfrOffsetFileSection = ""
973                ModuleFileName = mws.join(GenFdsGlobalVariable.WorkSpaceDir, self.InfFileName)
974                InfData = GenFdsGlobalVariable.WorkSpace.BuildObject[PathClass(ModuleFileName), self.CurrentArch]
975                #
976                # Search the source list in InfData to find if there are .vfr file exist.
977                #
978                VfrUniBaseName = {}
979                VfrUniOffsetList = []
980                for SourceFile in InfData.Sources:
981                    if SourceFile.Type.upper() == ".VFR" :
982                        #
983                        # search the .map file to find the offset of vfr binary in the PE32+/TE file.
984                        #
985                        VfrUniBaseName[SourceFile.BaseName] = (SourceFile.BaseName + "Bin")
986                    if SourceFile.Type.upper() == ".UNI" :
987                        #
988                        # search the .map file to find the offset of Uni strings binary in the PE32+/TE file.
989                        #
990                        VfrUniBaseName["UniOffsetName"] = (self.BaseName + "Strings")
991
992
993                if len(VfrUniBaseName) > 0:
994                    if IsMakefile:
995                        if InfData.BuildType != 'UEFI_HII':
996                            UniVfrOffsetFileName = os.path.join(self.OutputPath, self.BaseName + '.offset')
997                            UniVfrOffsetFileSection = os.path.join(self.OutputPath, self.BaseName + 'Offset' + '.raw')
998                            UniVfrOffsetFileNameList = []
999                            UniVfrOffsetFileNameList.append(UniVfrOffsetFileName)
1000                            TrimCmd = "Trim --Vfr-Uni-Offset -o %s --ModuleName=%s --DebugDir=%s " % (UniVfrOffsetFileName, self.BaseName, self.EfiDebugPath)
1001                            GenFdsGlobalVariable.SecCmdList.append(TrimCmd)
1002                            GenFdsGlobalVariable.GenerateSection(UniVfrOffsetFileSection,
1003                                                                [UniVfrOffsetFileName],
1004                                                                "EFI_SECTION_RAW",
1005                                                                IsMakefile = True
1006                                                                )
1007                    else:
1008                        VfrUniOffsetList = self.__GetBuildOutputMapFileVfrUniInfo(VfrUniBaseName)
1009                        #
1010                        # Generate the Raw data of raw section
1011                        #
1012                        if VfrUniOffsetList:
1013                            UniVfrOffsetFileName = os.path.join(self.OutputPath, self.BaseName + '.offset')
1014                            UniVfrOffsetFileSection = os.path.join(self.OutputPath, self.BaseName + 'Offset' + '.raw')
1015                            FfsInfStatement.__GenUniVfrOffsetFile (VfrUniOffsetList, UniVfrOffsetFileName)
1016                            UniVfrOffsetFileNameList = []
1017                            UniVfrOffsetFileNameList.append(UniVfrOffsetFileName)
1018                            """Call GenSection"""
1019
1020                            GenFdsGlobalVariable.GenerateSection(UniVfrOffsetFileSection,
1021                                                                 UniVfrOffsetFileNameList,
1022                                                                 "EFI_SECTION_RAW"
1023                                                                 )
1024                            #os.remove(UniVfrOffsetFileName)
1025                    if UniVfrOffsetFileSection:
1026                        SectList.append(UniVfrOffsetFileSection)
1027                        HasGeneratedFlag = True
1028
1029            for SecName in  SectList :
1030                SectFiles.append(SecName)
1031                SectAlignments.append(Align)
1032            Index = Index + 1
1033        return SectFiles, SectAlignments
1034
1035    ## __GenComplexFileFfs__() method
1036    #
1037    #   Generate FFS
1038    #
1039    #   @param  self        The object pointer
1040    #   @param  Rule        The rule object used to generate section
1041    #   @param  InputFileList        The output file list from GenSection
1042    #   @retval string      Generated FFS file name
1043    #
1044    def __GenComplexFileFfs__(self, Rule, InputFile, Alignments, MakefilePath = None):
1045
1046        if Rule.NameGuid is not None and Rule.NameGuid.startswith('PCD('):
1047            PcdValue = GenFdsGlobalVariable.GetPcdValue(Rule.NameGuid)
1048            if len(PcdValue) == 0:
1049                EdkLogger.error("GenFds", GENFDS_ERROR, '%s NOT defined.' \
1050                            % (Rule.NameGuid))
1051            if PcdValue.startswith('{'):
1052                PcdValue = GuidStructureByteArrayToGuidString(PcdValue)
1053            RegistryGuidStr = PcdValue
1054            if len(RegistryGuidStr) == 0:
1055                EdkLogger.error("GenFds", GENFDS_ERROR, 'GUID value for %s in wrong format.' \
1056                            % (Rule.NameGuid))
1057            self.ModuleGuid = RegistryGuidStr
1058
1059        FfsOutput = os.path.join( self.OutputPath, self.ModuleGuid + '.ffs')
1060        GenFdsGlobalVariable.GenerateFfs(FfsOutput, InputFile,
1061                                             FdfFvFileTypeToFileType[Rule.FvFileType],
1062                                             self.ModuleGuid, Fixed=Rule.Fixed,
1063                                             CheckSum=Rule.CheckSum, Align=Rule.Alignment,
1064                                             SectionAlign=Alignments,
1065                                             MakefilePath=MakefilePath
1066                                             )
1067        return FfsOutput
1068
1069    ## __GetBuildOutputMapFileVfrUniInfo() method
1070    #
1071    #   Find the offset of UNI/INF object offset in the EFI image file.
1072    #
1073    #   @param  self                  The object pointer
1074    #   @param  VfrUniBaseName        A name list contain the UNI/INF object name.
1075    #   @retval RetValue              A list contain offset of UNI/INF object.
1076    #
1077    def __GetBuildOutputMapFileVfrUniInfo(self, VfrUniBaseName):
1078        MapFileName = os.path.join(self.EfiOutputPath, self.BaseName + ".map")
1079        EfiFileName = os.path.join(self.EfiOutputPath, self.BaseName + ".efi")
1080        return GetVariableOffset(MapFileName, EfiFileName, list(VfrUniBaseName.values()))
1081
1082    ## __GenUniVfrOffsetFile() method
1083    #
1084    #   Generate the offset file for the module which contain VFR or UNI file.
1085    #
1086    #   @param  VfrUniOffsetList        A list contain the VFR/UNI offsets in the EFI image file.
1087    #   @param  UniVfrOffsetFileName    The output offset file name.
1088    #
1089    @staticmethod
1090    def __GenUniVfrOffsetFile(VfrUniOffsetList, UniVfrOffsetFileName):
1091
1092        # Use a instance of StringIO to cache data
1093        fStringIO = BytesIO()
1094
1095        for Item in VfrUniOffsetList:
1096            if (Item[0].find("Strings") != -1):
1097                #
1098                # UNI offset in image.
1099                # GUID + Offset
1100                # { 0x8913c5e0, 0x33f6, 0x4d86, { 0x9b, 0xf1, 0x43, 0xef, 0x89, 0xfc, 0x6, 0x66 } }
1101                #
1102                UniGuid = b'\xe0\xc5\x13\x89\xf63\x86M\x9b\xf1C\xef\x89\xfc\x06f'
1103                fStringIO.write(UniGuid)
1104                UniValue = pack ('Q', int (Item[1], 16))
1105                fStringIO.write (UniValue)
1106            else:
1107                #
1108                # VFR binary offset in image.
1109                # GUID + Offset
1110                # { 0xd0bc7cb4, 0x6a47, 0x495f, { 0xaa, 0x11, 0x71, 0x7, 0x46, 0xda, 0x6, 0xa2 } };
1111                #
1112                VfrGuid = b'\xb4|\xbc\xd0Gj_I\xaa\x11q\x07F\xda\x06\xa2'
1113                fStringIO.write(VfrGuid)
1114                type (Item[1])
1115                VfrValue = pack ('Q', int (Item[1], 16))
1116                fStringIO.write (VfrValue)
1117
1118        #
1119        # write data into file.
1120        #
1121        try :
1122            SaveFileOnChange(UniVfrOffsetFileName, fStringIO.getvalue())
1123        except:
1124            EdkLogger.error("GenFds", FILE_WRITE_FAILURE, "Write data to file %s failed, please check whether the file been locked or using by other applications." %UniVfrOffsetFileName, None)
1125
1126        fStringIO.close ()
1127
1128
1129