/** @file The implementation of EDKII Redfish Platform Config Protocol. (C) Copyright 2021-2022 Hewlett Packard Enterprise Development LP
Copyright (c) 2022-2024, NVIDIA CORPORATION & AFFILIATES. All rights reserved. Copyright (C) 2024 Advanced Micro Devices, Inc. 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; } /** Debug dump HII statement value. @param[in] ErrorLevel DEBUG macro error level @param[in] Value HII statement value to dump @param[in] Message Debug message @retval EFI_SUCCESS Dump HII statement value successfully @retval Others Errors occur **/ EFI_STATUS DumpHiiStatementValue ( IN UINTN ErrorLevel, IN HII_STATEMENT_VALUE *Value, IN CHAR8 *Message OPTIONAL ) { UINT64 Data; if (Value == NULL) { return EFI_INVALID_PARAMETER; } switch (Value->Type) { case EFI_IFR_TYPE_NUM_SIZE_8: Data = Value->Value.u8; break; case EFI_IFR_TYPE_NUM_SIZE_16: Data = Value->Value.u16; break; case EFI_IFR_TYPE_NUM_SIZE_32: Data = Value->Value.u32; break; case EFI_IFR_TYPE_NUM_SIZE_64: Data = Value->Value.u64; break; case EFI_IFR_TYPE_BOOLEAN: Data = (Value->Value.b ? 1 : 0); break; default: DEBUG ((ErrorLevel, "%a: unsupported type: 0x%x\n", __func__, Value->Type)); return EFI_UNSUPPORTED; } if (IS_EMPTY_STRING (Message)) { DEBUG ((ErrorLevel, "0x%lx\n", Data)); } else { DEBUG ((ErrorLevel, "%a: 0x%lx\n", Message, Data)); } return EFI_SUCCESS; } /** Debug dump HII statement prompt string. @param[in] ErrorLevel DEBUG macro error level @param[in] HiiHandle HII handle instance @param[in] HiiStatement HII statement @param[in] Message Debug message @retval EFI_SUCCESS Dump HII statement string successfully @retval Others Errors occur **/ EFI_STATUS DumpHiiStatementPrompt ( IN UINTN ErrorLevel, IN EFI_HII_HANDLE HiiHandle, IN HII_STATEMENT *HiiStatement, IN CHAR8 *Message OPTIONAL ) { EFI_STRING String; if ((HiiHandle == NULL) || (HiiStatement == NULL)) { return EFI_INVALID_PARAMETER; } if (HiiStatement->Prompt == 0) { return EFI_NOT_FOUND; } String = HiiGetString (HiiHandle, HiiStatement->Prompt, NULL); if (String == NULL) { return EFI_NOT_FOUND; } if (IS_EMPTY_STRING (Message)) { DEBUG ((ErrorLevel, "%s\n", String)); } else { DEBUG ((ErrorLevel, "%a: %s\n", Message, String)); } FreePool (String); return EFI_SUCCESS; } /** 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 * BuildMenuPath ( 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 ((DEBUG_REDFISH_PLATFORM_CONFIG, "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 ((DEBUG_REDFISH_PLATFORM_CONFIG, " %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) { TmpString = HiiGetRedfishString (Statement->ParentForm->ParentFormset->HiiHandle, ENGLISH_LANGUAGE_CODE, 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; DEBUG ((DEBUG_ERROR, "%a: Unsupported value type: 0x%x\n", __func__, Value->Type)); 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_REDFISH_PLATFORM_CONFIG, "Value.Type= 0x%x\n", OrderedListStatement->Value.Type)); DEBUG ((DEBUG_REDFISH_PLATFORM_CONFIG, "Value.BufferValueType= 0x%x\n", OrderedListStatement->Value.BufferValueType)); DEBUG ((DEBUG_REDFISH_PLATFORM_CONFIG, "Value.BufferLen= 0x%x\n", OrderedListStatement->Value.BufferLen)); DEBUG ((DEBUG_REDFISH_PLATFORM_CONFIG, "Value.Buffer= 0x%x\n", OrderedListStatement->Value.Buffer)); DEBUG ((DEBUG_REDFISH_PLATFORM_CONFIG, "Value.MaxContainers= 0x%x\n", OrderedListStatement->ExtraData.OrderListData.MaxContainers)); DEBUG ((DEBUG_REDFISH_PLATFORM_CONFIG, "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_REDFISH_PLATFORM_CONFIG, "%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_REDFISH_PLATFORM_CONFIG, "%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_REDFISH_PLATFORM_CONFIG, "%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_REDFISH_PLATFORM_CONFIG, "%d ", Value64[Index])); } break; default: Value8 = (UINT8 *)OrderedListStatement->Value.Buffer; Count = OrderedListStatement->StorageWidth / sizeof (UINT8); for (Index = 0; Index < Count; Index++) { DEBUG ((DEBUG_REDFISH_PLATFORM_CONFIG, "%d ", Value8[Index])); } break; } DEBUG ((DEBUG_REDFISH_PLATFORM_CONFIG, "\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) { TmpString = HiiGetRedfishString (Statement->ParentForm->ParentFormset->HiiHandle, ENGLISH_LANGUAGE_CODE, 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; CHAR8 NullChar; if ((HiiHandle == NULL) || (HiiStatement == NULL) || (Value == NULL) || (RedfishValue == NULL) || IS_EMPTY_STRING (FullSchema)) { return EFI_INVALID_PARAMETER; } StringIdArray = NULL; Count = 0; Status = EFI_SUCCESS; NullChar = '\0'; switch (HiiStatement->Operand) { case EFI_IFR_ONE_OF_OP: StringId = HiiValueToOneOfOptionStringId (HiiStatement, Value); if (StringId == 0) { // // Print prompt string of HII statement for ease of debugging // DumpHiiStatementPrompt (DEBUG_ERROR, HiiHandle, HiiStatement, "Can not find string ID"); DumpHiiStatementValue (DEBUG_ERROR, Value, "Current value"); 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; } if (Value->Buffer == NULL) { RedfishValue->Value.Buffer = AllocateCopyPool (sizeof (NullChar), &NullChar); } else { RedfishValue->Value.Buffer = StrToAsciiStr ((EFI_STRING)Value->Buffer); } if (RedfishValue->Value.Buffer == NULL) { Status = EFI_OUT_OF_RESOURCES; break; } RedfishValue->Type = RedfishValueTypeString; break; case EFI_IFR_CHECKBOX_OP: // // There is case where HII driver defines UINT8 for checked-box opcode storage. // IFR compiler will assign EFI_IFR_TYPE_NUM_SIZE_8 to its value type instead of // EFI_IFR_TYPE_BOOLEAN. We do a patch here and use boolean value type for this // case. // if (Value->Type != EFI_IFR_TYPE_BOOLEAN) { Value->Type = EFI_IFR_TYPE_BOOLEAN; } 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) { // // Print prompt string of HII statement for ease of debugging // DumpHiiStatementPrompt (DEBUG_ERROR, HiiHandle, HiiStatement, "Can not get string ID array"); ASSERT (FALSE); Status = EFI_DEVICE_ERROR; break; } RedfishValue->Value.StringArray = AllocatePool (sizeof (CHAR8 *) * Count); if (RedfishValue->Value.StringArray == NULL) { // // Print prompt string of HII statement for ease of debugging // DumpHiiStatementPrompt (DEBUG_ERROR, HiiHandle, HiiStatement, "Can not allocate memory"); ASSERT (FALSE); Status = EFI_OUT_OF_RESOURCES; break; } for (Index = 0; Index < Count; Index++) { if (StringIdArray[Index] == 0) { // // Print prompt string of HII statement for ease of debugging // DumpHiiStatementPrompt (DEBUG_ERROR, HiiHandle, HiiStatement, "String ID in array is 0"); ASSERT (FALSE); } RedfishValue->Value.StringArray[Index] = HiiGetRedfishAsciiString (HiiHandle, FullSchema, StringIdArray[Index]); ASSERT (RedfishValue->Value.StringArray[Index] != NULL); } RedfishValue->ArrayCount = Count; RedfishValue->Type = RedfishValueTypeStringArray; FreePool (StringIdArray); break; case EFI_IFR_TEXT_OP: // // Use text two as the value // if (HiiStatement->ExtraData.TextTwo == 0x00) { Status = EFI_NOT_FOUND; break; } RedfishValue->Value.Buffer = HiiGetRedfishAsciiString (HiiHandle, FullSchema, HiiStatement->ExtraData.TextTwo); if (RedfishValue->Value.Buffer == NULL) { // // No x-uefi-redfish string defined. Try to get string in English. // RedfishValue->Value.Buffer = HiiGetEnglishAsciiString (HiiHandle, HiiStatement->ExtraData.TextTwo); } if (RedfishValue->Value.Buffer == NULL) { Status = EFI_OUT_OF_RESOURCES; break; } RedfishValue->Type = RedfishValueTypeString; 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) { 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; } /** Convert input unicode string to ascii string. It's caller's responsibility to free returned buffer using FreePool(). @param[in] UnicodeString Unicode string to be converted. @retval CHAR8 * Ascii string on return. **/ CHAR8 * StrToAsciiStr ( IN EFI_STRING UnicodeString ) { UINTN StringLen; CHAR8 *Buffer; EFI_STATUS Status; if (UnicodeString == NULL) { return NULL; } StringLen = HiiStrLen (UnicodeString) + 1; Buffer = AllocatePool (StringLen * sizeof (CHAR8)); if (Buffer == NULL) { return NULL; } Status = UnicodeStrToAsciiStrS (UnicodeString, 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)) { // // Keep input buffer to TempBuffer because StatementValue will be // assigned in HiiStringToOneOfOptionValue(). // TempBuffer = (EFI_STRING)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); } } if ((TargetStatement->HiiStatement->Operand == EFI_IFR_STRING_OP) && (StatementValue->Type == EFI_IFR_TYPE_STRING)) { // // Create string ID for new string. // StatementValue->Value.string = HiiSetString (TargetStatement->ParentForm->ParentFormset->HiiHandle, 0x00, (EFI_STRING)StatementValue->Buffer, NULL); if (StatementValue->Value.string == 0) { DEBUG ((DEBUG_ERROR, "%a: can not create string id\n", __func__)); return EFI_OUT_OF_RESOURCES; } } 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)); } if ((TargetStatement->HiiStatement->Operand == EFI_IFR_STRING_OP) && (StatementValue->Type == EFI_IFR_TYPE_STRING)) { if (StatementValue->Value.string != 0) { // Delete HII string which was created for HII statement operand = EFI_IFR_STRING_OP and Type = EFI_IFR_TYPE_STRING. HiiDeleteString (StatementValue->Value.string, TargetStatement->ParentForm->ParentFormset->HiiHandle); } } return Status; } /** 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: if (Value.Value.Buffer == NULL) { Status = EFI_INVALID_PARAMETER; goto RELEASE_RESOURCE; } NewValue.Type = EFI_IFR_TYPE_STRING; NewValue.BufferLen = (UINT16)(AsciiStrSize (Value.Value.Buffer) * sizeof (CHAR16)); NewValue.Buffer = (UINT8 *)StrToUnicodeStr (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); } if ((Value.Type == RedfishValueTypeString) && (NewValue.Buffer != NULL)) { FreePool (NewValue.Buffer); } 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 *TmpConfigureLangList; UINTN Index; CHAR8 *FullSchema; DEBUG ((DEBUG_INFO, "%a: Harvest config language of %a_%a (Regex: %s).\n", __func__, Schema, Version, RegexPattern)); if ((This == NULL) || IS_EMPTY_STRING (Schema) || IS_EMPTY_STRING (Version) || (Count == NULL) || (ConfigureLangList == NULL) || IS_EMPTY_STRING (RegexPattern)) { return EFI_INVALID_PARAMETER; } ZeroMem (&StatementList, sizeof (StatementList)); *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) { ASSERT (StatementRef->Statement->XuefiRedfishStr != NULL); TmpConfigureLangList[Index] = AllocateCopyPool (HiiStrSize (StatementRef->Statement->XuefiRedfishStr), (VOID *)StatementRef->Statement->XuefiRedfishStr); ++Index; } } } *Count = StatementList.Count; *ConfigureLangList = TmpConfigureLangList; DEBUG_REDFISH_THIS_MODULE ( REDFISH_PLATFORM_CONFIG_DEBUG_CONFIG_LANG_REGEX, "%a: Number of configure language strings harvested: %d\n", __func__, StatementList.Count ); DEBUG_REDFISH_THIS_MODULE_CODE ( REDFISH_PLATFORM_CONFIG_DEBUG_CONFIG_LANG_REGEX, DEBUG_REDFISH (DEBUG_REDFISH_COMPONENT_PLATFORM_CONFIG_DXE, "%a: Number of configure language strings harvested: %d\n", __func__, StatementList.Count); for (Index = 0; Index < *Count; Index++) { DEBUG_REDFISH (DEBUG_REDFISH_COMPONENT_PLATFORM_CONFIG_DXE, " (%d) %s\n", Index, TmpConfigureLangList[Index]); } ); RELEASE_RESOURCE: if (FullSchema != NULL) { FreePool (FullSchema); } if (StatementList.Count > 0) { ReleaseStatementList (&StatementList); } DEBUG ((DEBUG_INFO, "%a: exit.\n", __func__)); 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; DEBUG ((DEBUG_INFO, "%a: Entry\n", __func__)); 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 // if (RedfishPlatformConfigFeatureProp (REDFISH_PLATFORM_CONFIG_BUILD_MENU_PATH)) { AttributeValue->MenuPath = BuildMenuPath (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); } DEBUG ((DEBUG_INFO, "%a: Exit\n", __func__)); 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; }