BaseTool/VfrCompiler: Support Bit fields in EFI/Buffer VarStore
REF: https://bugzilla.tianocore.org/show_bug.cgi?id=545 Enhance VfrCompiler to parse following case: 1. EFI/Buffer VarStore can contain bit fields in their structure. 2. For question Oneof/Checkbox/numeric, their storage can be bit fields of an EFI VarStore/Buffer VarStore. Cc: Eric Dong <eric.dong@intel.com> Cc: Liming Gao <liming.gao@intel.com> Contributed-under: TianoCore Contribution Agreement 1.1 Signed-off-by: Dandan Bi <dandan.bi@intel.com> Reviewed-by: Eric Dong <eric.dong@intel.com> Reviewed-by: Liming Gao <liming.gao@intel.com>
This commit is contained in:
@@ -600,6 +600,61 @@ CVfrVarDataTypeDB::ExtractStructTypeName (
|
||||
return VFR_RETURN_SUCCESS;
|
||||
}
|
||||
|
||||
/**
|
||||
Check whether the DataType contain bit field.
|
||||
|
||||
@param TypeName The name of the type.
|
||||
|
||||
**/
|
||||
BOOLEAN
|
||||
CVfrVarDataTypeDB::DataTypeHasBitField (
|
||||
IN CHAR8 *TypeName
|
||||
)
|
||||
{
|
||||
SVfrDataType *pType = NULL;
|
||||
SVfrDataField *pTmp;
|
||||
|
||||
GetDataType (TypeName, &pType);
|
||||
for (pTmp = pType->mMembers; pTmp!= NULL; pTmp = pTmp->mNext) {
|
||||
if (pTmp->mIsBitField) {
|
||||
return TRUE;
|
||||
}
|
||||
}
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
/**
|
||||
Check whether the field is bit field or not.
|
||||
|
||||
@param VarStr Point to the field name which may contain the structure name.
|
||||
|
||||
**/
|
||||
BOOLEAN
|
||||
CVfrVarDataTypeDB::IsThisBitField (
|
||||
IN CHAR8 *VarStr
|
||||
)
|
||||
{
|
||||
CHAR8 FName[MAX_NAME_LEN];
|
||||
CHAR8 TName[MAX_NAME_LEN];
|
||||
UINT32 ArrayIdx;
|
||||
SVfrDataType *pType = NULL;
|
||||
SVfrDataField *pField = NULL;
|
||||
|
||||
CHECK_ERROR_RETURN (ExtractStructTypeName (VarStr, TName), VFR_RETURN_SUCCESS);
|
||||
CHECK_ERROR_RETURN (GetDataType (TName, &pType), VFR_RETURN_SUCCESS);
|
||||
|
||||
while (*VarStr != '\0') {
|
||||
CHECK_ERROR_RETURN(ExtractFieldNameAndArrary(VarStr, FName, ArrayIdx), VFR_RETURN_SUCCESS);
|
||||
CHECK_ERROR_RETURN(GetTypeField (FName, pType, pField), VFR_RETURN_SUCCESS);
|
||||
pType = pField->mFieldType;
|
||||
}
|
||||
if (pField->mIsBitField) {
|
||||
return TRUE;
|
||||
} else {
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
EFI_VFR_RETURN_CODE
|
||||
CVfrVarDataTypeDB::ExtractFieldNameAndArrary (
|
||||
IN CHAR8 *&VarStr,
|
||||
@@ -697,7 +752,8 @@ EFI_VFR_RETURN_CODE
|
||||
CVfrVarDataTypeDB::GetFieldOffset (
|
||||
IN SVfrDataField *Field,
|
||||
IN UINT32 ArrayIdx,
|
||||
OUT UINT32 &Offset
|
||||
OUT UINT32 &Offset,
|
||||
IN BOOLEAN IsBitField
|
||||
)
|
||||
{
|
||||
if (Field == NULL) {
|
||||
@@ -729,8 +785,11 @@ CVfrVarDataTypeDB::GetFieldOffset (
|
||||
// return VFR_RETURN_ERROR_ARRARY_NUM;
|
||||
// }
|
||||
//
|
||||
|
||||
Offset = Field->mOffset + Field->mFieldType->mTotalSize * ((ArrayIdx == INVALID_ARRAY_INDEX) ? 0 : ArrayIdx);
|
||||
if (IsBitField) {
|
||||
Offset = Field->mBitOffset + Field->mFieldType->mTotalSize * ((ArrayIdx == INVALID_ARRAY_INDEX) ? 0 : ArrayIdx) * 8;
|
||||
} else {
|
||||
Offset = Field->mOffset + Field->mFieldType->mTotalSize * ((ArrayIdx == INVALID_ARRAY_INDEX) ? 0 : ArrayIdx);
|
||||
}
|
||||
return VFR_RETURN_SUCCESS;
|
||||
}
|
||||
|
||||
@@ -749,7 +808,8 @@ CVfrVarDataTypeDB::GetFieldWidth (
|
||||
UINT32
|
||||
CVfrVarDataTypeDB::GetFieldSize (
|
||||
IN SVfrDataField *Field,
|
||||
IN UINT32 ArrayIdx
|
||||
IN UINT32 ArrayIdx,
|
||||
IN BOOLEAN BitField
|
||||
)
|
||||
{
|
||||
if (Field == NULL) {
|
||||
@@ -757,9 +817,13 @@ CVfrVarDataTypeDB::GetFieldSize (
|
||||
}
|
||||
|
||||
if ((ArrayIdx == INVALID_ARRAY_INDEX) && (Field->mArrayNum != 0)) {
|
||||
return Field->mFieldType->mTotalSize * Field->mArrayNum;
|
||||
return Field->mFieldType->mTotalSize * Field->mArrayNum;
|
||||
} else {
|
||||
return Field->mFieldType->mTotalSize;
|
||||
if (BitField) {
|
||||
return Field->mBitWidth;
|
||||
} else {
|
||||
return Field->mFieldType->mTotalSize;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -788,18 +852,21 @@ CVfrVarDataTypeDB::InternalTypesListInit (
|
||||
pYearField->mOffset = 0;
|
||||
pYearField->mNext = pMonthField;
|
||||
pYearField->mArrayNum = 0;
|
||||
pYearField->mIsBitField = FALSE;
|
||||
|
||||
strcpy (pMonthField->mFieldName, "Month");
|
||||
GetDataType ((CHAR8 *)"UINT8", &pMonthField->mFieldType);
|
||||
pMonthField->mOffset = 2;
|
||||
pMonthField->mNext = pDayField;
|
||||
pMonthField->mArrayNum = 0;
|
||||
pMonthField->mIsBitField = FALSE;
|
||||
|
||||
strcpy (pDayField->mFieldName, "Day");
|
||||
GetDataType ((CHAR8 *)"UINT8", &pDayField->mFieldType);
|
||||
pDayField->mOffset = 3;
|
||||
pDayField->mNext = NULL;
|
||||
pDayField->mArrayNum = 0;
|
||||
pDayField->mIsBitField = FALSE;
|
||||
|
||||
New->mMembers = pYearField;
|
||||
} else if (strcmp (gInternalTypesTable[Index].mTypeName, "EFI_HII_TIME") == 0) {
|
||||
@@ -812,18 +879,21 @@ CVfrVarDataTypeDB::InternalTypesListInit (
|
||||
pHoursField->mOffset = 0;
|
||||
pHoursField->mNext = pMinutesField;
|
||||
pHoursField->mArrayNum = 0;
|
||||
pHoursField->mIsBitField = FALSE;
|
||||
|
||||
strcpy (pMinutesField->mFieldName, "Minutes");
|
||||
GetDataType ((CHAR8 *)"UINT8", &pMinutesField->mFieldType);
|
||||
pMinutesField->mOffset = 1;
|
||||
pMinutesField->mNext = pSecondsField;
|
||||
pMinutesField->mArrayNum = 0;
|
||||
pMinutesField->mIsBitField = FALSE;
|
||||
|
||||
strcpy (pSecondsField->mFieldName, "Seconds");
|
||||
GetDataType ((CHAR8 *)"UINT8", &pSecondsField->mFieldType);
|
||||
pSecondsField->mOffset = 2;
|
||||
pSecondsField->mNext = NULL;
|
||||
pSecondsField->mArrayNum = 0;
|
||||
pSecondsField->mIsBitField = FALSE;
|
||||
|
||||
New->mMembers = pHoursField;
|
||||
} else if (strcmp (gInternalTypesTable[Index].mTypeName, "EFI_HII_REF") == 0) {
|
||||
@@ -837,24 +907,28 @@ CVfrVarDataTypeDB::InternalTypesListInit (
|
||||
pQuestionIdField->mOffset = 0;
|
||||
pQuestionIdField->mNext = pFormIdField;
|
||||
pQuestionIdField->mArrayNum = 0;
|
||||
pQuestionIdField->mIsBitField = FALSE;
|
||||
|
||||
strcpy (pFormIdField->mFieldName, "FormId");
|
||||
GetDataType ((CHAR8 *)"UINT16", &pFormIdField->mFieldType);
|
||||
pFormIdField->mOffset = 2;
|
||||
pFormIdField->mNext = pFormSetGuidField;
|
||||
pFormIdField->mArrayNum = 0;
|
||||
pFormIdField->mIsBitField = FALSE;
|
||||
|
||||
strcpy (pFormSetGuidField->mFieldName, "FormSetGuid");
|
||||
GetDataType ((CHAR8 *)"EFI_GUID", &pFormSetGuidField->mFieldType);
|
||||
pFormSetGuidField->mOffset = 4;
|
||||
pFormSetGuidField->mNext = pDevicePathField;
|
||||
pFormSetGuidField->mArrayNum = 0;
|
||||
pFormSetGuidField->mIsBitField = FALSE;
|
||||
|
||||
strcpy (pDevicePathField->mFieldName, "DevicePath");
|
||||
GetDataType ((CHAR8 *)"EFI_STRING_ID", &pDevicePathField->mFieldType);
|
||||
pDevicePathField->mOffset = 20;
|
||||
pDevicePathField->mNext = NULL;
|
||||
pDevicePathField->mArrayNum = 0;
|
||||
pDevicePathField->mIsBitField = FALSE;
|
||||
|
||||
New->mMembers = pQuestionIdField;
|
||||
} else {
|
||||
@@ -978,6 +1052,7 @@ CVfrVarDataTypeDB::DeclareDataTypeBegin (
|
||||
pNewType->mTotalSize = 0;
|
||||
pNewType->mMembers = NULL;
|
||||
pNewType->mNext = NULL;
|
||||
pNewType->mHasBitField = FALSE;
|
||||
|
||||
mNewDataType = pNewType;
|
||||
}
|
||||
@@ -1009,6 +1084,125 @@ CVfrVarDataTypeDB::SetNewTypeName (
|
||||
return VFR_RETURN_SUCCESS;
|
||||
}
|
||||
|
||||
/**
|
||||
Record the bit field info in the data type.
|
||||
|
||||
@param FieldName Point to the field name.
|
||||
@param TypeName Point to the type name.
|
||||
@param Width The bit width.
|
||||
@param FieldInUnion The filed is in Union type or Structure type.
|
||||
|
||||
**/
|
||||
EFI_VFR_RETURN_CODE
|
||||
CVfrVarDataTypeDB::DataTypeAddBitField (
|
||||
IN CHAR8 *FieldName,
|
||||
IN CHAR8 *TypeName,
|
||||
IN UINT32 Width,
|
||||
IN BOOLEAN FieldInUnion
|
||||
)
|
||||
{
|
||||
SVfrDataField *pNewField = NULL;
|
||||
SVfrDataType *pFieldType = NULL;
|
||||
SVfrDataField *pTmp;
|
||||
UINT32 Align;
|
||||
UINT32 MaxDataTypeSize;
|
||||
BOOLEAN UpdateTotalSize;
|
||||
|
||||
CHECK_ERROR_RETURN (GetDataType (TypeName, &pFieldType), VFR_RETURN_SUCCESS);
|
||||
|
||||
if (Width > MAX_BIT_WIDTH) {
|
||||
return VFR_RETURN_BIT_WIDTH_ERROR;
|
||||
}
|
||||
|
||||
if (Width > pFieldType->mTotalSize * 8) {
|
||||
return VFR_RETURN_BIT_WIDTH_ERROR;
|
||||
}
|
||||
|
||||
if (FieldName != NULL && strlen (FieldName) >= MAX_NAME_LEN) {
|
||||
return VFR_RETURN_INVALID_PARAMETER;
|
||||
}
|
||||
|
||||
if (Width == 0 && FieldName != NULL) {
|
||||
return VFR_RETURN_INVALID_PARAMETER;
|
||||
}
|
||||
|
||||
for (pTmp = mNewDataType->mMembers; pTmp != NULL; pTmp = pTmp->mNext) {
|
||||
if (FieldName != NULL && strcmp (pTmp->mFieldName, FieldName) == 0) {
|
||||
return VFR_RETURN_REDEFINED;
|
||||
}
|
||||
}
|
||||
|
||||
Align = MIN (mPackAlign, pFieldType->mAlign);
|
||||
UpdateTotalSize = FALSE;
|
||||
|
||||
if ((pNewField = new SVfrDataField) == NULL) {
|
||||
return VFR_RETURN_OUT_FOR_RESOURCES;
|
||||
}
|
||||
|
||||
MaxDataTypeSize = mNewDataType->mTotalSize;
|
||||
if (FieldName != NULL) {
|
||||
strcpy (pNewField->mFieldName, FieldName);
|
||||
}
|
||||
pNewField->mFieldType = pFieldType;
|
||||
pNewField->mIsBitField = TRUE;
|
||||
pNewField->mBitWidth = Width;
|
||||
pNewField->mArrayNum = 0;
|
||||
pNewField->mBitOffset = 0;
|
||||
pNewField->mOffset = 0;
|
||||
|
||||
if (mNewDataType->mMembers == NULL) {
|
||||
mNewDataType->mMembers = pNewField;
|
||||
pNewField->mNext = NULL;
|
||||
} else {
|
||||
for (pTmp = mNewDataType->mMembers; pTmp->mNext != NULL; pTmp = pTmp->mNext)
|
||||
;
|
||||
pTmp->mNext = pNewField;
|
||||
pNewField->mNext = NULL;
|
||||
}
|
||||
|
||||
if (FieldInUnion) {
|
||||
pNewField->mOffset = 0;
|
||||
if (MaxDataTypeSize < pNewField->mFieldType->mTotalSize) {
|
||||
mNewDataType->mTotalSize = pNewField->mFieldType->mTotalSize;
|
||||
}
|
||||
} else {
|
||||
//
|
||||
// Check whether the bit fileds can be contained within one FieldType.
|
||||
//
|
||||
if (pTmp != NULL && pTmp->mIsBitField && strcmp (pTmp->mFieldType->mTypeName, pNewField->mFieldType->mTypeName) == 0 &&
|
||||
(pTmp->mBitOffset - pTmp->mOffset * 8) + pTmp->mBitWidth + pNewField->mBitWidth <= pNewField->mFieldType->mTotalSize * 8) {
|
||||
pNewField->mBitOffset = pTmp->mBitOffset + pTmp->mBitWidth;
|
||||
pNewField->mOffset = pTmp->mOffset;
|
||||
//
|
||||
// If BitWidth=0,used to force alignment at the next word boundary.
|
||||
// So make this bit field occupy the remaing bit width of current field type.
|
||||
//
|
||||
if (pNewField->mBitWidth == 0) {
|
||||
pNewField->mBitWidth = pNewField->mFieldType->mTotalSize * 8 - (pNewField->mBitOffset - pTmp->mOffset * 8);
|
||||
}
|
||||
} else {
|
||||
//
|
||||
// The bit filed start a new memory
|
||||
//
|
||||
pNewField->mBitOffset = mNewDataType->mTotalSize * 8;
|
||||
UpdateTotalSize = TRUE;
|
||||
}
|
||||
}
|
||||
|
||||
if (UpdateTotalSize){
|
||||
if ((mNewDataType->mTotalSize % Align) == 0) {
|
||||
pNewField->mOffset = mNewDataType->mTotalSize;
|
||||
} else {
|
||||
pNewField->mOffset = mNewDataType->mTotalSize + ALIGN_STUFF(mNewDataType->mTotalSize, Align);
|
||||
}
|
||||
mNewDataType->mTotalSize = pNewField->mOffset + (pNewField->mFieldType->mTotalSize);
|
||||
}
|
||||
|
||||
mNewDataType->mAlign = MIN (mPackAlign, MAX (pFieldType->mAlign, mNewDataType->mAlign));
|
||||
mNewDataType->mHasBitField = TRUE;
|
||||
return VFR_RETURN_SUCCESS;
|
||||
}
|
||||
|
||||
EFI_VFR_RETURN_CODE
|
||||
CVfrVarDataTypeDB::DataTypeAddField (
|
||||
IN CHAR8 *FieldName,
|
||||
@@ -1044,6 +1238,7 @@ CVfrVarDataTypeDB::DataTypeAddField (
|
||||
strcpy (pNewField->mFieldName, FieldName);
|
||||
pNewField->mFieldType = pFieldType;
|
||||
pNewField->mArrayNum = ArrayNum;
|
||||
pNewField->mIsBitField = FALSE;
|
||||
if ((mNewDataType->mTotalSize % Align) == 0) {
|
||||
pNewField->mOffset = mNewDataType->mTotalSize;
|
||||
} else {
|
||||
@@ -1183,21 +1378,26 @@ CVfrVarDataTypeDB::GetDataFieldInfo (
|
||||
IN CHAR8 *VarStr,
|
||||
OUT UINT16 &Offset,
|
||||
OUT UINT8 &Type,
|
||||
OUT UINT32 &Size
|
||||
OUT UINT32 &Size,
|
||||
OUT BOOLEAN &BitField
|
||||
)
|
||||
{
|
||||
CHAR8 TName[MAX_NAME_LEN], FName[MAX_NAME_LEN];
|
||||
UINT32 ArrayIdx, Tmp;
|
||||
SVfrDataType *pType = NULL;
|
||||
SVfrDataField *pField = NULL;
|
||||
CHAR8 *VarStrName;
|
||||
|
||||
Offset = 0;
|
||||
Type = EFI_IFR_TYPE_OTHER;
|
||||
Size = 0;
|
||||
VarStrName = VarStr;
|
||||
|
||||
CHECK_ERROR_RETURN (ExtractStructTypeName (VarStr, TName), VFR_RETURN_SUCCESS);
|
||||
CHECK_ERROR_RETURN (GetDataType (TName, &pType), VFR_RETURN_SUCCESS);
|
||||
|
||||
BitField = IsThisBitField (VarStrName);
|
||||
|
||||
//
|
||||
// if it is not struct data type
|
||||
//
|
||||
@@ -1205,13 +1405,17 @@ CVfrVarDataTypeDB::GetDataFieldInfo (
|
||||
Size = pType->mTotalSize;
|
||||
|
||||
while (*VarStr != '\0') {
|
||||
CHECK_ERROR_RETURN(ExtractFieldNameAndArrary(VarStr, FName, ArrayIdx), VFR_RETURN_SUCCESS);
|
||||
CHECK_ERROR_RETURN(ExtractFieldNameAndArrary(VarStr, FName, ArrayIdx), VFR_RETURN_SUCCESS);
|
||||
CHECK_ERROR_RETURN(GetTypeField (FName, pType, pField), VFR_RETURN_SUCCESS);
|
||||
pType = pField->mFieldType;
|
||||
CHECK_ERROR_RETURN(GetFieldOffset (pField, ArrayIdx, Tmp), VFR_RETURN_SUCCESS);
|
||||
Offset = (UINT16) (Offset + Tmp);
|
||||
CHECK_ERROR_RETURN(GetFieldOffset (pField, ArrayIdx, Tmp, pField->mIsBitField), VFR_RETURN_SUCCESS);
|
||||
if (BitField && !pField->mIsBitField) {
|
||||
Offset = (UINT16) (Offset + Tmp * 8);
|
||||
} else {
|
||||
Offset = (UINT16) (Offset + Tmp);
|
||||
}
|
||||
Type = GetFieldWidth (pField);
|
||||
Size = GetFieldSize (pField, ArrayIdx);
|
||||
Size = GetFieldSize (pField, ArrayIdx, BitField);
|
||||
}
|
||||
return VFR_RETURN_SUCCESS;
|
||||
}
|
||||
@@ -1360,6 +1564,7 @@ SVfrVarStorageNode::SVfrVarStorageNode (
|
||||
IN CHAR8 *StoreName,
|
||||
IN EFI_VARSTORE_ID VarStoreId,
|
||||
IN SVfrDataType *DataType,
|
||||
IN BOOLEAN BitsVarstore,
|
||||
IN BOOLEAN Flag
|
||||
)
|
||||
{
|
||||
@@ -1376,7 +1581,11 @@ SVfrVarStorageNode::SVfrVarStorageNode (
|
||||
}
|
||||
mNext = NULL;
|
||||
mVarStoreId = VarStoreId;
|
||||
mVarStoreType = EFI_VFR_VARSTORE_BUFFER;
|
||||
if (BitsVarstore) {
|
||||
mVarStoreType = EFI_VFR_VARSTORE_BUFFER_BITS;
|
||||
} else {
|
||||
mVarStoreType = EFI_VFR_VARSTORE_BUFFER;
|
||||
}
|
||||
mStorageInfo.mDataType = DataType;
|
||||
mAssignedFlag = Flag;
|
||||
}
|
||||
@@ -1648,6 +1857,7 @@ CVfrDataStorage::DeclareBufferVarStore (
|
||||
IN CVfrVarDataTypeDB *DataTypeDB,
|
||||
IN CHAR8 *TypeName,
|
||||
IN EFI_VARSTORE_ID VarStoreId,
|
||||
IN BOOLEAN IsBitVarStore,
|
||||
IN BOOLEAN Flag
|
||||
)
|
||||
{
|
||||
@@ -1674,7 +1884,7 @@ CVfrDataStorage::DeclareBufferVarStore (
|
||||
MarkVarStoreIdUsed (VarStoreId);
|
||||
}
|
||||
|
||||
if ((pNew = new SVfrVarStorageNode (Guid, StoreName, VarStoreId, pDataType, Flag)) == NULL) {
|
||||
if ((pNew = new SVfrVarStorageNode (Guid, StoreName, VarStoreId, pDataType, IsBitVarStore, Flag)) == NULL) {
|
||||
return VFR_RETURN_OUT_FOR_RESOURCES;
|
||||
}
|
||||
|
||||
@@ -2388,6 +2598,7 @@ EFI_VARSTORE_INFO::EFI_VARSTORE_INFO (
|
||||
mInfo.mVarOffset = EFI_VAROFFSET_INVALID;
|
||||
mVarType = EFI_IFR_TYPE_OTHER;
|
||||
mVarTotalSize = 0;
|
||||
mIsBitVar = FALSE;
|
||||
}
|
||||
|
||||
EFI_VARSTORE_INFO::EFI_VARSTORE_INFO (
|
||||
@@ -2399,6 +2610,7 @@ EFI_VARSTORE_INFO::EFI_VARSTORE_INFO (
|
||||
mInfo.mVarOffset = Info.mInfo.mVarOffset;
|
||||
mVarType = Info.mVarType;
|
||||
mVarTotalSize = Info.mVarTotalSize;
|
||||
mIsBitVar = Info.mIsBitVar;
|
||||
}
|
||||
|
||||
EFI_VARSTORE_INFO&
|
||||
@@ -2412,6 +2624,7 @@ EFI_VARSTORE_INFO::operator= (
|
||||
mInfo.mVarOffset = Info.mInfo.mVarOffset;
|
||||
mVarType = Info.mVarType;
|
||||
mVarTotalSize = Info.mVarTotalSize;
|
||||
mIsBitVar = Info.mIsBitVar;
|
||||
}
|
||||
|
||||
return *this;
|
||||
@@ -2426,7 +2639,8 @@ EFI_VARSTORE_INFO::operator == (
|
||||
(mInfo.mVarName == Info->mInfo.mVarName) &&
|
||||
(mInfo.mVarOffset == Info->mInfo.mVarOffset) &&
|
||||
(mVarType == Info->mVarType) &&
|
||||
(mVarTotalSize == Info->mVarTotalSize)) {
|
||||
(mVarTotalSize == Info->mVarTotalSize) &&
|
||||
(mIsBitVar == Info->mIsBitVar)) {
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
|
Reference in New Issue
Block a user