]> git.proxmox.com Git - mirror_edk2.git/blobdiff - IntelFsp2Pkg/Tools/GenCfgOpt.py
UefiCpuPkg: Move AsmRelocateApLoopStart from Mpfuncs.nasm to AmdSev.nasm
[mirror_edk2.git] / IntelFsp2Pkg / Tools / GenCfgOpt.py
index e8cec95aa7352086a4bb5c44b34cb932464ca242..13be81ddbcec42aba7a9f9908b03872378cb7143 100644 (file)
@@ -1,13 +1,7 @@
 ## @ GenCfgOpt.py\r
 #\r
-# Copyright (c) 2014 - 2016, Intel Corporation. All rights reserved.<BR>\r
-# This program and the accompanying materials are licensed and made available under\r
-# the terms and conditions of the BSD License that accompanies this distribution.\r
-# The full text of the license may be found at\r
-# http://opensource.org/licenses/bsd-license.php.\r
-#\r
-# THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
-# WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+# Copyright (c) 2014 - 2022, Intel Corporation. All rights reserved.<BR>\r
+# SPDX-License-Identifier: BSD-2-Clause-Patent\r
 #\r
 ##\r
 \r
@@ -16,6 +10,7 @@ import re
 import sys\r
 import struct\r
 from   datetime import date\r
+from functools import reduce\r
 \r
 # Generated file copyright header\r
 \r
@@ -88,17 +83,19 @@ are permitted provided that the following conditions are met:
 **/\r
 """\r
 \r
+BuildOptionPcd = []\r
+\r
 class CLogicalExpression:\r
     def __init__(self):\r
         self.index    = 0\r
         self.string   = ''\r
 \r
     def errExit(self, err = ''):\r
-        print "ERROR: Express parsing for:"\r
-        print "       %s" % self.string\r
-        print "       %s^" % (' ' * self.index)\r
+        print ("ERROR: Express parsing for:")\r
+        print ("       %s" % self.string)\r
+        print ("       %s^" % (' ' * self.index))\r
         if err:\r
-            print "INFO : %s" % err\r
+            print ("INFO : %s" % err)\r
         raise SystemExit\r
 \r
     def getNonNumber (self, n1, n2):\r
@@ -286,11 +283,10 @@ class CLogicalExpression:
         return Result\r
 \r
 class CGenCfgOpt:\r
-    def __init__(self):\r
+    def __init__(self, Mode = ''):\r
         self.Debug          = False\r
         self.Error          = ''\r
-        self.ReleaseMode    = True\r
-\r
+        self.Mode           = Mode\r
         self._GlobalDataDef = """\r
 GlobalDataDef\r
     SKUID = 0, "DEFAULT"\r
