From 82a6a9605c35f814bd6187979980258ed1b75abd Mon Sep 17 00:00:00 2001 From: Bob Feng Date: Fri, 10 Apr 2015 06:59:47 +0000 Subject: [PATCH] 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" Reviewed-by: "Chen, Hesheng" Reviewed-by: "Liu, Yingke D" git-svn-id: https://svn.code.sf.net/p/edk2/code/trunk/edk2@17158 6f19259b-4bc3-4df7-8a09-765794883524 --- BaseTools/Source/Python/AutoGen/AutoGen.py | 5 +- BaseTools/Source/Python/AutoGen/GenC.py | 19 +- BaseTools/Source/Python/AutoGen/GenPcdDb.py | 54 +- .../Python/AutoGen/ValidCheckingInfoObject.py | 351 +++++++++ .../Source/Python/Common/BuildToolError.py | 5 +- BaseTools/Source/Python/Common/DataType.py | 3 +- BaseTools/Source/Python/Common/Misc.py | 8 +- .../Source/Python/Common/RangeExpression.py | 737 ++++++++++++++++++ .../Python/Common/VariableAttributes.py | 57 ++ .../Python/CommonDataClass/CommonClass.py | 5 +- .../Python/Workspace/BuildClassObject.py | 7 +- .../Source/Python/Workspace/MetaFileParser.py | 4 +- .../Source/Python/Workspace/MetaFileTable.py | 22 +- .../Python/Workspace/WorkspaceDatabase.py | 52 +- 14 files changed, 1299 insertions(+), 30 deletions(-) create mode 100644 BaseTools/Source/Python/AutoGen/ValidCheckingInfoObject.py create mode 100644 BaseTools/Source/Python/Common/RangeExpression.py create mode 100644 BaseTools/Source/Python/Common/VariableAttributes.py diff --git a/BaseTools/Source/Python/AutoGen/AutoGen.py b/BaseTools/Source/Python/AutoGen/AutoGen.py index cd61e8e758..a1e1818e3b 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.
+# Copyright (c) 2007 - 2015, Intel Corporation. All rights reserved.
# 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 @@ class PlatformAutoGen(AutoGen): 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 a140cc80a4..9bdb0363b2 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.
+# Copyright (c) 2007 - 2015, Intel Corporation. All rights reserved.
# 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 @@ def CreateModulePcdCode(Info, AutoGenC, AutoGenH, Pcd): 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 @@ def CreateModulePcdCode(Info, AutoGenC, AutoGenH, Pcd): 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 @@ def CreateModulePcdCode(Info, AutoGenC, AutoGenH, Pcd): 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 @@ def CreateLibraryPcdCode(Info, AutoGenC, AutoGenH, Pcd): 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 @@ def CreateLibraryPcdCode(Info, AutoGenC, AutoGenH, Pcd): 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 e995e141da..4ccd2d65e3 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.
+# Copyright (c) 2013 - 2015, Intel Corporation. All rights reserved.
# 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 StringIO import StringIO 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 @@ class DbVariableTableItemList (DbComItemList): 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 @@ class DbVariableTableItemList (DbComItemList): 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 @@ def BuildExDataBase(Dict): # 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 @@ def BuildExDataBase(Dict): 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 @@ def BuildExDataBase(Dict): 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 @@ def CreatePcdDatabasePhaseSpecificAutoGen (Platform, Phase): 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 @@ def CreatePcdDatabasePhaseSpecificAutoGen (Platform, Phase): 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 @@ def CreatePcdDatabasePhaseSpecificAutoGen (Platform, Phase): 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 @@ def CreatePcdDatabasePhaseSpecificAutoGen (Platform, Phase): # 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 @@ def CreatePcdDatabasePhaseSpecificAutoGen (Platform, Phase): 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 0000000000..4a6e031053 --- /dev/null +++ b/BaseTools/Source/Python/AutoGen/ValidCheckingInfoObject.py @@ -0,0 +1,351 @@ +# Copyright (c) 2015, Intel Corporation. All rights reserved.
+# 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 b9512a1b4d..0a393fec60 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.
+# Copyright (c) 2007 - 2015, Intel Corporation. All rights reserved.
# 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 @@ EOT_ERROR = 0xF005 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 6d66523847..b4abc88e3e 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.
+# Copyright (c) 2007 - 2015, Intel Corporation. All rights reserved.
# Portions copyright (c) 2011 - 2013, ARM Ltd. All rights reserved.
# 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_SUPPORTED_ARCHITECTURES = 'SUPPORTED_ARCHITECTURES' 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 96ee30b2bf..79073e2fef 100644 --- a/BaseTools/Source/Python/Common/Misc.py +++ b/BaseTools/Source/Python/Common/Misc.py @@ -1508,15 +1508,17 @@ def AnalyzeDscPcd(Setting, PcdType, DataType=''): 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 0000000000..5da4a476f4 --- /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.
+# 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 0000000000..a2e22ca040 --- /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.
+# 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 bb4b434af8..5e908a6edf 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.
+# Copyright (c) 2007 - 2015, Intel Corporation. All rights reserved.
# 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 PpiClass(GuidProtocolPpiCommonClass): # 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 @@ class SkuInfoClass(object): 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 8b98f164fd..ea26e5e5a1 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.
+# Copyright (c) 2007 - 2015, Intel Corporation. All rights reserved.
# 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 @@ from Common.BuildToolError import * # @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 @@ class PcdClassObject(object): 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 f96c73c1db..eb02b664a6 100644 --- a/BaseTools/Source/Python/Workspace/MetaFileParser.py +++ b/BaseTools/Source/Python/Workspace/MetaFileParser.py @@ -376,7 +376,8 @@ class MetaFileParser(object): 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 @@ class DscParser(MetaFileParser): "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 607225a0ef..89a12cd228 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.
+# Copyright (c) 2008 - 2015, Intel Corporation. All rights reserved.
# 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 @@ class PackageTable(MetaFileTable): 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 83f730e629..9f79f74e8f 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.
+# Copyright (c) 2008 - 2015, Intel Corporation. All rights reserved.
# 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 AnalyzeDscPcd 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 @@ class DscBuildData(PlatformBuildClassObject): 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 @@ class DscBuildData(PlatformBuildClassObject): 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 @@ class DscBuildData(PlatformBuildClassObject): 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 @@ class DscBuildData(PlatformBuildClassObject): 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 @@ class DscBuildData(PlatformBuildClassObject): def _GetDynamicHiiPcd(self, Type): SkuObj = SkuClass(self.SkuIdentifier,self.SkuIds) + VariableAttrs = {} Pcds = sdict() # @@ -931,8 +953,12 @@ class DscBuildData(PlatformBuildClassObject): 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 @@ class DscBuildData(PlatformBuildClassObject): 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 @@ class DscBuildData(PlatformBuildClassObject): '', {SkuName : SkuInfo}, False, - None + None, + pcdDecObject.validateranges, + pcdDecObject.validlists, + pcdDecObject.expressions ) @@ -1143,6 +1178,7 @@ class DscBuildData(PlatformBuildClassObject): 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 @@ class DecBuildData(PackageBuildClassObject): 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 @@ class DecBuildData(PackageBuildClassObject): '', {}, False, - None + None, + list(validateranges), + list(validlists), + list(expressions) ) return Pcds -- 2.39.2