BaseTools/Build: Add SDL support

1.BaseTool add ATTRIBUTE (+/-RT, RO) support in PCD declaration in DSC file
2.BaseTool collect valid PCD value in DEC file and generate data base for runtime sanity check
3.BaseTool support SetPcd error.

Contributed-under: TianoCore Contribution Agreement 1.0
Signed-off-by: "Bob Feng" <bob.c.feng@intel.com>
Reviewed-by: "Chen, Hesheng" <hesheng.chen@intel.com>
Reviewed-by: "Liu, Yingke D" <yingke.d.liu@intel.com>

git-svn-id: https://svn.code.sf.net/p/edk2/code/trunk/edk2@17158 6f19259b-4bc3-4df7-8a09-765794883524
diff --git a/BaseTools/Source/Python/AutoGen/AutoGen.py b/BaseTools/Source/Python/AutoGen/AutoGen.py
index cd61e8e..a1e1818 100644
--- a/BaseTools/Source/Python/AutoGen/AutoGen.py
+++ b/BaseTools/Source/Python/AutoGen/AutoGen.py
@@ -1,7 +1,7 @@
 ## @file

 # Generate AutoGen.h, AutoGen.c and *.depex files

 #

-# Copyright (c) 2007 - 2014, Intel Corporation. All rights reserved.<BR>

+# Copyright (c) 2007 - 2015, Intel Corporation. All rights reserved.<BR>

 # This program and the accompanying materials

 # are licensed and made available under the terms and conditions of the BSD License

 # which accompanies this distribution.  The full text of the license may be found at

@@ -1813,6 +1813,9 @@
             if not IsValid:

                 EdkLogger.error('build', FORMAT_INVALID, Cause, File=self.MetaFile,

                                 ExtraData="%s.%s" % (ToPcd.TokenSpaceGuidCName, ToPcd.TokenCName))

+            ToPcd.validateranges = FromPcd.validateranges

+            ToPcd.validlists = FromPcd.validlists

