From: "Abner Chang" <abner.chang@hpe.com>
To: devel@edk2.groups.io
Cc: nickle.wang@hpe.com, Liming Gao <gaoliming@byosoft.com.cn>
Subject: [PATCH RESEND 3/5] edk2-staging/RedfishPkg: Implementation of EDKII_REDFISH_PLATFORM_CONFIG_PROTOCOL
Date: Thu, 28 Oct 2021 09:07:21 +0800 [thread overview]
Message-ID: <20211028010723.37316-4-abner.chang@hpe.com> (raw)
In-Reply-To: <20211028010723.37316-1-abner.chang@hpe.com>
This is the Implementation of EDKII_REDFISH_PLATFORM_CONFIG_PROTOCOL,
which is the EDKII Redfish Platform Config driver instance that accesses
EDK2 HII configuration format and storage.
Signed-off-by: Nickle Wang <nickle.wang@hpe.com>
Cc: Abner Chang <abner.chang@hpe.com>
Cc: Liming Gao <gaoliming@byosoft.com.cn>
---
.../RedfishPlatformConfigDxe.inf | 53 +
.../RedfishPlatformConfigDxe.h | 64 +
.../RedfishPlatformConfigImpl.h | 274 ++++
.../RedfishPlatformConfigDxe.c | 1304 +++++++++++++++++
.../RedfishPlatformConfigImpl.c | 1240 ++++++++++++++++
5 files changed, 2935 insertions(+)
create mode 100644 RedfishPkg/RedfishPlatformConfigDxe/RedfishPlatformConfigDxe.inf
create mode 100644 RedfishPkg/RedfishPlatformConfigDxe/RedfishPlatformConfigDxe.h
create mode 100644 RedfishPkg/RedfishPlatformConfigDxe/RedfishPlatformConfigImpl.h
create mode 100644 RedfishPkg/RedfishPlatformConfigDxe/RedfishPlatformConfigDxe.c
create mode 100644 RedfishPkg/RedfishPlatformConfigDxe/RedfishPlatformConfigImpl.c
diff --git a/RedfishPkg/RedfishPlatformConfigDxe/RedfishPlatformConfigDxe.inf b/RedfishPkg/RedfishPlatformConfigDxe/RedfishPlatformConfigDxe.inf
new file mode 100644
index 00000000000..16739bef7a3
--- /dev/null
+++ b/RedfishPkg/RedfishPlatformConfigDxe/RedfishPlatformConfigDxe.inf
@@ -0,0 +1,53 @@
+## @file
+# Implementation of EDKII_REDFISH_PLATFORM_CONFIG_PROTOCOL interfaces.
+#
+# (C) Copyright 2021 Hewlett Packard Enterprise Development LP<BR>
+# SPDX-License-Identifier: BSD-2-Clause-Patent
+#
+##
+
+[Defines]
+ INF_VERSION = 0x00010005
+ BASE_NAME = RedfishPlatformConfigDxe
+ FILE_GUID = BEAEFFE1-0633-41B5-913C-9389339C2927
+ MODULE_TYPE = DXE_DRIVER
+ VERSION_STRING = 1.0
+ ENTRY_POINT = RedfishPlatformConfigDxeEntryPoint
+ UNLOAD_IMAGE = RedfishPlatformConfigDxeUnload
+
+[Packages]
+ MdePkg/MdePkg.dec
+ MdeModulePkg/MdeModulePkg.dec
+ RedfishPkg/RedfishPkg.dec
+
+[Sources]
+ RedfishPlatformConfigDxe.h
+ RedfishPlatformConfigDxe.c
+ RedfishPlatformConfigImpl.h
+ RedfishPlatformConfigImpl.c
+
+[LibraryClasses]
+ BaseLib
+ BaseMemoryLib
+ DebugLib
+ DevicePathLib
+ HiiLib
+ HiiUtilityLib
+ MemoryAllocationLib
+ PrintLib
+ UefiLib
+ UefiBootServicesTableLib
+ UefiRuntimeServicesTableLib
+ UefiDriverEntryPoint
+
+[Protocols]
+ gEdkIIRedfishPlatformConfigProtocolGuid ## PRODUCED
+ gEfiHiiDatabaseProtocolGuid ## CONSUMED
+ gEfiHiiStringProtocolGuid ## CONSUMED
+ gEfiRegularExpressionProtocolGuid ## CONSUMED
+
+[Guids]
+ gEfiRegexSyntaxTypePerlGuid ## CONSUMED
+
+[Depex]
+ TRUE
\ No newline at end of file
diff --git a/RedfishPkg/RedfishPlatformConfigDxe/RedfishPlatformConfigDxe.h b/RedfishPkg/RedfishPlatformConfigDxe/RedfishPlatformConfigDxe.h
new file mode 100644
index 00000000000..99a613d229c
--- /dev/null
+++ b/RedfishPkg/RedfishPlatformConfigDxe/RedfishPlatformConfigDxe.h
@@ -0,0 +1,64 @@
+/** @file
+ This file defines the EDKII Redfish Platform Config Protocol interface.
+
+ (C) Copyright 2021 Hewlett Packard Enterprise Development LP<BR>
+
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#ifndef EDKII_REDFISH_PLATFORM_CONFIG_DXE_H_
+#define EDKII_REDFISH_PLATFORM_CONFIG_DXE_H_
+
+#include <Uefi.h>
+
+//
+// Libraries
+//
+#include <Library/BaseLib.h>
+#include <Library/BaseMemoryLib.h>
+#include <Library/DebugLib.h>
+#include <Library/MemoryAllocationLib.h>
+#include <Library/PrintLib.h>
+#include <Library/UefiLib.h>
+#include <Library/UefiBootServicesTableLib.h>
+#include <Library/UefiDriverEntryPoint.h>
+
+//
+// Produced Protocols
+//
+#include <Protocol/EdkIIRedfishPlatformConfig.h>
+#include <Protocol/HiiDatabase.h>
+#include <Protocol/HiiString.h>
+#include <Protocol/RegularExpressionProtocol.h>
+
+//
+// Definition of EDKII_REDFISH_PLATFORM_CONFIG_NOTIFY.
+//
+typedef struct {
+ EFI_EVENT ProtocolEvent; // Protocol notification event.
+ VOID *Registration; // Protocol notification registration.
+} REDFISH_PLATFORM_CONFIG_NOTIFY;
+
+//
+// Definition of REDFISH_PLATFORM_CONFIG_PRIVATE.
+//
+typedef struct {
+ EFI_HANDLE ImageHandle; // Driver image handle.
+ EDKII_REDFISH_PLATFORM_CONFIG_PROTOCOL Protocol;
+ REDFISH_PLATFORM_CONFIG_NOTIFY HiiDbNotify;
+ EFI_HII_DATABASE_PROTOCOL *HiiDatabase; // The HII database protocol.
+ REDFISH_PLATFORM_CONFIG_NOTIFY HiiStringNotify;
+ EFI_HII_STRING_PROTOCOL *HiiString; // HII String Protocol.
+ REDFISH_PLATFORM_CONFIG_NOTIFY RegexNotify;
+ EFI_REGULAR_EXPRESSION_PROTOCOL *RegularExpressionProtocol; // Regular Expression Protocol.
+ EFI_HANDLE NotifyHandle; // The notify handle.
+ LIST_ENTRY FormsetList; // The list to keep cached HII formset.
+ LIST_ENTRY PendingList; // The list to keep updated HII handle.
+} REDFISH_PLATFORM_CONFIG_PRIVATE;
+
+#define REDFISH_PLATFORM_CONFIG_PRIVATE_FROM_THIS(a) BASE_CR (a, REDFISH_PLATFORM_CONFIG_PRIVATE, Protocol)
+#define REGULAR_EXPRESSION_INCLUDE_ALL L".*"
+#define CONFIGURE_LANGUAGE_PREFIX "x-uefi-redfish-"
+
+#endif
diff --git a/RedfishPkg/RedfishPlatformConfigDxe/RedfishPlatformConfigImpl.h b/RedfishPkg/RedfishPlatformConfigDxe/RedfishPlatformConfigImpl.h
new file mode 100644
index 00000000000..e0ba0fb2d3d
--- /dev/null
+++ b/RedfishPkg/RedfishPlatformConfigDxe/RedfishPlatformConfigImpl.h
@@ -0,0 +1,274 @@
+/** @file
+ This file defines the EDKII Redfish Platform Config Protocol interface.
+
+ (C) Copyright 2021 Hewlett Packard Enterprise Development LP<BR>
+
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#ifndef EDKII_REDFISH_PLATFORM_CONFIG_IMPL_H_
+#define EDKII_REDFISH_PLATFORM_CONFIG_IMPL_H_
+
+#include <Uefi.h>
+
+//
+// Libraries
+//
+#include <Library/BaseLib.h>
+#include <Library/BaseMemoryLib.h>
+#include <Library/DebugLib.h>
+#include <Library/DevicePathLib.h>
+#include <Library/HiiUtilityLib.h>
+#include <Library/HiiLib.h>
+#include <Library/MemoryAllocationLib.h>
+#include <Library/UefiBootServicesTableLib.h>
+#include <Library/UefiLib.h>
+
+#define REDFISH_PLATFORM_CONFIG_DELETE_EXPIRED_FORMSET 0x00
+#define IS_EMPTY_STRING(a) (a == NULL || a[0] == L'\0')
+#define ENGLISH_LANGUAGE_CODE "en-US"
+#define X_UEFI_SCHEMA_PREFIX "x-uefi-redfish-"
+
+//
+// Definition of REDFISH_PLATFORM_CONFIG_PRIVATE.
+//
+typedef struct {
+ LIST_ENTRY Link;
+ EFI_HII_HANDLE HiiHandle;
+ BOOLEAN IsDeleted;
+} REDFISH_PLATFORM_CONFIG_PENDING_LIST;
+
+#define REDFISH_PLATFORM_CONFIG_PENDING_LIST_FROM_LINK(a) BASE_CR (a, REDFISH_PLATFORM_CONFIG_PENDING_LIST, Link)
+
+typedef struct {
+ UINTN Count; // Number of schema in list
+ CHAR8 **SchemaList; // Schema list
+} REDFISH_PLATFORM_CONFIG_SCHEMA;
+
+//
+// Definition of REDFISH_PLATFORM_CONFIG_FORM_SET_PRIVATE
+//
+typedef struct {
+ LIST_ENTRY Link;
+ HII_FORMSET *HiiFormSet; // Pointer to HII formset data.
+ EFI_GUID Guid; // Formset GUID.
+ EFI_HII_HANDLE HiiHandle; // Hii Handle of this formset.
+ LIST_ENTRY HiiFormList; // Form list that keep form data under this formset.
+ CHAR16 *DevicePathStr; // Device path of this formset.
+ REDFISH_PLATFORM_CONFIG_SCHEMA SupportedSchema; // Schema that is supported in this formset.
+} REDFISH_PLATFORM_CONFIG_FORM_SET_PRIVATE;
+
+#define REDFISH_PLATFORM_CONFIG_FORMSET_FROM_LINK(a) BASE_CR (a, REDFISH_PLATFORM_CONFIG_FORM_SET_PRIVATE, Link)
+
+//
+// Definition of REDFISH_PLATFORM_CONFIG_FORM_PRIVATE
+//
+typedef struct {
+ LIST_ENTRY Link;
+ UINT16 Id; // Form ID.
+ EFI_STRING_ID Title; // String token of form title.
+ REDFISH_PLATFORM_CONFIG_FORM_SET_PRIVATE *ParentFormset;
+ HII_FORM *HiiForm; // Pointer to HII form data.
+ LIST_ENTRY StatementList; // Statement list that keep statement under this form.
+} REDFISH_PLATFORM_CONFIG_FORM_PRIVATE;
+
+#define REDFISH_PLATFORM_CONFIG_FORM_FROM_LINK(a) BASE_CR (a, REDFISH_PLATFORM_CONFIG_FORM_PRIVATE, Link)
+
+//
+// Definition of REDFISH_PLATFORM_CONFIG_STATEMENT_PRIVATE
+//
+typedef struct {
+ LIST_ENTRY Link;
+ REDFISH_PLATFORM_CONFIG_FORM_PRIVATE *ParentForm;
+ HII_STATEMENT *HiiStatement; // Pointer to HII statement data.
+ EFI_QUESTION_ID QuestionId; // Question ID of this statement.
+ EFI_STRING_ID Description; // String token of this question.
+ EFI_STRING DesStringCache; // The string cache for search function.
+} REDFISH_PLATFORM_CONFIG_STATEMENT_PRIVATE;
+
+#define REDFISH_PLATFORM_CONFIG_STATEMENT_FROM_LINK(a) BASE_CR (a, REDFISH_PLATFORM_CONFIG_STATEMENT_PRIVATE, Link)
+
+//
+// Definition of REDFISH_PLATFORM_CONFIG_STATEMENT_PRIVATE_REF
+//
+typedef struct {
+ LIST_ENTRY Link;
+ REDFISH_PLATFORM_CONFIG_STATEMENT_PRIVATE *Statement;
+} REDFISH_PLATFORM_CONFIG_STATEMENT_PRIVATE_REF;
+
+#define REDFISH_PLATFORM_CONFIG_STATEMENT_REF_FROM_LINK(a) BASE_CR (a, REDFISH_PLATFORM_CONFIG_STATEMENT_PRIVATE_REF, Link)
+
+//
+// Definition of REDFISH_PLATFORM_CONFIG_STATEMENT_PRIVATE_LIST
+//
+typedef struct {
+ LIST_ENTRY StatementList; // List of REDFISH_PLATFORM_CONFIG_STATEMENT_PRIVATE_REF
+ UINTN Count;
+} REDFISH_PLATFORM_CONFIG_STATEMENT_PRIVATE_LIST;
+
+/**
+ Release formset list and all the forms that belong to this formset.
+
+ @param[in] FormsetList Pointer to formst list that needs to be
+ released.
+
+ @retval EFI_STATUS
+
+**/
+EFI_STATUS
+ReleaseFormsetList (
+ IN LIST_ENTRY *FormsetList
+ );
+
+/**
+ Release formset list and all the forms that belong to this formset.
+
+ @param[in] FormsetList Pointer to formst list that needs to be
+ released.
+
+ @retval EFI_STATUS
+
+**/
+EFI_STATUS
+LoadFormsetList (
+ IN EFI_HII_HANDLE *HiiHandle,
+ OUT LIST_ENTRY *FormsetList
+ );
+
+/**
+ When HII database is updated. Keep updated HII handle into pending list so
+ we can process them later.
+
+ @param[in] HiiHandle HII handle instance.
+ @param[in] PendingList Pending list to keep HII handle which is recently updated.
+
+ @retval EFI_SUCCESS HII handle is saved in pending list.
+ @retval EFI_INVALID_PARAMETER HiiHnalde is NULL or PendingList is NULL.
+ @retval EFI_OUT_OF_RESOURCES System is out of memory.
+
+**/
+EFI_STATUS
+NotifyFormsetUpdate (
+ IN EFI_HII_HANDLE *HiiHandle,
+ IN LIST_ENTRY *PendingList
+ );
+
+/**
+ When HII database is updated and form-set is deleted. Keep deleted HII handle into pending list so
+ we can process them later.
+
+ @param[in] HiiHandle HII handle instance.
+ @param[in] PendingList Pending list to keep HII handle which is recently updated.
+
+ @retval EFI_SUCCESS HII handle is saved in pending list.
+ @retval EFI_INVALID_PARAMETER HiiHnalde is NULL or PendingList is NULL.
+ @retval EFI_OUT_OF_RESOURCES System is out of memory.
+
+**/
+EFI_STATUS
+NotifyFormsetDeleted (
+ IN EFI_HII_HANDLE *HiiHandle,
+ IN LIST_ENTRY *PendingList
+ );
+
+/**
+ Get statement private instance by the given configure language.
+
+ @param[in] FormsetList Form-set list to search.
+ @param[in] Schema Schema to be matched.
+ @param[in] ConfigureLang Configure language.
+
+ @retval REDFISH_PLATFORM_CONFIG_STATEMENT_PRIVATE * Pointer to statement private instance.
+
+**/
+REDFISH_PLATFORM_CONFIG_STATEMENT_PRIVATE *
+GetStatementPrivateByConfigureLang (
+ IN LIST_ENTRY *FormsetList,
+ IN CHAR8 *Schema,
+ IN EFI_STRING ConfigureLang
+ );
+
+/**
+ Search and find statement private instance by given regular expression patthern
+ which describes the Configure Language.
+
+ @param[in] RegularExpressionProtocol Regular express protocol.
+ @param[in] FormsetList Form-set list to search.
+ @param[in] Schema Schema to be matched.
+ @param[in] Pattern Regular expression pattern.
+ @param[out] StatementList Statement list that match above pattern.
+
+ @retval EFI_SUCCESS Statement list is returned.
+ @retval EFI_INVALID_PARAMETER Input parameter is NULL.
+ @retval EFI_NOT_READY Regular express protocol is NULL.
+ @retval EFI_NOT_FOUND No statement is found.
+ @retval EFI_OUT_OF_RESOURCES System is out of memory.
+
+**/
+EFI_STATUS
+GetStatementPrivateByConfigureLangRegex (
+ IN EFI_REGULAR_EXPRESSION_PROTOCOL *RegularExpressionProtocol,
+ IN LIST_ENTRY *FormsetList,
+ IN CHAR8 *Schema,
+ IN EFI_STRING Pattern,
+ OUT REDFISH_PLATFORM_CONFIG_STATEMENT_PRIVATE_LIST *StatementList
+ );
+
+/**
+ There are HII database update and we need to process them accordingly so that we
+ won't use stale data. This function will parse updated HII handle again in order
+ to get updated data-set.
+
+ @param[in] FormsetList List to keep HII form-set.
+ @param[in] PendingList List to keep HII handle that is updated.
+
+ @retval EFI_SUCCESS HII handle is saved in pending list.
+ @retval EFI_INVALID_PARAMETER FormsetList is NULL or PendingList is NULL.
+
+**/
+EFI_STATUS
+ProcessPendingList (
+ IN LIST_ENTRY *FormsetList,
+ IN LIST_ENTRY *PendingList
+ );
+
+/**
+ Retrieves a string from a string package in a English language. The
+ returned string is allocated using AllocatePool(). The caller is responsible
+ for freeing the allocated buffer using FreePool().
+
+ If HiiHandle is NULL, then ASSERT().
+ If StringId is 0, then ASSET.
+
+ @param[in] HiiStringProtocol EFI_HII_STRING_PROTOCOL instance.
+ @param[in] HiiHandle A handle that was previously registered in the HII Database.
+ @param[in] StringId The identifier of the string to retrieved from the string
+ package associated with HiiHandle.
+
+ @retval NULL The string specified by StringId is not present in the string package.
+ @retval Other The string was returned.
+
+**/
+EFI_STRING
+HiiGetRedfishString (
+ IN EFI_HII_HANDLE HiiHandle,
+ IN CHAR8 *Language,
+ IN EFI_STRING_ID StringId
+ );
+
+/**
+ Release all resource in statement list.
+
+ @param[in] StatementList Statement list to be released.
+
+ @retval EFI_SUCCESS All resource are released.
+ @retval EFI_INVALID_PARAMETER StatementList is NULL.
+
+**/
+EFI_STATUS
+ReleaseStatementList (
+ IN REDFISH_PLATFORM_CONFIG_STATEMENT_PRIVATE_LIST *StatementList
+ );
+
+#endif
diff --git a/RedfishPkg/RedfishPlatformConfigDxe/RedfishPlatformConfigDxe.c b/RedfishPkg/RedfishPlatformConfigDxe/RedfishPlatformConfigDxe.c
new file mode 100644
index 00000000000..67818cccd24
--- /dev/null
+++ b/RedfishPkg/RedfishPlatformConfigDxe/RedfishPlatformConfigDxe.c
@@ -0,0 +1,1304 @@
+/** @file
+
+ The implementation of EDKII Redfidh Platform Config Protocol.
+
+ (C) Copyright 2021 Hewlett Packard Enterprise Development LP<BR>
+
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include "RedfishPlatformConfigDxe.h"
+#include "RedfishPlatformConfigImpl.h"
+
+REDFISH_PLATFORM_CONFIG_PRIVATE *mRedfishPlatformConfigPrivate = NULL;
+
+/**
+ Compare two value in HII statement format.
+
+ @param[in] Value1 Firt value to compare.
+ @param[in] Value2 Second value to be compared.
+
+ @retval UINTN 0 is retuned 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.
+
+**/
+UINTN
+CompareHiiStatementValue (
+ IN HII_STATEMENT_VALUE *Value1,
+ IN HII_STATEMENT_VALUE *Value2
+ )
+{
+ INTN Result;
+ UINT64 Data1;
+ UINT64 Data2;
+
+ if (Value1 == NULL || Value2 == NULL) {
+ return 0xFF;
+ }
+
+ 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 0xFF;
+ }
+
+ 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 0xFF;
+ }
+
+ Result = (Data1 == Data2 ? 0 : (Data1 > Data2 ? 1 : -1));
+
+ return Result;
+}
+
+/**
+ Convert HII value to the string in HII one-of opcode.
+
+ @param[in] Statement Statement private instance
+
+ @retval EFI_STRING_ID The string ID in HII database.
+ 0 is returned when something goes wrong.
+
+**/
+EFI_STRING_ID
+HiiValueToOneOfOptionStringId (
+ IN REDFISH_PLATFORM_CONFIG_STATEMENT_PRIVATE *Statement
+ )
+{
+ LIST_ENTRY *Link;
+ HII_QUESTION_OPTION *Option;
+
+ if (Statement->HiiStatement->Operand != EFI_IFR_ONE_OF_OP) {
+ return 0;
+ }
+
+ if (IsListEmpty (&Statement->HiiStatement->OptionListHead)) {
+ return 0;
+ }
+
+ Link = GetFirstNode (&Statement->HiiStatement->OptionListHead);
+ while (!IsNull (&Statement->HiiStatement->OptionListHead, Link)) {
+ Option = HII_QUESTION_OPTION_FROM_LINK (Link);
+
+ if (CompareHiiStatementValue (&Statement->HiiStatement->Value, &Option->Value) == 0) {
+ return Option->Text;
+ }
+
+ Link = GetNextNode (&Statement->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 = REDFISH_VALUE_TYPE_INTEGER;
+ RedfishValue->Value.Integer = (INT64)Value->Value.u8;
+ break;
+ case EFI_IFR_TYPE_NUM_SIZE_16:
+ RedfishValue->Type = REDFISH_VALUE_TYPE_INTEGER;
+ RedfishValue->Value.Integer = (INT64)Value->Value.u16;
+ break;
+ case EFI_IFR_TYPE_NUM_SIZE_32:
+ RedfishValue->Type = REDFISH_VALUE_TYPE_INTEGER;
+ RedfishValue->Value.Integer = (INT64)Value->Value.u32;
+ break;
+ case EFI_IFR_TYPE_NUM_SIZE_64:
+ RedfishValue->Type = REDFISH_VALUE_TYPE_INTEGER;
+ RedfishValue->Value.Integer = (INT64)Value->Value.u64;
+ break;
+ case EFI_IFR_TYPE_BOOLEAN:
+ RedfishValue->Type = REDFISH_VALUE_TYPE_BOOLEAN;
+ RedfishValue->Value.Boolean = Value->Value.b;
+ break;
+ default:
+ RedfishValue->Type = REDFISH_VALUE_TYPE_UNKNOWN;
+ 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 REDFISH_VALUE_TYPE_INTEGER:
+ Value->Type = EFI_IFR_TYPE_NUM_SIZE_64;
+ Value->Value.u64 = (UINT64)RedfishValue->Value.Integer;
+ break;
+ case REDFISH_VALUE_TYPE_BOOLEAN:
+ Value->Type = EFI_IFR_TYPE_BOOLEAN;
+ Value->Value.b = RedfishValue->Value.Boolean;
+ break;
+ default:
+ Value->Type = EFI_IFR_TYPE_UNDEFINED;
+ break;
+ }
+
+ return EFI_SUCCESS;
+}
+
+/**
+ 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", __FUNCTION__));
+ 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", __FUNCTION__, 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", __FUNCTION__, ConfigureLang, Schema));
+ return EFI_NOT_FOUND;
+ }
+
+ //
+ // Find current HII question value.
+ //
+ Status = GetQuestionValue (
+ TargetStatement->ParentForm->ParentFormset->HiiFormSet,
+ TargetStatement->ParentForm->HiiForm,
+ TargetStatement->HiiStatement,
+ GetSetValueWithHiiDriver
+ );
+ if (EFI_ERROR (Status)) {
+ DEBUG ((DEBUG_ERROR, "%a, failed to get question current value: %r\n", __FUNCTION__, 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;
+ EFI_STRING_ID StringId;
+ CHAR8 *FullSchema;
+ EFI_STRING HiiString;
+ UINTN Size;
+
+ 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 = REDFISH_VALUE_TYPE_UNKNOWN;
+ FullSchema = NULL;
+ HiiString = 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;
+ }
+
+ switch (TargetStatement->HiiStatement->Operand) {
+ case EFI_IFR_ONE_OF_OP:
+ StringId = HiiValueToOneOfOptionStringId (TargetStatement);
+ if (StringId == 0) {
+ ASSERT (FALSE);
+ Status = EFI_DEVICE_ERROR;
+ goto RELEASE_RESOURCE;
+ }
+
+ HiiString = HiiGetRedfishString (TargetStatement->ParentForm->ParentFormset->HiiHandle, FullSchema, StringId);
+ if (HiiString == NULL) {
+ DEBUG ((DEBUG_ERROR, "%a, Can not find string ID: 0x%x with %a\n", __FUNCTION__, StringId, FullSchema));
+ Status = EFI_NOT_FOUND;
+ goto RELEASE_RESOURCE;
+ }
+
+ Size = StrLen (HiiString) + 1;
+ Value->Value.Buffer = AllocatePool (Size);
+ if (Value->Value.Buffer == NULL) {
+ Status = EFI_OUT_OF_RESOURCES;
+ goto RELEASE_RESOURCE;
+ }
+
+ UnicodeStrToAsciiStrS (HiiString, Value->Value.Buffer, Size);
+ Value->Type = REDFISH_VALUE_TYPE_STRING;
+
+ break;
+ case EFI_IFR_STRING_OP:
+ if (TargetStatement->HiiStatement->Value.Type != EFI_IFR_TYPE_STRING) {
+ ASSERT (FALSE);
+ Status = EFI_DEVICE_ERROR;
+ goto RELEASE_RESOURCE;
+ }
+
+ Value->Type = REDFISH_VALUE_TYPE_STRING;
+ Value->Value.Buffer = AllocateCopyPool (StrSize ((CHAR16 *)TargetStatement->HiiStatement->Value.Buffer), TargetStatement->HiiStatement->Value.Buffer);
+ if (Value->Value.Buffer == NULL) {
+ Status = EFI_OUT_OF_RESOURCES;
+ goto RELEASE_RESOURCE;
+ }
+ break;
+ case EFI_IFR_CHECKBOX_OP:
+ case EFI_IFR_NUMERIC_OP:
+ Status = HiiValueToRedfishNumeric (&TargetStatement->HiiStatement->Value, Value);
+ if (EFI_ERROR (Status)) {
+ DEBUG ((DEBUG_ERROR, "%a, failed to convert HII value to Redfish value: %r\n", __FUNCTION__, Status));
+ goto RELEASE_RESOURCE;
+ }
+ break;
+ default:
+ DEBUG ((DEBUG_ERROR, "%a, catch unsupported type: 0x%x! Please contact with author if we need to support this type.\n", __FUNCTION__, TargetStatement->HiiStatement->Operand));
+ ASSERT (FALSE);
+ Status = EFI_UNSUPPORTED;
+ goto RELEASE_RESOURCE;
+ }
+
+RELEASE_RESOURCE:
+
+ if (FullSchema != NULL) {
+ FreePool (FullSchema);
+ }
+
+ if (HiiString != NULL) {
+ FreePool (HiiString);
+ }
+
+ 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 applyu.
+
+ @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", __FUNCTION__, Status));
+ return Status;
+ }
+
+ Status = SubmitForm (HiiFormset, HiiForm);
+ if (EFI_ERROR (Status)) {
+ DEBUG ((DEBUG_ERROR, "%a, failed to submit form: %r\n", __FUNCTION__, 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] Statement Statement instance
+
+ @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;
+
+ if (RedfishPlatformConfigPrivate == NULL || IS_EMPTY_STRING (Schema) || IS_EMPTY_STRING (ConfigureLang) || StatementValue == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ TempBuffer = NULL;
+
+ Status = ProcessPendingList (&RedfishPlatformConfigPrivate->FormsetList, &RedfishPlatformConfigPrivate->PendingList);
+ if (EFI_ERROR (Status)) {
+ DEBUG ((DEBUG_ERROR, "%a, ProcessPendingList failure: %r\n", __FUNCTION__, 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", __FUNCTION__, 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 = AllocatePool (StatementValue->BufferLen * sizeof (CHAR16));
+ if (TempBuffer == NULL) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ AsciiStrToUnicodeStrS (StatementValue->Buffer, TempBuffer, StatementValue->BufferLen);
+ 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", __FUNCTION__, TempBuffer));
+ FreePool (TempBuffer);
+ return EFI_NOT_FOUND;
+ }
+
+ FreePool (TempBuffer);
+ } 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", __FUNCTION__, 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", __FUNCTION__, 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 == REDFISH_VALUE_TYPE_UNKNOWN || Value.Type >= REDFISH_VALUE_TYPE_MAX) {
+ 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 REDFISH_VALUE_TYPE_INTEGER:
+ case REDFISH_VALUE_TYPE_BOOLEAN:
+ Status = RedfishNumericToHiiValue (&Value, &NewValue);
+ if (EFI_ERROR (Status)) {
+ DEBUG ((DEBUG_ERROR, "%a, failed to convert Redfish value to Hii value: %r\n", __FUNCTION__, Status));
+ goto RELEASE_RESOURCE;
+ }
+ break;
+ case REDFISH_VALUE_TYPE_STRING:
+ 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;
+ 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", __FUNCTION__, Status));
+ }
+
+RELEASE_RESOURCE:
+
+ if (FullSchema != NULL) {
+ FreePool (FullSchema);
+ }
+
+ return Status;
+}
+
+/**
+ Get the list of Configure Language from platform configuration by the given Schema and Pattern.
+
+ @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] Pattern The target Configure Language pattern.
+ @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 Pattern,
+ 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 (Pattern)) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ *Count = 0;
+ *ConfigureLangList = NULL;
+ FullSchema = 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", __FUNCTION__, Status));
+ return Status;
+ }
+
+ FullSchema = GetFullSchemaString (Schema, Version);
+ if (FullSchema == NULL) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ Status = GetStatementPrivateByConfigureLangRegex (
+ RedfishPlatformConfigPrivate->RegularExpressionProtocol,
+ &RedfishPlatformConfigPrivate->FormsetList,
+ FullSchema,
+ Pattern,
+ &StatementList
+ );
+ if (EFI_ERROR (Status)) {
+ DEBUG ((DEBUG_ERROR, "%a, GetStatementPrivateByConfigureLangRegex failure: %r\n", __FUNCTION__, 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 paltform configuration on give HII handle.
+
+ @param[in] This Pointer to EDKII_REDFISH_PLATFORM_CONFIG_PROTOCOL instance.
+ @param[in] HiiHandle The target handle to search. If handle is NULL,
+ this function return all schema from HII database.
+ @param[out] SupportedSchema The supported schema list which is separated by ';'.
+ 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,
+ IN EFI_HII_HANDLE HiiHandle, OPTIONAL
+ 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", __FUNCTION__, 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 (HiiHandle != NULL && HiiHandle != HiiFormsetPrivate->HiiHandle) {
+ HiiFormsetLink = HiiFormsetNextLink;
+ continue;
+ }
+
+ 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 (HiiHandle != NULL && HiiHandle != HiiFormsetPrivate->HiiHandle) {
+ HiiFormsetLink = HiiFormsetNextLink;
+ continue;
+ }
+
+ 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;
+}
+
+/**
+ 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", __FUNCTION__, 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", __FUNCTION__, 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", __FUNCTION__, 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", __FUNCTION__, 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", __FUNCTION__, 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", __FUNCTION__, Status));
+ }
+
+#if REDFISH_PLATFORM_CONFIG_DELETE_EXPIRED_FORMSET
+ //
+ // Register package notification when new form package is removed.
+ //
+ Status = mRedfishPlatformConfigPrivate->HiiDatabase->RegisterPackageNotify (
+ mRedfishPlatformConfigPrivate->HiiDatabase,
+ EFI_HII_PACKAGE_FORMS,
+ NULL,
+ RedfishPlatformConfigFormUpdateNotify,
+ EFI_HII_DATABASE_NOTIFY_REMOVE_PACK,
+ &mRedfishPlatformConfigPrivate->NotifyHandle
+ );
+ if (EFI_ERROR (Status)) {
+ DEBUG ((DEBUG_ERROR, "%a, RegisterPackageNotify for EFI_HII_DATABASE_NOTIFY_NEW_PACK failure: %r\n", __FUNCTION__, Status));
+ }
+#endif
+
+ 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", __FUNCTION__, 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", __FUNCTION__, 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", __FUNCTION__));
+ ASSERT (FALSE);
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ //
+ // Protocol initialization
+ //
+ mRedfishPlatformConfigPrivate->ImageHandle = ImageHandle;
+ mRedfishPlatformConfigPrivate->Protocol.GetValue = RedfishPlatformConfigProtocolGetValue;
+ mRedfishPlatformConfigPrivate->Protocol.SetValue = RedfishPlatformConfigProtocolSetValue;
+ mRedfishPlatformConfigPrivate->Protocol.GetConfigureLang = RedfishPlatformConfigProtocolGetConfigureLang;
+ mRedfishPlatformConfigPrivate->Protocol.GetSupportedSchema = RedfishPlatformConfigProtocolGetSupportedSchema;
+
+ 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", __FUNCTION__, 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", __FUNCTION__));
+ 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", __FUNCTION__));
+ 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", __FUNCTION__));
+ ASSERT (FALSE);
+ }
+
+ return EFI_SUCCESS;
+}
diff --git a/RedfishPkg/RedfishPlatformConfigDxe/RedfishPlatformConfigImpl.c b/RedfishPkg/RedfishPlatformConfigDxe/RedfishPlatformConfigImpl.c
new file mode 100644
index 00000000000..d9eab6c883e
--- /dev/null
+++ b/RedfishPkg/RedfishPlatformConfigDxe/RedfishPlatformConfigImpl.c
@@ -0,0 +1,1240 @@
+/** @file
+
+ The implementation of EDKII Redfidh Platform Config Protocol.
+
+ (C) Copyright 2021 Hewlett Packard Enterprise Development LP<BR>
+
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+#include "RedfishPlatformConfigDxe.h"
+#include "RedfishPlatformConfigImpl.h"
+
+extern REDFISH_PLATFORM_CONFIG_PRIVATE *mRedfishPlatformConfigPrivate;
+
+/**
+ Debug dump HII string
+
+ @param[in] HiiHandle HII handle instance
+ @param[in] StringId HII string to dump
+
+ @retval EFI_SUCCESS Dump HII string successfully
+ @retval Others Errors occur
+
+**/
+EFI_STATUS
+DumpHiiString (
+ IN EFI_HII_HANDLE HiiHandle,
+ IN EFI_STRING_ID StringId
+ )
+{
+ EFI_STRING String;
+
+ if (HiiHandle == NULL || StringId == 0) {
+ DEBUG ((DEBUG_INFO, "???"));
+ return EFI_INVALID_PARAMETER;
+ }
+
+ String = HiiGetString (HiiHandle, StringId, NULL);
+ if (String == NULL) {
+ return EFI_NOT_FOUND;
+ }
+
+ DEBUG ((DEBUG_INFO, "%s", String));
+ FreePool (String);
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Debug dump HII form-set data
+
+ @param[in] FormsetPrivate HII form-set private instance.
+
+ @retval EFI_SUCCESS Dump form-set successfully
+ @retval Others Errors occur
+
+**/
+EFI_STATUS
+DumpFormset (
+ IN REDFISH_PLATFORM_CONFIG_FORM_SET_PRIVATE *FormsetPrivate
+ )
+{
+ LIST_ENTRY *HiiFormLink;
+ LIST_ENTRY *HiiNextFormLink;
+ REDFISH_PLATFORM_CONFIG_FORM_PRIVATE *HiiFormPrivate;
+ LIST_ENTRY *HiiStatementLink;
+ LIST_ENTRY *HiiNextStatementLink;
+ REDFISH_PLATFORM_CONFIG_STATEMENT_PRIVATE *HiiStatementPrivate;
+ UINTN Index;
+
+ if (FormsetPrivate == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ Index = 0;
+ HiiFormLink = GetFirstNode (&FormsetPrivate->HiiFormList);
+ while (!IsNull (&FormsetPrivate->HiiFormList, HiiFormLink)) {
+ HiiFormPrivate = REDFISH_PLATFORM_CONFIG_FORM_FROM_LINK (HiiFormLink);
+ HiiNextFormLink = GetNextNode (&FormsetPrivate->HiiFormList, HiiFormLink);
+
+ DEBUG ((DEBUG_INFO, " [%d] form: %d title: ", ++Index, HiiFormPrivate->Id));
+ DumpHiiString (FormsetPrivate->HiiHandle, HiiFormPrivate->Title);
+ DEBUG ((DEBUG_INFO, "\n"));
+
+ HiiStatementLink = GetFirstNode (&HiiFormPrivate->StatementList);
+ while (!IsNull (&HiiFormPrivate->StatementList, HiiStatementLink)) {
+ HiiStatementPrivate = REDFISH_PLATFORM_CONFIG_STATEMENT_FROM_LINK (HiiStatementLink);
+ HiiNextStatementLink = GetNextNode (&HiiFormPrivate->StatementList, HiiStatementLink);
+
+ DEBUG ((DEBUG_INFO, " QID: 0x%x Prompt: ", HiiStatementPrivate->QuestionId));
+ DumpHiiString (FormsetPrivate->HiiHandle, HiiStatementPrivate->Description);
+ DEBUG ((DEBUG_INFO, "\n"));
+
+ HiiStatementLink = HiiNextStatementLink;
+ }
+
+ HiiFormLink = HiiNextFormLink;
+ }
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Debug dump HII form-set list
+
+ @param[in] FormsetList Form-set list instance
+
+ @retval EFI_SUCCESS Dump list successfully
+ @retval Others Errors occur
+
+**/
+EFI_STATUS
+DumpFormsetList (
+ IN LIST_ENTRY *FormsetList
+ )
+{
+ LIST_ENTRY *HiiFormsetLink;
+ LIST_ENTRY *HiiFormsetNextLink;
+ REDFISH_PLATFORM_CONFIG_FORM_SET_PRIVATE *HiiFormsetPrivate;
+ UINTN Index;
+
+ if (FormsetList == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if (IsListEmpty (FormsetList)) {
+ DEBUG ((DEBUG_INFO, "%a, Empty formset list\n", __FUNCTION__));
+ return EFI_SUCCESS;
+ }
+
+ Index = 0;
+ HiiFormsetLink = GetFirstNode (FormsetList);
+ while (!IsNull (FormsetList, HiiFormsetLink)) {
+ HiiFormsetNextLink = GetNextNode (FormsetList, HiiFormsetLink);
+ HiiFormsetPrivate = REDFISH_PLATFORM_CONFIG_FORMSET_FROM_LINK (HiiFormsetLink);
+
+ DEBUG ((DEBUG_INFO, "[%d] HII Handle: 0x%x formset: %g at %s\n", ++Index, HiiFormsetPrivate->HiiHandle, &HiiFormsetPrivate->Guid, HiiFormsetPrivate->DevicePathStr));
+ DumpFormset (HiiFormsetPrivate);
+
+ HiiFormsetLink = HiiFormsetNextLink;
+ }
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Retrieves a string from a string package in a English language. The
+ returned string is allocated using AllocatePool(). The caller is responsible
+ for freeing the allocated buffer using FreePool().
+
+ If HiiHandle is NULL, then ASSERT().
+ If StringId is 0, then ASSET.
+
+ @param[in] HiiStringProtocol EFI_HII_STRING_PROTOCOL instance.
+ @param[in] HiiHandle A handle that was previously registered in the HII Database.
+ @param[in] StringId The identifier of the string to retrieved from the string
+ package associated with HiiHandle.
+
+ @retval NULL The string specified by StringId is not present in the string package.
+ @retval Other The string was returned.
+
+**/
+EFI_STRING
+HiiGetRedfishString (
+ IN EFI_HII_HANDLE HiiHandle,
+ IN CHAR8 *Language,
+ IN EFI_STRING_ID StringId
+ )
+{
+ EFI_STATUS Status;
+ UINTN StringSize;
+ CHAR16 TempString;
+ EFI_STRING String;
+
+ if (mRedfishPlatformConfigPrivate->HiiString == NULL || HiiHandle == NULL || StringId == 0 || IS_EMPTY_STRING (Language)) {
+ ASSERT (FALSE);
+ return NULL;
+ }
+
+ //
+ // Retrieve the size of the string in the string package for the BestLanguage
+ //
+ StringSize = 0;
+ Status = mRedfishPlatformConfigPrivate->HiiString->GetString (
+ mRedfishPlatformConfigPrivate->HiiString,
+ Language,
+ HiiHandle,
+ StringId,
+ &TempString,
+ &StringSize,
+ NULL
+ );
+ //
+ // If GetString() returns EFI_SUCCESS for a zero size,
+ // then there are no supported languages registered for HiiHandle. If GetString()
+ // returns an error other than EFI_BUFFER_TOO_SMALL, then HiiHandle is not present
+ // in the HII Database
+ //
+ if (Status != EFI_BUFFER_TOO_SMALL) {
+ return NULL;
+ }
+
+ //
+ // Allocate a buffer for the return string
+ //
+ String = AllocateZeroPool (StringSize);
+ if (String == NULL) {
+ return NULL;
+ }
+
+ //
+ // Retrieve the string from the string package
+ //
+ Status = mRedfishPlatformConfigPrivate->HiiString->GetString (
+ mRedfishPlatformConfigPrivate->HiiString,
+ Language,
+ HiiHandle,
+ StringId,
+ String,
+ &StringSize,
+ NULL
+ );
+ if (EFI_ERROR (Status)) {
+ //
+ // Free the buffer and return NULL if the supported languages can not be retrieved.
+ //
+ FreePool (String);
+ String = NULL;
+ }
+
+ //
+ // Return the Null-terminated Unicode string
+ //
+ return String;
+}
+
+/**
+ Get string from HII database in English language.
+
+ @param[in] HiiHandle A handle that was previously registered in the HII Database.
+ @param[in] StringId The identifier of the string to retrieved from the string
+ package associated with HiiHandle.
+
+ @retval NULL The string specified by StringId is not present in the string package.
+ @retval Other The string was returned.
+
+**/
+EFI_STRING
+HiiGetEnglishString (
+ IN EFI_HII_HANDLE HiiHandle,
+ IN EFI_STRING_ID StringId
+ )
+{
+ return HiiGetRedfishString (HiiHandle, ENGLISH_LANGUAGE_CODE, StringId);
+}
+
+/**
+ Check and see if this is supported schema or not.
+
+ @param[in] SupportedSchema The list of supported schema.
+ @param[in] Schema Schema string to be checked.
+
+ @retval BOOLEAN TRUE if this is supported schema. FALSE otherwise.
+
+**/
+BOOLEAN
+CheckSupportedSchema (
+ IN REDFISH_PLATFORM_CONFIG_SCHEMA *SupportedSchema,
+ IN CHAR8 *Schema
+ )
+{
+ UINTN Index;
+
+ if (SupportedSchema == NULL || IS_EMPTY_STRING (Schema)) {
+ return FALSE;
+ }
+
+ if (SupportedSchema->Count == 0) {
+ return FALSE;
+ }
+
+ for (Index = 0; Index < SupportedSchema->Count; Index++) {
+ if (AsciiStrCmp (SupportedSchema->SchemaList[Index], Schema) == 0) {
+ return TRUE;
+ }
+ }
+
+ return FALSE;
+}
+
+/**
+ Get the list of supported schema from the given HII handle.
+
+ @param[in] HiiHandle HII handle instance.
+ @param[out] SupportedSchema Supported schema on this HII handle.
+
+ @retval EFI_SUCCESS Schema list is returned.
+ @retval EFI_INVALID_PARAMETER HiiHandle is NULL or SupportedSchema is NULL.
+ @retval EFI_NOT_FOUND No supported schema found.
+ @retval EFI_OUT_OF_RESOURCES System is out of memory.
+
+**/
+EFI_STATUS
+GetSupportedSchema (
+ IN EFI_HII_HANDLE HiiHandle,
+ OUT REDFISH_PLATFORM_CONFIG_SCHEMA *SupportedSchema
+ )
+{
+ CHAR8 *SupportedLanguages;
+ UINTN Index;
+ UINTN LangIndex;
+ UINTN Count;
+ UINTN StrSize;
+ UINTN ListIndex;
+
+ if (HiiHandle == NULL || SupportedSchema == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ SupportedSchema->Count = 0;
+
+ SupportedLanguages = HiiGetSupportedLanguages (HiiHandle);
+ if (SupportedLanguages == NULL) {
+ return EFI_NOT_FOUND;
+ }
+
+ Index = 0;
+ LangIndex = 0;
+ Count = 0;
+ while (TRUE) {
+ if (SupportedLanguages[Index] == ';' || SupportedLanguages[Index] == '\0') {
+ if (AsciiStrnCmp (&SupportedLanguages[LangIndex], X_UEFI_SCHEMA_PREFIX, AsciiStrLen (X_UEFI_SCHEMA_PREFIX)) == 0) {
+ ++Count;
+ }
+ LangIndex = Index + 1;
+ }
+
+ if (SupportedLanguages[Index] == '\0') {
+ break;
+ }
+
+ ++Index;
+ }
+
+ if (Count == 0) {
+ return EFI_NOT_FOUND;
+ }
+
+ SupportedSchema->Count = Count;
+ SupportedSchema->SchemaList = AllocatePool (sizeof (CHAR8 *) * Count);
+ if (SupportedSchema->SchemaList == NULL) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ Index = 0;
+ LangIndex = 0;
+ ListIndex = 0;
+ while (TRUE) {
+
+ if (SupportedLanguages[Index] == ';' || SupportedLanguages[Index] == '\0') {
+ if (AsciiStrnCmp (&SupportedLanguages[LangIndex], X_UEFI_SCHEMA_PREFIX, AsciiStrLen (X_UEFI_SCHEMA_PREFIX)) == 0) {
+ StrSize = Index - LangIndex;
+ SupportedSchema->SchemaList[ListIndex] = AllocateCopyPool ((StrSize + 1), &SupportedLanguages[LangIndex]);
+ SupportedSchema->SchemaList[ListIndex][StrSize] = '\0';
+ ++ListIndex;
+ }
+
+ LangIndex = Index + 1;
+ }
+
+ if (SupportedLanguages[Index] == '\0') {
+ break;
+ }
+
+ ++Index;
+ }
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Search and find statement private instance by given regular expression patthern
+ which describes the Configure Language.
+
+ @param[in] RegularExpressionProtocol Regular express protocol.
+ @param[in] FormsetList Form-set list to search.
+ @param[in] Schema Schema to be matched.
+ @param[in] Pattern Regular expression pattern.
+ @param[out] StatementList Statement list that match above pattern.
+
+ @retval EFI_SUCCESS Statement list is returned.
+ @retval EFI_INVALID_PARAMETER Input parameter is NULL.
+ @retval EFI_NOT_READY Regular express protocol is NULL.
+ @retval EFI_NOT_FOUND No statement is found.
+ @retval EFI_OUT_OF_RESOURCES System is out of memory.
+
+**/
+EFI_STATUS
+GetStatementPrivateByConfigureLangRegex (
+ IN EFI_REGULAR_EXPRESSION_PROTOCOL *RegularExpressionProtocol,
+ IN LIST_ENTRY *FormsetList,
+ IN CHAR8 *Schema,
+ IN EFI_STRING Pattern,
+ OUT REDFISH_PLATFORM_CONFIG_STATEMENT_PRIVATE_LIST *StatementList
+ )
+{
+ LIST_ENTRY *HiiFormsetLink;
+ LIST_ENTRY *HiiFormsetNextLink;
+ REDFISH_PLATFORM_CONFIG_FORM_SET_PRIVATE *HiiFormsetPrivate;
+ LIST_ENTRY *HiiFormLink;
+ LIST_ENTRY *HiiNextFormLink;
+ REDFISH_PLATFORM_CONFIG_FORM_PRIVATE *HiiFormPrivate;
+ LIST_ENTRY *HiiStatementLink;
+ LIST_ENTRY *HiiNextStatementLink;
+ REDFISH_PLATFORM_CONFIG_STATEMENT_PRIVATE *HiiStatementPrivate;
+ EFI_STRING TmpString;
+ UINTN CaptureCount;
+ BOOLEAN IsMatch;
+ EFI_STATUS Status;
+ REDFISH_PLATFORM_CONFIG_STATEMENT_PRIVATE_REF *StatementRef;
+
+ if (FormsetList == NULL || IS_EMPTY_STRING (Schema) || IS_EMPTY_STRING (Pattern) || StatementList == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if (RegularExpressionProtocol == NULL) {
+ return EFI_NOT_READY;
+ }
+
+ StatementList->Count = 0;
+ InitializeListHead (&StatementList->StatementList);
+
+ if (IsListEmpty (FormsetList)) {
+ return EFI_NOT_FOUND;
+ }
+
+ HiiFormsetLink = GetFirstNode (FormsetList);
+ while (!IsNull (FormsetList, HiiFormsetLink)) {
+ HiiFormsetNextLink = GetNextNode (FormsetList, HiiFormsetLink);
+ HiiFormsetPrivate = REDFISH_PLATFORM_CONFIG_FORMSET_FROM_LINK (HiiFormsetLink);
+
+ //
+ // Performance check.
+ // If there is no desired Redfish schema found, skip this formset.
+ //
+ if (!CheckSupportedSchema (&HiiFormsetPrivate->SupportedSchema, Schema)) {
+ HiiFormsetLink = HiiFormsetNextLink;
+ continue;
+ }
+
+ HiiFormLink = GetFirstNode (&HiiFormsetPrivate->HiiFormList);
+ while (!IsNull (&HiiFormsetPrivate->HiiFormList, HiiFormLink)) {
+ HiiNextFormLink = GetNextNode (&HiiFormsetPrivate->HiiFormList, HiiFormLink);
+ HiiFormPrivate = REDFISH_PLATFORM_CONFIG_FORM_FROM_LINK (HiiFormLink);
+
+ HiiStatementLink =GetFirstNode (&HiiFormPrivate->StatementList);
+ while (!IsNull (&HiiFormPrivate->StatementList, HiiStatementLink)) {
+ HiiNextStatementLink = GetNextNode (&HiiFormPrivate->StatementList, HiiStatementLink);
+ HiiStatementPrivate = REDFISH_PLATFORM_CONFIG_STATEMENT_FROM_LINK (HiiStatementLink);
+
+ if (HiiStatementPrivate->Description != 0) {
+ TmpString = HiiGetRedfishString (HiiFormsetPrivate->HiiHandle, Schema, HiiStatementPrivate->Description);
+ if (TmpString != NULL) {
+ Status = RegularExpressionProtocol->MatchString (
+ RegularExpressionProtocol,
+ TmpString,
+ Pattern,
+ &gEfiRegexSyntaxTypePerlGuid,
+ &IsMatch,
+ NULL,
+ &CaptureCount
+ );
+ if (EFI_ERROR (Status)) {
+ DEBUG ((DEBUG_ERROR, "%a, MatchString \"%s\" failed: %r\n", __FUNCTION__, Pattern, Status));
+ ASSERT (FALSE);
+ return Status;
+ }
+
+ //
+ // Found
+ //
+ if (IsMatch) {
+ StatementRef = AllocateZeroPool (sizeof (REDFISH_PLATFORM_CONFIG_STATEMENT_PRIVATE_REF));
+ if (StatementRef == NULL) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ StatementRef->Statement = HiiStatementPrivate;
+ InsertTailList (&StatementList->StatementList, &StatementRef->Link);
+ ++StatementList->Count;
+ }
+
+ FreePool (TmpString);
+ }
+ }
+
+ HiiStatementLink = HiiNextStatementLink;
+ }
+
+ HiiFormLink = HiiNextFormLink;
+ }
+
+ HiiFormsetLink = HiiFormsetNextLink;
+ }
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Get statement private instance by the given configure language.
+
+ @param[in] FormsetList Form-set list to search.
+ @param[in] Schema Schema to be matched.
+ @param[in] ConfigureLang Configure language.
+
+ @retval REDFISH_PLATFORM_CONFIG_STATEMENT_PRIVATE * Pointer to statement private instance.
+
+**/
+REDFISH_PLATFORM_CONFIG_STATEMENT_PRIVATE *
+GetStatementPrivateByConfigureLang (
+ IN LIST_ENTRY *FormsetList,
+ IN CHAR8 *Schema,
+ IN EFI_STRING ConfigureLang
+ )
+{
+ LIST_ENTRY *HiiFormsetLink;
+ LIST_ENTRY *HiiFormsetNextLink;
+ REDFISH_PLATFORM_CONFIG_FORM_SET_PRIVATE *HiiFormsetPrivate;
+ LIST_ENTRY *HiiFormLink;
+ LIST_ENTRY *HiiNextFormLink;
+ REDFISH_PLATFORM_CONFIG_FORM_PRIVATE *HiiFormPrivate;
+ LIST_ENTRY *HiiStatementLink;
+ LIST_ENTRY *HiiNextStatementLink;
+ REDFISH_PLATFORM_CONFIG_STATEMENT_PRIVATE *HiiStatementPrivate;
+ EFI_STRING TmpString;
+
+ if (FormsetList == NULL || IS_EMPTY_STRING (Schema) || IS_EMPTY_STRING (ConfigureLang)) {
+ return NULL;
+ }
+
+ if (IsListEmpty (FormsetList)) {
+ return NULL;
+ }
+
+ HiiFormsetLink = GetFirstNode (FormsetList);
+ while (!IsNull (FormsetList, HiiFormsetLink)) {
+ HiiFormsetNextLink = GetNextNode (FormsetList, HiiFormsetLink);
+ HiiFormsetPrivate = REDFISH_PLATFORM_CONFIG_FORMSET_FROM_LINK (HiiFormsetLink);
+
+ //
+ // Performance check.
+ // If there is no desired Redfish schema found, skip this formset.
+ //
+ if (!CheckSupportedSchema (&HiiFormsetPrivate->SupportedSchema, Schema)) {
+ HiiFormsetLink = HiiFormsetNextLink;
+ continue;
+ }
+
+ HiiFormLink = GetFirstNode (&HiiFormsetPrivate->HiiFormList);
+ while (!IsNull (&HiiFormsetPrivate->HiiFormList, HiiFormLink)) {
+ HiiNextFormLink = GetNextNode (&HiiFormsetPrivate->HiiFormList, HiiFormLink);
+ HiiFormPrivate = REDFISH_PLATFORM_CONFIG_FORM_FROM_LINK (HiiFormLink);
+
+ HiiStatementLink =GetFirstNode (&HiiFormPrivate->StatementList);
+ while (!IsNull (&HiiFormPrivate->StatementList, HiiStatementLink)) {
+ HiiNextStatementLink = GetNextNode (&HiiFormPrivate->StatementList, HiiStatementLink);
+ HiiStatementPrivate = REDFISH_PLATFORM_CONFIG_STATEMENT_FROM_LINK (HiiStatementLink);
+
+ DEBUG_CODE (
+ STATIC UINTN Index = 0;
+ DEBUG ((DEBUG_INFO, "%a, [%d] search %s in QID: 0x%x form: 0x%x formset: %g\n", __FUNCTION__, ++Index, ConfigureLang, HiiStatementPrivate->QuestionId, HiiFormPrivate->Id, &HiiFormsetPrivate->Guid));
+ );
+
+ if (HiiStatementPrivate->Description != 0) {
+ TmpString = HiiGetRedfishString (HiiFormsetPrivate->HiiHandle, Schema, HiiStatementPrivate->Description);
+ if (TmpString != NULL) {
+ if (StrCmp (TmpString, ConfigureLang) == 0) {
+ FreePool (TmpString);
+ return HiiStatementPrivate;
+ }
+
+ FreePool (TmpString);
+ }
+ }
+
+ HiiStatementLink = HiiNextStatementLink;
+ }
+
+ HiiFormLink = HiiNextFormLink;
+ }
+
+ HiiFormsetLink = HiiFormsetNextLink;
+ }
+
+ return NULL;
+}
+
+/**
+ Get form-set private instance by the given HII handle.
+
+ @param[in] HiiHandle HII handle instance.
+ @param[in] FormsetList Form-set list to search.
+
+ @retval REDFISH_PLATFORM_CONFIG_FORM_SET_PRIVATE * Pointer to form-set private instance.
+
+**/
+REDFISH_PLATFORM_CONFIG_FORM_SET_PRIVATE *
+GetFormsetPrivateByHiiHandle (
+ IN EFI_HII_HANDLE HiiHandle,
+ IN LIST_ENTRY *FormsetList
+ )
+{
+ LIST_ENTRY *HiiFormsetLink;
+ LIST_ENTRY *HiiFormsetNextLink;
+ REDFISH_PLATFORM_CONFIG_FORM_SET_PRIVATE *HiiFormsetPrivate;
+
+ if (HiiHandle == NULL || FormsetList == NULL) {
+ return NULL;
+ }
+
+ if (IsListEmpty (FormsetList)) {
+ return NULL;
+ }
+
+ HiiFormsetLink = GetFirstNode (FormsetList);
+ while (!IsNull (FormsetList, HiiFormsetLink)) {
+ HiiFormsetNextLink = GetNextNode (FormsetList, HiiFormsetLink);
+ HiiFormsetPrivate = REDFISH_PLATFORM_CONFIG_FORMSET_FROM_LINK (HiiFormsetLink);
+
+ if (HiiFormsetPrivate->HiiHandle == HiiHandle) {
+ return HiiFormsetPrivate;
+ }
+
+ HiiFormsetLink = HiiFormsetNextLink;
+ }
+
+ return NULL;
+}
+
+/**
+ Release formset and all the forms and statements that belong to this formset.
+
+ @param[in] FormsetPrivate Pointer to HP_HII_FORM_SET_PRIVATE
+
+ @retval EFI_STATUS
+
+**/
+EFI_STATUS
+ReleaseFormset (
+ IN REDFISH_PLATFORM_CONFIG_FORM_SET_PRIVATE *FormsetPrivate
+ )
+{
+ LIST_ENTRY *HiiFormLink;
+ LIST_ENTRY *HiiNextFormLink;
+ REDFISH_PLATFORM_CONFIG_FORM_PRIVATE *HiiFormPrivate;
+ LIST_ENTRY *HiiStatementLink;
+ LIST_ENTRY *HiiNextStatementLink;
+ REDFISH_PLATFORM_CONFIG_STATEMENT_PRIVATE *HiiStatementPrivate;
+ UINTN Index;
+
+ if (FormsetPrivate == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ HiiFormLink = GetFirstNode (&FormsetPrivate->HiiFormList);
+ while (!IsNull (&FormsetPrivate->HiiFormList, HiiFormLink)) {
+ HiiFormPrivate = REDFISH_PLATFORM_CONFIG_FORM_FROM_LINK (HiiFormLink);
+ HiiNextFormLink = GetNextNode (&FormsetPrivate->HiiFormList, HiiFormLink);
+
+ HiiStatementLink = GetFirstNode (&HiiFormPrivate->StatementList);
+ while (!IsNull (&HiiFormPrivate->StatementList, HiiStatementLink)) {
+ HiiStatementPrivate = REDFISH_PLATFORM_CONFIG_STATEMENT_FROM_LINK (HiiStatementLink);
+ HiiNextStatementLink = GetNextNode (&HiiFormPrivate->StatementList, HiiStatementLink);
+
+ //
+ // HiiStatementPrivate->HiiStatement will be released in DestroyFormSet().
+ //
+
+ if (HiiStatementPrivate->DesStringCache != NULL) {
+ FreePool (HiiStatementPrivate->DesStringCache);
+ HiiStatementPrivate->DesStringCache = NULL;
+ }
+
+ RemoveEntryList (&HiiStatementPrivate->Link);
+ FreePool (HiiStatementPrivate);
+ HiiStatementLink = HiiNextStatementLink;
+ }
+
+ //
+ // HiiStatementPrivate->HiiForm will be released in DestroyFormSet().
+ //
+
+ RemoveEntryList (&HiiFormPrivate->Link);
+ FreePool (HiiFormPrivate);
+ HiiFormLink = HiiNextFormLink;
+ }
+
+ if (FormsetPrivate->HiiFormSet != NULL) {
+ DestroyFormSet (FormsetPrivate->HiiFormSet);
+ FormsetPrivate->HiiFormSet = NULL;
+ }
+
+ FreePool (FormsetPrivate->DevicePathStr);
+
+ //
+ // Release schema list
+ //
+ if (FormsetPrivate->SupportedSchema.SchemaList != NULL) {
+ for (Index = 0; Index < FormsetPrivate->SupportedSchema.Count; Index++) {
+ FreePool (FormsetPrivate->SupportedSchema.SchemaList[Index]);
+ }
+
+ FreePool (FormsetPrivate->SupportedSchema.SchemaList);
+ FormsetPrivate->SupportedSchema.SchemaList = NULL;
+ FormsetPrivate->SupportedSchema.Count = 0;
+ }
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Create new form-set instance.
+
+ @retval REDFISH_PLATFORM_CONFIG_FORM_SET_PRIVATE * Pointer to newly created form-set private instance.
+
+**/
+REDFISH_PLATFORM_CONFIG_FORM_SET_PRIVATE *
+NewFormsetPrivate (
+ VOID
+ )
+{
+ REDFISH_PLATFORM_CONFIG_FORM_SET_PRIVATE *NewFormsetPrivate;
+
+ NewFormsetPrivate = AllocateZeroPool (sizeof (REDFISH_PLATFORM_CONFIG_FORM_SET_PRIVATE));
+ if (NewFormsetPrivate == NULL) {
+ return NULL;
+ }
+
+ //
+ // Initial newly created formset private data.
+ //
+ InitializeListHead (&NewFormsetPrivate->HiiFormList);
+
+ return NewFormsetPrivate;
+}
+
+/**
+ Load the HII formset from the given HII handle.
+
+ @param[in] HiiHandle Target HII handle to load.
+ @param[out] FormsetPrivate The formset private data.
+
+ @retval EFI_STATUS
+
+**/
+EFI_STATUS
+LoadFormset (
+ IN EFI_HII_HANDLE HiiHandle,
+ OUT REDFISH_PLATFORM_CONFIG_FORM_SET_PRIVATE *FormsetPrivate
+ )
+{
+ EFI_STATUS Status;
+ HII_FORMSET *HiiFormSet;
+ HII_FORM *HiiForm;
+ LIST_ENTRY *HiiFormLink;
+ REDFISH_PLATFORM_CONFIG_FORM_PRIVATE *HiiFormPrivate;
+ HII_STATEMENT *HiiStatement;
+ LIST_ENTRY *HiiStatementLink;
+ REDFISH_PLATFORM_CONFIG_STATEMENT_PRIVATE *HiiStatementPrivate;
+ EFI_GUID ZeroGuid;
+
+ if (HiiHandle == NULL || FormsetPrivate == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+
+ HiiFormSet = AllocateZeroPool (sizeof (HII_FORMSET));
+ if (HiiFormSet == NULL) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ //
+ // Find HII formset by the given HII handle.
+ //
+ ZeroMem (&ZeroGuid, sizeof (ZeroGuid));
+ Status = CreateFormSetFromHiiHandle (HiiHandle, &ZeroGuid, HiiFormSet);
+ if (EFI_ERROR (Status) || IsListEmpty (&HiiFormSet->FormListHead)) {
+ Status = EFI_NOT_FOUND;
+ goto ErrorExit;
+ }
+
+ //
+ // Initialize formset
+ //
+ InitializeFormSet (HiiFormSet);
+
+ //
+ // Initialize formset private data.
+ //
+ FormsetPrivate->HiiFormSet = HiiFormSet;
+ FormsetPrivate->HiiHandle = HiiHandle;
+ CopyGuid (&FormsetPrivate->Guid, &HiiFormSet->Guid);
+ FormsetPrivate->DevicePathStr = ConvertDevicePathToText (HiiFormSet->DevicePath, FALSE, FALSE);
+ Status = GetSupportedSchema (FormsetPrivate->HiiHandle, &FormsetPrivate->SupportedSchema);
+ if (EFI_ERROR (Status)) {
+ DEBUG ((DEBUG_WARN, "%a, No schema from HII handle: 0x%x found: %r\n", __FUNCTION__, FormsetPrivate->HiiHandle, Status));
+ }
+
+ HiiFormLink = GetFirstNode (&HiiFormSet->FormListHead);
+ while (!IsNull (&HiiFormSet->FormListHead, HiiFormLink)) {
+ HiiForm = HII_FORM_FROM_LINK (HiiFormLink);
+
+ HiiFormPrivate = AllocateZeroPool (sizeof (REDFISH_PLATFORM_CONFIG_FORM_PRIVATE));
+ if (HiiFormPrivate == NULL) {
+ Status = EFI_OUT_OF_RESOURCES;
+ goto ErrorExit;
+ }
+
+ //
+ // Initialize form private data.
+ //
+ HiiFormPrivate->HiiForm = HiiForm;
+ HiiFormPrivate->Id = HiiForm->FormId;
+ HiiFormPrivate->Title = HiiForm->FormTitle;
+ HiiFormPrivate->ParentFormset = FormsetPrivate;
+ InitializeListHead (&HiiFormPrivate->StatementList);
+
+ HiiStatementLink = GetFirstNode (&HiiForm->StatementListHead);
+ while (!IsNull (&HiiForm->StatementListHead, HiiStatementLink)) {
+ HiiStatement = HII_STATEMENT_FROM_LINK (HiiStatementLink);
+
+ HiiStatementPrivate = AllocateZeroPool (sizeof (REDFISH_PLATFORM_CONFIG_STATEMENT_PRIVATE));
+ if (HiiStatementPrivate == NULL) {
+ Status = EFI_OUT_OF_RESOURCES;
+ goto ErrorExit;
+ }
+ //
+ // Initialize statement private data.
+ //
+ HiiStatementPrivate->HiiStatement = HiiStatement;
+ HiiStatementPrivate->QuestionId = HiiStatement->QuestionId;
+ HiiStatementPrivate->Description = HiiStatement->Prompt;
+ HiiStatementPrivate->ParentForm = HiiFormPrivate;
+
+ //
+ // Attach to statement list.
+ //
+ InsertTailList (&HiiFormPrivate->StatementList, &HiiStatementPrivate->Link);
+ HiiStatementLink = GetNextNode (&HiiForm->StatementListHead, HiiStatementLink);
+ }
+ //
+ // Attach to form list.
+ //
+ InsertTailList (&FormsetPrivate->HiiFormList, &HiiFormPrivate->Link);
+ HiiFormLink = GetNextNode (&HiiFormSet->FormListHead, HiiFormLink);
+ }
+
+ return EFI_SUCCESS;
+
+ErrorExit:
+
+ //
+ // Release HiiFormSet if HiiFormSet is not linked to FormsetPrivate yet.
+ //
+ if (HiiFormSet != NULL && FormsetPrivate->HiiFormSet != HiiFormSet) {
+ DestroyFormSet (HiiFormSet);
+ }
+
+ //
+ // Release resource when error happens.
+ //
+ ReleaseFormset (FormsetPrivate);
+
+ return Status;
+}
+
+/**
+ Release formset list and all the forms that belong to this formset.
+
+ @param[in] FormsetList Pointer to formst list that needs to be
+ released.
+
+ @retval EFI_STATUS
+
+**/
+EFI_STATUS
+LoadFormsetList (
+ IN EFI_HII_HANDLE *HiiHandle,
+ OUT LIST_ENTRY *FormsetList
+ )
+{
+ EFI_STATUS Status;
+ REDFISH_PLATFORM_CONFIG_FORM_SET_PRIVATE *FormsetPrivate;
+
+ if (HiiHandle == NULL || FormsetList == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ FormsetPrivate = GetFormsetPrivateByHiiHandle (HiiHandle, FormsetList);
+ if (FormsetPrivate != NULL) {
+ return EFI_ALREADY_STARTED;
+ }
+
+ FormsetPrivate = NewFormsetPrivate ();
+ if (FormsetPrivate == NULL) {
+ DEBUG ((DEBUG_ERROR, "%a, out of resource\n", __FUNCTION__));
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ //
+ // Load formset on the given HII handle.
+ //
+ Status = LoadFormset (HiiHandle, FormsetPrivate);
+ if (EFI_ERROR (Status)) {
+ DEBUG ((DEBUG_ERROR, "%a, failed to load formset: %r\n", __FUNCTION__, Status));
+ FreePool (FormsetPrivate);
+ return Status;
+ }
+
+ //
+ // Attach to cache list.
+ //
+ InsertTailList (FormsetList, &FormsetPrivate->Link);
+
+ DEBUG_CODE (
+ DumpFormsetList (FormsetList);
+ );
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Release formset list and all the forms that belong to this formset.
+
+ @param[in] FormsetList Pointer to formst list that needs to be
+ released.
+
+ @retval EFI_STATUS
+
+**/
+EFI_STATUS
+ReleaseFormsetList (
+ IN LIST_ENTRY *FormsetList
+ )
+{
+ LIST_ENTRY *HiiFormsetLink;
+ LIST_ENTRY *HiiFormsetNextLink;
+ REDFISH_PLATFORM_CONFIG_FORM_SET_PRIVATE *HiiFormsetPrivate;
+
+ if (FormsetList == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if (IsListEmpty (FormsetList)) {
+ return EFI_SUCCESS;
+ }
+
+ HiiFormsetLink = GetFirstNode (FormsetList);
+ while (!IsNull (FormsetList, HiiFormsetLink)) {
+ HiiFormsetNextLink = GetNextNode (FormsetList, HiiFormsetLink);
+ HiiFormsetPrivate = REDFISH_PLATFORM_CONFIG_FORMSET_FROM_LINK (HiiFormsetLink);
+
+ //
+ // Detach from list.
+ //
+ RemoveEntryList (&HiiFormsetPrivate->Link);
+ ReleaseFormset (HiiFormsetPrivate);
+ FreePool (HiiFormsetPrivate);
+ HiiFormsetLink = HiiFormsetNextLink;
+ }
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Get all pending list.
+
+ @param[in] HiiHandle HII handle instance.
+ @param[in] PendingList Pending list to keep pending data.
+
+ @retval REDFISH_PLATFORM_CONFIG_PENDING_LIST * Pointer to pending list data.
+
+**/
+REDFISH_PLATFORM_CONFIG_PENDING_LIST *
+GetPendingList (
+ IN EFI_HII_HANDLE *HiiHandle,
+ IN LIST_ENTRY *PendingList
+ )
+{
+ LIST_ENTRY *PendingListLink;
+ REDFISH_PLATFORM_CONFIG_PENDING_LIST *Target;
+
+ if (HiiHandle == NULL || PendingList == NULL) {
+ return NULL;
+ }
+
+ if (IsListEmpty (PendingList)) {
+ return NULL;
+ }
+
+ PendingListLink = GetFirstNode (PendingList);
+ while (!IsNull (PendingList, PendingListLink)) {
+ Target = REDFISH_PLATFORM_CONFIG_PENDING_LIST_FROM_LINK (PendingListLink);
+
+ if (Target->HiiHandle == HiiHandle) {
+ return Target;
+ }
+
+ PendingListLink = GetNextNode (PendingList, PendingListLink);
+ }
+
+ return NULL;
+}
+
+/**
+ When HII database is updated. Keep updated HII handle into pending list so
+ we can process them later.
+
+ @param[in] HiiHandle HII handle instance.
+ @param[in] PendingList Pending list to keep HII handle which is recently updated.
+
+ @retval EFI_SUCCESS HII handle is saved in pending list.
+ @retval EFI_INVALID_PARAMETER HiiHnalde is NULL or PendingList is NULL.
+ @retval EFI_OUT_OF_RESOURCES System is out of memory.
+
+**/
+EFI_STATUS
+NotifyFormsetUpdate (
+ IN EFI_HII_HANDLE *HiiHandle,
+ IN LIST_ENTRY *PendingList
+ )
+{
+ REDFISH_PLATFORM_CONFIG_PENDING_LIST *TargetPendingList;
+
+ if (HiiHandle == NULL || PendingList == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ //
+ // Check and see if this HII handle is processed already.
+ //
+ TargetPendingList = GetPendingList (HiiHandle, PendingList);
+ if (TargetPendingList != NULL) {
+ TargetPendingList->IsDeleted = FALSE;
+ DEBUG_CODE (
+ DEBUG ((DEBUG_INFO, "%a, HII handle: 0x%x is updated\n", __FUNCTION__, HiiHandle));
+ );
+ return EFI_SUCCESS;
+ }
+
+ TargetPendingList= AllocateZeroPool (sizeof (REDFISH_PLATFORM_CONFIG_PENDING_LIST));
+ if (TargetPendingList == NULL) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ TargetPendingList->HiiHandle = HiiHandle;
+ TargetPendingList->IsDeleted = FALSE;
+
+ InsertTailList (PendingList, &TargetPendingList->Link);
+
+ DEBUG_CODE (
+ DEBUG ((DEBUG_INFO, "%a, HII handle: 0x%x is created\n", __FUNCTION__, HiiHandle));
+ );
+
+ return EFI_SUCCESS;
+}
+
+/**
+ When HII database is updated and form-set is deleted. Keep deleted HII handle into pending list so
+ we can process them later.
+
+ @param[in] HiiHandle HII handle instance.
+ @param[in] PendingList Pending list to keep HII handle which is recently updated.
+
+ @retval EFI_SUCCESS HII handle is saved in pending list.
+ @retval EFI_INVALID_PARAMETER HiiHnalde is NULL or PendingList is NULL.
+ @retval EFI_OUT_OF_RESOURCES System is out of memory.
+
+**/
+EFI_STATUS
+NotifyFormsetDeleted (
+ IN EFI_HII_HANDLE *HiiHandle,
+ IN LIST_ENTRY *PendingList
+ )
+{
+ REDFISH_PLATFORM_CONFIG_PENDING_LIST *TargetPendingList;
+
+ if (HiiHandle == NULL || PendingList == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ //
+ // Check and see if this HII handle is processed already.
+ //
+ TargetPendingList = GetPendingList (HiiHandle, PendingList);
+ if (TargetPendingList != NULL) {
+ TargetPendingList->IsDeleted = TRUE;
+ DEBUG_CODE (
+ DEBUG ((DEBUG_INFO, "%a, HII handle: 0x%x is updated and deleted\n", __FUNCTION__, HiiHandle));
+ );
+ return EFI_SUCCESS;
+ }
+
+ TargetPendingList= AllocateZeroPool (sizeof (REDFISH_PLATFORM_CONFIG_PENDING_LIST));
+ if (TargetPendingList == NULL) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ TargetPendingList->HiiHandle = HiiHandle;
+ TargetPendingList->IsDeleted = TRUE;
+
+ InsertTailList (PendingList, &TargetPendingList->Link);
+
+ DEBUG_CODE (
+ DEBUG ((DEBUG_INFO, "%a, HII handle: 0x%x is deleted\n", __FUNCTION__, HiiHandle));
+ );
+
+ return EFI_SUCCESS;
+}
+
+/**
+ There are HII database update and we need to process them accordingly so that we
+ won't use stale data. This function will parse updated HII handle again in order
+ to get updated data-set.
+
+ @param[in] FormsetList List to keep HII form-set.
+ @param[in] PendingList List to keep HII handle that is updated.
+
+ @retval EFI_SUCCESS HII handle is saved in pending list.
+ @retval EFI_INVALID_PARAMETER FormsetList is NULL or PendingList is NULL.
+
+**/
+EFI_STATUS
+ProcessPendingList (
+ IN LIST_ENTRY *FormsetList,
+ IN LIST_ENTRY *PendingList
+ )
+{
+ LIST_ENTRY *PendingListLink;
+ LIST_ENTRY *PendingListNextLink;
+ REDFISH_PLATFORM_CONFIG_PENDING_LIST *Target;
+ REDFISH_PLATFORM_CONFIG_FORM_SET_PRIVATE *FormsetPrivate;
+ EFI_STATUS Status;
+
+
+ if (FormsetList == NULL || PendingList == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if (IsListEmpty (PendingList)) {
+ return EFI_SUCCESS;
+ }
+
+ PendingListLink = GetFirstNode (PendingList);
+ while (!IsNull (PendingList, PendingListLink)) {
+ PendingListNextLink = GetNextNode (PendingList, PendingListLink);
+ Target = REDFISH_PLATFORM_CONFIG_PENDING_LIST_FROM_LINK (PendingListLink);
+
+ if (Target->IsDeleted) {
+ //
+ // The HII resource on this HII handle is removed. Release the formset.
+ //
+ FormsetPrivate = GetFormsetPrivateByHiiHandle (Target->HiiHandle, FormsetList);
+ if (FormsetPrivate != NULL) {
+ DEBUG ((DEBUG_INFO, "%a, formset: %g is removed because driver release HII resource it already\n", __FUNCTION__, FormsetPrivate->Guid));
+ RemoveEntryList (&FormsetPrivate->Link);
+ ReleaseFormset (FormsetPrivate);
+ FreePool (FormsetPrivate);
+ } else {
+ DEBUG ((DEBUG_WARN, "%a, formset on HII handle 0x%x was removed already\n", __FUNCTION__, Target->HiiHandle));
+ }
+ } else {
+ //
+ // The HII resource on this HII handle is updated/removed.
+ //
+ FormsetPrivate = GetFormsetPrivateByHiiHandle (Target->HiiHandle, FormsetList);
+ if (FormsetPrivate != NULL) {
+ //
+ // HII formset already exist, release it and query again.
+ //
+ DEBUG ((DEBUG_INFO, "%a, formset: %g is updated. Release current formset\n", __FUNCTION__, &FormsetPrivate->Guid));
+ RemoveEntryList (&FormsetPrivate->Link);
+ ReleaseFormset (FormsetPrivate);
+ FreePool (FormsetPrivate);
+ }
+
+ Status = LoadFormsetList (Target->HiiHandle, FormsetList);
+ if (EFI_ERROR (Status)) {
+ DEBUG ((DEBUG_ERROR, "%a, load formset from HII handle: 0x%x failed: %r\n", __FUNCTION__, Target->HiiHandle, Status));
+ }
+ }
+
+ //
+ // Detach it from list first.
+ //
+ RemoveEntryList (&Target->Link);
+ FreePool (Target);
+
+ PendingListLink = PendingListNextLink;
+ }
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Release all resource in statement list.
+
+ @param[in] StatementList Statement list to be released.
+
+ @retval EFI_SUCCESS All resource are released.
+ @retval EFI_INVALID_PARAMETER StatementList is NULL.
+
+**/
+EFI_STATUS
+ReleaseStatementList (
+ IN REDFISH_PLATFORM_CONFIG_STATEMENT_PRIVATE_LIST *StatementList
+ )
+{
+ REDFISH_PLATFORM_CONFIG_STATEMENT_PRIVATE_REF *StatementRef;
+ LIST_ENTRY *NextLink;
+
+ if (StatementList == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if (IsListEmpty (&StatementList->StatementList)) {
+ return EFI_SUCCESS;
+ }
+
+ NextLink = GetFirstNode (&StatementList->StatementList);
+ while (!IsNull (&StatementList->StatementList, NextLink)) {
+ StatementRef = REDFISH_PLATFORM_CONFIG_STATEMENT_REF_FROM_LINK (NextLink);
+ NextLink = GetNextNode (&StatementList->StatementList, NextLink);
+
+ RemoveEntryList (&StatementRef->Link);
+ FreePool (StatementRef);
+ }
+
+ return EFI_SUCCESS;
+}
--
2.21.0.windows.1
next prev parent reply other threads:[~2021-10-28 1:08 UTC|newest]
Thread overview: 6+ messages / expand[flat|nested] mbox.gz Atom feed top
2021-10-28 1:07 [PATCH RESEND 0/5] Implementation of EDKII Redfish Platform Config Protocol Abner Chang
2021-10-28 1:07 ` [PATCH RESEND 1/5] edk2-staging/RedfishPkg: EDKII_REDFISH_PLATFORM_CONFIG_PROTOCOL Abner Chang
2021-10-28 1:07 ` [PATCH RESEND 2/5] edk2-staging/RedfishPkg: HII utility helper library Abner Chang
2021-10-28 1:07 ` Abner Chang [this message]
2021-10-28 1:07 ` [PATCH RESEND 4/5] edk2-staging/RedfishPkg: Helper library of EDKII_REDFISH_PLATFORM_CONFIG_PROTOCOL Abner Chang
2021-10-28 1:07 ` [PATCH RESEND 5/5] edk2-staging/RedfishPkg: Enable Redfish Platform Config Protocol build process Abner Chang
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-list from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20211028010723.37316-4-abner.chang@hpe.com \
--to=devel@edk2.groups.io \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox