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