+            ToPcd.expressions = FromPcd.expressions

 

         if ToPcd.DatumType == "VOID*" and ToPcd.MaxDatumSize in ['', None]:

             EdkLogger.debug(EdkLogger.DEBUG_9, "No MaxDatumSize specified for PCD %s.%s" \

diff --git a/BaseTools/Source/Python/AutoGen/GenC.py b/BaseTools/Source/Python/AutoGen/GenC.py
index a140cc8..9bdb036 100644
--- a/BaseTools/Source/Python/AutoGen/GenC.py
+++ b/BaseTools/Source/Python/AutoGen/GenC.py
@@ -1,7 +1,7 @@
 ## @file

 # Routines for generating AutoGen.h and AutoGen.c

 #

-# Copyright (c) 2007 - 2013, Intel Corporation. All rights reserved.<BR>

+# Copyright (c) 2007 - 2015, Intel Corporation. All rights reserved.<BR>

 # This program and the accompanying materials

 # are licensed and made available under the terms and conditions of the BSD License

 # which accompanies this distribution.  The full text of the license may be found at

@@ -786,6 +786,7 @@
     DatumSizeLib = gDatumSizeStringDatabaseLib[Pcd.DatumType]

     GetModeName = '_PCD_GET_MODE_' + gDatumSizeStringDatabaseH[Pcd.DatumType] + '_' + Pcd.TokenCName

     SetModeName = '_PCD_SET_MODE_' + gDatumSizeStringDatabaseH[Pcd.DatumType] + '_' + Pcd.TokenCName

+    SetModeStatusName = '_PCD_SET_MODE_' + gDatumSizeStringDatabaseH[Pcd.DatumType] + '_S_' + Pcd.TokenCName

 

     PcdExCNameList  = []

     if Pcd.Type in gDynamicExPcd:

@@ -805,21 +806,27 @@
             AutoGenH.Append('// #define %s  LibPcdGetEx%s(&%s, %s)\n' % (GetModeName, DatumSizeLib, Pcd.TokenSpaceGuidCName, PcdTokenName))

             if Pcd.DatumType == 'VOID*':

                 AutoGenH.Append('// #define %s(SizeOfBuffer, Buffer)  LibPcdSetEx%s(&%s, %s, (SizeOfBuffer), (Buffer))\n' % (SetModeName, DatumSizeLib, Pcd.TokenSpaceGuidCName, PcdTokenName))

+                AutoGenH.Append('// #define %s(SizeOfBuffer, Buffer)  LibPcdSetEx%sS(&%s, %s, (SizeOfBuffer), (Buffer))\n' % (SetModeStatusName, DatumSizeLib, Pcd.TokenSpaceGuidCName, PcdTokenName))

             else:

                 AutoGenH.Append('// #define %s(Value)  LibPcdSetEx%s(&%s, %s, (Value))\n' % (SetModeName, DatumSizeLib, Pcd.TokenSpaceGuidCName, PcdTokenName))

+                AutoGenH.Append('// #define %s(Value)  LibPcdSetEx%sS(&%s, %s, (Value))\n' % (SetModeStatusName, DatumSizeLib, Pcd.TokenSpaceGuidCName, PcdTokenName))

         else:

             AutoGenH.Append('#define %s  %s\n' % (PcdTokenName, PcdExTokenName))

             AutoGenH.Append('#define %s  LibPcdGetEx%s(&%s, %s)\n' % (GetModeName, DatumSizeLib, Pcd.TokenSpaceGuidCName, PcdTokenName))

             if Pcd.DatumType == 'VOID*':

                 AutoGenH.Append('#define %s(SizeOfBuffer, Buffer)  LibPcdSetEx%s(&%s, %s, (SizeOfBuffer), (Buffer))\n' % (SetModeName, DatumSizeLib, Pcd.TokenSpaceGuidCName, PcdTokenName))

+                AutoGenH.Append('#define %s(SizeOfBuffer, Buffer)  LibPcdSetEx%sS(&%s, %s, (SizeOfBuffer), (Buffer))\n' % (SetModeStatusName, DatumSizeLib, Pcd.TokenSpaceGuidCName, PcdTokenName))

             else:

                 AutoGenH.Append('#define %s(Value)  LibPcdSetEx%s(&%s, %s, (Value))\n' % (SetModeName, DatumSizeLib, Pcd.TokenSpaceGuidCName, PcdTokenName))

+                AutoGenH.Append('#define %s(Value)  LibPcdSetEx%sS(&%s, %s, (Value))\n' % (SetModeStatusName, DatumSizeLib, Pcd.TokenSpaceGuidCName, PcdTokenName))

     elif Pcd.Type in gDynamicPcd:

         AutoGenH.Append('#define %s  LibPcdGet%s(%s)\n' % (GetModeName, DatumSizeLib, PcdTokenName))

         if Pcd.DatumType == 'VOID*':

             AutoGenH.Append('#define %s(SizeOfBuffer, Buffer)  LibPcdSet%s(%s, (SizeOfBuffer), (Buffer))\n' %(SetModeName, DatumSizeLib, PcdTokenName))

+            AutoGenH.Append('#define %s(SizeOfBuffer, Buffer)  LibPcdSet%sS(%s, (SizeOfBuffer), (Buffer))\n' % (SetModeStatusName, DatumSizeLib, PcdTokenName))

         else:

             AutoGenH.Append('#define %s(Value)  LibPcdSet%s(%s, (Value))\n' % (SetModeName, DatumSizeLib, PcdTokenName))

+            AutoGenH.Append('#define %s(Value)  LibPcdSet%sS(%s, (Value))\n' % (SetModeStatusName, DatumSizeLib, PcdTokenName))

     else:

         PcdVariableName = '_gPcd_' + gItemTypeStringDatabase[Pcd.Type] + '_' + Pcd.TokenCName

         Const = 'const'

@@ -963,8 +970,10 @@
         if Pcd.Type == TAB_PCDS_PATCHABLE_IN_MODULE:

             if Pcd.DatumType == 'VOID*':

                 AutoGenH.Append('#define %s(SizeOfBuffer, Buffer)  LibPatchPcdSetPtr(_gPcd_BinaryPatch_%s, (UINTN)_PCD_PATCHABLE_%s_SIZE, (SizeOfBuffer), (Buffer))\n' % (SetModeName, Pcd.TokenCName, Pcd.TokenCName))

+                AutoGenH.Append('#define %s(SizeOfBuffer, Buffer)  LibPatchPcdSetPtrS(_gPcd_BinaryPatch_%s, (UINTN)_PCD_PATCHABLE_%s_SIZE, (SizeOfBuffer), (Buffer))\n' % (SetModeStatusName, Pcd.TokenCName, Pcd.TokenCName))

             else:

                 AutoGenH.Append('#define %s(Value)  (%s = (Value))\n' % (SetModeName, PcdVariableName))

+                AutoGenH.Append('#define %s(Value)  ((%s = (Value)), RETURN_SUCCESS) \n' % (SetModeStatusName, PcdVariableName))

         else:

             AutoGenH.Append('//#define %s  ASSERT(FALSE)  // It is not allowed to set value for a FIXED_AT_BUILD PCD\n' % SetModeName)

 

@@ -1018,6 +1027,7 @@
     DatumSizeLib= gDatumSizeStringDatabaseLib[DatumType]

     GetModeName = '_PCD_GET_MODE_' + DatumSize + '_' + TokenCName

     SetModeName = '_PCD_SET_MODE_' + DatumSize + '_' + TokenCName

+    SetModeStatusName = '_PCD_SET_MODE_' + DatumSize + '_S_' + TokenCName

 

     Type = ''

     Array = ''

@@ -1046,28 +1056,35 @@
             AutoGenH.Append('// #define %s  LibPcdGetEx%s(&%s, %s)\n' % (GetModeName, DatumSizeLib, Pcd.TokenSpaceGuidCName, PcdTokenName))

             if Pcd.DatumType == 'VOID*':

                 AutoGenH.Append('// #define %s(SizeOfBuffer, Buffer)  LibPcdSetEx%s(&%s, %s, (SizeOfBuffer), (Buffer))\n' % (SetModeName, DatumSizeLib, Pcd.TokenSpaceGuidCName, PcdTokenName))

+                AutoGenH.Append('// #define %s(SizeOfBuffer, Buffer)  LibPcdSetEx%sS(&%s, %s, (SizeOfBuffer), (Buffer))\n' % (SetModeStatusName, DatumSizeLib, Pcd.TokenSpaceGuidCName, PcdTokenName))

             else:

                 AutoGenH.Append('// #define %s(Value)  LibPcdSetEx%s(&%s, %s, (Value))\n' % (SetModeName, DatumSizeLib, Pcd.TokenSpaceGuidCName, PcdTokenName))

+                AutoGenH.Append('// #define %s(Value)  LibPcdSetEx%sS(&%s, %s, (Value))\n' % (SetModeStatusName, DatumSizeLib, Pcd.TokenSpaceGuidCName, PcdTokenName))

         else:

             AutoGenH.Append('#define %s  %s\n' % (PcdTokenName, PcdExTokenName))

             AutoGenH.Append('#define %s  LibPcdGetEx%s(&%s, %s)\n' % (GetModeName, DatumSizeLib, Pcd.TokenSpaceGuidCName, PcdTokenName))

             if Pcd.DatumType == 'VOID*':

                 AutoGenH.Append('#define %s(SizeOfBuffer, Buffer)  LibPcdSetEx%s(&%s, %s, (SizeOfBuffer), (Buffer))\n' % (SetModeName, DatumSizeLib, Pcd.TokenSpaceGuidCName, PcdTokenName))

+                AutoGenH.Append('#define %s(SizeOfBuffer, Buffer)  LibPcdSetEx%sS(&%s, %s, (SizeOfBuffer), (Buffer))\n' % (SetModeStatusName, DatumSizeLib, Pcd.TokenSpaceGuidCName, PcdTokenName))

             else:

                 AutoGenH.Append('#define %s(Value)  LibPcdSetEx%s(&%s, %s, (Value))\n' % (SetModeName, DatumSizeLib, Pcd.TokenSpaceGuidCName, PcdTokenName))

+                AutoGenH.Append('#define %s(Value)  LibPcdSetEx%sS(&%s, %s, (Value))\n' % (SetModeStatusName, DatumSizeLib, Pcd.TokenSpaceGuidCName, PcdTokenName))

     else:

         AutoGenH.Append('#define _PCD_TOKEN_%s  %dU\n' % (TokenCName, TokenNumber))

     if PcdItemType in gDynamicPcd:

         AutoGenH.Append('#define %s  LibPcdGet%s(%s)\n' % (GetModeName, DatumSizeLib, PcdTokenName))

         if DatumType == 'VOID*':

             AutoGenH.Append('#define %s(SizeOfBuffer, Buffer)  LibPcdSet%s(%s, (SizeOfBuffer), (Buffer))\n' %(SetModeName, DatumSizeLib, PcdTokenName))

+            AutoGenH.Append('#define %s(SizeOfBuffer, Buffer)  LibPcdSet%sS(%s, (SizeOfBuffer), (Buffer))\n' % (SetModeStatusName, DatumSizeLib, PcdTokenName))

         else:

             AutoGenH.Append('#define %s(Value)  LibPcdSet%s(%s, (Value))\n' % (SetModeName, DatumSizeLib, PcdTokenName))

+            AutoGenH.Append('#define %s(Value)  LibPcdSet%sS(%s, (Value))\n' % (SetModeStatusName, DatumSizeLib, PcdTokenName))

     if PcdItemType == TAB_PCDS_PATCHABLE_IN_MODULE:

         PcdVariableName = '_gPcd_' + gItemTypeStringDatabase[TAB_PCDS_PATCHABLE_IN_MODULE] + '_' + TokenCName

         AutoGenH.Append('extern volatile %s _gPcd_BinaryPatch_%s%s;\n' %(DatumType, TokenCName, Array) )

         AutoGenH.Append('#define %s  %s_gPcd_BinaryPatch_%s\n' %(GetModeName, Type, TokenCName))

         AutoGenH.Append('#define %s(Value)  (%s = (Value))\n' % (SetModeName, PcdVariableName))

+        AutoGenH.Append('#define %s(Value)  ((%s = (Value)), RETURN_SUCCESS)\n' % (SetModeStatusName, PcdVariableName))

     if PcdItemType == TAB_PCDS_FIXED_AT_BUILD or PcdItemType == TAB_PCDS_FEATURE_FLAG:

         key = ".".join((Pcd.TokenSpaceGuidCName,Pcd.TokenCName))

         

diff --git a/BaseTools/Source/Python/AutoGen/GenPcdDb.py b/BaseTools/Source/Python/AutoGen/GenPcdDb.py
index e995e14..4ccd2d6 100644
--- a/BaseTools/Source/Python/AutoGen/GenPcdDb.py
+++ b/BaseTools/Source/Python/AutoGen/GenPcdDb.py
@@ -1,7 +1,7 @@
 ## @file

 # Routines for generating Pcd Database

 #

-# Copyright (c) 2013, Intel Corporation. All rights reserved.<BR>

+# Copyright (c) 2013 - 2015, Intel Corporation. All rights reserved.<BR>

 # This program and the accompanying materials

 # are licensed and made available under the terms and conditions of the BSD License

 # which accompanies this distribution.  The full text of the license may be found at

@@ -14,8 +14,12 @@
 from Common.Misc import *

 from Common.String import StringToArray

 from struct import pack

+from ValidCheckingInfoObject import VAR_CHECK_PCD_VARIABLE_TAB_CONTAINER

+from ValidCheckingInfoObject import VAR_CHECK_PCD_VARIABLE_TAB

+from ValidCheckingInfoObject import VAR_VALID_OBJECT_FACTORY

+from Common.VariableAttributes import VariableAttributes

 

-DATABASE_VERSION = 4

+DATABASE_VERSION = 5

 

 gPcdDatabaseAutoGenC = TemplateString("""

 //

@@ -444,7 +448,7 @@
             RawDataList = []

         DbComItemList.__init__(self, ItemSize, DataList, RawDataList)

     def PackData(self):

-        PackStr = "=LLHH"

+        PackStr = "=LLHHLHH"

         Buffer = ''

         for DataList in self.RawDataList:

             for Data in DataList:

@@ -452,7 +456,10 @@
                                GetIntegerValue(Data[0]),

                                GetIntegerValue(Data[1]),

                                GetIntegerValue(Data[2]),

-                               GetIntegerValue(Data[3]))

+                               GetIntegerValue(Data[3]),

+                               GetIntegerValue(Data[4]),

+                               GetIntegerValue(Data[5]),

+                               GetIntegerValue(0))

         return Buffer

 

 class DbStringHeadTableItemList(DbItemList):

@@ -712,7 +719,7 @@
     # DbItemList to DbStringHeadTableItemList

     DbStringHeadValue = DbStringHeadTableItemList(4, RawDataList = StringHeadValue)

     VariableTable = Dict['VARIABLE_DB_VALUE']

-    DbVariableTable = DbVariableTableItemList(12, RawDataList = VariableTable)

+    DbVariableTable = DbVariableTableItemList(20, RawDataList = VariableTable)

     NumberOfSkuEnabledPcd = GetIntegerValue(Dict['SKU_HEAD_SIZE'])

     Dict['SKUHEAD_TABLE_VALUE'] = [(0,0) for i in xrange(NumberOfSkuEnabledPcd)]

     SkuTable = Dict['SKUHEAD_TABLE_VALUE']  # Generated later

@@ -852,7 +859,7 @@
     for VariableEntries in VariableTable:

         skuindex = 0

         for VariableEntryPerSku in VariableEntries:

-            (VariableHeadGuidIndex, VariableHeadStringIndex, SKUVariableOffset, VariableOffset, VariableRefTable) = VariableEntryPerSku[:]

+            (VariableHeadGuidIndex, VariableHeadStringIndex, SKUVariableOffset, VariableOffset, VariableRefTable, VariableAttribute) = VariableEntryPerSku[:]

             DbIndex = 0

             DbOffset = FixedHeaderLen

             for DbIndex in xrange(len(DbTotal)):

@@ -867,8 +874,8 @@
             skuindex += 1

             if DbIndex >= InitTableNum:

                 assert(False)

-

-            VariableEntryPerSku[:] = (VariableHeadStringIndex, DbOffset, VariableHeadGuidIndex, SKUVariableOffset)

+            VarAttr, VarProp = VariableAttributes.GetVarAttributes(VariableAttribute)

+            VariableEntryPerSku[:] = (VariableHeadStringIndex, DbOffset, VariableHeadGuidIndex, SKUVariableOffset, VarAttr, VarProp)

 

     # calculate various table offset now

     DbTotalLength = FixedHeaderLen

@@ -1113,6 +1120,7 @@
     NumberOfSizeItems = 0

     NumberOfSkuEnabledPcd = 0

     GuidList = []

+    VarCheckTab = VAR_CHECK_PCD_VARIABLE_TAB_CONTAINER()

     i = 0

     ReorderedDynPcdList = GetOrderedDynamicPcdList(Platform.DynamicPcdList, Platform.PcdTokenNumber)

     for Pcd in ReorderedDynPcdList:

@@ -1182,6 +1190,29 @@
             SkuIdIndex += 1

     

             if len(Sku.VariableName) > 0:

+                VariableGuidStructure = Sku.VariableGuidValue

+                VariableGuid = GuidStructureStringToGuidValueName(VariableGuidStructure)

+                if Platform.Platform.VarCheckFlag:

+                    var_check_obj = VAR_CHECK_PCD_VARIABLE_TAB(VariableGuidStructure, StringToArray(Sku.VariableName))

+                    try:

+                        var_check_obj.push_back(VAR_VALID_OBJECT_FACTORY.Get_valid_object(Pcd, Sku.VariableOffset))

+                        VarAttr, _ = VariableAttributes.GetVarAttributes(Sku.VariableAttribute)

+                        var_check_obj.SetAttributes(VarAttr)

+                        var_check_obj.UpdateSize()

+                        VarCheckTab.push_back(var_check_obj)

+                    except Exception:

+                        ValidInfo = ''

+                        if Pcd.validateranges:

+                            ValidInfo = Pcd.validateranges[0]

+                        if Pcd.validlists:

+                            ValidInfo = Pcd.validlists[0]

+                        if ValidInfo:

+                            EdkLogger.error("build", PCD_VALIDATION_INFO_ERROR,

+                                                "The PCD '%s.%s' Validation information defined in DEC file has incorrect format." % (Pcd.TokenSpaceGuidCName, Pcd.TokenCName),

+                                                ExtraData = "[%s]" % str(ValidInfo))

+                        else:

+                            EdkLogger.error("build", PCD_VALIDATION_INFO_ERROR,

+                                                "The PCD '%s.%s' Validation information defined in DEC file has incorrect format." % (Pcd.TokenSpaceGuidCName, Pcd.TokenCName))

                 Pcd.TokenTypeList += ['PCD_TYPE_HII']

                 Pcd.InitString = 'INIT'

                 # Store all variable names of one HII PCD under different SKU to stringTable

@@ -1215,8 +1246,6 @@
                         

                 VariableHeadStringIndex = VariableHeadList[SkuIdIndex - 2]

                 # store VariableGuid to GuidTable and get the VariableHeadGuidIndex

-                VariableGuidStructure = Sku.VariableGuidValue

-                VariableGuid = GuidStructureStringToGuidValueName(VariableGuidStructure)

 

                 if VariableGuid not in GuidList:

                     GuidList += [VariableGuid]

@@ -1268,7 +1297,7 @@
                     # the Pcd default value was filled before

                     VariableOffset = len(Dict['VARDEF_DB_VALUE_' + Pcd.DatumType]) - 1

                     VariableRefTable = Dict['VARDEF_DB_VALUE_' + Pcd.DatumType]

-                VariableDbValueList.append([VariableHeadGuidIndex, VariableHeadStringIndex, Sku.VariableOffset, VariableOffset, VariableRefTable])

+                VariableDbValueList.append([VariableHeadGuidIndex, VariableHeadStringIndex, Sku.VariableOffset, VariableOffset, VariableRefTable, Sku.VariableAttribute])

 

             elif Sku.VpdOffset != '':

                 Pcd.TokenTypeList += ['PCD_TYPE_VPD']

@@ -1600,6 +1629,9 @@
                 

         AutoGenC.Append(gPcdDatabaseAutoGenC.Replace(Dict))

     

+    if Platform.Platform.VarCheckFlag:

+        dest = os.path.join(Platform.BuildDir, 'FV')

+        VarCheckTab.dump(dest, Phase)

     Buffer = BuildExDataBase(Dict)

     return AutoGenH, AutoGenC, Buffer

 

diff --git a/BaseTools/Source/Python/AutoGen/ValidCheckingInfoObject.py b/BaseTools/Source/Python/AutoGen/ValidCheckingInfoObject.py
new file mode 100644
index 0000000..4a6e031
--- /dev/null
+++ b/BaseTools/Source/Python/AutoGen/ValidCheckingInfoObject.py
@@ -0,0 +1,351 @@
+# Copyright (c) 2015, Intel Corporation. All rights reserved.<BR>

+# This program and the accompanying materials

+# are licensed and made available under the terms and conditions of the BSD License

+# which accompanies this distribution.  The full text of the license may be found at

+# http://opensource.org/licenses/bsd-license.php

+#

+# THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,

+# WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.

+

+#

+# This file is used to collect the Variable checking information

+#

+

+# #

+# Import Modules

+#

+import os

+from Common.RangeExpression import RangeExpression

+from Common.Misc import *

+from StringIO import StringIO

+from struct import pack

+

+class VAR_CHECK_PCD_VARIABLE_TAB_CONTAINER(object):

+    def __init__(self):

+        self.var_check_info = []

+        

+    def push_back(self, var_check_tab):

+        for tab in self.var_check_info:

+            if tab.equal(var_check_tab):

+                tab.merge(var_check_tab)

+                break

+        else:

+            self.var_check_info.append(var_check_tab)

+        

+    def dump(self, dest, Phase):

+        

+        FormatMap = {}

+        FormatMap[1] = "=B"

+        FormatMap[2] = "=H"

+        FormatMap[4] = "=L"

+        FormatMap[8] = "=Q"

+        

+        if not os.path.isabs(dest):

+            return

+        if not os.path.exists(dest):

+            os.mkdir(dest)

+        BinFileName = "PcdVarCheck.bin"

+        BinFilePath = os.path.join(dest, BinFileName)

+        Buffer = ''

+        index = 0

+        for var_check_tab in self.var_check_info:

+            index += 1

+            realLength = 0

+            realLength += 32

+            Name = var_check_tab.Name[1:-1]

+            NameChars = Name.split(",")

+            realLength += len(NameChars)

+            if (index < len(self.var_check_info) and realLength % 4) or (index == len(self.var_check_info) and len(var_check_tab.validtab) > 0 and realLength % 4):

+                realLength += (4 - (realLength % 4))

+            itemIndex = 0

+            for item in var_check_tab.validtab:

+                itemIndex += 1

+                realLength += 5

+                for v_data in item.data:

+                    if type(v_data) == type(1):

+                        realLength += item.StorageWidth

+                    else:

+                        realLength += item.StorageWidth

+                        realLength += item.StorageWidth

+                if (index == len(self.var_check_info)) :

+                    if (itemIndex < len(var_check_tab.validtab)) and realLength % 4:

+                        realLength += (4 - (realLength % 4))

+                else:

+                    if realLength % 4:

+                        realLength += (4 - (realLength % 4))

+            var_check_tab.Length = realLength

+        realLength = 0

+        index = 0

+        for var_check_tab in self.var_check_info:

+            index += 1

+

+            b = pack("=H", var_check_tab.Revision)

+            Buffer += b

+            realLength += 2

+

+            b = pack("=H", var_check_tab.HeaderLength)

+            Buffer += b

+            realLength += 2

+

+            b = pack("=L", var_check_tab.Length)

+            Buffer += b

+            realLength += 4

+

+            b = pack("=B", var_check_tab.Type)

+            Buffer += b

+            realLength += 1

+

+            for i in range(0, 3):

+                b = pack("=B", var_check_tab.Reserved)

+                Buffer += b

+                realLength += 1

+

+            b = pack("=L", var_check_tab.Attributes)

+            Buffer += b

+            realLength += 4

+

+            Guid = var_check_tab.Guid

+            b = pack('=LHHBBBBBBBB',

+                Guid[0],

+                Guid[1],

+                Guid[2],

+                Guid[3],

+                Guid[4],

+                Guid[5],

+                Guid[6],

+                Guid[7],

+                Guid[8],

+                Guid[9],

+                Guid[10],

+                )

+            Buffer += b

+            realLength += 16

+

+            Name = var_check_tab.Name[1:-1]

+            NameChars = Name.split(",")

+            for NameChar in NameChars:

+                NameCharNum = int(NameChar, 16)

+                b = pack("=B", NameCharNum)

+                Buffer += b

+                realLength += 1

+

+            if (index < len(self.var_check_info) and realLength % 4) or (index == len(self.var_check_info) and len(var_check_tab.validtab) > 0 and realLength % 4):

+                for i in range(4 - (realLength % 4)):

+                    b = pack("=B", var_check_tab.pad)

+                    Buffer += b

+                    realLength += 1

+            itemIndex = 0

+            for item in var_check_tab.validtab:

+                itemIndex += 1

+

+                b = pack("=B", item.Type)

+                Buffer += b

+                realLength += 1

+

+                b = pack("=B", item.Length)

+                Buffer += b

+                realLength += 1

+

+                b = pack("=H", int(item.VarOffset, 16))

+                Buffer += b

+                realLength += 2

+

+                b = pack("=B", item.StorageWidth)

+                Buffer += b

+                realLength += 1

+                

+                for v_data in item.data:

+                    if type(v_data) == type(1):

+                        b = pack(FormatMap[item.StorageWidth], v_data)

+                        Buffer += b

+                        realLength += item.StorageWidth

+                    else:

+                        b = pack(FormatMap[item.StorageWidth], v_data[0])

+                        Buffer += b

+                        realLength += item.StorageWidth

+                        b = pack(FormatMap[item.StorageWidth], v_data[1])

+                        Buffer += b

+                        realLength += item.StorageWidth

+

+                if (index == len(self.var_check_info)) :

+                    if (itemIndex < len(var_check_tab.validtab)) and realLength % 4:

+                        for i in range(4 - (realLength % 4)):

+                            b = pack("=B", var_check_tab.pad)

+                            Buffer += b

+                            realLength += 1

+                else:

+                    if realLength % 4:

+                        for i in range(4 - (realLength % 4)):

+                            b = pack("=B", var_check_tab.pad)

+                            Buffer += b

+                            realLength += 1

+        

+        DbFile = StringIO()

+        if Phase == 'DXE' and os.path.exists(BinFilePath):

+            BinFile = open(BinFilePath, "rb")

+            BinBuffer = BinFile.read()

+            BinFile.close()

+            BinBufferSize = len(BinBuffer)

+            if (BinBufferSize % 4):

+                for i in range(4 - (BinBufferSize % 4)):

+                    b = pack("=B", VAR_CHECK_PCD_VARIABLE_TAB.pad)

+                    BinBuffer += b

+            Buffer = BinBuffer + Buffer

+        DbFile.write(Buffer)

+        SaveFileOnChange(BinFilePath, DbFile.getvalue(), True)

+    

+

+class VAR_CHECK_PCD_VARIABLE_TAB(object):

+    pad = 0xDA

+    def __init__(self, TokenSpaceGuid, PcdCName):

+        self.Revision = 0x0001

+        self.HeaderLength = 0

+        self.Length = 0  # Length include this header

+        self.Type = 0

+        self.Reserved = 0

+        self.Attributes = 0x00000000

+        self.Guid = eval("[" + TokenSpaceGuid.replace("{", "").replace("}", "") + "]")

+        self.Name = PcdCName

+        self.validtab = []

+

+    def UpdateSize(self):

+        self.HeaderLength = 32 + len(self.Name.split(","))

+        self.Length = 32 + len(self.Name.split(",")) + self.GetValidTabLen()

+    

+    def GetValidTabLen(self):

+        validtablen = 0

+        for item in self.validtab:

+            validtablen += item.Length  

+        return validtablen 

+    

+    def SetAttributes(self, attributes):

+        self.Attributes = attributes

+            

+    def push_back(self, valid_obj):

+        if valid_obj is not None:

+            self.validtab.append(valid_obj)

+        

+    def equal(self, varchecktab):

+        if self.Guid == varchecktab.Guid and self.Name == varchecktab.Name:

+            return True

+        else:

+            return False

+        

+    def merge(self, varchecktab):

+        for validobj in varchecktab.validtab:

+            if validobj in self.validtab:

+                continue

+            self.validtab.append(validobj)

+        self.UpdateSize()

+

+

+class VAR_CHECK_PCD_VALID_OBJ(object):

+    def __init__(self, VarOffset, data, PcdDataType):

+        self.Type = 1

+        self.Length = 0  # Length include this header

+        self.VarOffset = VarOffset

+        self.StorageWidth = 0

+        self.PcdDataType = PcdDataType.strip()

+        self.rawdata = data

+        self.data = set()

+        self.ValidData = True

+        self.updateStorageWidth()

+    def updateStorageWidth(self):

+        if self.PcdDataType == "UINT8" or self.PcdDataType == "BOOLEAN":

+            self.StorageWidth = 1

+        elif self.PcdDataType == "UINT16":

+            self.StorageWidth = 2

+        elif self.PcdDataType == "UINT32":

+            self.StorageWidth = 4

+        elif self.PcdDataType == "UINT64":

+            self.StorageWidth = 8

+        else:

+            self.StorageWidth = 0

+            self.ValidData = False

+            

+    def __eq__(self, validObj):       

+        if self.VarOffset == validObj.VarOffset:

+            return True

+        else:

+            return False

+         

+class VAR_CHECK_PCD_VALID_LIST(VAR_CHECK_PCD_VALID_OBJ):

+    def __init__(self, VarOffset, validlist, PcdDataType):

+        super(VAR_CHECK_PCD_VALID_LIST, self).__init__(VarOffset, validlist, PcdDataType)

+        self.Type = 1

+        self.update_data()

+        self.update_size()

+    def update_data(self):

+        valid_num_list = []

+        data_list = []

+        for item in self.rawdata:

+            valid_num_list.extend(item.split(','))

+        

+        for valid_num in valid_num_list:

+            valid_num = valid_num.strip()

+

+            if valid_num.startswith('0x') or valid_num.startswith('0X'):

+                data_list.append(int(valid_num, 16))

+            else:

+                data_list.append(int(valid_num))

+

+                

+        self.data = set(data_list)

+        

+    def update_size(self):

+        self.Length = 5 + len(self.data) * self.StorageWidth

+        

+           

+class VAR_CHECK_PCD_VALID_RANGE(VAR_CHECK_PCD_VALID_OBJ):

+    def __init__(self, VarOffset, validrange, PcdDataType):

+        super(VAR_CHECK_PCD_VALID_RANGE, self).__init__(VarOffset, validrange, PcdDataType)

+        self.Type = 2

+        self.update_data()

+        self.update_size()

+    def update_data(self):

+        RangeExpr = ""

+        data_list = []

+        i = 0

+        for item in self.rawdata:

+            if i == 0:

+                RangeExpr = "( " + item + " )"

+            else:

+                RangeExpr = RangeExpr + "OR ( " + item + " )"

+        range_result = RangeExpression(RangeExpr, self.PcdDataType)(True)

+        for rangelist in range_result:

+            for obj in rangelist.pop():

+                data_list.append((obj.start, obj.end))

+        self.data = set(data_list)

+    

+    def update_size(self):

+        self.Length = 5 + len(self.data) * 2 * self.StorageWidth

+        

+

+class VAR_VALID_OBJECT_FACTORY(object):

+    def __init__(self):

+        pass

+    @staticmethod

+    def Get_valid_object(PcdClass, VarOffset):

+        if PcdClass.validateranges:

+            return VAR_CHECK_PCD_VALID_RANGE(VarOffset, PcdClass.validateranges, PcdClass.DatumType)

+        if PcdClass.validlists:

+            return VAR_CHECK_PCD_VALID_LIST(VarOffset, PcdClass.validlists, PcdClass.DatumType)

+        else:

+            return None

+

+if __name__ == "__main__":

+    class TestObj(object):

+        def __init__(self, number1):

+            self.number_1 = number1

+        def __eq__(self, testobj):

+            if self.number_1 == testobj.number_1:

+                return True

+            else:

+                return False

+    test1 = TestObj(1)

+    test2 = TestObj(2)

+    

+    testarr = [test1, test2]

+    print TestObj(2) in testarr

+    print TestObj(2) == test2

+    

diff --git a/BaseTools/Source/Python/Common/BuildToolError.py b/BaseTools/Source/Python/Common/BuildToolError.py
index b9512a1..0a393fe 100644
--- a/BaseTools/Source/Python/Common/BuildToolError.py
+++ b/BaseTools/Source/Python/Common/BuildToolError.py
@@ -1,7 +1,7 @@
 ## @file

 # Standardized Error Hanlding infrastructures.

 #

-# Copyright (c) 2007 - 2010, Intel Corporation. All rights reserved.<BR>

+# Copyright (c) 2007 - 2015, Intel Corporation. All rights reserved.<BR>

 # This program and the accompanying materials

 # are licensed and made available under the terms and conditions of the BSD License

 # which accompanies this distribution.  The full text of the license may be found at

@@ -81,6 +81,9 @@
 DDC_ERROR = 0xF009

 WARNING_AS_ERROR = 0xF006

 MIGRATION_ERROR = 0xF010

+PCD_VALIDATION_INFO_ERROR = 0xF011

+PCD_VARIABLE_ATTRIBUTES_ERROR = 0xF012

+PCD_VARIABLE_ATTRIBUTES_CONFLICT_ERROR = 0xF013

 ABORT_ERROR = 0xFFFE

 UNKNOWN_ERROR = 0xFFFF

 

diff --git a/BaseTools/Source/Python/Common/DataType.py b/BaseTools/Source/Python/Common/DataType.py
index 6d66523..b4abc88 100644
--- a/BaseTools/Source/Python/Common/DataType.py
+++ b/BaseTools/Source/Python/Common/DataType.py
@@ -1,7 +1,7 @@
 ## @file

 # This file is used to define common static strings used by INF/DEC/DSC files

 #

-# Copyright (c) 2007 - 2012, Intel Corporation. All rights reserved.<BR>

+# Copyright (c) 2007 - 2015, Intel Corporation. All rights reserved.<BR>

 # Portions copyright (c) 2011 - 2013, ARM Ltd. All rights reserved.<BR>

 # This program and the accompanying materials

 # are licensed and made available under the terms and conditions of the BSD License

@@ -398,6 +398,7 @@
 TAB_DSC_DEFINES_BUILD_TARGETS = 'BUILD_TARGETS'

 TAB_DSC_DEFINES_SKUID_IDENTIFIER = 'SKUID_IDENTIFIER'

 TAB_DSC_DEFINES_PCD_INFO_GENERATION = 'PCD_INFO_GENERATION'

+TAB_DSC_DEFINES_PCD_VAR_CHECK_GENERATION = 'PCD_VAR_CHECK_GENERATION'

 TAB_DSC_DEFINES_FLASH_DEFINITION = 'FLASH_DEFINITION'

 TAB_DSC_DEFINES_BUILD_NUMBER = 'BUILD_NUMBER'

 TAB_DSC_DEFINES_MAKEFILE_NAME = 'MAKEFILE_NAME'

diff --git a/BaseTools/Source/Python/Common/Misc.py b/BaseTools/Source/Python/Common/Misc.py
index 96ee30b..79073e2 100644
--- a/BaseTools/Source/Python/Common/Misc.py
+++ b/BaseTools/Source/Python/Common/Misc.py
@@ -1508,15 +1508,17 @@
         return [VpdOffset, Size, Value], IsValid, 2

     elif PcdType in (MODEL_PCD_DYNAMIC_HII, MODEL_PCD_DYNAMIC_EX_HII):

         HiiString = FieldList[0]

-        Guid = Offset = Value = ''

+        Guid = Offset = Value = Attribute = ''

         if len(FieldList) > 1:

             Guid = FieldList[1]

         if len(FieldList) > 2:

             Offset = FieldList[2]

         if len(FieldList) > 3:

             Value = FieldList[3]

-        IsValid = (3 <= len(FieldList) <= 4)

-        return [HiiString, Guid, Offset, Value], IsValid, 3

+        if len(FieldList) > 4:

+            Attribute = FieldList[4]

+        IsValid = (3 <= len(FieldList) <= 5)

+        return [HiiString, Guid, Offset, Value, Attribute], IsValid, 3

     return [], False, 0

 

 ## AnalyzePcdData

diff --git a/BaseTools/Source/Python/Common/RangeExpression.py b/BaseTools/Source/Python/Common/RangeExpression.py
new file mode 100644
index 0000000..5da4a47
--- /dev/null
+++ b/BaseTools/Source/Python/Common/RangeExpression.py
@@ -0,0 +1,737 @@
+# # @file

+# This file is used to parse and evaluate range expression in Pcd declaration.

+#

+# Copyright (c) 2015, Intel Corporation. All rights reserved.<BR>

+# This program and the accompanying materials

+# are licensed and made available under the terms and conditions of the BSD License

+# which accompanies this distribution.    The full text of the license may be found at

+# http://opensource.org/licenses/bsd-license.php

+#

+# THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,

+# WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.

+

+# # Import Modules

+#

+from Common.GlobalData import *

+from CommonDataClass.Exceptions import BadExpression

+from CommonDataClass.Exceptions import WrnExpression

+import uuid

+

+ERR_STRING_EXPR = 'This operator cannot be used in string expression: [%s].'

+ERR_SNYTAX = 'Syntax error, the rest of expression cannot be evaluated: [%s].'

+ERR_MATCH = 'No matching right parenthesis.'

+ERR_STRING_TOKEN = 'Bad string token: [%s].'

+ERR_MACRO_TOKEN = 'Bad macro token: [%s].'

+ERR_EMPTY_TOKEN = 'Empty token is not allowed.'

+ERR_PCD_RESOLVE = 'PCD token cannot be resolved: [%s].'

+ERR_VALID_TOKEN = 'No more valid token found from rest of string: [%s].'

+ERR_EXPR_TYPE = 'Different types found in expression.'

+ERR_OPERATOR_UNSUPPORT = 'Unsupported operator: [%s]'

+ERR_REL_NOT_IN = 'Expect "IN" after "not" operator.'

+WRN_BOOL_EXPR = 'Operand of boolean type cannot be used in arithmetic expression.'

+WRN_EQCMP_STR_OTHERS = '== Comparison between Operand of string type and Boolean/Number Type always return False.'

+WRN_NECMP_STR_OTHERS = '!= Comparison between Operand of string type and Boolean/Number Type always return True.'

+ERR_RELCMP_STR_OTHERS = 'Operator taking Operand of string type and Boolean/Number Type is not allowed: [%s].'

+ERR_STRING_CMP = 'Unicode string and general string cannot be compared: [%s %s %s]'

+ERR_ARRAY_TOKEN = 'Bad C array or C format GUID token: [%s].'

+ERR_ARRAY_ELE = 'This must be HEX value for NList or Array: [%s].'

+ERR_EMPTY_EXPR = 'Empty expression is not allowed.'

+ERR_IN_OPERAND = 'Macro after IN operator can only be: $(FAMILY), $(ARCH), $(TOOL_CHAIN_TAG) and $(TARGET).'

+

+def MaxOfType(DataType):

+    if DataType == 'UINT8':

+        return int('0xFF', 16)

+    if DataType == 'UINT16':

+        return int('0xFFFF', 16)

+    if DataType == 'UINT32':

+        return int('0xFFFFFFFF', 16)

+    if DataType == 'UINT64':

+        return int('0xFFFFFFFFFFFFFFFF', 16)

+

+class RangeObject(object):

+    def __init__(self, start, end, empty = False):

+        

+        if int(start) < int(end):

+            self.start = int(start)

+            self.end = int(end)

+        else:

+            self.start = int(end)

+            self.end = int(start)

+        self.empty = empty

+

+class RangeContainer(object):

+    def __init__(self):

+        self.rangelist = []

+        

+    def push(self, RangeObject):

+        self.rangelist.append(RangeObject)

+        self.rangelist = sorted(self.rangelist, key = lambda rangeobj : rangeobj.start)

+        self.merge()

+        

+    def pop(self):

+        for item in self.rangelist:

+            yield item

+   

+    def __clean__(self):   

+        newrangelist = []

+        for rangeobj in self.rangelist:

+            if rangeobj.empty == True:

+                continue

+            else:

+                newrangelist.append(rangeobj)

+        self.rangelist = newrangelist      

+    def merge(self):

+        self.__clean__()

+        for i in range(0, len(self.rangelist) - 1):

+            if self.rangelist[i + 1].start > self.rangelist[i].end:

+                continue

+            else:

+                self.rangelist[i + 1].start = self.rangelist[i].start

+                self.rangelist[i + 1].end = self.rangelist[i + 1].end > self.rangelist[i].end and self.rangelist[i + 1].end or self.rangelist[i].end 

+                self.rangelist[i].empty = True

+

+        self.__clean__()

+        

+    def dump(self):

+        print "----------------------"

+        rangelist = ""

+        for object in self.rangelist:

+            rangelist = rangelist + "[%d , %d]" % (object.start, object.end)

+        print rangelist

+        

+        

+class XOROperatorObject(object):   

+    def __init__(self):     

+        pass

+    def Calculate(self, Operand, DataType, SymbolTable): 

+        if type(Operand) == type('') and not Operand.isalnum():

+            Expr = "XOR ..."

+            raise BadExpression(ERR_SNYTAX % Expr)

+        rangeId = str(uuid.uuid1())

+        rangeContainer = RangeContainer()

+        rangeContainer.push(RangeObject(0, int(Operand) - 1))

+        rangeContainer.push(RangeObject(int(Operand) + 1, MaxOfType(DataType)))

+        SymbolTable[rangeId] = rangeContainer

+        return rangeId

+

+class LEOperatorObject(object):

+    def __init__(self):     

+        pass

+    def Calculate(self, Operand, DataType, SymbolTable): 

+        if type(Operand) == type('') and not Operand.isalnum():

+            Expr = "LE ..."

+            raise BadExpression(ERR_SNYTAX % Expr)

+        rangeId1 = str(uuid.uuid1())

+        rangeContainer = RangeContainer()

+        rangeContainer.push(RangeObject(0, int(Operand)))

+        SymbolTable[rangeId1] = rangeContainer

+        return rangeId1

+class LTOperatorObject(object):

+    def __init__(self):     

+        pass

+    def Calculate(self, Operand, DataType, SymbolTable):

+        if type(Operand) == type('') and not Operand.isalnum():

+            Expr = "LT ..." 

+            raise BadExpression(ERR_SNYTAX % Expr) 

+        rangeId1 = str(uuid.uuid1())

+        rangeContainer = RangeContainer()

+        rangeContainer.push(RangeObject(0, int(Operand) - 1))

+        SymbolTable[rangeId1] = rangeContainer

+        return rangeId1   

+

+class GEOperatorObject(object):

+    def __init__(self):     

+        pass

+    def Calculate(self, Operand, DataType, SymbolTable): 

+        if type(Operand) == type('') and not Operand.isalnum():

+            Expr = "GE ..."

+            raise BadExpression(ERR_SNYTAX % Expr)

+        rangeId1 = str(uuid.uuid1())

+        rangeContainer = RangeContainer()

+        rangeContainer.push(RangeObject(int(Operand), MaxOfType(DataType)))

+        SymbolTable[rangeId1] = rangeContainer

+        return rangeId1   

+      

+class GTOperatorObject(object):

+    def __init__(self):     

+        pass

+    def Calculate(self, Operand, DataType, SymbolTable): 

+        if type(Operand) == type('') and not Operand.isalnum():

+            Expr = "GT ..."

+            raise BadExpression(ERR_SNYTAX % Expr)

+        rangeId1 = str(uuid.uuid1())

+        rangeContainer = RangeContainer()

+        rangeContainer.push(RangeObject(int(Operand) + 1, MaxOfType(DataType)))

+        SymbolTable[rangeId1] = rangeContainer

+        return rangeId1   

+    

+class EQOperatorObject(object):

+    def __init__(self):     

+        pass

+    def Calculate(self, Operand, DataType, SymbolTable): 

+        if type(Operand) == type('') and not Operand.isalnum():

+            Expr = "EQ ..."

+            raise BadExpression(ERR_SNYTAX % Expr)

+        rangeId1 = str(uuid.uuid1())

+        rangeContainer = RangeContainer()

+        rangeContainer.push(RangeObject(int(Operand) , int(Operand)))

+        SymbolTable[rangeId1] = rangeContainer

+        return rangeId1   

+    

+def GetOperatorObject(Operator):

+    if Operator == '>':

+        return GTOperatorObject()

+    elif Operator == '>=':

+        return GEOperatorObject()

+    elif Operator == '<':

+        return LTOperatorObject()

+    elif Operator == '<=':

+        return LEOperatorObject()

+    elif Operator == '==':

+        return EQOperatorObject()

+    elif Operator == '^':

+        return XOROperatorObject()

+    else:

+        raise BadExpression("Bad Operator")

+

+class RangeExpression(object):

+    # Logical operator mapping

+    LogicalOperators = {

+        '&&' : 'and', '||' : 'or',

+        '!'  : 'not', 'AND': 'and',

+        'OR' : 'or' , 'NOT': 'not',

+        'XOR': '^'  , 'xor': '^',

+        'EQ' : '==' , 'NE' : '!=',

+        'GT' : '>'  , 'LT' : '<',

+        'GE' : '>=' , 'LE' : '<=',

+        'IN' : 'in'

+    }

+

+    NonLetterOpLst = ['+', '-', '&', '|', '^', '!', '=', '>', '<']

+

+    PcdPattern = re.compile(r'[_a-zA-Z][0-9A-Za-z_]*\.[_a-zA-Z][0-9A-Za-z_]*$')

+    HexPattern = re.compile(r'0[xX][0-9a-fA-F]+')

+    RegGuidPattern = re.compile(r'[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12}')

+    ExRegGuidPattern = re.compile(r'[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12}$')

+    

+    SymbolPattern = re.compile("("

+                                 "\$\([A-Z][A-Z0-9_]*\)|\$\(\w+\.\w+\)|\w+\.\w+|"

+                                 "&&|\|\||!(?!=)|"

+                                 "(?<=\W)AND(?=\W)|(?<=\W)OR(?=\W)|(?<=\W)NOT(?=\W)|(?<=\W)XOR(?=\W)|"

+                                 "(?<=\W)EQ(?=\W)|(?<=\W)NE(?=\W)|(?<=\W)GT(?=\W)|(?<=\W)LT(?=\W)|(?<=\W)GE(?=\W)|(?<=\W)LE(?=\W)"

+                               ")")

+    

+    RangePattern = re.compile(r'[0-9]+ - [0-9]+')

+

+    def preProcessRangeExpr(self, expr):

+        # convert hex to int

+        # convert interval to object index. ex. 1 - 10 to a GUID

+        expr = expr.strip()

+        NumberDict = {}

+        for HexNumber in self.HexPattern.findall(expr):

+            Number = str(int(HexNumber, 16))

+            NumberDict[HexNumber] = Number

+        for HexNum in NumberDict:

+            expr = expr.replace(HexNum, NumberDict[HexNum])

+        

+        rangedict = {}    

+        for validrange in self.RangePattern.findall(expr):

+            start, end = validrange.split(" - ")

+            start = start.strip()

+            end = end.strip()

+            rangeid = str(uuid.uuid1())

+            rangeContainer = RangeContainer()

+            rangeContainer.push(RangeObject(start, end))

+            self.operanddict[str(rangeid)] = rangeContainer

+            rangedict[validrange] = str(rangeid)

+            

+        for validrange in rangedict:

+            expr = expr.replace(validrange, rangedict[validrange])

+         

+        self._Expr = expr    

+        return expr

+            

+        

+    def EvalRange(self, Operator, Oprand):

+

+        operatorobj = GetOperatorObject(Operator)

+        return operatorobj.Calculate(Oprand, self.PcdDataType, self.operanddict)

+        

+    def Rangeintersection(self, Oprand1, Oprand2):

+        rangeContainer1 = self.operanddict[Oprand1]

+        rangeContainer2 = self.operanddict[Oprand2]

+        rangeContainer = RangeContainer()

+        for range1 in rangeContainer1.pop():

+            for range2 in rangeContainer2.pop():

+                if range1.start >= range2.start:

+                    start = range1.start

+                    end = range1.end

+                    range1.start = range2.start

+                    range1.end = range2.end

+                    range2.start = start

+                    range2.end = end

+                if range1.empty:

+                    rangeid = str(uuid.uuid1())

+                    rangeContainer.push(RangeObject(0, 0, True))

+                if range1.end < range2.start:

+                    rangeid = str(uuid.uuid1())

+                    rangeContainer.push(RangeObject(0, 0, True))

+                elif range1.end == range2.start:

+                    rangeid = str(uuid.uuid1())

+                    rangeContainer.push(RangeObject(range1.end, range1.end))

+                elif range1.end <= range2.end and range1.end > range2.start:

+                    rangeid = str(uuid.uuid1())

+                    rangeContainer.push(RangeObject(range2.start, range1.end))

+                elif range1.end >= range2.end:

+                    rangeid = str(uuid.uuid1())

+                    rangeContainer.push(RangeObject(range2.start, range2.end))

+        

+        self.operanddict[rangeid] = rangeContainer

+#        rangeContainer.dump()

+        return rangeid

+            

+    def Rangecollections(self, Oprand1, Oprand2):

+

+        rangeContainer1 = self.operanddict[Oprand1]

+        rangeContainer2 = self.operanddict[Oprand2]

+        rangeContainer = RangeContainer()

+        

+        for rangeobj in rangeContainer2.pop():

+            rangeContainer.push(rangeobj)

+        for rangeobj in rangeContainer1.pop():

+            rangeContainer.push(rangeobj)

+        

+        rangeid = str(uuid.uuid1())

+        self.operanddict[rangeid] = rangeContainer

+        

+#        rangeContainer.dump()

+        return rangeid

+        

+            

+    def NegtiveRange(self, Oprand1):

+        rangeContainer1 = self.operanddict[Oprand1]

+        

+        

+        rangeids = []

+        

+        for rangeobj in rangeContainer1.pop():

+            rangeContainer = RangeContainer()

+            rangeid = str(uuid.uuid1())

+            if rangeobj.empty:

+                rangeContainer.push(RangeObject(0, MaxOfType(self.PcdDataType)))

+            else:

+                if rangeobj.start > 0:

+                    rangeContainer.push(RangeObject(0, rangeobj.start - 1))

+                if rangeobj.end < MaxOfType(self.PcdDataType):

+                    rangeContainer.push(RangeObject(rangeobj.end + 1, MaxOfType(self.PcdDataType)))

+            self.operanddict[rangeid] = rangeContainer

+            rangeids.append(rangeid)

+

+        if len(rangeids) == 0:

+            rangeContainer = RangeContainer()

+            rangeContainer.push(RangeObject(0, MaxOfType(self.PcdDataType)))

+            rangeid = str(uuid.uuid1())

+            self.operanddict[rangeid] = rangeContainer

+            return rangeid

+

+        if len(rangeids) == 1:

+            return rangeids[0]

+

+        re = self.Rangeintersection(rangeids[0], rangeids[1])

+        for i in range(2, len(rangeids)):

+            re = self.Rangeintersection(re, rangeids[i])

+            

+        rangeid2 = str(uuid.uuid1())

+        self.operanddict[rangeid2] = self.operanddict[re]

+        return rangeid2

+        

+    def Eval(self, Operator, Oprand1, Oprand2 = None):

+        

+        if Operator in ["!", "NOT", "not"]:

+            if not self.RegGuidPattern.match(Oprand1.strip()):

+                raise BadExpression(ERR_STRING_EXPR % Operator)

+            return self.NegtiveRange(Oprand1)

+        else:

+            if Operator in ["==", ">=", "<=", ">", "<", '^']:

+                return self.EvalRange(Operator, Oprand1)

+            elif Operator == 'and' :

+                if not self.ExRegGuidPattern.match(Oprand1.strip()) or not self.ExRegGuidPattern.match(Oprand2.strip()):

+                    raise BadExpression(ERR_STRING_EXPR % Operator)

+                return self.Rangeintersection(Oprand1, Oprand2)    

+            elif Operator == 'or':

+                if not self.ExRegGuidPattern.match(Oprand1.strip()) or not self.ExRegGuidPattern.match(Oprand2.strip()):

+                    raise BadExpression(ERR_STRING_EXPR % Operator)

+                return self.Rangecollections(Oprand1, Oprand2)

+            else:

+                raise BadExpression(ERR_STRING_EXPR % Operator)

+

+

+    def __init__(self, Expression, PcdDataType, SymbolTable = {}):

+        self._NoProcess = False

+        if type(Expression) != type(''):

+            self._Expr = Expression

+            self._NoProcess = True

+            return

+

+        self._Expr = Expression.strip()

+

+        if not self._Expr.strip():

+            raise BadExpression(ERR_EMPTY_EXPR)

+

+        #

+        # The symbol table including PCD and macro mapping

+        #

+        self._Symb = SymbolTable

+        self._Symb.update(self.LogicalOperators)

+        self._Idx = 0

+        self._Len = len(self._Expr)

+        self._Token = ''

+        self._WarnExcept = None

+        

+

+        # Literal token without any conversion

+        self._LiteralToken = ''

+        

+        # store the operand object

+        self.operanddict = {}

+        # The Pcd max value depends on PcdDataType

+        self.PcdDataType = PcdDataType

+

+    # Public entry for this class

+    #   @param RealValue: False: only evaluate if the expression is true or false, used for conditional expression

+    #                     True : return the evaluated str(value), used for PCD value

+    #

+    #   @return: True or False if RealValue is False

+    #            Evaluated value of string format if RealValue is True

+    #

+    def __call__(self, RealValue = False, Depth = 0):

+        if self._NoProcess:

+            return self._Expr

+

+        self._Depth = Depth

+

+        self._Expr = self._Expr.strip()

+        

+        self.preProcessRangeExpr(self._Expr)

+        

+        # check if the expression does not need to evaluate

+        if RealValue and Depth == 0:

+            self._Token = self._Expr

+            if self.ExRegGuidPattern.match(self._Expr):

+                return [self.operanddict[self._Expr] ]

+

+            self._Idx = 0

+            self._Token = ''

+

+        Val = self._OrExpr()

+        RealVal = Val

+        

+        RangeIdList = RealVal.split("or")

+        RangeList = []

+        for rangeid in RangeIdList:

+            RangeList.append(self.operanddict[rangeid.strip()])

+            

+        return RangeList

+

+    # Template function to parse binary operators which have same precedence

+    # Expr [Operator Expr]*

+    def _ExprFuncTemplate(self, EvalFunc, OpLst):

+        Val = EvalFunc()

+        while self._IsOperator(OpLst):

+            Op = self._Token

+            try:

+                Val = self.Eval(Op, Val, EvalFunc())

+            except WrnExpression, Warn:

+                self._WarnExcept = Warn

+                Val = Warn.result

+        return Val

+

+    # A [|| B]*

+    def _OrExpr(self):

+        return self._ExprFuncTemplate(self._AndExpr, ["OR", "or"])

+

+    # A [&& B]*

+    def _AndExpr(self):

+        return self._ExprFuncTemplate(self._NeExpr, ["AND", "and"])

+

+    def _NeExpr(self):

+        Val = self._RelExpr()

+        while self._IsOperator([ "!=", "NOT", "not"]):

+            Op = self._Token

+            if Op in ["!", "NOT", "not"]:

+                if not self._IsOperator(["IN", "in"]):

+                    raise BadExpression(ERR_REL_NOT_IN)

+                Op += ' ' + self._Token

+            try:

+                Val = self.Eval(Op, Val, self._RelExpr())

+            except WrnExpression, Warn:

+                self._WarnExcept = Warn

+                Val = Warn.result

+        return Val

+

+    # [!]*A

+    def _RelExpr(self):

+        if self._IsOperator(["NOT" , "LE", "GE", "LT", "GT", "EQ", "XOR"]):

+            Token = self._Token

+            Val = self._NeExpr()

+            try:

+                return self.Eval(Token, Val)

+            except WrnExpression, Warn:

+                self._WarnExcept = Warn

+                return Warn.result

+        return self._IdenExpr()

+

+    # Parse identifier or encapsulated expression

+    def _IdenExpr(self):

+        Tk = self._GetToken()

+        if Tk == '(':

+            Val = self._OrExpr()

+            try:

+                # _GetToken may also raise BadExpression

+                if self._GetToken() != ')':

+                    raise BadExpression(ERR_MATCH)

+            except BadExpression:

+                raise BadExpression(ERR_MATCH)

+            return Val

+        return Tk

+

+    # Skip whitespace or tab

+    def __SkipWS(self):

+        for Char in self._Expr[self._Idx:]:

+            if Char not in ' \t':

+                break

+            self._Idx += 1

+

+    # Try to convert string to number

+    def __IsNumberToken(self):

+        Radix = 10

+        if self._Token.lower()[0:2] == '0x' and len(self._Token) > 2:

+            Radix = 16

+        try:

+            self._Token = int(self._Token, Radix)

+            return True

+        except ValueError:

+            return False

+        except TypeError:

+            return False

+

+    # Parse array: {...}

+    def __GetArray(self):

+        Token = '{'

+        self._Idx += 1

+        self.__GetNList(True)

+        Token += self._LiteralToken

+        if self._Idx >= self._Len or self._Expr[self._Idx] != '}':

+            raise BadExpression(ERR_ARRAY_TOKEN % Token)

+        Token += '}'

+

+        # All whitespace and tabs in array are already stripped.

+        IsArray = IsGuid = False

+        if len(Token.split(',')) == 11 and len(Token.split(',{')) == 2 \

+            and len(Token.split('},')) == 1:

+            HexLen = [11, 6, 6, 5, 4, 4, 4, 4, 4, 4, 6]

+            HexList = Token.split(',')

+            if HexList[3].startswith('{') and \

+                not [Index for Index, Hex in enumerate(HexList) if len(Hex) > HexLen[Index]]:

+                IsGuid = True

+        if Token.lstrip('{').rstrip('}').find('{') == -1:

+            if not [Hex for Hex in Token.lstrip('{').rstrip('}').split(',') if len(Hex) > 4]:

+                IsArray = True

+        if not IsArray and not IsGuid:

+            raise BadExpression(ERR_ARRAY_TOKEN % Token)

+        self._Idx += 1

+        self._Token = self._LiteralToken = Token

+        return self._Token

+

+    # Parse string, the format must be: "..."

+    def __GetString(self):

+        Idx = self._Idx

+

+        # Skip left quote

+        self._Idx += 1

+

+        # Replace escape \\\", \"

+        Expr = self._Expr[self._Idx:].replace('\\\\', '//').replace('\\\"', '\\\'')

+        for Ch in Expr:

+            self._Idx += 1

+            if Ch == '"':

+                break

+        self._Token = self._LiteralToken = self._Expr[Idx:self._Idx]

+        if not self._Token.endswith('"'):

+            raise BadExpression(ERR_STRING_TOKEN % self._Token)

+        self._Token = self._Token[1:-1]

+        return self._Token

+

+    # Get token that is comprised by alphanumeric, underscore or dot(used by PCD)

+    # @param IsAlphaOp: Indicate if parsing general token or script operator(EQ, NE...)

+    def __GetIdToken(self, IsAlphaOp = False):

+        IdToken = ''

+        for Ch in self._Expr[self._Idx:]:

+            if not self.__IsIdChar(Ch):

+                break

+            self._Idx += 1

+            IdToken += Ch

+

+        self._Token = self._LiteralToken = IdToken

+        if not IsAlphaOp:

+            self.__ResolveToken()

+        return self._Token

+

+    # Try to resolve token

+    def __ResolveToken(self):

+        if not self._Token:

+            raise BadExpression(ERR_EMPTY_TOKEN)

+

+        # PCD token

+        if self.PcdPattern.match(self._Token):

+            if self._Token not in self._Symb:

+                Ex = BadExpression(ERR_PCD_RESOLVE % self._Token)

+                Ex.Pcd = self._Token

+                raise Ex

+            self._Token = RangeExpression(self._Symb[self._Token], self._Symb)(True, self._Depth + 1)

+            if type(self._Token) != type(''):

+                self._LiteralToken = hex(self._Token)

+                return

+

+        if self._Token.startswith('"'):

+            self._Token = self._Token[1:-1]

+        elif self._Token in ["FALSE", "false", "False"]:

+            self._Token = False

+        elif self._Token in ["TRUE", "true", "True"]:

+            self._Token = True

+        else:

+            self.__IsNumberToken()

+

+    def __GetNList(self, InArray = False):

+        self._GetSingleToken()

+        if not self.__IsHexLiteral():

+            if InArray:

+                raise BadExpression(ERR_ARRAY_ELE % self._Token)

+            return self._Token

+

+        self.__SkipWS()

+        Expr = self._Expr[self._Idx:]

+        if not Expr.startswith(','):

+            return self._Token

+

+        NList = self._LiteralToken

+        while Expr.startswith(','):

+            NList += ','

+            self._Idx += 1

+            self.__SkipWS()

+            self._GetSingleToken()

+            if not self.__IsHexLiteral():

+                raise BadExpression(ERR_ARRAY_ELE % self._Token)

+            NList += self._LiteralToken

+            self.__SkipWS()

+            Expr = self._Expr[self._Idx:]

+        self._Token = self._LiteralToken = NList

+        return self._Token

+

+    def __IsHexLiteral(self):

+        if self._LiteralToken.startswith('{') and \

+            self._LiteralToken.endswith('}'):

+            return True

+

+        if self.HexPattern.match(self._LiteralToken):

+            Token = self._LiteralToken[2:]

+            Token = Token.lstrip('0')

+            if not Token:

+                self._LiteralToken = '0x0'

+            else:

+                self._LiteralToken = '0x' + Token.lower()

+            return True

+        return False

+

+    def _GetToken(self):

+        return self.__GetNList()

+

+    @staticmethod

+    def __IsIdChar(Ch):

+        return Ch in '._/:' or Ch.isalnum()

+

+    # Parse operand

+    def _GetSingleToken(self):

+        self.__SkipWS()

+        Expr = self._Expr[self._Idx:]

+        if Expr.startswith('L"'):

+            # Skip L

+            self._Idx += 1

+            UStr = self.__GetString()

+            self._Token = 'L"' + UStr + '"'

+            return self._Token

+

+        self._Token = ''

+        if Expr:

+            Ch = Expr[0]

+            Match = self.RegGuidPattern.match(Expr)

+            if Match and not Expr[Match.end():Match.end() + 1].isalnum() \

+                and Expr[Match.end():Match.end() + 1] != '_':

+                self._Idx += Match.end()

+                self._Token = Expr[0:Match.end()]

+                return self._Token

+            elif self.__IsIdChar(Ch):

+                return self.__GetIdToken()

+            elif Ch == '(' or Ch == ')':

+                self._Idx += 1

+                self._Token = Ch

+                return self._Token

+

+        raise BadExpression(ERR_VALID_TOKEN % Expr)

+

+    # Parse operator

+    def _GetOperator(self):

+        self.__SkipWS()

+        LegalOpLst = ['&&', '||', '!=', '==', '>=', '<='] + self.NonLetterOpLst

+

+        self._Token = ''

+        Expr = self._Expr[self._Idx:]

+

+        # Reach end of expression

+        if not Expr:

+            return ''

+

+        # Script operator: LT, GT, LE, GE, EQ, NE, and, or, xor, not

+        if Expr[0].isalpha():

+            return self.__GetIdToken(True)

+

+        # Start to get regular operator: +, -, <, > ...

+        if Expr[0] not in self.NonLetterOpLst:

+            return ''

+

+        OpToken = ''

+        for Ch in Expr:

+            if Ch in self.NonLetterOpLst:

+                if '!' == Ch and OpToken:

+                    break

+                self._Idx += 1

+                OpToken += Ch

+            else:

+                break

+

+        if OpToken not in LegalOpLst:

+            raise BadExpression(ERR_OPERATOR_UNSUPPORT % OpToken)

+        self._Token = OpToken

+        return OpToken

+

+    # Check if current token matches the operators given from OpList

+    def _IsOperator(self, OpList):

+        Idx = self._Idx

+        self._GetOperator()

+        if self._Token in OpList:

+            if self._Token in self.LogicalOperators:

+                self._Token = self.LogicalOperators[self._Token]

+            return True

+        self._Idx = Idx

+        return False

+

+

+    

+    

+    

+    

+

+

+

+

+#    UTRangeList()

diff --git a/BaseTools/Source/Python/Common/VariableAttributes.py b/BaseTools/Source/Python/Common/VariableAttributes.py
new file mode 100644
index 0000000..a2e22ca
--- /dev/null
+++ b/BaseTools/Source/Python/Common/VariableAttributes.py
@@ -0,0 +1,57 @@
+# # @file

+# 

+# This file is used to handle the variable attributes and property information

+#

+#

+# Copyright (c) 2015, Intel Corporation. All rights reserved.<BR>

+# This program and the accompanying materials

+# are licensed and made available under the terms and conditions of the BSD License

+# which accompanies this distribution.  The full text of the license may be found at

+# http://opensource.org/licenses/bsd-license.php

+#

+# THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,

+# WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.

+#

+   

+class VariableAttributes(object):

+    EFI_VARIABLE_NON_VOLATILE = 0x00000001

+    EFI_VARIABLE_BOOTSERVICE_ACCESS = 0x00000002

+    EFI_VARIABLE_RUNTIME_ACCESS = 0x00000004

+    VAR_CHECK_VARIABLE_PROPERTY_READ_ONLY = 0x00000001

+    VarAttributesMap = {

+                     "NV":EFI_VARIABLE_NON_VOLATILE,

+                     "BS":EFI_VARIABLE_BOOTSERVICE_ACCESS,

+                     "RT":EFI_VARIABLE_RUNTIME_ACCESS,

+                     "RO":VAR_CHECK_VARIABLE_PROPERTY_READ_ONLY

+                     }

+    

+    def __init__(self):

+        pass

+    

+    @staticmethod

+    def GetVarAttributes(var_attr_str):

+        VarAttr = 0x00000000

+        VarProp = 0x00000000

+        

+        attr_list = var_attr_str.split(",")

+        for attr in attr_list:

+            attr = attr.strip()

+            if attr == 'RO':

+                VarProp = VariableAttributes.VAR_CHECK_VARIABLE_PROPERTY_READ_ONLY

+            else:

+                VarAttr = VarAttr | VariableAttributes.VarAttributesMap.get(attr, 0x00000000)   

+        return VarAttr, VarProp

+    @staticmethod

+    def ValidateVarAttributes(var_attr_str):

+        if not var_attr_str:

+            return True, ""

+        attr_list = var_attr_str.split(",")

+        attr_temp = []

+        for attr in attr_list:

+            attr = attr.strip()

+            attr_temp.append(attr)

+            if attr not in VariableAttributes.VarAttributesMap:

+                return False, "The variable attribute %s is not support to be specified in dsc file. Supported variable attribute are ['BS','NV','RT','RO'] "

+        if 'RT' in attr_temp and 'BS' not in attr_temp:

+            return False, "the RT attribute need the BS attribute to be present"

+        return True, ""

diff --git a/BaseTools/Source/Python/CommonDataClass/CommonClass.py b/BaseTools/Source/Python/CommonDataClass/CommonClass.py
index bb4b434..5e908a6 100644
--- a/BaseTools/Source/Python/CommonDataClass/CommonClass.py
+++ b/BaseTools/Source/Python/CommonDataClass/CommonClass.py
@@ -1,7 +1,7 @@
 ## @file

 # This file is used to define common items of class object

 #

-# Copyright (c) 2007 - 2010, Intel Corporation. All rights reserved.<BR>

+# Copyright (c) 2007 - 2015, Intel Corporation. All rights reserved.<BR>

 # This program and the accompanying materials

 # are licensed and made available under the terms and conditions of the BSD License

 # which accompanies this distribution.    The full text of the license may be found at

@@ -270,7 +270,7 @@
 #

 class SkuInfoClass(object):

     def __init__(self, SkuIdName = '', SkuId = '', VariableName = '', VariableGuid = '', VariableOffset = '', 

-                 HiiDefaultValue = '', VpdOffset = '', DefaultValue = '', VariableGuidValue = ''):

+                 HiiDefaultValue = '', VpdOffset = '', DefaultValue = '', VariableGuidValue = '', VariableAttribute = ''):

         self.SkuIdName = SkuIdName

         self.SkuId = SkuId

         

@@ -282,6 +282,7 @@
         self.VariableGuidValue = VariableGuidValue

         self.VariableOffset = VariableOffset

         self.HiiDefaultValue = HiiDefaultValue

+        self.VariableAttribute = VariableAttribute

         

         #

         # Used by Vpd

diff --git a/BaseTools/Source/Python/Workspace/BuildClassObject.py b/BaseTools/Source/Python/Workspace/BuildClassObject.py
index 8b98f16..ea26e5e 100644
--- a/BaseTools/Source/Python/Workspace/BuildClassObject.py
+++ b/BaseTools/Source/Python/Workspace/BuildClassObject.py
@@ -1,7 +1,7 @@
 ## @file

 # This file is used to define each component of the build database

 #

-# Copyright (c) 2007 - 2014, Intel Corporation. All rights reserved.<BR>

+# Copyright (c) 2007 - 2015, Intel Corporation. All rights reserved.<BR>

 # This program and the accompanying materials

 # are licensed and made available under the terms and conditions of the BSD License

 # which accompanies this distribution.  The full text of the license may be found at

@@ -44,7 +44,7 @@
 # @var Phase:                To store value for Phase, default is "DXE"

 #

 class PcdClassObject(object):

-    def __init__(self, Name = None, Guid = None, Type = None, DatumType = None, Value = None, Token = None, MaxDatumSize = None, SkuInfoList = {}, IsOverrided = False, GuidValue = None):

+    def __init__(self, Name = None, Guid = None, Type = None, DatumType = None, Value = None, Token = None, MaxDatumSize = None, SkuInfoList = {}, IsOverrided = False, GuidValue = None, validateranges = [], validlists = [], expressions = []):

         self.TokenCName = Name

         self.TokenSpaceGuidCName = Guid

         self.TokenSpaceGuidValue = GuidValue

@@ -59,6 +59,9 @@
         self.IsOverrided = IsOverrided

         self.IsFromBinaryInf = False

         self.IsFromDsc = False

+        self.validateranges = validateranges

+        self.validlists = validlists

+        self.expressions = expressions

         

     ## Convert the class to a string

     #

diff --git a/BaseTools/Source/Python/Workspace/MetaFileParser.py b/BaseTools/Source/Python/Workspace/MetaFileParser.py
index f96c73c..eb02b66 100644
--- a/BaseTools/Source/Python/Workspace/MetaFileParser.py
+++ b/BaseTools/Source/Python/Workspace/MetaFileParser.py
@@ -376,7 +376,8 @@
                 File=self.MetaFile,

                 Line=self._LineIndex + 1

                 )

-

+    def GetValidExpression(self, TokenSpaceGuid, PcdCName):

+        return self._Table.GetValidExpression(TokenSpaceGuid, PcdCName)

     def _GetMacros(self):

         Macros = {}

         Macros.update(self._FileLocalMacros)

@@ -814,6 +815,7 @@
         "PLATFORM_VERSION",

         "SKUID_IDENTIFIER",

         "PCD_INFO_GENERATION",

+        "PCD_VAR_CHECK_GENERATION",

         "SUPPORTED_ARCHITECTURES",

         "BUILD_TARGETS",

         "OUTPUT_DIRECTORY",

diff --git a/BaseTools/Source/Python/Workspace/MetaFileTable.py b/BaseTools/Source/Python/Workspace/MetaFileTable.py
index 607225a..89a12cd 100644
--- a/BaseTools/Source/Python/Workspace/MetaFileTable.py
+++ b/BaseTools/Source/Python/Workspace/MetaFileTable.py
@@ -1,7 +1,7 @@
 ## @file

 # This file is used to create/update/query/erase a meta file table

 #

-# Copyright (c) 2008, Intel Corporation. All rights reserved.<BR>

+# Copyright (c) 2008 - 2015, Intel Corporation. All rights reserved.<BR>

 # This program and the accompanying materials

 # are licensed and made available under the terms and conditions of the BSD License

 # which accompanies this distribution.  The full text of the license may be found at

@@ -225,6 +225,26 @@
         SqlCommand = "SELECT %s FROM %s WHERE %s" % (ValueString, self.Table, ConditionString)

         return self.Exec(SqlCommand)

 

+    def GetValidExpression(self, TokenSpaceGuid, PcdCName):

+        SqlCommand = "select Value1 from %s WHERE Value2='%s' and Value3='%s'" % (self.Table, TokenSpaceGuid, PcdCName)

+        self.Cur.execute(SqlCommand)

+        validateranges = []

+        validlists = []

+        expressions = []

+        for row in self.Cur:

+            comment = row[0]

+            comment = comment.strip("#")

+            comment = comment.strip()

+            if comment.startswith("@ValidRange"):

+                comment = comment.replace("@ValidRange", "", 1)

+                validateranges.append(comment.split("|")[1].strip())

+            if comment.startswith("@ValidList"):

+                comment = comment.replace("@ValidList", "", 1)

+                validlists.append(comment.split("|")[1].strip())

+            if comment.startswith("@Expression"):

+                comment = comment.replace("@Expression", "", 1)

+                expressions.append(comment.split("|")[1].strip())

+        return set(validateranges), set(validlists), set(expressions)

 ## Python class representation of table storing platform data

 class PlatformTable(MetaFileTable):

     _COLUMN_ = '''

diff --git a/BaseTools/Source/Python/Workspace/WorkspaceDatabase.py b/BaseTools/Source/Python/Workspace/WorkspaceDatabase.py
index 83f730e..9f79f74 100644
--- a/BaseTools/Source/Python/Workspace/WorkspaceDatabase.py
+++ b/BaseTools/Source/Python/Workspace/WorkspaceDatabase.py
@@ -1,7 +1,7 @@
 ## @file

 # This file is used to create a database used by build tool

 #

-# Copyright (c) 2008 - 2014, Intel Corporation. All rights reserved.<BR>

+# Copyright (c) 2008 - 2015, Intel Corporation. All rights reserved.<BR>

 # This program and the accompanying materials

 # are licensed and made available under the terms and conditions of the BSD License

 # which accompanies this distribution.  The full text of the license may be found at

@@ -38,7 +38,7 @@
 from Common.Misc import ProcessDuplicatedInf

 import re

 from Common.Parsing import IsValidWord

-

+from Common.VariableAttributes import VariableAttributes

 import Common.GlobalData as GlobalData

 

 ## Platform build information from DSC file

@@ -133,6 +133,7 @@
         self._SkuName           = None

         self._SkuIdentifier     = None

         self._PcdInfoFlag       = None

+        self._VarCheckFlag = None

         self._FlashDefinition   = None

         self._BuildNumber       = None

         self._MakefileName      = None

@@ -233,6 +234,8 @@
                 self._SkuIdentifier = Record[2]

             elif Name == TAB_DSC_DEFINES_PCD_INFO_GENERATION:

                 self._PcdInfoFlag = Record[2]

+            elif Name == TAB_DSC_DEFINES_PCD_VAR_CHECK_GENERATION:

+                self._VarCheckFlag = Record[2]

             elif Name == TAB_FIX_LOAD_TOP_MEMORY_ADDRESS:

                 try:

                     self._LoadFixAddress = int (Record[2], 0)

@@ -352,6 +355,13 @@
             return True

         else:

             return False

+    def _GetVarCheckFlag(self):  

+        if self._VarCheckFlag == None or self._VarCheckFlag.upper() == 'FALSE':

+            return False

+        elif self._VarCheckFlag.upper() == 'TRUE':

+            return True

+        else:

+            return False

             

     def _GetSkuIdentifier(self):

         if self._SkuName:

@@ -898,6 +908,17 @@
                

         return Pcds

 

+    def CompareVarAttr(self, Attr1, Attr2):

+        if not Attr1 or not Attr2:  # for empty string

+            return True

+        Attr1s = [attr.strip() for attr in Attr1.split(",")]

+        Attr1Set = set(Attr1s)

+        Attr2s = [attr.strip() for attr in Attr2.split(",")]

+        Attr2Set = set(Attr2s)

+        if Attr2Set == Attr1Set:

+            return True

+        else:

+            return False

     ## Retrieve dynamic HII PCD settings

     #

     #   @param  Type    PCD type

@@ -907,6 +928,7 @@
     def _GetDynamicHiiPcd(self, Type):

         

         SkuObj = SkuClass(self.SkuIdentifier,self.SkuIds)

+        VariableAttrs = {}

         

         Pcds = sdict()

         #

@@ -931,8 +953,12 @@
             Setting = PcdDict[self._Arch, SkuName, PcdCName, TokenSpaceGuid]

             if Setting == None:

                 continue

-            VariableName, VariableGuid, VariableOffset, DefaultValue = self._ValidatePcd(PcdCName, TokenSpaceGuid, Setting, Type, Dummy4)

+            VariableName, VariableGuid, VariableOffset, DefaultValue, VarAttribute = self._ValidatePcd(PcdCName, TokenSpaceGuid, Setting, Type, Dummy4)

             

+            rt, Msg = VariableAttributes.ValidateVarAttributes(VarAttribute)

+            if not rt:

+                EdkLogger.error("build", PCD_VARIABLE_ATTRIBUTES_ERROR, "Variable attributes settings for %s is incorrect.\n %s" % (".".join((TokenSpaceGuid, PcdCName)), Msg),

+                        ExtraData = "[%s]" % VarAttribute)

             ExceedMax = False

             FormatCorrect = True

             if VariableOffset.isdigit():

@@ -955,8 +981,14 @@
             

             if ExceedMax:

                 EdkLogger.error('Build', OPTION_VALUE_INVALID, "The variable offset value must not exceed the maximum value of 0xFFFF (UINT16) for %s." % ".".join((TokenSpaceGuid,PcdCName)))

+            if (VariableName, VariableGuid) not in VariableAttrs:

+                VariableAttrs[(VariableName, VariableGuid)] = VarAttribute

+            else:

+                if not self.CompareVarAttr(VariableAttrs[(VariableName, VariableGuid)], VarAttribute):

+                    EdkLogger.error('Build', PCD_VARIABLE_ATTRIBUTES_CONFLICT_ERROR, "The variable %s.%s for DynamicHii PCDs has conflicting attributes [%s] and [%s] " % (VariableGuid, VariableName, VarAttribute, VariableAttrs[(VariableName, VariableGuid)]))

             

-            SkuInfo = SkuInfoClass(SkuName, self.SkuIds[SkuName], VariableName, VariableGuid, VariableOffset, DefaultValue)

+            SkuInfo = SkuInfoClass(SkuName, self.SkuIds[SkuName], VariableName, VariableGuid, VariableOffset, DefaultValue, VariableAttribute = VarAttribute)

+            pcdDecObject = self._DecPcds[PcdCName, TokenSpaceGuid]

             if (PcdCName,TokenSpaceGuid) in Pcds.keys():  

                 pcdObject = Pcds[PcdCName,TokenSpaceGuid]

                 pcdObject.SkuInfoList[SkuName] = SkuInfo

@@ -971,7 +1003,10 @@
                                                 '',

                                                 {SkuName : SkuInfo},

                                                 False,

-                                                None

+                                                None,

+                                                pcdDecObject.validateranges,

+                                                pcdDecObject.validlists,

+                                                pcdDecObject.expressions

                                                 )

                 

 

@@ -1143,6 +1178,7 @@
     SkuName             = property(_GetSkuName, _SetSkuName)

     SkuIdentifier       = property(_GetSkuIdentifier)

     PcdInfoFlag         = property(_GetPcdInfoFlag)

+    VarCheckFlag = property(_GetVarCheckFlag)

     FlashDefinition     = property(_GetFdfFile)

     BuildNumber         = property(_GetBuildNumber)

     MakefileName        = property(_GetMakefileName)

@@ -1462,6 +1498,7 @@
 

             DefaultValue, DatumType, TokenNumber = AnalyzePcdData(Setting)

                                        

+            validateranges, validlists, expressions = self._RawData.GetValidExpression(TokenSpaceGuid, PcdCName)                          

             Pcds[PcdCName, TokenSpaceGuid, self._PCD_TYPE_STRING_[Type]] = PcdClassObject(

                                                                             PcdCName,

                                                                             TokenSpaceGuid,

@@ -1472,7 +1509,10 @@
                                                                             '',

                                                                             {},

                                                                             False,

-                                                                            None

+                                                                            None,

+                                                                            list(validateranges),

+                                                                            list(validlists),

+                                                                            list(expressions)

                                                                             )

         return Pcds