BaseTools/ECC: Add a new checkpoint

Add a new checkpoint to check if the SMM communication parameter has
a correct buffer type.

Contributed-under: TianoCore Contribution Agreement 1.0
Signed-off-by: Hess Chen <hesheng.chen@intel.com>
Reviewed-by: Yonghong Zhu <yonghong.zhu@intel.com>
This commit is contained in:
Hess Chen
2017-04-11 16:17:19 +08:00
committed by Yonghong Zhu
parent 86601b7895
commit 703ef6cfd5
4 changed files with 159 additions and 2 deletions

View File

@ -41,6 +41,134 @@ class Check(object):
self.DeclAndDataTypeCheck()
self.FunctionLayoutCheck()
self.NamingConventionCheck()
self.SmmCommParaCheck()
def SmmCommParaCheck(self):
self.SmmCommParaCheckBufferType()
# Check if SMM communication function has correct parameter type
# 1. Get function calling with instance./->Communicate() interface
# and make sure the protocol instance is of type EFI_SMM_COMMUNICATION_PROTOCOL.
# 2. Find the origin of the 2nd parameter of Communicate() interface, if -
# a. it is a local buffer on stack
# report error.
# b. it is a global buffer, check the driver that holds the global buffer is of type DXE_RUNTIME_DRIVER
# report success.
# c. it is a buffer by AllocatePage/AllocatePool (may be wrapped by nested function calls),
# check the EFI_MEMORY_TYPE to be EfiRuntimeServicesCode,EfiRuntimeServicesData,
# EfiACPIMemoryNVS or EfiReservedMemoryType
# report success.
# d. it is a buffer located via EFI_SYSTEM_TABLE.ConfigurationTable (may be wrapped by nested function calls)
# report warning to indicate human code review.
# e. it is a buffer from other kind of pointers (may need to trace into nested function calls to locate),
# repeat checks in a.b.c and d.
def SmmCommParaCheckBufferType(self):
if EccGlobalData.gConfig.SmmCommParaCheckBufferType == '1' or EccGlobalData.gConfig.SmmCommParaCheckAll == '1':
EdkLogger.quiet("Checking SMM communication parameter type ...")
# Get all EFI_SMM_COMMUNICATION_PROTOCOL interface
CommApiList = []
for IdentifierTable in EccGlobalData.gIdentifierTableList:
SqlCommand = """select ID, Name, BelongsToFile from %s
where Modifier = 'EFI_SMM_COMMUNICATION_PROTOCOL*' """ % (IdentifierTable)
RecordSet = EccGlobalData.gDb.TblFile.Exec(SqlCommand)
if RecordSet:
for Record in RecordSet:
if Record[1] not in CommApiList:
CommApiList.append(Record[1])
# For each interface, check the second parameter
for CommApi in CommApiList:
for IdentifierTable in EccGlobalData.gIdentifierTableList:
SqlCommand = """select ID, Name, Value, BelongsToFile, StartLine from %s
where Name = '%s->Communicate' and Model = %s""" \
% (IdentifierTable, CommApi, MODEL_IDENTIFIER_FUNCTION_CALLING)
RecordSet = EccGlobalData.gDb.TblFile.Exec(SqlCommand)
if RecordSet:
# print IdentifierTable
for Record in RecordSet:
# Get the second parameter for Communicate function
SecondPara = Record[2].split(',')[1].strip()
SecondParaIndex = None
if SecondPara.startswith('&'):
SecondPara = SecondPara[1:]
if SecondPara.endswith(']'):
SecondParaIndex = SecondPara[SecondPara.find('[') + 1:-1]
SecondPara = SecondPara[:SecondPara.find('[')]
# Get the ID
Id = Record[0]
# Get the BelongsToFile
BelongsToFile = Record[3]
# Get the source file path
SqlCommand = """select FullPath from File where ID = %s""" % BelongsToFile
NewRecordSet = EccGlobalData.gDb.TblFile.Exec(SqlCommand)
FullPath = NewRecordSet[0][0]
# Get the line no of function calling
StartLine = Record[4]
# Get the module type
SqlCommand = """select Value3 from INF where BelongsToFile = (select ID from File
where Path = (select Path from File where ID = %s) and Model = 1011)
and Value2 = 'MODULE_TYPE'""" % BelongsToFile
NewRecordSet = EccGlobalData.gDb.TblFile.Exec(SqlCommand)
ModuleType = NewRecordSet[0][0] if NewRecordSet else None
# print BelongsToFile, FullPath, StartLine, ModuleType, SecondPara
Value = FindPara(FullPath, SecondPara, StartLine)
# Find the value of the parameter
if Value:
if 'AllocatePage' in Value \
or 'AllocatePool' in Value \
or 'AllocateRuntimePool' in Value \
or 'AllocateZeroPool' in Value:
pass
else:
if '->' in Value:
if not EccGlobalData.gException.IsException(
ERROR_SMM_COMM_PARA_CHECK_BUFFER_TYPE, Value):
EccGlobalData.gDb.TblReport.Insert(ERROR_SMM_COMM_PARA_CHECK_BUFFER_TYPE,
OtherMsg="Please review the buffer type"
+ "is correct or not. If it is correct" +
" please add [%s] to exception list"
% Value,
BelongsToTable=IdentifierTable,
BelongsToItem=Id)
else:
if not EccGlobalData.gException.IsException(
ERROR_SMM_COMM_PARA_CHECK_BUFFER_TYPE, Value):
EccGlobalData.gDb.TblReport.Insert(ERROR_SMM_COMM_PARA_CHECK_BUFFER_TYPE,
OtherMsg="Please review the buffer type"
+ "is correct or not. If it is correct" +
" please add [%s] to exception list"
% Value,
BelongsToTable=IdentifierTable,
BelongsToItem=Id)
# Not find the value of the parameter
else:
SqlCommand = """select ID, Modifier, Name, Value, Model, BelongsToFunction from %s
where Name = '%s' and StartLine < %s order by StartLine DESC""" \
% (IdentifierTable, SecondPara, StartLine)
NewRecordSet = EccGlobalData.gDb.TblFile.Exec(SqlCommand)
if NewRecordSet:
Value = NewRecordSet[0][1]
if 'AllocatePage' in Value \
or 'AllocatePool' in Value \
or 'AllocateRuntimePool' in Value \
or 'AllocateZeroPool' in Value:
pass
else:
if not EccGlobalData.gException.IsException(
ERROR_SMM_COMM_PARA_CHECK_BUFFER_TYPE, Value):
EccGlobalData.gDb.TblReport.Insert(ERROR_SMM_COMM_PARA_CHECK_BUFFER_TYPE,
OtherMsg="Please review the buffer type"
+ "is correct or not. If it is correct" +
" please add [%s] to exception list"
% Value,
BelongsToTable=IdentifierTable,
BelongsToItem=Id)
else:
pass
# Check UNI files
def UniCheck(self):
@ -1261,6 +1389,19 @@ class Check(object):
if not EccGlobalData.gException.IsException(ERROR_NAMING_CONVENTION_CHECK_SINGLE_CHARACTER_VARIABLE, Record[1]):
EccGlobalData.gDb.TblReport.Insert(ERROR_NAMING_CONVENTION_CHECK_SINGLE_CHARACTER_VARIABLE, OtherMsg="The variable name [%s] does not follow the rules" % (Record[1]), BelongsToTable=FileTable, BelongsToItem=Record[0])
def FindPara(FilePath, Para, CallingLine):
Lines = open(FilePath).readlines()
Line = ''
for Index in range(CallingLine - 1, 0, -1):
# Find the nearest statement for Para
Line = Lines[Index].strip()
if Line.startswith('%s = ' % Para):
Line = Line.strip()
return Line
break
return ''
##
#
# This acts like the main() function for the script, unless it is 'import'ed into another