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