@@ -304,26 +300,22 @@ List &EN_DIS
 EndList\r
 \r
 """\r
-\r
-        self._BsfKeyList    = ['FIND','NAME','HELP','TYPE','PAGE','OPTION','ORDER']\r
+        self._BsfKeyList    = ['FIND','NAME','HELP','TYPE','PAGE', 'PAGES', 'BLOCK', 'OPTION','CONDITION','ORDER', 'MARKER', 'SUBT']\r
         self._HdrKeyList    = ['HEADER','STRUCT', 'EMBED', 'COMMENT']\r
         self._BuidinOption  = {'$EN_DIS' : 'EN_DIS'}\r
 \r
         self._MacroDict   = {}\r
+        self._VarDict     = {}\r
         self._PcdsDict    = {}\r
         self._CfgBlkDict  = {}\r
         self._CfgPageDict = {}\r
+        self._BsfTempDict = {}\r
         self._CfgItemList = []\r
+        self._DscLines    = []\r
         self._DscFile     = ''\r
-        self._FvDir       = ''\r
-        self._MapVer      = 0\r
 \r
-    def ParseBuildMode (self, OutputStr):\r
-        if "RELEASE_" in OutputStr:\r
-            self.ReleaseMode = True\r
-        if "DEBUG_" in OutputStr:\r
-            self.ReleaseMode = False\r
-        return\r
+        self._MapVer      = 0\r
+        self._DscTime     = 0\r
 \r
     def ParseMacros (self, MacroDefStr):\r
         # ['-DABC=1', '-D', 'CFG_DEBUG=1', '-D', 'CFG_OUTDIR=Build']\r
@@ -350,18 +342,18 @@ EndList
         else:\r
             Error = 0\r
             if self.Debug:\r
-                print "INFO : Macro dictionary:"\r
+                print ("INFO : Macro dictionary:")\r
                 for Each in self._MacroDict:\r
-                    print "       $(%s) = [ %s ]" % (Each , self._MacroDict[Each])\r
+                    print ("       $(%s) = [ %s ]" % (Each , self._MacroDict[Each]))\r
         return Error\r
 \r
     def EvaulateIfdef   (self, Macro):\r
         Result = Macro in self._MacroDict\r
         if self.Debug:\r
-            print "INFO : Eval Ifdef [%s] : %s" % (Macro, Result)\r
+            print ("INFO : Eval Ifdef [%s] : %s" % (Macro, Result))\r
         return  Result\r
 \r
-    def ExpandMacros (self, Input):\r
+    def ExpandMacros (self, Input, Preserve = False):\r
         Line = Input\r
         Match = re.findall("\$\(\w+\)", Input)\r
         if Match:\r
@@ -371,8 +363,9 @@ EndList
                   Line = Line.replace(Each, self._MacroDict[Variable])\r
               else:\r
                   if self.Debug:\r
-                      print "WARN : %s is not defined" % Each\r
-                  Line = Line.replace(Each, Each[2:-1])\r
+                      print ("WARN : %s is not defined" % Each)\r
+                  if not Preserve:\r
+                      Line = Line.replace(Each, Each[2:-1])\r
         return Line\r
 \r
     def ExpandPcds (self, Input):\r
@@ -384,7 +377,7 @@ EndList
                   Line = Line.replace(PcdName, self._PcdsDict[PcdName])\r
               else:\r
                   if self.Debug:\r
-                      print "WARN : %s is not defined" % PcdName\r
+                      print ("WARN : %s is not defined" % PcdName)\r
         return Line\r
 \r
     def EvaluateExpress (self, Expr):\r
@@ -393,7 +386,71 @@ EndList
         LogExpr = CLogicalExpression()\r
         Result  = LogExpr.evaluateExpress (ExpExpr)\r
         if self.Debug:\r
-            print "INFO : Eval Express [%s] : %s" % (Expr, Result)\r
+            print ("INFO : Eval Express [%s] : %s" % (Expr, Result))\r
+        return Result\r
+\r
+    def ValueToByteArray (self, ValueStr, Length):\r
+        Match = re.match("\{\s*FILE:(.+)\}", ValueStr)\r
+        if Match:\r
+          FileList = Match.group(1).split(',')\r
+          Result  = bytearray()\r
+          for File in FileList:\r
+            File = File.strip()\r
+            BinPath = os.path.join(os.path.dirname(self._DscFile), File)\r
+            Result.extend(bytearray(open(BinPath, 'rb').read()))\r
+        else:\r
+            try:\r
+                Result  = bytearray(self.ValueToList(ValueStr, Length))\r
+            except ValueError as e:\r
+                raise Exception ("Bytes in '%s' must be in range 0~255 !" % ValueStr)\r
+        if len(Result) < Length:\r
+            Result.extend(b'\x00' * (Length - len(Result)))\r
+        elif len(Result) > Length:\r
+            raise Exception ("Value '%s' is too big to fit into %d bytes !" % (ValueStr, Length))\r
+\r
+        return Result[:Length]\r
+\r
+    def ValueToList (self, ValueStr, Length):\r
+        if ValueStr[0] == '{':\r
+            Result = []\r
+            BinList = ValueStr[1:-1].split(',')\r
+            InBitField     = False\r
+            LastInBitField = False\r
+            Value          = 0\r
+            BitLen         = 0\r
+            for Element in BinList:\r
+                InBitField = False\r
+                Each = Element.strip()\r
+                if len(Each) == 0:\r
+                    pass\r
+                else:\r
+                    if Each[0] in ['"', "'"]:\r
+                        Result.extend(list(bytearray(Each[1:-1], 'utf-8')))\r
+                    elif ':' in Each:\r
+                        Match    = re.match("(.+):(\d+)b", Each)\r
+                        if Match is None:\r
+                            raise Exception("Invald value list format '%s' !" % Each)\r
+                        InBitField = True\r
+                        CurrentBitLen = int(Match.group(2))\r
+                        CurrentValue  = ((self.EvaluateExpress(Match.group(1)) & (1<<CurrentBitLen) - 1)) << BitLen\r
+                    else:\r
+                        Result.append(self.EvaluateExpress(Each.strip()))\r
+                if InBitField:\r
+                    Value  += CurrentValue\r
+                    BitLen += CurrentBitLen\r
+                if LastInBitField and ((not InBitField) or (Element == BinList[-1])):\r
+                    if BitLen % 8 != 0:\r
+                        raise Exception("Invald bit field length!")\r
+                    Result.extend(Val2Bytes(Value, BitLen // 8))\r
+                    Value  = 0\r
+                    BitLen = 0\r
+                LastInBitField = InBitField\r
+        elif ValueStr.startswith("'") and ValueStr.endswith("'"):\r
+            Result = Str2Bytes (ValueStr, Length)\r
+        elif ValueStr.startswith('"') and ValueStr.endswith('"'):\r
+            Result = Str2Bytes (ValueStr, Length)\r
+        else:\r
+            Result = Val2Bytes (self.EvaluateExpress(ValueStr), Length)\r
         return Result\r
 \r
     def FormatListValue(self, ConfigDict):\r
@@ -418,7 +475,7 @@ EndList
         bytearray = []\r
         for each in dataarray:\r
             value = each\r
-            for loop in xrange(unit):\r
+            for loop in range(int(unit)):\r
                 bytearray.append("0x%02X" % (value & 0xFF))\r
                 value = value >> 8\r
         newvalue  = '{'  + ','.join(bytearray) + '}'\r
@@ -426,28 +483,61 @@ EndList
         return ""\r
 \r
     def ParseDscFile (self, DscFile, FvDir):\r
+        Hardcode = False\r
+        AutoAlign = False\r
         self._CfgItemList = []\r
         self._CfgPageDict = {}\r
         self._CfgBlkDict  = {}\r
         self._DscFile     = DscFile\r
         self._FvDir       = FvDir\r
 \r
+        self._DscLines    = []\r
+        self._BsfTempDict = {}\r
+\r
+        # Initial DSC time is parent DSC time.\r
+        self._DscTime     = os.path.getmtime(DscFile)\r
+\r
+        CfgDict = {}\r
+\r
         IsDefSect       = False\r
         IsPcdSect       = False\r
         IsUpdSect       = False\r
         IsVpdSect       = False\r
+        IsTmpSect       = False\r
+\r
+        TemplateName    = ''\r
 \r
         IfStack         = []\r
         ElifStack       = []\r
         Error           = 0\r
         ConfigDict      = {}\r
 \r
-        DscFd        = open(DscFile, "r")\r
-        DscLines     = DscFd.readlines()\r
-        DscFd.close()\r
+\r
+        if type(DscFile) is list:\r
+            # it is DSC lines already\r
+            DscLines       = DscFile\r
+            self._DscFile  = '.'\r
+        else:\r
+            DscFd        = open(DscFile, "r")\r
+            DscLines     = DscFd.readlines()\r
+            DscFd.close()\r
+            self._DscFile = DscFile\r
+\r
+        SkipLines = 0\r
+\r
+        MaxAlign = 32   #Default align to 32, but if there are 64 bit unit, align to 64\r
+        SizeAlign = 0   #record the struct max align\r
+        Base = 0        #Starting offset of sub-structure.\r
 \r
         while len(DscLines):\r
             DscLine  = DscLines.pop(0).strip()\r
+            if SkipLines == 0:\r
+              self._DscLines.append (DscLine)\r
+            else:\r
+              SkipLines = SkipLines - 1\r
+            if len(DscLine) == 0:\r
+              continue\r
+\r
             Handle   = False\r
             Match    = re.match("^\[(.+)\]", DscLine)\r
             if Match is not None:\r
@@ -455,11 +545,15 @@ EndList
                 IsPcdSect = False\r
                 IsVpdSect = False\r
                 IsUpdSect = False\r
-                if  Match.group(1).lower() == "Defines".lower():\r
+                IsTmpSect = False\r
+                SectionName = Match.group(1).lower()\r
+                if  SectionName == "Defines".lower():\r
                     IsDefSect = True\r
-                if  Match.group(1).lower() == "PcdsFeatureFlag".lower():\r
+                if  (SectionName == "PcdsFeatureFlag".lower() or SectionName == "PcdsFixedAtBuild".lower()):\r
                     IsPcdSect = True\r
-                elif Match.group(1).lower() == "PcdsDynamicVpd.Upd".lower():\r
+                elif SectionName == "PcdsDynamicVpd.Tmp".lower():\r
+                    IsTmpSect = True\r
+                elif SectionName == "PcdsDynamicVpd.Upd".lower():\r
                     ConfigDict = {}\r
                     ConfigDict['header']  = 'ON'\r
                     ConfigDict['region']  = 'UPD'\r
@@ -467,75 +561,98 @@ EndList
                     ConfigDict['page']    = ''\r
                     ConfigDict['name']    = ''\r
                     ConfigDict['find']    = ''\r
+                    ConfigDict['marker']  = ''\r
                     ConfigDict['struct']  = ''\r
                     ConfigDict['embed']   = ''\r
                     ConfigDict['comment'] = ''\r
                     ConfigDict['subreg']  = []\r
+                    ConfigDict['condition']  = ''\r
+                    ConfigDict['option']  = ''\r
                     IsUpdSect = True\r
+                    Offset    = 0\r
             else:\r
-                if IsDefSect or IsPcdSect or IsUpdSect or IsVpdSect:\r
-                    if re.match("^!else($|\s+#.+)", DscLine):\r
+                if IsDefSect or IsPcdSect or IsUpdSect or IsVpdSect or IsTmpSect:\r
+\r
+                    Match = False if DscLine[0] != '!' else True\r
+                    if Match:\r
+                        Match = re.match("^!(else|endif|ifdef|ifndef|if|elseif|include)\s*(.+)?$", DscLine.split("#")[0])\r
+                    Keyword   = Match.group(1) if Match else ''\r
+                    Remaining = Match.group(2) if Match else ''\r
+                    Remaining = '' if Remaining is None else Remaining.strip()\r
+\r
+                    if Keyword in ['if', 'elseif', 'ifdef', 'ifndef', 'include'] and not Remaining:\r
+                        raise Exception ("ERROR: Expression is expected after '!if' or !elseif' for line '%s'" % DscLine)\r
+\r
+                    if Keyword == 'else':\r
                         if IfStack:\r
                             IfStack[-1] = not IfStack[-1]\r
                         else:\r
-                            print("ERROR: No paired '!if' found for '!else' for line '%s'" % DscLine)\r
-                            raise SystemExit\r
-                    elif re.match("^!endif($|\s+#.+)", DscLine):\r
+                            raise Exception ("ERROR: No paired '!if' found for '!else' for line '%s'" % DscLine)\r
+                    elif Keyword == 'endif':\r
                         if IfStack:\r
                             IfStack.pop()\r
                             Level = ElifStack.pop()\r
                             if Level > 0:\r
                                 del IfStack[-Level:]\r
                         else:\r
-                            print("ERROR: No paired '!if' found for '!endif' for line '%s'" % DscLine)\r
-                            raise SystemExit\r
-                    else:\r
-                        Result = False\r
-                        Match = re.match("!(ifdef|ifndef)\s+(.+)", DscLine)\r
-                        if Match:\r
-                            Result = self.EvaulateIfdef (Match.group(2))\r
-                            if Match.group(1) == 'ifndef':\r
-                                Result = not Result\r
-                            IfStack.append(Result)\r
+                            raise Exception ("ERROR: No paired '!if' found for '!endif' for line '%s'" % DscLine)\r
+                    elif Keyword == 'ifdef' or Keyword == 'ifndef':\r
+                        Result = self.EvaulateIfdef (Remaining)\r
+                        if Keyword == 'ifndef':\r
+                            Result = not Result\r
+                        IfStack.append(Result)\r
+                        ElifStack.append(0)\r
+                    elif Keyword == 'if' or Keyword == 'elseif':\r
+                        Result = self.EvaluateExpress(Remaining)\r
+                        if Keyword == "if":\r
                             ElifStack.append(0)\r
+                            IfStack.append(Result)\r
+                        else:   #elseif\r
+                            if IfStack:\r
+                                IfStack[-1] = not IfStack[-1]\r
+                                IfStack.append(Result)\r
+                                ElifStack[-1] = ElifStack[-1] + 1\r
+                            else:\r
+                                raise Exception ("ERROR: No paired '!if' found for '!elif' for line '%s'" % DscLine)\r
+                    else:\r
+                        if IfStack:\r
+                            Handle = reduce(lambda x,y: x and y, IfStack)\r
                         else:\r
-                            Match  = re.match("!(if|elseif)\s+(.+)", DscLine)\r
+                            Handle = True\r
+                        if Handle:\r
+                            Match = re.match("!include\s+(.+)", DscLine)\r
                             if Match:\r
-                                Result = self.EvaluateExpress(Match.group(2))\r
-                                if Match.group(1) == "if":\r
-                                    ElifStack.append(0)\r
-                                    IfStack.append(Result)\r
-                                else:   #elseif\r
-                                    if IfStack:\r
-                                        IfStack[-1] = not IfStack[-1]\r
-                                        IfStack.append(Result)\r
-                                        ElifStack[-1] = ElifStack[-1] + 1\r
-                                    else:\r
-                                        print("ERROR: No paired '!if' found for '!elif' for line '%s'" % DscLine)\r
-                                        raise SystemExit\r
-                            else:\r
-                                if IfStack:\r
-                                    Handle = reduce(lambda x,y: x and y, IfStack)\r
+                                IncludeFilePath = Match.group(1)\r
+                                IncludeFilePath = self.ExpandMacros(IncludeFilePath)\r
+                                PackagesPath = os.getenv("PACKAGES_PATH")\r
+                                if PackagesPath:\r
+                                  for PackagePath in PackagesPath.split(os.pathsep):\r
+                                      IncludeFilePathAbs = os.path.join(os.path.normpath(PackagePath), os.path.normpath(IncludeFilePath))\r
+                                      if os.path.exists(IncludeFilePathAbs):\r
+                                          IncludeDsc  = open(IncludeFilePathAbs, "r")\r
+                                          break\r
                                 else:\r
-                                    Handle = True\r
-                                if Handle:\r
-                                    Match = re.match("!include\s+(.+)", DscLine)\r
-                                    if Match:\r
-                                        IncludeFilePath = Match.group(1)\r
-                                        IncludeFilePath = self.ExpandMacros(IncludeFilePath)\r
-                                        try:\r
-                                            IncludeDsc  = open(IncludeFilePath, "r")\r
-                                        except:\r
-                                            print("ERROR: Cannot open file '%s'" % IncludeFilePath)\r
-                                            raise SystemExit\r
-                                        NewDscLines = IncludeDsc.readlines()\r
-                                        IncludeDsc.close()\r
-                                        DscLines = NewDscLines + DscLines\r
-                                    else:\r
-                                        if DscLine.startswith('!'):\r
-                                            print("ERROR: Unrecoginized directive for line '%s'" % DscLine)\r
-                                            raise SystemExit\r
+                                  IncludeDsc  = open(IncludeFilePath, "r")\r
+                                if IncludeDsc == None:\r
+                                    print("ERROR: Cannot open file '%s'" % IncludeFilePath)\r
+                                    raise SystemExit\r
+\r
+                                # Update DscTime when newer DSC time found.\r
+                                CurrentDscTime = os.path.getmtime(os.path.realpath(IncludeDsc.name))\r
+                                if CurrentDscTime > self._DscTime:\r
+                                    self._DscTime = CurrentDscTime\r
+\r
+                                NewDscLines = IncludeDsc.readlines()\r
+                                IncludeDsc.close()\r
+                                DscLines = NewDscLines + DscLines\r
+                                del self._DscLines[-1]\r
+                                Offset = 0\r
+                            else:\r
+                                if DscLine.startswith('!'):\r
+                                    print("ERROR: Unrecognized directive for line '%s'" % DscLine)\r
+                                    raise SystemExit\r
             if not Handle:\r
+                del self._DscLines[-1]\r
                 continue\r
 \r
             if IsDefSect:\r
@@ -543,11 +660,11 @@ EndList
                 #DEFINE FSP_T_UPD_TOOL_GUID = 34686CA3-34F9-4901-B82A-BA630F0714C6\r
                 #DEFINE FSP_M_UPD_TOOL_GUID = 39A250DB-E465-4DD1-A2AC-E2BD3C0E2385\r
                 #DEFINE FSP_S_UPD_TOOL_GUID = CAE3605B-5B34-4C85-B3D7-27D54273C40F\r
-                Match = re.match("^\s*(?:DEFINE\s+)*(\w+)\s*=\s*([-.\w]+)", DscLine)\r
+                Match = re.match("^\s*(?:DEFINE\s+)*(\w+)\s*=\s*(.+)", DscLine)\r
                 if Match:\r
-                    self._MacroDict[Match.group(1)] = Match.group(2)\r
+                    self._MacroDict[Match.group(1)] = self.ExpandMacros(Match.group(2))\r
                     if self.Debug:\r
-                        print "INFO : DEFINE %s = [ %s ]" % (Match.group(1), Match.group(2))\r
+                        print ("INFO : DEFINE %s = [ %s ]" % (Match.group(1), self.ExpandMacros(Match.group(2))))\r
             elif IsPcdSect:\r
                 #gSiPkgTokenSpaceGuid.PcdTxtEnable|FALSE\r
                 #gSiPkgTokenSpaceGuid.PcdOverclockEnable|TRUE\r
@@ -555,7 +672,30 @@ EndList
                 if Match:\r
                     self._PcdsDict[Match.group(1)] = Match.group(2)\r
                     if self.Debug:\r
-                        print "INFO : PCD %s = [ %s ]" % (Match.group(1), Match.group(2))\r
+                        print ("INFO : PCD %s = [ %s ]" % (Match.group(1), Match.group(2)))\r
+                    i = 0\r
+                    while i < len(BuildOptionPcd):\r
+                        Match = re.match("\s*([\w\.]+)\s*\=\s*(\w+)", BuildOptionPcd[i])\r
+                        if Match:\r
+                            self._PcdsDict[Match.group(1)] = Match.group(2)\r
+                        i += 1\r
+\r
+            elif IsTmpSect:\r
+                # !BSF DEFT:{GPIO_TMPL:START}\r
+                Match = re.match("^\s*#\s+(!BSF)\s+DEFT:{(.+?):(START|END)}", DscLine)\r
+                if Match:\r
+                    if Match.group(3) == 'START' and not TemplateName:\r
+                        TemplateName = Match.group(2).strip()\r
+                        self._BsfTempDict[TemplateName] = []\r
+                    if Match.group(3) == 'END' and (TemplateName == Match.group(2).strip()) and TemplateName:\r
+                        TemplateName = ''\r
+                else:\r
+                    if TemplateName:\r
+                        Match = re.match("^!include\s*(.+)?$", DscLine)\r
+                        if Match:\r
+                            continue\r
+                        self._BsfTempDict[TemplateName].append(DscLine)\r
+\r
             else:\r
                 Match = re.match("^\s*#\s+(!BSF|@Bsf|!HDR)\s+(.+)", DscLine)\r
                 if Match:\r
@@ -568,7 +708,8 @@ EndList
                             for Page in PageList:\r
                                 Page  = Page.strip()\r
                                 Match = re.match("(\w+):\"(.+)\"", Page)\r
-                                self._CfgPageDict[Match.group(1)] = Match.group(2)\r
+                                if Match != None:\r
+                                    self._CfgPageDict[Match.group(1)] = Match.group(2)\r
 \r
                         Match = re.match("(?:^|.+\s+)BLOCK:{NAME:\"(.+)\"\s*,\s*VER:\"(.+)\"\s*}", Remaining)\r
                         if Match:\r
@@ -611,9 +752,9 @@ EndList
                 Match = re.match("^\s*#\s*@ValidRange\s*(.+)\s*\|\s*(.+)\s*-\s*(.+)\s*", DscLine)\r
                 if Match:\r
                     if "0x" in Match.group(2) or "0x" in Match.group(3):\r
-                       ConfigDict['type'] = "EditNum, HEX, (%s,%s)" % (Match.group(2), Match.group(3))\r
+                        ConfigDict['type'] = "EditNum, HEX, (%s,%s)" % (Match.group(2), Match.group(3))\r
                     else:\r
-                       ConfigDict['type'] = "EditNum, DEC, (%s,%s)" % (Match.group(2), Match.group(3))\r
+                        ConfigDict['type'] = "EditNum, DEC, (%s,%s)" % (Match.group(2), Match.group(3))\r
 \r
                 Match = re.match("^\s*##\s+(.+)", DscLine)\r
                 if Match:\r
@@ -621,13 +762,22 @@ EndList
 \r
                 # Check VPD/UPD\r
                 if IsUpdSect:\r
-                    Match = re.match("^([_a-zA-Z0-9]+).([_a-zA-Z0-9]+)\s*\|\s*(0x[0-9A-F]+)\s*\|\s*(\d+|0x[0-9a-fA-F]+)\s*\|\s*(.+)",DscLine)\r
+                    Match = re.match("^([_a-zA-Z0-9]+).([_a-zA-Z0-9]+)\s*\|\s*(0x[0-9A-F]+|\*)\s*\|\s*(\d+|0x[0-9a-fA-F]+)\s*\|\s*(.+)",DscLine)\r
                 else:\r
                     Match = re.match("^([_a-zA-Z0-9]+).([_a-zA-Z0-9]+)\s*\|\s*(0x[0-9A-F]+)(?:\s*\|\s*(.+))?",  DscLine)\r
                 if Match:\r
                     ConfigDict['space']  = Match.group(1)\r
                     ConfigDict['cname']  = Match.group(2)\r
-                    ConfigDict['offset'] = int (Match.group(3), 16)\r
+                    if Match.group(3) != '*':\r
+                        Hardcode = True\r
+                        Offset =  int (Match.group(3), 16)\r
+                    else:\r
+                        AutoAlign = True\r
+\r
+                    if Hardcode and AutoAlign:\r
+                        print("Hardcode and auto-align mixed mode is not supported by GenCfgOpt")\r
+                        raise SystemExit\r
+                    ConfigDict['offset'] = Offset\r
                     if ConfigDict['order'] == -1:\r
                         ConfigDict['order'] = ConfigDict['offset'] << 8\r
                     else:\r
@@ -639,6 +789,7 @@ EndList
                             Length  = int (Match.group(4), 16)\r
                         else :\r
                             Length  = int (Match.group(4))\r
+                        Offset += Length\r
                     else:\r
                         Value = Match.group(4)\r
                         if Value is None:\r
@@ -666,6 +817,52 @@ EndList
                         ConfigDict['help']   = ''\r
                         ConfigDict['type']   = ''\r
                         ConfigDict['option'] = ''\r
+                    if IsUpdSect and AutoAlign:\r
+                        ItemLength = int(ConfigDict['length'])\r
+                        ItemOffset = int(ConfigDict['offset'])\r
+                        ItemStruct = ConfigDict['struct']\r
+                        Unit = 1\r
+                        if ItemLength in [1, 2, 4, 8] and not ConfigDict['value'].startswith('{'):\r
+                            Unit = ItemLength\r
+                            # If there are 64 bit unit, align to 64\r
+                            if Unit == 8:\r
+                                MaxAlign = 64\r
+                                SizeAlign = 8\r
+                        if ItemStruct != '':\r
+                            UnitDict = {'UINT8':1, 'UINT16':2, 'UINT32':4, 'UINT64':8}\r
+                            if ItemStruct in ['UINT8', 'UINT16', 'UINT32', 'UINT64']:\r
+                                Unit = UnitDict[ItemStruct]\r
+                                # If there are 64 bit unit, align to 64\r
+                                if Unit == 8:\r
+                                    MaxAlign = 64\r
+                                SizeAlign = max(SizeAlign, Unit)\r
+                        if (ConfigDict['embed'].find(':START') != -1):\r
+                            Base = ItemOffset\r
+                        SubOffset = ItemOffset - Base\r
+                        SubRemainder = SubOffset % Unit\r
+                        if SubRemainder:\r
+                            Diff = Unit - SubRemainder\r
+                            Offset = Offset + Diff\r
+                            ItemOffset = ItemOffset + Diff\r
+\r
+                        if (ConfigDict['embed'].find(':END') != -1):\r
+                            Remainder = Offset % (MaxAlign/8)   # MaxAlign is either 32 or 64\r
+                            if Remainder:\r
+                                Diff = int((MaxAlign/8) - Remainder)\r
+                                Offset = Offset + Diff\r
+                                ItemOffset = ItemOffset + Diff\r
+                            MaxAlign = 32                       # Reset to default 32 align when struct end\r
+                        if (ConfigDict['cname'] == 'UpdTerminator'):\r
+                            # ItemLength is the size of UpdTerminator\r
+                            # Itemlength might be 16, 32, or 64\r
+                            # Struct align to 64 if UpdTerminator\r
+                            # or struct size is 64 bit, else align to 32\r
+                            Remainder = Offset % max(ItemLength/8, 4, SizeAlign)\r
+                            Offset = Offset + ItemLength\r
+                            if Remainder:\r
+                                Diff = int(max(ItemLength/8, 4, SizeAlign) - Remainder)\r
+                                ItemOffset = ItemOffset + Diff\r
+                        ConfigDict['offset'] = ItemOffset\r
 \r
                     self._CfgItemList.append(ConfigDict.copy())\r
                     ConfigDict['name']   = ''\r
@@ -673,6 +870,7 @@ EndList
                     ConfigDict['struct'] = ''\r
                     ConfigDict['embed']  = ''\r
                     ConfigDict['comment'] = ''\r
+                    ConfigDict['marker'] = ''\r
                     ConfigDict['order']  = -1\r
                     ConfigDict['subreg'] = []\r
                     ConfigDict['option'] = ''\r
@@ -711,9 +909,8 @@ EndList
         bitsvalue = bitsvalue[::-1]\r
         bitslen   = len(bitsvalue)\r
         if start > bitslen or end > bitslen:\r
-            print "Invalid bits offset [%d,%d] for %s" % (start, end, subitem['name'])\r
-            raise SystemExit\r
-        return hex(int(bitsvalue[start:end][::-1], 2))\r
+            raise Exception ("Invalid bits offset [%d,%d] %d for %s" % (start, end, bitslen, subitem['name']))\r
+        return '0x%X' % (int(bitsvalue[start:end][::-1], 2))\r
 \r
     def UpdateSubRegionDefaultValue (self):\r
         Error = 0\r
@@ -745,29 +942,35 @@ EndList
                 SubItem['value'] = valuestr\r
         return Error\r
 \r
+    def NoDscFileChange (self, OutPutFile):\r
+        NoFileChange = True\r
+        if not os.path.exists(OutPutFile):\r
+            NoFileChange = False\r
+        else:\r
+            OutputTime = os.path.getmtime(OutPutFile)\r
+            if self._DscTime > OutputTime:\r
+                NoFileChange = False\r
+        return NoFileChange\r
+\r
     def CreateSplitUpdTxt (self, UpdTxtFile):\r
-        GuidList = ['FSP_T_UPD_TOOL_GUID','FSP_M_UPD_TOOL_GUID','FSP_S_UPD_TOOL_GUID']\r
-        SignatureList = ['0x545F', '0x4D5F','0x535F']        #  _T, _M, and _S signature for FSPT, FSPM, FSPS\r
+        GuidList = ['FSP_T_UPD_TOOL_GUID','FSP_M_UPD_TOOL_GUID','FSP_S_UPD_TOOL_GUID','FSP_I_UPD_TOOL_GUID']\r
+        SignatureList = ['0x545F', '0x4D5F','0x535F','0x495F']        #  _T, _M, _S and _I signature for FSPT, FSPM, FSPS, FSPI\r
         for Index in range(len(GuidList)):\r
             UpdTxtFile = ''\r
             FvDir = self._FvDir\r
             if GuidList[Index] not in self._MacroDict:\r
-                self.Error = "%s definition is missing in DSC file" % (GuidList[Index])\r
-                return 1\r
+                NoFSPI = False\r
+                if GuidList[Index] == 'FSP_I_UPD_TOOL_GUID':\r
+                    NoFSPI = True\r
+                    continue\r
+                else:\r
+                    self.Error = "%s definition is missing in DSC file" % (GuidList[Index])\r
+                    return 1\r
 \r
             if UpdTxtFile == '':\r
                 UpdTxtFile = os.path.join(FvDir, self._MacroDict[GuidList[Index]] + '.txt')\r
 \r
-            ReCreate = False\r
-            if not os.path.exists(UpdTxtFile):\r
-                ReCreate = True\r
-            else:\r
-                DscTime = os.path.getmtime(self._DscFile)\r
-                TxtTime = os.path.getmtime(UpdTxtFile)\r
-                if DscTime > TxtTime:\r
-                    ReCreate = True\r
-\r
-            if not  ReCreate:\r
+            if (self.NoDscFileChange (UpdTxtFile)):\r
                 # DSC has not been modified yet\r
                 # So don't have to re-generate other files\r
                 self.Error = 'No DSC file change, skip to create UPD TXT file'\r
@@ -808,73 +1011,152 @@ EndList
                     TxtFd.write("%s.UnusedUpdSpace%d|%s0x%04X|0x%04X|{0}\n" % (Item['space'], SpaceIdx, Default, NextOffset - StartAddr, Offset - NextOffset))\r
                     SpaceIdx = SpaceIdx + 1\r
                 NextOffset = Offset + Item['length']\r
-                if Item['cname'] == 'PcdSerialIoUartDebugEnable':\r
-                    if self.ReleaseMode == False:\r
-                        Item['value'] = 0x01\r
                 TxtFd.write("%s.%s|%s0x%04X|%s|%s\n" % (Item['space'],Item['cname'],Default,Item['offset'] - StartAddr,Item['length'],Item['value']))\r
             TxtFd.close()\r
         return 0\r
 \r
-    def ProcessMultilines (self, String, MaxCharLength):\r
-            Multilines = ''\r
-            StringLength = len(String)\r
-            CurrentStringStart = 0\r
-            StringOffset = 0\r
-            BreakLineDict = []\r
-            if len(String) <= MaxCharLength:\r
-                while (StringOffset < StringLength):\r
-                    if StringOffset >= 1:\r
-                        if String[StringOffset - 1] == '\\' and String[StringOffset] == 'n':\r
-                            BreakLineDict.append (StringOffset + 1)\r
-                    StringOffset += 1\r
-                if BreakLineDict != []:\r
-                    for Each in BreakLineDict:\r
-                        Multilines += "  %s\n" % String[CurrentStringStart:Each].lstrip()\r
-                        CurrentStringStart = Each\r
-                    if StringLength - CurrentStringStart > 0:\r
-                        Multilines += "  %s\n" % String[CurrentStringStart:].lstrip()\r
+    def CreateVarDict (self):\r
+        Error = 0\r
+        self._VarDict = {}\r
+        if len(self._CfgItemList) > 0:\r
+            Item = self._CfgItemList[-1]\r
+            self._VarDict['_LENGTH_'] = '%d' % (Item['offset'] + Item['length'])\r
+        for Item in self._CfgItemList:\r
+            Embed = Item['embed']\r
+            Match = re.match("^(\w+):(\w+):(START|END)", Embed)\r
+            if Match:\r
+                StructName = Match.group(1)\r
+                VarName = '_%s_%s_' % (Match.group(3), StructName)\r
+                if Match.group(3) == 'END':\r
+                    self._VarDict[VarName] = Item['offset'] + Item['length']\r
+                    self._VarDict['_LENGTH_%s_' % StructName] = \\r
+                        self._VarDict['_END_%s_' % StructName] - self._VarDict['_START_%s_' % StructName]\r
+                    if Match.group(2).startswith('TAG_'):\r
+                        if (self.Mode != 'FSP') and (self._VarDict['_LENGTH_%s_' % StructName] % 4):\r
+                            raise Exception("Size of structure '%s' is %d, not DWORD aligned !" % (StructName, self._VarDict['_LENGTH_%s_' % StructName]))\r
+                        self._VarDict['_TAG_%s_' % StructName] = int (Match.group(2)[4:], 16) & 0xFFF\r
                 else:\r
-                    Multilines = "  %s\n" % String\r
+                    self._VarDict[VarName] = Item['offset']\r
+            if Item['marker']:\r
+                self._VarDict['_OFFSET_%s_' % Item['marker'].strip()] = Item['offset']\r
+        return Error\r
+\r
+    def UpdateBsfBitUnit (self, Item):\r
+        BitTotal  = 0\r
+        BitOffset = 0\r
+        StartIdx  = 0\r
+        Unit      = None\r
+        UnitDec   = {1:'BYTE', 2:'WORD', 4:'DWORD', 8:'QWORD'}\r
+        for Idx, SubItem in enumerate(Item['subreg']):\r
+            if Unit is None:\r
+                Unit  = SubItem['bitunit']\r
+            BitLength = SubItem['bitlength']\r
+            BitTotal  += BitLength\r
+            BitOffset += BitLength\r
+\r
+            if BitOffset > 64 or BitOffset > Unit * 8:\r
+                break\r
+\r
+            if BitOffset == Unit * 8:\r
+                for SubIdx in range (StartIdx, Idx + 1):\r
+                    Item['subreg'][SubIdx]['bitunit'] = Unit\r
+                BitOffset = 0\r
+                StartIdx  = Idx + 1\r
+                Unit      = None\r
+\r
+        if BitOffset > 0:\r
+            raise Exception ("Bit fields cannot fit into %s for '%s.%s' !" % (UnitDec[Unit], Item['cname'], SubItem['cname']))\r
+\r
+        ExpectedTotal = Item['length'] * 8\r
+        if Item['length'] * 8 != BitTotal:\r
+            raise Exception ("Bit fields total length (%d) does not match length (%d) of '%s' !" % (BitTotal, ExpectedTotal, Item['cname']))\r
+\r
+    def UpdateDefaultValue (self):\r
+        Error = 0\r
+        for Idx, Item in enumerate(self._CfgItemList):\r
+            if len(Item['subreg']) == 0:\r
+                Value = Item['value']\r
+                if (len(Value) > 0) and (Value[0] == '{' or Value[0] == "'" or Value[0] == '"'):\r
+                    # {XXX} or 'XXX' strings\r
+                    self.FormatListValue(self._CfgItemList[Idx])\r
+                else:\r
+                  Match = re.match("(0x[0-9a-fA-F]+|[0-9]+)", Value)\r
+                  if not Match:\r
+                    NumValue = self.EvaluateExpress (Value)\r
+                    Item['value'] = '0x%X' % NumValue\r
+            else:\r
+                ValArray = self.ValueToByteArray (Item['value'], Item['length'])\r
+                for SubItem in Item['subreg']:\r
+                    SubItem['value']   = self.GetBsfBitFields(SubItem, ValArray)\r
+                self.UpdateBsfBitUnit (Item)\r
+        return Error\r
+\r
+    def ProcessMultilines (self, String, MaxCharLength):\r
+        Multilines = ''\r
+        StringLength = len(String)\r
+        CurrentStringStart = 0\r
+        StringOffset = 0\r
+        BreakLineDict = []\r
+        if len(String) <= MaxCharLength:\r
+            while (StringOffset < StringLength):\r
+                if StringOffset >= 1:\r
+                    if String[StringOffset - 1] == '\\' and String[StringOffset] == 'n':\r
+                        BreakLineDict.append (StringOffset + 1)\r
+                StringOffset += 1\r
+            if BreakLineDict != []:\r
+                for Each in BreakLineDict:\r
+                    Multilines += "  %s\n" % String[CurrentStringStart:Each].lstrip()\r
+                    CurrentStringStart = Each\r
+                if StringLength - CurrentStringStart > 0:\r
+                    Multilines += "  %s\n" % String[CurrentStringStart:].lstrip()\r
             else:\r
-                NewLineStart = 0\r
-                NewLineCount = 0\r
-                FoundSpaceChar = False\r
-                while (StringOffset < StringLength):\r
-                    if StringOffset >= 1:\r
-                        if NewLineCount >= MaxCharLength - 1:\r
-                            if String[StringOffset] == ' ' and StringLength - StringOffset > 10:\r
-                                BreakLineDict.append (NewLineStart + NewLineCount)\r
-                                NewLineStart = NewLineStart + NewLineCount\r
-                                NewLineCount = 0\r
-                                FoundSpaceChar = True\r
-                            elif StringOffset == StringLength - 1 and FoundSpaceChar == False:\r
-                                BreakLineDict.append (0)\r
-                        if String[StringOffset - 1] == '\\' and String[StringOffset] == 'n':\r
-                            BreakLineDict.append (StringOffset + 1)\r
-                            NewLineStart = StringOffset + 1\r
+                Multilines = "  %s\n" % String\r
+        else:\r
+            NewLineStart = 0\r
+            NewLineCount = 0\r
+            FoundSpaceChar = False\r
+            while (StringOffset < StringLength):\r
+                if StringOffset >= 1:\r
+                    if NewLineCount >= MaxCharLength - 1:\r
+                        if String[StringOffset] == ' ' and StringLength - StringOffset > 10:\r
+                            BreakLineDict.append (NewLineStart + NewLineCount)\r
+                            NewLineStart = NewLineStart + NewLineCount\r
                             NewLineCount = 0\r
-                    StringOffset += 1\r
-                    NewLineCount += 1\r
-                if BreakLineDict != []:\r
-                    BreakLineDict.sort ()\r
-                    for Each in BreakLineDict:\r
-                        if Each > 0:\r
-                            Multilines += "  %s\n" % String[CurrentStringStart:Each].lstrip()\r
-                        CurrentStringStart = Each\r
-                    if StringLength - CurrentStringStart > 0:\r
-                        Multilines += "  %s\n" % String[CurrentStringStart:].lstrip()\r
-            return Multilines\r
-\r
-    def CreateField (self, Item, Name, Length, Offset, Struct, BsfName, Help, Option):\r
+                            FoundSpaceChar = True\r
+                        elif StringOffset == StringLength - 1 and FoundSpaceChar == False:\r
+                            BreakLineDict.append (0)\r
+                    if String[StringOffset - 1] == '\\' and String[StringOffset] == 'n':\r
+                        BreakLineDict.append (StringOffset + 1)\r
+                        NewLineStart = StringOffset + 1\r
+                        NewLineCount = 0\r
+                StringOffset += 1\r
+                NewLineCount += 1\r
+            if BreakLineDict != []:\r
+                BreakLineDict.sort ()\r
+                for Each in BreakLineDict:\r
+                    if Each > 0:\r
+                        Multilines += "  %s\n" % String[CurrentStringStart:Each].lstrip()\r
+                    CurrentStringStart = Each\r
+                if StringLength - CurrentStringStart > 0:\r
+                    Multilines += "  %s\n" % String[CurrentStringStart:].lstrip()\r
+        return Multilines\r
+\r
+    def CreateField (self, Item, Name, Length, Offset, Struct, BsfName, Help, Option, BitsLength = None):\r
         PosName    = 28\r
         PosComment = 30\r
         NameLine=''\r
         HelpLine=''\r
         OptionLine=''\r
 \r
+        if Length == 0 and Name == 'Dummy':\r
+            return '\n'\r
+\r
         IsArray = False\r
         if Length in [1,2,4,8]:\r
             Type = "UINT%d" % (Length * 8)\r
+            if Name.startswith("UnusedUpdSpace") and Length != 1:\r
+                IsArray = True\r
+                Type = "UINT8"\r
         else:\r
             IsArray = True\r
             Type = "UINT8"\r
@@ -916,7 +1198,12 @@ EndList
         else:\r
             OffsetStr = '0x%04X' % Offset\r
 \r
-        return "\n/** Offset %s%s%s%s**/\n  %s%s%s;\n" % (OffsetStr, NameLine, HelpLine, OptionLine, Type, ' ' * Space1, Name,)\r
+        if BitsLength is None:\r
+            BitsLength = ''\r
+        else:\r
+            BitsLength = ' : %d' % BitsLength\r
+\r
+        return "\n/** Offset %s%s%s%s**/\n  %s%s%s%s;\n" % (OffsetStr, NameLine, HelpLine, OptionLine, Type, ' ' * Space1, Name, BitsLength)\r
 \r
     def PostProcessBody (self, TextBody):\r
         NewTextBody = []\r
@@ -968,7 +1255,7 @@ EndList
 \r
            if Match and Match.group(3) == 'END':\r
                if (StructName != Match.group(1)) or (VariableName != Match.group(2)):\r
-                   print "Unmatched struct name '%s' and '%s' !"  % (StructName, Match.group(1))\r
+                   print ("Unmatched struct name '%s' and '%s' !"  % (StructName, Match.group(1)))\r
                else:\r
                    if IsUpdHdrDefined != True or IsUpdHeader != True:\r
                       NewTextBody.append ('} %s;\n\n' %  StructName)\r
@@ -977,6 +1264,13 @@ EndList
         NewTextBody.extend(OldTextBody)\r
         return NewTextBody\r
 \r
+    def WriteLinesWithoutTailingSpace (self, HeaderFd, Line):\r
+        TxtBody2 = Line.splitlines(True)\r
+        for Line2 in TxtBody2:\r
+            Line2 = Line2.rstrip()\r
+            Line2 += '\n'\r
+            HeaderFd.write (Line2)\r
+        return 0\r
     def CreateHeaderFile (self, InputHeaderFile):\r
         FvDir = self._FvDir\r
 \r
@@ -984,7 +1278,11 @@ EndList
         HeaderFile = os.path.join(FvDir, HeaderFileName)\r
 \r
         # Check if header needs to be recreated\r
-        ReCreate = False\r
+        if (self.NoDscFileChange (HeaderFile)):\r
+            # DSC has not been modified yet\r
+            # So don't have to re-generate other files\r
+            self.Error = 'No DSC file change, skip to create UPD header file'\r
+            return 256\r
 \r
         TxtBody = []\r
         for Item in self._CfgItemList:\r
@@ -995,21 +1293,25 @@ EndList
                    Chars.append(chr(Value & 0xFF))\r
                    Value = Value >> 8\r
                SignatureStr = ''.join(Chars)\r
-               # Signature will be _T / _M / _S for FSPT / FSPM / FSPS accordingly\r
+               # Signature will be _T / _M / _S / _I for FSPT / FSPM / FSPS /FSPI accordingly\r
                if '_T' in SignatureStr[6:6+2]:\r
                    TxtBody.append("#define FSPT_UPD_SIGNATURE               %s        /* '%s' */\n\n" % (Item['value'], SignatureStr))\r
                elif '_M' in SignatureStr[6:6+2]:\r
                    TxtBody.append("#define FSPM_UPD_SIGNATURE               %s        /* '%s' */\n\n" % (Item['value'], SignatureStr))\r
                elif '_S' in SignatureStr[6:6+2]:\r
                    TxtBody.append("#define FSPS_UPD_SIGNATURE               %s        /* '%s' */\n\n" % (Item['value'], SignatureStr))\r
+               elif '_I' in SignatureStr[6:6+2]:\r
+                   if NoFSPI == False:\r
+                       TxtBody.append("#define FSPI_UPD_SIGNATURE               %s        /* '%s' */\n\n" % (Item['value'], SignatureStr))\r
         TxtBody.append("\n")\r
 \r
         for Region in ['UPD']:\r
             UpdOffsetTable = []\r
-            UpdSignature = ['0x545F', '0x4D5F', '0x535F']   #['_T', '_M', '_S'] signature for FSPT, FSPM, FSPS\r
-            UpdStructure = ['FSPT_UPD', 'FSPM_UPD', 'FSPS_UPD']\r
+            UpdSignature = ['0x545F', '0x4D5F', '0x535F', '0x495F']   #['_T', '_M', '_S', '_I'] signature for FSPT, FSPM, FSPS, FSPI\r
+            UpdStructure = ['FSPT_UPD', 'FSPM_UPD', 'FSPS_UPD', 'FSPI_UPD']\r
             for Item in self._CfgItemList:\r
                 if Item["cname"] == 'Signature' and Item["value"][0:6] in UpdSignature:\r
+                    Item["offset"] = 0 # re-initialize offset to 0 when new UPD structure starting\r
                     UpdOffsetTable.append (Item["offset"])\r
 \r
             for UpdIdx in range(len(UpdOffsetTable)):\r
@@ -1099,12 +1401,15 @@ EndList
         HeaderTFileName = 'FsptUpd.h'\r
         HeaderMFileName = 'FspmUpd.h'\r
         HeaderSFileName = 'FspsUpd.h'\r
+        HeaderIFileName = 'FspiUpd.h'\r
 \r
-        UpdRegionCheck = ['FSPT', 'FSPM', 'FSPS']     # FSPX_UPD_REGION\r
-        UpdConfigCheck = ['FSP_T', 'FSP_M', 'FSP_S']  # FSP_X_CONFIG, FSP_X_TEST_CONFIG, FSP_X_RESTRICTED_CONFIG\r
-        UpdSignatureCheck = ['FSPT_UPD_SIGNATURE', 'FSPM_UPD_SIGNATURE', 'FSPS_UPD_SIGNATURE']\r
-        ExcludedSpecificUpd = 'FSPM_ARCH_UPD'\r
+        UpdRegionCheck = ['FSPT', 'FSPM', 'FSPS', 'FSPI']     # FSPX_UPD_REGION\r
+        UpdConfigCheck = ['FSP_T', 'FSP_M', 'FSP_S', 'FSP_I']  # FSP_X_CONFIG, FSP_X_TEST_CONFIG, FSP_X_RESTRICTED_CONFIG\r
+        UpdSignatureCheck = ['FSPT_UPD_SIGNATURE', 'FSPM_UPD_SIGNATURE', 'FSPS_UPD_SIGNATURE', 'FSPI_UPD_SIGNATURE']\r
+        ExcludedSpecificUpd = ['FSPT_ARCH_UPD', 'FSPM_ARCH_UPD', 'FSPS_ARCH_UPD', 'FSPI_ARCH_UPD']\r
+        ExcludedSpecificUpd1 = ['FSPT_ARCH2_UPD', 'FSPM_ARCH2_UPD', 'FSPS_ARCH2_UPD']\r
 \r
+        IncLines = []\r
         if InputHeaderFile != '':\r
             if not os.path.exists(InputHeaderFile):\r
                  self.Error = "Input header file '%s' does not exist" % InputHeaderFile\r
@@ -1124,12 +1429,15 @@ EndList
             elif UpdRegionCheck[item] == 'FSPS':\r
                 HeaderFd = open(os.path.join(FvDir, HeaderSFileName), "w")\r
                 FileBase = os.path.basename(os.path.join(FvDir, HeaderSFileName))\r
+            elif UpdRegionCheck[item] == 'FSPI':\r
+                HeaderFd = open(os.path.join(FvDir, HeaderIFileName), "w")\r
+                FileBase = os.path.basename(os.path.join(FvDir, HeaderIFileName))\r
             FileName = FileBase.replace(".", "_").upper()\r
             HeaderFd.write("%s\n"   % (__copyright_h__ % date.today().year))\r
             HeaderFd.write("#ifndef __%s__\n"   % FileName)\r
             HeaderFd.write("#define __%s__\n\n" % FileName)\r
             HeaderFd.write("#include <%s>\n\n" % HeaderFileName)\r
-            HeaderFd.write("#pragma pack(push, 1)\n\n")\r
+            HeaderFd.write("#pragma pack(1)\n\n")\r
 \r
             Export = False\r
             for Line in IncLines:\r
@@ -1157,7 +1465,7 @@ EndList
                 if Match:\r
                     StartIndex = Index - 1\r
                 Match = re.match("}\s([_A-Z0-9]+);", Line)\r
-                if Match and (UpdRegionCheck[item] in Match.group(1) or UpdConfigCheck[item] in Match.group(1)) and (ExcludedSpecificUpd not in Match.group(1)):\r
+                if Match and (UpdRegionCheck[item] in Match.group(1) or UpdConfigCheck[item] in Match.group(1)) and (ExcludedSpecificUpd[item] not in Match.group(1)) and (ExcludedSpecificUpd1[item] not in Match.group(1)):\r
                     EndIndex = Index\r
                     StructStart.append(StartIndex)\r
                     StructEnd.append(EndIndex)\r
@@ -1176,8 +1484,8 @@ EndList
                 Index += 1\r
                 for Item in range(len(StructStart)):\r
                     if Index >= StructStartWithComment[Item] and Index <= StructEnd[Item]:\r
-                        HeaderFd.write (Line)\r
-            HeaderFd.write("#pragma pack(pop)\n\n")\r
+                        self.WriteLinesWithoutTailingSpace(HeaderFd, Line)\r
+            HeaderFd.write("#pragma pack()\n\n")\r
             HeaderFd.write("#endif\n")\r
             HeaderFd.close()\r
 \r
@@ -1188,7 +1496,7 @@ EndList
         HeaderFd.write("#ifndef __%s__\n"   % FileName)\r
         HeaderFd.write("#define __%s__\n\n" % FileName)\r
         HeaderFd.write("#include <FspEas.h>\n\n")\r
-        HeaderFd.write("#pragma pack(push, 1)\n\n")\r
+        HeaderFd.write("#pragma pack(1)\n\n")\r
 \r
         for item in range(len(UpdRegionCheck)):\r
             Index = 0\r
@@ -1221,14 +1529,15 @@ EndList
                 Index += 1\r
                 for Item in range(len(StructStart)):\r
                     if Index >= StructStartWithComment[Item] and Index <= StructEnd[Item]:\r
-                        HeaderFd.write (Line)\r
-        HeaderFd.write("#pragma pack(pop)\n\n")\r
+                        self.WriteLinesWithoutTailingSpace(HeaderFd, Line)\r
+        HeaderFd.write("#pragma pack()\n\n")\r
         HeaderFd.write("#endif\n")\r
         HeaderFd.close()\r
 \r
         return 0\r
 \r
     def WriteBsfStruct  (self, BsfFd, Item):\r
+        LogExpr = CLogicalExpression()\r
         if Item['type'] == "None":\r
             Space = "gPlatformFspPkgTokenSpaceGuid"\r
         else:\r
@@ -1250,6 +1559,9 @@ EndList
                 for Option in OptList:\r
                     Option = Option.strip()\r
                     (OpVal, OpStr) = Option.split(':')\r
+                    test = LogExpr.getNumber (OpVal)\r
+                    if test is None:\r
+                        raise Exception("Selection Index '%s' is not a number" % OpVal)\r
                     TmpList.append((OpVal, OpStr))\r
         return  TmpList\r
 \r
@@ -1305,6 +1617,12 @@ EndList
             self.Error = "BSF output file '%s' is invalid" % BsfFile\r
             return 1\r
 \r
+        if (self.NoDscFileChange (BsfFile)):\r
+            # DSC has not been modified yet\r
+            # So don't have to re-generate other files\r
+            self.Error = 'No DSC file change, skip to create UPD BSF file'\r
+            return 256\r
+\r
         Error = 0\r
         OptionDict = {}\r
         BsfFd      = open(BsfFile, "w")\r
@@ -1341,7 +1659,7 @@ EndList
                         if BitsRemain:\r
                             BsfFd.write("        Skip %d bits\n" % BitsRemain)\r
                             BitsGap -= BitsRemain\r
-                        BytesRemain = BitsGap / 8\r
+                        BytesRemain = int(BitsGap / 8)\r
                         if BytesRemain:\r
                             BsfFd.write("        Skip %d bytes\n" % BytesRemain)\r
                     NextOffset = Item['offset'] + Item['length']\r
@@ -1390,17 +1708,24 @@ EndList
 \r
 \r
 def Usage():\r
-    print "GenCfgOpt Version 0.52"\r
-    print "Usage:"\r
-    print "    GenCfgOpt  UPDTXT  PlatformDscFile BuildFvDir                 [-D Macros]"\r
-    print "    GenCfgOpt  HEADER  PlatformDscFile BuildFvDir  InputHFile     [-D Macros]"\r
-    print "    GenCfgOpt  GENBSF  PlatformDscFile BuildFvDir  BsfOutFile     [-D Macros]"\r
+    print ("GenCfgOpt Version 0.59")\r
+    print ("Usage:")\r
+    print ("    GenCfgOpt  UPDTXT  PlatformDscFile BuildFvDir                 [-D Macros]")\r
+    print ("    GenCfgOpt  HEADER  PlatformDscFile BuildFvDir  InputHFile     [-D Macros]")\r
+    print ("    GenCfgOpt  GENBSF  PlatformDscFile BuildFvDir  BsfOutFile     [-D Macros]")\r
 \r
 def Main():\r
     #\r
     # Parse the options and args\r
     #\r
+    i = 1\r
+\r
     GenCfgOpt = CGenCfgOpt()\r
+    while i < len(sys.argv):\r
+        if sys.argv[i].strip().lower() == "--pcd":\r
+            BuildOptionPcd.append(sys.argv[i+1])\r
+            i += 1\r
+        i += 1\r
     argc = len(sys.argv)\r
     if argc < 4:\r
         Usage()\r
@@ -1408,7 +1733,7 @@ def Main():
     else:\r
         DscFile = sys.argv[2]\r
         if not os.path.exists(DscFile):\r
-            print "ERROR: Cannot open DSC file '%s' !" % DscFile\r
+            print ("ERROR: Cannot open DSC file '%s' !" % DscFile)\r
             return 2\r
 \r
         OutFile = ''\r
@@ -1418,21 +1743,21 @@ def Main():
             else:\r
                 OutFile = sys.argv[4]\r
                 Start = 5\r
-            GenCfgOpt.ParseBuildMode(sys.argv[3])\r
-            if GenCfgOpt.ParseMacros(sys.argv[Start:]) != 0:\r
-                print "ERROR: Macro parsing failed !"\r
-                return 3\r
+            if argc > Start:\r
+                if GenCfgOpt.ParseMacros(sys.argv[Start:]) != 0:\r
+                    print ("ERROR: Macro parsing failed !")\r
+                    return 3\r
 \r
         FvDir = sys.argv[3]\r
         if not os.path.exists(FvDir):\r
             os.makedirs(FvDir)\r
 \r
         if GenCfgOpt.ParseDscFile(DscFile, FvDir) != 0:\r
-            print "ERROR: %s !" % GenCfgOpt.Error\r
+            print ("ERROR: %s !" % GenCfgOpt.Error)\r
             return 5\r
 \r
         if GenCfgOpt.UpdateSubRegionDefaultValue() != 0:\r
-            print "ERROR: %s !" % GenCfgOpt.Error\r
+            print ("ERROR: %s !" % GenCfgOpt.Error)\r
             return 7\r
 \r
         if sys.argv[1] == "UPDTXT":\r
@@ -1440,23 +1765,35 @@ def Main():
             if Ret != 0:\r
                 # No change is detected\r
                 if Ret == 256:\r
-                    print "INFO: %s !" % (GenCfgOpt.Error)\r
+                    print ("INFO: %s !" % (GenCfgOpt.Error))\r
                 else :\r
-                    print "ERROR: %s !" % (GenCfgOpt.Error)\r
+                    print ("ERROR: %s !" % (GenCfgOpt.Error))\r
             return Ret\r
         elif sys.argv[1] == "HEADER":\r
-            if GenCfgOpt.CreateHeaderFile(OutFile) != 0:\r
-                print "ERROR: %s !" % GenCfgOpt.Error\r
-                return 8\r
+            Ret = GenCfgOpt.CreateHeaderFile(OutFile)\r
+            if Ret != 0:\r
+                # No change is detected\r
+                if Ret == 256:\r
+                    print ("INFO: %s !" % (GenCfgOpt.Error))\r
+                else :\r
+                    print ("ERROR: %s !" % (GenCfgOpt.Error))\r
+                    return 8\r
+            return Ret\r
         elif sys.argv[1] == "GENBSF":\r
-            if GenCfgOpt.GenerateBsfFile(OutFile) != 0:\r
-                print "ERROR: %s !" % GenCfgOpt.Error\r
-                return 9\r
+            Ret = GenCfgOpt.GenerateBsfFile(OutFile)\r
+            if Ret != 0:\r
+                # No change is detected\r
+                if Ret == 256:\r
+                    print ("INFO: %s !" % (GenCfgOpt.Error))\r
+                else :\r
+                    print ("ERROR: %s !" % (GenCfgOpt.Error))\r
+                    return 9\r
+            return Ret\r
         else:\r
             if argc < 5:\r
                 Usage()\r
                 return 1\r
-            print "ERROR: Unknown command '%s' !" % sys.argv[1]\r
+            print ("ERROR: Unknown command '%s' !" % sys.argv[1])\r
             Usage()\r
             return 1\r
         return 0\r