/** @file | |
The implementation of EDKII Redfish Platform Config Protocol. | |
(C) Copyright 2021-2022 Hewlett Packard Enterprise Development LP<BR> | |
Copyright (c) 2022-2023, NVIDIA CORPORATION & AFFILIATES. All rights reserved. | |
SPDX-License-Identifier: BSD-2-Clause-Patent | |
**/ | |
#include "RedfishPlatformConfigDxe.h" | |
#include "RedfishPlatformConfigImpl.h" | |
REDFISH_PLATFORM_CONFIG_PRIVATE *mRedfishPlatformConfigPrivate = NULL; | |
/** | |
Create a new stack instance with given stack size. | |
@param[in] StackSize The size of stack. | |
@retval REDFISH_STACK * Pointer to created stack. | |
@retval NULL Out of resource. | |
**/ | |
REDFISH_STACK * | |
NewRedfishStack ( | |
IN UINTN StackSize | |
) | |
{ | |
REDFISH_STACK *Buffer; | |
if (StackSize == 0) { | |
return NULL; | |
} | |
Buffer = AllocateZeroPool (sizeof (REDFISH_STACK)); | |
if (Buffer == NULL) { | |
return NULL; | |
} | |
Buffer->Pool = AllocateZeroPool (sizeof (VOID *) * StackSize); | |
if (Buffer->Pool == NULL) { | |
FreePool (Buffer); | |
return NULL; | |
} | |
Buffer->Size = StackSize; | |
Buffer->Index = 0; | |
return Buffer; | |
} | |
/** | |
Release stack buffer. | |
@param[in] Stack Pointer to stack instance. | |
**/ | |
VOID | |
ReleaseRedfishStack ( | |
IN REDFISH_STACK *Stack | |
) | |
{ | |
if (Stack == NULL) { | |
return; | |
} | |
FreePool (Stack->Pool); | |
FreePool (Stack); | |
} | |
/** | |
Check and see if stack is empty or not. | |
@param[in] Stack Pointer to stack instance. | |
@retval TRUE Stack is empty. | |
@retval FALSE Stack is not empty. | |
**/ | |
BOOLEAN | |
IsEmptyRedfishStack ( | |
IN REDFISH_STACK *Stack | |
) | |
{ | |
return (Stack->Index == 0); | |
} | |
/** | |
Push an item to stack. | |
@param[in] Stack Pointer to stack instance. | |
@param[in] Data Pointer to data. | |
@retval EFI_OUT_OF_RESOURCES Stack is full. | |
@retval EFI_SUCCESS Item is pushed successfully. | |
**/ | |
EFI_STATUS | |
PushRedfishStack ( | |
IN REDFISH_STACK *Stack, | |
IN VOID *Data | |
) | |
{ | |
if (Stack->Index == Stack->Size) { | |
return EFI_OUT_OF_RESOURCES; | |
} | |
Stack->Pool[Stack->Index] = Data; | |
Stack->Index += 1; | |
return EFI_SUCCESS; | |
} | |
/** | |
Pop an item from stack. | |
@param[in] Stack Pointer to stack instance. | |
@retval VOID * Pointer to popped item. | |
@retval NULL Stack is empty. | |
**/ | |
VOID * | |
PopRedfishStack ( | |
IN REDFISH_STACK *Stack | |
) | |
{ | |
if (IsEmptyRedfishStack (Stack)) { | |
return NULL; | |
} | |
Stack->Index -= 1; | |
return Stack->Pool[Stack->Index]; | |
} | |
/** | |
Seach forms in this HII package and find which form links to give form. | |
@param[in] FormPrivate Pointer to form private instance. | |
@retval REDFISH_PLATFORM_CONFIG_FORM_PRIVATE Pointer to target form | |
@retval NULL No form links to give form. | |
**/ | |
REDFISH_PLATFORM_CONFIG_FORM_PRIVATE * | |
FindFormLinkToThis ( | |
IN REDFISH_PLATFORM_CONFIG_FORM_PRIVATE *FormPrivate | |
) | |
{ | |
LIST_ENTRY *HiiFormLink; | |
LIST_ENTRY *HiiNextFormLink; | |
REDFISH_PLATFORM_CONFIG_FORM_PRIVATE *HiiFormPrivate; | |
LIST_ENTRY *HiiStatementLink; | |
LIST_ENTRY *HiiNextStatementLink; | |
REDFISH_PLATFORM_CONFIG_STATEMENT_PRIVATE *HiiStatementPrivate; | |
REDFISH_PLATFORM_CONFIG_FORM_SET_PRIVATE *HiiFormsetPrivate; | |
if (FormPrivate == NULL) { | |
return NULL; | |
} | |
HiiFormsetPrivate = FormPrivate->ParentFormset; | |
if (IsListEmpty (&HiiFormsetPrivate->HiiFormList)) { | |
return NULL; | |
} | |
HiiFormLink = GetFirstNode (&HiiFormsetPrivate->HiiFormList); | |
while (!IsNull (&HiiFormsetPrivate->HiiFormList, HiiFormLink)) { | |
HiiFormPrivate = REDFISH_PLATFORM_CONFIG_FORM_FROM_LINK (HiiFormLink); | |
HiiNextFormLink = GetNextNode (&HiiFormsetPrivate->HiiFormList, HiiFormLink); | |
// | |
// Skip myself | |
// | |
if (HiiFormPrivate == FormPrivate) { | |
HiiFormLink = HiiNextFormLink; | |
continue; | |
} | |
HiiStatementLink = GetFirstNode (&HiiFormPrivate->StatementList); | |
while (!IsNull (&HiiFormPrivate->StatementList, HiiStatementLink)) { | |
HiiStatementPrivate = REDFISH_PLATFORM_CONFIG_STATEMENT_FROM_LINK (HiiStatementLink); | |
HiiNextStatementLink = GetNextNode (&HiiFormPrivate->StatementList, HiiStatementLink); | |
// | |
// Check go-to opcode and find form ID. If form ID is the same ID as given form, | |
// this go-to opcode links to given form. | |
// | |
if ((HiiStatementPrivate->HiiStatement->Operand == EFI_IFR_REF_OP) && | |
(HiiStatementPrivate->HiiStatement->Value.Value.ref.FormId == FormPrivate->HiiForm->FormId)) | |
{ | |
return HiiFormPrivate; | |
} | |
HiiStatementLink = HiiNextStatementLink; | |
} | |
HiiFormLink = HiiNextFormLink; | |
} | |
return NULL; | |
} | |
/** | |
Build the menu path to given statement instance. It is caller's | |
responsibility to free returned string buffer. | |
@param[in] StatementPrivate Pointer to statement private instance. | |
@retval CHAR8 * Menu path to given statement. | |
@retval NULL Can not find menu path. | |
**/ | |
CHAR8 * | |
BuildMenPath ( | |
IN REDFISH_PLATFORM_CONFIG_STATEMENT_PRIVATE *StatementPrivate | |
) | |
{ | |
REDFISH_STACK *FormStack; | |
REDFISH_PLATFORM_CONFIG_FORM_PRIVATE *FormPrivate; | |
UINTN OldBufferSize; | |
UINTN NewBufferSize; | |
CHAR8 *Buffer; | |
CHAR8 *FormTitle; | |
EFI_STATUS Status; | |
Buffer = NULL; | |
OldBufferSize = 0; | |
NewBufferSize = 0; | |
FormStack = NewRedfishStack (REDFISH_MENU_PATH_SIZE); | |
if (FormStack == NULL) { | |
return NULL; | |
} | |
// | |
// Build form link stack | |
// | |
FormPrivate = StatementPrivate->ParentForm; | |
Status = PushRedfishStack (FormStack, (VOID *)FormPrivate); | |
if (EFI_ERROR (Status)) { | |
goto RELEASE; | |
} | |
do { | |
DEBUG ((REDFISH_PLATFORM_CONFIG_DEBUG, "F(%d) <-", FormPrivate->Id)); | |
FormPrivate = FindFormLinkToThis (FormPrivate); | |
if (FormPrivate == NULL) { | |
break; | |
} | |
PushRedfishStack (FormStack, (VOID *)FormPrivate); | |
if (EFI_ERROR (Status)) { | |
break; | |
} | |
} while (TRUE); | |
if (IsEmptyRedfishStack (FormStack)) { | |
goto RELEASE; | |
} | |
// | |
// Initial Buffer to empty string for error case. | |
// | |
OldBufferSize = AsciiStrSize (""); | |
Buffer = AllocateCopyPool (OldBufferSize, ""); | |
if (Buffer == NULL) { | |
goto RELEASE; | |
} | |
// | |
// Build menu path in string format | |
// | |
FormPrivate = (REDFISH_PLATFORM_CONFIG_FORM_PRIVATE *)PopRedfishStack (FormStack); | |
while (FormPrivate != NULL) { | |
FormTitle = HiiGetEnglishAsciiString (FormPrivate->ParentFormset->HiiHandle, FormPrivate->Title); | |
if (FormTitle != NULL) { | |
NewBufferSize = AsciiStrSize (FormTitle) + OldBufferSize; | |
Buffer = ReallocatePool (OldBufferSize, NewBufferSize, Buffer); | |
if (Buffer == NULL) { | |
goto RELEASE; | |
} | |
OldBufferSize = NewBufferSize; | |
AsciiStrCatS (Buffer, OldBufferSize, "/"); | |
AsciiStrCatS (Buffer, OldBufferSize, FormTitle); | |
FreePool (FormTitle); | |
DEBUG ((REDFISH_PLATFORM_CONFIG_DEBUG, " %a\n", Buffer)); | |
} | |
FormPrivate = (REDFISH_PLATFORM_CONFIG_FORM_PRIVATE *)PopRedfishStack (FormStack); | |
} | |
RELEASE: | |
ReleaseRedfishStack (FormStack); | |
return Buffer; | |
} | |
/** | |
Get the attribute name from config language. | |
For example: /Bios/Attributes/BiosOption1 is config language | |
and attribute name is BiosOption1. | |
@param[in] ConfigLanguage Config language string. | |
@retval CHAR8 * Attribute name string. | |
@retval NULL Can not find attribute name. | |
**/ | |
CHAR8 * | |
GetAttributeNameFromConfigLanguage ( | |
IN CHAR8 *ConfigLanguage | |
) | |
{ | |
CHAR8 *attributeName; | |
CHAR8 *Pointer; | |
UINTN StrLen; | |
UINTN Index; | |
UINTN AttrStrLen; | |
if (IS_EMPTY_STRING (ConfigLanguage)) { | |
return NULL; | |
} | |
attributeName = NULL; | |
Pointer = NULL; | |
AttrStrLen = 0; | |
StrLen = AsciiStrLen (ConfigLanguage); | |
if (ConfigLanguage[StrLen - 1] == '/') { | |
// | |
// wrong format | |
// | |
DEBUG ((DEBUG_ERROR, "%a: invalid format: %a\n", __func__, ConfigLanguage)); | |
ASSERT (FALSE); | |
return NULL; | |
} | |
Index = StrLen; | |
while (TRUE) { | |
Index -= 1; | |
if (ConfigLanguage[Index] == '/') { | |
Pointer = &ConfigLanguage[Index + 1]; | |
break; | |
} | |
if (Index == 0) { | |
break; | |
} | |
} | |
// | |
// Not found. There is no '/' in input string. | |
// | |
if (Pointer == NULL) { | |
return NULL; | |
} | |
AttrStrLen = StrLen - Index; | |
attributeName = AllocateCopyPool (AttrStrLen, Pointer); | |
return attributeName; | |
} | |
/** | |
Convert one-of options to string array in Redfish attribute. | |
@param[in] HiiHandle HII handle. | |
@param[in] SchemaName Schema string. | |
@param[in] StatementPrivate Pointer to statement instance. | |
@param[out] Values Attribute value array. | |
@retval EFI_SUCCESS Options are converted successfully. | |
@retval Other Error occurs. | |
**/ | |
EFI_STATUS | |
OneOfStatementToAttributeValues ( | |
IN EFI_HII_HANDLE HiiHandle, | |
IN CHAR8 *SchemaName, | |
IN REDFISH_PLATFORM_CONFIG_STATEMENT_PRIVATE *StatementPrivate, | |
OUT EDKII_REDFISH_POSSIBLE_VALUES *Values | |
) | |
{ | |
LIST_ENTRY *Link; | |
HII_QUESTION_OPTION *Option; | |
UINTN Index; | |
HII_STATEMENT *HiiStatement; | |
if ((HiiHandle == NULL) || (StatementPrivate == NULL) || (Values == NULL)) { | |
return EFI_INVALID_PARAMETER; | |
} | |
HiiStatement = StatementPrivate->HiiStatement; | |
ASSERT (HiiStatement != NULL); | |
if (IsListEmpty (&HiiStatement->OptionListHead)) { | |
return EFI_NOT_FOUND; | |
} | |
// | |
// Loop through the option to get count | |
// | |
Values->ValueCount = 0; | |
Link = GetFirstNode (&HiiStatement->OptionListHead); | |
while (!IsNull (&HiiStatement->OptionListHead, Link)) { | |
Option = HII_QUESTION_OPTION_FROM_LINK (Link); | |
if ((Option->SuppressExpression != NULL) && | |
(EvaluateExpressionList (Option->SuppressExpression, TRUE, StatementPrivate->ParentForm->ParentFormset->HiiFormSet, StatementPrivate->ParentForm->HiiForm) != ExpressFalse)) | |
{ | |
Link = GetNextNode (&HiiStatement->OptionListHead, Link); | |
continue; | |
} | |
Values->ValueCount += 1; | |
Link = GetNextNode (&HiiStatement->OptionListHead, Link); | |
} | |
Values->ValueArray = AllocateZeroPool (sizeof (EDKII_REDFISH_ATTRIBUTE_VALUE) * Values->ValueCount); | |
if (Values->ValueArray == NULL) { | |
Values->ValueCount = 0; | |
return EFI_OUT_OF_RESOURCES; | |
} | |
Index = 0; | |
Link = GetFirstNode (&HiiStatement->OptionListHead); | |
while (!IsNull (&HiiStatement->OptionListHead, Link)) { | |
Option = HII_QUESTION_OPTION_FROM_LINK (Link); | |
if ((Option->SuppressExpression != NULL) && | |
(EvaluateExpressionList (Option->SuppressExpression, FALSE, NULL, NULL) != ExpressFalse)) | |
{ | |
Link = GetNextNode (&HiiStatement->OptionListHead, Link); | |
continue; | |
} | |
if (Option->Text != 0) { | |
Values->ValueArray[Index].ValueName = HiiGetRedfishAsciiString (HiiHandle, SchemaName, Option->Text); | |
Values->ValueArray[Index].ValueDisplayName = HiiGetEnglishAsciiString (HiiHandle, Option->Text); | |
} | |
Index += 1; | |
Link = GetNextNode (&HiiStatement->OptionListHead, Link); | |
} | |
return EFI_SUCCESS; | |
} | |
/** | |
Return Redfish attribute type from given HII statement operand. | |
@param[in] HiiStatement Target HII statement. | |
@retval EDKII_REDFISH_ATTRIBUTE_TYPES Attribute type. | |
**/ | |
EDKII_REDFISH_ATTRIBUTE_TYPES | |
HiiStatementToAttributeType ( | |
IN HII_STATEMENT *HiiStatement | |
) | |
{ | |
EDKII_REDFISH_ATTRIBUTE_TYPES type; | |
if (HiiStatement == NULL) { | |
return RedfishAttributeTypeUnknown; | |
} | |
type = RedfishAttributeTypeUnknown; | |
switch (HiiStatement->Operand) { | |
case EFI_IFR_ONE_OF_OP: | |
case EFI_IFR_ORDERED_LIST_OP: | |
type = RedfishAttributeTypeEnumeration; | |
break; | |
case EFI_IFR_STRING_OP: | |
type = RedfishAttributeTypeString; | |
break; | |
case EFI_IFR_NUMERIC_OP: | |
type = RedfishAttributeTypeInteger; | |
break; | |
case EFI_IFR_CHECKBOX_OP: | |
type = RedfishAttributeTypeBoolean; | |
break; | |
case EFI_IFR_DATE_OP: | |
case EFI_IFR_TIME_OP: | |
default: | |
DEBUG ((DEBUG_ERROR, "%a: unsupported operand: 0x%x\n", __func__, HiiStatement->Operand)); | |
break; | |
} | |
return type; | |
} | |
/** | |
Zero extend integer/boolean to UINT64 for comparing. | |
@param Value HII Value to be converted. | |
**/ | |
UINT64 | |
ExtendHiiValueToU64 ( | |
IN HII_STATEMENT_VALUE *Value | |
) | |
{ | |
UINT64 Temp; | |
Temp = 0; | |
switch (Value->Type) { | |
case EFI_IFR_TYPE_NUM_SIZE_8: | |
Temp = Value->Value.u8; | |
break; | |
case EFI_IFR_TYPE_NUM_SIZE_16: | |
Temp = Value->Value.u16; | |
break; | |
case EFI_IFR_TYPE_NUM_SIZE_32: | |
Temp = Value->Value.u32; | |
break; | |
case EFI_IFR_TYPE_BOOLEAN: | |
Temp = Value->Value.b; | |
break; | |
case EFI_IFR_TYPE_TIME: | |
case EFI_IFR_TYPE_DATE: | |
default: | |
break; | |
} | |
return Temp; | |
} | |
/** | |
Set value of a data element in an Array by its Index in ordered list buffer. | |
@param Array The data array. | |
@param Type Type of the data in this array. | |
@param Index Zero based index for data in this array. | |
@param Value The value to be set. | |
**/ | |
VOID | |
OrderedListSetArrayData ( | |
IN VOID *Array, | |
IN UINT8 Type, | |
IN UINTN Index, | |
IN UINT64 Value | |
) | |
{ | |
ASSERT (Array != NULL); | |
switch (Type) { | |
case EFI_IFR_TYPE_NUM_SIZE_8: | |
*(((UINT8 *)Array) + Index) = (UINT8)Value; | |
break; | |
case EFI_IFR_TYPE_NUM_SIZE_16: | |
*(((UINT16 *)Array) + Index) = (UINT16)Value; | |
break; | |
case EFI_IFR_TYPE_NUM_SIZE_32: | |
*(((UINT32 *)Array) + Index) = (UINT32)Value; | |
break; | |
case EFI_IFR_TYPE_NUM_SIZE_64: | |
*(((UINT64 *)Array) + Index) = (UINT64)Value; | |
break; | |
default: | |
break; | |
} | |
} | |
/** | |
Return data element in an Array by its Index in ordered list array buffer. | |
@param Array The data array. | |
@param Type Type of the data in this array. | |
@param Index Zero based index for data in this array. | |
@retval Value The data to be returned | |
**/ | |
UINT64 | |
OrderedListGetArrayData ( | |
IN VOID *Array, | |
IN UINT8 Type, | |
IN UINTN Index | |
) | |
{ | |
UINT64 Data; | |
ASSERT (Array != NULL); | |
Data = 0; | |
switch (Type) { | |
case EFI_IFR_TYPE_NUM_SIZE_8: | |
Data = (UINT64)*(((UINT8 *)Array) + Index); | |
break; | |
case EFI_IFR_TYPE_NUM_SIZE_16: | |
Data = (UINT64)*(((UINT16 *)Array) + Index); | |
break; | |
case EFI_IFR_TYPE_NUM_SIZE_32: | |
Data = (UINT64)*(((UINT32 *)Array) + Index); | |
break; | |
case EFI_IFR_TYPE_NUM_SIZE_64: | |
Data = (UINT64)*(((UINT64 *)Array) + Index); | |
break; | |
default: | |
break; | |
} | |
return Data; | |
} | |
/** | |
Find string ID of option if its value equals to given value. | |
@param[in] HiiStatement Statement to search. | |
@param[in] Value Target value. | |
@retval EFI_SUCCESS HII value is returned successfully. | |
@retval Others Errors occur | |
**/ | |
EFI_STRING_ID | |
OrderedListOptionValueToStringId ( | |
IN HII_STATEMENT *HiiStatement, | |
IN UINT64 Value | |
) | |
{ | |
LIST_ENTRY *Link; | |
HII_QUESTION_OPTION *Option; | |
UINT64 CurrentValue; | |
if (HiiStatement == NULL) { | |
return 0; | |
} | |
if (HiiStatement->Operand != EFI_IFR_ORDERED_LIST_OP) { | |
return 0; | |
} | |
if (IsListEmpty (&HiiStatement->OptionListHead)) { | |
return 0; | |
} | |
Link = GetFirstNode (&HiiStatement->OptionListHead); | |
while (!IsNull (&HiiStatement->OptionListHead, Link)) { | |
Option = HII_QUESTION_OPTION_FROM_LINK (Link); | |
CurrentValue = ExtendHiiValueToU64 (&Option->Value); | |
if (Value == CurrentValue) { | |
return Option->Text; | |
} | |
Link = GetNextNode (&HiiStatement->OptionListHead, Link); | |
} | |
return 0; | |
} | |
/** | |
Compare two value in HII statement format. | |
@param[in] Value1 First value to compare. | |
@param[in] Value2 Second value to be compared. | |
@retval INTN 0 is returned when two values are equal. | |
1 is returned when first value is greater than second value. | |
-1 is returned when second value is greater than first value. | |
**/ | |
INTN | |
CompareHiiStatementValue ( | |
IN HII_STATEMENT_VALUE *Value1, | |
IN HII_STATEMENT_VALUE *Value2 | |
) | |
{ | |
INTN Result; | |
UINT64 Data1; | |
UINT64 Data2; | |
if ((Value1 == NULL) || (Value2 == NULL)) { | |
return -1; | |
} | |
switch (Value1->Type) { | |
case EFI_IFR_TYPE_NUM_SIZE_8: | |
Data1 = Value1->Value.u8; | |
break; | |
case EFI_IFR_TYPE_NUM_SIZE_16: | |
Data1 = Value1->Value.u16; | |
break; | |
case EFI_IFR_TYPE_NUM_SIZE_32: | |
Data1 = Value1->Value.u32; | |
break; | |
case EFI_IFR_TYPE_NUM_SIZE_64: | |
Data1 = Value1->Value.u64; | |
break; | |
case EFI_IFR_TYPE_BOOLEAN: | |
Data1 = (Value1->Value.b ? 1 : 0); | |
break; | |
default: | |
return -1; | |
} | |
switch (Value2->Type) { | |
case EFI_IFR_TYPE_NUM_SIZE_8: | |
Data2 = Value2->Value.u8; | |
break; | |
case EFI_IFR_TYPE_NUM_SIZE_16: | |
Data2 = Value2->Value.u16; | |
break; | |
case EFI_IFR_TYPE_NUM_SIZE_32: | |
Data2 = Value2->Value.u32; | |
break; | |
case EFI_IFR_TYPE_NUM_SIZE_64: | |
Data2 = Value2->Value.u64; | |
break; | |
case EFI_IFR_TYPE_BOOLEAN: | |
Data2 = (Value2->Value.b ? 1 : 0); | |
break; | |
default: | |
return -1; | |
} | |
Result = (Data1 == Data2 ? 0 : (Data1 > Data2 ? 1 : -1)); | |
return Result; | |
} | |
/** | |
Convert HII value to the string in HII one-of opcode. | |
@param[in] HiiStatement HII Statement private instance | |
@param[in] Value HII Statement value | |
@retval EFI_STRING_ID The string ID in HII database. | |
0 is returned when something goes wrong. | |
**/ | |
EFI_STRING_ID | |
HiiValueToOneOfOptionStringId ( | |
IN HII_STATEMENT *HiiStatement, | |
IN HII_STATEMENT_VALUE *Value | |
) | |
{ | |
LIST_ENTRY *Link; | |
HII_QUESTION_OPTION *Option; | |
if ((HiiStatement == NULL) || (Value == NULL)) { | |
return 0; | |
} | |
if (HiiStatement->Operand != EFI_IFR_ONE_OF_OP) { | |
return 0; | |
} | |
if (IsListEmpty (&HiiStatement->OptionListHead)) { | |
return 0; | |
} | |
Link = GetFirstNode (&HiiStatement->OptionListHead); | |
while (!IsNull (&HiiStatement->OptionListHead, Link)) { | |
Option = HII_QUESTION_OPTION_FROM_LINK (Link); | |
if (CompareHiiStatementValue (Value, &Option->Value) == 0) { | |
return Option->Text; | |
} | |
Link = GetNextNode (&HiiStatement->OptionListHead, Link); | |
} | |
return 0; | |
} | |
/** | |
Convert HII string to the value in HII one-of opcode. | |
@param[in] Statement Statement private instance | |
@param[in] Schema Schema string | |
@param[in] HiiString Input string | |
@param[out] Value Value returned | |
@retval EFI_SUCCESS HII value is returned successfully. | |
@retval Others Errors occur | |
**/ | |
EFI_STATUS | |
HiiStringToOneOfOptionValue ( | |
IN REDFISH_PLATFORM_CONFIG_STATEMENT_PRIVATE *Statement, | |
IN CHAR8 *Schema, | |
IN EFI_STRING HiiString, | |
OUT HII_STATEMENT_VALUE *Value | |
) | |
{ | |
LIST_ENTRY *Link; | |
HII_QUESTION_OPTION *Option; | |
EFI_STRING TmpString; | |
BOOLEAN Found; | |
if ((Statement == NULL) || IS_EMPTY_STRING (HiiString) || (Value == NULL)) { | |
return EFI_INVALID_PARAMETER; | |
} | |
if (Statement->HiiStatement->Operand != EFI_IFR_ONE_OF_OP) { | |
return EFI_UNSUPPORTED; | |
} | |
if (IsListEmpty (&Statement->HiiStatement->OptionListHead)) { | |
return EFI_NOT_FOUND; | |
} | |
Found = FALSE; | |
Link = GetFirstNode (&Statement->HiiStatement->OptionListHead); | |
while (!IsNull (&Statement->HiiStatement->OptionListHead, Link)) { | |
Option = HII_QUESTION_OPTION_FROM_LINK (Link); | |
TmpString = HiiGetRedfishString (Statement->ParentForm->ParentFormset->HiiHandle, Schema, Option->Text); | |
if (TmpString != NULL) { | |
if (StrCmp (TmpString, HiiString) == 0) { | |
CopyMem (Value, &Option->Value, sizeof (HII_STATEMENT_VALUE)); | |
Found = TRUE; | |
} | |
FreePool (TmpString); | |
} | |
if (Found) { | |
return EFI_SUCCESS; | |
} | |
Link = GetNextNode (&Statement->HiiStatement->OptionListHead, Link); | |
} | |
return EFI_NOT_FOUND; | |
} | |
/** | |
Convert HII value to numeric value in Redfish format. | |
@param[in] Value Value to be converted. | |
@param[out] RedfishValue Value in Redfish format. | |
@retval EFI_SUCCESS Redfish value is returned successfully. | |
@retval Others Errors occur | |
**/ | |
EFI_STATUS | |
HiiValueToRedfishNumeric ( | |
IN HII_STATEMENT_VALUE *Value, | |
OUT EDKII_REDFISH_VALUE *RedfishValue | |
) | |
{ | |
if ((Value == NULL) || (RedfishValue == NULL)) { | |
return EFI_INVALID_PARAMETER; | |
} | |
switch (Value->Type) { | |
case EFI_IFR_TYPE_NUM_SIZE_8: | |
RedfishValue->Type = RedfishValueTypeInteger; | |
RedfishValue->Value.Integer = (INT64)Value->Value.u8; | |
break; | |
case EFI_IFR_TYPE_NUM_SIZE_16: | |
RedfishValue->Type = RedfishValueTypeInteger; | |
RedfishValue->Value.Integer = (INT64)Value->Value.u16; | |
break; | |
case EFI_IFR_TYPE_NUM_SIZE_32: | |
RedfishValue->Type = RedfishValueTypeInteger; | |
RedfishValue->Value.Integer = (INT64)Value->Value.u32; | |
break; | |
case EFI_IFR_TYPE_NUM_SIZE_64: | |
RedfishValue->Type = RedfishValueTypeInteger; | |
RedfishValue->Value.Integer = (INT64)Value->Value.u64; | |
break; | |
case EFI_IFR_TYPE_BOOLEAN: | |
RedfishValue->Type = RedfishValueTypeBoolean; | |
RedfishValue->Value.Boolean = Value->Value.b; | |
break; | |
default: | |
RedfishValue->Type = RedfishValueTypeUnknown; | |
break; | |
} | |
return EFI_SUCCESS; | |
} | |
/** | |
Convert numeric value in Redfish format to HII value. | |
@param[in] RedfishValue Value in Redfish format to be converted. | |
@param[out] Value HII value returned. | |
@retval EFI_SUCCESS HII value is returned successfully. | |
@retval Others Errors occur | |
**/ | |
EFI_STATUS | |
RedfishNumericToHiiValue ( | |
IN EDKII_REDFISH_VALUE *RedfishValue, | |
OUT HII_STATEMENT_VALUE *Value | |
) | |
{ | |
if ((Value == NULL) || (RedfishValue == NULL)) { | |
return EFI_INVALID_PARAMETER; | |
} | |
switch (RedfishValue->Type) { | |
case RedfishValueTypeInteger: | |
Value->Type = EFI_IFR_TYPE_NUM_SIZE_64; | |
Value->Value.u64 = (UINT64)RedfishValue->Value.Integer; | |
break; | |
case RedfishValueTypeBoolean: | |
Value->Type = EFI_IFR_TYPE_BOOLEAN; | |
Value->Value.b = RedfishValue->Value.Boolean; | |
break; | |
default: | |
Value->Type = EFI_IFR_TYPE_UNDEFINED; | |
break; | |
} | |
return EFI_SUCCESS; | |
} | |
/** | |
Dump the value in ordered list buffer. | |
@param[in] OrderedListStatement Ordered list statement. | |
**/ | |
VOID | |
DumpOrderedListValue ( | |
IN HII_STATEMENT *OrderedListStatement | |
) | |
{ | |
UINT8 *Value8; | |
UINT16 *Value16; | |
UINT32 *Value32; | |
UINT64 *Value64; | |
UINTN Count; | |
UINTN Index; | |
if ((OrderedListStatement == NULL) || (OrderedListStatement->Operand != EFI_IFR_ORDERED_LIST_OP)) { | |
return; | |
} | |
DEBUG ((DEBUG_ERROR, "Value.Type= 0x%x\n", OrderedListStatement->Value.Type)); | |
DEBUG ((DEBUG_ERROR, "Value.BufferValueType= 0x%x\n", OrderedListStatement->Value.BufferValueType)); | |
DEBUG ((DEBUG_ERROR, "Value.BufferLen= 0x%x\n", OrderedListStatement->Value.BufferLen)); | |
DEBUG ((DEBUG_ERROR, "Value.Buffer= 0x%x\n", OrderedListStatement->Value.Buffer)); | |
DEBUG ((DEBUG_ERROR, "Value.MaxContainers= 0x%x\n", OrderedListStatement->ExtraData.OrderListData.MaxContainers)); | |
DEBUG ((DEBUG_ERROR, "StorageWidth= 0x%x\n", OrderedListStatement->StorageWidth)); | |
if (OrderedListStatement->Value.Buffer == NULL) { | |
return; | |
} | |
Value8 = NULL; | |
Value16 = NULL; | |
Value32 = NULL; | |
Value64 = NULL; | |
Count = 0; | |
switch (OrderedListStatement->Value.BufferValueType) { | |
case EFI_IFR_TYPE_NUM_SIZE_8: | |
Value8 = (UINT8 *)OrderedListStatement->Value.Buffer; | |
Count = OrderedListStatement->StorageWidth / sizeof (UINT8); | |
for (Index = 0; Index < Count; Index++) { | |
DEBUG ((DEBUG_ERROR, "%d ", Value8[Index])); | |
} | |
break; | |
case EFI_IFR_TYPE_NUM_SIZE_16: | |
Value16 = (UINT16 *)OrderedListStatement->Value.Buffer; | |
Count = OrderedListStatement->StorageWidth / sizeof (UINT16); | |
for (Index = 0; Index < Count; Index++) { | |
DEBUG ((DEBUG_ERROR, "%d ", Value16[Index])); | |
} | |
break; | |
case EFI_IFR_TYPE_NUM_SIZE_32: | |
Value32 = (UINT32 *)OrderedListStatement->Value.Buffer; | |
Count = OrderedListStatement->StorageWidth / sizeof (UINT32); | |
for (Index = 0; Index < Count; Index++) { | |
DEBUG ((DEBUG_ERROR, "%d ", Value32[Index])); | |
} | |
break; | |
case EFI_IFR_TYPE_NUM_SIZE_64: | |
Value64 = (UINT64 *)OrderedListStatement->Value.Buffer; | |
Count = OrderedListStatement->StorageWidth / sizeof (UINT64); | |
for (Index = 0; Index < Count; Index++) { | |
DEBUG ((DEBUG_ERROR, "%d ", Value64[Index])); | |
} | |
break; | |
default: | |
Value8 = (UINT8 *)OrderedListStatement->Value.Buffer; | |
Count = OrderedListStatement->StorageWidth / sizeof (UINT8); | |
for (Index = 0; Index < Count; Index++) { | |
DEBUG ((DEBUG_ERROR, "%d ", Value8[Index])); | |
} | |
break; | |
} | |
DEBUG ((DEBUG_ERROR, "\n")); | |
} | |
/** | |
Convert HII value to the string in HII ordered list opcode. It's caller's | |
responsibility to free returned buffer using FreePool(). | |
@param[in] HiiStatement HII Statement private instance | |
@param[out] ReturnSize The size of returned array | |
@retval EFI_STRING_ID The string ID array for options in ordered list. | |
**/ | |
EFI_STRING_ID * | |
HiiValueToOrderedListOptionStringId ( | |
IN HII_STATEMENT *HiiStatement, | |
OUT UINTN *ReturnSize | |
) | |
{ | |
LIST_ENTRY *Link; | |
UINTN OptionCount; | |
EFI_STRING_ID *ReturnedArray; | |
UINTN Index; | |
UINT64 Value; | |
if ((HiiStatement == NULL) || (ReturnSize == NULL)) { | |
return NULL; | |
} | |
*ReturnSize = 0; | |
if (HiiStatement->Operand != EFI_IFR_ORDERED_LIST_OP) { | |
return NULL; | |
} | |
if (IsListEmpty (&HiiStatement->OptionListHead)) { | |
return NULL; | |
} | |
DEBUG_CODE ( | |
DumpOrderedListValue (HiiStatement); | |
); | |
OptionCount = 0; | |
Link = GetFirstNode (&HiiStatement->OptionListHead); | |
while (!IsNull (&HiiStatement->OptionListHead, Link)) { | |
++OptionCount; | |
Link = GetNextNode (&HiiStatement->OptionListHead, Link); | |
} | |
*ReturnSize = OptionCount; | |
ReturnedArray = AllocatePool (sizeof (EFI_STRING_ID) * OptionCount); | |
if (ReturnedArray == NULL) { | |
DEBUG ((DEBUG_ERROR, "%a: out of resource\n", __func__)); | |
*ReturnSize = 0; | |
return NULL; | |
} | |
for (Index = 0; Index < OptionCount; Index++) { | |
Value = OrderedListGetArrayData (HiiStatement->Value.Buffer, HiiStatement->Value.BufferValueType, Index); | |
ReturnedArray[Index] = OrderedListOptionValueToStringId (HiiStatement, Value); | |
} | |
return ReturnedArray; | |
} | |
/** | |
Convert HII string to the value in HII ordered list opcode. | |
@param[in] Statement Statement private instance | |
@param[in] Schema Schema string | |
@param[in] HiiString Input string | |
@param[out] Value Value returned | |
@retval EFI_SUCCESS HII value is returned successfully. | |
@retval Others Errors occur | |
**/ | |
EFI_STATUS | |
HiiStringToOrderedListOptionValue ( | |
IN REDFISH_PLATFORM_CONFIG_STATEMENT_PRIVATE *Statement, | |
IN CHAR8 *Schema, | |
IN EFI_STRING HiiString, | |
OUT UINT64 *Value | |
) | |
{ | |
LIST_ENTRY *Link; | |
HII_QUESTION_OPTION *Option; | |
EFI_STRING TmpString; | |
BOOLEAN Found; | |
if ((Statement == NULL) || IS_EMPTY_STRING (HiiString) || (Value == NULL)) { | |
return EFI_INVALID_PARAMETER; | |
} | |
*Value = 0; | |
if (Statement->HiiStatement->Operand != EFI_IFR_ORDERED_LIST_OP) { | |
return EFI_UNSUPPORTED; | |
} | |
if (IsListEmpty (&Statement->HiiStatement->OptionListHead)) { | |
return EFI_NOT_FOUND; | |
} | |
Found = FALSE; | |
Link = GetFirstNode (&Statement->HiiStatement->OptionListHead); | |
while (!IsNull (&Statement->HiiStatement->OptionListHead, Link)) { | |
Option = HII_QUESTION_OPTION_FROM_LINK (Link); | |
TmpString = HiiGetRedfishString (Statement->ParentForm->ParentFormset->HiiHandle, Schema, Option->Text); | |
if (TmpString != NULL) { | |
if (StrCmp (TmpString, HiiString) == 0) { | |
*Value = ExtendHiiValueToU64 (&Option->Value); | |
Found = TRUE; | |
} | |
FreePool (TmpString); | |
} | |
if (Found) { | |
return EFI_SUCCESS; | |
} | |
Link = GetNextNode (&Statement->HiiStatement->OptionListHead, Link); | |
} | |
return EFI_NOT_FOUND; | |
} | |
/** | |
Convert HII value to Redfish value. | |
@param[in] HiiHandle HII handle. | |
@param[in] FullSchema Schema string. | |
@param[in] HiiStatement HII statement. | |
@param[in] Value Value to be converted. | |
@param[out] RedfishValue Value in Redfish format. | |
@retval EFI_SUCCESS Redfish value is returned successfully. | |
@retval Others Errors occur | |
**/ | |
EFI_STATUS | |
HiiValueToRedfishValue ( | |
IN EFI_HII_HANDLE HiiHandle, | |
IN CHAR8 *FullSchema, | |
IN HII_STATEMENT *HiiStatement, | |
IN HII_STATEMENT_VALUE *Value, | |
OUT EDKII_REDFISH_VALUE *RedfishValue | |
) | |
{ | |
EFI_STATUS Status; | |
EFI_STRING_ID StringId; | |
UINTN Index; | |
UINTN Count; | |
EFI_STRING_ID *StringIdArray; | |
if ((HiiHandle == NULL) || (HiiStatement == NULL) || (Value == NULL) || (RedfishValue == NULL) || IS_EMPTY_STRING (FullSchema)) { | |
return EFI_INVALID_PARAMETER; | |
} | |
StringIdArray = NULL; | |
Count = 0; | |
Status = EFI_SUCCESS; | |
switch (HiiStatement->Operand) { | |
case EFI_IFR_ONE_OF_OP: | |
StringId = HiiValueToOneOfOptionStringId (HiiStatement, Value); | |
if (StringId == 0) { | |
ASSERT (FALSE); | |
Status = EFI_DEVICE_ERROR; | |
break; | |
} | |
RedfishValue->Value.Buffer = HiiGetRedfishAsciiString (HiiHandle, FullSchema, StringId); | |
if (RedfishValue->Value.Buffer == NULL) { | |
Status = EFI_OUT_OF_RESOURCES; | |
break; | |
} | |
RedfishValue->Type = RedfishValueTypeString; | |
break; | |
case EFI_IFR_STRING_OP: | |
if (Value->Type != EFI_IFR_TYPE_STRING) { | |
ASSERT (FALSE); | |
Status = EFI_DEVICE_ERROR; | |
break; | |
} | |
RedfishValue->Type = RedfishValueTypeString; | |
RedfishValue->Value.Buffer = AllocatePool (StrLen ((CHAR16 *)Value->Buffer) + 1); | |
UnicodeStrToAsciiStrS ((CHAR16 *)Value->Buffer, RedfishValue->Value.Buffer, StrLen ((CHAR16 *)Value->Buffer) + 1); | |
break; | |
case EFI_IFR_CHECKBOX_OP: | |
case EFI_IFR_NUMERIC_OP: | |
Status = HiiValueToRedfishNumeric (Value, RedfishValue); | |
if (EFI_ERROR (Status)) { | |
DEBUG ((DEBUG_ERROR, "%a: failed to convert HII value to Redfish value: %r\n", __func__, Status)); | |
break; | |
} | |
break; | |
case EFI_IFR_ACTION_OP: | |
if (Value->Type != EFI_IFR_TYPE_ACTION) { | |
ASSERT (FALSE); | |
Status = EFI_DEVICE_ERROR; | |
break; | |
} | |
// | |
// Action has no value. Just return unknown type. | |
// | |
RedfishValue->Type = RedfishValueTypeUnknown; | |
break; | |
case EFI_IFR_ORDERED_LIST_OP: | |
StringIdArray = HiiValueToOrderedListOptionStringId (HiiStatement, &Count); | |
if (StringIdArray == NULL) { | |
ASSERT (FALSE); | |
Status = EFI_DEVICE_ERROR; | |
break; | |
} | |
RedfishValue->Value.StringArray = AllocatePool (sizeof (CHAR8 *) * Count); | |
if (RedfishValue->Value.StringArray == NULL) { | |
ASSERT (FALSE); | |
Status = EFI_OUT_OF_RESOURCES; | |
break; | |
} | |
for (Index = 0; Index < Count; Index++) { | |
ASSERT (StringIdArray[Index] != 0); | |
RedfishValue->Value.StringArray[Index] = HiiGetRedfishAsciiString (HiiHandle, FullSchema, StringIdArray[Index]); | |
ASSERT (RedfishValue->Value.StringArray[Index] != NULL); | |
} | |
RedfishValue->ArrayCount = Count; | |
RedfishValue->Type = RedfishValueTypeStringArray; | |
FreePool (StringIdArray); | |
break; | |
default: | |
DEBUG ((DEBUG_ERROR, "%a: catch unsupported type: 0x%x! Please contact with author if we need to support this type.\n", __func__, HiiStatement->Operand)); | |
ASSERT (FALSE); | |
Status = EFI_UNSUPPORTED; | |
break; | |
} | |
return Status; | |
} | |
/** | |
Convert input ascii string to unicode string. It's caller's | |
responsibility to free returned buffer using FreePool(). | |
@param[in] AsciiString Ascii string to be converted. | |
@retval CHAR16 * Unicode string on return. | |
**/ | |
EFI_STRING | |
StrToUnicodeStr ( | |
IN CHAR8 *AsciiString | |
) | |
{ | |
UINTN StringLen; | |
EFI_STRING Buffer; | |
EFI_STATUS Status; | |
if ((AsciiString == NULL) || (AsciiString[0] == '\0')) { | |
return NULL; | |
} | |
StringLen = AsciiStrLen (AsciiString) + 1; | |
Buffer = AllocatePool (StringLen * sizeof (CHAR16)); | |
if (Buffer == NULL) { | |
return NULL; | |
} | |
Status = AsciiStrToUnicodeStrS (AsciiString, Buffer, StringLen); | |
if (EFI_ERROR (Status)) { | |
FreePool (Buffer); | |
return NULL; | |
} | |
return Buffer; | |
} | |
/** | |
Return the full Redfish schema string from the given Schema and Version. | |
Returned schema string is: Schema + '.' + Version | |
@param[in] Schema Schema string | |
@param[in] Version Schema version string | |
@retval CHAR8 * Schema string. NULL when errors occur. | |
**/ | |
CHAR8 * | |
GetFullSchemaString ( | |
IN CHAR8 *Schema, | |
IN CHAR8 *Version | |
) | |
{ | |
UINTN Size; | |
CHAR8 *FullName; | |
if (IS_EMPTY_STRING (Schema) || IS_EMPTY_STRING (Version)) { | |
return NULL; | |
} | |
Size = AsciiStrSize (CONFIGURE_LANGUAGE_PREFIX) + AsciiStrSize (Schema) + AsciiStrSize (Version); | |
FullName = AllocatePool (Size); | |
if (FullName == NULL) { | |
DEBUG ((DEBUG_ERROR, "%a: out-of-resource\n", __func__)); | |
return NULL; | |
} | |
AsciiSPrint (FullName, Size, "%a%a.%a", CONFIGURE_LANGUAGE_PREFIX, Schema, Version); | |
return FullName; | |
} | |
/** | |
Common implementation to get statement private instance. | |
@param[in] RedfishPlatformConfigPrivate Private instance. | |
@param[in] Schema Redfish schema string. | |
@param[in] ConfigureLang Configure language that refers to this statement. | |
@param[out] Statement Statement instance | |
@retval EFI_SUCCESS HII value is returned successfully. | |
@retval Others Errors occur | |
**/ | |
EFI_STATUS | |
RedfishPlatformConfigGetStatementCommon ( | |
IN REDFISH_PLATFORM_CONFIG_PRIVATE *RedfishPlatformConfigPrivate, | |
IN CHAR8 *Schema, | |
IN EFI_STRING ConfigureLang, | |
OUT REDFISH_PLATFORM_CONFIG_STATEMENT_PRIVATE **Statement | |
) | |
{ | |
EFI_STATUS Status; | |
REDFISH_PLATFORM_CONFIG_STATEMENT_PRIVATE *TargetStatement; | |
if ((RedfishPlatformConfigPrivate == NULL) || IS_EMPTY_STRING (Schema) || IS_EMPTY_STRING (ConfigureLang) || (Statement == NULL)) { | |
return EFI_INVALID_PARAMETER; | |
} | |
*Statement = NULL; | |
Status = ProcessPendingList (&RedfishPlatformConfigPrivate->FormsetList, &RedfishPlatformConfigPrivate->PendingList); | |
if (EFI_ERROR (Status)) { | |
DEBUG ((DEBUG_ERROR, "%a: ProcessPendingList failure: %r\n", __func__, Status)); | |
return Status; | |
} | |
TargetStatement = GetStatementPrivateByConfigureLang (&RedfishPlatformConfigPrivate->FormsetList, Schema, ConfigureLang); | |
if (TargetStatement == NULL) { | |
DEBUG ((DEBUG_ERROR, "%a: No match HII statement is found by the given %s in schema %a\n", __func__, ConfigureLang, Schema)); | |
return EFI_NOT_FOUND; | |
} | |
// | |
// Find current HII question value. | |
// | |
Status = GetQuestionValue ( | |
TargetStatement->ParentForm->ParentFormset->HiiFormSet, | |
TargetStatement->ParentForm->HiiForm, | |
TargetStatement->HiiStatement, | |
GetSetValueWithBuffer | |
); | |
if (EFI_ERROR (Status)) { | |
DEBUG ((DEBUG_ERROR, "%a: failed to get question current value: %r\n", __func__, Status)); | |
return Status; | |
} | |
if (TargetStatement->HiiStatement->Value.Type == EFI_IFR_TYPE_UNDEFINED) { | |
return EFI_DEVICE_ERROR; | |
} | |
// | |
// Return Value. | |
// | |
*Statement = TargetStatement; | |
return EFI_SUCCESS; | |
} | |
/** | |
Get Redfish value with the given Schema and Configure Language. | |
@param[in] This Pointer to EDKII_REDFISH_PLATFORM_CONFIG_PROTOCOL instance. | |
@param[in] Schema The Redfish schema to query. | |
@param[in] Version The Redfish version to query. | |
@param[in] ConfigureLang The target value which match this configure Language. | |
@param[out] Value The returned value. | |
@retval EFI_SUCCESS Value is returned successfully. | |
@retval Others Some error happened. | |
**/ | |
EFI_STATUS | |
EFIAPI | |
RedfishPlatformConfigProtocolGetValue ( | |
IN EDKII_REDFISH_PLATFORM_CONFIG_PROTOCOL *This, | |
IN CHAR8 *Schema, | |
IN CHAR8 *Version, | |
IN EFI_STRING ConfigureLang, | |
OUT EDKII_REDFISH_VALUE *Value | |
) | |
{ | |
EFI_STATUS Status; | |
REDFISH_PLATFORM_CONFIG_PRIVATE *RedfishPlatformConfigPrivate; | |
REDFISH_PLATFORM_CONFIG_STATEMENT_PRIVATE *TargetStatement; | |
CHAR8 *FullSchema; | |
if ((This == NULL) || IS_EMPTY_STRING (Schema) || IS_EMPTY_STRING (Version) || IS_EMPTY_STRING (ConfigureLang) || (Value == NULL)) { | |
return EFI_INVALID_PARAMETER; | |
} | |
RedfishPlatformConfigPrivate = REDFISH_PLATFORM_CONFIG_PRIVATE_FROM_THIS (This); | |
Value->Type = RedfishValueTypeUnknown; | |
Value->ArrayCount = 0; | |
FullSchema = NULL; | |
FullSchema = GetFullSchemaString (Schema, Version); | |
if (FullSchema == NULL) { | |
return EFI_OUT_OF_RESOURCES; | |
} | |
Status = RedfishPlatformConfigGetStatementCommon (RedfishPlatformConfigPrivate, FullSchema, ConfigureLang, &TargetStatement); | |
if (EFI_ERROR (Status)) { | |
goto RELEASE_RESOURCE; | |
} | |
if (TargetStatement->Suppressed) { | |
Status = EFI_ACCESS_DENIED; | |
goto RELEASE_RESOURCE; | |
} | |
Status = HiiValueToRedfishValue ( | |
TargetStatement->ParentForm->ParentFormset->HiiHandle, | |
FullSchema, | |
TargetStatement->HiiStatement, | |
&TargetStatement->HiiStatement->Value, | |
Value | |
); | |
if (EFI_ERROR (Status)) { | |
DEBUG ((DEBUG_ERROR, "%a: HiiValueToRedfishValue failed: %r\n", __func__, Status)); | |
} | |
RELEASE_RESOURCE: | |
if (FullSchema != NULL) { | |
FreePool (FullSchema); | |
} | |
return Status; | |
} | |
/** | |
Function to save question value into HII database. | |
@param[in] HiiFormset HII form-set instance | |
@param[in] HiiForm HII form instance | |
@param[in] HiiStatement HII statement that keeps new value. | |
@param[in] Value New value to apply. | |
@retval EFI_SUCCESS HII value is returned successfully. | |
@retval Others Errors occur | |
**/ | |
EFI_STATUS | |
RedfishPlatformConfigSaveQuestionValue ( | |
IN HII_FORMSET *HiiFormset, | |
IN HII_FORM *HiiForm, | |
IN HII_STATEMENT *HiiStatement, | |
IN HII_STATEMENT_VALUE *Value | |
) | |
{ | |
EFI_STATUS Status; | |
if ((HiiFormset == NULL) || (HiiForm == NULL) || (HiiStatement == NULL) || (Value == NULL)) { | |
return EFI_INVALID_PARAMETER; | |
} | |
Status = SetQuestionValue ( | |
HiiFormset, | |
HiiForm, | |
HiiStatement, | |
Value | |
); | |
if (EFI_ERROR (Status)) { | |
DEBUG ((DEBUG_ERROR, "%a: failed to set question value: %r\n", __func__, Status)); | |
return Status; | |
} | |
Status = SubmitForm (HiiFormset, HiiForm); | |
if (EFI_ERROR (Status)) { | |
DEBUG ((DEBUG_ERROR, "%a: failed to submit form: %r\n", __func__, Status)); | |
return Status; | |
} | |
return EFI_SUCCESS; | |
} | |
/** | |
Common implementation to set statement private instance. | |
@param[in] RedfishPlatformConfigPrivate Private instance. | |
@param[in] Schema Redfish schema string. | |
@param[in] ConfigureLang Configure language that refers to this statement. | |
@param[in] StatementValue Statement value. | |
@retval EFI_SUCCESS HII value is returned successfully. | |
@retval Others Errors occur | |
**/ | |
EFI_STATUS | |
RedfishPlatformConfigSetStatementCommon ( | |
IN REDFISH_PLATFORM_CONFIG_PRIVATE *RedfishPlatformConfigPrivate, | |
IN CHAR8 *Schema, | |
IN EFI_STRING ConfigureLang, | |
IN HII_STATEMENT_VALUE *StatementValue | |
) | |
{ | |
EFI_STATUS Status; | |
REDFISH_PLATFORM_CONFIG_STATEMENT_PRIVATE *TargetStatement; | |
EFI_STRING TempBuffer; | |
UINT8 *StringArray; | |
UINTN Index; | |
UINT64 Value; | |
CHAR8 **CharArray; | |
if ((RedfishPlatformConfigPrivate == NULL) || IS_EMPTY_STRING (Schema) || IS_EMPTY_STRING (ConfigureLang) || (StatementValue == NULL)) { | |
return EFI_INVALID_PARAMETER; | |
} | |
TempBuffer = NULL; | |
StringArray = NULL; | |
Status = ProcessPendingList (&RedfishPlatformConfigPrivate->FormsetList, &RedfishPlatformConfigPrivate->PendingList); | |
if (EFI_ERROR (Status)) { | |
DEBUG ((DEBUG_ERROR, "%a: ProcessPendingList failure: %r\n", __func__, Status)); | |
return Status; | |
} | |
TargetStatement = GetStatementPrivateByConfigureLang (&RedfishPlatformConfigPrivate->FormsetList, Schema, ConfigureLang); | |
if (TargetStatement == NULL) { | |
DEBUG ((DEBUG_ERROR, "%a: No match HII statement is found by the given %s in schema %a\n", __func__, ConfigureLang, Schema)); | |
return EFI_NOT_FOUND; | |
} | |
if (StatementValue->Type != TargetStatement->HiiStatement->Value.Type) { | |
// | |
// We treat one-of type as string in Redfish. But one-of statement is not | |
// in string format from HII point of view. Do a patch here. | |
// | |
if ((TargetStatement->HiiStatement->Operand == EFI_IFR_ONE_OF_OP) && (StatementValue->Type == EFI_IFR_TYPE_STRING)) { | |
TempBuffer = StrToUnicodeStr ((CHAR8 *)StatementValue->Buffer); | |
if (TempBuffer == NULL) { | |
return EFI_OUT_OF_RESOURCES; | |
} | |
FreePool (StatementValue->Buffer); | |
StatementValue->Buffer = NULL; | |
StatementValue->BufferLen = 0; | |
Status = HiiStringToOneOfOptionValue (TargetStatement, Schema, TempBuffer, StatementValue); | |
if (EFI_ERROR (Status)) { | |
DEBUG ((DEBUG_ERROR, "%a: failed to find option value by the given %s\n", __func__, TempBuffer)); | |
FreePool (TempBuffer); | |
return EFI_NOT_FOUND; | |
} | |
FreePool (TempBuffer); | |
} else if ((TargetStatement->HiiStatement->Operand == EFI_IFR_ORDERED_LIST_OP) && (StatementValue->Type == EFI_IFR_TYPE_STRING)) { | |
// | |
// We treat ordered list type as string in Redfish. But ordered list statement is not | |
// in string format from HII point of view. Do a patch here. | |
// | |
StringArray = AllocateZeroPool (TargetStatement->HiiStatement->StorageWidth); | |
if (StringArray == NULL) { | |
return EFI_OUT_OF_RESOURCES; | |
} | |
// | |
// Arrange new option order from input string array | |
// | |
CharArray = (CHAR8 **)StatementValue->Buffer; | |
for (Index = 0; Index < StatementValue->BufferLen; Index++) { | |
TempBuffer = StrToUnicodeStr (CharArray[Index]); | |
if (TempBuffer == NULL) { | |
return EFI_OUT_OF_RESOURCES; | |
} | |
Status = HiiStringToOrderedListOptionValue (TargetStatement, Schema, TempBuffer, &Value); | |
if (EFI_ERROR (Status)) { | |
ASSERT (FALSE); | |
continue; | |
} | |
FreePool (TempBuffer); | |
OrderedListSetArrayData (StringArray, TargetStatement->HiiStatement->Value.BufferValueType, Index, Value); | |
} | |
StatementValue->Type = EFI_IFR_TYPE_BUFFER; | |
StatementValue->Buffer = StringArray; | |
StatementValue->BufferLen = TargetStatement->HiiStatement->StorageWidth; | |
StatementValue->BufferValueType = TargetStatement->HiiStatement->Value.BufferValueType; | |
} else if ((TargetStatement->HiiStatement->Operand == EFI_IFR_NUMERIC_OP) && (StatementValue->Type == EFI_IFR_TYPE_NUM_SIZE_64)) { | |
// | |
// Redfish only has numeric value type and it does not care about the value size. | |
// Do a patch here so we have proper value size applied. | |
// | |
StatementValue->Type = TargetStatement->HiiStatement->Value.Type; | |
} else { | |
DEBUG ((DEBUG_ERROR, "%a: catch value type mismatch! input type: 0x%x but target value type: 0x%x\n", __func__, StatementValue->Type, TargetStatement->HiiStatement->Value.Type)); | |
ASSERT (FALSE); | |
} | |
} | |
Status = RedfishPlatformConfigSaveQuestionValue ( | |
TargetStatement->ParentForm->ParentFormset->HiiFormSet, | |
TargetStatement->ParentForm->HiiForm, | |
TargetStatement->HiiStatement, | |
StatementValue | |
); | |
if (EFI_ERROR (Status)) { | |
DEBUG ((DEBUG_ERROR, "%a: failed to save question value: %r\n", __func__, Status)); | |
return Status; | |
} | |
return EFI_SUCCESS; | |
} | |
/** | |
Set Redfish value with the given Schema and Configure Language. | |
@param[in] This Pointer to EDKII_REDFISH_PLATFORM_CONFIG_PROTOCOL instance. | |
@param[in] Schema The Redfish schema to query. | |
@param[in] Version The Redfish version to query. | |
@param[in] ConfigureLang The target value which match this configure Language. | |
@param[in] Value The value to set. | |
@retval EFI_SUCCESS Value is returned successfully. | |
@retval Others Some error happened. | |
**/ | |
EFI_STATUS | |
EFIAPI | |
RedfishPlatformConfigProtocolSetValue ( | |
IN EDKII_REDFISH_PLATFORM_CONFIG_PROTOCOL *This, | |
IN CHAR8 *Schema, | |
IN CHAR8 *Version, | |
IN EFI_STRING ConfigureLang, | |
IN EDKII_REDFISH_VALUE Value | |
) | |
{ | |
EFI_STATUS Status; | |
REDFISH_PLATFORM_CONFIG_PRIVATE *RedfishPlatformConfigPrivate; | |
CHAR8 *FullSchema; | |
HII_STATEMENT_VALUE NewValue; | |
if ((This == NULL) || IS_EMPTY_STRING (Schema) || IS_EMPTY_STRING (Version) || IS_EMPTY_STRING (ConfigureLang)) { | |
return EFI_INVALID_PARAMETER; | |
} | |
if ((Value.Type == RedfishValueTypeUnknown) || (Value.Type >= RedfishValueTypeMax)) { | |
return EFI_INVALID_PARAMETER; | |
} | |
RedfishPlatformConfigPrivate = REDFISH_PLATFORM_CONFIG_PRIVATE_FROM_THIS (This); | |
FullSchema = NULL; | |
FullSchema = GetFullSchemaString (Schema, Version); | |
if (FullSchema == NULL) { | |
return EFI_OUT_OF_RESOURCES; | |
} | |
ZeroMem (&NewValue, sizeof (HII_STATEMENT_VALUE)); | |
switch (Value.Type) { | |
case RedfishValueTypeInteger: | |
case RedfishValueTypeBoolean: | |
Status = RedfishNumericToHiiValue (&Value, &NewValue); | |
if (EFI_ERROR (Status)) { | |
DEBUG ((DEBUG_ERROR, "%a: failed to convert Redfish value to Hii value: %r\n", __func__, Status)); | |
goto RELEASE_RESOURCE; | |
} | |
break; | |
case RedfishValueTypeString: | |
NewValue.Type = EFI_IFR_TYPE_STRING; | |
NewValue.BufferLen = (UINT16)AsciiStrSize (Value.Value.Buffer); | |
NewValue.Buffer = AllocateCopyPool (NewValue.BufferLen, Value.Value.Buffer); | |
if (NewValue.Buffer == NULL) { | |
Status = EFI_OUT_OF_RESOURCES; | |
goto RELEASE_RESOURCE; | |
} | |
break; | |
case RedfishValueTypeStringArray: | |
NewValue.Type = EFI_IFR_TYPE_STRING; | |
NewValue.BufferLen = (UINT16)Value.ArrayCount; | |
NewValue.Buffer = (UINT8 *)Value.Value.StringArray; | |
break; | |
default: | |
ASSERT (FALSE); | |
break; | |
} | |
Status = RedfishPlatformConfigSetStatementCommon (RedfishPlatformConfigPrivate, FullSchema, ConfigureLang, &NewValue); | |
if (EFI_ERROR (Status)) { | |
DEBUG ((DEBUG_ERROR, "%a: failed to set value to statement: %r\n", __func__, Status)); | |
} | |
RELEASE_RESOURCE: | |
if (FullSchema != NULL) { | |
FreePool (FullSchema); | |
} | |
return Status; | |
} | |
/** | |
Get the list of Configure Language from platform configuration by the given Schema and RegexPattern. | |
@param[in] This Pointer to EDKII_REDFISH_PLATFORM_CONFIG_PROTOCOL instance. | |
@param[in] Schema The Redfish schema to query. | |
@param[in] Version The Redfish version to query. | |
@param[in] RegexPattern The target Configure Language pattern. This is used for regular expression matching. | |
@param[out] ConfigureLangList The list of Configure Language. | |
@param[out] Count The number of Configure Language in ConfigureLangList. | |
@retval EFI_SUCCESS ConfigureLangList is returned successfully. | |
@retval Others Some error happened. | |
**/ | |
EFI_STATUS | |
EFIAPI | |
RedfishPlatformConfigProtocolGetConfigureLang ( | |
IN EDKII_REDFISH_PLATFORM_CONFIG_PROTOCOL *This, | |
IN CHAR8 *Schema, | |
IN CHAR8 *Version, | |
IN EFI_STRING RegexPattern, | |
OUT EFI_STRING **ConfigureLangList, | |
OUT UINTN *Count | |
) | |
{ | |
REDFISH_PLATFORM_CONFIG_PRIVATE *RedfishPlatformConfigPrivate; | |
EFI_STATUS Status; | |
REDFISH_PLATFORM_CONFIG_STATEMENT_PRIVATE_LIST StatementList; | |
REDFISH_PLATFORM_CONFIG_STATEMENT_PRIVATE_REF *StatementRef; | |
LIST_ENTRY *NextLink; | |
EFI_STRING TmpString; | |
EFI_STRING *TmpConfigureLangList; | |
UINTN Index; | |
CHAR8 *FullSchema; | |
if ((This == NULL) || IS_EMPTY_STRING (Schema) || IS_EMPTY_STRING (Version) || (Count == NULL) || (ConfigureLangList == NULL) || IS_EMPTY_STRING (RegexPattern)) { | |
return EFI_INVALID_PARAMETER; | |
} | |
*Count = 0; | |
*ConfigureLangList = NULL; | |
FullSchema = NULL; | |
TmpConfigureLangList = NULL; | |
RedfishPlatformConfigPrivate = REDFISH_PLATFORM_CONFIG_PRIVATE_FROM_THIS (This); | |
Status = ProcessPendingList (&RedfishPlatformConfigPrivate->FormsetList, &RedfishPlatformConfigPrivate->PendingList); | |
if (EFI_ERROR (Status)) { | |
DEBUG ((DEBUG_ERROR, "%a: ProcessPendingList failure: %r\n", __func__, Status)); | |
return Status; | |
} | |
FullSchema = GetFullSchemaString (Schema, Version); | |
if (FullSchema == NULL) { | |
return EFI_OUT_OF_RESOURCES; | |
} | |
Status = GetStatementPrivateByConfigureLangRegex ( | |
RedfishPlatformConfigPrivate->RegularExpressionProtocol, | |
&RedfishPlatformConfigPrivate->FormsetList, | |
FullSchema, | |
RegexPattern, | |
&StatementList | |
); | |
if (EFI_ERROR (Status)) { | |
DEBUG ((DEBUG_ERROR, "%a: GetStatementPrivateByConfigureLangRegex failure: %r\n", __func__, Status)); | |
goto RELEASE_RESOURCE; | |
} | |
if (!IsListEmpty (&StatementList.StatementList)) { | |
TmpConfigureLangList = AllocateZeroPool (sizeof (CHAR16 *) * StatementList.Count); | |
if (TmpConfigureLangList == NULL) { | |
Status = EFI_OUT_OF_RESOURCES; | |
goto RELEASE_RESOURCE; | |
} | |
Index = 0; | |
NextLink = GetFirstNode (&StatementList.StatementList); | |
while (!IsNull (&StatementList.StatementList, NextLink)) { | |
StatementRef = REDFISH_PLATFORM_CONFIG_STATEMENT_REF_FROM_LINK (NextLink); | |
NextLink = GetNextNode (&StatementList.StatementList, NextLink); | |
ASSERT (StatementRef->Statement->Description != 0); | |
if (StatementRef->Statement->Description != 0) { | |
TmpString = HiiGetRedfishString (StatementRef->Statement->ParentForm->ParentFormset->HiiHandle, FullSchema, StatementRef->Statement->Description); | |
ASSERT (TmpString != NULL); | |
if (TmpString != NULL) { | |
TmpConfigureLangList[Index] = AllocateCopyPool (StrSize (TmpString), TmpString); | |
ASSERT (TmpConfigureLangList[Index] != NULL); | |
FreePool (TmpString); | |
++Index; | |
} | |
} | |
} | |
} | |
*Count = StatementList.Count; | |
*ConfigureLangList = TmpConfigureLangList; | |
RELEASE_RESOURCE: | |
if (FullSchema != NULL) { | |
FreePool (FullSchema); | |
} | |
ReleaseStatementList (&StatementList); | |
return Status; | |
} | |
/** | |
Get the list of supported Redfish schema from platform configuration. | |
@param[in] This Pointer to EDKII_REDFISH_PLATFORM_CONFIG_PROTOCOL instance. | |
@param[out] SupportedSchema The supported schema list which is separated by ';'. | |
For example: "x-uefi-redfish-Memory.v1_7_1;x-uefi-redfish-Boot.v1_0_1" | |
The SupportedSchema is allocated by the callee. It's caller's | |
responsibility to free this buffer using FreePool(). | |
@retval EFI_SUCCESS Schema is returned successfully. | |
@retval Others Some error happened. | |
**/ | |
EFI_STATUS | |
EFIAPI | |
RedfishPlatformConfigProtocolGetSupportedSchema ( | |
IN EDKII_REDFISH_PLATFORM_CONFIG_PROTOCOL *This, | |
OUT CHAR8 **SupportedSchema | |
) | |
{ | |
REDFISH_PLATFORM_CONFIG_PRIVATE *RedfishPlatformConfigPrivate; | |
EFI_STATUS Status; | |
LIST_ENTRY *HiiFormsetLink; | |
LIST_ENTRY *HiiFormsetNextLink; | |
REDFISH_PLATFORM_CONFIG_FORM_SET_PRIVATE *HiiFormsetPrivate; | |
UINTN Index; | |
UINTN StringSize; | |
CHAR8 *StringBuffer; | |
UINTN StringIndex; | |
if ((This == NULL) || (SupportedSchema == NULL)) { | |
return EFI_INVALID_PARAMETER; | |
} | |
*SupportedSchema = NULL; | |
RedfishPlatformConfigPrivate = REDFISH_PLATFORM_CONFIG_PRIVATE_FROM_THIS (This); | |
Status = ProcessPendingList (&RedfishPlatformConfigPrivate->FormsetList, &RedfishPlatformConfigPrivate->PendingList); | |
if (EFI_ERROR (Status)) { | |
DEBUG ((DEBUG_ERROR, "%a: ProcessPendingList failure: %r\n", __func__, Status)); | |
return Status; | |
} | |
if (IsListEmpty (&RedfishPlatformConfigPrivate->FormsetList)) { | |
return EFI_NOT_FOUND; | |
} | |
// | |
// Calculate for string buffer size. | |
// | |
StringSize = 0; | |
HiiFormsetLink = GetFirstNode (&RedfishPlatformConfigPrivate->FormsetList); | |
while (!IsNull (&RedfishPlatformConfigPrivate->FormsetList, HiiFormsetLink)) { | |
HiiFormsetNextLink = GetNextNode (&RedfishPlatformConfigPrivate->FormsetList, HiiFormsetLink); | |
HiiFormsetPrivate = REDFISH_PLATFORM_CONFIG_FORMSET_FROM_LINK (HiiFormsetLink); | |
if (HiiFormsetPrivate->SupportedSchema.Count > 0) { | |
for (Index = 0; Index < HiiFormsetPrivate->SupportedSchema.Count; Index++) { | |
StringSize += AsciiStrSize (HiiFormsetPrivate->SupportedSchema.SchemaList[Index]); | |
} | |
} | |
HiiFormsetLink = HiiFormsetNextLink; | |
} | |
if (StringSize == 0) { | |
return EFI_NOT_FOUND; | |
} | |
StringBuffer = AllocatePool (StringSize); | |
if (StringBuffer == NULL) { | |
return EFI_OUT_OF_RESOURCES; | |
} | |
StringIndex = 0; | |
HiiFormsetLink = GetFirstNode (&RedfishPlatformConfigPrivate->FormsetList); | |
while (!IsNull (&RedfishPlatformConfigPrivate->FormsetList, HiiFormsetLink)) { | |
HiiFormsetNextLink = GetNextNode (&RedfishPlatformConfigPrivate->FormsetList, HiiFormsetLink); | |
HiiFormsetPrivate = REDFISH_PLATFORM_CONFIG_FORMSET_FROM_LINK (HiiFormsetLink); | |
if (HiiFormsetPrivate->SupportedSchema.Count > 0) { | |
for (Index = 0; Index < HiiFormsetPrivate->SupportedSchema.Count; Index++) { | |
AsciiStrCpyS (&StringBuffer[StringIndex], (StringSize - StringIndex), HiiFormsetPrivate->SupportedSchema.SchemaList[Index]); | |
StringIndex += AsciiStrLen (HiiFormsetPrivate->SupportedSchema.SchemaList[Index]); | |
StringBuffer[StringIndex] = ';'; | |
++StringIndex; | |
} | |
} | |
HiiFormsetLink = HiiFormsetNextLink; | |
} | |
StringBuffer[--StringIndex] = '\0'; | |
*SupportedSchema = StringBuffer; | |
return EFI_SUCCESS; | |
} | |
/** | |
Get Redfish default value with the given Schema and Configure Language. | |
@param[in] This Pointer to EDKII_REDFISH_PLATFORM_CONFIG_PROTOCOL instance. | |
@param[in] Schema The Redfish schema to query. | |
@param[in] Version The Redfish version to query. | |
@param[in] ConfigureLang The target value which match this configure Language. | |
@param[in] DefaultClass The UEFI defined default class. | |
Please refer to UEFI spec. 33.2.5.8 "defaults" for details. | |
@param[out] Value The returned value. | |
@retval EFI_SUCCESS Value is returned successfully. | |
@retval Others Some error happened. | |
**/ | |
EFI_STATUS | |
EFIAPI | |
RedfishPlatformConfigProtocolGetDefaultValue ( | |
IN EDKII_REDFISH_PLATFORM_CONFIG_PROTOCOL *This, | |
IN CHAR8 *Schema, | |
IN CHAR8 *Version, | |
IN EFI_STRING ConfigureLang, | |
IN UINT16 DefaultClass, | |
OUT EDKII_REDFISH_VALUE *Value | |
) | |
{ | |
EFI_STATUS Status; | |
REDFISH_PLATFORM_CONFIG_PRIVATE *RedfishPlatformConfigPrivate; | |
REDFISH_PLATFORM_CONFIG_STATEMENT_PRIVATE *TargetStatement; | |
CHAR8 *FullSchema; | |
HII_STATEMENT_VALUE DefaultValue; | |
if ((This == NULL) || IS_EMPTY_STRING (Schema) || IS_EMPTY_STRING (Version) || IS_EMPTY_STRING (ConfigureLang) || (Value == NULL)) { | |
return EFI_INVALID_PARAMETER; | |
} | |
RedfishPlatformConfigPrivate = REDFISH_PLATFORM_CONFIG_PRIVATE_FROM_THIS (This); | |
ZeroMem (&DefaultValue, sizeof (HII_STATEMENT_VALUE)); | |
ZeroMem (Value, sizeof (EDKII_REDFISH_VALUE)); | |
FullSchema = NULL; | |
FullSchema = GetFullSchemaString (Schema, Version); | |
if (FullSchema == NULL) { | |
return EFI_OUT_OF_RESOURCES; | |
} | |
Status = RedfishPlatformConfigGetStatementCommon (RedfishPlatformConfigPrivate, FullSchema, ConfigureLang, &TargetStatement); | |
if (EFI_ERROR (Status)) { | |
goto RELEASE_RESOURCE; | |
} | |
if (TargetStatement->Suppressed) { | |
Status = EFI_ACCESS_DENIED; | |
goto RELEASE_RESOURCE; | |
} | |
Status = GetQuestionDefault (TargetStatement->ParentForm->ParentFormset->HiiFormSet, TargetStatement->ParentForm->HiiForm, TargetStatement->HiiStatement, DefaultClass, &DefaultValue); | |
if (EFI_ERROR (Status)) { | |
DEBUG ((DEBUG_ERROR, "%a: GetQuestionDefault failed: %r\n", __func__, Status)); | |
goto RELEASE_RESOURCE; | |
} | |
Status = HiiValueToRedfishValue ( | |
TargetStatement->ParentForm->ParentFormset->HiiHandle, | |
FullSchema, | |
TargetStatement->HiiStatement, | |
&DefaultValue, | |
Value | |
); | |
if (EFI_ERROR (Status)) { | |
DEBUG ((DEBUG_ERROR, "%a: HiiValueToRedfishValue failed: %r\n", __func__, Status)); | |
} | |
RELEASE_RESOURCE: | |
if (FullSchema != NULL) { | |
FreePool (FullSchema); | |
} | |
return Status; | |
} | |
/** | |
Get Redfish attribute value with the given Schema and Configure Language. | |
@param[in] This Pointer to EDKII_REDFISH_PLATFORM_CONFIG_PROTOCOL instance. | |
@param[in] Schema The Redfish schema to query. | |
@param[in] Version The Redfish version to query. | |
@param[in] ConfigureLang The target value which match this configure Language. | |
@param[out] AttributeValue The attribute value. | |
@retval EFI_SUCCESS Value is returned successfully. | |
@retval Others Some error happened. | |
**/ | |
EFI_STATUS | |
EFIAPI | |
RedfishPlatformConfigProtocolGetAttribute ( | |
IN EDKII_REDFISH_PLATFORM_CONFIG_PROTOCOL *This, | |
IN CHAR8 *Schema, | |
IN CHAR8 *Version, | |
IN EFI_STRING ConfigureLang, | |
OUT EDKII_REDFISH_ATTRIBUTE *AttributeValue | |
) | |
{ | |
EFI_STATUS Status; | |
REDFISH_PLATFORM_CONFIG_PRIVATE *RedfishPlatformConfigPrivate; | |
REDFISH_PLATFORM_CONFIG_STATEMENT_PRIVATE *TargetStatement; | |
CHAR8 *FullSchema; | |
CHAR8 *Buffer; | |
if ((This == NULL) || IS_EMPTY_STRING (Schema) || IS_EMPTY_STRING (Version) || IS_EMPTY_STRING (ConfigureLang) || (AttributeValue == NULL)) { | |
return EFI_INVALID_PARAMETER; | |
} | |
RedfishPlatformConfigPrivate = REDFISH_PLATFORM_CONFIG_PRIVATE_FROM_THIS (This); | |
ZeroMem (AttributeValue, sizeof (EDKII_REDFISH_ATTRIBUTE)); | |
FullSchema = NULL; | |
FullSchema = GetFullSchemaString (Schema, Version); | |
if (FullSchema == NULL) { | |
return EFI_OUT_OF_RESOURCES; | |
} | |
Status = RedfishPlatformConfigGetStatementCommon (RedfishPlatformConfigPrivate, FullSchema, ConfigureLang, &TargetStatement); | |
if (EFI_ERROR (Status)) { | |
goto RELEASE_RESOURCE; | |
} | |
if (TargetStatement->Description != 0) { | |
AttributeValue->AttributeName = HiiGetRedfishAsciiString (TargetStatement->ParentForm->ParentFormset->HiiHandle, FullSchema, TargetStatement->Description); | |
Buffer = GetAttributeNameFromConfigLanguage (AttributeValue->AttributeName); | |
if (Buffer != NULL) { | |
FreePool (AttributeValue->AttributeName); | |
AttributeValue->AttributeName = Buffer; | |
} | |
AttributeValue->DisplayName = HiiGetEnglishAsciiString (TargetStatement->ParentForm->ParentFormset->HiiHandle, TargetStatement->Description); | |
} | |
if (TargetStatement->Help != 0) { | |
AttributeValue->HelpText = HiiGetEnglishAsciiString (TargetStatement->ParentForm->ParentFormset->HiiHandle, TargetStatement->Help); | |
} | |
AttributeValue->ReadOnly = ((TargetStatement->Flags & EFI_IFR_FLAG_READ_ONLY) == 0 ? FALSE : TRUE); | |
AttributeValue->ResetRequired = ((TargetStatement->Flags & EFI_IFR_FLAG_RESET_REQUIRED) == 0 ? FALSE : TRUE); | |
AttributeValue->Type = HiiStatementToAttributeType (TargetStatement->HiiStatement); | |
AttributeValue->Suppress = TargetStatement->Suppressed; | |
AttributeValue->GrayedOut = TargetStatement->GrayedOut; | |
// | |
// Build up menu path | |
// | |
AttributeValue->MenuPath = BuildMenPath (TargetStatement); | |
if (AttributeValue->MenuPath == NULL) { | |
DEBUG ((DEBUG_ERROR, "%a: failed to build menu path for \"%a\"\n", __func__, AttributeValue->AttributeName)); | |
} | |
// | |
// Deal with maximum and minimum | |
// | |
if (AttributeValue->Type == RedfishAttributeTypeString) { | |
AttributeValue->StrMaxSize = TargetStatement->StatementData.StrMaxSize; | |
AttributeValue->StrMinSize = TargetStatement->StatementData.StrMinSize; | |
} else if (AttributeValue->Type == RedfishAttributeTypeInteger) { | |
AttributeValue->NumMaximum = TargetStatement->StatementData.NumMaximum; | |
AttributeValue->NumMinimum = TargetStatement->StatementData.NumMinimum; | |
AttributeValue->NumStep = TargetStatement->StatementData.NumStep; | |
} | |
// | |
// Provide value array if this is enumeration type. | |
// | |
if (TargetStatement->HiiStatement->Operand == EFI_IFR_ONE_OF_OP) { | |
Status = OneOfStatementToAttributeValues (TargetStatement->ParentForm->ParentFormset->HiiHandle, FullSchema, TargetStatement, &AttributeValue->Values); | |
if (EFI_ERROR (Status)) { | |
DEBUG ((DEBUG_ERROR, "%a: failed to convert one-of options to attribute values: %r\n", __func__, Status)); | |
} | |
} | |
RELEASE_RESOURCE: | |
if (FullSchema != NULL) { | |
FreePool (FullSchema); | |
} | |
return Status; | |
} | |
/** | |
Functions which are registered to receive notification of | |
database events have this prototype. The actual event is encoded | |
in NotifyType. The following table describes how PackageType, | |
PackageGuid, Handle, and Package are used for each of the | |
notification types. | |
@param[in] PackageType Package type of the notification. | |
@param[in] PackageGuid If PackageType is | |
EFI_HII_PACKAGE_TYPE_GUID, then this is | |
the pointer to the GUID from the Guid | |
field of EFI_HII_PACKAGE_GUID_HEADER. | |
Otherwise, it must be NULL. | |
@param[in] Package Points to the package referred to by the | |
notification Handle The handle of the package | |
list which contains the specified package. | |
@param[in] Handle The HII handle. | |
@param[in] NotifyType The type of change concerning the | |
database. See | |
EFI_HII_DATABASE_NOTIFY_TYPE. | |
**/ | |
EFI_STATUS | |
EFIAPI | |
RedfishPlatformConfigFormUpdateNotify ( | |
IN UINT8 PackageType, | |
IN CONST EFI_GUID *PackageGuid, | |
IN CONST EFI_HII_PACKAGE_HEADER *Package, | |
IN EFI_HII_HANDLE Handle, | |
IN EFI_HII_DATABASE_NOTIFY_TYPE NotifyType | |
) | |
{ | |
EFI_STATUS Status; | |
if ((NotifyType == EFI_HII_DATABASE_NOTIFY_NEW_PACK) || (NotifyType == EFI_HII_DATABASE_NOTIFY_ADD_PACK)) { | |
// | |
// HII formset on this handle is updated by driver during run-time. The formset needs to be reloaded. | |
// | |
Status = NotifyFormsetUpdate (Handle, &mRedfishPlatformConfigPrivate->PendingList); | |
if (EFI_ERROR (Status)) { | |
DEBUG ((DEBUG_ERROR, "%a: failed to notify updated formset of HII handle: 0x%x\n", __func__, Handle)); | |
return Status; | |
} | |
} else if (NotifyType == EFI_HII_DATABASE_NOTIFY_REMOVE_PACK) { | |
// | |
// HII resource is removed. The formset is no longer exist. | |
// | |
Status = NotifyFormsetDeleted (Handle, &mRedfishPlatformConfigPrivate->PendingList); | |
if (EFI_ERROR (Status)) { | |
DEBUG ((DEBUG_ERROR, "%a: failed to notify deleted formset of HII handle: 0x%x\n", __func__, Handle)); | |
return Status; | |
} | |
} | |
return EFI_SUCCESS; | |
} | |
/** | |
This is a EFI_HII_STRING_PROTOCOL notification event handler. | |
Install HII package notification. | |
@param[in] Event Event whose notification function is being invoked. | |
@param[in] Context Pointer to the notification function's context. | |
**/ | |
VOID | |
EFIAPI | |
HiiStringProtocolInstalled ( | |
IN EFI_EVENT Event, | |
IN VOID *Context | |
) | |
{ | |
EFI_STATUS Status; | |
// | |
// Locate HII database protocol. | |
// | |
Status = gBS->LocateProtocol ( | |
&gEfiHiiStringProtocolGuid, | |
NULL, | |
(VOID **)&mRedfishPlatformConfigPrivate->HiiString | |
); | |
if (EFI_ERROR (Status)) { | |
DEBUG ((DEBUG_ERROR, "%a: locate EFI_HII_STRING_PROTOCOL failure: %r\n", __func__, Status)); | |
return; | |
} | |
gBS->CloseEvent (Event); | |
mRedfishPlatformConfigPrivate->HiiStringNotify.ProtocolEvent = NULL; | |
} | |
/** | |
This is a EFI_HII_DATABASE_PROTOCOL notification event handler. | |
Install HII package notification. | |
@param[in] Event Event whose notification function is being invoked. | |
@param[in] Context Pointer to the notification function's context. | |
**/ | |
VOID | |
EFIAPI | |
HiiDatabaseProtocolInstalled ( | |
IN EFI_EVENT Event, | |
IN VOID *Context | |
) | |
{ | |
EFI_STATUS Status; | |
// | |
// Locate HII database protocol. | |
// | |
Status = gBS->LocateProtocol ( | |
&gEfiHiiDatabaseProtocolGuid, | |
NULL, | |
(VOID **)&mRedfishPlatformConfigPrivate->HiiDatabase | |
); | |
if (EFI_ERROR (Status)) { | |
DEBUG ((DEBUG_ERROR, "%a: locate EFI_HII_DATABASE_PROTOCOL failure: %r\n", __func__, Status)); | |
return; | |
} | |
// | |
// Register package notification when new form package is installed. | |
// | |
Status = mRedfishPlatformConfigPrivate->HiiDatabase->RegisterPackageNotify ( | |
mRedfishPlatformConfigPrivate->HiiDatabase, | |
EFI_HII_PACKAGE_FORMS, | |
NULL, | |
RedfishPlatformConfigFormUpdateNotify, | |
EFI_HII_DATABASE_NOTIFY_NEW_PACK, | |
&mRedfishPlatformConfigPrivate->NotifyHandle | |
); | |
if (EFI_ERROR (Status)) { | |
DEBUG ((DEBUG_ERROR, "%a: RegisterPackageNotify for EFI_HII_DATABASE_NOTIFY_NEW_PACK failure: %r\n", __func__, Status)); | |
} | |
// | |
// Register package notification when new form package is updated. | |
// | |
Status = mRedfishPlatformConfigPrivate->HiiDatabase->RegisterPackageNotify ( | |
mRedfishPlatformConfigPrivate->HiiDatabase, | |
EFI_HII_PACKAGE_FORMS, | |
NULL, | |
RedfishPlatformConfigFormUpdateNotify, | |
EFI_HII_DATABASE_NOTIFY_ADD_PACK, | |
&mRedfishPlatformConfigPrivate->NotifyHandle | |
); | |
if (EFI_ERROR (Status)) { | |
DEBUG ((DEBUG_ERROR, "%a: RegisterPackageNotify for EFI_HII_DATABASE_NOTIFY_NEW_PACK failure: %r\n", __func__, Status)); | |
} | |
gBS->CloseEvent (Event); | |
mRedfishPlatformConfigPrivate->HiiDbNotify.ProtocolEvent = NULL; | |
} | |
/** | |
This is a EFI_REGULAR_EXPRESSION_PROTOCOL notification event handler. | |
@param[in] Event Event whose notification function is being invoked. | |
@param[in] Context Pointer to the notification function's context. | |
**/ | |
VOID | |
EFIAPI | |
RegexProtocolInstalled ( | |
IN EFI_EVENT Event, | |
IN VOID *Context | |
) | |
{ | |
EFI_STATUS Status; | |
// | |
// Locate regular expression protocol. | |
// | |
Status = gBS->LocateProtocol ( | |
&gEfiRegularExpressionProtocolGuid, | |
NULL, | |
(VOID **)&mRedfishPlatformConfigPrivate->RegularExpressionProtocol | |
); | |
if (EFI_ERROR (Status)) { | |
DEBUG ((DEBUG_ERROR, "%a: locate EFI_REGULAR_EXPRESSION_PROTOCOL failure: %r\n", __func__, Status)); | |
return; | |
} | |
gBS->CloseEvent (Event); | |
mRedfishPlatformConfigPrivate->RegexNotify.ProtocolEvent = NULL; | |
} | |
/** | |
Unloads an image. | |
@param ImageHandle Handle that identifies the image to be unloaded. | |
@retval EFI_SUCCESS The image has been unloaded. | |
@retval EFI_INVALID_PARAMETER ImageHandle is not a valid image handle. | |
**/ | |
EFI_STATUS | |
EFIAPI | |
RedfishPlatformConfigDxeUnload ( | |
IN EFI_HANDLE ImageHandle | |
) | |
{ | |
EFI_STATUS Status; | |
if (mRedfishPlatformConfigPrivate != NULL) { | |
Status = gBS->UninstallProtocolInterface ( | |
mRedfishPlatformConfigPrivate->ImageHandle, | |
&gEdkIIRedfishPlatformConfigProtocolGuid, | |
(VOID *)&mRedfishPlatformConfigPrivate->Protocol | |
); | |
if (EFI_ERROR (Status)) { | |
DEBUG ((DEBUG_ERROR, "%a: can not uninstall gEdkIIRedfishPlatformConfigProtocolGuid: %r\n", __func__, Status)); | |
ASSERT (FALSE); | |
} | |
// | |
// Close events | |
// | |
if (mRedfishPlatformConfigPrivate->HiiDbNotify.ProtocolEvent != NULL) { | |
gBS->CloseEvent (mRedfishPlatformConfigPrivate->HiiDbNotify.ProtocolEvent); | |
} | |
if (mRedfishPlatformConfigPrivate->HiiStringNotify.ProtocolEvent != NULL) { | |
gBS->CloseEvent (mRedfishPlatformConfigPrivate->HiiStringNotify.ProtocolEvent); | |
} | |
if (mRedfishPlatformConfigPrivate->RegexNotify.ProtocolEvent != NULL) { | |
gBS->CloseEvent (mRedfishPlatformConfigPrivate->RegexNotify.ProtocolEvent); | |
} | |
// | |
// Unregister package notification. | |
// | |
if (mRedfishPlatformConfigPrivate->NotifyHandle != NULL) { | |
mRedfishPlatformConfigPrivate->HiiDatabase->UnregisterPackageNotify ( | |
mRedfishPlatformConfigPrivate->HiiDatabase, | |
mRedfishPlatformConfigPrivate->NotifyHandle | |
); | |
} | |
ReleaseFormsetList (&mRedfishPlatformConfigPrivate->FormsetList); | |
FreePool (mRedfishPlatformConfigPrivate); | |
mRedfishPlatformConfigPrivate = NULL; | |
} | |
return EFI_SUCCESS; | |
} | |
/** | |
This is the declaration of an EFI image entry point. This entry point is | |
the same for UEFI Applications, UEFI OS Loaders, and UEFI Drivers including | |
both device drivers and bus drivers. | |
@param ImageHandle The firmware allocated handle for the UEFI image. | |
@param SystemTable A pointer to the EFI System Table. | |
@retval EFI_SUCCESS The operation completed successfully. | |
@retval Others An unexpected error occurred. | |
**/ | |
EFI_STATUS | |
EFIAPI | |
RedfishPlatformConfigDxeEntryPoint ( | |
IN EFI_HANDLE ImageHandle, | |
IN EFI_SYSTEM_TABLE *SystemTable | |
) | |
{ | |
EFI_STATUS Status; | |
mRedfishPlatformConfigPrivate = (REDFISH_PLATFORM_CONFIG_PRIVATE *)AllocateZeroPool (sizeof (REDFISH_PLATFORM_CONFIG_PRIVATE)); | |
if (mRedfishPlatformConfigPrivate == NULL) { | |
DEBUG ((DEBUG_ERROR, "%a: can not allocate pool for REDFISH_PLATFORM_CONFIG_PRIVATE\n", __func__)); | |
ASSERT (FALSE); | |
return EFI_OUT_OF_RESOURCES; | |
} | |
// | |
// Protocol initialization | |
// | |
mRedfishPlatformConfigPrivate->ImageHandle = ImageHandle; | |
mRedfishPlatformConfigPrivate->Protocol.Revision = REDFISH_PLATFORM_CONFIG_VERSION; | |
mRedfishPlatformConfigPrivate->Protocol.GetValue = RedfishPlatformConfigProtocolGetValue; | |
mRedfishPlatformConfigPrivate->Protocol.SetValue = RedfishPlatformConfigProtocolSetValue; | |
mRedfishPlatformConfigPrivate->Protocol.GetConfigureLang = RedfishPlatformConfigProtocolGetConfigureLang; | |
mRedfishPlatformConfigPrivate->Protocol.GetSupportedSchema = RedfishPlatformConfigProtocolGetSupportedSchema; | |
mRedfishPlatformConfigPrivate->Protocol.GetAttribute = RedfishPlatformConfigProtocolGetAttribute; | |
mRedfishPlatformConfigPrivate->Protocol.GetDefaultValue = RedfishPlatformConfigProtocolGetDefaultValue; | |
InitializeListHead (&mRedfishPlatformConfigPrivate->FormsetList); | |
InitializeListHead (&mRedfishPlatformConfigPrivate->PendingList); | |
Status = gBS->InstallProtocolInterface ( | |
&ImageHandle, | |
&gEdkIIRedfishPlatformConfigProtocolGuid, | |
EFI_NATIVE_INTERFACE, | |
(VOID *)&mRedfishPlatformConfigPrivate->Protocol | |
); | |
if (EFI_ERROR (Status)) { | |
DEBUG ((DEBUG_ERROR, "%a: can not install gEdkIIRedfishPlatformConfigProtocolGuid: %r\n", __func__, Status)); | |
ASSERT (FALSE); | |
} | |
// | |
// Install protocol notification if HII database protocol is installed. | |
// | |
mRedfishPlatformConfigPrivate->HiiDbNotify.ProtocolEvent = EfiCreateProtocolNotifyEvent ( | |
&gEfiHiiDatabaseProtocolGuid, | |
TPL_CALLBACK, | |
HiiDatabaseProtocolInstalled, | |
NULL, | |
&mRedfishPlatformConfigPrivate->HiiDbNotify.Registration | |
); | |
if (mRedfishPlatformConfigPrivate->HiiDbNotify.ProtocolEvent == NULL) { | |
DEBUG ((DEBUG_ERROR, "%a: failed to create protocol notification for gEfiHiiDatabaseProtocolGuid\n", __func__)); | |
ASSERT (FALSE); | |
} | |
// | |
// Install protocol notification if HII string protocol is installed. | |
// | |
mRedfishPlatformConfigPrivate->HiiStringNotify.ProtocolEvent = EfiCreateProtocolNotifyEvent ( | |
&gEfiHiiStringProtocolGuid, | |
TPL_CALLBACK, | |
HiiStringProtocolInstalled, | |
NULL, | |
&mRedfishPlatformConfigPrivate->HiiStringNotify.Registration | |
); | |
if (mRedfishPlatformConfigPrivate->HiiStringNotify.ProtocolEvent == NULL) { | |
DEBUG ((DEBUG_ERROR, "%a: failed to create protocol notification for gEfiHiiStringProtocolGuid\n", __func__)); | |
ASSERT (FALSE); | |
} | |
// | |
// Install protocol notification if regular expression protocol is installed. | |
// | |
mRedfishPlatformConfigPrivate->RegexNotify.ProtocolEvent = EfiCreateProtocolNotifyEvent ( | |
&gEfiRegularExpressionProtocolGuid, | |
TPL_CALLBACK, | |
RegexProtocolInstalled, | |
NULL, | |
&mRedfishPlatformConfigPrivate->RegexNotify.Registration | |
); | |
if (mRedfishPlatformConfigPrivate->RegexNotify.ProtocolEvent == NULL) { | |
DEBUG ((DEBUG_ERROR, "%a: failed to create protocol notification for gEfiRegularExpressionProtocolGuid\n", __func__)); | |
ASSERT (FALSE); | |
} | |
return EFI_SUCCESS; | |
} |