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