public inbox for devel@edk2.groups.io
 help / color / mirror / Atom feed
* [edk2-devel] [edk2-redfish-client][PATCH 1/2] RedfishClientPkg/Features: support Redfish Secure Boot
@ 2024-03-14 14:53 Nickle Wang via groups.io
  2024-03-14 19:38 ` Mike Maslenkin
  0 siblings, 1 reply; 5+ messages in thread
From: Nickle Wang via groups.io @ 2024-03-14 14:53 UTC (permalink / raw)
  To: devel; +Cc: Abner Chang, Igor Kulchytskyy, Nick Ramirez

Introduce SecureBoot driver to support
/redfish/v1/Systems/SYS/SecureBoot resource.

Signed-off-by: Nickle Wang <nicklew@nvidia.com>
Cc: Abner Chang <abner.chang@amd.com>
Cc: Igor Kulchytskyy <igork@ami.com>
Cc: Nick Ramirez <nramirez@nvidia.com>
---
 .../RedfishClientComponents.dsc.inc           |   2 +
 RedfishClientPkg/RedfishClientLibs.dsc.inc    |   4 +
 .../SecureBoot/v1_1_0/Dxe/SecureBootDxe.inf   |  60 ++
 .../v1_1_0/Common/SecureBootCommon.h          |  40 +
 .../v1_1_0/Common/SecureBootCommon.c          | 756 ++++++++++++++++
 .../SecureBoot/v1_1_0/Dxe/SecureBootDxe.c     | 808 ++++++++++++++++++
 RedfishClientPkg/RedfishClient.fdf.inc        |   1 +
 7 files changed, 1671 insertions(+)
 create mode 100644 RedfishClientPkg/Features/SecureBoot/v1_1_0/Dxe/SecureBootDxe.inf
 create mode 100644 RedfishClientPkg/Features/SecureBoot/v1_1_0/Common/SecureBootCommon.h
 create mode 100644 RedfishClientPkg/Features/SecureBoot/v1_1_0/Common/SecureBootCommon.c
 create mode 100644 RedfishClientPkg/Features/SecureBoot/v1_1_0/Dxe/SecureBootDxe.c

diff --git a/RedfishClientPkg/RedfishClientComponents.dsc.inc b/RedfishClientPkg/RedfishClientComponents.dsc.inc
index ae2a4b025..42fc0c299 100644
--- a/RedfishClientPkg/RedfishClientComponents.dsc.inc
+++ b/RedfishClientPkg/RedfishClientComponents.dsc.inc
@@ -34,6 +34,7 @@
   RedfishClientPkg/Features/Bios/v1_0_9/Dxe/BiosDxe.inf
   RedfishClientPkg/Features/BootOptionCollection/BootOptionCollectionDxe.inf
   RedfishClientPkg/Features/BootOption/v1_0_4/Dxe/BootOptionDxe.inf
+  RedfishClientPkg/Features/SecureBoot/v1_1_0/Dxe/SecureBootDxe.inf
 
   !include RedfishClientPkg/RedfishJsonStructureDxe.dsc.inc
 
@@ -47,3 +48,4 @@
   RedfishClientPkg/Converter/Bios/v1_0_9/RedfishBios_V1_0_9_Dxe.inf
   RedfishClientPkg/Converter/BootOptionCollection/RedfishBootOptionCollection_Dxe.inf
   RedfishClientPkg/Converter/BootOption/v1_0_4/RedfishBootOption_V1_0_4_Dxe.inf
+  RedfishClientPkg/Converter/SecureBoot/v1_1_0/RedfishSecureBoot_V1_1_0_Dxe.inf
diff --git a/RedfishClientPkg/RedfishClientLibs.dsc.inc b/RedfishClientPkg/RedfishClientLibs.dsc.inc
index 6599926ab..9126465df 100644
--- a/RedfishClientPkg/RedfishClientLibs.dsc.inc
+++ b/RedfishClientPkg/RedfishClientLibs.dsc.inc
@@ -25,6 +25,8 @@
   BiosV1_0_9Lib|RedfishClientPkg/ConverterLib/edk2library/Bios/v1_0_9/Lib.inf
   BootOptionCollectionLib|RedfishClientPkg/ConverterLib/edk2library/BootOptionCollection/Lib.inf
   BootOptionV1_0_4Lib|RedfishClientPkg/ConverterLib/edk2library/BootOption/v1_0_4/Lib.inf
+  SecureBootV1_1_0Lib|RedfishClientPkg/ConverterLib/edk2library/SecureBoot/v1_1_0/Lib.inf
+
   #
   # Above modules should be pulled in by build tool.
   #
@@ -42,3 +44,5 @@
   RedfishAddendumLib|RedfishClientPkg/Library/RedfishAddendumLib/RedfishAddendumLib.inf
   RedfishDebugLib|RedfishPkg/Library/RedfishDebugLib/RedfishDebugLib.inf
   RedfishHttpLib|RedfishPkg/Library/RedfishHttpLib/RedfishHttpLib.inf
+  SecureBootVariableLib|SecurityPkg/Library/SecureBootVariableLib/SecureBootVariableLib.inf
+  PlatformPKProtectionLib|SecurityPkg/Library/PlatformPKProtectionLibVarPolicy/PlatformPKProtectionLibVarPolicy.inf
diff --git a/RedfishClientPkg/Features/SecureBoot/v1_1_0/Dxe/SecureBootDxe.inf b/RedfishClientPkg/Features/SecureBoot/v1_1_0/Dxe/SecureBootDxe.inf
new file mode 100644
index 000000000..1ad8c623f
--- /dev/null
+++ b/RedfishClientPkg/Features/SecureBoot/v1_1_0/Dxe/SecureBootDxe.inf
@@ -0,0 +1,60 @@
+## @file
+#
+#  (C) Copyright 2020-2022 Hewlett Packard Enterprise Development LP<BR>
+#  Copyright (c) 2022-2024, NVIDIA CORPORATION & AFFILIATES. All rights reserved.
+#
+#  SPDX-License-Identifier: BSD-2-Clause-Patent
+#
+##
+
+
+[Defines]
+  INF_VERSION               = 0x00010005
+  BASE_NAME                 = SecureBootDxe
+  FILE_GUID                 = 5E4025F8-DA42-468A-853E-6A1091D35052
+  MODULE_TYPE               = DXE_DRIVER
+  VERSION_STRING            = 1.0
+  ENTRY_POINT               = RedfishResourceEntryPoint
+  UNLOAD_IMAGE              = RedfishResourceUnload
+
+[Packages]
+  MdePkg/MdePkg.dec
+  MdeModulePkg/MdeModulePkg.dec
+  SecurityPkg/SecurityPkg.dec
+  RedfishPkg/RedfishPkg.dec
+  RedfishClientPkg/RedfishClientPkg.dec
+
+[Sources]
+  ../Common/SecureBootCommon.h
+  ../Common/SecureBootCommon.c
+  SecureBootDxe.c
+
+[LibraryClasses]
+  BaseMemoryLib
+  DebugLib
+  EdkIIRedfishResourceConfigLib
+  RedfishFeatureUtilityLib
+  RedfishVersionLib
+  RedfishResourceIdentifyLib
+  SecureBootVariableLib
+  UefiLib
+  UefiDriverEntryPoint
+  RedfishAddendumLib
+  UefiRuntimeServicesTableLib
+
+[Protocols]
+  gEdkIIRedfishConfigHandlerProtocolGuid          ## PRODUCED
+  gEfiRestJsonStructureProtocolGuid               ## CONSUMED
+  gEdkIIRedfishResourceConfigProtocolGuid         ## PRODUCED
+  gEdkIIRedfishFeatureProtocolGuid                ## CONSUMED
+
+[Guids]
+  gEfiSecureBootEnableDisableGuid                 ## CONSUMED
+
+[Pcd]
+  gEfiRedfishClientPkgTokenSpaceGuid.PcdMaxRedfishSchemaStringSize
+  gEfiRedfishClientPkgTokenSpaceGuid.PcdMaxRedfishSchemaVersionSize
+  gEfiRedfishClientPkgTokenSpaceGuid.PcdRedfishSystemRebootRequired
+
+[Depex]
+  TRUE
diff --git a/RedfishClientPkg/Features/SecureBoot/v1_1_0/Common/SecureBootCommon.h b/RedfishClientPkg/Features/SecureBoot/v1_1_0/Common/SecureBootCommon.h
new file mode 100644
index 000000000..0d1824160
--- /dev/null
+++ b/RedfishClientPkg/Features/SecureBoot/v1_1_0/Common/SecureBootCommon.h
@@ -0,0 +1,40 @@
+/** @file
+
+  Redfish feature driver implementation - internal header file
+  (C) Copyright 2020-2022 Hewlett Packard Enterprise Development LP<BR>
+  Copyright (c) 2022-2024, NVIDIA CORPORATION & AFFILIATES. All rights reserved.
+
+  SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#ifndef EFI_REDFISH_SECUREBOOT_COMMON_H_
+#define EFI_REDFISH_SECUREBOOT_COMMON_H_
+
+#include <Guid/ImageAuthentication.h>
+#include <Guid/GlobalVariable.h>
+#include <Guid/AuthenticatedVariableFormat.h>
+#include <RedfishJsonStructure/SecureBoot/v1_1_0/EfiSecureBootV1_1_0.h>
+#include <RedfishResourceCommon.h>
+#include <UefiSecureBoot.h>
+#include <Library/UefiRuntimeServicesTableLib.h>
+#include <Library/SecureBootVariableLib.h>
+
+//
+// Schema information.
+//
+#define REDFISH_MANAGED_URI        L"Systems/{}/SecureBoot"
+#define REDFISH_DUMMY_CONFIG_LANG  L"Systems/{1}/SecureBoot"
+#define MAX_URI_LENGTH             256
+#define RESOURCE_SCHEMA            "SecureBoot"
+#define RESOURCE_SCHEMA_MAJOR      "1"
+#define RESOURCE_SCHEMA_MINOR      "1"
+#define RESOURCE_SCHEMA_ERRATA     "0"
+#define RESOURCE_SCHEMA_VERSION    "v1_1_0"
+#define SECURE_BOOT_SETUP_MODE     "SetupMode"
+#define SECURE_BOOT_USER_MODE      "UserMode"
+#define SECURE_BOOT_ENABLED        "Enabled"
+#define SECURE_BOOT_DISABLED       "Disabled"
+#define SECURE_BOOT_MODE_STR_LEN   16
+
+#endif
diff --git a/RedfishClientPkg/Features/SecureBoot/v1_1_0/Common/SecureBootCommon.c b/RedfishClientPkg/Features/SecureBoot/v1_1_0/Common/SecureBootCommon.c
new file mode 100644
index 000000000..56a45ee72
--- /dev/null
+++ b/RedfishClientPkg/Features/SecureBoot/v1_1_0/Common/SecureBootCommon.c
@@ -0,0 +1,756 @@
+/** @file
+  Redfish feature driver implementation - common functions
+
+  (C) Copyright 2020-2022 Hewlett Packard Enterprise Development LP<BR>
+  Copyright (c) 2023-2024, NVIDIA CORPORATION & AFFILIATES. All rights reserved.
+
+  SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include "SecureBootCommon.h"
+
+CHAR8  SecureBootEmptyJson[] = "{\"@odata.id\": \"\", \"@odata.type\": \"#SecureBoot.v1_1_0.SecureBoot\", \"Id\": \"\", \"Name\": \"\", \"Attributes\":{}}";
+
+REDFISH_RESOURCE_COMMON_PRIVATE  *mRedfishResourcePrivate                                  = NULL;
+EFI_HANDLE                       mRedfishResourceConfigProtocolHandle                      = NULL;
+CHAR16                           *mSecureBootSupportedAttributes[SECURE_BOOT_MODE_STR_LEN] = {
+  L"SecureBootCurrentBoot",
+  L"SecureBootEnable",
+  L"SecureBootMode"
+};
+
+/**
+  Read EFI_SECURE_BOOT_ENABLE_NAME variable and return its value to caller.
+
+  @retval BOOLEAN    TRUE when EFI_SECURE_BOOT_ENABLE_NAME value is SECURE_BOOT_ENABLE
+                     FALSE when EFI_SECURE_BOOT_ENABLE_NAME value is SECURE_BOOT_DISABLE
+**/
+BOOLEAN
+RedfishReadSecureBootEnable (
+  VOID
+  )
+{
+  UINT8    *Buffer;
+  BOOLEAN  SecureBootEnableValue;
+
+  Buffer                = NULL;
+  SecureBootEnableValue = FALSE;
+
+  GetVariable2 (
+    EFI_SECURE_BOOT_ENABLE_NAME,
+    &gEfiSecureBootEnableDisableGuid,
+    (VOID **)&Buffer,
+    NULL
+    );
+
+  if (Buffer != NULL) {
+    if (*Buffer == SECURE_BOOT_ENABLE) {
+      SecureBootEnableValue = TRUE;
+    }
+
+    FreePool (Buffer);
+  }
+
+  return SecureBootEnableValue;
+}
+
+/**
+  Write EFI_SECURE_BOOT_ENABLE_NAME variable with given value.
+
+  @param[in]   SecureBootEnableValue    Value to write. TRUE is SECURE_BOOT_ENABLE.
+                                        FALSE is SECURE_BOOT_DISABLE.
+
+  @retval EFI_SUCCESS              Write value successfully.
+  @retval Others                   Some error happened.
+**/
+EFI_STATUS
+RedfishWriteSecureBootEnable (
+  BOOLEAN  SecureBootEnableValue
+  )
+{
+  EFI_STATUS  Status;
+  UINT8       VarValue;
+
+  VarValue = (SecureBootEnableValue ? SECURE_BOOT_ENABLE : SECURE_BOOT_DISABLE);
+  Status   = gRT->SetVariable (
+                    EFI_SECURE_BOOT_ENABLE_NAME,
+                    &gEfiSecureBootEnableDisableGuid,
+                    EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS,
+                    sizeof (VarValue),
+                    &VarValue
+                    );
+
+  return Status;
+}
+
+/**
+  Consume Redfish resource in given Json data.
+
+  @param[in]   This                Pointer to REDFISH_RESOURCE_COMMON_PRIVATE instance.
+  @param[in]   Json                The JSON to consume.
+  @param[in]   HeaderEtag          The Etag string returned in HTTP header.
+
+  @retval EFI_SUCCESS              Consume Redfish attribute successfully.
+  @retval Others                   Some error happened.
+
+**/
+EFI_STATUS
+RedfishConsumeResourceCommon (
+  IN  REDFISH_RESOURCE_COMMON_PRIVATE  *Private,
+  IN  CHAR8                            *Json,
+  IN  CHAR8                            *HeaderEtag OPTIONAL
+  )
+{
+  EFI_STATUS                        Status;
+  EFI_REDFISH_SECUREBOOT_V1_1_0     *SecureBoot;
+  EFI_REDFISH_SECUREBOOT_V1_1_0_CS  *SecureBootCs;
+  BOOLEAN                           SecureBootEnableDisable;
+
+  if ((Private == NULL) || IS_EMPTY_STRING (Json)) {
+    return EFI_INVALID_PARAMETER;
+  }
+
+  SecureBoot              = NULL;
+  SecureBootCs            = NULL;
+  SecureBootEnableDisable = RedfishReadSecureBootEnable ();
+
+  Status = Private->JsonStructProtocol->ToStructure (
+                                          Private->JsonStructProtocol,
+                                          NULL,
+                                          Json,
+                                          (EFI_REST_JSON_STRUCTURE_HEADER **)&SecureBoot
+                                          );
+  if (EFI_ERROR (Status)) {
+    DEBUG ((DEBUG_ERROR, "%a: ToStructure() failed: %r\n", __func__, Status));
+    return Status;
+  }
+
+  SecureBootCs = SecureBoot->SecureBoot;
+
+  //
+  // Check ETAG to see if we need to consume it
+  //
+  if (CheckEtag (Private->Uri, HeaderEtag, SecureBootCs->odata_etag)) {
+    //
+    // No change
+    //
+    DEBUG ((REDFISH_DEBUG_TRACE, "%a: ETAG: %s has no change, ignore consume action\n", __func__, Private->Uri));
+    Status = EFI_ALREADY_STARTED;
+    goto ON_RELEASE;
+  }
+
+  //
+  // Secure boot enable
+  //
+  if (SecureBootCs->SecureBootEnable != NULL) {
+    if (SecureBootEnableDisable != *SecureBootCs->SecureBootEnable) {
+      //
+      // Write value to "SecureBootEnable" variable. AuthVariableLib will enable or disable secure boot
+      // based on "SecureBootEnable" value.
+      //
+      Status = RedfishWriteSecureBootEnable (*SecureBootCs->SecureBootEnable);
+      if (EFI_ERROR (Status)) {
+        DEBUG ((DEBUG_ERROR, "%a: write secure boot enable disable failed: %r\n", __func__, Status));
+      } else {
+        REDFISH_ENABLE_SYSTEM_REBOOT ();
+      }
+    } else {
+      DEBUG ((REDFISH_DEBUG_TRACE, "%a: secure boot mode is not changed\n", __func__));
+    }
+  }
+
+ON_RELEASE:
+
+  //
+  // Release resource.
+  //
+  Private->JsonStructProtocol->DestoryStructure (
+                                 Private->JsonStructProtocol,
+                                 (EFI_REST_JSON_STRUCTURE_HEADER *)SecureBoot
+                                 );
+
+  return EFI_SUCCESS;
+}
+
+/**
+  Provision Redfish resource. This function reads secure boot variable and convert it
+  to Redfish attribute.
+
+  @param[in]   JsonStructProtocol  Pointer to Json structure protocol.
+  @param[in]   InputJson           Jason data on input.
+  @param[in]   ResourceId          Resource ID. This is optional.
+  @param[in]   ConfigureLang       Configure language for this Redfish resource.
+  @param[in]   ProvisionMode       TRUE when this is to provision Redfish attribute to
+                                   Redfish service. FALSE is to update Redfish attribute
+                                   to Redfish service.
+  @param[out]  ResultJson          Json data on output.
+
+  @retval EFI_SUCCESS              Provision Redfish attribute successfully.
+  @retval Others                   Some error happened.
+
+**/
+EFI_STATUS
+ProvisioningSecureBootProperties (
+  IN  EFI_REST_JSON_STRUCTURE_PROTOCOL  *JsonStructProtocol,
+  IN  CHAR8                             *InputJson,
+  IN  CHAR8                             *ResourceId OPTIONAL,
+  IN  EFI_STRING                        ConfigureLang,
+  IN  BOOLEAN                           ProvisionMode,
+  OUT CHAR8                             **ResultJson
+  )
+{
+  EFI_REDFISH_SECUREBOOT_V1_1_0     *SecureBoot;
+  EFI_REDFISH_SECUREBOOT_V1_1_0_CS  *SecureBootCs;
+  EFI_STATUS                        Status;
+  BOOLEAN                           PropertyChanged;
+  CHAR8                             *AsciiStringValue;
+  INT32                             *IntegerValue;
+  UINT8                             SetupMode;
+  BOOLEAN                           SecureBootEnabled;
+  BOOLEAN                           SecureBootEnableDisable;
+
+  if ((JsonStructProtocol == NULL) || (ResultJson == NULL) || IS_EMPTY_STRING (InputJson) || IS_EMPTY_STRING (ConfigureLang)) {
+    return EFI_INVALID_PARAMETER;
+  }
+
+  DEBUG ((REDFISH_DEBUG_TRACE, "%a provision for %s with: %s\n", __func__, ConfigureLang, (ProvisionMode ? L"Provision resource" : L"Update resource")));
+
+  *ResultJson             = NULL;
+  PropertyChanged         = FALSE;
+  AsciiStringValue        = NULL;
+  SecureBootEnableDisable = RedfishReadSecureBootEnable ();
+  SecureBootEnabled       = IsSecureBootEnabled ();
+
+  SecureBoot = NULL;
+  Status     = JsonStructProtocol->ToStructure (
+                                     JsonStructProtocol,
+                                     NULL,
+                                     InputJson,
+                                     (EFI_REST_JSON_STRUCTURE_HEADER **)&SecureBoot
+                                     );
+  if (EFI_ERROR (Status)) {
+    DEBUG ((DEBUG_ERROR, "%a: ToStructure failure: %r\n", __func__, Status));
+    return Status;
+  }
+
+  SecureBootCs = SecureBoot->SecureBoot;
+
+  //
+  // ID
+  //
+  if (SecureBootCs->Id != NULL) {
+    SecureBootCs->Id = NULL;
+  }
+
+  //
+  // Name
+  //
+  if (SecureBootCs->Name != NULL) {
+    SecureBootCs->Name = NULL;
+  }
+
+  //
+  // Secure boot variables that we will handle here
+  //
+  // EFI_SETUP_MODE_NAME (gEfiGlobalVariableGuid)
+  // EFI_SECURE_BOOT_MODE_NAME (gEfiGlobalVariableGuid)
+  // EFI_SECURE_BOOT_ENABLE_NAME (gEfiSecureBootEnableDisableGuid)
+  //
+
+  //
+  // Current Boot
+  //
+  if (PropertyChecker (SecureBootCs->SecureBootCurrentBoot, ProvisionMode)) {
+    AsciiStringValue = AllocateZeroPool (SECURE_BOOT_MODE_STR_LEN * sizeof (CHAR8));
+    if (AsciiStringValue != NULL) {
+      AsciiSPrint (AsciiStringValue, SECURE_BOOT_MODE_STR_LEN, "%a", (SecureBootEnabled ? SECURE_BOOT_ENABLED : SECURE_BOOT_DISABLED));
+      if (ProvisionMode || (AsciiStrCmp (SecureBootCs->SecureBootCurrentBoot, AsciiStringValue) != 0)) {
+        SecureBootCs->SecureBootCurrentBoot = AsciiStringValue;
+        PropertyChanged                     = TRUE;
+      }
+    } else {
+      DEBUG ((DEBUG_ERROR, "%a: out of resource\n", __func__));
+    }
+  }
+
+  //
+  // Secure boot enable
+  //
+  if (PropertyChecker (SecureBootCs->SecureBootEnable, ProvisionMode)) {
+    if (ProvisionMode || (*SecureBootCs->SecureBootEnable != SecureBootEnableDisable)) {
+      IntegerValue = AllocatePool (sizeof (*IntegerValue));
+      if (IntegerValue != NULL) {
+        *IntegerValue                  = (SecureBootEnableDisable ? 0x01 : 0x00);
+        SecureBootCs->SecureBootEnable = IntegerValue;
+        PropertyChanged                = TRUE;
+      } else {
+        DEBUG ((DEBUG_ERROR, "%a: out of resource\n", __func__));
+      }
+    }
+  }
+
+  //
+  // Secure boot mode
+  //
+  if (PropertyChecker (SecureBootCs->SecureBootMode, ProvisionMode)) {
+    Status = GetSetupMode (&SetupMode);
+    if (!EFI_ERROR (Status)) {
+      AsciiStringValue = AllocateZeroPool (SECURE_BOOT_MODE_STR_LEN *sizeof (CHAR8));
+      if (AsciiStringValue != NULL) {
+        AsciiSPrint (AsciiStringValue, SECURE_BOOT_MODE_STR_LEN *sizeof (CHAR8), "%a", (SetupMode == USER_MODE ? SECURE_BOOT_USER_MODE : SECURE_BOOT_SETUP_MODE));
+        if (ProvisionMode || (AsciiStrCmp (SecureBootCs->SecureBootMode, AsciiStringValue) != 0)) {
+          SecureBootCs->SecureBootMode = AsciiStringValue;
+          PropertyChanged              = TRUE;
+        }
+      }
+    } else {
+      DEBUG ((DEBUG_ERROR, "%a: cannot read setup mode: %r\n", __func__, Status));
+    }
+  }
+
+  //
+  // Convert C structure back to JSON text.
+  //
+  Status = JsonStructProtocol->ToJson (
+                                 JsonStructProtocol,
+                                 (EFI_REST_JSON_STRUCTURE_HEADER *)SecureBoot,
+                                 ResultJson
+                                 );
+  if (EFI_ERROR (Status)) {
+    DEBUG ((DEBUG_ERROR, "%a: ToJson() failed: %r\n", __func__, Status));
+    return Status;
+  }
+
+  //
+  // Release resource.
+  //
+  JsonStructProtocol->DestoryStructure (
+                        JsonStructProtocol,
+                        (EFI_REST_JSON_STRUCTURE_HEADER *)SecureBoot
+                        );
+
+  return (PropertyChanged ? EFI_SUCCESS : EFI_NOT_FOUND);
+}
+
+/**
+  Provision Redfish resource and upload data to Redfish service. This function
+  checks OEM data and platform addendum data before sending data to Redfish service.
+
+  @param[in]   Private   Pointer to private data.
+
+  @retval EFI_SUCCESS              Provision Redfish resource successfully.
+  @retval Others                   Some error happened.
+
+**/
+EFI_STATUS
+ProvisioningSecureBootResource (
+  IN  REDFISH_RESOURCE_COMMON_PRIVATE  *Private
+  )
+{
+  EFI_STATUS        Status;
+  CHAR8             *Json;
+  CHAR8             *JsonWithAddendum;
+  REDFISH_RESPONSE  Response;
+
+  if (Private == NULL) {
+    return EFI_INVALID_PARAMETER;
+  }
+
+  ZeroMem (&Response, sizeof (REDFISH_RESPONSE));
+  Json = NULL;
+
+  Status = ProvisioningSecureBootProperties (
+             Private->JsonStructProtocol,
+             SecureBootEmptyJson,
+             NULL,
+             REDFISH_DUMMY_CONFIG_LANG,
+             TRUE,
+             &Json
+             );
+  if (EFI_ERROR (Status)) {
+    if (Status == EFI_NOT_FOUND) {
+      DEBUG ((REDFISH_DEBUG_TRACE, "%a: provisioning existing resource for %s ignored. Nothing changed\n", __func__, REDFISH_DUMMY_CONFIG_LANG));
+      Status = EFI_SUCCESS;
+    } else {
+      DEBUG ((DEBUG_ERROR, "%a: provisioning existing resource for %s failed: %r\n", __func__, REDFISH_DUMMY_CONFIG_LANG, Status));
+    }
+
+    goto ON_RELEASE;
+  }
+
+  //
+  // Check and see if platform has OEM data or not
+  //
+  Status = RedfishGetOemData (
+             Private->Uri,
+             RESOURCE_SCHEMA,
+             RESOURCE_SCHEMA_VERSION,
+             Json,
+             &JsonWithAddendum
+             );
+  if (!EFI_ERROR (Status) && (JsonWithAddendum != NULL)) {
+    FreePool (Json);
+    Json             = JsonWithAddendum;
+    JsonWithAddendum = NULL;
+  }
+
+  //
+  // Check and see if platform has addendum data or not
+  //
+  Status = RedfishGetAddendumData (
+             Private->Uri,
+             RESOURCE_SCHEMA,
+             RESOURCE_SCHEMA_VERSION,
+             Json,
+             &JsonWithAddendum
+             );
+  if (!EFI_ERROR (Status) && (JsonWithAddendum != NULL)) {
+    FreePool (Json);
+    Json             = JsonWithAddendum;
+    JsonWithAddendum = NULL;
+  }
+
+  DEBUG ((REDFISH_DEBUG_TRACE, "%a: provisioning existing resource for %s\n", __func__, REDFISH_DUMMY_CONFIG_LANG));
+
+  //
+  // PATCH back to instance
+  //
+  Status = RedfishHttpPatchResource (Private->RedfishService, Private->Uri, Json, &Response);
+  if (EFI_ERROR (Status)) {
+    DEBUG ((DEBUG_ERROR, "%a: patch resource for %s failed: %r\n", __func__, REDFISH_DUMMY_CONFIG_LANG, Status));
+  }
+
+ON_RELEASE:
+
+  if (Json != NULL) {
+    FreePool (Json);
+  }
+
+  RedfishHttpFreeResponse (&Response);
+
+  return Status;
+}
+
+/**
+  Provisioning redfish resource to Redfish service.
+
+  @param[in]   Private             Pointer to private data.
+  @param[in]   ResourceExist       TRUE if resource exists, PUT method will be used.
+                                   FALSE if resource does not exist POST method is used.
+
+  @retval EFI_SUCCESS              Provision resource successfully.
+  @retval Others                   Some error happened.
+
+**/
+EFI_STATUS
+RedfishProvisioningResourceCommon (
+  IN     REDFISH_RESOURCE_COMMON_PRIVATE  *Private,
+  IN     BOOLEAN                          ResourceExist
+  )
+{
+  if (Private == NULL) {
+    return EFI_INVALID_PARAMETER;
+  }
+
+  return ProvisioningSecureBootResource (Private);
+}
+
+/**
+  Check resource from given Json data.
+
+  @param[in]   This                Pointer to REDFISH_RESOURCE_COMMON_PRIVATE instance.
+  @param[in]   Json                The JSON data to check.
+  @param[in]   HeaderEtag          The Etag string returned in HTTP header.
+
+  @retval EFI_SUCCESS              Check resource successfully.
+  @retval Others                   Some error happened.
+
+**/
+EFI_STATUS
+RedfishCheckResourceCommon (
+  IN     REDFISH_RESOURCE_COMMON_PRIVATE  *Private,
+  IN     CHAR8                            *Json,
+  IN     CHAR8                            *HeaderEtag OPTIONAL
+  )
+{
+  UINTN       Index;
+  EFI_STATUS  Status;
+  UINTN       Count;
+  EFI_STRING  Property;
+
+  if ((Private == NULL) || IS_EMPTY_STRING (Json)) {
+    return EFI_INVALID_PARAMETER;
+  }
+
+  //
+  // Check ETAG to see if we need to check it
+  //
+  if (CheckEtag (Private->Uri, HeaderEtag, NULL)) {
+    //
+    // No change
+    //
+    DEBUG ((REDFISH_DEBUG_TRACE, "%a: ETAG: %s has no change, ignore check action\n", __func__, Private->Uri));
+    return EFI_SUCCESS;
+  }
+
+  Count = sizeof (mSecureBootSupportedAttributes) / sizeof (mSecureBootSupportedAttributes[0]);
+  if (Count == 0) {
+    return EFI_UNSUPPORTED;
+  }
+
+  Status = EFI_SUCCESS;
+  for (Index = 0; Index < Count; Index++) {
+    Property = mSecureBootSupportedAttributes[Index];
+    if (Property == NULL) {
+      continue;
+    }
+
+    DEBUG ((REDFISH_DEBUG_TRACE, "%a: [%d] check attribute for: %s\n", __func__, Index, Property));
+    if (!MatchPropertyWithJsonContext (Property, Json)) {
+      DEBUG ((REDFISH_DEBUG_TRACE, "%a: property is missing: %s\n", __func__, Property));
+      Status = EFI_NOT_FOUND;
+    }
+  }
+
+  return Status;
+}
+
+/**
+  Update resource to Redfish service.
+
+  @param[in]   Private             Pointer to REDFISH_RESOURCE_COMMON_PRIVATE instance.
+  @param[in]   Json                The JSON data to be updated.
+
+  @retval EFI_SUCCESS              Update resource successfully.
+  @retval Others                   Some error happened.
+
+**/
+EFI_STATUS
+RedfishUpdateResourceCommon (
+  IN     REDFISH_RESOURCE_COMMON_PRIVATE  *Private,
+  IN     CHAR8                            *InputJson
+  )
+{
+  EFI_STATUS        Status;
+  CHAR8             *Json;
+  CHAR8             *JsonWithAddendum;
+  REDFISH_RESPONSE  Response;
+
+  if ((Private == NULL) || IS_EMPTY_STRING (InputJson)) {
+    return EFI_INVALID_PARAMETER;
+  }
+
+  ZeroMem (&Response, sizeof (REDFISH_RESPONSE));
+  Json = NULL;
+
+  Status = ProvisioningSecureBootProperties (
+             Private->JsonStructProtocol,
+             SecureBootEmptyJson,
+             NULL,
+             REDFISH_DUMMY_CONFIG_LANG,
+             TRUE,
+             &Json
+             );
+  if (EFI_ERROR (Status)) {
+    if (Status == EFI_NOT_FOUND) {
+      DEBUG ((REDFISH_DEBUG_TRACE, "%a: update resource for %s ignored. Nothing changed\n", __func__, REDFISH_DUMMY_CONFIG_LANG));
+      Status = EFI_SUCCESS;
+    } else {
+      DEBUG ((DEBUG_ERROR, "%a: update resource for %s failed: %r\n", __func__, REDFISH_DUMMY_CONFIG_LANG, Status));
+    }
+
+    goto ON_RELEASE;
+  }
+
+  //
+  // Check and see if platform has OEM data or not
+  //
+  Status = RedfishGetOemData (
+             Private->Uri,
+             RESOURCE_SCHEMA,
+             RESOURCE_SCHEMA_VERSION,
+             Json,
+             &JsonWithAddendum
+             );
+  if (!EFI_ERROR (Status) && (JsonWithAddendum != NULL)) {
+    FreePool (Json);
+    Json             = JsonWithAddendum;
+    JsonWithAddendum = NULL;
+  }
+
+  //
+  // Check and see if platform has addendum data or not
+  //
+  Status = RedfishGetAddendumData (
+             Private->Uri,
+             RESOURCE_SCHEMA,
+             RESOURCE_SCHEMA_VERSION,
+             Json,
+             &JsonWithAddendum
+             );
+  if (!EFI_ERROR (Status) && (JsonWithAddendum != NULL)) {
+    FreePool (Json);
+    Json             = JsonWithAddendum;
+    JsonWithAddendum = NULL;
+  }
+
+  DEBUG ((REDFISH_DEBUG_TRACE, "%a: update resource for %s\n", __func__, REDFISH_DUMMY_CONFIG_LANG));
+
+  //
+  // PATCH back to instance
+  //
+  Status = RedfishHttpPatchResource (Private->RedfishService, Private->Uri, Json, &Response);
+  if (EFI_ERROR (Status)) {
+    DEBUG ((DEBUG_ERROR, "%a: patch resource for %s failed: %r\n", __func__, REDFISH_DUMMY_CONFIG_LANG, Status));
+  }
+
+ON_RELEASE:
+
+  if (Json != NULL) {
+    FreePool (Json);
+  }
+
+  RedfishHttpFreeResponse (&Response);
+
+  return Status;
+}
+
+/**
+  Identify resource in given Json data.
+
+  @param[in]   Private             Pointer to REDFISH_RESOURCE_COMMON_PRIVATE instance.
+  @param[in]   Json                The JSON to be identified.
+
+  @retval EFI_SUCCESS              Identify resource successfully.
+  @retval Others                   Some error happened.
+
+**/
+EFI_STATUS
+RedfishIdentifyResourceCommon (
+  IN     REDFISH_RESOURCE_COMMON_PRIVATE  *Private,
+  IN     CHAR8                            *Json
+  )
+{
+  BOOLEAN  Supported;
+
+  Supported = RedfishIdentifyResource (Private->Uri, Private->Json);
+  if (Supported) {
+    //
+    // Keep URI and ConfigLang mapping
+    //
+    RedfishSetRedfishUri (REDFISH_DUMMY_CONFIG_LANG, Private->Uri);
+  }
+
+  return (Supported ? EFI_SUCCESS : EFI_UNSUPPORTED);
+}
+
+/**
+  Handle Redfish resource in Uri.
+
+  @param[in]   Private             Pointer to REDFISH_RESOURCE_COMMON_PRIVATE instance.
+  @param[in]   Uri                 URI to Redfish resource that we like to process.
+
+  @retval EFI_SUCCESS              Handle resource successfully.
+  @retval Others                   Some error happened.
+
+**/
+EFI_STATUS
+HandleResource (
+  IN  REDFISH_RESOURCE_COMMON_PRIVATE  *Private,
+  IN  EFI_STRING                       Uri
+  )
+{
+  EFI_STATUS           Status;
+  REDFISH_SCHEMA_INFO  SchemaInfo;
+  EFI_STRING           ConfigLang;
+
+  if ((Private == NULL) || IS_EMPTY_STRING (Uri)) {
+    return EFI_INVALID_PARAMETER;
+  }
+
+  //
+  // Resource match
+  //
+
+  DEBUG ((REDFISH_DEBUG_TRACE, "%a: process resource for: %s\n", __func__, Uri));
+
+  Status = GetRedfishSchemaInfo (Private->RedfishService, Private->JsonStructProtocol, Uri, NULL, &SchemaInfo);
+  if (EFI_ERROR (Status)) {
+    DEBUG ((DEBUG_ERROR, "%a: failed to get schema information from: %s %r\n", __func__, Uri, Status));
+    return Status;
+  }
+
+  //
+  // Check and see if this is target resource that we want to handle.
+  // Some resource is handled by other provider so we have to make sure this first.
+  //
+  DEBUG ((REDFISH_DEBUG_TRACE, "%a: Identify for %s\n", __func__, Uri));
+  ConfigLang = RedfishGetConfigLanguage (Uri);
+  if (ConfigLang == NULL) {
+    Status = EdkIIRedfishResourceConfigIdentify (&SchemaInfo, Uri, NULL, Private->InformationExchange);
+    if (EFI_ERROR (Status)) {
+      if (Status == EFI_UNSUPPORTED) {
+        DEBUG ((REDFISH_DEBUG_TRACE, "%a: \"%s\" is not handled by us\n", __func__, Uri));
+        return EFI_SUCCESS;
+      } else if (Status == EFI_NOT_FOUND) {
+        DEBUG ((REDFISH_DEBUG_TRACE, "%a: \"%s\" has nothing to handle\n", __func__, Uri));
+        return EFI_SUCCESS;
+      }
+
+      DEBUG ((DEBUG_ERROR, "%a: fail to identify resource: \"%s\": %r\n", __func__, Uri, Status));
+      return Status;
+    }
+  } else {
+    DEBUG ((REDFISH_DEBUG_TRACE, "%a: history record found: %s\n", __func__, ConfigLang));
+    FreePool (ConfigLang);
+  }
+
+  //
+  // Check and see if target property exist or not even when collection member exists.
+  // If not, we sill do provision.
+  //
+  DEBUG ((REDFISH_DEBUG_TRACE, "%a Check for %s\n", __func__, Uri));
+  Status = EdkIIRedfishResourceConfigCheck (&SchemaInfo, Uri, NULL);
+  if (EFI_ERROR (Status)) {
+    if (Status == EFI_UNSUPPORTED) {
+      DEBUG ((REDFISH_DEBUG_TRACE, "%a: \"%s\" is not handled by us\n", __func__, Uri));
+      return EFI_SUCCESS;
+    }
+
+    //
+    // The target property does not exist, do the provision to create property.
+    //
+    DEBUG ((REDFISH_DEBUG_TRACE, "%a provision for %s\n", __func__, Uri));
+    Status = EdkIIRedfishResourceConfigProvisioning (&SchemaInfo, Uri, NULL, Private->InformationExchange, FALSE);
+    if (EFI_ERROR (Status)) {
+      DEBUG ((DEBUG_ERROR, "%a: failed to provision with GET mode: %r\n", __func__, Status));
+    }
+
+    DEBUG ((REDFISH_DEBUG_TRACE, "%a: process resource for: %s finished\n", __func__, Uri));
+
+    return Status;
+  }
+
+  //
+  // Consume first.
+  //
+  DEBUG ((REDFISH_DEBUG_TRACE, "%a consume for %s\n", __func__, Uri));
+  Status = EdkIIRedfishResourceConfigConsume (&SchemaInfo, Uri, NULL);
+  if (EFI_ERROR (Status)) {
+    DEBUG ((DEBUG_ERROR, "%a: failed to consume resource for: %s: %r\n", __func__, Uri, Status));
+  }
+
+  //
+  // Patch.
+  //
+  DEBUG ((REDFISH_DEBUG_TRACE, "%a update for %s\n", __func__, Uri));
+  Status = EdkIIRedfishResourceConfigUpdate (&SchemaInfo, Uri, NULL);
+  if (EFI_ERROR (Status)) {
+    DEBUG ((DEBUG_ERROR, "%a: failed to update resource for: %s: %r\n", __func__, Uri, Status));
+  }
+
+  DEBUG ((REDFISH_DEBUG_TRACE, "%a: process resource for: %s finished\n", __func__, Uri));
+
+  return Status;
+}
diff --git a/RedfishClientPkg/Features/SecureBoot/v1_1_0/Dxe/SecureBootDxe.c b/RedfishClientPkg/Features/SecureBoot/v1_1_0/Dxe/SecureBootDxe.c
new file mode 100644
index 000000000..a0f4f3d14
--- /dev/null
+++ b/RedfishClientPkg/Features/SecureBoot/v1_1_0/Dxe/SecureBootDxe.c
@@ -0,0 +1,808 @@
+/** @file
+  Redfish feature driver implementation - SecureBoot
+
+  (C) Copyright 2020-2022 Hewlett Packard Enterprise Development LP<BR>
+  Copyright (c) 2023, NVIDIA CORPORATION & AFFILIATES. All rights reserved.
+
+  SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include "../Common/SecureBootCommon.h"
+
+extern REDFISH_RESOURCE_COMMON_PRIVATE  *mRedfishResourcePrivate;
+extern EFI_HANDLE                       mRedfishResourceConfigProtocolHandle;
+
+EFI_STATUS
+HandleResource (
+  IN  REDFISH_RESOURCE_COMMON_PRIVATE  *Private,
+  IN  EFI_STRING                       Uri
+  );
+
+/**
+  Provisioning redfish resource by given URI.
+
+  @param[in]   This                Pointer to EFI_HP_REDFISH_HII_PROTOCOL instance.
+  @param[in]   Uri                 Target URI to create resource.
+  @param[in]   PostMode            TRUE if the resource does not exist, post method is used.
+                                   FALSE if the resource exist but property is missing, put method is used.
+
+  @retval EFI_SUCCESS              Value is returned successfully.
+  @retval Others                   Some error happened.
+
+**/
+EFI_STATUS
+EFIAPI
+RedfishResourceProvisioningResource (
+  IN     EDKII_REDFISH_RESOURCE_CONFIG_PROTOCOL  *This,
+  IN     EFI_STRING                              Uri,
+  IN     BOOLEAN                                 PostMode
+  )
+{
+  REDFISH_RESOURCE_COMMON_PRIVATE  *Private;
+  EFI_STATUS                       Status;
+  REDFISH_RESPONSE                 Response;
+
+  if ((This == NULL) || IS_EMPTY_STRING (Uri)) {
+    return EFI_INVALID_PARAMETER;
+  }
+
+  DEBUG ((REDFISH_DEBUG_TRACE, "%a: provisioning in %s mode\n", __func__, (PostMode ? L"POST" : L"PATCH")));
+
+  ZeroMem (&Response, sizeof (REDFISH_RESPONSE));
+  Private = REDFISH_RESOURCE_COMMON_PRIVATE_DATA_FROM_RESOURCE_PROTOCOL (This);
+
+  if (Private->RedfishService == NULL) {
+    return EFI_NOT_READY;
+  }
+
+  Status = RedfishHttpGetResource (Private->RedfishService, Uri, NULL, &Response, TRUE);
+  if (EFI_ERROR (Status)) {
+    DEBUG ((DEBUG_ERROR, "%a: get resource from: %s failed\n", __func__, Uri));
+    return Status;
+  }
+
+  Private->Uri     = Uri;
+  Private->Payload = Response.Payload;
+  ASSERT (Private->Payload != NULL);
+
+  Status = RedfishProvisioningResourceCommon (Private, !PostMode);
+  if (EFI_ERROR (Status)) {
+    DEBUG ((DEBUG_ERROR, "%a: failed to provision resource to: %s: %r\n", __func__, Uri, Status));
+  } else {
+    //
+    // Get latest ETag on URI and keep it in variable.
+    //
+    SetEtagFromUri (Private->RedfishService, Private->Uri, TRUE);
+  }
+
+  //
+  // Release resource
+  //
+  RedfishHttpFreeResponse (&Response);
+  Private->Payload = NULL;
+
+  return Status;
+}
+
+/**
+  Consume resource from given URI.
+
+  @param[in]   This                Pointer to EFI_HP_REDFISH_HII_PROTOCOL instance.
+  @param[in]   Uri                 The target URI to consume.
+
+  @retval EFI_SUCCESS              Value is returned successfully.
+  @retval Others                   Some error happened.
+
+**/
+EFI_STATUS
+EFIAPI
+RedfishResourceConsumeResource (
+  IN     EDKII_REDFISH_RESOURCE_CONFIG_PROTOCOL  *This,
+  IN     EFI_STRING                              Uri
+  )
+{
+  REDFISH_RESOURCE_COMMON_PRIVATE  *Private;
+  EFI_STATUS                       Status;
+  REDFISH_RESPONSE                 Response;
+  EFI_STRING                       PendingSettingUri;
+  REDFISH_RESPONSE                 PendingSettingResponse;
+  REDFISH_RESPONSE                 *ExpectedResponse;
+  CHAR8                            *Etag;
+
+  if ((This == NULL) || IS_EMPTY_STRING (Uri)) {
+    return EFI_INVALID_PARAMETER;
+  }
+
+  ZeroMem (&Response, sizeof (REDFISH_RESPONSE));
+  ZeroMem (&PendingSettingResponse, sizeof (REDFISH_RESPONSE));
+  Private = REDFISH_RESOURCE_COMMON_PRIVATE_DATA_FROM_RESOURCE_PROTOCOL (This);
+
+  if (Private->RedfishService == NULL) {
+    return EFI_NOT_READY;
+  }
+
+  Status = RedfishHttpGetResource (Private->RedfishService, Uri, NULL, &Response, TRUE);
+  if (EFI_ERROR (Status)) {
+    DEBUG ((DEBUG_ERROR, "%a: get resource from: %s failed\n", __func__, Uri));
+    return Status;
+  }
+
+  //
+  // Check and see if "@Redfish.Settings" exist or not.
+  //
+  PendingSettingUri = NULL;
+  Status            = GetPendingSettings (
+                        Private->RedfishService,
+                        Response.Payload,
+                        &PendingSettingResponse,
+                        &PendingSettingUri
+                        );
+  if (!EFI_ERROR (Status)) {
+    DEBUG ((REDFISH_DEBUG_TRACE, "%a: @Redfish.Settings found: %s\n", __func__, PendingSettingUri));
+    Private->Uri     = PendingSettingUri;
+    ExpectedResponse = &PendingSettingResponse;
+  } else {
+    Private->Uri     = Uri;
+    ExpectedResponse = &Response;
+  }
+
+  Private->Payload = ExpectedResponse->Payload;
+  ASSERT (Private->Payload != NULL);
+
+  Private->Json = JsonDumpString (RedfishJsonInPayload (Private->Payload), EDKII_JSON_COMPACT);
+  ASSERT (Private->Json != NULL);
+
+  //
+  // Searching for etag in HTTP response header
+  //
+  Etag   = NULL;
+  Status = GetHttpResponseEtag (ExpectedResponse, &Etag);
+  if (EFI_ERROR (Status)) {
+    DEBUG ((DEBUG_ERROR, "%a: failed to get ETag from HTTP header\n", __func__));
+  }
+
+  Status = RedfishConsumeResourceCommon (Private, Private->Json, Etag);
+  if (EFI_ERROR (Status)) {
+    DEBUG ((DEBUG_ERROR, "%a: failed to consume resource from: %s: %r\n", __func__, Private->Uri, Status));
+  }
+
+  //
+  // Release resource
+  //
+  RedfishHttpFreeResponse (&Response);
+  RedfishHttpFreeResponse (&PendingSettingResponse);
+  Private->Payload = NULL;
+
+  if (Private->Json != NULL) {
+    FreePool (Private->Json);
+    Private->Json = NULL;
+  }
+
+  if (Etag != NULL) {
+    FreePool (Etag);
+  }
+
+  if (PendingSettingUri != NULL) {
+    FreePool (PendingSettingUri);
+  }
+
+  return Status;
+}
+
+/**
+  Get information about this protocol.
+
+  @param[in]   This                Pointer to EFI_HP_REDFISH_HII_PROTOCOL instance.
+  @param[out]  Schema              Supported schema.
+  @param[out]  Major               Supported major number.
+  @param[out]  Minor               Supported minor number.
+  @param[out]  Errata              Supported errata number.
+
+  @retval EFI_SUCCESS              Value is returned successfully.
+  @retval Others                   Some error happened.
+
+**/
+EFI_STATUS
+EFIAPI
+RedfishResourceGetInfo (
+  IN     EDKII_REDFISH_RESOURCE_CONFIG_PROTOCOL  *This,
+  OUT    REDFISH_SCHEMA_INFO                     *Info
+  )
+{
+  if ((This == NULL) || (Info == NULL)) {
+    return EFI_INVALID_PARAMETER;
+  }
+
+  AsciiStrCpyS (Info->Schema, REDFISH_SCHEMA_STRING_SIZE, RESOURCE_SCHEMA);
+  AsciiStrCpyS (Info->Major, REDFISH_SCHEMA_VERSION_SIZE, RESOURCE_SCHEMA_MAJOR);
+  AsciiStrCpyS (Info->Minor, REDFISH_SCHEMA_VERSION_SIZE, RESOURCE_SCHEMA_MINOR);
+  AsciiStrCpyS (Info->Errata, REDFISH_SCHEMA_VERSION_SIZE, RESOURCE_SCHEMA_ERRATA);
+
+  return EFI_SUCCESS;
+}
+
+/**
+  Update resource to given URI.
+
+  @param[in]   This                Pointer to EFI_HP_REDFISH_HII_PROTOCOL instance.
+  @param[in]   Uri                 The target URI to consume.
+
+  @retval EFI_SUCCESS              Value is returned successfully.
+  @retval Others                   Some error happened.
+
+**/
+EFI_STATUS
+EFIAPI
+RedfishResourceUpdate (
+  IN     EDKII_REDFISH_RESOURCE_CONFIG_PROTOCOL  *This,
+  IN     EFI_STRING                              Uri
+  )
+{
+  REDFISH_RESOURCE_COMMON_PRIVATE  *Private;
+  EFI_STATUS                       Status;
+  REDFISH_RESPONSE                 Response;
+
+  if ((This == NULL) || IS_EMPTY_STRING (Uri)) {
+    return EFI_INVALID_PARAMETER;
+  }
+
+  ZeroMem (&Response, sizeof (REDFISH_RESPONSE));
+  Private = REDFISH_RESOURCE_COMMON_PRIVATE_DATA_FROM_RESOURCE_PROTOCOL (This);
+
+  if (Private->RedfishService == NULL) {
+    return EFI_NOT_READY;
+  }
+
+  Status = RedfishHttpGetResource (Private->RedfishService, Uri, NULL, &Response, TRUE);
+  if (EFI_ERROR (Status)) {
+    DEBUG ((DEBUG_ERROR, "%a: get resource from: %s failed\n", __func__, Uri));
+    return Status;
+  }
+
+  Private->Uri     = Uri;
+  Private->Payload = Response.Payload;
+  ASSERT (Private->Payload != NULL);
+
+  Private->Json = JsonDumpString (RedfishJsonInPayload (Private->Payload), EDKII_JSON_COMPACT);
+  ASSERT (Private->Json != NULL);
+
+  Status = RedfishUpdateResourceCommon (Private, Private->Json);
+  if (EFI_ERROR (Status)) {
+    DEBUG ((DEBUG_ERROR, "%a: failed to update resource to: %s: %r\n", __func__, Uri, Status));
+  } else {
+    //
+    // Get latest ETag on URI and keep it in variable.
+    //
+    SetEtagFromUri (Private->RedfishService, Private->Uri, TRUE);
+  }
+
+  //
+  // Release resource
+  //
+  RedfishHttpFreeResponse (&Response);
+  Private->Payload = NULL;
+
+  if (Private->Json != NULL) {
+    FreePool (Private->Json);
+    Private->Json = NULL;
+  }
+
+  return Status;
+}
+
+/**
+  Check resource on given URI.
+
+  @param[in]   This                Pointer to EFI_HP_REDFISH_HII_PROTOCOL instance.
+  @param[in]   Uri                 The target URI to consume.
+
+  @retval EFI_SUCCESS              Value is returned successfully.
+  @retval Others                   Some error happened.
+
+**/
+EFI_STATUS
+EFIAPI
+RedfishResourceCheck (
+  IN     EDKII_REDFISH_RESOURCE_CONFIG_PROTOCOL  *This,
+  IN     EFI_STRING                              Uri
+  )
+{
+  REDFISH_RESOURCE_COMMON_PRIVATE  *Private;
+  EFI_STATUS                       Status;
+  REDFISH_RESPONSE                 Response;
+  CHAR8                            *Etag;
+
+  if ((This == NULL) || IS_EMPTY_STRING (Uri)) {
+    return EFI_INVALID_PARAMETER;
+  }
+
+  ZeroMem (&Response, sizeof (REDFISH_RESPONSE));
+  Private = REDFISH_RESOURCE_COMMON_PRIVATE_DATA_FROM_RESOURCE_PROTOCOL (This);
+
+  if (Private->RedfishService == NULL) {
+    return EFI_NOT_READY;
+  }
+
+  Status = RedfishHttpGetResource (Private->RedfishService, Uri, NULL, &Response, TRUE);
+  if (EFI_ERROR (Status)) {
+    DEBUG ((DEBUG_ERROR, "%a: get resource from: %s failed\n", __func__, Uri));
+    return Status;
+  }
+
+  Private->Uri     = Uri;
+  Private->Payload = Response.Payload;
+  ASSERT (Private->Payload != NULL);
+
+  Private->Json = JsonDumpString (RedfishJsonInPayload (Private->Payload), EDKII_JSON_COMPACT);
+  ASSERT (Private->Json != NULL);
+
+  //
+  // Find etag in HTTP response header
+  //
+  Etag   = NULL;
+  Status = GetHttpResponseEtag (&Response, &Etag);
+  if (EFI_ERROR (Status)) {
+    DEBUG ((DEBUG_ERROR, "%a: failed to get ETag from HTTP header\n", __func__));
+  }
+
+  Status = RedfishCheckResourceCommon (Private, Private->Json, Etag);
+  if (EFI_ERROR (Status)) {
+    DEBUG ((DEBUG_ERROR, "%a: failed to check resource from: %s: %r\n", __func__, Uri, Status));
+  }
+
+  //
+  // Release resource
+  //
+  if (Etag != NULL) {
+    FreePool (Etag);
+  }
+
+  RedfishHttpFreeResponse (&Response);
+  Private->Payload = NULL;
+
+  if (Private->Json != NULL) {
+    FreePool (Private->Json);
+    Private->Json = NULL;
+  }
+
+  return Status;
+}
+
+/**
+  Identify resource on given URI.
+
+  @param[in]   This                Pointer to EDKII_REDFISH_RESOURCE_CONFIG_PROTOCOL instance.
+  @param[in]   Uri                 The target URI to consume.
+
+  @retval EFI_SUCCESS              This is target resource which we want to handle.
+  @retval EFI_UNSUPPORTED          This is not the target resource.
+  @retval Others                   Some error happened.
+
+**/
+EFI_STATUS
+EFIAPI
+RedfishResourceIdentify (
+  IN     EDKII_REDFISH_RESOURCE_CONFIG_PROTOCOL  *This,
+  IN     EFI_STRING                              Uri
+  )
+{
+  REDFISH_RESOURCE_COMMON_PRIVATE  *Private;
+  EFI_STATUS                       Status;
+  REDFISH_RESPONSE                 Response;
+
+  if ((This == NULL) || IS_EMPTY_STRING (Uri)) {
+    return EFI_INVALID_PARAMETER;
+  }
+
+  ZeroMem (&Response, sizeof (REDFISH_RESPONSE));
+  Private = REDFISH_RESOURCE_COMMON_PRIVATE_DATA_FROM_RESOURCE_PROTOCOL (This);
+
+  if (Private->RedfishService == NULL) {
+    return EFI_NOT_READY;
+  }
+
+  Status = RedfishHttpGetResource (Private->RedfishService, Uri, NULL, &Response, TRUE);
+  if (EFI_ERROR (Status)) {
+    DEBUG ((DEBUG_ERROR, "%a: get resource from: %s failed\n", __func__, Uri));
+    return Status;
+  }
+
+  Private->Uri     = Uri;
+  Private->Payload = Response.Payload;
+  ASSERT (Private->Payload != NULL);
+
+  Private->Json = JsonDumpString (RedfishJsonInPayload (Private->Payload), EDKII_JSON_COMPACT);
+  ASSERT (Private->Json != NULL);
+
+  Status = RedfishIdentifyResourceCommon (Private, Private->Json);
+  if (EFI_ERROR (Status)) {
+    DEBUG ((DEBUG_ERROR, "%a: identify %s failed: %r\n", __func__, Uri, Status));
+  }
+
+  //
+  // Release resource
+  //
+  RedfishHttpFreeResponse (&Response);
+  Private->Payload = NULL;
+
+  if (Private->Json != NULL) {
+    FreePool (Private->Json);
+    Private->Json = NULL;
+  }
+
+  return Status;
+}
+
+EDKII_REDFISH_RESOURCE_CONFIG_PROTOCOL  mRedfishResourceConfig = {
+  RedfishResourceProvisioningResource,
+  RedfishResourceConsumeResource,
+  RedfishResourceUpdate,
+  RedfishResourceCheck,
+  RedfishResourceIdentify,
+  RedfishResourceGetInfo
+};
+
+/**
+  Initialize a Redfish configure handler.
+
+  This function will be called by the Redfish config driver to initialize each Redfish configure
+  handler.
+
+  @param[in]   This                     Pointer to EDKII_REDFISH_CONFIG_HANDLER_PROTOCOL instance.
+  @param[in]   RedfishConfigServiceInfo Redfish service information.
+
+  @retval EFI_SUCCESS                  The handler has been initialized successfully.
+  @retval EFI_DEVICE_ERROR             Failed to create or configure the REST EX protocol instance.
+  @retval EFI_ALREADY_STARTED          This handler has already been initialized.
+  @retval Other                        Error happens during the initialization.
+
+**/
+EFI_STATUS
+EFIAPI
+RedfishResourceInit (
+  IN  EDKII_REDFISH_CONFIG_HANDLER_PROTOCOL  *This,
+  IN  REDFISH_CONFIG_SERVICE_INFORMATION     *RedfishConfigServiceInfo
+  )
+{
+  REDFISH_RESOURCE_COMMON_PRIVATE  *Private;
+
+  Private = REDFISH_RESOURCE_COMMON_PRIVATE_DATA_FROM_CONFIG_PROTOCOL (This);
+
+  Private->RedfishService = RedfishCreateService (RedfishConfigServiceInfo);
+  if (Private->RedfishService == NULL) {
+    return EFI_DEVICE_ERROR;
+  }
+
+  return EFI_SUCCESS;
+}
+
+/**
+  Stop a Redfish configure handler.
+
+  @param[in]   This                Pointer to EDKII_REDFISH_CONFIG_HANDLER_PROTOCOL instance.
+
+  @retval EFI_SUCCESS              This handler has been stoped successfully.
+  @retval Others                   Some error happened.
+
+**/
+EFI_STATUS
+EFIAPI
+RedfishResourceStop (
+  IN  EDKII_REDFISH_CONFIG_HANDLER_PROTOCOL  *This
+  )
+{
+  REDFISH_RESOURCE_COMMON_PRIVATE  *Private;
+
+  Private = REDFISH_RESOURCE_COMMON_PRIVATE_DATA_FROM_CONFIG_PROTOCOL (This);
+
+  if (Private->Event != NULL) {
+    gBS->CloseEvent (Private->Event);
+    Private->Event = NULL;
+  }
+
+  if (Private->RedfishService != NULL) {
+    RedfishCleanupService (Private->RedfishService);
+    Private->RedfishService = NULL;
+  }
+
+  return EFI_SUCCESS;
+}
+
+EDKII_REDFISH_CONFIG_HANDLER_PROTOCOL  mRedfishConfigHandler = {
+  RedfishResourceInit,
+  RedfishResourceStop
+};
+
+/**
+  Callback function when gEfiRestJsonStructureProtocolGuid is installed.
+
+  @param[in] Event    Event whose notification function is being invoked.
+  @param[in] Context  Pointer to the notification function's context.
+**/
+VOID
+EFIAPI
+EfiRestJsonStructureProtocolIsReady (
+  IN  EFI_EVENT  Event,
+  IN  VOID       *Context
+  )
+{
+  EFI_STATUS  Status;
+
+  if (mRedfishResourcePrivate == NULL) {
+    return;
+  }
+
+  if (mRedfishResourcePrivate->JsonStructProtocol != NULL) {
+    return;
+  }
+
+  Status = gBS->LocateProtocol (
+                  &gEfiRestJsonStructureProtocolGuid,
+                  NULL,
+                  (VOID **)&mRedfishResourcePrivate->JsonStructProtocol
+                  );
+  if (EFI_ERROR (Status)) {
+    DEBUG ((DEBUG_ERROR, "%a: failed to locate gEfiRestJsonStructureProtocolGuid: %r\n", __func__, Status));
+  }
+
+  gBS->CloseEvent (Event);
+}
+
+/**
+  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
+RedfishResourceUnload (
+  IN EFI_HANDLE  ImageHandle
+  )
+{
+  EFI_STATUS                             Status;
+  EDKII_REDFISH_CONFIG_HANDLER_PROTOCOL  *ConfigHandler;
+
+  if (mRedfishResourcePrivate == NULL) {
+    return EFI_NOT_READY;
+  }
+
+  ConfigHandler = NULL;
+
+  //
+  // Firstly, find ConfigHandler Protocol interface in this ImageHandle.
+  //
+  Status = gBS->OpenProtocol (
+                  ImageHandle,
+                  &gEdkIIRedfishConfigHandlerProtocolGuid,
+                  (VOID **)&ConfigHandler,
+                  NULL,
+                  NULL,
+                  EFI_OPEN_PROTOCOL_BY_HANDLE_PROTOCOL
+                  );
+  if (EFI_ERROR (Status) || (ConfigHandler == NULL)) {
+    return Status;
+  }
+
+  ConfigHandler->Stop (ConfigHandler);
+
+  //
+  // Last, uninstall ConfigHandler Protocol and resource protocol.
+  //
+  Status = gBS->UninstallMultipleProtocolInterfaces (
+                  ImageHandle,
+                  &gEdkIIRedfishConfigHandlerProtocolGuid,
+                  ConfigHandler,
+                  &gEdkIIRedfishResourceConfigProtocolGuid,
+                  &mRedfishResourcePrivate->RedfishResourceConfig,
+                  NULL
+                  );
+
+  FreePool (mRedfishResourcePrivate);
+  mRedfishResourcePrivate = NULL;
+
+  return Status;
+}
+
+/**
+  The callback function provided by Redfish Feature driver.
+
+  @param[in]     This                Pointer to EDKII_REDFISH_FEATURE_PROTOCOL instance.
+  @param[in]     FeatureAction       The action Redfish feature driver should take.
+  @param[in]     Uri                 The collection URI.
+  @param[in]     Context             The context of Redfish feature driver.
+  @param[in,out] InformationExchange The pointer to RESOURCE_INFORMATION_EXCHANGE
+
+  @retval EFI_SUCCESS              Redfish feature driver callback is executed successfully.
+  @retval Others                   Some errors happened.
+
+  @retval EFI_SUCCESS              Redfish feature driver callback is executed successfully.
+  @retval Others                   Some errors happened.
+
+**/
+EFI_STATUS
+EFIAPI
+RedfishExternalResourceResourceFeatureCallback (
+  IN     EDKII_REDFISH_FEATURE_PROTOCOL  *This,
+  IN     FEATURE_CALLBACK_ACTION         FeatureAction,
+  IN     VOID                            *Context,
+  IN OUT RESOURCE_INFORMATION_EXCHANGE   *InformationExchange
+  )
+{
+  EFI_STATUS                       Status;
+  REDFISH_SERVICE                  RedfishService;
+  REDFISH_RESOURCE_COMMON_PRIVATE  *Private;
+  EFI_STRING                       ResourceUri;
+  EFI_STRING                       SecureBootUri;
+
+  if (FeatureAction != CallbackActionStartOperation) {
+    return EFI_UNSUPPORTED;
+  }
+
+  Private = (REDFISH_RESOURCE_COMMON_PRIVATE *)Context;
+
+  RedfishService = Private->RedfishService;
+  if (RedfishService == NULL) {
+    DEBUG ((DEBUG_ERROR, "%a: no Redfish service configured\n", __func__));
+    return EFI_NOT_READY;
+  }
+
+  //
+  // Save in private structure.
+  //
+  Private->InformationExchange = InformationExchange;
+
+  //
+  // Find Redfish version on Redfish ser
+  //
+  Private->RedfishVersion = RedfishGetVersion (RedfishService);
+
+  //
+  // Create the full URI from Redfish service root.
+  //
+  ResourceUri = (EFI_STRING)AllocateZeroPool (MAX_URI_LENGTH * sizeof (CHAR16));
+  if (ResourceUri == NULL) {
+    DEBUG ((DEBUG_ERROR, "%a: Fail to allocate memory for full URI.\n", __func__));
+    return EFI_OUT_OF_RESOURCES;
+  }
+
+  StrCatS (ResourceUri, MAX_URI_LENGTH, Private->RedfishVersion);
+  StrCatS (ResourceUri, MAX_URI_LENGTH, InformationExchange->SendInformation.FullUri);
+
+  //
+  // Initialize collection path
+  //
+  SecureBootUri = RedfishGetUri (ResourceUri);
+  if (SecureBootUri == NULL) {
+    ASSERT (FALSE);
+    FreePool (ResourceUri);
+    return EFI_OUT_OF_RESOURCES;
+  }
+
+  Status = HandleResource (Private, SecureBootUri);
+  if (EFI_ERROR (Status)) {
+    DEBUG ((DEBUG_ERROR, "%a: process external resource: %s failed: %r\n", __func__, SecureBootUri, Status));
+  }
+
+  FreePool (SecureBootUri);
+  FreePool (ResourceUri);
+  return Status;
+}
+
+/**
+  Callback function when gEdkIIRedfishFeatureProtocolGuid is installed.
+
+  @param[in] Event    Event whose notification function is being invoked.
+  @param[in] Context  Pointer to the notification function's context.
+**/
+VOID
+EFIAPI
+EdkIIRedfishFeatureProtocolIsReady (
+  IN  EFI_EVENT  Event,
+  IN  VOID       *Context
+  )
+{
+  EFI_STATUS                      Status;
+  EDKII_REDFISH_FEATURE_PROTOCOL  *FeatureProtocol;
+
+  if (mRedfishResourcePrivate == NULL) {
+    return;
+  }
+
+  if (mRedfishResourcePrivate->FeatureProtocol != NULL) {
+    return;
+  }
+
+  Status = gBS->LocateProtocol (
+                  &gEdkIIRedfishFeatureProtocolGuid,
+                  NULL,
+                  (VOID **)&FeatureProtocol
+                  );
+  if (EFI_ERROR (Status)) {
+    DEBUG ((DEBUG_ERROR, "%a: failed to locate gEdkIIRedfishFeatureProtocolGuid: %r\n", __func__, Status));
+    gBS->CloseEvent (Event);
+    return;
+  }
+
+  Status = FeatureProtocol->Register (
+                              FeatureProtocol,
+                              REDFISH_MANAGED_URI,
+                              RedfishExternalResourceResourceFeatureCallback,
+                              (VOID *)mRedfishResourcePrivate
+                              );
+  if (EFI_ERROR (Status)) {
+    DEBUG ((DEBUG_ERROR, "%a: failed to register %s: %r\n", __func__, REDFISH_MANAGED_URI, Status));
+  }
+
+  mRedfishResourcePrivate->FeatureProtocol = FeatureProtocol;
+
+  gBS->CloseEvent (Event);
+}
+
+/**
+  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. It initialize the global variables and
+  publish the driver binding protocol.
+
+  @param[in]   ImageHandle      The firmware allocated handle for the UEFI image.
+  @param[in]   SystemTable      A pointer to the EFI System Table.
+
+  @retval EFI_SUCCESS           The operation completed successfully.
+  @retval EFI_ACCESS_DENIED     EFI_ISCSI_INITIATOR_NAME_PROTOCOL was installed unexpectedly.
+  @retval Others                Other errors as indicated.
+**/
+EFI_STATUS
+EFIAPI
+RedfishResourceEntryPoint (
+  IN EFI_HANDLE        ImageHandle,
+  IN EFI_SYSTEM_TABLE  *SystemTable
+  )
+{
+  EFI_STATUS  Status;
+  VOID        *Registration;
+
+  if (mRedfishResourcePrivate != NULL) {
+    return EFI_ALREADY_STARTED;
+  }
+
+  mRedfishResourceConfigProtocolHandle = ImageHandle;
+
+  mRedfishResourcePrivate = AllocateZeroPool (sizeof (REDFISH_RESOURCE_COMMON_PRIVATE));
+  CopyMem (&mRedfishResourcePrivate->ConfigHandler, &mRedfishConfigHandler, sizeof (EDKII_REDFISH_CONFIG_HANDLER_PROTOCOL));
+  CopyMem (&mRedfishResourcePrivate->RedfishResourceConfig, &mRedfishResourceConfig, sizeof (EDKII_REDFISH_RESOURCE_CONFIG_PROTOCOL));
+
+  //
+  // Publish config handler protocol and resource protocol.
+  //
+  Status = gBS->InstallMultipleProtocolInterfaces (
+                  &ImageHandle,
+                  &gEdkIIRedfishConfigHandlerProtocolGuid,
+                  &mRedfishResourcePrivate->ConfigHandler,
+                  &gEdkIIRedfishResourceConfigProtocolGuid,
+                  &mRedfishResourcePrivate->RedfishResourceConfig,
+                  NULL
+                  );
+
+  EfiCreateProtocolNotifyEvent (
+    &gEfiRestJsonStructureProtocolGuid,
+    TPL_CALLBACK,
+    EfiRestJsonStructureProtocolIsReady,
+    NULL,
+    &Registration
+    );
+
+  EfiCreateProtocolNotifyEvent (
+    &gEdkIIRedfishFeatureProtocolGuid,
+    TPL_CALLBACK,
+    EdkIIRedfishFeatureProtocolIsReady,
+    (VOID *)mRedfishResourcePrivate,
+    &Registration
+    );
+
+  return Status;
+}
diff --git a/RedfishClientPkg/RedfishClient.fdf.inc b/RedfishClientPkg/RedfishClient.fdf.inc
index 59b8acba1..154f641b2 100644
--- a/RedfishClientPkg/RedfishClient.fdf.inc
+++ b/RedfishClientPkg/RedfishClient.fdf.inc
@@ -25,6 +25,7 @@
   INF RedfishClientPkg/HiiToRedfishBiosDxe/HiiToRedfishBiosDxe.inf
   INF RedfishClientPkg/Features/BootOptionCollection/BootOptionCollectionDxe.inf
   INF RedfishClientPkg/Features/BootOption/v1_0_4/Dxe/BootOptionDxe.inf
+  INF RedfishClientPkg/Features/SecureBoot/v1_1_0/Dxe/SecureBootDxe.inf
 
   !include RedfishClientPkg/RedfishJsonStructureDxe.fdf.inc
   #
-- 
2.34.1



-=-=-=-=-=-=-=-=-=-=-=-
Groups.io Links: You receive all messages sent to this group.
View/Reply Online (#116764): https://edk2.groups.io/g/devel/message/116764
Mute This Topic: https://groups.io/mt/104927848/7686176
Group Owner: devel+owner@edk2.groups.io
Unsubscribe: https://edk2.groups.io/g/devel/unsub [rebecca@openfw.io]
-=-=-=-=-=-=-=-=-=-=-=-



^ permalink raw reply related	[flat|nested] 5+ messages in thread

* Re: [edk2-devel] [edk2-redfish-client][PATCH 1/2] RedfishClientPkg/Features: support Redfish Secure Boot
  2024-03-14 14:53 [edk2-devel] [edk2-redfish-client][PATCH 1/2] RedfishClientPkg/Features: support Redfish Secure Boot Nickle Wang via groups.io
@ 2024-03-14 19:38 ` Mike Maslenkin
  2024-03-26 13:57   ` Nickle Wang via groups.io
  0 siblings, 1 reply; 5+ messages in thread
From: Mike Maslenkin @ 2024-03-14 19:38 UTC (permalink / raw)
  To: devel, Nickle Wang; +Cc: Abner Chang, Igor Kulchytskyy, Nick Ramirez

[-- Attachment #1: Type: text/plain, Size: 63058 bytes --]

Hi Nickle,

please find my comments below

> On 14. 3. 2024., at 17:53, Nickle Wang via groups.io <http://groups.io/> <nicklew=nvidia.com@groups.io <mailto:nvidia.com@groups.io>> wrote:
> 
> Introduce SecureBoot driver to support
> /redfish/v1/Systems/SYS/SecureBoot resource.
> 
> Signed-off-by: Nickle Wang <nicklew@nvidia.com <mailto:nicklew@nvidia.com>>
> Cc: Abner Chang <abner.chang@amd.com <mailto:abner.chang@amd.com>>
> Cc: Igor Kulchytskyy <igork@ami.com <mailto:igork@ami.com>>
> Cc: Nick Ramirez <nramirez@nvidia.com <mailto:nramirez@nvidia.com>>
> ---
> .../RedfishClientComponents.dsc.inc           |   2 +
> RedfishClientPkg/RedfishClientLibs.dsc.inc    |   4 +
> .../SecureBoot/v1_1_0/Dxe/SecureBootDxe.inf   |  60 ++
> .../v1_1_0/Common/SecureBootCommon.h          |  40 +
> .../v1_1_0/Common/SecureBootCommon.c          | 756 ++++++++++++++++
> .../SecureBoot/v1_1_0/Dxe/SecureBootDxe.c     | 808 ++++++++++++++++++
> RedfishClientPkg/RedfishClient.fdf.inc        |   1 +
> 7 files changed, 1671 insertions(+)
> create mode 100644 RedfishClientPkg/Features/SecureBoot/v1_1_0/Dxe/SecureBootDxe.inf
> create mode 100644 RedfishClientPkg/Features/SecureBoot/v1_1_0/Common/SecureBootCommon.h
> create mode 100644 RedfishClientPkg/Features/SecureBoot/v1_1_0/Common/SecureBootCommon.c
> create mode 100644 RedfishClientPkg/Features/SecureBoot/v1_1_0/Dxe/SecureBootDxe.c
> 
> diff --git a/RedfishClientPkg/RedfishClientComponents.dsc.inc b/RedfishClientPkg/RedfishClientComponents.dsc.inc
> index ae2a4b025..42fc0c299 100644
> --- a/RedfishClientPkg/RedfishClientComponents.dsc.inc
> +++ b/RedfishClientPkg/RedfishClientComponents.dsc.inc
> @@ -34,6 +34,7 @@
>   RedfishClientPkg/Features/Bios/v1_0_9/Dxe/BiosDxe.inf
>   RedfishClientPkg/Features/BootOptionCollection/BootOptionCollectionDxe.inf
>   RedfishClientPkg/Features/BootOption/v1_0_4/Dxe/BootOptionDxe.inf
> +  RedfishClientPkg/Features/SecureBoot/v1_1_0/Dxe/SecureBootDxe.inf
> 
>   !include RedfishClientPkg/RedfishJsonStructureDxe.dsc.inc
> 
> @@ -47,3 +48,4 @@
>   RedfishClientPkg/Converter/Bios/v1_0_9/RedfishBios_V1_0_9_Dxe.inf
>   RedfishClientPkg/Converter/BootOptionCollection/RedfishBootOptionCollection_Dxe.inf
>   RedfishClientPkg/Converter/BootOption/v1_0_4/RedfishBootOption_V1_0_4_Dxe.inf
> +  RedfishClientPkg/Converter/SecureBoot/v1_1_0/RedfishSecureBoot_V1_1_0_Dxe.inf
> diff --git a/RedfishClientPkg/RedfishClientLibs.dsc.inc b/RedfishClientPkg/RedfishClientLibs.dsc.inc
> index 6599926ab..9126465df 100644
> --- a/RedfishClientPkg/RedfishClientLibs.dsc.inc
> +++ b/RedfishClientPkg/RedfishClientLibs.dsc.inc
> @@ -25,6 +25,8 @@
>   BiosV1_0_9Lib|RedfishClientPkg/ConverterLib/edk2library/Bios/v1_0_9/Lib.inf
>   BootOptionCollectionLib|RedfishClientPkg/ConverterLib/edk2library/BootOptionCollection/Lib.inf
>   BootOptionV1_0_4Lib|RedfishClientPkg/ConverterLib/edk2library/BootOption/v1_0_4/Lib.inf
> +  SecureBootV1_1_0Lib|RedfishClientPkg/ConverterLib/edk2library/SecureBoot/v1_1_0/Lib.inf
> +
>   #
>   # Above modules should be pulled in by build tool.
>   #
> @@ -42,3 +44,5 @@
>   RedfishAddendumLib|RedfishClientPkg/Library/RedfishAddendumLib/RedfishAddendumLib.inf
>   RedfishDebugLib|RedfishPkg/Library/RedfishDebugLib/RedfishDebugLib.inf
>   RedfishHttpLib|RedfishPkg/Library/RedfishHttpLib/RedfishHttpLib.inf
> +  SecureBootVariableLib|SecurityPkg/Library/SecureBootVariableLib/SecureBootVariableLib.inf
> +  PlatformPKProtectionLib|SecurityPkg/Library/PlatformPKProtectionLibVarPolicy/PlatformPKProtectionLibVarPolicy.inf
> diff --git a/RedfishClientPkg/Features/SecureBoot/v1_1_0/Dxe/SecureBootDxe.inf b/RedfishClientPkg/Features/SecureBoot/v1_1_0/Dxe/SecureBootDxe.inf
> new file mode 100644
> index 000000000..1ad8c623f
> --- /dev/null
> +++ b/RedfishClientPkg/Features/SecureBoot/v1_1_0/Dxe/SecureBootDxe.inf
> @@ -0,0 +1,60 @@
> +## @file
> +#
> +#  (C) Copyright 2020-2022 Hewlett Packard Enterprise Development LP<BR>
> +#  Copyright (c) 2022-2024, NVIDIA CORPORATION & AFFILIATES. All rights reserved.
> +#
> +#  SPDX-License-Identifier: BSD-2-Clause-Patent
> +#
> +##
> +
> +
> +[Defines]
> +  INF_VERSION               = 0x00010005
> +  BASE_NAME                 = SecureBootDxe
> +  FILE_GUID                 = 5E4025F8-DA42-468A-853E-6A1091D35052
> +  MODULE_TYPE               = DXE_DRIVER
> +  VERSION_STRING            = 1.0
> +  ENTRY_POINT               = RedfishResourceEntryPoint
> +  UNLOAD_IMAGE              = RedfishResourceUnload
> +
> +[Packages]
> +  MdePkg/MdePkg.dec
> +  MdeModulePkg/MdeModulePkg.dec
> +  SecurityPkg/SecurityPkg.dec
> +  RedfishPkg/RedfishPkg.dec
> +  RedfishClientPkg/RedfishClientPkg.dec
> +
> +[Sources]
> +  ../Common/SecureBootCommon.h
> +  ../Common/SecureBootCommon.c
> +  SecureBootDxe.c
> +
> +[LibraryClasses]
> +  BaseMemoryLib
> +  DebugLib
> +  EdkIIRedfishResourceConfigLib
> +  RedfishFeatureUtilityLib
> +  RedfishVersionLib
> +  RedfishResourceIdentifyLib
> +  SecureBootVariableLib
> +  UefiLib
> +  UefiDriverEntryPoint
> +  RedfishAddendumLib
> +  UefiRuntimeServicesTableLib
> +
> +[Protocols]
> +  gEdkIIRedfishConfigHandlerProtocolGuid          ## PRODUCED
> +  gEfiRestJsonStructureProtocolGuid               ## CONSUMED
> +  gEdkIIRedfishResourceConfigProtocolGuid         ## PRODUCED
> +  gEdkIIRedfishFeatureProtocolGuid                ## CONSUMED
> +
> +[Guids]
> +  gEfiSecureBootEnableDisableGuid                 ## CONSUMED
> +
> +[Pcd]
> +  gEfiRedfishClientPkgTokenSpaceGuid.PcdMaxRedfishSchemaStringSize
> +  gEfiRedfishClientPkgTokenSpaceGuid.PcdMaxRedfishSchemaVersionSize
> +  gEfiRedfishClientPkgTokenSpaceGuid.PcdRedfishSystemRebootRequired
> +
> +[Depex]
> +  TRUE
> diff --git a/RedfishClientPkg/Features/SecureBoot/v1_1_0/Common/SecureBootCommon.h b/RedfishClientPkg/Features/SecureBoot/v1_1_0/Common/SecureBootCommon.h
> new file mode 100644
> index 000000000..0d1824160
> --- /dev/null
> +++ b/RedfishClientPkg/Features/SecureBoot/v1_1_0/Common/SecureBootCommon.h
> @@ -0,0 +1,40 @@
> +/** @file
> +
> +  Redfish feature driver implementation - internal header file
> +  (C) Copyright 2020-2022 Hewlett Packard Enterprise Development LP<BR>
> +  Copyright (c) 2022-2024, NVIDIA CORPORATION & AFFILIATES. All rights reserved.
> +
> +  SPDX-License-Identifier: BSD-2-Clause-Patent
> +
> +**/
> +
> +#ifndef EFI_REDFISH_SECUREBOOT_COMMON_H_
> +#define EFI_REDFISH_SECUREBOOT_COMMON_H_
> +
> +#include <Guid/ImageAuthentication.h>
> +#include <Guid/GlobalVariable.h>
> +#include <Guid/AuthenticatedVariableFormat.h>
> +#include <RedfishJsonStructure/SecureBoot/v1_1_0/EfiSecureBootV1_1_0.h>
> +#include <RedfishResourceCommon.h>
> +#include <UefiSecureBoot.h>
> +#include <Library/UefiRuntimeServicesTableLib.h>
> +#include <Library/SecureBootVariableLib.h>
> +
> +//
> +// Schema information.
> +//
> +#define REDFISH_MANAGED_URI        L"Systems/{}/SecureBoot"
> +#define REDFISH_DUMMY_CONFIG_LANG  L"Systems/{1}/SecureBoot"
> +#define MAX_URI_LENGTH             256
> +#define RESOURCE_SCHEMA            "SecureBoot"
> +#define RESOURCE_SCHEMA_MAJOR      "1"
> +#define RESOURCE_SCHEMA_MINOR      "1"
> +#define RESOURCE_SCHEMA_ERRATA     "0"
> +#define RESOURCE_SCHEMA_VERSION    "v1_1_0"
> +#define SECURE_BOOT_SETUP_MODE     "SetupMode"
> +#define SECURE_BOOT_USER_MODE      "UserMode"
> +#define SECURE_BOOT_ENABLED        "Enabled"
> +#define SECURE_BOOT_DISABLED       "Disabled"
> +#define SECURE_BOOT_MODE_STR_LEN   16
> +
> +#endif
> diff --git a/RedfishClientPkg/Features/SecureBoot/v1_1_0/Common/SecureBootCommon.c b/RedfishClientPkg/Features/SecureBoot/v1_1_0/Common/SecureBootCommon.c
> new file mode 100644
> index 000000000..56a45ee72
> --- /dev/null
> +++ b/RedfishClientPkg/Features/SecureBoot/v1_1_0/Common/SecureBootCommon.c
> @@ -0,0 +1,756 @@
> +/** @file
> +  Redfish feature driver implementation - common functions
> +
> +  (C) Copyright 2020-2022 Hewlett Packard Enterprise Development LP<BR>
> +  Copyright (c) 2023-2024, NVIDIA CORPORATION & AFFILIATES. All rights reserved.
> +
> +  SPDX-License-Identifier: BSD-2-Clause-Patent
> +
> +**/
> +
> +#include "SecureBootCommon.h"
> +
> +CHAR8  SecureBootEmptyJson[] = "{\"@odata.id <http://odata.id/>\": \"\", \"@odata.type\": \"#SecureBoot.v1_1_0.SecureBoot\", \"Id\": \"\", \"Name\": \"\", \"Attributes\":{}}";
> +
> +REDFISH_RESOURCE_COMMON_PRIVATE  *mRedfishResourcePrivate                                  = NULL;
> +EFI_HANDLE                       mRedfishResourceConfigProtocolHandle                      = NULL;
> +CHAR16                           *mSecureBootSupportedAttributes[SECURE_BOOT_MODE_STR_LEN] = {
> +  L"SecureBootCurrentBoot",
> +  L"SecureBootEnable",
> +  L"SecureBootMode"
> +};
> +
> +/**
> +  Read EFI_SECURE_BOOT_ENABLE_NAME variable and return its value to caller.
> +
> +  @retval BOOLEAN    TRUE when EFI_SECURE_BOOT_ENABLE_NAME value is SECURE_BOOT_ENABLE
> +                     FALSE when EFI_SECURE_BOOT_ENABLE_NAME value is SECURE_BOOT_DISABLE
> +**/
> +BOOLEAN
> +RedfishReadSecureBootEnable (
> +  VOID
> +  )
> +{
> +  UINT8    *Buffer;
> +  BOOLEAN  SecureBootEnableValue;
> +
> +  Buffer                = NULL;
> +  SecureBootEnableValue = FALSE;
> +
> +  GetVariable2 (
> +    EFI_SECURE_BOOT_ENABLE_NAME,
> +    &gEfiSecureBootEnableDisableGuid,
> +    (VOID **)&Buffer,
> +    NULL
> +    );
> +
> +  if (Buffer != NULL) {
> +    if (*Buffer == SECURE_BOOT_ENABLE) {
> +      SecureBootEnableValue = TRUE;
> +    }
> +
> +    FreePool (Buffer);
> +  }
> +
> +  return SecureBootEnableValue;
> +}
> +
> +/**
> +  Write EFI_SECURE_BOOT_ENABLE_NAME variable with given value.
> +
> +  @param[in]   SecureBootEnableValue    Value to write. TRUE is SECURE_BOOT_ENABLE.
> +                                        FALSE is SECURE_BOOT_DISABLE.
> +
> +  @retval EFI_SUCCESS              Write value successfully.
> +  @retval Others                   Some error happened.
> +**/
> +EFI_STATUS
> +RedfishWriteSecureBootEnable (
> +  BOOLEAN  SecureBootEnableValue
> +  )
> +{
> +  EFI_STATUS  Status;
> +  UINT8       VarValue;
> +
> +  VarValue = (SecureBootEnableValue ? SECURE_BOOT_ENABLE : SECURE_BOOT_DISABLE);
> +  Status   = gRT->SetVariable (
> +                    EFI_SECURE_BOOT_ENABLE_NAME,
> +                    &gEfiSecureBootEnableDisableGuid,
> +                    EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS,
> +                    sizeof (VarValue),
> +                    &VarValue
> +                    );
> +
> +  return Status;
> +}
> +
> +/**
> +  Consume Redfish resource in given Json data.
> +
> +  @param[in]   This                Pointer to REDFISH_RESOURCE_COMMON_PRIVATE instance.
> +  @param[in]   Json                The JSON to consume.
> +  @param[in]   HeaderEtag          The Etag string returned in HTTP header.
> +
> +  @retval EFI_SUCCESS              Consume Redfish attribute successfully.
> +  @retval Others                   Some error happened.
> +
> +**/
> +EFI_STATUS
> +RedfishConsumeResourceCommon (
> +  IN  REDFISH_RESOURCE_COMMON_PRIVATE  *Private,
> +  IN  CHAR8                            *Json,
> +  IN  CHAR8                            *HeaderEtag OPTIONAL
> +  )
> +{
> +  EFI_STATUS                        Status;
> +  EFI_REDFISH_SECUREBOOT_V1_1_0     *SecureBoot;
> +  EFI_REDFISH_SECUREBOOT_V1_1_0_CS  *SecureBootCs;
> +  BOOLEAN                           SecureBootEnableDisable;
> +
> +  if ((Private == NULL) || IS_EMPTY_STRING (Json)) {
> +    return EFI_INVALID_PARAMETER;
> +  }
> +
> +  SecureBoot              = NULL;
> +  SecureBootCs            = NULL;
> +  SecureBootEnableDisable = RedfishReadSecureBootEnable ();
> +
> +  Status = Private->JsonStructProtocol->ToStructure (
> +                                          Private->JsonStructProtocol,
> +                                          NULL,
> +                                          Json,
> +                                          (EFI_REST_JSON_STRUCTURE_HEADER **)&SecureBoot
> +                                          );
> +  if (EFI_ERROR (Status)) {
> +    DEBUG ((DEBUG_ERROR, "%a: ToStructure() failed: %r\n", __func__, Status));
> +    return Status;
> +  }
> +
> +  SecureBootCs = SecureBoot->SecureBoot;
> +
> +  //
> +  // Check ETAG to see if we need to consume it
> +  //
> +  if (CheckEtag (Private->Uri, HeaderEtag, SecureBootCs->odata_etag)) {
> +    //
> +    // No change
> +    //
> +    DEBUG ((REDFISH_DEBUG_TRACE, "%a: ETAG: %s has no change, ignore consume action\n", __func__, Private->Uri));
> +    Status = EFI_ALREADY_STARTED;
> +    goto ON_RELEASE;
> +  }
> +
> +  //
> +  // Secure boot enable
> +  //
> +  if (SecureBootCs->SecureBootEnable != NULL) {
> +    if (SecureBootEnableDisable != *SecureBootCs->SecureBootEnable) {
> +      //
> +      // Write value to "SecureBootEnable" variable. AuthVariableLib will enable or disable secure boot
> +      // based on "SecureBootEnable" value.
> +      //
> +      Status = RedfishWriteSecureBootEnable (*SecureBootCs->SecureBootEnable);
> +      if (EFI_ERROR (Status)) {
> +        DEBUG ((DEBUG_ERROR, "%a: write secure boot enable disable failed: %r\n", __func__, Status));
> +      } else {
> +        REDFISH_ENABLE_SYSTEM_REBOOT ();
> +      }
> +    } else {
> +      DEBUG ((REDFISH_DEBUG_TRACE, "%a: secure boot mode is not changed\n", __func__));
> +    }
> +  }
> +
> +ON_RELEASE:
> +
> +  //
> +  // Release resource.
> +  //
> +  Private->JsonStructProtocol->DestoryStructure (
> +                                 Private->JsonStructProtocol,
> +                                 (EFI_REST_JSON_STRUCTURE_HEADER *)SecureBoot
> +                                 );
> +
> +  return EFI_SUCCESS;
> +}
> +
> +/**
> +  Provision Redfish resource. This function reads secure boot variable and convert it
> +  to Redfish attribute.
> +
> +  @param[in]   JsonStructProtocol  Pointer to Json structure protocol.
> +  @param[in]   InputJson           Jason data on input.
> +  @param[in]   ResourceId          Resource ID. This is optional.
> +  @param[in]   ConfigureLang       Configure language for this Redfish resource.
> +  @param[in]   ProvisionMode       TRUE when this is to provision Redfish attribute to
> +                                   Redfish service. FALSE is to update Redfish attribute
> +                                   to Redfish service.
> +  @param[out]  ResultJson          Json data on output.
> +
> +  @retval EFI_SUCCESS              Provision Redfish attribute successfully.
> +  @retval Others                   Some error happened.
> +
> +**/
> +EFI_STATUS
> +ProvisioningSecureBootProperties (
> +  IN  EFI_REST_JSON_STRUCTURE_PROTOCOL  *JsonStructProtocol,
> +  IN  CHAR8                             *InputJson,
> +  IN  CHAR8                             *ResourceId OPTIONAL,
> +  IN  EFI_STRING                        ConfigureLang,
> +  IN  BOOLEAN                           ProvisionMode,
> +  OUT CHAR8                             **ResultJson
> +  )
> +{
> +  EFI_REDFISH_SECUREBOOT_V1_1_0     *SecureBoot;
> +  EFI_REDFISH_SECUREBOOT_V1_1_0_CS  *SecureBootCs;
> +  EFI_STATUS                        Status;
> +  BOOLEAN                           PropertyChanged;
> +  CHAR8                             *AsciiStringValue;
> +  INT32                             *IntegerValue;
> +  UINT8                             SetupMode;
> +  BOOLEAN                           SecureBootEnabled;
> +  BOOLEAN                           SecureBootEnableDisable;
> +
> +  if ((JsonStructProtocol == NULL) || (ResultJson == NULL) || IS_EMPTY_STRING (InputJson) || IS_EMPTY_STRING (ConfigureLang)) {
> +    return EFI_INVALID_PARAMETER;
> +  }
> +
> +  DEBUG ((REDFISH_DEBUG_TRACE, "%a provision for %s with: %s\n", __func__, ConfigureLang, (ProvisionMode ? L"Provision resource" : L"Update resource")));
> +
> +  *ResultJson             = NULL;
> +  PropertyChanged         = FALSE;
> +  AsciiStringValue        = NULL;
> +  SecureBootEnableDisable = RedfishReadSecureBootEnable ();
> +  SecureBootEnabled       = IsSecureBootEnabled ();
> +
> +  SecureBoot = NULL;
> +  Status     = JsonStructProtocol->ToStructure (
> +                                     JsonStructProtocol,
> +                                     NULL,
> +                                     InputJson,
> +                                     (EFI_REST_JSON_STRUCTURE_HEADER **)&SecureBoot
> +                                     );
> +  if (EFI_ERROR (Status)) {
> +    DEBUG ((DEBUG_ERROR, "%a: ToStructure failure: %r\n", __func__, Status));
> +    return Status;
> +  }
> +
> +  SecureBootCs = SecureBoot->SecureBoot;
> +
> +  //
> +  // ID
> +  //
> +  if (SecureBootCs->Id != NULL) {
> +    SecureBootCs->Id = NULL;
> +  }
> +
> +  //
> +  // Name
> +  //
> +  if (SecureBootCs->Name != NULL) {
> +    SecureBootCs->Name = NULL;
> +  }
> +
> +  //
> +  // Secure boot variables that we will handle here
> +  //
> +  // EFI_SETUP_MODE_NAME (gEfiGlobalVariableGuid)
> +  // EFI_SECURE_BOOT_MODE_NAME (gEfiGlobalVariableGuid)
> +  // EFI_SECURE_BOOT_ENABLE_NAME (gEfiSecureBootEnableDisableGuid)
> +  //
> +
> +  //
> +  // Current Boot
> +  //
> +  if (PropertyChecker (SecureBootCs->SecureBootCurrentBoot, ProvisionMode)) {
> +    AsciiStringValue = AllocateZeroPool (SECURE_BOOT_MODE_STR_LEN * sizeof (CHAR8));
> +    if (AsciiStringValue != NULL) {
> +      AsciiSPrint (AsciiStringValue, SECURE_BOOT_MODE_STR_LEN, "%a", (SecureBootEnabled ? SECURE_BOOT_ENABLED : SECURE_BOOT_DISABLED));
> +      if (ProvisionMode || (AsciiStrCmp (SecureBootCs->SecureBootCurrentBoot, AsciiStringValue) != 0)) {
> +        SecureBootCs->SecureBootCurrentBoot = AsciiStringValue;
> +        PropertyChanged                     = TRUE;
> +      }
> +    } else {
> +      DEBUG ((DEBUG_ERROR, "%a: out of resource\n", __func__));
> +    }
> +  }
> +
> +  //
> +  // Secure boot enable
> +  //
> +  if (PropertyChecker (SecureBootCs->SecureBootEnable, ProvisionMode)) {
> +    if (ProvisionMode || (*SecureBootCs->SecureBootEnable != SecureBootEnableDisable)) {
> +      IntegerValue = AllocatePool (sizeof (*IntegerValue));
> +      if (IntegerValue != NULL) {
> +        *IntegerValue                  = (SecureBootEnableDisable ? 0x01 : 0x00);
> +        SecureBootCs->SecureBootEnable = IntegerValue;
> +        PropertyChanged                = TRUE;
> +      } else {
> +        DEBUG ((DEBUG_ERROR, "%a: out of resource\n", __func__));
> +      }
> +    }
> +  }
> +
> +  //
> +  // Secure boot mode
> +  //
> +  if (PropertyChecker (SecureBootCs->SecureBootMode, ProvisionMode)) {
> +    Status = GetSetupMode (&SetupMode);
> +    if (!EFI_ERROR (Status)) {
> +      AsciiStringValue = AllocateZeroPool (SECURE_BOOT_MODE_STR_LEN *sizeof (CHAR8));
> +      if (AsciiStringValue != NULL) {
> +        AsciiSPrint (AsciiStringValue, SECURE_BOOT_MODE_STR_LEN *sizeof (CHAR8), "%a", (SetupMode == USER_MODE ? SECURE_BOOT_USER_MODE : SECURE_BOOT_SETUP_MODE));
> +        if (ProvisionMode || (AsciiStrCmp (SecureBootCs->SecureBootMode, AsciiStringValue) != 0)) {
> +          SecureBootCs->SecureBootMode = AsciiStringValue;
> +          PropertyChanged              = TRUE;
> +        }
> +      }
> +    } else {
> +      DEBUG ((DEBUG_ERROR, "%a: cannot read setup mode: %r\n", __func__, Status));
> +    }
> +  }
> +
> +  //
> +  // Convert C structure back to JSON text.
> +  //
> +  Status = JsonStructProtocol->ToJson (
> +                                 JsonStructProtocol,
> +                                 (EFI_REST_JSON_STRUCTURE_HEADER *)SecureBoot,
> +                                 ResultJson
> +                                 );
> +  if (EFI_ERROR (Status)) {
> +    DEBUG ((DEBUG_ERROR, "%a: ToJson() failed: %r\n", __func__, Status));
> +    return Status;



  SecureBoot structure leak. It is released below.

> +  }
> +
> +  //
> +  // Release resource.
> +  //
> +  JsonStructProtocol->DestoryStructure (
> +                        JsonStructProtocol,
> +                        (EFI_REST_JSON_STRUCTURE_HEADER *)SecureBoot
> +                        );
> +
> +  return (PropertyChanged ? EFI_SUCCESS : EFI_NOT_FOUND);
> +}
> +
> +/**
> +  Provision Redfish resource and upload data to Redfish service. This function
> +  checks OEM data and platform addendum data before sending data to Redfish service.
> +
> +  @param[in]   Private   Pointer to private data.
> +
> +  @retval EFI_SUCCESS              Provision Redfish resource successfully.
> +  @retval Others                   Some error happened.
> +
> +**/
> +EFI_STATUS
> +ProvisioningSecureBootResource (
> +  IN  REDFISH_RESOURCE_COMMON_PRIVATE  *Private
> +  )
> +{
> +  EFI_STATUS        Status;
> +  CHAR8             *Json;
> +  CHAR8             *JsonWithAddendum;
> +  REDFISH_RESPONSE  Response;
> +
> +  if (Private == NULL) {
> +    return EFI_INVALID_PARAMETER;
> +  }
> +
> +  ZeroMem (&Response, sizeof (REDFISH_RESPONSE));
> +  Json = NULL;
> +
> +  Status = ProvisioningSecureBootProperties (
> +             Private->JsonStructProtocol,
> +             SecureBootEmptyJson,
> +             NULL,
> +             REDFISH_DUMMY_CONFIG_LANG,
> +             TRUE,
> +             &Json
> +             );
> +  if (EFI_ERROR (Status)) {
> +    if (Status == EFI_NOT_FOUND) {
> +      DEBUG ((REDFISH_DEBUG_TRACE, "%a: provisioning existing resource for %s ignored. Nothing changed\n", __func__, REDFISH_DUMMY_CONFIG_LANG));
> +      Status = EFI_SUCCESS;
> +    } else {
> +      DEBUG ((DEBUG_ERROR, "%a: provisioning existing resource for %s failed: %r\n", __func__, REDFISH_DUMMY_CONFIG_LANG, Status));
> +    }
> +
> +    goto ON_RELEASE;
> +  }
> +
> +  //
> +  // Check and see if platform has OEM data or not
> +  //
> +  Status = RedfishGetOemData (
> +             Private->Uri,
> +             RESOURCE_SCHEMA,
> +             RESOURCE_SCHEMA_VERSION,
> +             Json,
> +             &JsonWithAddendum
> +             );
> +  if (!EFI_ERROR (Status) && (JsonWithAddendum != NULL)) {
> +    FreePool (Json);
> +    Json             = JsonWithAddendum;
> +    JsonWithAddendum = NULL;
> +  }
> +
> +  //
> +  // Check and see if platform has addendum data or not
> +  //
> +  Status = RedfishGetAddendumData (
> +             Private->Uri,
> +             RESOURCE_SCHEMA,
> +             RESOURCE_SCHEMA_VERSION,
> +             Json,
> +             &JsonWithAddendum
> +             );
> +  if (!EFI_ERROR (Status) && (JsonWithAddendum != NULL)) {
> +    FreePool (Json);
> +    Json             = JsonWithAddendum;
> +    JsonWithAddendum = NULL;
> +  }
> +
> +  DEBUG ((REDFISH_DEBUG_TRACE, "%a: provisioning existing resource for %s\n", __func__, REDFISH_DUMMY_CONFIG_LANG));
> +
> +  //
> +  // PATCH back to instance
> +  //
> +  Status = RedfishHttpPatchResource (Private->RedfishService, Private->Uri, Json, &Response);
> +  if (EFI_ERROR (Status)) {
> +    DEBUG ((DEBUG_ERROR, "%a: patch resource for %s failed: %r\n", __func__, REDFISH_DUMMY_CONFIG_LANG, Status));
> +  }
> +
> +ON_RELEASE:
> +
> +  if (Json != NULL) {
> +    FreePool (Json);
> +  }
> +
> +  RedfishHttpFreeResponse (&Response);
> +
> +  return Status;
> +}
> +
> +/**
> +  Provisioning redfish resource to Redfish service.
> +
> +  @param[in]   Private             Pointer to private data.
> +  @param[in]   ResourceExist       TRUE if resource exists, PUT method will be used.
> +                                   FALSE if resource does not exist POST method is used.


Actually ProvisioningSecureBootResource uses PATCH only.


> +
> +  @retval EFI_SUCCESS              Provision resource successfully.
> +  @retval Others                   Some error happened.
> +
> +**/
> +EFI_STATUS
> +RedfishProvisioningResourceCommon (
> +  IN     REDFISH_RESOURCE_COMMON_PRIVATE  *Private,
> +  IN     BOOLEAN                          ResourceExist
> +  )
> +{
> +  if (Private == NULL) {
> +    return EFI_INVALID_PARAMETER;
> +  }
> +
> +  return ProvisioningSecureBootResource (Private);
> +}
> +
> +/**
> +  Check resource from given Json data.
> +
> +  @param[in]   This                Pointer to REDFISH_RESOURCE_COMMON_PRIVATE instance.
> +  @param[in]   Json                The JSON data to check.
> +  @param[in]   HeaderEtag          The Etag string returned in HTTP header.
> +
> +  @retval EFI_SUCCESS              Check resource successfully.
> +  @retval Others                   Some error happened.
> +
> +**/
> +EFI_STATUS
> +RedfishCheckResourceCommon (
> +  IN     REDFISH_RESOURCE_COMMON_PRIVATE  *Private,
> +  IN     CHAR8                            *Json,
> +  IN     CHAR8                            *HeaderEtag OPTIONAL
> +  )
> +{
> +  UINTN       Index;
> +  EFI_STATUS  Status;
> +  UINTN       Count;
> +  EFI_STRING  Property;
> +
> +  if ((Private == NULL) || IS_EMPTY_STRING (Json)) {
> +    return EFI_INVALID_PARAMETER;
> +  }
> +
> +  //
> +  // Check ETAG to see if we need to check it
> +  //
> +  if (CheckEtag (Private->Uri, HeaderEtag, NULL)) {
> +    //
> +    // No change
> +    //
> +    DEBUG ((REDFISH_DEBUG_TRACE, "%a: ETAG: %s has no change, ignore check action\n", __func__, Private->Uri));
> +    return EFI_SUCCESS;
> +  }
> +
> +  Count = sizeof (mSecureBootSupportedAttributes) / sizeof (mSecureBootSupportedAttributes[0]);
> +  if (Count == 0) {
> +    return EFI_UNSUPPORTED;
> +  }
> +
> +  Status = EFI_SUCCESS;
> +  for (Index = 0; Index < Count; Index++) {
> +    Property = mSecureBootSupportedAttributes[Index];
> +    if (Property == NULL) {
> +      continue;
> +    }
> +
> +    DEBUG ((REDFISH_DEBUG_TRACE, "%a: [%d] check attribute for: %s\n", __func__, Index, Property));
> +    if (!MatchPropertyWithJsonContext (Property, Json)) {
> +      DEBUG ((REDFISH_DEBUG_TRACE, "%a: property is missing: %s\n", __func__, Property));
> +      Status = EFI_NOT_FOUND;
> +    }
> +  }
> +
> +  return Status;
> +}
> +
> +/**
> +  Update resource to Redfish service.
> +
> +  @param[in]   Private             Pointer to REDFISH_RESOURCE_COMMON_PRIVATE instance.
> +  @param[in]   Json                The JSON data to be updated.
> +
> +  @retval EFI_SUCCESS              Update resource successfully.
> +  @retval Others                   Some error happened.
> +
> +**/
> +EFI_STATUS
> +RedfishUpdateResourceCommon (
> +  IN     REDFISH_RESOURCE_COMMON_PRIVATE  *Private,
> +  IN     CHAR8                            *InputJson
> +  )
> +{
> +  EFI_STATUS        Status;
> +  CHAR8             *Json;
> +  CHAR8             *JsonWithAddendum;
> +  REDFISH_RESPONSE  Response;
> +
> +  if ((Private == NULL) || IS_EMPTY_STRING (InputJson)) {
> +    return EFI_INVALID_PARAMETER;
> +  }
> +
> +  ZeroMem (&Response, sizeof (REDFISH_RESPONSE));
> +  Json = NULL;
> +
> +  Status = ProvisioningSecureBootProperties (
> +             Private->JsonStructProtocol,
> +             SecureBootEmptyJson,
> +             NULL,
> +             REDFISH_DUMMY_CONFIG_LANG,
> +             TRUE,
> +             &Json
> +             );
> +  if (EFI_ERROR (Status)) {
> +    if (Status == EFI_NOT_FOUND) {
> +      DEBUG ((REDFISH_DEBUG_TRACE, "%a: update resource for %s ignored. Nothing changed\n", __func__, REDFISH_DUMMY_CONFIG_LANG));
> +      Status = EFI_SUCCESS;
> +    } else {
> +      DEBUG ((DEBUG_ERROR, "%a: update resource for %s failed: %r\n", __func__, REDFISH_DUMMY_CONFIG_LANG, Status));
> +    }
> +
> +    goto ON_RELEASE;
> +  }
> +
> +  //
> +  // Check and see if platform has OEM data or not
> +  //
> +  Status = RedfishGetOemData (
> +             Private->Uri,
> +             RESOURCE_SCHEMA,
> +             RESOURCE_SCHEMA_VERSION,
> +             Json,
> +             &JsonWithAddendum
> +             );
> +  if (!EFI_ERROR (Status) && (JsonWithAddendum != NULL)) {
> +    FreePool (Json);
> +    Json             = JsonWithAddendum;
> +    JsonWithAddendum = NULL;
> +  }
> +
> +  //
> +  // Check and see if platform has addendum data or not
> +  //
> +  Status = RedfishGetAddendumData (
> +             Private->Uri,
> +             RESOURCE_SCHEMA,
> +             RESOURCE_SCHEMA_VERSION,
> +             Json,
> +             &JsonWithAddendum
> +             );
> +  if (!EFI_ERROR (Status) && (JsonWithAddendum != NULL)) {
> +    FreePool (Json);
> +    Json             = JsonWithAddendum;
> +    JsonWithAddendum = NULL;
> +  }
> +
> +  DEBUG ((REDFISH_DEBUG_TRACE, "%a: update resource for %s\n", __func__, REDFISH_DUMMY_CONFIG_LANG));
> +
> +  //
> +  // PATCH back to instance
> +  //
> +  Status = RedfishHttpPatchResource (Private->RedfishService, Private->Uri, Json, &Response);
> +  if (EFI_ERROR (Status)) {
> +    DEBUG ((DEBUG_ERROR, "%a: patch resource for %s failed: %r\n", __func__, REDFISH_DUMMY_CONFIG_LANG, Status));
> +  }
> +
> +ON_RELEASE:
> +
> +  if (Json != NULL) {
> +    FreePool (Json);
> +  }
> +
> +  RedfishHttpFreeResponse (&Response);
> +
> +  return Status;
> +}
> +
> +/**
> +  Identify resource in given Json data.
> +
> +  @param[in]   Private             Pointer to REDFISH_RESOURCE_COMMON_PRIVATE instance.
> +  @param[in]   Json                The JSON to be identified.
> +
> +  @retval EFI_SUCCESS              Identify resource successfully.
> +  @retval Others                   Some error happened.
> +
> +**/
> +EFI_STATUS
> +RedfishIdentifyResourceCommon (
> +  IN     REDFISH_RESOURCE_COMMON_PRIVATE  *Private,
> +  IN     CHAR8                            *Json
> +  )
> +{
> +  BOOLEAN  Supported;
> +
> +  Supported = RedfishIdentifyResource (Private->Uri, Private->Json);
> +  if (Supported) {
> +    //
> +    // Keep URI and ConfigLang mapping
> +    //
> +    RedfishSetRedfishUri (REDFISH_DUMMY_CONFIG_LANG, Private->Uri);
> +  }
> +
> +  return (Supported ? EFI_SUCCESS : EFI_UNSUPPORTED);
> +}
> +
> +/**
> +  Handle Redfish resource in Uri.
> +
> +  @param[in]   Private             Pointer to REDFISH_RESOURCE_COMMON_PRIVATE instance.
> +  @param[in]   Uri                 URI to Redfish resource that we like to process.
> +
> +  @retval EFI_SUCCESS              Handle resource successfully.
> +  @retval Others                   Some error happened.
> +
> +**/
> +EFI_STATUS
> +HandleResource (
> +  IN  REDFISH_RESOURCE_COMMON_PRIVATE  *Private,
> +  IN  EFI_STRING                       Uri
> +  )
> +{
> +  EFI_STATUS           Status;
> +  REDFISH_SCHEMA_INFO  SchemaInfo;
> +  EFI_STRING           ConfigLang;
> +
> +  if ((Private == NULL) || IS_EMPTY_STRING (Uri)) {
> +    return EFI_INVALID_PARAMETER;
> +  }
> +
> +  //
> +  // Resource match
> +  //
> +
> +  DEBUG ((REDFISH_DEBUG_TRACE, "%a: process resource for: %s\n", __func__, Uri));
> +
> +  Status = GetRedfishSchemaInfo (Private->RedfishService, Private->JsonStructProtocol, Uri, NULL, &SchemaInfo);
> +  if (EFI_ERROR (Status)) {
> +    DEBUG ((DEBUG_ERROR, "%a: failed to get schema information from: %s %r\n", __func__, Uri, Status));
> +    return Status;
> +  }
> +
> +  //
> +  // Check and see if this is target resource that we want to handle.
> +  // Some resource is handled by other provider so we have to make sure this first.
> +  //
> +  DEBUG ((REDFISH_DEBUG_TRACE, "%a: Identify for %s\n", __func__, Uri));
> +  ConfigLang = RedfishGetConfigLanguage (Uri);
> +  if (ConfigLang == NULL) {
> +    Status = EdkIIRedfishResourceConfigIdentify (&SchemaInfo, Uri, NULL, Private->InformationExchange);
> +    if (EFI_ERROR (Status)) {
> +      if (Status == EFI_UNSUPPORTED) {
> +        DEBUG ((REDFISH_DEBUG_TRACE, "%a: \"%s\" is not handled by us\n", __func__, Uri));
> +        return EFI_SUCCESS;
> +      } else if (Status == EFI_NOT_FOUND) {
> +        DEBUG ((REDFISH_DEBUG_TRACE, "%a: \"%s\" has nothing to handle\n", __func__, Uri));
> +        return EFI_SUCCESS;
> +      }
> +
> +      DEBUG ((DEBUG_ERROR, "%a: fail to identify resource: \"%s\": %r\n", __func__, Uri, Status));
> +      return Status;
> +    }
> +  } else {
> +    DEBUG ((REDFISH_DEBUG_TRACE, "%a: history record found: %s\n", __func__, ConfigLang));
> +    FreePool (ConfigLang);
> +  }
> +
> +  //
> +  // Check and see if target property exist or not even when collection member exists.
> +  // If not, we sill do provision.

%s/sill/still

> +  //
> +  DEBUG ((REDFISH_DEBUG_TRACE, "%a Check for %s\n", __func__, Uri));
> +  Status = EdkIIRedfishResourceConfigCheck (&SchemaInfo, Uri, NULL);
> +  if (EFI_ERROR (Status)) {
> +    if (Status == EFI_UNSUPPORTED) {
> +      DEBUG ((REDFISH_DEBUG_TRACE, "%a: \"%s\" is not handled by us\n", __func__, Uri));
> +      return EFI_SUCCESS;
> +    }
> +
> +    //
> +    // The target property does not exist, do the provision to create property.
> +    //
> +    DEBUG ((REDFISH_DEBUG_TRACE, "%a provision for %s\n", __func__, Uri));
> +    Status = EdkIIRedfishResourceConfigProvisioning (&SchemaInfo, Uri, NULL, Private->InformationExchange, FALSE);
> +    if (EFI_ERROR (Status)) {
> +      DEBUG ((DEBUG_ERROR, "%a: failed to provision with GET mode: %r\n", __func__, Status));
> +    }
> +
> +    DEBUG ((REDFISH_DEBUG_TRACE, "%a: process resource for: %s finished\n", __func__, Uri));
> +
> +    return Status;
> +  }
> +
> +  //
> +  // Consume first.
> +  //
> +  DEBUG ((REDFISH_DEBUG_TRACE, "%a consume for %s\n", __func__, Uri));
> +  Status = EdkIIRedfishResourceConfigConsume (&SchemaInfo, Uri, NULL);
> +  if (EFI_ERROR (Status)) {
> +    DEBUG ((DEBUG_ERROR, "%a: failed to consume resource for: %s: %r\n", __func__, Uri, Status));
> +  }
> +
> +  //
> +  // Patch.
> +  //
> +  DEBUG ((REDFISH_DEBUG_TRACE, "%a update for %s\n", __func__, Uri));
> +  Status = EdkIIRedfishResourceConfigUpdate (&SchemaInfo, Uri, NULL);
> +  if (EFI_ERROR (Status)) {
> +    DEBUG ((DEBUG_ERROR, "%a: failed to update resource for: %s: %r\n", __func__, Uri, Status));
> +  }
> +
> +  DEBUG ((REDFISH_DEBUG_TRACE, "%a: process resource for: %s finished\n", __func__, Uri));
> +
> +  return Status;
> +}
> diff --git a/RedfishClientPkg/Features/SecureBoot/v1_1_0/Dxe/SecureBootDxe.c b/RedfishClientPkg/Features/SecureBoot/v1_1_0/Dxe/SecureBootDxe.c
> new file mode 100644
> index 000000000..a0f4f3d14
> --- /dev/null
> +++ b/RedfishClientPkg/Features/SecureBoot/v1_1_0/Dxe/SecureBootDxe.c
> @@ -0,0 +1,808 @@
> +/** @file
> +  Redfish feature driver implementation - SecureBoot
> +
> +  (C) Copyright 2020-2022 Hewlett Packard Enterprise Development LP<BR>
> +  Copyright (c) 2023, NVIDIA CORPORATION & AFFILIATES. All rights reserved.
> +
> +  SPDX-License-Identifier: BSD-2-Clause-Patent
> +
> +**/
> +
> +#include "../Common/SecureBootCommon.h"
> +
> +extern REDFISH_RESOURCE_COMMON_PRIVATE  *mRedfishResourcePrivate;
> +extern EFI_HANDLE                       mRedfishResourceConfigProtocolHandle;
> +
> +EFI_STATUS
> +HandleResource (
> +  IN  REDFISH_RESOURCE_COMMON_PRIVATE  *Private,
> +  IN  EFI_STRING                       Uri
> +  );
> +
> +/**
> +  Provisioning redfish resource by given URI.
> +
> +  @param[in]   This                Pointer to EFI_HP_REDFISH_HII_PROTOCOL instance.
> +  @param[in]   Uri                 Target URI to create resource.
> +  @param[in]   PostMode            TRUE if the resource does not exist, post method is used.
> +                                   FALSE if the resource exist but property is missing, put method is used.
> +
> +  @retval EFI_SUCCESS              Value is returned successfully.
> +  @retval Others                   Some error happened.
> +
> +**/
> +EFI_STATUS
> +EFIAPI
> +RedfishResourceProvisioningResource (
> +  IN     EDKII_REDFISH_RESOURCE_CONFIG_PROTOCOL  *This,
> +  IN     EFI_STRING                              Uri,
> +  IN     BOOLEAN                                 PostMode
> +  )
> +{
> +  REDFISH_RESOURCE_COMMON_PRIVATE  *Private;
> +  EFI_STATUS                       Status;
> +  REDFISH_RESPONSE                 Response;
> +
> +  if ((This == NULL) || IS_EMPTY_STRING (Uri)) {
> +    return EFI_INVALID_PARAMETER;
> +  }
> +
> +  DEBUG ((REDFISH_DEBUG_TRACE, "%a: provisioning in %s mode\n", __func__, (PostMode ? L"POST" : L"PATCH")));


This message conflicts with PostMode parameter description.


> +
> +  ZeroMem (&Response, sizeof (REDFISH_RESPONSE));
> +  Private = REDFISH_RESOURCE_COMMON_PRIVATE_DATA_FROM_RESOURCE_PROTOCOL (This);
> +
> +  if (Private->RedfishService == NULL) {
> +    return EFI_NOT_READY;
> +  }
> +
> +  Status = RedfishHttpGetResource (Private->RedfishService, Uri, NULL, &Response, TRUE);
> +  if (EFI_ERROR (Status)) {
> +    DEBUG ((DEBUG_ERROR, "%a: get resource from: %s failed\n", __func__, Uri));
> +    return Status;
> +  }
> +
> +  Private->Uri     = Uri;
> +  Private->Payload = Response.Payload;
> +  ASSERT (Private->Payload != NULL);
> +
> +  Status = RedfishProvisioningResourceCommon (Private, !PostMode);
> +  if (EFI_ERROR (Status)) {
> +    DEBUG ((DEBUG_ERROR, "%a: failed to provision resource to: %s: %r\n", __func__, Uri, Status));
> +  } else {
> +    //
> +    // Get latest ETag on URI and keep it in variable.
> +    //
> +    SetEtagFromUri (Private->RedfishService, Private->Uri, TRUE);
> +  }
> +
> +  //
> +  // Release resource
> +  //
> +  RedfishHttpFreeResponse (&Response);
> +  Private->Payload = NULL;
> +
> +  return Status;
> +}
> +
> +/**
> +  Consume resource from given URI.
> +
> +  @param[in]   This                Pointer to EFI_HP_REDFISH_HII_PROTOCOL instance.
> +  @param[in]   Uri                 The target URI to consume.
> +
> +  @retval EFI_SUCCESS              Value is returned successfully.
> +  @retval Others                   Some error happened.
> +
> +**/
> +EFI_STATUS
> +EFIAPI
> +RedfishResourceConsumeResource (
> +  IN     EDKII_REDFISH_RESOURCE_CONFIG_PROTOCOL  *This,
> +  IN     EFI_STRING                              Uri
> +  )
> +{
> +  REDFISH_RESOURCE_COMMON_PRIVATE  *Private;
> +  EFI_STATUS                       Status;
> +  REDFISH_RESPONSE                 Response;
> +  EFI_STRING                       PendingSettingUri;
> +  REDFISH_RESPONSE                 PendingSettingResponse;
> +  REDFISH_RESPONSE                 *ExpectedResponse;
> +  CHAR8                            *Etag;
> +
> +  if ((This == NULL) || IS_EMPTY_STRING (Uri)) {
> +    return EFI_INVALID_PARAMETER;
> +  }
> +
> +  ZeroMem (&Response, sizeof (REDFISH_RESPONSE));
> +  ZeroMem (&PendingSettingResponse, sizeof (REDFISH_RESPONSE));
> +  Private = REDFISH_RESOURCE_COMMON_PRIVATE_DATA_FROM_RESOURCE_PROTOCOL (This);
> +
> +  if (Private->RedfishService == NULL) {
> +    return EFI_NOT_READY;
> +  }
> +
> +  Status = RedfishHttpGetResource (Private->RedfishService, Uri, NULL, &Response, TRUE);
> +  if (EFI_ERROR (Status)) {
> +    DEBUG ((DEBUG_ERROR, "%a: get resource from: %s failed\n", __func__, Uri));
> +    return Status;
> +  }
> +
> +  //
> +  // Check and see if "@Redfish.Settings" exist or not.
> +  //
> +  PendingSettingUri = NULL;
> +  Status            = GetPendingSettings (
> +                        Private->RedfishService,
> +                        Response.Payload,
> +                        &PendingSettingResponse,
> +                        &PendingSettingUri
> +                        );
> +  if (!EFI_ERROR (Status)) {
> +    DEBUG ((REDFISH_DEBUG_TRACE, "%a: @Redfish.Settings found: %s\n", __func__, PendingSettingUri));
> +    Private->Uri     = PendingSettingUri;
> +    ExpectedResponse = &PendingSettingResponse;
> +  } else {
> +    Private->Uri     = Uri;
> +    ExpectedResponse = &Response;
> +  }
> +
> +  Private->Payload = ExpectedResponse->Payload;
> +  ASSERT (Private->Payload != NULL);
> +
> +  Private->Json = JsonDumpString (RedfishJsonInPayload (Private->Payload), EDKII_JSON_COMPACT);
> +  ASSERT (Private->Json != NULL);
> +
> +  //
> +  // Searching for etag in HTTP response header
> +  //
> +  Etag   = NULL;
> +  Status = GetHttpResponseEtag (ExpectedResponse, &Etag);
> +  if (EFI_ERROR (Status)) {
> +    DEBUG ((DEBUG_ERROR, "%a: failed to get ETag from HTTP header\n", __func__));
> +  }
> +
> +  Status = RedfishConsumeResourceCommon (Private, Private->Json, Etag);
> +  if (EFI_ERROR (Status)) {
> +    DEBUG ((DEBUG_ERROR, "%a: failed to consume resource from: %s: %r\n", __func__, Private->Uri, Status));
> +  }
> +
> +  //
> +  // Release resource
> +  //
> +  RedfishHttpFreeResponse (&Response);
> +  RedfishHttpFreeResponse (&PendingSettingResponse);
> +  Private->Payload = NULL;
> +
> +  if (Private->Json != NULL) {
> +    FreePool (Private->Json);
> +    Private->Json = NULL;
> +  }
> +
> +  if (Etag != NULL) {
> +    FreePool (Etag);
> +  }
> +
> +  if (PendingSettingUri != NULL) {
> +    FreePool (PendingSettingUri);
> +  }
> +
> +  return Status;
> +}
> +
> +/**
> +  Get information about this protocol.
> +
> +  @param[in]   This                Pointer to EFI_HP_REDFISH_HII_PROTOCOL instance.
> +  @param[out]  Schema              Supported schema.
> +  @param[out]  Major               Supported major number.
> +  @param[out]  Minor               Supported minor number.
> +  @param[out]  Errata              Supported errata number.
> +
> +  @retval EFI_SUCCESS              Value is returned successfully.
> +  @retval Others                   Some error happened.
> +
> +**/
> +EFI_STATUS
> +EFIAPI
> +RedfishResourceGetInfo (
> +  IN     EDKII_REDFISH_RESOURCE_CONFIG_PROTOCOL  *This,
> +  OUT    REDFISH_SCHEMA_INFO                     *Info
> +  )
> +{
> +  if ((This == NULL) || (Info == NULL)) {
> +    return EFI_INVALID_PARAMETER;
> +  }
> +
> +  AsciiStrCpyS (Info->Schema, REDFISH_SCHEMA_STRING_SIZE, RESOURCE_SCHEMA);
> +  AsciiStrCpyS (Info->Major, REDFISH_SCHEMA_VERSION_SIZE, RESOURCE_SCHEMA_MAJOR);
> +  AsciiStrCpyS (Info->Minor, REDFISH_SCHEMA_VERSION_SIZE, RESOURCE_SCHEMA_MINOR);
> +  AsciiStrCpyS (Info->Errata, REDFISH_SCHEMA_VERSION_SIZE, RESOURCE_SCHEMA_ERRATA);
> +
> +  return EFI_SUCCESS;
> +}
> +
> +/**
> +  Update resource to given URI.
> +
> +  @param[in]   This                Pointer to EFI_HP_REDFISH_HII_PROTOCOL instance.
> +  @param[in]   Uri                 The target URI to consume.
> +
> +  @retval EFI_SUCCESS              Value is returned successfully.
> +  @retval Others                   Some error happened.
> +
> +**/
> +EFI_STATUS
> +EFIAPI
> +RedfishResourceUpdate (
> +  IN     EDKII_REDFISH_RESOURCE_CONFIG_PROTOCOL  *This,
> +  IN     EFI_STRING                              Uri
> +  )
> +{
> +  REDFISH_RESOURCE_COMMON_PRIVATE  *Private;
> +  EFI_STATUS                       Status;
> +  REDFISH_RESPONSE                 Response;
> +
> +  if ((This == NULL) || IS_EMPTY_STRING (Uri)) {
> +    return EFI_INVALID_PARAMETER;
> +  }
> +
> +  ZeroMem (&Response, sizeof (REDFISH_RESPONSE));
> +  Private = REDFISH_RESOURCE_COMMON_PRIVATE_DATA_FROM_RESOURCE_PROTOCOL (This);
> +
> +  if (Private->RedfishService == NULL) {
> +    return EFI_NOT_READY;
> +  }
> +
> +  Status = RedfishHttpGetResource (Private->RedfishService, Uri, NULL, &Response, TRUE);
> +  if (EFI_ERROR (Status)) {
> +    DEBUG ((DEBUG_ERROR, "%a: get resource from: %s failed\n", __func__, Uri));
> +    return Status;
> +  }
> +
> +  Private->Uri     = Uri;
> +  Private->Payload = Response.Payload;
> +  ASSERT (Private->Payload != NULL);
> +
> +  Private->Json = JsonDumpString (RedfishJsonInPayload (Private->Payload), EDKII_JSON_COMPACT);
> +  ASSERT (Private->Json != NULL);
> +
> +  Status = RedfishUpdateResourceCommon (Private, Private->Json);
> +  if (EFI_ERROR (Status)) {
> +    DEBUG ((DEBUG_ERROR, "%a: failed to update resource to: %s: %r\n", __func__, Uri, Status));
> +  } else {
> +    //
> +    // Get latest ETag on URI and keep it in variable.
> +    //
> +    SetEtagFromUri (Private->RedfishService, Private->Uri, TRUE);
> +  }
> +
> +  //
> +  // Release resource
> +  //
> +  RedfishHttpFreeResponse (&Response);
> +  Private->Payload = NULL;
> +
> +  if (Private->Json != NULL) {
> +    FreePool (Private->Json);
> +    Private->Json = NULL;
> +  }
> +
> +  return Status;
> +}
> +
> +/**
> +  Check resource on given URI.
> +
> +  @param[in]   This                Pointer to EFI_HP_REDFISH_HII_PROTOCOL instance.
> +  @param[in]   Uri                 The target URI to consume.
> +
> +  @retval EFI_SUCCESS              Value is returned successfully.
> +  @retval Others                   Some error happened.
> +
> +**/
> +EFI_STATUS
> +EFIAPI
> +RedfishResourceCheck (
> +  IN     EDKII_REDFISH_RESOURCE_CONFIG_PROTOCOL  *This,
> +  IN     EFI_STRING                              Uri
> +  )
> +{
> +  REDFISH_RESOURCE_COMMON_PRIVATE  *Private;
> +  EFI_STATUS                       Status;
> +  REDFISH_RESPONSE                 Response;
> +  CHAR8                            *Etag;
> +
> +  if ((This == NULL) || IS_EMPTY_STRING (Uri)) {
> +    return EFI_INVALID_PARAMETER;
> +  }
> +
> +  ZeroMem (&Response, sizeof (REDFISH_RESPONSE));
> +  Private = REDFISH_RESOURCE_COMMON_PRIVATE_DATA_FROM_RESOURCE_PROTOCOL (This);
> +
> +  if (Private->RedfishService == NULL) {
> +    return EFI_NOT_READY;
> +  }
> +
> +  Status = RedfishHttpGetResource (Private->RedfishService, Uri, NULL, &Response, TRUE);
> +  if (EFI_ERROR (Status)) {
> +    DEBUG ((DEBUG_ERROR, "%a: get resource from: %s failed\n", __func__, Uri));
> +    return Status;
> +  }
> +
> +  Private->Uri     = Uri;
> +  Private->Payload = Response.Payload;
> +  ASSERT (Private->Payload != NULL);
> +
> +  Private->Json = JsonDumpString (RedfishJsonInPayload (Private->Payload), EDKII_JSON_COMPACT);
> +  ASSERT (Private->Json != NULL);
> +
> +  //
> +  // Find etag in HTTP response header
> +  //
> +  Etag   = NULL;
> +  Status = GetHttpResponseEtag (&Response, &Etag);
> +  if (EFI_ERROR (Status)) {
> +    DEBUG ((DEBUG_ERROR, "%a: failed to get ETag from HTTP header\n", __func__));
> +  }
> +
> +  Status = RedfishCheckResourceCommon (Private, Private->Json, Etag);
> +  if (EFI_ERROR (Status)) {
> +    DEBUG ((DEBUG_ERROR, "%a: failed to check resource from: %s: %r\n", __func__, Uri, Status));
> +  }
> +
> +  //
> +  // Release resource
> +  //
> +  if (Etag != NULL) {
> +    FreePool (Etag);
> +  }
> +
> +  RedfishHttpFreeResponse (&Response);
> +  Private->Payload = NULL;
> +
> +  if (Private->Json != NULL) {
> +    FreePool (Private->Json);
> +    Private->Json = NULL;
> +  }
> +
> +  return Status;
> +}
> +
> +/**
> +  Identify resource on given URI.
> +
> +  @param[in]   This                Pointer to EDKII_REDFISH_RESOURCE_CONFIG_PROTOCOL instance.
> +  @param[in]   Uri                 The target URI to consume.
> +
> +  @retval EFI_SUCCESS              This is target resource which we want to handle.
> +  @retval EFI_UNSUPPORTED          This is not the target resource.
> +  @retval Others                   Some error happened.
> +
> +**/
> +EFI_STATUS
> +EFIAPI
> +RedfishResourceIdentify (
> +  IN     EDKII_REDFISH_RESOURCE_CONFIG_PROTOCOL  *This,
> +  IN     EFI_STRING                              Uri
> +  )
> +{
> +  REDFISH_RESOURCE_COMMON_PRIVATE  *Private;
> +  EFI_STATUS                       Status;
> +  REDFISH_RESPONSE                 Response;
> +
> +  if ((This == NULL) || IS_EMPTY_STRING (Uri)) {
> +    return EFI_INVALID_PARAMETER;
> +  }
> +
> +  ZeroMem (&Response, sizeof (REDFISH_RESPONSE));
> +  Private = REDFISH_RESOURCE_COMMON_PRIVATE_DATA_FROM_RESOURCE_PROTOCOL (This);
> +
> +  if (Private->RedfishService == NULL) {
> +    return EFI_NOT_READY;
> +  }
> +
> +  Status = RedfishHttpGetResource (Private->RedfishService, Uri, NULL, &Response, TRUE);
> +  if (EFI_ERROR (Status)) {
> +    DEBUG ((DEBUG_ERROR, "%a: get resource from: %s failed\n", __func__, Uri));
> +    return Status;
> +  }
> +
> +  Private->Uri     = Uri;
> +  Private->Payload = Response.Payload;
> +  ASSERT (Private->Payload != NULL);
> +
> +  Private->Json = JsonDumpString (RedfishJsonInPayload (Private->Payload), EDKII_JSON_COMPACT);
> +  ASSERT (Private->Json != NULL);
> +
> +  Status = RedfishIdentifyResourceCommon (Private, Private->Json);
> +  if (EFI_ERROR (Status)) {
> +    DEBUG ((DEBUG_ERROR, "%a: identify %s failed: %r\n", __func__, Uri, Status));
> +  }
> +
> +  //
> +  // Release resource
> +  //
> +  RedfishHttpFreeResponse (&Response);
> +  Private->Payload = NULL;
> +
> +  if (Private->Json != NULL) {
> +    FreePool (Private->Json);
> +    Private->Json = NULL;
> +  }
> +
> +  return Status;
> +}
> +
> +EDKII_REDFISH_RESOURCE_CONFIG_PROTOCOL  mRedfishResourceConfig = {
> +  RedfishResourceProvisioningResource,
> +  RedfishResourceConsumeResource,
> +  RedfishResourceUpdate,
> +  RedfishResourceCheck,
> +  RedfishResourceIdentify,
> +  RedfishResourceGetInfo
> +};
> +
> +/**
> +  Initialize a Redfish configure handler.
> +
> +  This function will be called by the Redfish config driver to initialize each Redfish configure
> +  handler.
> +
> +  @param[in]   This                     Pointer to EDKII_REDFISH_CONFIG_HANDLER_PROTOCOL instance.
> +  @param[in]   RedfishConfigServiceInfo Redfish service information.
> +
> +  @retval EFI_SUCCESS                  The handler has been initialized successfully.
> +  @retval EFI_DEVICE_ERROR             Failed to create or configure the REST EX protocol instance.
> +  @retval EFI_ALREADY_STARTED          This handler has already been initialized.
> +  @retval Other                        Error happens during the initialization.
> +
> +**/
> +EFI_STATUS
> +EFIAPI
> +RedfishResourceInit (
> +  IN  EDKII_REDFISH_CONFIG_HANDLER_PROTOCOL  *This,
> +  IN  REDFISH_CONFIG_SERVICE_INFORMATION     *RedfishConfigServiceInfo
> +  )
> +{
> +  REDFISH_RESOURCE_COMMON_PRIVATE  *Private;
> +
> +  Private = REDFISH_RESOURCE_COMMON_PRIVATE_DATA_FROM_CONFIG_PROTOCOL (This);
> +
> +  Private->RedfishService = RedfishCreateService (RedfishConfigServiceInfo);
> +  if (Private->RedfishService == NULL) {
> +    return EFI_DEVICE_ERROR;
> +  }
> +
> +  return EFI_SUCCESS;
> +}
> +
> +/**
> +  Stop a Redfish configure handler.
> +
> +  @param[in]   This                Pointer to EDKII_REDFISH_CONFIG_HANDLER_PROTOCOL instance.
> +
> +  @retval EFI_SUCCESS              This handler has been stoped successfully.
> +  @retval Others                   Some error happened.
> +
> +**/
> +EFI_STATUS
> +EFIAPI
> +RedfishResourceStop (
> +  IN  EDKII_REDFISH_CONFIG_HANDLER_PROTOCOL  *This
> +  )
> +{
> +  REDFISH_RESOURCE_COMMON_PRIVATE  *Private;
> +
> +  Private = REDFISH_RESOURCE_COMMON_PRIVATE_DATA_FROM_CONFIG_PROTOCOL (This);
> +
> +  if (Private->Event != NULL) {
> +    gBS->CloseEvent (Private->Event);
> +    Private->Event = NULL;
> +  }
> +
> +  if (Private->RedfishService != NULL) {
> +    RedfishCleanupService (Private->RedfishService);
> +    Private->RedfishService = NULL;
> +  }
> +
> +  return EFI_SUCCESS;
> +}
> +
> +EDKII_REDFISH_CONFIG_HANDLER_PROTOCOL  mRedfishConfigHandler = {
> +  RedfishResourceInit,
> +  RedfishResourceStop
> +};
> +
> +/**
> +  Callback function when gEfiRestJsonStructureProtocolGuid is installed.
> +
> +  @param[in] Event    Event whose notification function is being invoked.
> +  @param[in] Context  Pointer to the notification function's context.
> +**/
> +VOID
> +EFIAPI
> +EfiRestJsonStructureProtocolIsReady (
> +  IN  EFI_EVENT  Event,
> +  IN  VOID       *Context
> +  )
> +{
> +  EFI_STATUS  Status;
> +
> +  if (mRedfishResourcePrivate == NULL) {
> +    return;
> +  }
> +
> +  if (mRedfishResourcePrivate->JsonStructProtocol != NULL) {
> +    return;
> +  }
> +
> +  Status = gBS->LocateProtocol (
> +                  &gEfiRestJsonStructureProtocolGuid,
> +                  NULL,
> +                  (VOID **)&mRedfishResourcePrivate->JsonStructProtocol
> +                  );
> +  if (EFI_ERROR (Status)) {
> +    DEBUG ((DEBUG_ERROR, "%a: failed to locate gEfiRestJsonStructureProtocolGuid: %r\n", __func__, Status));
> +  }
> +
> +  gBS->CloseEvent (Event);
> +}
> +
> +/**
> +  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
> +RedfishResourceUnload (
> +  IN EFI_HANDLE  ImageHandle
> +  )
> +{
> +  EFI_STATUS                             Status;
> +  EDKII_REDFISH_CONFIG_HANDLER_PROTOCOL  *ConfigHandler;
> +
> +  if (mRedfishResourcePrivate == NULL) {
> +    return EFI_NOT_READY;
> +  }
> +
> +  ConfigHandler = NULL;
> +
> +  //
> +  // Firstly, find ConfigHandler Protocol interface in this ImageHandle.
> +  //
> +  Status = gBS->OpenProtocol (
> +                  ImageHandle,
> +                  &gEdkIIRedfishConfigHandlerProtocolGuid,
> +                  (VOID **)&ConfigHandler,
> +                  NULL,
> +                  NULL,
> +                  EFI_OPEN_PROTOCOL_BY_HANDLE_PROTOCOL
> +                  );
> +  if (EFI_ERROR (Status) || (ConfigHandler == NULL)) {
> +    return Status;
> +  }
> +
> +  ConfigHandler->Stop (ConfigHandler);
> +
> +  //
> +  // Last, uninstall ConfigHandler Protocol and resource protocol.
> +  //
> +  Status = gBS->UninstallMultipleProtocolInterfaces (
> +                  ImageHandle,
> +                  &gEdkIIRedfishConfigHandlerProtocolGuid,
> +                  ConfigHandler,
> +                  &gEdkIIRedfishResourceConfigProtocolGuid,
> +                  &mRedfishResourcePrivate->RedfishResourceConfig,
> +                  NULL
> +                  );
> +
> +  FreePool (mRedfishResourcePrivate);
> +  mRedfishResourcePrivate = NULL;
> +
> +  return Status;
> +}
> +
> +/**
> +  The callback function provided by Redfish Feature driver.
> +
> +  @param[in]     This                Pointer to EDKII_REDFISH_FEATURE_PROTOCOL instance.
> +  @param[in]     FeatureAction       The action Redfish feature driver should take.
> +  @param[in]     Uri                 The collection URI.
> +  @param[in]     Context             The context of Redfish feature driver.
> +  @param[in,out] InformationExchange The pointer to RESOURCE_INFORMATION_EXCHANGE
> +
> +  @retval EFI_SUCCESS              Redfish feature driver callback is executed successfully.
> +  @retval Others                   Some errors happened.
> +
> +  @retval EFI_SUCCESS              Redfish feature driver callback is executed successfully.
> +  @retval Others                   Some errors happened.
> +
> +**/
> +EFI_STATUS
> +EFIAPI
> +RedfishExternalResourceResourceFeatureCallback (
> +  IN     EDKII_REDFISH_FEATURE_PROTOCOL  *This,
> +  IN     FEATURE_CALLBACK_ACTION         FeatureAction,
> +  IN     VOID                            *Context,
> +  IN OUT RESOURCE_INFORMATION_EXCHANGE   *InformationExchange
> +  )
> +{
> +  EFI_STATUS                       Status;
> +  REDFISH_SERVICE                  RedfishService;
> +  REDFISH_RESOURCE_COMMON_PRIVATE  *Private;
> +  EFI_STRING                       ResourceUri;
> +  EFI_STRING                       SecureBootUri;
> +
> +  if (FeatureAction != CallbackActionStartOperation) {
> +    return EFI_UNSUPPORTED;
> +  }
> +
> +  Private = (REDFISH_RESOURCE_COMMON_PRIVATE *)Context;
> +
> +  RedfishService = Private->RedfishService;
> +  if (RedfishService == NULL) {
> +    DEBUG ((DEBUG_ERROR, "%a: no Redfish service configured\n", __func__));
> +    return EFI_NOT_READY;
> +  }
> +
> +  //
> +  // Save in private structure.
> +  //
> +  Private->InformationExchange = InformationExchange;
> +
> +  //
> +  // Find Redfish version on Redfish ser
> +  //
> +  Private->RedfishVersion = RedfishGetVersion (RedfishService);
> +
> +  //
> +  // Create the full URI from Redfish service root.
> +  //
> +  ResourceUri = (EFI_STRING)AllocateZeroPool (MAX_URI_LENGTH * sizeof (CHAR16));
> +  if (ResourceUri == NULL) {
> +    DEBUG ((DEBUG_ERROR, "%a: Fail to allocate memory for full URI.\n", __func__));
> +    return EFI_OUT_OF_RESOURCES;
> +  }
> +
> +  StrCatS (ResourceUri, MAX_URI_LENGTH, Private->RedfishVersion);
> +  StrCatS (ResourceUri, MAX_URI_LENGTH, InformationExchange->SendInformation.FullUri);
> +
> +  //
> +  // Initialize collection path
> +  //
> +  SecureBootUri = RedfishGetUri (ResourceUri);
> +  if (SecureBootUri == NULL) {
> +    ASSERT (FALSE);
> +    FreePool (ResourceUri);
> +    return EFI_OUT_OF_RESOURCES;
> +  }
> +
> +  Status = HandleResource (Private, SecureBootUri);
> +  if (EFI_ERROR (Status)) {
> +    DEBUG ((DEBUG_ERROR, "%a: process external resource: %s failed: %r\n", __func__, SecureBootUri, Status));
> +  }
> +
> +  FreePool (SecureBootUri);
> +  FreePool (ResourceUri);
> +  return Status;
> +}
> +
> +/**
> +  Callback function when gEdkIIRedfishFeatureProtocolGuid is installed.
> +
> +  @param[in] Event    Event whose notification function is being invoked.
> +  @param[in] Context  Pointer to the notification function's context.
> +**/
> +VOID
> +EFIAPI
> +EdkIIRedfishFeatureProtocolIsReady (
> +  IN  EFI_EVENT  Event,
> +  IN  VOID       *Context
> +  )
> +{
> +  EFI_STATUS                      Status;
> +  EDKII_REDFISH_FEATURE_PROTOCOL  *FeatureProtocol;
> +
> +  if (mRedfishResourcePrivate == NULL) {
> +    return;
> +  }
> +
> +  if (mRedfishResourcePrivate->FeatureProtocol != NULL) {
> +    return;
> +  }
> +
> +  Status = gBS->LocateProtocol (
> +                  &gEdkIIRedfishFeatureProtocolGuid,
> +                  NULL,
> +                  (VOID **)&FeatureProtocol
> +                  );
> +  if (EFI_ERROR (Status)) {
> +    DEBUG ((DEBUG_ERROR, "%a: failed to locate gEdkIIRedfishFeatureProtocolGuid: %r\n", __func__, Status));
> +    gBS->CloseEvent (Event);
> +    return;
> +  }
> +
> +  Status = FeatureProtocol->Register (
> +                              FeatureProtocol,
> +                              REDFISH_MANAGED_URI,
> +                              RedfishExternalResourceResourceFeatureCallback,
> +                              (VOID *)mRedfishResourcePrivate
> +                              );
> +  if (EFI_ERROR (Status)) {
> +    DEBUG ((DEBUG_ERROR, "%a: failed to register %s: %r\n", __func__, REDFISH_MANAGED_URI, Status));
> +  }
> +
> +  mRedfishResourcePrivate->FeatureProtocol = FeatureProtocol;
> +
> +  gBS->CloseEvent (Event);
> +}
> +
> +/**
> +  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. It initialize the global variables and
> +  publish the driver binding protocol.
> +
> +  @param[in]   ImageHandle      The firmware allocated handle for the UEFI image.
> +  @param[in]   SystemTable      A pointer to the EFI System Table.
> +
> +  @retval EFI_SUCCESS           The operation completed successfully.
> +  @retval EFI_ACCESS_DENIED     EFI_ISCSI_INITIATOR_NAME_PROTOCOL was installed unexpectedly.
> +  @retval Others                Other errors as indicated.
> +**/
> +EFI_STATUS
> +EFIAPI
> +RedfishResourceEntryPoint (
> +  IN EFI_HANDLE        ImageHandle,
> +  IN EFI_SYSTEM_TABLE  *SystemTable
> +  )
> +{
> +  EFI_STATUS  Status;
> +  VOID        *Registration;
> +
> +  if (mRedfishResourcePrivate != NULL) {
> +    return EFI_ALREADY_STARTED;
> +  }
> +
> +  mRedfishResourceConfigProtocolHandle = ImageHandle;
> +
> +  mRedfishResourcePrivate = AllocateZeroPool (sizeof (REDFISH_RESOURCE_COMMON_PRIVATE));
> +  CopyMem (&mRedfishResourcePrivate->ConfigHandler, &mRedfishConfigHandler, sizeof (EDKII_REDFISH_CONFIG_HANDLER_PROTOCOL));
> +  CopyMem (&mRedfishResourcePrivate->RedfishResourceConfig, &mRedfishResourceConfig, sizeof (EDKII_REDFISH_RESOURCE_CONFIG_PROTOCOL));
> +
> +  //
> +  // Publish config handler protocol and resource protocol.
> +  //
> +  Status = gBS->InstallMultipleProtocolInterfaces (
> +                  &ImageHandle,
> +                  &gEdkIIRedfishConfigHandlerProtocolGuid,
> +                  &mRedfishResourcePrivate->ConfigHandler,
> +                  &gEdkIIRedfishResourceConfigProtocolGuid,
> +                  &mRedfishResourcePrivate->RedfishResourceConfig,
> +                  NULL
> +                  );
> +
> +  EfiCreateProtocolNotifyEvent (
> +    &gEfiRestJsonStructureProtocolGuid,
> +    TPL_CALLBACK,
> +    EfiRestJsonStructureProtocolIsReady,
> +    NULL,
> +    &Registration
> +    );
> +
> +  EfiCreateProtocolNotifyEvent (
> +    &gEdkIIRedfishFeatureProtocolGuid,
> +    TPL_CALLBACK,
> +    EdkIIRedfishFeatureProtocolIsReady,
> +    (VOID *)mRedfishResourcePrivate,
> +    &Registration
> +    );
> +
> +  return Status;
> +}
> diff --git a/RedfishClientPkg/RedfishClient.fdf.inc b/RedfishClientPkg/RedfishClient.fdf.inc
> index 59b8acba1..154f641b2 100644
> --- a/RedfishClientPkg/RedfishClient.fdf.inc
> +++ b/RedfishClientPkg/RedfishClient.fdf.inc
> @@ -25,6 +25,7 @@
>   INF RedfishClientPkg/HiiToRedfishBiosDxe/HiiToRedfishBiosDxe.inf
>   INF RedfishClientPkg/Features/BootOptionCollection/BootOptionCollectionDxe.inf
>   INF RedfishClientPkg/Features/BootOption/v1_0_4/Dxe/BootOptionDxe.inf
> +  INF RedfishClientPkg/Features/SecureBoot/v1_1_0/Dxe/SecureBootDxe.inf
> 
>   !include RedfishClientPkg/RedfishJsonStructureDxe.fdf.inc
>   #
> -- 
> 2.34.1
> 


Regards,
Mike



-=-=-=-=-=-=-=-=-=-=-=-
Groups.io Links: You receive all messages sent to this group.
View/Reply Online (#116774): https://edk2.groups.io/g/devel/message/116774
Mute This Topic: https://groups.io/mt/104927848/7686176
Group Owner: devel+owner@edk2.groups.io
Unsubscribe: https://edk2.groups.io/g/devel/unsub [rebecca@openfw.io]
-=-=-=-=-=-=-=-=-=-=-=-



[-- Attachment #2: Type: text/html, Size: 119630 bytes --]

^ permalink raw reply	[flat|nested] 5+ messages in thread

* Re: [edk2-devel] [edk2-redfish-client][PATCH 1/2] RedfishClientPkg/Features: support Redfish Secure Boot
  2024-03-14 19:38 ` Mike Maslenkin
@ 2024-03-26 13:57   ` Nickle Wang via groups.io
  2024-03-26 22:56     ` Mike Maslenkin
  0 siblings, 1 reply; 5+ messages in thread
From: Nickle Wang via groups.io @ 2024-03-26 13:57 UTC (permalink / raw)
  To: Mike Maslenkin, devel; +Cc: Abner Chang, Igor Kulchytskyy, Nick Ramirez

[-- Attachment #1: Type: text/plain, Size: 60299 bytes --]

Hi Mike,

Thanks for your review. I addressed your review comments in pull request: https://github.com/tianocore/edk2-redfish-client/pull/83

I am waiting for Abner's patch (PR#84) because I plan to incorporate Abner's changes into this driver. I will send version 2 patch series here for review later.

Regards,
Nickle

From: Mike Maslenkin <mike.maslenkin@gmail.com>
Sent: Friday, March 15, 2024 3:38 AM
To: devel@edk2.groups.io; Nickle Wang <nicklew@nvidia.com>
Cc: Abner Chang <abner.chang@amd.com>; Igor Kulchytskyy <igork@ami.com>; Nick Ramirez <nramirez@nvidia.com>
Subject: Re: [edk2-devel] [edk2-redfish-client][PATCH 1/2] RedfishClientPkg/Features: support Redfish Secure Boot

External email: Use caution opening links or attachments

Hi Nickle,

please find my comments below


On 14. 3. 2024., at 17:53, Nickle Wang via groups.io<http://groups.io/> <nicklew=nvidia.com@groups.io<mailto:nvidia.com@groups.io>> wrote:

Introduce SecureBoot driver to support
/redfish/v1/Systems/SYS/SecureBoot resource.

Signed-off-by: Nickle Wang <nicklew@nvidia.com<mailto:nicklew@nvidia.com>>
Cc: Abner Chang <abner.chang@amd.com<mailto:abner.chang@amd.com>>
Cc: Igor Kulchytskyy <igork@ami.com<mailto:igork@ami.com>>
Cc: Nick Ramirez <nramirez@nvidia.com<mailto:nramirez@nvidia.com>>
---
.../RedfishClientComponents.dsc.inc           |   2 +
RedfishClientPkg/RedfishClientLibs.dsc.inc    |   4 +
.../SecureBoot/v1_1_0/Dxe/SecureBootDxe.inf   |  60 ++
.../v1_1_0/Common/SecureBootCommon.h          |  40 +
.../v1_1_0/Common/SecureBootCommon.c          | 756 ++++++++++++++++
.../SecureBoot/v1_1_0/Dxe/SecureBootDxe.c     | 808 ++++++++++++++++++
RedfishClientPkg/RedfishClient.fdf.inc        |   1 +
7 files changed, 1671 insertions(+)
create mode 100644 RedfishClientPkg/Features/SecureBoot/v1_1_0/Dxe/SecureBootDxe.inf
create mode 100644 RedfishClientPkg/Features/SecureBoot/v1_1_0/Common/SecureBootCommon.h
create mode 100644 RedfishClientPkg/Features/SecureBoot/v1_1_0/Common/SecureBootCommon.c
create mode 100644 RedfishClientPkg/Features/SecureBoot/v1_1_0/Dxe/SecureBootDxe.c

diff --git a/RedfishClientPkg/RedfishClientComponents.dsc.inc b/RedfishClientPkg/RedfishClientComponents.dsc.inc
index ae2a4b025..42fc0c299 100644
--- a/RedfishClientPkg/RedfishClientComponents.dsc.inc
+++ b/RedfishClientPkg/RedfishClientComponents.dsc.inc
@@ -34,6 +34,7 @@
  RedfishClientPkg/Features/Bios/v1_0_9/Dxe/BiosDxe.inf
  RedfishClientPkg/Features/BootOptionCollection/BootOptionCollectionDxe.inf
  RedfishClientPkg/Features/BootOption/v1_0_4/Dxe/BootOptionDxe.inf
+  RedfishClientPkg/Features/SecureBoot/v1_1_0/Dxe/SecureBootDxe.inf

  !include RedfishClientPkg/RedfishJsonStructureDxe.dsc.inc

@@ -47,3 +48,4 @@
  RedfishClientPkg/Converter/Bios/v1_0_9/RedfishBios_V1_0_9_Dxe.inf
  RedfishClientPkg/Converter/BootOptionCollection/RedfishBootOptionCollection_Dxe.inf
  RedfishClientPkg/Converter/BootOption/v1_0_4/RedfishBootOption_V1_0_4_Dxe.inf
+  RedfishClientPkg/Converter/SecureBoot/v1_1_0/RedfishSecureBoot_V1_1_0_Dxe.inf
diff --git a/RedfishClientPkg/RedfishClientLibs.dsc.inc b/RedfishClientPkg/RedfishClientLibs.dsc.inc
index 6599926ab..9126465df 100644
--- a/RedfishClientPkg/RedfishClientLibs.dsc.inc
+++ b/RedfishClientPkg/RedfishClientLibs.dsc.inc
@@ -25,6 +25,8 @@
  BiosV1_0_9Lib|RedfishClientPkg/ConverterLib/edk2library/Bios/v1_0_9/Lib.inf
  BootOptionCollectionLib|RedfishClientPkg/ConverterLib/edk2library/BootOptionCollection/Lib.inf
  BootOptionV1_0_4Lib|RedfishClientPkg/ConverterLib/edk2library/BootOption/v1_0_4/Lib.inf
+  SecureBootV1_1_0Lib|RedfishClientPkg/ConverterLib/edk2library/SecureBoot/v1_1_0/Lib.inf
+
  #
  # Above modules should be pulled in by build tool.
  #
@@ -42,3 +44,5 @@
  RedfishAddendumLib|RedfishClientPkg/Library/RedfishAddendumLib/RedfishAddendumLib.inf
  RedfishDebugLib|RedfishPkg/Library/RedfishDebugLib/RedfishDebugLib.inf
  RedfishHttpLib|RedfishPkg/Library/RedfishHttpLib/RedfishHttpLib.inf
+  SecureBootVariableLib|SecurityPkg/Library/SecureBootVariableLib/SecureBootVariableLib.inf
+  PlatformPKProtectionLib|SecurityPkg/Library/PlatformPKProtectionLibVarPolicy/PlatformPKProtectionLibVarPolicy.inf
diff --git a/RedfishClientPkg/Features/SecureBoot/v1_1_0/Dxe/SecureBootDxe.inf b/RedfishClientPkg/Features/SecureBoot/v1_1_0/Dxe/SecureBootDxe.inf
new file mode 100644
index 000000000..1ad8c623f
--- /dev/null
+++ b/RedfishClientPkg/Features/SecureBoot/v1_1_0/Dxe/SecureBootDxe.inf
@@ -0,0 +1,60 @@
+## @file
+#
+#  (C) Copyright 2020-2022 Hewlett Packard Enterprise Development LP<BR>
+#  Copyright (c) 2022-2024, NVIDIA CORPORATION & AFFILIATES. All rights reserved.
+#
+#  SPDX-License-Identifier: BSD-2-Clause-Patent
+#
+##
+
+
+[Defines]
+  INF_VERSION               = 0x00010005
+  BASE_NAME                 = SecureBootDxe
+  FILE_GUID                 = 5E4025F8-DA42-468A-853E-6A1091D35052
+  MODULE_TYPE               = DXE_DRIVER
+  VERSION_STRING            = 1.0
+  ENTRY_POINT               = RedfishResourceEntryPoint
+  UNLOAD_IMAGE              = RedfishResourceUnload
+
+[Packages]
+  MdePkg/MdePkg.dec
+  MdeModulePkg/MdeModulePkg.dec
+  SecurityPkg/SecurityPkg.dec
+  RedfishPkg/RedfishPkg.dec
+  RedfishClientPkg/RedfishClientPkg.dec
+
+[Sources]
+  ../Common/SecureBootCommon.h
+  ../Common/SecureBootCommon.c
+  SecureBootDxe.c
+
+[LibraryClasses]
+  BaseMemoryLib
+  DebugLib
+  EdkIIRedfishResourceConfigLib
+  RedfishFeatureUtilityLib
+  RedfishVersionLib
+  RedfishResourceIdentifyLib
+  SecureBootVariableLib
+  UefiLib
+  UefiDriverEntryPoint
+  RedfishAddendumLib
+  UefiRuntimeServicesTableLib
+
+[Protocols]
+  gEdkIIRedfishConfigHandlerProtocolGuid          ## PRODUCED
+  gEfiRestJsonStructureProtocolGuid               ## CONSUMED
+  gEdkIIRedfishResourceConfigProtocolGuid         ## PRODUCED
+  gEdkIIRedfishFeatureProtocolGuid                ## CONSUMED
+
+[Guids]
+  gEfiSecureBootEnableDisableGuid                 ## CONSUMED
+
+[Pcd]
+  gEfiRedfishClientPkgTokenSpaceGuid.PcdMaxRedfishSchemaStringSize
+  gEfiRedfishClientPkgTokenSpaceGuid.PcdMaxRedfishSchemaVersionSize
+  gEfiRedfishClientPkgTokenSpaceGuid.PcdRedfishSystemRebootRequired
+
+[Depex]
+  TRUE
diff --git a/RedfishClientPkg/Features/SecureBoot/v1_1_0/Common/SecureBootCommon.h b/RedfishClientPkg/Features/SecureBoot/v1_1_0/Common/SecureBootCommon.h
new file mode 100644
index 000000000..0d1824160
--- /dev/null
+++ b/RedfishClientPkg/Features/SecureBoot/v1_1_0/Common/SecureBootCommon.h
@@ -0,0 +1,40 @@
+/** @file
+
+  Redfish feature driver implementation - internal header file
+  (C) Copyright 2020-2022 Hewlett Packard Enterprise Development LP<BR>
+  Copyright (c) 2022-2024, NVIDIA CORPORATION & AFFILIATES. All rights reserved.
+
+  SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#ifndef EFI_REDFISH_SECUREBOOT_COMMON_H_
+#define EFI_REDFISH_SECUREBOOT_COMMON_H_
+
+#include <Guid/ImageAuthentication.h>
+#include <Guid/GlobalVariable.h>
+#include <Guid/AuthenticatedVariableFormat.h>
+#include <RedfishJsonStructure/SecureBoot/v1_1_0/EfiSecureBootV1_1_0.h>
+#include <RedfishResourceCommon.h>
+#include <UefiSecureBoot.h>
+#include <Library/UefiRuntimeServicesTableLib.h>
+#include <Library/SecureBootVariableLib.h>
+
+//
+// Schema information.
+//
+#define REDFISH_MANAGED_URI        L"Systems/{}/SecureBoot"
+#define REDFISH_DUMMY_CONFIG_LANG  L"Systems/{1}/SecureBoot"
+#define MAX_URI_LENGTH             256
+#define RESOURCE_SCHEMA            "SecureBoot"
+#define RESOURCE_SCHEMA_MAJOR      "1"
+#define RESOURCE_SCHEMA_MINOR      "1"
+#define RESOURCE_SCHEMA_ERRATA     "0"
+#define RESOURCE_SCHEMA_VERSION    "v1_1_0"
+#define SECURE_BOOT_SETUP_MODE     "SetupMode"
+#define SECURE_BOOT_USER_MODE      "UserMode"
+#define SECURE_BOOT_ENABLED        "Enabled"
+#define SECURE_BOOT_DISABLED       "Disabled"
+#define SECURE_BOOT_MODE_STR_LEN   16
+
+#endif
diff --git a/RedfishClientPkg/Features/SecureBoot/v1_1_0/Common/SecureBootCommon.c b/RedfishClientPkg/Features/SecureBoot/v1_1_0/Common/SecureBootCommon.c
new file mode 100644
index 000000000..56a45ee72
--- /dev/null
+++ b/RedfishClientPkg/Features/SecureBoot/v1_1_0/Common/SecureBootCommon.c
@@ -0,0 +1,756 @@
+/** @file
+  Redfish feature driver implementation - common functions
+
+  (C) Copyright 2020-2022 Hewlett Packard Enterprise Development LP<BR>
+  Copyright (c) 2023-2024, NVIDIA CORPORATION & AFFILIATES. All rights reserved.
+
+  SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include "SecureBootCommon.h"
+
+CHAR8  SecureBootEmptyJson[] = "{\"@odata.id<http://odata.id/>\": \"\", \"@odata.type\": \"#SecureBoot.v1_1_0.SecureBoot\", \"Id\": \"\", \"Name\": \"\", \"Attributes\":{}}";
+
+REDFISH_RESOURCE_COMMON_PRIVATE  *mRedfishResourcePrivate                                  = NULL;
+EFI_HANDLE                       mRedfishResourceConfigProtocolHandle                      = NULL;
+CHAR16                           *mSecureBootSupportedAttributes[SECURE_BOOT_MODE_STR_LEN] = {
+  L"SecureBootCurrentBoot",
+  L"SecureBootEnable",
+  L"SecureBootMode"
+};
+
+/**
+  Read EFI_SECURE_BOOT_ENABLE_NAME variable and return its value to caller.
+
+  @retval BOOLEAN    TRUE when EFI_SECURE_BOOT_ENABLE_NAME value is SECURE_BOOT_ENABLE
+                     FALSE when EFI_SECURE_BOOT_ENABLE_NAME value is SECURE_BOOT_DISABLE
+**/
+BOOLEAN
+RedfishReadSecureBootEnable (
+  VOID
+  )
+{
+  UINT8    *Buffer;
+  BOOLEAN  SecureBootEnableValue;
+
+  Buffer                = NULL;
+  SecureBootEnableValue = FALSE;
+
+  GetVariable2 (
+    EFI_SECURE_BOOT_ENABLE_NAME,
+    &gEfiSecureBootEnableDisableGuid,
+    (VOID **)&Buffer,
+    NULL
+    );
+
+  if (Buffer != NULL) {
+    if (*Buffer == SECURE_BOOT_ENABLE) {
+      SecureBootEnableValue = TRUE;
+    }
+
+    FreePool (Buffer);
+  }
+
+  return SecureBootEnableValue;
+}
+
+/**
+  Write EFI_SECURE_BOOT_ENABLE_NAME variable with given value.
+
+  @param[in]   SecureBootEnableValue    Value to write. TRUE is SECURE_BOOT_ENABLE.
+                                        FALSE is SECURE_BOOT_DISABLE.
+
+  @retval EFI_SUCCESS              Write value successfully.
+  @retval Others                   Some error happened.
+**/
+EFI_STATUS
+RedfishWriteSecureBootEnable (
+  BOOLEAN  SecureBootEnableValue
+  )
+{
+  EFI_STATUS  Status;
+  UINT8       VarValue;
+
+  VarValue = (SecureBootEnableValue ? SECURE_BOOT_ENABLE : SECURE_BOOT_DISABLE);
+  Status   = gRT->SetVariable (
+                    EFI_SECURE_BOOT_ENABLE_NAME,
+                    &gEfiSecureBootEnableDisableGuid,
+                    EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS,
+                    sizeof (VarValue),
+                    &VarValue
+                    );
+
+  return Status;
+}
+
+/**
+  Consume Redfish resource in given Json data.
+
+  @param[in]   This                Pointer to REDFISH_RESOURCE_COMMON_PRIVATE instance.
+  @param[in]   Json                The JSON to consume.
+  @param[in]   HeaderEtag          The Etag string returned in HTTP header.
+
+  @retval EFI_SUCCESS              Consume Redfish attribute successfully.
+  @retval Others                   Some error happened.
+
+**/
+EFI_STATUS
+RedfishConsumeResourceCommon (
+  IN  REDFISH_RESOURCE_COMMON_PRIVATE  *Private,
+  IN  CHAR8                            *Json,
+  IN  CHAR8                            *HeaderEtag OPTIONAL
+  )
+{
+  EFI_STATUS                        Status;
+  EFI_REDFISH_SECUREBOOT_V1_1_0     *SecureBoot;
+  EFI_REDFISH_SECUREBOOT_V1_1_0_CS  *SecureBootCs;
+  BOOLEAN                           SecureBootEnableDisable;
+
+  if ((Private == NULL) || IS_EMPTY_STRING (Json)) {
+    return EFI_INVALID_PARAMETER;
+  }
+
+  SecureBoot              = NULL;
+  SecureBootCs            = NULL;
+  SecureBootEnableDisable = RedfishReadSecureBootEnable ();
+
+  Status = Private->JsonStructProtocol->ToStructure (
+                                          Private->JsonStructProtocol,
+                                          NULL,
+                                          Json,
+                                          (EFI_REST_JSON_STRUCTURE_HEADER **)&SecureBoot
+                                          );
+  if (EFI_ERROR (Status)) {
+    DEBUG ((DEBUG_ERROR, "%a: ToStructure() failed: %r\n", __func__, Status));
+    return Status;
+  }
+
+  SecureBootCs = SecureBoot->SecureBoot;
+
+  //
+  // Check ETAG to see if we need to consume it
+  //
+  if (CheckEtag (Private->Uri, HeaderEtag, SecureBootCs->odata_etag)) {
+    //
+    // No change
+    //
+    DEBUG ((REDFISH_DEBUG_TRACE, "%a: ETAG: %s has no change, ignore consume action\n", __func__, Private->Uri));
+    Status = EFI_ALREADY_STARTED;
+    goto ON_RELEASE;
+  }
+
+  //
+  // Secure boot enable
+  //
+  if (SecureBootCs->SecureBootEnable != NULL) {
+    if (SecureBootEnableDisable != *SecureBootCs->SecureBootEnable) {
+      //
+      // Write value to "SecureBootEnable" variable. AuthVariableLib will enable or disable secure boot
+      // based on "SecureBootEnable" value.
+      //
+      Status = RedfishWriteSecureBootEnable (*SecureBootCs->SecureBootEnable);
+      if (EFI_ERROR (Status)) {
+        DEBUG ((DEBUG_ERROR, "%a: write secure boot enable disable failed: %r\n", __func__, Status));
+      } else {
+        REDFISH_ENABLE_SYSTEM_REBOOT ();
+      }
+    } else {
+      DEBUG ((REDFISH_DEBUG_TRACE, "%a: secure boot mode is not changed\n", __func__));
+    }
+  }
+
+ON_RELEASE:
+
+  //
+  // Release resource.
+  //
+  Private->JsonStructProtocol->DestoryStructure (
+                                 Private->JsonStructProtocol,
+                                 (EFI_REST_JSON_STRUCTURE_HEADER *)SecureBoot
+                                 );
+
+  return EFI_SUCCESS;
+}
+
+/**
+  Provision Redfish resource. This function reads secure boot variable and convert it
+  to Redfish attribute.
+
+  @param[in]   JsonStructProtocol  Pointer to Json structure protocol.
+  @param[in]   InputJson           Jason data on input.
+  @param[in]   ResourceId          Resource ID. This is optional.
+  @param[in]   ConfigureLang       Configure language for this Redfish resource.
+  @param[in]   ProvisionMode       TRUE when this is to provision Redfish attribute to
+                                   Redfish service. FALSE is to update Redfish attribute
+                                   to Redfish service.
+  @param[out]  ResultJson          Json data on output.
+
+  @retval EFI_SUCCESS              Provision Redfish attribute successfully.
+  @retval Others                   Some error happened.
+
+**/
+EFI_STATUS
+ProvisioningSecureBootProperties (
+  IN  EFI_REST_JSON_STRUCTURE_PROTOCOL  *JsonStructProtocol,
+  IN  CHAR8                             *InputJson,
+  IN  CHAR8                             *ResourceId OPTIONAL,
+  IN  EFI_STRING                        ConfigureLang,
+  IN  BOOLEAN                           ProvisionMode,
+  OUT CHAR8                             **ResultJson
+  )
+{
+  EFI_REDFISH_SECUREBOOT_V1_1_0     *SecureBoot;
+  EFI_REDFISH_SECUREBOOT_V1_1_0_CS  *SecureBootCs;
+  EFI_STATUS                        Status;
+  BOOLEAN                           PropertyChanged;
+  CHAR8                             *AsciiStringValue;
+  INT32                             *IntegerValue;
+  UINT8                             SetupMode;
+  BOOLEAN                           SecureBootEnabled;
+  BOOLEAN                           SecureBootEnableDisable;
+
+  if ((JsonStructProtocol == NULL) || (ResultJson == NULL) || IS_EMPTY_STRING (InputJson) || IS_EMPTY_STRING (ConfigureLang)) {
+    return EFI_INVALID_PARAMETER;
+  }
+
+  DEBUG ((REDFISH_DEBUG_TRACE, "%a provision for %s with: %s\n", __func__, ConfigureLang, (ProvisionMode ? L"Provision resource" : L"Update resource")));
+
+  *ResultJson             = NULL;
+  PropertyChanged         = FALSE;
+  AsciiStringValue        = NULL;
+  SecureBootEnableDisable = RedfishReadSecureBootEnable ();
+  SecureBootEnabled       = IsSecureBootEnabled ();
+
+  SecureBoot = NULL;
+  Status     = JsonStructProtocol->ToStructure (
+                                     JsonStructProtocol,
+                                     NULL,
+                                     InputJson,
+                                     (EFI_REST_JSON_STRUCTURE_HEADER **)&SecureBoot
+                                     );
+  if (EFI_ERROR (Status)) {
+    DEBUG ((DEBUG_ERROR, "%a: ToStructure failure: %r\n", __func__, Status));
+    return Status;
+  }
+
+  SecureBootCs = SecureBoot->SecureBoot;
+
+  //
+  // ID
+  //
+  if (SecureBootCs->Id != NULL) {
+    SecureBootCs->Id = NULL;
+  }
+
+  //
+  // Name
+  //
+  if (SecureBootCs->Name != NULL) {
+    SecureBootCs->Name = NULL;
+  }
+
+  //
+  // Secure boot variables that we will handle here
+  //
+  // EFI_SETUP_MODE_NAME (gEfiGlobalVariableGuid)
+  // EFI_SECURE_BOOT_MODE_NAME (gEfiGlobalVariableGuid)
+  // EFI_SECURE_BOOT_ENABLE_NAME (gEfiSecureBootEnableDisableGuid)
+  //
+
+  //
+  // Current Boot
+  //
+  if (PropertyChecker (SecureBootCs->SecureBootCurrentBoot, ProvisionMode)) {
+    AsciiStringValue = AllocateZeroPool (SECURE_BOOT_MODE_STR_LEN * sizeof (CHAR8));
+    if (AsciiStringValue != NULL) {
+      AsciiSPrint (AsciiStringValue, SECURE_BOOT_MODE_STR_LEN, "%a", (SecureBootEnabled ? SECURE_BOOT_ENABLED : SECURE_BOOT_DISABLED));
+      if (ProvisionMode || (AsciiStrCmp (SecureBootCs->SecureBootCurrentBoot, AsciiStringValue) != 0)) {
+        SecureBootCs->SecureBootCurrentBoot = AsciiStringValue;
+        PropertyChanged                     = TRUE;
+      }
+    } else {
+      DEBUG ((DEBUG_ERROR, "%a: out of resource\n", __func__));
+    }
+  }
+
+  //
+  // Secure boot enable
+  //
+  if (PropertyChecker (SecureBootCs->SecureBootEnable, ProvisionMode)) {
+    if (ProvisionMode || (*SecureBootCs->SecureBootEnable != SecureBootEnableDisable)) {
+      IntegerValue = AllocatePool (sizeof (*IntegerValue));
+      if (IntegerValue != NULL) {
+        *IntegerValue                  = (SecureBootEnableDisable ? 0x01 : 0x00);
+        SecureBootCs->SecureBootEnable = IntegerValue;
+        PropertyChanged                = TRUE;
+      } else {
+        DEBUG ((DEBUG_ERROR, "%a: out of resource\n", __func__));
+      }
+    }
+  }
+
+  //
+  // Secure boot mode
+  //
+  if (PropertyChecker (SecureBootCs->SecureBootMode, ProvisionMode)) {
+    Status = GetSetupMode (&SetupMode);
+    if (!EFI_ERROR (Status)) {
+      AsciiStringValue = AllocateZeroPool (SECURE_BOOT_MODE_STR_LEN *sizeof (CHAR8));
+      if (AsciiStringValue != NULL) {
+        AsciiSPrint (AsciiStringValue, SECURE_BOOT_MODE_STR_LEN *sizeof (CHAR8), "%a", (SetupMode == USER_MODE ? SECURE_BOOT_USER_MODE : SECURE_BOOT_SETUP_MODE));
+        if (ProvisionMode || (AsciiStrCmp (SecureBootCs->SecureBootMode, AsciiStringValue) != 0)) {
+          SecureBootCs->SecureBootMode = AsciiStringValue;
+          PropertyChanged              = TRUE;
+        }
+      }
+    } else {
+      DEBUG ((DEBUG_ERROR, "%a: cannot read setup mode: %r\n", __func__, Status));
+    }
+  }
+
+  //
+  // Convert C structure back to JSON text.
+  //
+  Status = JsonStructProtocol->ToJson (
+                                 JsonStructProtocol,
+                                 (EFI_REST_JSON_STRUCTURE_HEADER *)SecureBoot,
+                                 ResultJson
+                                 );
+  if (EFI_ERROR (Status)) {
+    DEBUG ((DEBUG_ERROR, "%a: ToJson() failed: %r\n", __func__, Status));
+    return Status;



  SecureBoot structure leak. It is released below.


+  }
+
+  //
+  // Release resource.
+  //
+  JsonStructProtocol->DestoryStructure (
+                        JsonStructProtocol,
+                        (EFI_REST_JSON_STRUCTURE_HEADER *)SecureBoot
+                        );
+
+  return (PropertyChanged ? EFI_SUCCESS : EFI_NOT_FOUND);
+}
+
+/**
+  Provision Redfish resource and upload data to Redfish service. This function
+  checks OEM data and platform addendum data before sending data to Redfish service.
+
+  @param[in]   Private   Pointer to private data.
+
+  @retval EFI_SUCCESS              Provision Redfish resource successfully.
+  @retval Others                   Some error happened.
+
+**/
+EFI_STATUS
+ProvisioningSecureBootResource (
+  IN  REDFISH_RESOURCE_COMMON_PRIVATE  *Private
+  )
+{
+  EFI_STATUS        Status;
+  CHAR8             *Json;
+  CHAR8             *JsonWithAddendum;
+  REDFISH_RESPONSE  Response;
+
+  if (Private == NULL) {
+    return EFI_INVALID_PARAMETER;
+  }
+
+  ZeroMem (&Response, sizeof (REDFISH_RESPONSE));
+  Json = NULL;
+
+  Status = ProvisioningSecureBootProperties (
+             Private->JsonStructProtocol,
+             SecureBootEmptyJson,
+             NULL,
+             REDFISH_DUMMY_CONFIG_LANG,
+             TRUE,
+             &Json
+             );
+  if (EFI_ERROR (Status)) {
+    if (Status == EFI_NOT_FOUND) {
+      DEBUG ((REDFISH_DEBUG_TRACE, "%a: provisioning existing resource for %s ignored. Nothing changed\n", __func__, REDFISH_DUMMY_CONFIG_LANG));
+      Status = EFI_SUCCESS;
+    } else {
+      DEBUG ((DEBUG_ERROR, "%a: provisioning existing resource for %s failed: %r\n", __func__, REDFISH_DUMMY_CONFIG_LANG, Status));
+    }
+
+    goto ON_RELEASE;
+  }
+
+  //
+  // Check and see if platform has OEM data or not
+  //
+  Status = RedfishGetOemData (
+             Private->Uri,
+             RESOURCE_SCHEMA,
+             RESOURCE_SCHEMA_VERSION,
+             Json,
+             &JsonWithAddendum
+             );
+  if (!EFI_ERROR (Status) && (JsonWithAddendum != NULL)) {
+    FreePool (Json);
+    Json             = JsonWithAddendum;
+    JsonWithAddendum = NULL;
+  }
+
+  //
+  // Check and see if platform has addendum data or not
+  //
+  Status = RedfishGetAddendumData (
+             Private->Uri,
+             RESOURCE_SCHEMA,
+             RESOURCE_SCHEMA_VERSION,
+             Json,
+             &JsonWithAddendum
+             );
+  if (!EFI_ERROR (Status) && (JsonWithAddendum != NULL)) {
+    FreePool (Json);
+    Json             = JsonWithAddendum;
+    JsonWithAddendum = NULL;
+  }
+
+  DEBUG ((REDFISH_DEBUG_TRACE, "%a: provisioning existing resource for %s\n", __func__, REDFISH_DUMMY_CONFIG_LANG));
+
+  //
+  // PATCH back to instance
+  //
+  Status = RedfishHttpPatchResource (Private->RedfishService, Private->Uri, Json, &Response);
+  if (EFI_ERROR (Status)) {
+    DEBUG ((DEBUG_ERROR, "%a: patch resource for %s failed: %r\n", __func__, REDFISH_DUMMY_CONFIG_LANG, Status));
+  }
+
+ON_RELEASE:
+
+  if (Json != NULL) {
+    FreePool (Json);
+  }
+
+  RedfishHttpFreeResponse (&Response);
+
+  return Status;
+}
+
+/**
+  Provisioning redfish resource to Redfish service.
+
+  @param[in]   Private             Pointer to private data.
+  @param[in]   ResourceExist       TRUE if resource exists, PUT method will be used.
+                                   FALSE if resource does not exist POST method is used.


Actually ProvisioningSecureBootResource uses PATCH only.



+
+  @retval EFI_SUCCESS              Provision resource successfully.
+  @retval Others                   Some error happened.
+
+**/
+EFI_STATUS
+RedfishProvisioningResourceCommon (
+  IN     REDFISH_RESOURCE_COMMON_PRIVATE  *Private,
+  IN     BOOLEAN                          ResourceExist
+  )
+{
+  if (Private == NULL) {
+    return EFI_INVALID_PARAMETER;
+  }
+
+  return ProvisioningSecureBootResource (Private);
+}
+
+/**
+  Check resource from given Json data.
+
+  @param[in]   This                Pointer to REDFISH_RESOURCE_COMMON_PRIVATE instance.
+  @param[in]   Json                The JSON data to check.
+  @param[in]   HeaderEtag          The Etag string returned in HTTP header.
+
+  @retval EFI_SUCCESS              Check resource successfully.
+  @retval Others                   Some error happened.
+
+**/
+EFI_STATUS
+RedfishCheckResourceCommon (
+  IN     REDFISH_RESOURCE_COMMON_PRIVATE  *Private,
+  IN     CHAR8                            *Json,
+  IN     CHAR8                            *HeaderEtag OPTIONAL
+  )
+{
+  UINTN       Index;
+  EFI_STATUS  Status;
+  UINTN       Count;
+  EFI_STRING  Property;
+
+  if ((Private == NULL) || IS_EMPTY_STRING (Json)) {
+    return EFI_INVALID_PARAMETER;
+  }
+
+  //
+  // Check ETAG to see if we need to check it
+  //
+  if (CheckEtag (Private->Uri, HeaderEtag, NULL)) {
+    //
+    // No change
+    //
+    DEBUG ((REDFISH_DEBUG_TRACE, "%a: ETAG: %s has no change, ignore check action\n", __func__, Private->Uri));
+    return EFI_SUCCESS;
+  }
+
+  Count = sizeof (mSecureBootSupportedAttributes) / sizeof (mSecureBootSupportedAttributes[0]);
+  if (Count == 0) {
+    return EFI_UNSUPPORTED;
+  }
+
+  Status = EFI_SUCCESS;
+  for (Index = 0; Index < Count; Index++) {
+    Property = mSecureBootSupportedAttributes[Index];
+    if (Property == NULL) {
+      continue;
+    }
+
+    DEBUG ((REDFISH_DEBUG_TRACE, "%a: [%d] check attribute for: %s\n", __func__, Index, Property));
+    if (!MatchPropertyWithJsonContext (Property, Json)) {
+      DEBUG ((REDFISH_DEBUG_TRACE, "%a: property is missing: %s\n", __func__, Property));
+      Status = EFI_NOT_FOUND;
+    }
+  }
+
+  return Status;
+}
+
+/**
+  Update resource to Redfish service.
+
+  @param[in]   Private             Pointer to REDFISH_RESOURCE_COMMON_PRIVATE instance.
+  @param[in]   Json                The JSON data to be updated.
+
+  @retval EFI_SUCCESS              Update resource successfully.
+  @retval Others                   Some error happened.
+
+**/
+EFI_STATUS
+RedfishUpdateResourceCommon (
+  IN     REDFISH_RESOURCE_COMMON_PRIVATE  *Private,
+  IN     CHAR8                            *InputJson
+  )
+{
+  EFI_STATUS        Status;
+  CHAR8             *Json;
+  CHAR8             *JsonWithAddendum;
+  REDFISH_RESPONSE  Response;
+
+  if ((Private == NULL) || IS_EMPTY_STRING (InputJson)) {
+    return EFI_INVALID_PARAMETER;
+  }
+
+  ZeroMem (&Response, sizeof (REDFISH_RESPONSE));
+  Json = NULL;
+
+  Status = ProvisioningSecureBootProperties (
+             Private->JsonStructProtocol,
+             SecureBootEmptyJson,
+             NULL,
+             REDFISH_DUMMY_CONFIG_LANG,
+             TRUE,
+             &Json
+             );
+  if (EFI_ERROR (Status)) {
+    if (Status == EFI_NOT_FOUND) {
+      DEBUG ((REDFISH_DEBUG_TRACE, "%a: update resource for %s ignored. Nothing changed\n", __func__, REDFISH_DUMMY_CONFIG_LANG));
+      Status = EFI_SUCCESS;
+    } else {
+      DEBUG ((DEBUG_ERROR, "%a: update resource for %s failed: %r\n", __func__, REDFISH_DUMMY_CONFIG_LANG, Status));
+    }
+
+    goto ON_RELEASE;
+  }
+
+  //
+  // Check and see if platform has OEM data or not
+  //
+  Status = RedfishGetOemData (
+             Private->Uri,
+             RESOURCE_SCHEMA,
+             RESOURCE_SCHEMA_VERSION,
+             Json,
+             &JsonWithAddendum
+             );
+  if (!EFI_ERROR (Status) && (JsonWithAddendum != NULL)) {
+    FreePool (Json);
+    Json             = JsonWithAddendum;
+    JsonWithAddendum = NULL;
+  }
+
+  //
+  // Check and see if platform has addendum data or not
+  //
+  Status = RedfishGetAddendumData (
+             Private->Uri,
+             RESOURCE_SCHEMA,
+             RESOURCE_SCHEMA_VERSION,
+             Json,
+             &JsonWithAddendum
+             );
+  if (!EFI_ERROR (Status) && (JsonWithAddendum != NULL)) {
+    FreePool (Json);
+    Json             = JsonWithAddendum;
+    JsonWithAddendum = NULL;
+  }
+
+  DEBUG ((REDFISH_DEBUG_TRACE, "%a: update resource for %s\n", __func__, REDFISH_DUMMY_CONFIG_LANG));
+
+  //
+  // PATCH back to instance
+  //
+  Status = RedfishHttpPatchResource (Private->RedfishService, Private->Uri, Json, &Response);
+  if (EFI_ERROR (Status)) {
+    DEBUG ((DEBUG_ERROR, "%a: patch resource for %s failed: %r\n", __func__, REDFISH_DUMMY_CONFIG_LANG, Status));
+  }
+
+ON_RELEASE:
+
+  if (Json != NULL) {
+    FreePool (Json);
+  }
+
+  RedfishHttpFreeResponse (&Response);
+
+  return Status;
+}
+
+/**
+  Identify resource in given Json data.
+
+  @param[in]   Private             Pointer to REDFISH_RESOURCE_COMMON_PRIVATE instance.
+  @param[in]   Json                The JSON to be identified.
+
+  @retval EFI_SUCCESS              Identify resource successfully.
+  @retval Others                   Some error happened.
+
+**/
+EFI_STATUS
+RedfishIdentifyResourceCommon (
+  IN     REDFISH_RESOURCE_COMMON_PRIVATE  *Private,
+  IN     CHAR8                            *Json
+  )
+{
+  BOOLEAN  Supported;
+
+  Supported = RedfishIdentifyResource (Private->Uri, Private->Json);
+  if (Supported) {
+    //
+    // Keep URI and ConfigLang mapping
+    //
+    RedfishSetRedfishUri (REDFISH_DUMMY_CONFIG_LANG, Private->Uri);
+  }
+
+  return (Supported ? EFI_SUCCESS : EFI_UNSUPPORTED);
+}
+
+/**
+  Handle Redfish resource in Uri.
+
+  @param[in]   Private             Pointer to REDFISH_RESOURCE_COMMON_PRIVATE instance.
+  @param[in]   Uri                 URI to Redfish resource that we like to process.
+
+  @retval EFI_SUCCESS              Handle resource successfully.
+  @retval Others                   Some error happened.
+
+**/
+EFI_STATUS
+HandleResource (
+  IN  REDFISH_RESOURCE_COMMON_PRIVATE  *Private,
+  IN  EFI_STRING                       Uri
+  )
+{
+  EFI_STATUS           Status;
+  REDFISH_SCHEMA_INFO  SchemaInfo;
+  EFI_STRING           ConfigLang;
+
+  if ((Private == NULL) || IS_EMPTY_STRING (Uri)) {
+    return EFI_INVALID_PARAMETER;
+  }
+
+  //
+  // Resource match
+  //
+
+  DEBUG ((REDFISH_DEBUG_TRACE, "%a: process resource for: %s\n", __func__, Uri));
+
+  Status = GetRedfishSchemaInfo (Private->RedfishService, Private->JsonStructProtocol, Uri, NULL, &SchemaInfo);
+  if (EFI_ERROR (Status)) {
+    DEBUG ((DEBUG_ERROR, "%a: failed to get schema information from: %s %r\n", __func__, Uri, Status));
+    return Status;
+  }
+
+  //
+  // Check and see if this is target resource that we want to handle.
+  // Some resource is handled by other provider so we have to make sure this first.
+  //
+  DEBUG ((REDFISH_DEBUG_TRACE, "%a: Identify for %s\n", __func__, Uri));
+  ConfigLang = RedfishGetConfigLanguage (Uri);
+  if (ConfigLang == NULL) {
+    Status = EdkIIRedfishResourceConfigIdentify (&SchemaInfo, Uri, NULL, Private->InformationExchange);
+    if (EFI_ERROR (Status)) {
+      if (Status == EFI_UNSUPPORTED) {
+        DEBUG ((REDFISH_DEBUG_TRACE, "%a: \"%s\" is not handled by us\n", __func__, Uri));
+        return EFI_SUCCESS;
+      } else if (Status == EFI_NOT_FOUND) {
+        DEBUG ((REDFISH_DEBUG_TRACE, "%a: \"%s\" has nothing to handle\n", __func__, Uri));
+        return EFI_SUCCESS;
+      }
+
+      DEBUG ((DEBUG_ERROR, "%a: fail to identify resource: \"%s\": %r\n", __func__, Uri, Status));
+      return Status;
+    }
+  } else {
+    DEBUG ((REDFISH_DEBUG_TRACE, "%a: history record found: %s\n", __func__, ConfigLang));
+    FreePool (ConfigLang);
+  }
+
+  //
+  // Check and see if target property exist or not even when collection member exists.
+  // If not, we sill do provision.

%s/sill/still


+  //
+  DEBUG ((REDFISH_DEBUG_TRACE, "%a Check for %s\n", __func__, Uri));
+  Status = EdkIIRedfishResourceConfigCheck (&SchemaInfo, Uri, NULL);
+  if (EFI_ERROR (Status)) {
+    if (Status == EFI_UNSUPPORTED) {
+      DEBUG ((REDFISH_DEBUG_TRACE, "%a: \"%s\" is not handled by us\n", __func__, Uri));
+      return EFI_SUCCESS;
+    }
+
+    //
+    // The target property does not exist, do the provision to create property.
+    //
+    DEBUG ((REDFISH_DEBUG_TRACE, "%a provision for %s\n", __func__, Uri));
+    Status = EdkIIRedfishResourceConfigProvisioning (&SchemaInfo, Uri, NULL, Private->InformationExchange, FALSE);
+    if (EFI_ERROR (Status)) {
+      DEBUG ((DEBUG_ERROR, "%a: failed to provision with GET mode: %r\n", __func__, Status));
+    }
+
+    DEBUG ((REDFISH_DEBUG_TRACE, "%a: process resource for: %s finished\n", __func__, Uri));
+
+    return Status;
+  }
+
+  //
+  // Consume first.
+  //
+  DEBUG ((REDFISH_DEBUG_TRACE, "%a consume for %s\n", __func__, Uri));
+  Status = EdkIIRedfishResourceConfigConsume (&SchemaInfo, Uri, NULL);
+  if (EFI_ERROR (Status)) {
+    DEBUG ((DEBUG_ERROR, "%a: failed to consume resource for: %s: %r\n", __func__, Uri, Status));
+  }
+
+  //
+  // Patch.
+  //
+  DEBUG ((REDFISH_DEBUG_TRACE, "%a update for %s\n", __func__, Uri));
+  Status = EdkIIRedfishResourceConfigUpdate (&SchemaInfo, Uri, NULL);
+  if (EFI_ERROR (Status)) {
+    DEBUG ((DEBUG_ERROR, "%a: failed to update resource for: %s: %r\n", __func__, Uri, Status));
+  }
+
+  DEBUG ((REDFISH_DEBUG_TRACE, "%a: process resource for: %s finished\n", __func__, Uri));
+
+  return Status;
+}
diff --git a/RedfishClientPkg/Features/SecureBoot/v1_1_0/Dxe/SecureBootDxe.c b/RedfishClientPkg/Features/SecureBoot/v1_1_0/Dxe/SecureBootDxe.c
new file mode 100644
index 000000000..a0f4f3d14
--- /dev/null
+++ b/RedfishClientPkg/Features/SecureBoot/v1_1_0/Dxe/SecureBootDxe.c
@@ -0,0 +1,808 @@
+/** @file
+  Redfish feature driver implementation - SecureBoot
+
+  (C) Copyright 2020-2022 Hewlett Packard Enterprise Development LP<BR>
+  Copyright (c) 2023, NVIDIA CORPORATION & AFFILIATES. All rights reserved.
+
+  SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include "../Common/SecureBootCommon.h"
+
+extern REDFISH_RESOURCE_COMMON_PRIVATE  *mRedfishResourcePrivate;
+extern EFI_HANDLE                       mRedfishResourceConfigProtocolHandle;
+
+EFI_STATUS
+HandleResource (
+  IN  REDFISH_RESOURCE_COMMON_PRIVATE  *Private,
+  IN  EFI_STRING                       Uri
+  );
+
+/**
+  Provisioning redfish resource by given URI.
+
+  @param[in]   This                Pointer to EFI_HP_REDFISH_HII_PROTOCOL instance.
+  @param[in]   Uri                 Target URI to create resource.
+  @param[in]   PostMode            TRUE if the resource does not exist, post method is used.
+                                   FALSE if the resource exist but property is missing, put method is used.
+
+  @retval EFI_SUCCESS              Value is returned successfully.
+  @retval Others                   Some error happened.
+
+**/
+EFI_STATUS
+EFIAPI
+RedfishResourceProvisioningResource (
+  IN     EDKII_REDFISH_RESOURCE_CONFIG_PROTOCOL  *This,
+  IN     EFI_STRING                              Uri,
+  IN     BOOLEAN                                 PostMode
+  )
+{
+  REDFISH_RESOURCE_COMMON_PRIVATE  *Private;
+  EFI_STATUS                       Status;
+  REDFISH_RESPONSE                 Response;
+
+  if ((This == NULL) || IS_EMPTY_STRING (Uri)) {
+    return EFI_INVALID_PARAMETER;
+  }
+
+  DEBUG ((REDFISH_DEBUG_TRACE, "%a: provisioning in %s mode\n", __func__, (PostMode ? L"POST" : L"PATCH")));


This message conflicts with PostMode parameter description.



+
+  ZeroMem (&Response, sizeof (REDFISH_RESPONSE));
+  Private = REDFISH_RESOURCE_COMMON_PRIVATE_DATA_FROM_RESOURCE_PROTOCOL (This);
+
+  if (Private->RedfishService == NULL) {
+    return EFI_NOT_READY;
+  }
+
+  Status = RedfishHttpGetResource (Private->RedfishService, Uri, NULL, &Response, TRUE);
+  if (EFI_ERROR (Status)) {
+    DEBUG ((DEBUG_ERROR, "%a: get resource from: %s failed\n", __func__, Uri));
+    return Status;
+  }
+
+  Private->Uri     = Uri;
+  Private->Payload = Response.Payload;
+  ASSERT (Private->Payload != NULL);
+
+  Status = RedfishProvisioningResourceCommon (Private, !PostMode);
+  if (EFI_ERROR (Status)) {
+    DEBUG ((DEBUG_ERROR, "%a: failed to provision resource to: %s: %r\n", __func__, Uri, Status));
+  } else {
+    //
+    // Get latest ETag on URI and keep it in variable.
+    //
+    SetEtagFromUri (Private->RedfishService, Private->Uri, TRUE);
+  }
+
+  //
+  // Release resource
+  //
+  RedfishHttpFreeResponse (&Response);
+  Private->Payload = NULL;
+
+  return Status;
+}
+
+/**
+  Consume resource from given URI.
+
+  @param[in]   This                Pointer to EFI_HP_REDFISH_HII_PROTOCOL instance.
+  @param[in]   Uri                 The target URI to consume.
+
+  @retval EFI_SUCCESS              Value is returned successfully.
+  @retval Others                   Some error happened.
+
+**/
+EFI_STATUS
+EFIAPI
+RedfishResourceConsumeResource (
+  IN     EDKII_REDFISH_RESOURCE_CONFIG_PROTOCOL  *This,
+  IN     EFI_STRING                              Uri
+  )
+{
+  REDFISH_RESOURCE_COMMON_PRIVATE  *Private;
+  EFI_STATUS                       Status;
+  REDFISH_RESPONSE                 Response;
+  EFI_STRING                       PendingSettingUri;
+  REDFISH_RESPONSE                 PendingSettingResponse;
+  REDFISH_RESPONSE                 *ExpectedResponse;
+  CHAR8                            *Etag;
+
+  if ((This == NULL) || IS_EMPTY_STRING (Uri)) {
+    return EFI_INVALID_PARAMETER;
+  }
+
+  ZeroMem (&Response, sizeof (REDFISH_RESPONSE));
+  ZeroMem (&PendingSettingResponse, sizeof (REDFISH_RESPONSE));
+  Private = REDFISH_RESOURCE_COMMON_PRIVATE_DATA_FROM_RESOURCE_PROTOCOL (This);
+
+  if (Private->RedfishService == NULL) {
+    return EFI_NOT_READY;
+  }
+
+  Status = RedfishHttpGetResource (Private->RedfishService, Uri, NULL, &Response, TRUE);
+  if (EFI_ERROR (Status)) {
+    DEBUG ((DEBUG_ERROR, "%a: get resource from: %s failed\n", __func__, Uri));
+    return Status;
+  }
+
+  //
+  // Check and see if "@Redfish.Settings" exist or not.
+  //
+  PendingSettingUri = NULL;
+  Status            = GetPendingSettings (
+                        Private->RedfishService,
+                        Response.Payload,
+                        &PendingSettingResponse,
+                        &PendingSettingUri
+                        );
+  if (!EFI_ERROR (Status)) {
+    DEBUG ((REDFISH_DEBUG_TRACE, "%a: @Redfish.Settings found: %s\n", __func__, PendingSettingUri));
+    Private->Uri     = PendingSettingUri;
+    ExpectedResponse = &PendingSettingResponse;
+  } else {
+    Private->Uri     = Uri;
+    ExpectedResponse = &Response;
+  }
+
+  Private->Payload = ExpectedResponse->Payload;
+  ASSERT (Private->Payload != NULL);
+
+  Private->Json = JsonDumpString (RedfishJsonInPayload (Private->Payload), EDKII_JSON_COMPACT);
+  ASSERT (Private->Json != NULL);
+
+  //
+  // Searching for etag in HTTP response header
+  //
+  Etag   = NULL;
+  Status = GetHttpResponseEtag (ExpectedResponse, &Etag);
+  if (EFI_ERROR (Status)) {
+    DEBUG ((DEBUG_ERROR, "%a: failed to get ETag from HTTP header\n", __func__));
+  }
+
+  Status = RedfishConsumeResourceCommon (Private, Private->Json, Etag);
+  if (EFI_ERROR (Status)) {
+    DEBUG ((DEBUG_ERROR, "%a: failed to consume resource from: %s: %r\n", __func__, Private->Uri, Status));
+  }
+
+  //
+  // Release resource
+  //
+  RedfishHttpFreeResponse (&Response);
+  RedfishHttpFreeResponse (&PendingSettingResponse);
+  Private->Payload = NULL;
+
+  if (Private->Json != NULL) {
+    FreePool (Private->Json);
+    Private->Json = NULL;
+  }
+
+  if (Etag != NULL) {
+    FreePool (Etag);
+  }
+
+  if (PendingSettingUri != NULL) {
+    FreePool (PendingSettingUri);
+  }
+
+  return Status;
+}
+
+/**
+  Get information about this protocol.
+
+  @param[in]   This                Pointer to EFI_HP_REDFISH_HII_PROTOCOL instance.
+  @param[out]  Schema              Supported schema.
+  @param[out]  Major               Supported major number.
+  @param[out]  Minor               Supported minor number.
+  @param[out]  Errata              Supported errata number.
+
+  @retval EFI_SUCCESS              Value is returned successfully.
+  @retval Others                   Some error happened.
+
+**/
+EFI_STATUS
+EFIAPI
+RedfishResourceGetInfo (
+  IN     EDKII_REDFISH_RESOURCE_CONFIG_PROTOCOL  *This,
+  OUT    REDFISH_SCHEMA_INFO                     *Info
+  )
+{
+  if ((This == NULL) || (Info == NULL)) {
+    return EFI_INVALID_PARAMETER;
+  }
+
+  AsciiStrCpyS (Info->Schema, REDFISH_SCHEMA_STRING_SIZE, RESOURCE_SCHEMA);
+  AsciiStrCpyS (Info->Major, REDFISH_SCHEMA_VERSION_SIZE, RESOURCE_SCHEMA_MAJOR);
+  AsciiStrCpyS (Info->Minor, REDFISH_SCHEMA_VERSION_SIZE, RESOURCE_SCHEMA_MINOR);
+  AsciiStrCpyS (Info->Errata, REDFISH_SCHEMA_VERSION_SIZE, RESOURCE_SCHEMA_ERRATA);
+
+  return EFI_SUCCESS;
+}
+
+/**
+  Update resource to given URI.
+
+  @param[in]   This                Pointer to EFI_HP_REDFISH_HII_PROTOCOL instance.
+  @param[in]   Uri                 The target URI to consume.
+
+  @retval EFI_SUCCESS              Value is returned successfully.
+  @retval Others                   Some error happened.
+
+**/
+EFI_STATUS
+EFIAPI
+RedfishResourceUpdate (
+  IN     EDKII_REDFISH_RESOURCE_CONFIG_PROTOCOL  *This,
+  IN     EFI_STRING                              Uri
+  )
+{
+  REDFISH_RESOURCE_COMMON_PRIVATE  *Private;
+  EFI_STATUS                       Status;
+  REDFISH_RESPONSE                 Response;
+
+  if ((This == NULL) || IS_EMPTY_STRING (Uri)) {
+    return EFI_INVALID_PARAMETER;
+  }
+
+  ZeroMem (&Response, sizeof (REDFISH_RESPONSE));
+  Private = REDFISH_RESOURCE_COMMON_PRIVATE_DATA_FROM_RESOURCE_PROTOCOL (This);
+
+  if (Private->RedfishService == NULL) {
+    return EFI_NOT_READY;
+  }
+
+  Status = RedfishHttpGetResource (Private->RedfishService, Uri, NULL, &Response, TRUE);
+  if (EFI_ERROR (Status)) {
+    DEBUG ((DEBUG_ERROR, "%a: get resource from: %s failed\n", __func__, Uri));
+    return Status;
+  }
+
+  Private->Uri     = Uri;
+  Private->Payload = Response.Payload;
+  ASSERT (Private->Payload != NULL);
+
+  Private->Json = JsonDumpString (RedfishJsonInPayload (Private->Payload), EDKII_JSON_COMPACT);
+  ASSERT (Private->Json != NULL);
+
+  Status = RedfishUpdateResourceCommon (Private, Private->Json);
+  if (EFI_ERROR (Status)) {
+    DEBUG ((DEBUG_ERROR, "%a: failed to update resource to: %s: %r\n", __func__, Uri, Status));
+  } else {
+    //
+    // Get latest ETag on URI and keep it in variable.
+    //
+    SetEtagFromUri (Private->RedfishService, Private->Uri, TRUE);
+  }
+
+  //
+  // Release resource
+  //
+  RedfishHttpFreeResponse (&Response);
+  Private->Payload = NULL;
+
+  if (Private->Json != NULL) {
+    FreePool (Private->Json);
+    Private->Json = NULL;
+  }
+
+  return Status;
+}
+
+/**
+  Check resource on given URI.
+
+  @param[in]   This                Pointer to EFI_HP_REDFISH_HII_PROTOCOL instance.
+  @param[in]   Uri                 The target URI to consume.
+
+  @retval EFI_SUCCESS              Value is returned successfully.
+  @retval Others                   Some error happened.
+
+**/
+EFI_STATUS
+EFIAPI
+RedfishResourceCheck (
+  IN     EDKII_REDFISH_RESOURCE_CONFIG_PROTOCOL  *This,
+  IN     EFI_STRING                              Uri
+  )
+{
+  REDFISH_RESOURCE_COMMON_PRIVATE  *Private;
+  EFI_STATUS                       Status;
+  REDFISH_RESPONSE                 Response;
+  CHAR8                            *Etag;
+
+  if ((This == NULL) || IS_EMPTY_STRING (Uri)) {
+    return EFI_INVALID_PARAMETER;
+  }
+
+  ZeroMem (&Response, sizeof (REDFISH_RESPONSE));
+  Private = REDFISH_RESOURCE_COMMON_PRIVATE_DATA_FROM_RESOURCE_PROTOCOL (This);
+
+  if (Private->RedfishService == NULL) {
+    return EFI_NOT_READY;
+  }
+
+  Status = RedfishHttpGetResource (Private->RedfishService, Uri, NULL, &Response, TRUE);
+  if (EFI_ERROR (Status)) {
+    DEBUG ((DEBUG_ERROR, "%a: get resource from: %s failed\n", __func__, Uri));
+    return Status;
+  }
+
+  Private->Uri     = Uri;
+  Private->Payload = Response.Payload;
+  ASSERT (Private->Payload != NULL);
+
+  Private->Json = JsonDumpString (RedfishJsonInPayload (Private->Payload), EDKII_JSON_COMPACT);
+  ASSERT (Private->Json != NULL);
+
+  //
+  // Find etag in HTTP response header
+  //
+  Etag   = NULL;
+  Status = GetHttpResponseEtag (&Response, &Etag);
+  if (EFI_ERROR (Status)) {
+    DEBUG ((DEBUG_ERROR, "%a: failed to get ETag from HTTP header\n", __func__));
+  }
+
+  Status = RedfishCheckResourceCommon (Private, Private->Json, Etag);
+  if (EFI_ERROR (Status)) {
+    DEBUG ((DEBUG_ERROR, "%a: failed to check resource from: %s: %r\n", __func__, Uri, Status));
+  }
+
+  //
+  // Release resource
+  //
+  if (Etag != NULL) {
+    FreePool (Etag);
+  }
+
+  RedfishHttpFreeResponse (&Response);
+  Private->Payload = NULL;
+
+  if (Private->Json != NULL) {
+    FreePool (Private->Json);
+    Private->Json = NULL;
+  }
+
+  return Status;
+}
+
+/**
+  Identify resource on given URI.
+
+  @param[in]   This                Pointer to EDKII_REDFISH_RESOURCE_CONFIG_PROTOCOL instance.
+  @param[in]   Uri                 The target URI to consume.
+
+  @retval EFI_SUCCESS              This is target resource which we want to handle.
+  @retval EFI_UNSUPPORTED          This is not the target resource.
+  @retval Others                   Some error happened.
+
+**/
+EFI_STATUS
+EFIAPI
+RedfishResourceIdentify (
+  IN     EDKII_REDFISH_RESOURCE_CONFIG_PROTOCOL  *This,
+  IN     EFI_STRING                              Uri
+  )
+{
+  REDFISH_RESOURCE_COMMON_PRIVATE  *Private;
+  EFI_STATUS                       Status;
+  REDFISH_RESPONSE                 Response;
+
+  if ((This == NULL) || IS_EMPTY_STRING (Uri)) {
+    return EFI_INVALID_PARAMETER;
+  }
+
+  ZeroMem (&Response, sizeof (REDFISH_RESPONSE));
+  Private = REDFISH_RESOURCE_COMMON_PRIVATE_DATA_FROM_RESOURCE_PROTOCOL (This);
+
+  if (Private->RedfishService == NULL) {
+    return EFI_NOT_READY;
+  }
+
+  Status = RedfishHttpGetResource (Private->RedfishService, Uri, NULL, &Response, TRUE);
+  if (EFI_ERROR (Status)) {
+    DEBUG ((DEBUG_ERROR, "%a: get resource from: %s failed\n", __func__, Uri));
+    return Status;
+  }
+
+  Private->Uri     = Uri;
+  Private->Payload = Response.Payload;
+  ASSERT (Private->Payload != NULL);
+
+  Private->Json = JsonDumpString (RedfishJsonInPayload (Private->Payload), EDKII_JSON_COMPACT);
+  ASSERT (Private->Json != NULL);
+
+  Status = RedfishIdentifyResourceCommon (Private, Private->Json);
+  if (EFI_ERROR (Status)) {
+    DEBUG ((DEBUG_ERROR, "%a: identify %s failed: %r\n", __func__, Uri, Status));
+  }
+
+  //
+  // Release resource
+  //
+  RedfishHttpFreeResponse (&Response);
+  Private->Payload = NULL;
+
+  if (Private->Json != NULL) {
+    FreePool (Private->Json);
+    Private->Json = NULL;
+  }
+
+  return Status;
+}
+
+EDKII_REDFISH_RESOURCE_CONFIG_PROTOCOL  mRedfishResourceConfig = {
+  RedfishResourceProvisioningResource,
+  RedfishResourceConsumeResource,
+  RedfishResourceUpdate,
+  RedfishResourceCheck,
+  RedfishResourceIdentify,
+  RedfishResourceGetInfo
+};
+
+/**
+  Initialize a Redfish configure handler.
+
+  This function will be called by the Redfish config driver to initialize each Redfish configure
+  handler.
+
+  @param[in]   This                     Pointer to EDKII_REDFISH_CONFIG_HANDLER_PROTOCOL instance.
+  @param[in]   RedfishConfigServiceInfo Redfish service information.
+
+  @retval EFI_SUCCESS                  The handler has been initialized successfully.
+  @retval EFI_DEVICE_ERROR             Failed to create or configure the REST EX protocol instance.
+  @retval EFI_ALREADY_STARTED          This handler has already been initialized.
+  @retval Other                        Error happens during the initialization.
+
+**/
+EFI_STATUS
+EFIAPI
+RedfishResourceInit (
+  IN  EDKII_REDFISH_CONFIG_HANDLER_PROTOCOL  *This,
+  IN  REDFISH_CONFIG_SERVICE_INFORMATION     *RedfishConfigServiceInfo
+  )
+{
+  REDFISH_RESOURCE_COMMON_PRIVATE  *Private;
+
+  Private = REDFISH_RESOURCE_COMMON_PRIVATE_DATA_FROM_CONFIG_PROTOCOL (This);
+
+  Private->RedfishService = RedfishCreateService (RedfishConfigServiceInfo);
+  if (Private->RedfishService == NULL) {
+    return EFI_DEVICE_ERROR;
+  }
+
+  return EFI_SUCCESS;
+}
+
+/**
+  Stop a Redfish configure handler.
+
+  @param[in]   This                Pointer to EDKII_REDFISH_CONFIG_HANDLER_PROTOCOL instance.
+
+  @retval EFI_SUCCESS              This handler has been stoped successfully.
+  @retval Others                   Some error happened.
+
+**/
+EFI_STATUS
+EFIAPI
+RedfishResourceStop (
+  IN  EDKII_REDFISH_CONFIG_HANDLER_PROTOCOL  *This
+  )
+{
+  REDFISH_RESOURCE_COMMON_PRIVATE  *Private;
+
+  Private = REDFISH_RESOURCE_COMMON_PRIVATE_DATA_FROM_CONFIG_PROTOCOL (This);
+
+  if (Private->Event != NULL) {
+    gBS->CloseEvent (Private->Event);
+    Private->Event = NULL;
+  }
+
+  if (Private->RedfishService != NULL) {
+    RedfishCleanupService (Private->RedfishService);
+    Private->RedfishService = NULL;
+  }
+
+  return EFI_SUCCESS;
+}
+
+EDKII_REDFISH_CONFIG_HANDLER_PROTOCOL  mRedfishConfigHandler = {
+  RedfishResourceInit,
+  RedfishResourceStop
+};
+
+/**
+  Callback function when gEfiRestJsonStructureProtocolGuid is installed.
+
+  @param[in] Event    Event whose notification function is being invoked.
+  @param[in] Context  Pointer to the notification function's context.
+**/
+VOID
+EFIAPI
+EfiRestJsonStructureProtocolIsReady (
+  IN  EFI_EVENT  Event,
+  IN  VOID       *Context
+  )
+{
+  EFI_STATUS  Status;
+
+  if (mRedfishResourcePrivate == NULL) {
+    return;
+  }
+
+  if (mRedfishResourcePrivate->JsonStructProtocol != NULL) {
+    return;
+  }
+
+  Status = gBS->LocateProtocol (
+                  &gEfiRestJsonStructureProtocolGuid,
+                  NULL,
+                  (VOID **)&mRedfishResourcePrivate->JsonStructProtocol
+                  );
+  if (EFI_ERROR (Status)) {
+    DEBUG ((DEBUG_ERROR, "%a: failed to locate gEfiRestJsonStructureProtocolGuid: %r\n", __func__, Status));
+  }
+
+  gBS->CloseEvent (Event);
+}
+
+/**
+  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
+RedfishResourceUnload (
+  IN EFI_HANDLE  ImageHandle
+  )
+{
+  EFI_STATUS                             Status;
+  EDKII_REDFISH_CONFIG_HANDLER_PROTOCOL  *ConfigHandler;
+
+  if (mRedfishResourcePrivate == NULL) {
+    return EFI_NOT_READY;
+  }
+
+  ConfigHandler = NULL;
+
+  //
+  // Firstly, find ConfigHandler Protocol interface in this ImageHandle.
+  //
+  Status = gBS->OpenProtocol (
+                  ImageHandle,
+                  &gEdkIIRedfishConfigHandlerProtocolGuid,
+                  (VOID **)&ConfigHandler,
+                  NULL,
+                  NULL,
+                  EFI_OPEN_PROTOCOL_BY_HANDLE_PROTOCOL
+                  );
+  if (EFI_ERROR (Status) || (ConfigHandler == NULL)) {
+    return Status;
+  }
+
+  ConfigHandler->Stop (ConfigHandler);
+
+  //
+  // Last, uninstall ConfigHandler Protocol and resource protocol.
+  //
+  Status = gBS->UninstallMultipleProtocolInterfaces (
+                  ImageHandle,
+                  &gEdkIIRedfishConfigHandlerProtocolGuid,
+                  ConfigHandler,
+                  &gEdkIIRedfishResourceConfigProtocolGuid,
+                  &mRedfishResourcePrivate->RedfishResourceConfig,
+                  NULL
+                  );
+
+  FreePool (mRedfishResourcePrivate);
+  mRedfishResourcePrivate = NULL;
+
+  return Status;
+}
+
+/**
+  The callback function provided by Redfish Feature driver.
+
+  @param[in]     This                Pointer to EDKII_REDFISH_FEATURE_PROTOCOL instance.
+  @param[in]     FeatureAction       The action Redfish feature driver should take.
+  @param[in]     Uri                 The collection URI.
+  @param[in]     Context             The context of Redfish feature driver.
+  @param[in,out] InformationExchange The pointer to RESOURCE_INFORMATION_EXCHANGE
+
+  @retval EFI_SUCCESS              Redfish feature driver callback is executed successfully.
+  @retval Others                   Some errors happened.
+
+  @retval EFI_SUCCESS              Redfish feature driver callback is executed successfully.
+  @retval Others                   Some errors happened.
+
+**/
+EFI_STATUS
+EFIAPI
+RedfishExternalResourceResourceFeatureCallback (
+  IN     EDKII_REDFISH_FEATURE_PROTOCOL  *This,
+  IN     FEATURE_CALLBACK_ACTION         FeatureAction,
+  IN     VOID                            *Context,
+  IN OUT RESOURCE_INFORMATION_EXCHANGE   *InformationExchange
+  )
+{
+  EFI_STATUS                       Status;
+  REDFISH_SERVICE                  RedfishService;
+  REDFISH_RESOURCE_COMMON_PRIVATE  *Private;
+  EFI_STRING                       ResourceUri;
+  EFI_STRING                       SecureBootUri;
+
+  if (FeatureAction != CallbackActionStartOperation) {
+    return EFI_UNSUPPORTED;
+  }
+
+  Private = (REDFISH_RESOURCE_COMMON_PRIVATE *)Context;
+
+  RedfishService = Private->RedfishService;
+  if (RedfishService == NULL) {
+    DEBUG ((DEBUG_ERROR, "%a: no Redfish service configured\n", __func__));
+    return EFI_NOT_READY;
+  }
+
+  //
+  // Save in private structure.
+  //
+  Private->InformationExchange = InformationExchange;
+
+  //
+  // Find Redfish version on Redfish ser
+  //
+  Private->RedfishVersion = RedfishGetVersion (RedfishService);
+
+  //
+  // Create the full URI from Redfish service root.
+  //
+  ResourceUri = (EFI_STRING)AllocateZeroPool (MAX_URI_LENGTH * sizeof (CHAR16));
+  if (ResourceUri == NULL) {
+    DEBUG ((DEBUG_ERROR, "%a: Fail to allocate memory for full URI.\n", __func__));
+    return EFI_OUT_OF_RESOURCES;
+  }
+
+  StrCatS (ResourceUri, MAX_URI_LENGTH, Private->RedfishVersion);
+  StrCatS (ResourceUri, MAX_URI_LENGTH, InformationExchange->SendInformation.FullUri);
+
+  //
+  // Initialize collection path
+  //
+  SecureBootUri = RedfishGetUri (ResourceUri);
+  if (SecureBootUri == NULL) {
+    ASSERT (FALSE);
+    FreePool (ResourceUri);
+    return EFI_OUT_OF_RESOURCES;
+  }
+
+  Status = HandleResource (Private, SecureBootUri);
+  if (EFI_ERROR (Status)) {
+    DEBUG ((DEBUG_ERROR, "%a: process external resource: %s failed: %r\n", __func__, SecureBootUri, Status));
+  }
+
+  FreePool (SecureBootUri);
+  FreePool (ResourceUri);
+  return Status;
+}
+
+/**
+  Callback function when gEdkIIRedfishFeatureProtocolGuid is installed.
+
+  @param[in] Event    Event whose notification function is being invoked.
+  @param[in] Context  Pointer to the notification function's context.
+**/
+VOID
+EFIAPI
+EdkIIRedfishFeatureProtocolIsReady (
+  IN  EFI_EVENT  Event,
+  IN  VOID       *Context
+  )
+{
+  EFI_STATUS                      Status;
+  EDKII_REDFISH_FEATURE_PROTOCOL  *FeatureProtocol;
+
+  if (mRedfishResourcePrivate == NULL) {
+    return;
+  }
+
+  if (mRedfishResourcePrivate->FeatureProtocol != NULL) {
+    return;
+  }
+
+  Status = gBS->LocateProtocol (
+                  &gEdkIIRedfishFeatureProtocolGuid,
+                  NULL,
+                  (VOID **)&FeatureProtocol
+                  );
+  if (EFI_ERROR (Status)) {
+    DEBUG ((DEBUG_ERROR, "%a: failed to locate gEdkIIRedfishFeatureProtocolGuid: %r\n", __func__, Status));
+    gBS->CloseEvent (Event);
+    return;
+  }
+
+  Status = FeatureProtocol->Register (
+                              FeatureProtocol,
+                              REDFISH_MANAGED_URI,
+                              RedfishExternalResourceResourceFeatureCallback,
+                              (VOID *)mRedfishResourcePrivate
+                              );
+  if (EFI_ERROR (Status)) {
+    DEBUG ((DEBUG_ERROR, "%a: failed to register %s: %r\n", __func__, REDFISH_MANAGED_URI, Status));
+  }
+
+  mRedfishResourcePrivate->FeatureProtocol = FeatureProtocol;
+
+  gBS->CloseEvent (Event);
+}
+
+/**
+  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. It initialize the global variables and
+  publish the driver binding protocol.
+
+  @param[in]   ImageHandle      The firmware allocated handle for the UEFI image.
+  @param[in]   SystemTable      A pointer to the EFI System Table.
+
+  @retval EFI_SUCCESS           The operation completed successfully.
+  @retval EFI_ACCESS_DENIED     EFI_ISCSI_INITIATOR_NAME_PROTOCOL was installed unexpectedly.
+  @retval Others                Other errors as indicated.
+**/
+EFI_STATUS
+EFIAPI
+RedfishResourceEntryPoint (
+  IN EFI_HANDLE        ImageHandle,
+  IN EFI_SYSTEM_TABLE  *SystemTable
+  )
+{
+  EFI_STATUS  Status;
+  VOID        *Registration;
+
+  if (mRedfishResourcePrivate != NULL) {
+    return EFI_ALREADY_STARTED;
+  }
+
+  mRedfishResourceConfigProtocolHandle = ImageHandle;
+
+  mRedfishResourcePrivate = AllocateZeroPool (sizeof (REDFISH_RESOURCE_COMMON_PRIVATE));
+  CopyMem (&mRedfishResourcePrivate->ConfigHandler, &mRedfishConfigHandler, sizeof (EDKII_REDFISH_CONFIG_HANDLER_PROTOCOL));
+  CopyMem (&mRedfishResourcePrivate->RedfishResourceConfig, &mRedfishResourceConfig, sizeof (EDKII_REDFISH_RESOURCE_CONFIG_PROTOCOL));
+
+  //
+  // Publish config handler protocol and resource protocol.
+  //
+  Status = gBS->InstallMultipleProtocolInterfaces (
+                  &ImageHandle,
+                  &gEdkIIRedfishConfigHandlerProtocolGuid,
+                  &mRedfishResourcePrivate->ConfigHandler,
+                  &gEdkIIRedfishResourceConfigProtocolGuid,
+                  &mRedfishResourcePrivate->RedfishResourceConfig,
+                  NULL
+                  );
+
+  EfiCreateProtocolNotifyEvent (
+    &gEfiRestJsonStructureProtocolGuid,
+    TPL_CALLBACK,
+    EfiRestJsonStructureProtocolIsReady,
+    NULL,
+    &Registration
+    );
+
+  EfiCreateProtocolNotifyEvent (
+    &gEdkIIRedfishFeatureProtocolGuid,
+    TPL_CALLBACK,
+    EdkIIRedfishFeatureProtocolIsReady,
+    (VOID *)mRedfishResourcePrivate,
+    &Registration
+    );
+
+  return Status;
+}
diff --git a/RedfishClientPkg/RedfishClient.fdf.inc b/RedfishClientPkg/RedfishClient.fdf.inc
index 59b8acba1..154f641b2 100644
--- a/RedfishClientPkg/RedfishClient.fdf.inc
+++ b/RedfishClientPkg/RedfishClient.fdf.inc
@@ -25,6 +25,7 @@
  INF RedfishClientPkg/HiiToRedfishBiosDxe/HiiToRedfishBiosDxe.inf
  INF RedfishClientPkg/Features/BootOptionCollection/BootOptionCollectionDxe.inf
  INF RedfishClientPkg/Features/BootOption/v1_0_4/Dxe/BootOptionDxe.inf
+  INF RedfishClientPkg/Features/SecureBoot/v1_1_0/Dxe/SecureBootDxe.inf

  !include RedfishClientPkg/RedfishJsonStructureDxe.fdf.inc
  #
--
2.34.1



Regards,
Mike



-=-=-=-=-=-=-=-=-=-=-=-
Groups.io Links: You receive all messages sent to this group.
View/Reply Online (#117119): https://edk2.groups.io/g/devel/message/117119
Mute This Topic: https://groups.io/mt/104927848/7686176
Group Owner: devel+owner@edk2.groups.io
Unsubscribe: https://edk2.groups.io/g/devel/unsub [rebecca@openfw.io]
-=-=-=-=-=-=-=-=-=-=-=-



[-- Attachment #2: Type: text/html, Size: 112493 bytes --]

^ permalink raw reply related	[flat|nested] 5+ messages in thread

* Re: [edk2-devel] [edk2-redfish-client][PATCH 1/2] RedfishClientPkg/Features: support Redfish Secure Boot
  2024-03-26 13:57   ` Nickle Wang via groups.io
@ 2024-03-26 22:56     ` Mike Maslenkin
  2024-04-01 14:25       ` Nickle Wang via groups.io
  0 siblings, 1 reply; 5+ messages in thread
From: Mike Maslenkin @ 2024-03-26 22:56 UTC (permalink / raw)
  To: Nickle Wang; +Cc: devel, Abner Chang, Igor Kulchytskyy, Nick Ramirez

[-- Attachment #1: Type: text/plain, Size: 66172 bytes --]

Hi Nickle,

On Tue, Mar 26, 2024 at 4:57 PM Nickle Wang <nicklew@nvidia.com> wrote:

> Hi Mike,
>
>
>
> Thanks for your review. I addressed your review comments in pull request:
> https://github.com/tianocore/edk2-redfish-client/pull/83
>
>
>
> I am waiting for Abner’s patch (PR#84) because I plan to incorporate
> Abner’s changes into this driver. I will send version 2 patch series here
> for review later.
>
>
>
> Regards,
>
> Nickle
>
>
>


I see my comments were addressed, and I agree with that.

But I think I found another minor leaks in a common pattern:

+  if (PropertyChecker (SecureBootCs->SecureBootMode, ProvisionMode)) {
+    Status = GetSetupMode (&SetupMode);
+    if (!EFI_ERROR (Status)) {
+      AsciiStringValue = AllocateZeroPool (SECURE_BOOT_MODE_STR_LEN
*sizeof (CHAR8));
+      if (AsciiStringValue != NULL) {
+        AsciiSPrint (AsciiStringValue, SECURE_BOOT_MODE_STR_LEN *sizeof
(CHAR8), "%a", (SetupMode == USER_MODE ? SECURE_BOOT_USER_MODE :
SECURE_BOOT_SETUP_MODE));
+        if (ProvisionMode || (AsciiStrCmp (SecureBootCs->SecureBootMode,
AsciiStringValue) != 0)) {
+          SecureBootCs->SecureBootMode = AsciiStringValue;
+          PropertyChanged              = TRUE;
+        }
+      }
+    } else {
+      DEBUG ((DEBUG_ERROR, "%a: cannot read setup mode: %r\n", __func__,
Status));
+    }
+  }

For the case when PropertyChanged left FALSE, allocated values AsciiStringValue
and IntegerValue are leaked.

Also there is a one new question below:


> *From:* Mike Maslenkin <mike.maslenkin@gmail.com>
> *Sent:* Friday, March 15, 2024 3:38 AM
> *To:* devel@edk2.groups.io; Nickle Wang <nicklew@nvidia.com>
> *Cc:* Abner Chang <abner.chang@amd.com>; Igor Kulchytskyy <igork@ami.com>;
> Nick Ramirez <nramirez@nvidia.com>
> *Subject:* Re: [edk2-devel] [edk2-redfish-client][PATCH 1/2]
> RedfishClientPkg/Features: support Redfish Secure Boot
>
>
>
> *External email: Use caution opening links or attachments*
>
>
>
> Hi Nickle,
>
>
>
> please find my comments below
>
>
>
> On 14. 3. 2024., at 17:53, Nickle Wang via groups.io <nicklew=
> nvidia.com@groups.io> wrote:
>
>
>
> Introduce SecureBoot driver to support
> /redfish/v1/Systems/SYS/SecureBoot resource.
>
> Signed-off-by: Nickle Wang <nicklew@nvidia.com>
> Cc: Abner Chang <abner.chang@amd.com>
> Cc: Igor Kulchytskyy <igork@ami.com>
> Cc: Nick Ramirez <nramirez@nvidia.com>
> ---
> .../RedfishClientComponents.dsc.inc           |   2 +
> RedfishClientPkg/RedfishClientLibs.dsc.inc    |   4 +
> .../SecureBoot/v1_1_0/Dxe/SecureBootDxe.inf   |  60 ++
> .../v1_1_0/Common/SecureBootCommon.h          |  40 +
> .../v1_1_0/Common/SecureBootCommon.c          | 756 ++++++++++++++++
> .../SecureBoot/v1_1_0/Dxe/SecureBootDxe.c     | 808 ++++++++++++++++++
> RedfishClientPkg/RedfishClient.fdf.inc        |   1 +
> 7 files changed, 1671 insertions(+)
> create mode 100644
> RedfishClientPkg/Features/SecureBoot/v1_1_0/Dxe/SecureBootDxe.inf
> create mode 100644
> RedfishClientPkg/Features/SecureBoot/v1_1_0/Common/SecureBootCommon.h
> create mode 100644
> RedfishClientPkg/Features/SecureBoot/v1_1_0/Common/SecureBootCommon.c
> create mode 100644
> RedfishClientPkg/Features/SecureBoot/v1_1_0/Dxe/SecureBootDxe.c
>
> diff --git a/RedfishClientPkg/RedfishClientComponents.dsc.inc
> b/RedfishClientPkg/RedfishClientComponents.dsc.inc
> index ae2a4b025..42fc0c299 100644
> --- a/RedfishClientPkg/RedfishClientComponents.dsc.inc
> +++ b/RedfishClientPkg/RedfishClientComponents.dsc.inc
> @@ -34,6 +34,7 @@
>   RedfishClientPkg/Features/Bios/v1_0_9/Dxe/BiosDxe.inf
>
>   RedfishClientPkg/Features/BootOptionCollection/BootOptionCollectionDxe.inf
>   RedfishClientPkg/Features/BootOption/v1_0_4/Dxe/BootOptionDxe.inf
> +  RedfishClientPkg/Features/SecureBoot/v1_1_0/Dxe/SecureBootDxe.inf
>
>   !include RedfishClientPkg/RedfishJsonStructureDxe.dsc.inc
>
> @@ -47,3 +48,4 @@
>   RedfishClientPkg/Converter/Bios/v1_0_9/RedfishBios_V1_0_9_Dxe.inf
>
>   RedfishClientPkg/Converter/BootOptionCollection/RedfishBootOptionCollection_Dxe.inf
>
>   RedfishClientPkg/Converter/BootOption/v1_0_4/RedfishBootOption_V1_0_4_Dxe.inf
> +
>  RedfishClientPkg/Converter/SecureBoot/v1_1_0/RedfishSecureBoot_V1_1_0_Dxe.inf
> diff --git a/RedfishClientPkg/RedfishClientLibs.dsc.inc
> b/RedfishClientPkg/RedfishClientLibs.dsc.inc
> index 6599926ab..9126465df 100644
> --- a/RedfishClientPkg/RedfishClientLibs.dsc.inc
> +++ b/RedfishClientPkg/RedfishClientLibs.dsc.inc
> @@ -25,6 +25,8 @@
>
>   BiosV1_0_9Lib|RedfishClientPkg/ConverterLib/edk2library/Bios/v1_0_9/Lib.inf
>
>   BootOptionCollectionLib|RedfishClientPkg/ConverterLib/edk2library/BootOptionCollection/Lib.inf
>
>   BootOptionV1_0_4Lib|RedfishClientPkg/ConverterLib/edk2library/BootOption/v1_0_4/Lib.inf
> +
>  SecureBootV1_1_0Lib|RedfishClientPkg/ConverterLib/edk2library/SecureBoot/v1_1_0/Lib.inf
> +
>   #
>   # Above modules should be pulled in by build tool.
>   #
> @@ -42,3 +44,5 @@
>
>   RedfishAddendumLib|RedfishClientPkg/Library/RedfishAddendumLib/RedfishAddendumLib.inf
>   RedfishDebugLib|RedfishPkg/Library/RedfishDebugLib/RedfishDebugLib.inf
>   RedfishHttpLib|RedfishPkg/Library/RedfishHttpLib/RedfishHttpLib.inf
> +
>  SecureBootVariableLib|SecurityPkg/Library/SecureBootVariableLib/SecureBootVariableLib.inf
> +
>  PlatformPKProtectionLib|SecurityPkg/Library/PlatformPKProtectionLibVarPolicy/PlatformPKProtectionLibVarPolicy.inf
> diff --git
> a/RedfishClientPkg/Features/SecureBoot/v1_1_0/Dxe/SecureBootDxe.inf
> b/RedfishClientPkg/Features/SecureBoot/v1_1_0/Dxe/SecureBootDxe.inf
> new file mode 100644
> index 000000000..1ad8c623f
> --- /dev/null
> +++ b/RedfishClientPkg/Features/SecureBoot/v1_1_0/Dxe/SecureBootDxe.inf
> @@ -0,0 +1,60 @@
> +## @file
> +#
> +#  (C) Copyright 2020-2022 Hewlett Packard Enterprise Development LP<BR>
> +#  Copyright (c) 2022-2024, NVIDIA CORPORATION & AFFILIATES. All rights
> reserved.
> +#
> +#  SPDX-License-Identifier: BSD-2-Clause-Patent
> +#
> +##
> +
> +
> +[Defines]
> +  INF_VERSION               = 0x00010005
> +  BASE_NAME                 = SecureBootDxe
> +  FILE_GUID                 = 5E4025F8-DA42-468A-853E-6A1091D35052
> +  MODULE_TYPE               = DXE_DRIVER
> +  VERSION_STRING            = 1.0
> +  ENTRY_POINT               = RedfishResourceEntryPoint
> +  UNLOAD_IMAGE              = RedfishResourceUnload
> +
> +[Packages]
> +  MdePkg/MdePkg.dec
> +  MdeModulePkg/MdeModulePkg.dec
> +  SecurityPkg/SecurityPkg.dec
> +  RedfishPkg/RedfishPkg.dec
> +  RedfishClientPkg/RedfishClientPkg.dec
> +
> +[Sources]
> +  ../Common/SecureBootCommon.h
> +  ../Common/SecureBootCommon.c
> +  SecureBootDxe.c
> +
> +[LibraryClasses]
> +  BaseMemoryLib
> +  DebugLib
> +  EdkIIRedfishResourceConfigLib
> +  RedfishFeatureUtilityLib
> +  RedfishVersionLib
> +  RedfishResourceIdentifyLib
> +  SecureBootVariableLib
> +  UefiLib
> +  UefiDriverEntryPoint
> +  RedfishAddendumLib
>
> +  UefiRuntimeServicesTableLib
> +
> +[Protocols]
> +  gEdkIIRedfishConfigHandlerProtocolGuid          ## PRODUCED
> +  gEfiRestJsonStructureProtocolGuid               ## CONSUMED
> +  gEdkIIRedfishResourceConfigProtocolGuid         ## PRODUCED
> +  gEdkIIRedfishFeatureProtocolGuid                ## CONSUMED
> +
> +[Guids]
> +  gEfiSecureBootEnableDisableGuid                 ## CONSUMED
> +
> +[Pcd]
> +  gEfiRedfishClientPkgTokenSpaceGuid.PcdMaxRedfishSchemaStringSize
> +  gEfiRedfishClientPkgTokenSpaceGuid.PcdMaxRedfishSchemaVersionSize
> +  gEfiRedfishClientPkgTokenSpaceGuid.PcdRedfishSystemRebootRequired
> +
> +[Depex]
> +  TRUE
> diff --git
> a/RedfishClientPkg/Features/SecureBoot/v1_1_0/Common/SecureBootCommon.h
> b/RedfishClientPkg/Features/SecureBoot/v1_1_0/Common/SecureBootCommon.h
> new file mode 100644
> index 000000000..0d1824160
> --- /dev/null
> +++ b/RedfishClientPkg/Features/SecureBoot/v1_1_0/Common/SecureBootCommon.h
> @@ -0,0 +1,40 @@
> +/** @file
> +
> +  Redfish feature driver implementation - internal header file
> +  (C) Copyright 2020-2022 Hewlett Packard Enterprise Development LP<BR>
> +  Copyright (c) 2022-2024, NVIDIA CORPORATION & AFFILIATES. All rights
> reserved.
> +
> +  SPDX-License-Identifier: BSD-2-Clause-Patent
> +
> +**/
> +
> +#ifndef EFI_REDFISH_SECUREBOOT_COMMON_H_
> +#define EFI_REDFISH_SECUREBOOT_COMMON_H_
> +
> +#include <Guid/ImageAuthentication.h>
> +#include <Guid/GlobalVariable.h>
> +#include <Guid/AuthenticatedVariableFormat.h>
> +#include <RedfishJsonStructure/SecureBoot/v1_1_0/EfiSecureBootV1_1_0.h>
> +#include <RedfishResourceCommon.h>
> +#include <UefiSecureBoot.h>
> +#include <Library/UefiRuntimeServicesTableLib.h>
> +#include <Library/SecureBootVariableLib.h>
> +
> +//
> +// Schema information.
> +//
> +#define REDFISH_MANAGED_URI        L"Systems/{}/SecureBoot"
> +#define REDFISH_DUMMY_CONFIG_LANG  L"Systems/{1}/SecureBoot"
> +#define MAX_URI_LENGTH             256
> +#define RESOURCE_SCHEMA            "SecureBoot"
> +#define RESOURCE_SCHEMA_MAJOR      "1"
> +#define RESOURCE_SCHEMA_MINOR      "1"
> +#define RESOURCE_SCHEMA_ERRATA     "0"
> +#define RESOURCE_SCHEMA_VERSION    "v1_1_0"
> +#define SECURE_BOOT_SETUP_MODE     "SetupMode"
> +#define SECURE_BOOT_USER_MODE      "UserMode"
> +#define SECURE_BOOT_ENABLED        "Enabled"
> +#define SECURE_BOOT_DISABLED       "Disabled"
> +#define SECURE_BOOT_MODE_STR_LEN   16
> +
> +#endif
> diff --git
> a/RedfishClientPkg/Features/SecureBoot/v1_1_0/Common/SecureBootCommon.c
> b/RedfishClientPkg/Features/SecureBoot/v1_1_0/Common/SecureBootCommon.c
> new file mode 100644
> index 000000000..56a45ee72
> --- /dev/null
> +++ b/RedfishClientPkg/Features/SecureBoot/v1_1_0/Common/SecureBootCommon.c
> @@ -0,0 +1,756 @@
> +/** @file
> +  Redfish feature driver implementation - common functions
> +
> +  (C) Copyright 2020-2022 Hewlett Packard Enterprise Development LP<BR>
> +  Copyright (c) 2023-2024, NVIDIA CORPORATION & AFFILIATES. All rights
> reserved.
> +
> +  SPDX-License-Identifier: BSD-2-Clause-Patent
> +
> +**/
> +
> +#include "SecureBootCommon.h"
> +
> +CHAR8  SecureBootEmptyJson[] = "{\"@odata.id\": \"\", \"@odata.type\":
> \"#SecureBoot.v1_1_0.SecureBoot\", \"Id\": \"\", \"Name\": \"\",
> \"Attributes\":{}}";
> +
> +REDFISH_RESOURCE_COMMON_PRIVATE  *mRedfishResourcePrivate
>                                  = NULL;
> +EFI_HANDLE                       mRedfishResourceConfigProtocolHandle
>                      = NULL;
> +CHAR16
>                           *mSecureBootSupportedAttributes[SECURE_BOOT_MODE_STR_LEN]
> = {
> +  L"SecureBootCurrentBoot",
> +  L"SecureBootEnable",
> +  L"SecureBootMode"
> +};
> +
> +/**
> +  Read EFI_SECURE_BOOT_ENABLE_NAME variable and return its value to
> caller.
> +
> +  @retval BOOLEAN    TRUE when EFI_SECURE_BOOT_ENABLE_NAME value is
> SECURE_BOOT_ENABLE
> +                     FALSE when EFI_SECURE_BOOT_ENABLE_NAME value is
> SECURE_BOOT_DISABLE
> +**/
> +BOOLEAN
> +RedfishReadSecureBootEnable (
> +  VOID
> +  )
> +{
> +  UINT8    *Buffer;
> +  BOOLEAN  SecureBootEnableValue;
> +
> +  Buffer                = NULL;
> +  SecureBootEnableValue = FALSE;
> +
> +  GetVariable2 (
> +    EFI_SECURE_BOOT_ENABLE_NAME,
> +    &gEfiSecureBootEnableDisableGuid,
> +    (VOID **)&Buffer,
> +    NULL
> +    );
> +
> +  if (Buffer != NULL) {
> +    if (*Buffer == SECURE_BOOT_ENABLE) {
> +      SecureBootEnableValue = TRUE;
> +    }
> +
> +    FreePool (Buffer);
> +  }
> +
> +  return SecureBootEnableValue;
> +}
> +
> +/**
> +  Write EFI_SECURE_BOOT_ENABLE_NAME variable with given value.
> +
> +  @param[in]   SecureBootEnableValue    Value to write. TRUE is
> SECURE_BOOT_ENABLE.
> +                                        FALSE is SECURE_BOOT_DISABLE.
> +
> +  @retval EFI_SUCCESS              Write value successfully.
> +  @retval Others                   Some error happened.
> +**/
> +EFI_STATUS
> +RedfishWriteSecureBootEnable (
> +  BOOLEAN  SecureBootEnableValue
> +  )
> +{
> +  EFI_STATUS  Status;
> +  UINT8       VarValue;
> +
> +  VarValue = (SecureBootEnableValue ? SECURE_BOOT_ENABLE :
> SECURE_BOOT_DISABLE);
> +  Status   = gRT->SetVariable (
> +                    EFI_SECURE_BOOT_ENABLE_NAME,
> +                    &gEfiSecureBootEnableDisableGuid,
> +                    EFI_VARIABLE_NON_VOLATILE |
> EFI_VARIABLE_BOOTSERVICE_ACCESS,
> +                    sizeof (VarValue),
> +                    &VarValue
> +                    );
> +
> +  return Status;
> +}
> +
> +/**
> +  Consume Redfish resource in given Json data.
> +
> +  @param[in]   This                Pointer to
> REDFISH_RESOURCE_COMMON_PRIVATE instance.
> +  @param[in]   Json                The JSON to consume.
> +  @param[in]   HeaderEtag          The Etag string returned in HTTP
> header.
> +
> +  @retval EFI_SUCCESS              Consume Redfish attribute successfully.
> +  @retval Others                   Some error happened.
> +
> +**/
> +EFI_STATUS
> +RedfishConsumeResourceCommon (
> +  IN  REDFISH_RESOURCE_COMMON_PRIVATE  *Private,
> +  IN  CHAR8                            *Json,
> +  IN  CHAR8                            *HeaderEtag OPTIONAL
> +  )
> +{
> +  EFI_STATUS                        Status;
> +  EFI_REDFISH_SECUREBOOT_V1_1_0     *SecureBoot;
> +  EFI_REDFISH_SECUREBOOT_V1_1_0_CS  *SecureBootCs;
> +  BOOLEAN                           SecureBootEnableDisable;
> +
> +  if ((Private == NULL) || IS_EMPTY_STRING (Json)) {
> +    return EFI_INVALID_PARAMETER;
> +  }
> +
> +  SecureBoot              = NULL;
> +  SecureBootCs            = NULL;
> +  SecureBootEnableDisable = RedfishReadSecureBootEnable ();
> +
> +  Status = Private->JsonStructProtocol->ToStructure (
> +                                          Private->JsonStructProtocol,
> +                                          NULL,
> +                                          Json,
> +                                          (EFI_REST_JSON_STRUCTURE_HEADER
> **)&SecureBoot
> +                                          );
> +  if (EFI_ERROR (Status)) {
> +    DEBUG ((DEBUG_ERROR, "%a: ToStructure() failed: %r\n", __func__,
> Status));
> +    return Status;
> +  }
> +
> +  SecureBootCs = SecureBoot->SecureBoot;
> +
> +  //
> +  // Check ETAG to see if we need to consume it
> +  //
> +  if (CheckEtag (Private->Uri, HeaderEtag, SecureBootCs->odata_etag)) {
> +    //
> +    // No change
> +    //
> +    DEBUG ((REDFISH_DEBUG_TRACE, "%a: ETAG: %s has no change, ignore
> consume action\n", __func__, Private->Uri));
> +    Status = EFI_ALREADY_STARTED;
> +    goto ON_RELEASE;
> +  }
> +
> +  //
> +  // Secure boot enable
> +  //
> +  if (SecureBootCs->SecureBootEnable != NULL) {
> +    if (SecureBootEnableDisable != *SecureBootCs->SecureBootEnable) {
> +      //
> +      // Write value to "SecureBootEnable" variable. AuthVariableLib will
> enable or disable secure boot
> +      // based on "SecureBootEnable" value.
> +      //
> +      Status = RedfishWriteSecureBootEnable
> (*SecureBootCs->SecureBootEnable);
> +      if (EFI_ERROR (Status)) {
> +        DEBUG ((DEBUG_ERROR, "%a: write secure boot enable disable
> failed: %r\n", __func__, Status));
> +      } else {
> +        REDFISH_ENABLE_SYSTEM_REBOOT ();
> +      }
> +    } else {
> +      DEBUG ((REDFISH_DEBUG_TRACE, "%a: secure boot mode is not
> changed\n", __func__));
> +    }
> +  }
> +
> +ON_RELEASE:
> +
> +  //
> +  // Release resource.
> +  //
> +  Private->JsonStructProtocol->DestoryStructure (
> +                                 Private->JsonStructProtocol,
> +                                 (EFI_REST_JSON_STRUCTURE_HEADER
> *)SecureBoot
> +                                 );
> +
> +  return EFI_SUCCESS;
> +}
> +
> +/**
> +  Provision Redfish resource. This function reads secure boot variable
> and convert it
> +  to Redfish attribute.
> +
> +  @param[in]   JsonStructProtocol  Pointer to Json structure protocol.
> +  @param[in]   InputJson           Jason data on input.
> +  @param[in]   ResourceId          Resource ID. This is optional.
> +  @param[in]   ConfigureLang       Configure language for this Redfish
> resource.
> +  @param[in]   ProvisionMode       TRUE when this is to provision Redfish
> attribute to
> +                                   Redfish service. FALSE is to update
> Redfish attribute
> +                                   to Redfish service.
> +  @param[out]  ResultJson          Json data on output.
> +
> +  @retval EFI_SUCCESS              Provision Redfish attribute
> successfully.
> +  @retval Others                   Some error happened.
> +
> +**/
> +EFI_STATUS
> +ProvisioningSecureBootProperties (
> +  IN  EFI_REST_JSON_STRUCTURE_PROTOCOL  *JsonStructProtocol,
> +  IN  CHAR8                             *InputJson,
> +  IN  CHAR8                             *ResourceId OPTIONAL,
> +  IN  EFI_STRING                        ConfigureLang,
> +  IN  BOOLEAN                           ProvisionMode,
> +  OUT CHAR8                             **ResultJson
> +  )
> +{
> +  EFI_REDFISH_SECUREBOOT_V1_1_0     *SecureBoot;
> +  EFI_REDFISH_SECUREBOOT_V1_1_0_CS  *SecureBootCs;
> +  EFI_STATUS                        Status;
> +  BOOLEAN                           PropertyChanged;
> +  CHAR8                             *AsciiStringValue;
> +  INT32                             *IntegerValue;
> +  UINT8                             SetupMode;
> +  BOOLEAN                           SecureBootEnabled;
> +  BOOLEAN                           SecureBootEnableDisable;
> +
> +  if ((JsonStructProtocol == NULL) || (ResultJson == NULL) ||
> IS_EMPTY_STRING (InputJson) || IS_EMPTY_STRING (ConfigureLang)) {
> +    return EFI_INVALID_PARAMETER;
> +  }
> +
> +  DEBUG ((REDFISH_DEBUG_TRACE, "%a provision for %s with: %s\n",
> __func__, ConfigureLang, (ProvisionMode ? L"Provision resource" : L"Update
> resource")));
> +
> +  *ResultJson             = NULL;
> +  PropertyChanged         = FALSE;
> +  AsciiStringValue        = NULL;
> +  SecureBootEnableDisable = RedfishReadSecureBootEnable ();
> +  SecureBootEnabled       = IsSecureBootEnabled ();
> +
> +  SecureBoot = NULL;
> +  Status     = JsonStructProtocol->ToStructure (
> +                                     JsonStructProtocol,
> +                                     NULL,
> +                                     InputJson,
> +                                     (EFI_REST_JSON_STRUCTURE_HEADER
> **)&SecureBoot
> +                                     );
> +  if (EFI_ERROR (Status)) {
> +    DEBUG ((DEBUG_ERROR, "%a: ToStructure failure: %r\n", __func__,
> Status));
> +    return Status;
> +  }
> +
> +  SecureBootCs = SecureBoot->SecureBoot;
> +
> +  //
> +  // ID
> +  //
> +  if (SecureBootCs->Id != NULL) {
> +    SecureBootCs->Id = NULL;
> +  }
> +
> +  //
> +  // Name
> +  //
> +  if (SecureBootCs->Name != NULL) {
> +    SecureBootCs->Name = NULL;
> +  }
> +
> +  //
> +  // Secure boot variables that we will handle here
> +  //
> +  // EFI_SETUP_MODE_NAME (gEfiGlobalVariableGuid)
> +  // EFI_SECURE_BOOT_MODE_NAME (gEfiGlobalVariableGuid)
> +  // EFI_SECURE_BOOT_ENABLE_NAME (gEfiSecureBootEnableDisableGuid)
> +  //
> +
> +  //
> +  // Current Boot
> +  //
> +  if (PropertyChecker (SecureBootCs->SecureBootCurrentBoot,
> ProvisionMode)) {
> +    AsciiStringValue = AllocateZeroPool (SECURE_BOOT_MODE_STR_LEN *
> sizeof (CHAR8));
> +    if (AsciiStringValue != NULL) {
> +      AsciiSPrint (AsciiStringValue, SECURE_BOOT_MODE_STR_LEN, "%a",
> (SecureBootEnabled ? SECURE_BOOT_ENABLED : SECURE_BOOT_DISABLED));
> +      if (ProvisionMode || (AsciiStrCmp
> (SecureBootCs->SecureBootCurrentBoot, AsciiStringValue) != 0)) {
> +        SecureBootCs->SecureBootCurrentBoot = AsciiStringValue;
> +        PropertyChanged                     = TRUE;
> +      }
> +    } else {
> +      DEBUG ((DEBUG_ERROR, "%a: out of resource\n", __func__));
> +    }
> +  }
> +
> +  //
> +  // Secure boot enable
> +  //
> +  if (PropertyChecker (SecureBootCs->SecureBootEnable, ProvisionMode)) {
> +    if (ProvisionMode || (*SecureBootCs->SecureBootEnable !=
> SecureBootEnableDisable)) {
> +      IntegerValue = AllocatePool (sizeof (*IntegerValue));
> +      if (IntegerValue != NULL) {
> +        *IntegerValue                  = (SecureBootEnableDisable ? 0x01
> : 0x00);
> +        SecureBootCs->SecureBootEnable = IntegerValue;
> +        PropertyChanged                = TRUE;
> +      } else {
> +        DEBUG ((DEBUG_ERROR, "%a: out of resource\n", __func__));
> +      }
> +    }
> +  }
> +
> +  //
> +  // Secure boot mode
> +  //
> +  if (PropertyChecker (SecureBootCs->SecureBootMode, ProvisionMode)) {
> +    Status = GetSetupMode (&SetupMode);
> +    if (!EFI_ERROR (Status)) {
> +      AsciiStringValue = AllocateZeroPool (SECURE_BOOT_MODE_STR_LEN
> *sizeof (CHAR8));
> +      if (AsciiStringValue != NULL) {
> +        AsciiSPrint (AsciiStringValue, SECURE_BOOT_MODE_STR_LEN *sizeof
> (CHAR8), "%a", (SetupMode == USER_MODE ? SECURE_BOOT_USER_MODE :
> SECURE_BOOT_SETUP_MODE));
> +        if (ProvisionMode || (AsciiStrCmp (SecureBootCs->SecureBootMode,
> AsciiStringValue) != 0)) {
> +          SecureBootCs->SecureBootMode = AsciiStringValue;
> +          PropertyChanged              = TRUE;
> +        }
> +      }
> +    } else {
> +      DEBUG ((DEBUG_ERROR, "%a: cannot read setup mode: %r\n", __func__,
> Status));
> +    }
> +  }
> +
> +  //
> +  // Convert C structure back to JSON text.
> +  //
> +  Status = JsonStructProtocol->ToJson (
> +                                 JsonStructProtocol,
> +                                 (EFI_REST_JSON_STRUCTURE_HEADER
> *)SecureBoot,
> +                                 ResultJson
> +                                 );
> +  if (EFI_ERROR (Status)) {
> +    DEBUG ((DEBUG_ERROR, "%a: ToJson() failed: %r\n", __func__, Status));
> +    return Status;
>
>
>
>
>
>
>
>   SecureBoot structure leak. It is released below.
>
>
>
> +  }
> +
> +  //
> +  // Release resource.
> +  //
> +  JsonStructProtocol->DestoryStructure (
> +                        JsonStructProtocol,
> +                        (EFI_REST_JSON_STRUCTURE_HEADER *)SecureBoot
> +                        );
> +
> +  return (PropertyChanged ? EFI_SUCCESS : EFI_NOT_FOUND);
> +}
> +
> +/**
> +  Provision Redfish resource and upload data to Redfish service. This
> function
> +  checks OEM data and platform addendum data before sending data to
> Redfish service.
> +
> +  @param[in]   Private   Pointer to private data.
> +
> +  @retval EFI_SUCCESS              Provision Redfish resource
> successfully.
> +  @retval Others                   Some error happened.
> +
> +**/
> +EFI_STATUS
> +ProvisioningSecureBootResource (
> +  IN  REDFISH_RESOURCE_COMMON_PRIVATE  *Private
> +  )
> +{
> +  EFI_STATUS        Status;
> +  CHAR8             *Json;
> +  CHAR8             *JsonWithAddendum;
> +  REDFISH_RESPONSE  Response;
> +
> +  if (Private == NULL) {
> +    return EFI_INVALID_PARAMETER;
> +  }
> +
> +  ZeroMem (&Response, sizeof (REDFISH_RESPONSE));
> +  Json = NULL;
> +
> +  Status = ProvisioningSecureBootProperties (
> +             Private->JsonStructProtocol,
> +             SecureBootEmptyJson,
> +             NULL,
> +             REDFISH_DUMMY_CONFIG_LANG,
> +             TRUE,
> +             &Json
> +             );
> +  if (EFI_ERROR (Status)) {
> +    if (Status == EFI_NOT_FOUND) {
> +      DEBUG ((REDFISH_DEBUG_TRACE, "%a: provisioning existing resource
> for %s ignored. Nothing changed\n", __func__, REDFISH_DUMMY_CONFIG_LANG));
> +      Status = EFI_SUCCESS;
> +    } else {
> +      DEBUG ((DEBUG_ERROR, "%a: provisioning existing resource for %s
> failed: %r\n", __func__, REDFISH_DUMMY_CONFIG_LANG, Status));
> +    }
> +
> +    goto ON_RELEASE;
> +  }
> +
> +  //
> +  // Check and see if platform has OEM data or not
> +  //
> +  Status = RedfishGetOemData (
> +             Private->Uri,
> +             RESOURCE_SCHEMA,
> +             RESOURCE_SCHEMA_VERSION,
> +             Json,
> +             &JsonWithAddendum
> +             );
> +  if (!EFI_ERROR (Status) && (JsonWithAddendum != NULL)) {
> +    FreePool (Json);
> +    Json             = JsonWithAddendum;
> +    JsonWithAddendum = NULL;
> +  }
> +
> +  //
> +  // Check and see if platform has addendum data or not
> +  //
> +  Status = RedfishGetAddendumData (
> +             Private->Uri,
> +             RESOURCE_SCHEMA,
> +             RESOURCE_SCHEMA_VERSION,
> +             Json,
> +             &JsonWithAddendum
> +             );
> +  if (!EFI_ERROR (Status) && (JsonWithAddendum != NULL)) {
> +    FreePool (Json);
> +    Json             = JsonWithAddendum;
> +    JsonWithAddendum = NULL;
> +  }
> +
> +  DEBUG ((REDFISH_DEBUG_TRACE, "%a: provisioning existing resource for
> %s\n", __func__, REDFISH_DUMMY_CONFIG_LANG));
> +
> +  //
> +  // PATCH back to instance
> +  //
> +  Status = RedfishHttpPatchResource (Private->RedfishService,
> Private->Uri, Json, &Response);
> +  if (EFI_ERROR (Status)) {
> +    DEBUG ((DEBUG_ERROR, "%a: patch resource for %s failed: %r\n",
> __func__, REDFISH_DUMMY_CONFIG_LANG, Status));
> +  }
> +
> +ON_RELEASE:
> +
> +  if (Json != NULL) {
> +    FreePool (Json);
> +  }
> +
> +  RedfishHttpFreeResponse (&Response);
> +
> +  return Status;
> +}
> +
> +/**
> +  Provisioning redfish resource to Redfish service.
> +
> +  @param[in]   Private             Pointer to private data.
> +  @param[in]   ResourceExist       TRUE if resource exists, PUT method
> will be used.
> +                                   FALSE if resource does not exist POST
> method is used.
>
>
>
>
>
> Actually ProvisioningSecureBootResource uses PATCH only.
>
>
>
>
>
> +
> +  @retval EFI_SUCCESS              Provision resource successfully.
> +  @retval Others                   Some error happened.
> +
> +**/
> +EFI_STATUS
> +RedfishProvisioningResourceCommon (
> +  IN     REDFISH_RESOURCE_COMMON_PRIVATE  *Private,
> +  IN     BOOLEAN                          ResourceExist
> +  )
> +{
> +  if (Private == NULL) {
> +    return EFI_INVALID_PARAMETER;
> +  }
> +
> +  return ProvisioningSecureBootResource (Private);
> +}
> +
> +/**
> +  Check resource from given Json data.
> +
> +  @param[in]   This                Pointer to
> REDFISH_RESOURCE_COMMON_PRIVATE instance.
> +  @param[in]   Json                The JSON data to check.
> +  @param[in]   HeaderEtag          The Etag string returned in HTTP
> header.
> +
> +  @retval EFI_SUCCESS              Check resource successfully.
> +  @retval Others                   Some error happened.
> +
> +**/
> +EFI_STATUS
> +RedfishCheckResourceCommon (
> +  IN     REDFISH_RESOURCE_COMMON_PRIVATE  *Private,
> +  IN     CHAR8                            *Json,
> +  IN     CHAR8                            *HeaderEtag OPTIONAL
> +  )
> +{
> +  UINTN       Index;
> +  EFI_STATUS  Status;
> +  UINTN       Count;
> +  EFI_STRING  Property;
> +
> +  if ((Private == NULL) || IS_EMPTY_STRING (Json)) {
> +    return EFI_INVALID_PARAMETER;
> +  }
> +
> +  //
> +  // Check ETAG to see if we need to check it
> +  //
> +  if (CheckEtag (Private->Uri, HeaderEtag, NULL)) {
> +    //
> +    // No change
> +    //
> +    DEBUG ((REDFISH_DEBUG_TRACE, "%a: ETAG: %s has no change, ignore
> check action\n", __func__, Private->Uri));
> +    return EFI_SUCCESS;
> +  }
> +
> +  Count = sizeof (mSecureBootSupportedAttributes) / sizeof
> (mSecureBootSupportedAttributes[0]);
> +  if (Count == 0) {
> +    return EFI_UNSUPPORTED;
> +  }
> +
> +  Status = EFI_SUCCESS;
> +  for (Index = 0; Index < Count; Index++) {
> +    Property = mSecureBootSupportedAttributes[Index];
> +    if (Property == NULL) {
> +      continue;
> +    }
> +
> +    DEBUG ((REDFISH_DEBUG_TRACE, "%a: [%d] check attribute for: %s\n",
> __func__, Index, Property));
> +    if (!MatchPropertyWithJsonContext (Property, Json)) {
> +      DEBUG ((REDFISH_DEBUG_TRACE, "%a: property is missing: %s\n",
> __func__, Property));
> +      Status = EFI_NOT_FOUND;
>
>
Oh! I have a question about this condition.
Can we just break the loop here?
I'm asking mostly in context of Bios feature driver where the same loop
exists.
While in this driver Count not greater than 3, but for Bios driver there
could be a hundreds of iterations
and AFAIR during provisioning we have EFI_NOT_FOUND right after the first
iteration.
MatchPropertyWithJsonContext() seems to be a heavy call.

The only useful thing this loop does in that case is printing missed
property if enabled.

+    }
> +  }
> +
>
> +  return Status;
> +}
> +
> +/**
> +  Update resource to Redfish service.
> +
> +  @param[in]   Private             Pointer to
> REDFISH_RESOURCE_COMMON_PRIVATE instance.
> +  @param[in]   Json                The JSON data to be updated.
> +
> +  @retval EFI_SUCCESS              Update resource successfully.
> +  @retval Others                   Some error happened.
> +
> +**/
> +EFI_STATUS
> +RedfishUpdateResourceCommon (
> +  IN     REDFISH_RESOURCE_COMMON_PRIVATE  *Private,
> +  IN     CHAR8                            *InputJson
> +  )
> +{
> +  EFI_STATUS        Status;
> +  CHAR8             *Json;
> +  CHAR8             *JsonWithAddendum;
> +  REDFISH_RESPONSE  Response;
> +
> +  if ((Private == NULL) || IS_EMPTY_STRING (InputJson)) {
> +    return EFI_INVALID_PARAMETER;
> +  }
> +
> +  ZeroMem (&Response, sizeof (REDFISH_RESPONSE));
> +  Json = NULL;
> +
> +  Status = ProvisioningSecureBootProperties (
> +             Private->JsonStructProtocol,
> +             SecureBootEmptyJson,
> +             NULL,
> +             REDFISH_DUMMY_CONFIG_LANG,
> +             TRUE,
> +             &Json
> +             );
> +  if (EFI_ERROR (Status)) {
> +    if (Status == EFI_NOT_FOUND) {
> +      DEBUG ((REDFISH_DEBUG_TRACE, "%a: update resource for %s ignored.
> Nothing changed\n", __func__, REDFISH_DUMMY_CONFIG_LANG));
> +      Status = EFI_SUCCESS;
> +    } else {
> +      DEBUG ((DEBUG_ERROR, "%a: update resource for %s failed: %r\n",
> __func__, REDFISH_DUMMY_CONFIG_LANG, Status));
> +    }
> +
> +    goto ON_RELEASE;
> +  }
> +
> +  //
> +  // Check and see if platform has OEM data or not
> +  //
> +  Status = RedfishGetOemData (
> +             Private->Uri,
> +             RESOURCE_SCHEMA,
> +             RESOURCE_SCHEMA_VERSION,
> +             Json,
> +             &JsonWithAddendum
> +             );
> +  if (!EFI_ERROR (Status) && (JsonWithAddendum != NULL)) {
> +    FreePool (Json);
> +    Json             = JsonWithAddendum;
> +    JsonWithAddendum = NULL;
> +  }
> +
> +  //
> +  // Check and see if platform has addendum data or not
> +  //
> +  Status = RedfishGetAddendumData (
> +             Private->Uri,
> +             RESOURCE_SCHEMA,
> +             RESOURCE_SCHEMA_VERSION,
> +             Json,
> +             &JsonWithAddendum
> +             );
> +  if (!EFI_ERROR (Status) && (JsonWithAddendum != NULL)) {
> +    FreePool (Json);
> +    Json             = JsonWithAddendum;
> +    JsonWithAddendum = NULL;
> +  }
> +
> +  DEBUG ((REDFISH_DEBUG_TRACE, "%a: update resource for %s\n", __func__,
> REDFISH_DUMMY_CONFIG_LANG));
> +
> +  //
> +  // PATCH back to instance
> +  //
> +  Status = RedfishHttpPatchResource (Private->RedfishService,
> Private->Uri, Json, &Response);
> +  if (EFI_ERROR (Status)) {
> +    DEBUG ((DEBUG_ERROR, "%a: patch resource for %s failed: %r\n",
> __func__, REDFISH_DUMMY_CONFIG_LANG, Status));
> +  }
> +
> +ON_RELEASE:
> +
> +  if (Json != NULL) {
> +    FreePool (Json);
> +  }
> +
> +  RedfishHttpFreeResponse (&Response);
> +
> +  return Status;
> +}
> +
> +/**
> +  Identify resource in given Json data.
> +
> +  @param[in]   Private             Pointer to
> REDFISH_RESOURCE_COMMON_PRIVATE instance.
> +  @param[in]   Json                The JSON to be identified.
> +
> +  @retval EFI_SUCCESS              Identify resource successfully.
> +  @retval Others                   Some error happened.
> +
> +**/
> +EFI_STATUS
> +RedfishIdentifyResourceCommon (
> +  IN     REDFISH_RESOURCE_COMMON_PRIVATE  *Private,
> +  IN     CHAR8                            *Json
> +  )
> +{
> +  BOOLEAN  Supported;
> +
> +  Supported = RedfishIdentifyResource (Private->Uri, Private->Json);
> +  if (Supported) {
> +    //
> +    // Keep URI and ConfigLang mapping
> +    //
> +    RedfishSetRedfishUri (REDFISH_DUMMY_CONFIG_LANG, Private->Uri);
> +  }
> +
> +  return (Supported ? EFI_SUCCESS : EFI_UNSUPPORTED);
> +}
> +
> +/**
> +  Handle Redfish resource in Uri.
> +
> +  @param[in]   Private             Pointer to
> REDFISH_RESOURCE_COMMON_PRIVATE instance.
> +  @param[in]   Uri                 URI to Redfish resource that we like
> to process.
> +
> +  @retval EFI_SUCCESS              Handle resource successfully.
> +  @retval Others                   Some error happened.
> +
> +**/
> +EFI_STATUS
> +HandleResource (
> +  IN  REDFISH_RESOURCE_COMMON_PRIVATE  *Private,
> +  IN  EFI_STRING                       Uri
> +  )
> +{
> +  EFI_STATUS           Status;
> +  REDFISH_SCHEMA_INFO  SchemaInfo;
> +  EFI_STRING           ConfigLang;
> +
> +  if ((Private == NULL) || IS_EMPTY_STRING (Uri)) {
> +    return EFI_INVALID_PARAMETER;
> +  }
> +
> +  //
> +  // Resource match
> +  //
> +
> +  DEBUG ((REDFISH_DEBUG_TRACE, "%a: process resource for: %s\n",
> __func__, Uri));
> +
> +  Status = GetRedfishSchemaInfo (Private->RedfishService,
> Private->JsonStructProtocol, Uri, NULL, &SchemaInfo);
> +  if (EFI_ERROR (Status)) {
> +    DEBUG ((DEBUG_ERROR, "%a: failed to get schema information from: %s
> %r\n", __func__, Uri, Status));
> +    return Status;
> +  }
> +
> +  //
> +  // Check and see if this is target resource that we want to handle.
> +  // Some resource is handled by other provider so we have to make sure
> this first.
> +  //
> +  DEBUG ((REDFISH_DEBUG_TRACE, "%a: Identify for %s\n", __func__, Uri));
> +  ConfigLang = RedfishGetConfigLanguage (Uri);
> +  if (ConfigLang == NULL) {
> +    Status = EdkIIRedfishResourceConfigIdentify (&SchemaInfo, Uri, NULL,
> Private->InformationExchange);
> +    if (EFI_ERROR (Status)) {
> +      if (Status == EFI_UNSUPPORTED) {
> +        DEBUG ((REDFISH_DEBUG_TRACE, "%a: \"%s\" is not handled by us\n",
> __func__, Uri));
> +        return EFI_SUCCESS;
> +      } else if (Status == EFI_NOT_FOUND) {
> +        DEBUG ((REDFISH_DEBUG_TRACE, "%a: \"%s\" has nothing to
> handle\n", __func__, Uri));
> +        return EFI_SUCCESS;
> +      }
> +
> +      DEBUG ((DEBUG_ERROR, "%a: fail to identify resource: \"%s\": %r\n",
> __func__, Uri, Status));
> +      return Status;
> +    }
> +  } else {
> +    DEBUG ((REDFISH_DEBUG_TRACE, "%a: history record found: %s\n",
> __func__, ConfigLang));
> +    FreePool (ConfigLang);
> +  }
> +
> +  //
> +  // Check and see if target property exist or not even when collection
> member exists.
> +  // If not, we sill do provision.
>
>
>
> %s/sill/still
>
>
>
> +  //
> +  DEBUG ((REDFISH_DEBUG_TRACE, "%a Check for %s\n", __func__, Uri));
> +  Status = EdkIIRedfishResourceConfigCheck (&SchemaInfo, Uri, NULL);
> +  if (EFI_ERROR (Status)) {
> +    if (Status == EFI_UNSUPPORTED) {
> +      DEBUG ((REDFISH_DEBUG_TRACE, "%a: \"%s\" is not handled by us\n",
> __func__, Uri));
> +      return EFI_SUCCESS;
> +    }
> +
> +    //
> +    // The target property does not exist, do the provision to create
> property.
> +    //
> +    DEBUG ((REDFISH_DEBUG_TRACE, "%a provision for %s\n", __func__, Uri));
> +    Status = EdkIIRedfishResourceConfigProvisioning (&SchemaInfo, Uri,
> NULL, Private->InformationExchange, FALSE);
> +    if (EFI_ERROR (Status)) {
> +      DEBUG ((DEBUG_ERROR, "%a: failed to provision with GET mode: %r\n",
> __func__, Status));
> +    }
> +
> +    DEBUG ((REDFISH_DEBUG_TRACE, "%a: process resource for: %s
> finished\n", __func__, Uri));
> +
> +    return Status;
> +  }
> +
> +  //
> +  // Consume first.
> +  //
> +  DEBUG ((REDFISH_DEBUG_TRACE, "%a consume for %s\n", __func__, Uri));
> +  Status = EdkIIRedfishResourceConfigConsume (&SchemaInfo, Uri, NULL);
> +  if (EFI_ERROR (Status)) {
> +    DEBUG ((DEBUG_ERROR, "%a: failed to consume resource for: %s: %r\n",
> __func__, Uri, Status));
> +  }
> +
> +  //
> +  // Patch.
> +  //
> +  DEBUG ((REDFISH_DEBUG_TRACE, "%a update for %s\n", __func__, Uri));
> +  Status = EdkIIRedfishResourceConfigUpdate (&SchemaInfo, Uri, NULL);
> +  if (EFI_ERROR (Status)) {
> +    DEBUG ((DEBUG_ERROR, "%a: failed to update resource for: %s: %r\n",
> __func__, Uri, Status));
> +  }
> +
> +  DEBUG ((REDFISH_DEBUG_TRACE, "%a: process resource for: %s finished\n",
> __func__, Uri));
> +
> +  return Status;
> +}
> diff --git
> a/RedfishClientPkg/Features/SecureBoot/v1_1_0/Dxe/SecureBootDxe.c
> b/RedfishClientPkg/Features/SecureBoot/v1_1_0/Dxe/SecureBootDxe.c
> new file mode 100644
> index 000000000..a0f4f3d14
> --- /dev/null
> +++ b/RedfishClientPkg/Features/SecureBoot/v1_1_0/Dxe/SecureBootDxe.c
> @@ -0,0 +1,808 @@
> +/** @file
> +  Redfish feature driver implementation - SecureBoot
> +
> +  (C) Copyright 2020-2022 Hewlett Packard Enterprise Development LP<BR>
> +  Copyright (c) 2023, NVIDIA CORPORATION & AFFILIATES. All rights
> reserved.
> +
> +  SPDX-License-Identifier: BSD-2-Clause-Patent
> +
> +**/
> +
> +#include "../Common/SecureBootCommon.h"
> +
> +extern REDFISH_RESOURCE_COMMON_PRIVATE  *mRedfishResourcePrivate;
> +extern EFI_HANDLE
>                       mRedfishResourceConfigProtocolHandle;
> +
> +EFI_STATUS
> +HandleResource (
> +  IN  REDFISH_RESOURCE_COMMON_PRIVATE  *Private,
> +  IN  EFI_STRING                       Uri
> +  );
> +
> +/**
> +  Provisioning redfish resource by given URI.
> +
> +  @param[in]   This                Pointer to EFI_HP_REDFISH_HII_PROTOCOL
> instance.
> +  @param[in]   Uri                 Target URI to create resource.
> +  @param[in]   PostMode            TRUE if the resource does not exist,
> post method is used.
> +                                   FALSE if the resource exist but
> property is missing, put method is used.
> +
> +  @retval EFI_SUCCESS              Value is returned successfully.
> +  @retval Others                   Some error happened.
> +
> +**/
> +EFI_STATUS
> +EFIAPI
> +RedfishResourceProvisioningResource (
> +  IN     EDKII_REDFISH_RESOURCE_CONFIG_PROTOCOL  *This,
> +  IN     EFI_STRING                              Uri,
> +  IN     BOOLEAN                                 PostMode
> +  )
> +{
> +  REDFISH_RESOURCE_COMMON_PRIVATE  *Private;
> +  EFI_STATUS                       Status;
> +  REDFISH_RESPONSE                 Response;
> +
> +  if ((This == NULL) || IS_EMPTY_STRING (Uri)) {
> +    return EFI_INVALID_PARAMETER;
> +  }
> +
> +  DEBUG ((REDFISH_DEBUG_TRACE, "%a: provisioning in %s mode\n", __func__,
> (PostMode ? L"POST" : L"PATCH")));
>
>
>
>
>
> This message conflicts with PostMode parameter description.
>
>
>
>
>
> +
> +  ZeroMem (&Response, sizeof (REDFISH_RESPONSE));
> +  Private = REDFISH_RESOURCE_COMMON_PRIVATE_DATA_FROM_RESOURCE_PROTOCOL
> (This);
> +
> +  if (Private->RedfishService == NULL) {
> +    return EFI_NOT_READY;
> +  }
> +
> +  Status = RedfishHttpGetResource (Private->RedfishService, Uri, NULL,
> &Response, TRUE);
> +  if (EFI_ERROR (Status)) {
> +    DEBUG ((DEBUG_ERROR, "%a: get resource from: %s failed\n", __func__,
> Uri));
> +    return Status;
> +  }
> +
> +  Private->Uri     = Uri;
> +  Private->Payload = Response.Payload;
> +  ASSERT (Private->Payload != NULL);
> +
> +  Status = RedfishProvisioningResourceCommon (Private, !PostMode);
> +  if (EFI_ERROR (Status)) {
> +    DEBUG ((DEBUG_ERROR, "%a: failed to provision resource to: %s: %r\n",
> __func__, Uri, Status));
> +  } else {
> +    //
> +    // Get latest ETag on URI and keep it in variable.
> +    //
> +    SetEtagFromUri (Private->RedfishService, Private->Uri, TRUE);
> +  }
> +
> +  //
> +  // Release resource
> +  //
> +  RedfishHttpFreeResponse (&Response);
> +  Private->Payload = NULL;
> +
> +  return Status;
> +}
> +
> +/**
> +  Consume resource from given URI.
> +
> +  @param[in]   This                Pointer to EFI_HP_REDFISH_HII_PROTOCOL
> instance.
> +  @param[in]   Uri                 The target URI to consume.
> +
> +  @retval EFI_SUCCESS              Value is returned successfully.
> +  @retval Others                   Some error happened.
> +
> +**/
> +EFI_STATUS
> +EFIAPI
> +RedfishResourceConsumeResource (
> +  IN     EDKII_REDFISH_RESOURCE_CONFIG_PROTOCOL  *This,
> +  IN     EFI_STRING                              Uri
> +  )
> +{
> +  REDFISH_RESOURCE_COMMON_PRIVATE  *Private;
> +  EFI_STATUS                       Status;
> +  REDFISH_RESPONSE                 Response;
> +  EFI_STRING                       PendingSettingUri;
> +  REDFISH_RESPONSE                 PendingSettingResponse;
> +  REDFISH_RESPONSE                 *ExpectedResponse;
> +  CHAR8                            *Etag;
> +
> +  if ((This == NULL) || IS_EMPTY_STRING (Uri)) {
> +    return EFI_INVALID_PARAMETER;
> +  }
> +
> +  ZeroMem (&Response, sizeof (REDFISH_RESPONSE));
> +  ZeroMem (&PendingSettingResponse, sizeof (REDFISH_RESPONSE));
> +  Private = REDFISH_RESOURCE_COMMON_PRIVATE_DATA_FROM_RESOURCE_PROTOCOL
> (This);
> +
> +  if (Private->RedfishService == NULL) {
> +    return EFI_NOT_READY;
> +  }
> +
> +  Status = RedfishHttpGetResource (Private->RedfishService, Uri, NULL,
> &Response, TRUE);
> +  if (EFI_ERROR (Status)) {
> +    DEBUG ((DEBUG_ERROR, "%a: get resource from: %s failed\n", __func__,
> Uri));
> +    return Status;
> +  }
> +
> +  //
> +  // Check and see if "@Redfish.Settings" exist or not.
> +  //
> +  PendingSettingUri = NULL;
> +  Status            = GetPendingSettings (
> +                        Private->RedfishService,
> +                        Response.Payload,
> +                        &PendingSettingResponse,
> +                        &PendingSettingUri
> +                        );
> +  if (!EFI_ERROR (Status)) {
> +    DEBUG ((REDFISH_DEBUG_TRACE, "%a: @Redfish.Settings found: %s\n",
> __func__, PendingSettingUri));
> +    Private->Uri     = PendingSettingUri;
> +    ExpectedResponse = &PendingSettingResponse;
> +  } else {
> +    Private->Uri     = Uri;
> +    ExpectedResponse = &Response;
> +  }
> +
> +  Private->Payload = ExpectedResponse->Payload;
> +  ASSERT (Private->Payload != NULL);
> +
> +  Private->Json = JsonDumpString (RedfishJsonInPayload
> (Private->Payload), EDKII_JSON_COMPACT);
> +  ASSERT (Private->Json != NULL);
> +
> +  //
> +  // Searching for etag in HTTP response header
> +  //
> +  Etag   = NULL;
> +  Status = GetHttpResponseEtag (ExpectedResponse, &Etag);
> +  if (EFI_ERROR (Status)) {
> +    DEBUG ((DEBUG_ERROR, "%a: failed to get ETag from HTTP header\n",
> __func__));
> +  }
> +
> +  Status = RedfishConsumeResourceCommon (Private, Private->Json, Etag);
> +  if (EFI_ERROR (Status)) {
> +    DEBUG ((DEBUG_ERROR, "%a: failed to consume resource from: %s: %r\n",
> __func__, Private->Uri, Status));
> +  }
> +
> +  //
> +  // Release resource
> +  //
> +  RedfishHttpFreeResponse (&Response);
> +  RedfishHttpFreeResponse (&PendingSettingResponse);
> +  Private->Payload = NULL;
> +
> +  if (Private->Json != NULL) {
> +    FreePool (Private->Json);
> +    Private->Json = NULL;
> +  }
> +
> +  if (Etag != NULL) {
> +    FreePool (Etag);
> +  }
> +
> +  if (PendingSettingUri != NULL) {
> +    FreePool (PendingSettingUri);
> +  }
> +
> +  return Status;
> +}
> +
> +/**
> +  Get information about this protocol.
> +
> +  @param[in]   This                Pointer to EFI_HP_REDFISH_HII_PROTOCOL
> instance.
> +  @param[out]  Schema              Supported schema.
> +  @param[out]  Major               Supported major number.
> +  @param[out]  Minor               Supported minor number.
> +  @param[out]  Errata              Supported errata number.
> +
> +  @retval EFI_SUCCESS              Value is returned successfully.
> +  @retval Others                   Some error happened.
> +
> +**/
> +EFI_STATUS
> +EFIAPI
> +RedfishResourceGetInfo (
> +  IN     EDKII_REDFISH_RESOURCE_CONFIG_PROTOCOL  *This,
> +  OUT    REDFISH_SCHEMA_INFO                     *Info
> +  )
> +{
> +  if ((This == NULL) || (Info == NULL)) {
> +    return EFI_INVALID_PARAMETER;
> +  }
> +
> +  AsciiStrCpyS (Info->Schema, REDFISH_SCHEMA_STRING_SIZE,
> RESOURCE_SCHEMA);
> +  AsciiStrCpyS (Info->Major, REDFISH_SCHEMA_VERSION_SIZE,
> RESOURCE_SCHEMA_MAJOR);
> +  AsciiStrCpyS (Info->Minor, REDFISH_SCHEMA_VERSION_SIZE,
> RESOURCE_SCHEMA_MINOR);
> +  AsciiStrCpyS (Info->Errata, REDFISH_SCHEMA_VERSION_SIZE,
> RESOURCE_SCHEMA_ERRATA);
> +
> +  return EFI_SUCCESS;
> +}
> +
> +/**
> +  Update resource to given URI.
> +
> +  @param[in]   This                Pointer to EFI_HP_REDFISH_HII_PROTOCOL
> instance.
> +  @param[in]   Uri                 The target URI to consume.
> +
> +  @retval EFI_SUCCESS              Value is returned successfully.
> +  @retval Others                   Some error happened.
> +
> +**/
> +EFI_STATUS
> +EFIAPI
> +RedfishResourceUpdate (
> +  IN     EDKII_REDFISH_RESOURCE_CONFIG_PROTOCOL  *This,
> +  IN     EFI_STRING                              Uri
> +  )
> +{
> +  REDFISH_RESOURCE_COMMON_PRIVATE  *Private;
> +  EFI_STATUS                       Status;
> +  REDFISH_RESPONSE                 Response;
> +
> +  if ((This == NULL) || IS_EMPTY_STRING (Uri)) {
> +    return EFI_INVALID_PARAMETER;
> +  }
> +
> +  ZeroMem (&Response, sizeof (REDFISH_RESPONSE));
> +  Private = REDFISH_RESOURCE_COMMON_PRIVATE_DATA_FROM_RESOURCE_PROTOCOL
> (This);
> +
> +  if (Private->RedfishService == NULL) {
> +    return EFI_NOT_READY;
> +  }
> +
> +  Status = RedfishHttpGetResource (Private->RedfishService, Uri, NULL,
> &Response, TRUE);
> +  if (EFI_ERROR (Status)) {
> +    DEBUG ((DEBUG_ERROR, "%a: get resource from: %s failed\n", __func__,
> Uri));
> +    return Status;
> +  }
> +
> +  Private->Uri     = Uri;
> +  Private->Payload = Response.Payload;
> +  ASSERT (Private->Payload != NULL);
> +
> +  Private->Json = JsonDumpString (RedfishJsonInPayload
> (Private->Payload), EDKII_JSON_COMPACT);
> +  ASSERT (Private->Json != NULL);
> +
> +  Status = RedfishUpdateResourceCommon (Private, Private->Json);
> +  if (EFI_ERROR (Status)) {
> +    DEBUG ((DEBUG_ERROR, "%a: failed to update resource to: %s: %r\n",
> __func__, Uri, Status));
> +  } else {
> +    //
> +    // Get latest ETag on URI and keep it in variable.
> +    //
> +    SetEtagFromUri (Private->RedfishService, Private->Uri, TRUE);
> +  }
> +
> +  //
> +  // Release resource
> +  //
> +  RedfishHttpFreeResponse (&Response);
> +  Private->Payload = NULL;
> +
> +  if (Private->Json != NULL) {
> +    FreePool (Private->Json);
> +    Private->Json = NULL;
> +  }
> +
> +  return Status;
> +}
> +
> +/**
> +  Check resource on given URI.
> +
> +  @param[in]   This                Pointer to EFI_HP_REDFISH_HII_PROTOCOL
> instance.
> +  @param[in]   Uri                 The target URI to consume.
> +
> +  @retval EFI_SUCCESS              Value is returned successfully.
> +  @retval Others                   Some error happened.
> +
> +**/
> +EFI_STATUS
> +EFIAPI
> +RedfishResourceCheck (
> +  IN     EDKII_REDFISH_RESOURCE_CONFIG_PROTOCOL  *This,
> +  IN     EFI_STRING                              Uri
> +  )
> +{
> +  REDFISH_RESOURCE_COMMON_PRIVATE  *Private;
> +  EFI_STATUS                       Status;
> +  REDFISH_RESPONSE                 Response;
> +  CHAR8                            *Etag;
> +
> +  if ((This == NULL) || IS_EMPTY_STRING (Uri)) {
> +    return EFI_INVALID_PARAMETER;
> +  }
> +
> +  ZeroMem (&Response, sizeof (REDFISH_RESPONSE));
> +  Private = REDFISH_RESOURCE_COMMON_PRIVATE_DATA_FROM_RESOURCE_PROTOCOL
> (This);
> +
> +  if (Private->RedfishService == NULL) {
> +    return EFI_NOT_READY;
> +  }
> +
> +  Status = RedfishHttpGetResource (Private->RedfishService, Uri, NULL,
> &Response, TRUE);
> +  if (EFI_ERROR (Status)) {
> +    DEBUG ((DEBUG_ERROR, "%a: get resource from: %s failed\n", __func__,
> Uri));
> +    return Status;
> +  }
> +
> +  Private->Uri     = Uri;
> +  Private->Payload = Response.Payload;
> +  ASSERT (Private->Payload != NULL);
> +
> +  Private->Json = JsonDumpString (RedfishJsonInPayload
> (Private->Payload), EDKII_JSON_COMPACT);
> +  ASSERT (Private->Json != NULL);
> +
> +  //
> +  // Find etag in HTTP response header
> +  //
> +  Etag   = NULL;
> +  Status = GetHttpResponseEtag (&Response, &Etag);
> +  if (EFI_ERROR (Status)) {
> +    DEBUG ((DEBUG_ERROR, "%a: failed to get ETag from HTTP header\n",
> __func__));
> +  }
> +
> +  Status = RedfishCheckResourceCommon (Private, Private->Json, Etag);
> +  if (EFI_ERROR (Status)) {
> +    DEBUG ((DEBUG_ERROR, "%a: failed to check resource from: %s: %r\n",
> __func__, Uri, Status));
> +  }
> +
> +  //
> +  // Release resource
> +  //
> +  if (Etag != NULL) {
> +    FreePool (Etag);
> +  }
> +
> +  RedfishHttpFreeResponse (&Response);
> +  Private->Payload = NULL;
> +
> +  if (Private->Json != NULL) {
> +    FreePool (Private->Json);
> +    Private->Json = NULL;
> +  }
> +
> +  return Status;
> +}
> +
> +/**
> +  Identify resource on given URI.
> +
> +  @param[in]   This                Pointer to
> EDKII_REDFISH_RESOURCE_CONFIG_PROTOCOL instance.
> +  @param[in]   Uri                 The target URI to consume.
> +
> +  @retval EFI_SUCCESS              This is target resource which we want
> to handle.
> +  @retval EFI_UNSUPPORTED          This is not the target resource.
> +  @retval Others                   Some error happened.
> +
> +**/
> +EFI_STATUS
> +EFIAPI
> +RedfishResourceIdentify (
> +  IN     EDKII_REDFISH_RESOURCE_CONFIG_PROTOCOL  *This,
> +  IN     EFI_STRING                              Uri
> +  )
> +{
> +  REDFISH_RESOURCE_COMMON_PRIVATE  *Private;
> +  EFI_STATUS                       Status;
> +  REDFISH_RESPONSE                 Response;
> +
> +  if ((This == NULL) || IS_EMPTY_STRING (Uri)) {
> +    return EFI_INVALID_PARAMETER;
> +  }
> +
> +  ZeroMem (&Response, sizeof (REDFISH_RESPONSE));
> +  Private = REDFISH_RESOURCE_COMMON_PRIVATE_DATA_FROM_RESOURCE_PROTOCOL
> (This);
> +
> +  if (Private->RedfishService == NULL) {
> +    return EFI_NOT_READY;
> +  }
> +
> +  Status = RedfishHttpGetResource (Private->RedfishService, Uri, NULL,
> &Response, TRUE);
> +  if (EFI_ERROR (Status)) {
> +    DEBUG ((DEBUG_ERROR, "%a: get resource from: %s failed\n", __func__,
> Uri));
> +    return Status;
> +  }
> +
> +  Private->Uri     = Uri;
> +  Private->Payload = Response.Payload;
> +  ASSERT (Private->Payload != NULL);
> +
> +  Private->Json = JsonDumpString (RedfishJsonInPayload
> (Private->Payload), EDKII_JSON_COMPACT);
> +  ASSERT (Private->Json != NULL);
> +
> +  Status = RedfishIdentifyResourceCommon (Private, Private->Json);
> +  if (EFI_ERROR (Status)) {
> +    DEBUG ((DEBUG_ERROR, "%a: identify %s failed: %r\n", __func__, Uri,
> Status));
> +  }
> +
> +  //
> +  // Release resource
> +  //
> +  RedfishHttpFreeResponse (&Response);
> +  Private->Payload = NULL;
> +
> +  if (Private->Json != NULL) {
> +    FreePool (Private->Json);
> +    Private->Json = NULL;
> +  }
> +
> +  return Status;
> +}
> +
> +EDKII_REDFISH_RESOURCE_CONFIG_PROTOCOL  mRedfishResourceConfig = {
> +  RedfishResourceProvisioningResource,
> +  RedfishResourceConsumeResource,
> +  RedfishResourceUpdate,
> +  RedfishResourceCheck,
> +  RedfishResourceIdentify,
> +  RedfishResourceGetInfo
> +};
> +
> +/**
> +  Initialize a Redfish configure handler.
> +
> +  This function will be called by the Redfish config driver to initialize
> each Redfish configure
> +  handler.
> +
> +  @param[in]   This                     Pointer to
> EDKII_REDFISH_CONFIG_HANDLER_PROTOCOL instance.
> +  @param[in]   RedfishConfigServiceInfo Redfish service information.
> +
> +  @retval EFI_SUCCESS                  The handler has been initialized
> successfully.
> +  @retval EFI_DEVICE_ERROR             Failed to create or configure the
> REST EX protocol instance.
> +  @retval EFI_ALREADY_STARTED          This handler has already been
> initialized.
> +  @retval Other                        Error happens during the
> initialization.
> +
> +**/
> +EFI_STATUS
> +EFIAPI
> +RedfishResourceInit (
> +  IN  EDKII_REDFISH_CONFIG_HANDLER_PROTOCOL  *This,
> +  IN  REDFISH_CONFIG_SERVICE_INFORMATION     *RedfishConfigServiceInfo
> +  )
> +{
> +  REDFISH_RESOURCE_COMMON_PRIVATE  *Private;
> +
> +  Private = REDFISH_RESOURCE_COMMON_PRIVATE_DATA_FROM_CONFIG_PROTOCOL
> (This);
> +
> +  Private->RedfishService = RedfishCreateService
> (RedfishConfigServiceInfo);
> +  if (Private->RedfishService == NULL) {
> +    return EFI_DEVICE_ERROR;
> +  }
> +
> +  return EFI_SUCCESS;
> +}
> +
> +/**
> +  Stop a Redfish configure handler.
> +
> +  @param[in]   This                Pointer to
> EDKII_REDFISH_CONFIG_HANDLER_PROTOCOL instance.
> +
> +  @retval EFI_SUCCESS              This handler has been stoped
> successfully.
> +  @retval Others                   Some error happened.
> +
> +**/
> +EFI_STATUS
> +EFIAPI
> +RedfishResourceStop (
> +  IN  EDKII_REDFISH_CONFIG_HANDLER_PROTOCOL  *This
> +  )
> +{
> +  REDFISH_RESOURCE_COMMON_PRIVATE  *Private;
> +
> +  Private = REDFISH_RESOURCE_COMMON_PRIVATE_DATA_FROM_CONFIG_PROTOCOL
> (This);
> +
> +  if (Private->Event != NULL) {
> +    gBS->CloseEvent (Private->Event);
> +    Private->Event = NULL;
> +  }
> +
> +  if (Private->RedfishService != NULL) {
> +    RedfishCleanupService (Private->RedfishService);
> +    Private->RedfishService = NULL;
> +  }
> +
> +  return EFI_SUCCESS;
> +}
> +
> +EDKII_REDFISH_CONFIG_HANDLER_PROTOCOL  mRedfishConfigHandler = {
> +  RedfishResourceInit,
> +  RedfishResourceStop
> +};
> +
> +/**
> +  Callback function when gEfiRestJsonStructureProtocolGuid is installed.
> +
> +  @param[in] Event    Event whose notification function is being invoked.
> +  @param[in] Context  Pointer to the notification function's context.
> +**/
> +VOID
> +EFIAPI
> +EfiRestJsonStructureProtocolIsReady (
> +  IN  EFI_EVENT  Event,
> +  IN  VOID       *Context
> +  )
> +{
> +  EFI_STATUS  Status;
> +
> +  if (mRedfishResourcePrivate == NULL) {
> +    return;
> +  }
> +
> +  if (mRedfishResourcePrivate->JsonStructProtocol != NULL) {
> +    return;
> +  }
> +
> +  Status = gBS->LocateProtocol (
> +                  &gEfiRestJsonStructureProtocolGuid,
> +                  NULL,
> +                  (VOID **)&mRedfishResourcePrivate->JsonStructProtocol
> +                  );
> +  if (EFI_ERROR (Status)) {
> +    DEBUG ((DEBUG_ERROR, "%a: failed to locate
> gEfiRestJsonStructureProtocolGuid: %r\n", __func__, Status));
> +  }
> +
> +  gBS->CloseEvent (Event);
> +}
> +
> +/**
> +  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
> +RedfishResourceUnload (
> +  IN EFI_HANDLE  ImageHandle
> +  )
> +{
> +  EFI_STATUS                             Status;
> +  EDKII_REDFISH_CONFIG_HANDLER_PROTOCOL  *ConfigHandler;
> +
> +  if (mRedfishResourcePrivate == NULL) {
> +    return EFI_NOT_READY;
> +  }
> +
> +  ConfigHandler = NULL;
> +
> +  //
> +  // Firstly, find ConfigHandler Protocol interface in this ImageHandle.
> +  //
> +  Status = gBS->OpenProtocol (
> +                  ImageHandle,
> +                  &gEdkIIRedfishConfigHandlerProtocolGuid,
> +                  (VOID **)&ConfigHandler,
> +                  NULL,
> +                  NULL,
> +                  EFI_OPEN_PROTOCOL_BY_HANDLE_PROTOCOL
> +                  );
> +  if (EFI_ERROR (Status) || (ConfigHandler == NULL)) {
> +    return Status;
> +  }
> +
> +  ConfigHandler->Stop (ConfigHandler);
> +
> +  //
> +  // Last, uninstall ConfigHandler Protocol and resource protocol.
> +  //
> +  Status = gBS->UninstallMultipleProtocolInterfaces (
> +                  ImageHandle,
> +                  &gEdkIIRedfishConfigHandlerProtocolGuid,
> +                  ConfigHandler,
> +                  &gEdkIIRedfishResourceConfigProtocolGuid,
> +                  &mRedfishResourcePrivate->RedfishResourceConfig,
> +                  NULL
> +                  );
> +
> +  FreePool (mRedfishResourcePrivate);
> +  mRedfishResourcePrivate = NULL;
> +
> +  return Status;
> +}
> +
> +/**
> +  The callback function provided by Redfish Feature driver.
> +
> +  @param[in]     This                Pointer to
> EDKII_REDFISH_FEATURE_PROTOCOL instance.
> +  @param[in]     FeatureAction       The action Redfish feature driver
> should take.
> +  @param[in]     Uri                 The collection URI.
> +  @param[in]     Context             The context of Redfish feature
> driver.
> +  @param[in,out] InformationExchange The pointer to
> RESOURCE_INFORMATION_EXCHANGE
> +
> +  @retval EFI_SUCCESS              Redfish feature driver callback is
> executed successfully.
> +  @retval Others                   Some errors happened.
> +
> +  @retval EFI_SUCCESS              Redfish feature driver callback is
> executed successfully.
> +  @retval Others                   Some errors happened.
> +
> +**/
> +EFI_STATUS
> +EFIAPI
> +RedfishExternalResourceResourceFeatureCallback (
> +  IN     EDKII_REDFISH_FEATURE_PROTOCOL  *This,
> +  IN     FEATURE_CALLBACK_ACTION         FeatureAction,
> +  IN     VOID                            *Context,
> +  IN OUT RESOURCE_INFORMATION_EXCHANGE   *InformationExchange
> +  )
> +{
> +  EFI_STATUS                       Status;
> +  REDFISH_SERVICE                  RedfishService;
> +  REDFISH_RESOURCE_COMMON_PRIVATE  *Private;
> +  EFI_STRING                       ResourceUri;
> +  EFI_STRING                       SecureBootUri;
> +
> +  if (FeatureAction != CallbackActionStartOperation) {
> +    return EFI_UNSUPPORTED;
> +  }
> +
> +  Private = (REDFISH_RESOURCE_COMMON_PRIVATE *)Context;
> +
> +  RedfishService = Private->RedfishService;
> +  if (RedfishService == NULL) {
> +    DEBUG ((DEBUG_ERROR, "%a: no Redfish service configured\n",
> __func__));
> +    return EFI_NOT_READY;
> +  }
> +
> +  //
> +  // Save in private structure.
> +  //
> +  Private->InformationExchange = InformationExchange;
> +
> +  //
> +  // Find Redfish version on Redfish ser
> +  //
> +  Private->RedfishVersion = RedfishGetVersion (RedfishService);
> +
> +  //
> +  // Create the full URI from Redfish service root.
> +  //
> +  ResourceUri = (EFI_STRING)AllocateZeroPool (MAX_URI_LENGTH * sizeof
> (CHAR16));
> +  if (ResourceUri == NULL) {
> +    DEBUG ((DEBUG_ERROR, "%a: Fail to allocate memory for full URI.\n",
> __func__));
> +    return EFI_OUT_OF_RESOURCES;
> +  }
> +
> +  StrCatS (ResourceUri, MAX_URI_LENGTH, Private->RedfishVersion);
> +  StrCatS (ResourceUri, MAX_URI_LENGTH,
> InformationExchange->SendInformation.FullUri);
> +
> +  //
> +  // Initialize collection path
> +  //
> +  SecureBootUri = RedfishGetUri (ResourceUri);
> +  if (SecureBootUri == NULL) {
> +    ASSERT (FALSE);
> +    FreePool (ResourceUri);
> +    return EFI_OUT_OF_RESOURCES;
> +  }
> +
> +  Status = HandleResource (Private, SecureBootUri);
> +  if (EFI_ERROR (Status)) {
> +    DEBUG ((DEBUG_ERROR, "%a: process external resource: %s failed:
> %r\n", __func__, SecureBootUri, Status));
> +  }
> +
> +  FreePool (SecureBootUri);
> +  FreePool (ResourceUri);
> +  return Status;
> +}
> +
> +/**
> +  Callback function when gEdkIIRedfishFeatureProtocolGuid is installed.
> +
> +  @param[in] Event    Event whose notification function is being invoked.
> +  @param[in] Context  Pointer to the notification function's context.
> +**/
> +VOID
> +EFIAPI
> +EdkIIRedfishFeatureProtocolIsReady (
> +  IN  EFI_EVENT  Event,
> +  IN  VOID       *Context
> +  )
> +{
> +  EFI_STATUS                      Status;
> +  EDKII_REDFISH_FEATURE_PROTOCOL  *FeatureProtocol;
> +
> +  if (mRedfishResourcePrivate == NULL) {
> +    return;
> +  }
> +
> +  if (mRedfishResourcePrivate->FeatureProtocol != NULL) {
> +    return;
> +  }
> +
> +  Status = gBS->LocateProtocol (
> +                  &gEdkIIRedfishFeatureProtocolGuid,
> +                  NULL,
> +                  (VOID **)&FeatureProtocol
> +                  );
> +  if (EFI_ERROR (Status)) {
> +    DEBUG ((DEBUG_ERROR, "%a: failed to locate
> gEdkIIRedfishFeatureProtocolGuid: %r\n", __func__, Status));
> +    gBS->CloseEvent (Event);
> +    return;
> +  }
> +
> +  Status = FeatureProtocol->Register (
> +                              FeatureProtocol,
> +                              REDFISH_MANAGED_URI,
> +
>                              RedfishExternalResourceResourceFeatureCallback,
> +                              (VOID *)mRedfishResourcePrivate
> +                              );
> +  if (EFI_ERROR (Status)) {
> +    DEBUG ((DEBUG_ERROR, "%a: failed to register %s: %r\n", __func__,
> REDFISH_MANAGED_URI, Status));
> +  }
> +
> +  mRedfishResourcePrivate->FeatureProtocol = FeatureProtocol;
> +
> +  gBS->CloseEvent (Event);
> +}
> +
> +/**
> +  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. It initialize the global variables
> and
> +  publish the driver binding protocol.
> +
> +  @param[in]   ImageHandle      The firmware allocated handle for the
> UEFI image.
> +  @param[in]   SystemTable      A pointer to the EFI System Table.
> +
> +  @retval EFI_SUCCESS           The operation completed successfully.
> +  @retval EFI_ACCESS_DENIED     EFI_ISCSI_INITIATOR_NAME_PROTOCOL was
> installed unexpectedly.
> +  @retval Others                Other errors as indicated.
> +**/
> +EFI_STATUS
> +EFIAPI
> +RedfishResourceEntryPoint (
> +  IN EFI_HANDLE        ImageHandle,
> +  IN EFI_SYSTEM_TABLE  *SystemTable
> +  )
> +{
> +  EFI_STATUS  Status;
> +  VOID        *Registration;
> +
> +  if (mRedfishResourcePrivate != NULL) {
> +    return EFI_ALREADY_STARTED;
> +  }
> +
> +  mRedfishResourceConfigProtocolHandle = ImageHandle;
> +
> +  mRedfishResourcePrivate = AllocateZeroPool (sizeof
> (REDFISH_RESOURCE_COMMON_PRIVATE));
> +  CopyMem (&mRedfishResourcePrivate->ConfigHandler,
> &mRedfishConfigHandler, sizeof (EDKII_REDFISH_CONFIG_HANDLER_PROTOCOL));
> +  CopyMem (&mRedfishResourcePrivate->RedfishResourceConfig,
> &mRedfishResourceConfig, sizeof (EDKII_REDFISH_RESOURCE_CONFIG_PROTOCOL));
> +
> +  //
> +  // Publish config handler protocol and resource protocol.
> +  //
> +  Status = gBS->InstallMultipleProtocolInterfaces (
> +                  &ImageHandle,
> +                  &gEdkIIRedfishConfigHandlerProtocolGuid,
> +                  &mRedfishResourcePrivate->ConfigHandler,
> +                  &gEdkIIRedfishResourceConfigProtocolGuid,
> +                  &mRedfishResourcePrivate->RedfishResourceConfig,
> +                  NULL
> +                  );
> +
> +  EfiCreateProtocolNotifyEvent (
> +    &gEfiRestJsonStructureProtocolGuid,
> +    TPL_CALLBACK,
> +    EfiRestJsonStructureProtocolIsReady,
> +    NULL,
> +    &Registration
> +    );
> +
> +  EfiCreateProtocolNotifyEvent (
> +    &gEdkIIRedfishFeatureProtocolGuid,
> +    TPL_CALLBACK,
> +    EdkIIRedfishFeatureProtocolIsReady,
> +    (VOID *)mRedfishResourcePrivate,
> +    &Registration
> +    );
> +
> +  return Status;
> +}
> diff --git a/RedfishClientPkg/RedfishClient.fdf.inc
> b/RedfishClientPkg/RedfishClient.fdf.inc
> index 59b8acba1..154f641b2 100644
> --- a/RedfishClientPkg/RedfishClient.fdf.inc
> +++ b/RedfishClientPkg/RedfishClient.fdf.inc
> @@ -25,6 +25,7 @@
>   INF RedfishClientPkg/HiiToRedfishBiosDxe/HiiToRedfishBiosDxe.inf
>   INF
> RedfishClientPkg/Features/BootOptionCollection/BootOptionCollectionDxe.inf
>   INF RedfishClientPkg/Features/BootOption/v1_0_4/Dxe/BootOptionDxe.inf
> +  INF RedfishClientPkg/Features/SecureBoot/v1_1_0/Dxe/SecureBootDxe.inf
>
>   !include RedfishClientPkg/RedfishJsonStructureDxe.fdf.inc
>   #
> --
> 2.34.1
>
>
>
>
>
>
>
> Regards,
>
> Mike
>
>
>

Regards,
Mike.


-=-=-=-=-=-=-=-=-=-=-=-
Groups.io Links: You receive all messages sent to this group.
View/Reply Online (#117142): https://edk2.groups.io/g/devel/message/117142
Mute This Topic: https://groups.io/mt/104927848/7686176
Group Owner: devel+owner@edk2.groups.io
Unsubscribe: https://edk2.groups.io/g/devel/unsub [rebecca@openfw.io]
-=-=-=-=-=-=-=-=-=-=-=-



[-- Attachment #2: Type: text/html, Size: 86463 bytes --]

^ permalink raw reply	[flat|nested] 5+ messages in thread

* Re: [edk2-devel] [edk2-redfish-client][PATCH 1/2] RedfishClientPkg/Features: support Redfish Secure Boot
  2024-03-26 22:56     ` Mike Maslenkin
@ 2024-04-01 14:25       ` Nickle Wang via groups.io
  0 siblings, 0 replies; 5+ messages in thread
From: Nickle Wang via groups.io @ 2024-04-01 14:25 UTC (permalink / raw)
  To: Mike Maslenkin; +Cc: devel, Abner Chang, Igor Kulchytskyy, Nick Ramirez

[-- Attachment #1: Type: text/plain, Size: 63339 bytes --]

Hi Mike,

> For the case when PropertyChanged left FALSE, allocated values AsciiStringValue and IntegerValue are leaked.

Thanks for catching this memory issue.

> MatchPropertyWithJsonContext() seems to be a heavy call.
> The only useful thing this loop does in that case is printing missed property if enabled.

Yes, it makes sense to break loop when we have EFI_NOT_FOUND case. I guess I don’t do this is just because I like to know how many properties are missing on BMC as you suggested.

I addressed above comments in version2 path set here: https://edk2.groups.io/g/devel/message/117292  And we also need same changes for other feature drivers. I will send out another patch for them later.

Regards,
Nickle

From: Mike Maslenkin <mike.maslenkin@gmail.com>
Sent: Wednesday, March 27, 2024 6:57 AM
To: Nickle Wang <nicklew@nvidia.com>
Cc: devel@edk2.groups.io; Abner Chang <abner.chang@amd.com>; Igor Kulchytskyy <igork@ami.com>; Nick Ramirez <nramirez@nvidia.com>
Subject: Re: [edk2-devel] [edk2-redfish-client][PATCH 1/2] RedfishClientPkg/Features: support Redfish Secure Boot

External email: Use caution opening links or attachments

Hi Nickle,

On Tue, Mar 26, 2024 at 4:57 PM Nickle Wang <nicklew@nvidia.com<mailto:nicklew@nvidia.com>> wrote:
Hi Mike,

Thanks for your review. I addressed your review comments in pull request: https://github.com/tianocore/edk2-redfish-client/pull/83

I am waiting for Abner’s patch (PR#84) because I plan to incorporate Abner’s changes into this driver. I will send version 2 patch series here for review later.

Regards,
Nickle



I see my comments were addressed, and I agree with that.

But I think I found another minor leaks in a common pattern:
+  if (PropertyChecker (SecureBootCs->SecureBootMode, ProvisionMode)) {
+    Status = GetSetupMode (&SetupMode);
+    if (!EFI_ERROR (Status)) {
+      AsciiStringValue = AllocateZeroPool (SECURE_BOOT_MODE_STR_LEN *sizeof (CHAR8));
+      if (AsciiStringValue != NULL) {
+        AsciiSPrint (AsciiStringValue, SECURE_BOOT_MODE_STR_LEN *sizeof (CHAR8), "%a", (SetupMode == USER_MODE ? SECURE_BOOT_USER_MODE : SECURE_BOOT_SETUP_MODE));
+        if (ProvisionMode || (AsciiStrCmp (SecureBootCs->SecureBootMode, AsciiStringValue) != 0)) {
+          SecureBootCs->SecureBootMode = AsciiStringValue;
+          PropertyChanged              = TRUE;
+        }
+      }
+    } else {
+      DEBUG ((DEBUG_ERROR, "%a: cannot read setup mode: %r\n", __func__, Status));
+    }
+  }

For the case when PropertyChanged left FALSE, allocated values AsciiStringValue and IntegerValue are leaked.

Also there is a one new question below:

From: Mike Maslenkin <mike.maslenkin@gmail.com<mailto:mike.maslenkin@gmail.com>>
Sent: Friday, March 15, 2024 3:38 AM
To: devel@edk2.groups.io<mailto:devel@edk2.groups.io>; Nickle Wang <nicklew@nvidia.com<mailto:nicklew@nvidia.com>>
Cc: Abner Chang <abner.chang@amd.com<mailto:abner.chang@amd.com>>; Igor Kulchytskyy <igork@ami.com<mailto:igork@ami.com>>; Nick Ramirez <nramirez@nvidia.com<mailto:nramirez@nvidia.com>>
Subject: Re: [edk2-devel] [edk2-redfish-client][PATCH 1/2] RedfishClientPkg/Features: support Redfish Secure Boot

External email: Use caution opening links or attachments

Hi Nickle,

please find my comments below

On 14. 3. 2024., at 17:53, Nickle Wang via groups.io<http://groups.io/> <nicklew=nvidia.com@groups.io<mailto:nvidia.com@groups.io>> wrote:

Introduce SecureBoot driver to support
/redfish/v1/Systems/SYS/SecureBoot resource.

Signed-off-by: Nickle Wang <nicklew@nvidia.com<mailto:nicklew@nvidia.com>>
Cc: Abner Chang <abner.chang@amd.com<mailto:abner.chang@amd.com>>
Cc: Igor Kulchytskyy <igork@ami.com<mailto:igork@ami.com>>
Cc: Nick Ramirez <nramirez@nvidia.com<mailto:nramirez@nvidia.com>>
---
.../RedfishClientComponents.dsc.inc           |   2 +
RedfishClientPkg/RedfishClientLibs.dsc.inc    |   4 +
.../SecureBoot/v1_1_0/Dxe/SecureBootDxe.inf   |  60 ++
.../v1_1_0/Common/SecureBootCommon.h          |  40 +
.../v1_1_0/Common/SecureBootCommon.c          | 756 ++++++++++++++++
.../SecureBoot/v1_1_0/Dxe/SecureBootDxe.c     | 808 ++++++++++++++++++
RedfishClientPkg/RedfishClient.fdf.inc        |   1 +
7 files changed, 1671 insertions(+)
create mode 100644 RedfishClientPkg/Features/SecureBoot/v1_1_0/Dxe/SecureBootDxe.inf
create mode 100644 RedfishClientPkg/Features/SecureBoot/v1_1_0/Common/SecureBootCommon.h
create mode 100644 RedfishClientPkg/Features/SecureBoot/v1_1_0/Common/SecureBootCommon.c
create mode 100644 RedfishClientPkg/Features/SecureBoot/v1_1_0/Dxe/SecureBootDxe.c

diff --git a/RedfishClientPkg/RedfishClientComponents.dsc.inc b/RedfishClientPkg/RedfishClientComponents.dsc.inc
index ae2a4b025..42fc0c299 100644
--- a/RedfishClientPkg/RedfishClientComponents.dsc.inc
+++ b/RedfishClientPkg/RedfishClientComponents.dsc.inc
@@ -34,6 +34,7 @@
  RedfishClientPkg/Features/Bios/v1_0_9/Dxe/BiosDxe.inf
  RedfishClientPkg/Features/BootOptionCollection/BootOptionCollectionDxe.inf
  RedfishClientPkg/Features/BootOption/v1_0_4/Dxe/BootOptionDxe.inf
+  RedfishClientPkg/Features/SecureBoot/v1_1_0/Dxe/SecureBootDxe.inf

  !include RedfishClientPkg/RedfishJsonStructureDxe.dsc.inc

@@ -47,3 +48,4 @@
  RedfishClientPkg/Converter/Bios/v1_0_9/RedfishBios_V1_0_9_Dxe.inf
  RedfishClientPkg/Converter/BootOptionCollection/RedfishBootOptionCollection_Dxe.inf
  RedfishClientPkg/Converter/BootOption/v1_0_4/RedfishBootOption_V1_0_4_Dxe.inf
+  RedfishClientPkg/Converter/SecureBoot/v1_1_0/RedfishSecureBoot_V1_1_0_Dxe.inf
diff --git a/RedfishClientPkg/RedfishClientLibs.dsc.inc b/RedfishClientPkg/RedfishClientLibs.dsc.inc
index 6599926ab..9126465df 100644
--- a/RedfishClientPkg/RedfishClientLibs.dsc.inc
+++ b/RedfishClientPkg/RedfishClientLibs.dsc.inc
@@ -25,6 +25,8 @@
  BiosV1_0_9Lib|RedfishClientPkg/ConverterLib/edk2library/Bios/v1_0_9/Lib.inf
  BootOptionCollectionLib|RedfishClientPkg/ConverterLib/edk2library/BootOptionCollection/Lib.inf
  BootOptionV1_0_4Lib|RedfishClientPkg/ConverterLib/edk2library/BootOption/v1_0_4/Lib.inf
+  SecureBootV1_1_0Lib|RedfishClientPkg/ConverterLib/edk2library/SecureBoot/v1_1_0/Lib.inf
+
  #
  # Above modules should be pulled in by build tool.
  #
@@ -42,3 +44,5 @@
  RedfishAddendumLib|RedfishClientPkg/Library/RedfishAddendumLib/RedfishAddendumLib.inf
  RedfishDebugLib|RedfishPkg/Library/RedfishDebugLib/RedfishDebugLib.inf
  RedfishHttpLib|RedfishPkg/Library/RedfishHttpLib/RedfishHttpLib.inf
+  SecureBootVariableLib|SecurityPkg/Library/SecureBootVariableLib/SecureBootVariableLib.inf
+  PlatformPKProtectionLib|SecurityPkg/Library/PlatformPKProtectionLibVarPolicy/PlatformPKProtectionLibVarPolicy.inf
diff --git a/RedfishClientPkg/Features/SecureBoot/v1_1_0/Dxe/SecureBootDxe.inf b/RedfishClientPkg/Features/SecureBoot/v1_1_0/Dxe/SecureBootDxe.inf
new file mode 100644
index 000000000..1ad8c623f
--- /dev/null
+++ b/RedfishClientPkg/Features/SecureBoot/v1_1_0/Dxe/SecureBootDxe.inf
@@ -0,0 +1,60 @@
+## @file
+#
+#  (C) Copyright 2020-2022 Hewlett Packard Enterprise Development LP<BR>
+#  Copyright (c) 2022-2024, NVIDIA CORPORATION & AFFILIATES. All rights reserved.
+#
+#  SPDX-License-Identifier: BSD-2-Clause-Patent
+#
+##
+
+
+[Defines]
+  INF_VERSION               = 0x00010005
+  BASE_NAME                 = SecureBootDxe
+  FILE_GUID                 = 5E4025F8-DA42-468A-853E-6A1091D35052
+  MODULE_TYPE               = DXE_DRIVER
+  VERSION_STRING            = 1.0
+  ENTRY_POINT               = RedfishResourceEntryPoint
+  UNLOAD_IMAGE              = RedfishResourceUnload
+
+[Packages]
+  MdePkg/MdePkg.dec
+  MdeModulePkg/MdeModulePkg.dec
+  SecurityPkg/SecurityPkg.dec
+  RedfishPkg/RedfishPkg.dec
+  RedfishClientPkg/RedfishClientPkg.dec
+
+[Sources]
+  ../Common/SecureBootCommon.h
+  ../Common/SecureBootCommon.c
+  SecureBootDxe.c
+
+[LibraryClasses]
+  BaseMemoryLib
+  DebugLib
+  EdkIIRedfishResourceConfigLib
+  RedfishFeatureUtilityLib
+  RedfishVersionLib
+  RedfishResourceIdentifyLib
+  SecureBootVariableLib
+  UefiLib
+  UefiDriverEntryPoint
+  RedfishAddendumLib
+  UefiRuntimeServicesTableLib
+
+[Protocols]
+  gEdkIIRedfishConfigHandlerProtocolGuid          ## PRODUCED
+  gEfiRestJsonStructureProtocolGuid               ## CONSUMED
+  gEdkIIRedfishResourceConfigProtocolGuid         ## PRODUCED
+  gEdkIIRedfishFeatureProtocolGuid                ## CONSUMED
+
+[Guids]
+  gEfiSecureBootEnableDisableGuid                 ## CONSUMED
+
+[Pcd]
+  gEfiRedfishClientPkgTokenSpaceGuid.PcdMaxRedfishSchemaStringSize
+  gEfiRedfishClientPkgTokenSpaceGuid.PcdMaxRedfishSchemaVersionSize
+  gEfiRedfishClientPkgTokenSpaceGuid.PcdRedfishSystemRebootRequired
+
+[Depex]
+  TRUE
diff --git a/RedfishClientPkg/Features/SecureBoot/v1_1_0/Common/SecureBootCommon.h b/RedfishClientPkg/Features/SecureBoot/v1_1_0/Common/SecureBootCommon.h
new file mode 100644
index 000000000..0d1824160
--- /dev/null
+++ b/RedfishClientPkg/Features/SecureBoot/v1_1_0/Common/SecureBootCommon.h
@@ -0,0 +1,40 @@
+/** @file
+
+  Redfish feature driver implementation - internal header file
+  (C) Copyright 2020-2022 Hewlett Packard Enterprise Development LP<BR>
+  Copyright (c) 2022-2024, NVIDIA CORPORATION & AFFILIATES. All rights reserved.
+
+  SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#ifndef EFI_REDFISH_SECUREBOOT_COMMON_H_
+#define EFI_REDFISH_SECUREBOOT_COMMON_H_
+
+#include <Guid/ImageAuthentication.h>
+#include <Guid/GlobalVariable.h>
+#include <Guid/AuthenticatedVariableFormat.h>
+#include <RedfishJsonStructure/SecureBoot/v1_1_0/EfiSecureBootV1_1_0.h>
+#include <RedfishResourceCommon.h>
+#include <UefiSecureBoot.h>
+#include <Library/UefiRuntimeServicesTableLib.h>
+#include <Library/SecureBootVariableLib.h>
+
+//
+// Schema information.
+//
+#define REDFISH_MANAGED_URI        L"Systems/{}/SecureBoot"
+#define REDFISH_DUMMY_CONFIG_LANG  L"Systems/{1}/SecureBoot"
+#define MAX_URI_LENGTH             256
+#define RESOURCE_SCHEMA            "SecureBoot"
+#define RESOURCE_SCHEMA_MAJOR      "1"
+#define RESOURCE_SCHEMA_MINOR      "1"
+#define RESOURCE_SCHEMA_ERRATA     "0"
+#define RESOURCE_SCHEMA_VERSION    "v1_1_0"
+#define SECURE_BOOT_SETUP_MODE     "SetupMode"
+#define SECURE_BOOT_USER_MODE      "UserMode"
+#define SECURE_BOOT_ENABLED        "Enabled"
+#define SECURE_BOOT_DISABLED       "Disabled"
+#define SECURE_BOOT_MODE_STR_LEN   16
+
+#endif
diff --git a/RedfishClientPkg/Features/SecureBoot/v1_1_0/Common/SecureBootCommon.c b/RedfishClientPkg/Features/SecureBoot/v1_1_0/Common/SecureBootCommon.c
new file mode 100644
index 000000000..56a45ee72
--- /dev/null
+++ b/RedfishClientPkg/Features/SecureBoot/v1_1_0/Common/SecureBootCommon.c
@@ -0,0 +1,756 @@
+/** @file
+  Redfish feature driver implementation - common functions
+
+  (C) Copyright 2020-2022 Hewlett Packard Enterprise Development LP<BR>
+  Copyright (c) 2023-2024, NVIDIA CORPORATION & AFFILIATES. All rights reserved.
+
+  SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include "SecureBootCommon.h"
+
+CHAR8  SecureBootEmptyJson[] = "{\"@odata.id<http://odata.id/>\": \"\", \"@odata.type\": \"#SecureBoot.v1_1_0.SecureBoot\", \"Id\": \"\", \"Name\": \"\", \"Attributes\":{}}";
+
+REDFISH_RESOURCE_COMMON_PRIVATE  *mRedfishResourcePrivate                                  = NULL;
+EFI_HANDLE                       mRedfishResourceConfigProtocolHandle                      = NULL;
+CHAR16                           *mSecureBootSupportedAttributes[SECURE_BOOT_MODE_STR_LEN] = {
+  L"SecureBootCurrentBoot",
+  L"SecureBootEnable",
+  L"SecureBootMode"
+};
+
+/**
+  Read EFI_SECURE_BOOT_ENABLE_NAME variable and return its value to caller.
+
+  @retval BOOLEAN    TRUE when EFI_SECURE_BOOT_ENABLE_NAME value is SECURE_BOOT_ENABLE
+                     FALSE when EFI_SECURE_BOOT_ENABLE_NAME value is SECURE_BOOT_DISABLE
+**/
+BOOLEAN
+RedfishReadSecureBootEnable (
+  VOID
+  )
+{
+  UINT8    *Buffer;
+  BOOLEAN  SecureBootEnableValue;
+
+  Buffer                = NULL;
+  SecureBootEnableValue = FALSE;
+
+  GetVariable2 (
+    EFI_SECURE_BOOT_ENABLE_NAME,
+    &gEfiSecureBootEnableDisableGuid,
+    (VOID **)&Buffer,
+    NULL
+    );
+
+  if (Buffer != NULL) {
+    if (*Buffer == SECURE_BOOT_ENABLE) {
+      SecureBootEnableValue = TRUE;
+    }
+
+    FreePool (Buffer);
+  }
+
+  return SecureBootEnableValue;
+}
+
+/**
+  Write EFI_SECURE_BOOT_ENABLE_NAME variable with given value.
+
+  @param[in]   SecureBootEnableValue    Value to write. TRUE is SECURE_BOOT_ENABLE.
+                                        FALSE is SECURE_BOOT_DISABLE.
+
+  @retval EFI_SUCCESS              Write value successfully.
+  @retval Others                   Some error happened.
+**/
+EFI_STATUS
+RedfishWriteSecureBootEnable (
+  BOOLEAN  SecureBootEnableValue
+  )
+{
+  EFI_STATUS  Status;
+  UINT8       VarValue;
+
+  VarValue = (SecureBootEnableValue ? SECURE_BOOT_ENABLE : SECURE_BOOT_DISABLE);
+  Status   = gRT->SetVariable (
+                    EFI_SECURE_BOOT_ENABLE_NAME,
+                    &gEfiSecureBootEnableDisableGuid,
+                    EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS,
+                    sizeof (VarValue),
+                    &VarValue
+                    );
+
+  return Status;
+}
+
+/**
+  Consume Redfish resource in given Json data.
+
+  @param[in]   This                Pointer to REDFISH_RESOURCE_COMMON_PRIVATE instance.
+  @param[in]   Json                The JSON to consume.
+  @param[in]   HeaderEtag          The Etag string returned in HTTP header.
+
+  @retval EFI_SUCCESS              Consume Redfish attribute successfully.
+  @retval Others                   Some error happened.
+
+**/
+EFI_STATUS
+RedfishConsumeResourceCommon (
+  IN  REDFISH_RESOURCE_COMMON_PRIVATE  *Private,
+  IN  CHAR8                            *Json,
+  IN  CHAR8                            *HeaderEtag OPTIONAL
+  )
+{
+  EFI_STATUS                        Status;
+  EFI_REDFISH_SECUREBOOT_V1_1_0     *SecureBoot;
+  EFI_REDFISH_SECUREBOOT_V1_1_0_CS  *SecureBootCs;
+  BOOLEAN                           SecureBootEnableDisable;
+
+  if ((Private == NULL) || IS_EMPTY_STRING (Json)) {
+    return EFI_INVALID_PARAMETER;
+  }
+
+  SecureBoot              = NULL;
+  SecureBootCs            = NULL;
+  SecureBootEnableDisable = RedfishReadSecureBootEnable ();
+
+  Status = Private->JsonStructProtocol->ToStructure (
+                                          Private->JsonStructProtocol,
+                                          NULL,
+                                          Json,
+                                          (EFI_REST_JSON_STRUCTURE_HEADER **)&SecureBoot
+                                          );
+  if (EFI_ERROR (Status)) {
+    DEBUG ((DEBUG_ERROR, "%a: ToStructure() failed: %r\n", __func__, Status));
+    return Status;
+  }
+
+  SecureBootCs = SecureBoot->SecureBoot;
+
+  //
+  // Check ETAG to see if we need to consume it
+  //
+  if (CheckEtag (Private->Uri, HeaderEtag, SecureBootCs->odata_etag)) {
+    //
+    // No change
+    //
+    DEBUG ((REDFISH_DEBUG_TRACE, "%a: ETAG: %s has no change, ignore consume action\n", __func__, Private->Uri));
+    Status = EFI_ALREADY_STARTED;
+    goto ON_RELEASE;
+  }
+
+  //
+  // Secure boot enable
+  //
+  if (SecureBootCs->SecureBootEnable != NULL) {
+    if (SecureBootEnableDisable != *SecureBootCs->SecureBootEnable) {
+      //
+      // Write value to "SecureBootEnable" variable. AuthVariableLib will enable or disable secure boot
+      // based on "SecureBootEnable" value.
+      //
+      Status = RedfishWriteSecureBootEnable (*SecureBootCs->SecureBootEnable);
+      if (EFI_ERROR (Status)) {
+        DEBUG ((DEBUG_ERROR, "%a: write secure boot enable disable failed: %r\n", __func__, Status));
+      } else {
+        REDFISH_ENABLE_SYSTEM_REBOOT ();
+      }
+    } else {
+      DEBUG ((REDFISH_DEBUG_TRACE, "%a: secure boot mode is not changed\n", __func__));
+    }
+  }
+
+ON_RELEASE:
+
+  //
+  // Release resource.
+  //
+  Private->JsonStructProtocol->DestoryStructure (
+                                 Private->JsonStructProtocol,
+                                 (EFI_REST_JSON_STRUCTURE_HEADER *)SecureBoot
+                                 );
+
+  return EFI_SUCCESS;
+}
+
+/**
+  Provision Redfish resource. This function reads secure boot variable and convert it
+  to Redfish attribute.
+
+  @param[in]   JsonStructProtocol  Pointer to Json structure protocol.
+  @param[in]   InputJson           Jason data on input.
+  @param[in]   ResourceId          Resource ID. This is optional.
+  @param[in]   ConfigureLang       Configure language for this Redfish resource.
+  @param[in]   ProvisionMode       TRUE when this is to provision Redfish attribute to
+                                   Redfish service. FALSE is to update Redfish attribute
+                                   to Redfish service.
+  @param[out]  ResultJson          Json data on output.
+
+  @retval EFI_SUCCESS              Provision Redfish attribute successfully.
+  @retval Others                   Some error happened.
+
+**/
+EFI_STATUS
+ProvisioningSecureBootProperties (
+  IN  EFI_REST_JSON_STRUCTURE_PROTOCOL  *JsonStructProtocol,
+  IN  CHAR8                             *InputJson,
+  IN  CHAR8                             *ResourceId OPTIONAL,
+  IN  EFI_STRING                        ConfigureLang,
+  IN  BOOLEAN                           ProvisionMode,
+  OUT CHAR8                             **ResultJson
+  )
+{
+  EFI_REDFISH_SECUREBOOT_V1_1_0     *SecureBoot;
+  EFI_REDFISH_SECUREBOOT_V1_1_0_CS  *SecureBootCs;
+  EFI_STATUS                        Status;
+  BOOLEAN                           PropertyChanged;
+  CHAR8                             *AsciiStringValue;
+  INT32                             *IntegerValue;
+  UINT8                             SetupMode;
+  BOOLEAN                           SecureBootEnabled;
+  BOOLEAN                           SecureBootEnableDisable;
+
+  if ((JsonStructProtocol == NULL) || (ResultJson == NULL) || IS_EMPTY_STRING (InputJson) || IS_EMPTY_STRING (ConfigureLang)) {
+    return EFI_INVALID_PARAMETER;
+  }
+
+  DEBUG ((REDFISH_DEBUG_TRACE, "%a provision for %s with: %s\n", __func__, ConfigureLang, (ProvisionMode ? L"Provision resource" : L"Update resource")));
+
+  *ResultJson             = NULL;
+  PropertyChanged         = FALSE;
+  AsciiStringValue        = NULL;
+  SecureBootEnableDisable = RedfishReadSecureBootEnable ();
+  SecureBootEnabled       = IsSecureBootEnabled ();
+
+  SecureBoot = NULL;
+  Status     = JsonStructProtocol->ToStructure (
+                                     JsonStructProtocol,
+                                     NULL,
+                                     InputJson,
+                                     (EFI_REST_JSON_STRUCTURE_HEADER **)&SecureBoot
+                                     );
+  if (EFI_ERROR (Status)) {
+    DEBUG ((DEBUG_ERROR, "%a: ToStructure failure: %r\n", __func__, Status));
+    return Status;
+  }
+
+  SecureBootCs = SecureBoot->SecureBoot;
+
+  //
+  // ID
+  //
+  if (SecureBootCs->Id != NULL) {
+    SecureBootCs->Id = NULL;
+  }
+
+  //
+  // Name
+  //
+  if (SecureBootCs->Name != NULL) {
+    SecureBootCs->Name = NULL;
+  }
+
+  //
+  // Secure boot variables that we will handle here
+  //
+  // EFI_SETUP_MODE_NAME (gEfiGlobalVariableGuid)
+  // EFI_SECURE_BOOT_MODE_NAME (gEfiGlobalVariableGuid)
+  // EFI_SECURE_BOOT_ENABLE_NAME (gEfiSecureBootEnableDisableGuid)
+  //
+
+  //
+  // Current Boot
+  //
+  if (PropertyChecker (SecureBootCs->SecureBootCurrentBoot, ProvisionMode)) {
+    AsciiStringValue = AllocateZeroPool (SECURE_BOOT_MODE_STR_LEN * sizeof (CHAR8));
+    if (AsciiStringValue != NULL) {
+      AsciiSPrint (AsciiStringValue, SECURE_BOOT_MODE_STR_LEN, "%a", (SecureBootEnabled ? SECURE_BOOT_ENABLED : SECURE_BOOT_DISABLED));
+      if (ProvisionMode || (AsciiStrCmp (SecureBootCs->SecureBootCurrentBoot, AsciiStringValue) != 0)) {
+        SecureBootCs->SecureBootCurrentBoot = AsciiStringValue;
+        PropertyChanged                     = TRUE;
+      }
+    } else {
+      DEBUG ((DEBUG_ERROR, "%a: out of resource\n", __func__));
+    }
+  }
+
+  //
+  // Secure boot enable
+  //
+  if (PropertyChecker (SecureBootCs->SecureBootEnable, ProvisionMode)) {
+    if (ProvisionMode || (*SecureBootCs->SecureBootEnable != SecureBootEnableDisable)) {
+      IntegerValue = AllocatePool (sizeof (*IntegerValue));
+      if (IntegerValue != NULL) {
+        *IntegerValue                  = (SecureBootEnableDisable ? 0x01 : 0x00);
+        SecureBootCs->SecureBootEnable = IntegerValue;
+        PropertyChanged                = TRUE;
+      } else {
+        DEBUG ((DEBUG_ERROR, "%a: out of resource\n", __func__));
+      }
+    }
+  }
+
+  //
+  // Secure boot mode
+  //
+  if (PropertyChecker (SecureBootCs->SecureBootMode, ProvisionMode)) {
+    Status = GetSetupMode (&SetupMode);
+    if (!EFI_ERROR (Status)) {
+      AsciiStringValue = AllocateZeroPool (SECURE_BOOT_MODE_STR_LEN *sizeof (CHAR8));
+      if (AsciiStringValue != NULL) {
+        AsciiSPrint (AsciiStringValue, SECURE_BOOT_MODE_STR_LEN *sizeof (CHAR8), "%a", (SetupMode == USER_MODE ? SECURE_BOOT_USER_MODE : SECURE_BOOT_SETUP_MODE));
+        if (ProvisionMode || (AsciiStrCmp (SecureBootCs->SecureBootMode, AsciiStringValue) != 0)) {
+          SecureBootCs->SecureBootMode = AsciiStringValue;
+          PropertyChanged              = TRUE;
+        }
+      }
+    } else {
+      DEBUG ((DEBUG_ERROR, "%a: cannot read setup mode: %r\n", __func__, Status));
+    }
+  }
+
+  //
+  // Convert C structure back to JSON text.
+  //
+  Status = JsonStructProtocol->ToJson (
+                                 JsonStructProtocol,
+                                 (EFI_REST_JSON_STRUCTURE_HEADER *)SecureBoot,
+                                 ResultJson
+                                 );
+  if (EFI_ERROR (Status)) {
+    DEBUG ((DEBUG_ERROR, "%a: ToJson() failed: %r\n", __func__, Status));
+    return Status;



  SecureBoot structure leak. It is released below.

+  }
+
+  //
+  // Release resource.
+  //
+  JsonStructProtocol->DestoryStructure (
+                        JsonStructProtocol,
+                        (EFI_REST_JSON_STRUCTURE_HEADER *)SecureBoot
+                        );
+
+  return (PropertyChanged ? EFI_SUCCESS : EFI_NOT_FOUND);
+}
+
+/**
+  Provision Redfish resource and upload data to Redfish service. This function
+  checks OEM data and platform addendum data before sending data to Redfish service.
+
+  @param[in]   Private   Pointer to private data.
+
+  @retval EFI_SUCCESS              Provision Redfish resource successfully.
+  @retval Others                   Some error happened.
+
+**/
+EFI_STATUS
+ProvisioningSecureBootResource (
+  IN  REDFISH_RESOURCE_COMMON_PRIVATE  *Private
+  )
+{
+  EFI_STATUS        Status;
+  CHAR8             *Json;
+  CHAR8             *JsonWithAddendum;
+  REDFISH_RESPONSE  Response;
+
+  if (Private == NULL) {
+    return EFI_INVALID_PARAMETER;
+  }
+
+  ZeroMem (&Response, sizeof (REDFISH_RESPONSE));
+  Json = NULL;
+
+  Status = ProvisioningSecureBootProperties (
+             Private->JsonStructProtocol,
+             SecureBootEmptyJson,
+             NULL,
+             REDFISH_DUMMY_CONFIG_LANG,
+             TRUE,
+             &Json
+             );
+  if (EFI_ERROR (Status)) {
+    if (Status == EFI_NOT_FOUND) {
+      DEBUG ((REDFISH_DEBUG_TRACE, "%a: provisioning existing resource for %s ignored. Nothing changed\n", __func__, REDFISH_DUMMY_CONFIG_LANG));
+      Status = EFI_SUCCESS;
+    } else {
+      DEBUG ((DEBUG_ERROR, "%a: provisioning existing resource for %s failed: %r\n", __func__, REDFISH_DUMMY_CONFIG_LANG, Status));
+    }
+
+    goto ON_RELEASE;
+  }
+
+  //
+  // Check and see if platform has OEM data or not
+  //
+  Status = RedfishGetOemData (
+             Private->Uri,
+             RESOURCE_SCHEMA,
+             RESOURCE_SCHEMA_VERSION,
+             Json,
+             &JsonWithAddendum
+             );
+  if (!EFI_ERROR (Status) && (JsonWithAddendum != NULL)) {
+    FreePool (Json);
+    Json             = JsonWithAddendum;
+    JsonWithAddendum = NULL;
+  }
+
+  //
+  // Check and see if platform has addendum data or not
+  //
+  Status = RedfishGetAddendumData (
+             Private->Uri,
+             RESOURCE_SCHEMA,
+             RESOURCE_SCHEMA_VERSION,
+             Json,
+             &JsonWithAddendum
+             );
+  if (!EFI_ERROR (Status) && (JsonWithAddendum != NULL)) {
+    FreePool (Json);
+    Json             = JsonWithAddendum;
+    JsonWithAddendum = NULL;
+  }
+
+  DEBUG ((REDFISH_DEBUG_TRACE, "%a: provisioning existing resource for %s\n", __func__, REDFISH_DUMMY_CONFIG_LANG));
+
+  //
+  // PATCH back to instance
+  //
+  Status = RedfishHttpPatchResource (Private->RedfishService, Private->Uri, Json, &Response);
+  if (EFI_ERROR (Status)) {
+    DEBUG ((DEBUG_ERROR, "%a: patch resource for %s failed: %r\n", __func__, REDFISH_DUMMY_CONFIG_LANG, Status));
+  }
+
+ON_RELEASE:
+
+  if (Json != NULL) {
+    FreePool (Json);
+  }
+
+  RedfishHttpFreeResponse (&Response);
+
+  return Status;
+}
+
+/**
+  Provisioning redfish resource to Redfish service.
+
+  @param[in]   Private             Pointer to private data.
+  @param[in]   ResourceExist       TRUE if resource exists, PUT method will be used.
+                                   FALSE if resource does not exist POST method is used.


Actually ProvisioningSecureBootResource uses PATCH only.


+
+  @retval EFI_SUCCESS              Provision resource successfully.
+  @retval Others                   Some error happened.
+
+**/
+EFI_STATUS
+RedfishProvisioningResourceCommon (
+  IN     REDFISH_RESOURCE_COMMON_PRIVATE  *Private,
+  IN     BOOLEAN                          ResourceExist
+  )
+{
+  if (Private == NULL) {
+    return EFI_INVALID_PARAMETER;
+  }
+
+  return ProvisioningSecureBootResource (Private);
+}
+
+/**
+  Check resource from given Json data.
+
+  @param[in]   This                Pointer to REDFISH_RESOURCE_COMMON_PRIVATE instance.
+  @param[in]   Json                The JSON data to check.
+  @param[in]   HeaderEtag          The Etag string returned in HTTP header.
+
+  @retval EFI_SUCCESS              Check resource successfully.
+  @retval Others                   Some error happened.
+
+**/
+EFI_STATUS
+RedfishCheckResourceCommon (
+  IN     REDFISH_RESOURCE_COMMON_PRIVATE  *Private,
+  IN     CHAR8                            *Json,
+  IN     CHAR8                            *HeaderEtag OPTIONAL
+  )
+{
+  UINTN       Index;
+  EFI_STATUS  Status;
+  UINTN       Count;
+  EFI_STRING  Property;
+
+  if ((Private == NULL) || IS_EMPTY_STRING (Json)) {
+    return EFI_INVALID_PARAMETER;
+  }
+
+  //
+  // Check ETAG to see if we need to check it
+  //
+  if (CheckEtag (Private->Uri, HeaderEtag, NULL)) {
+    //
+    // No change
+    //
+    DEBUG ((REDFISH_DEBUG_TRACE, "%a: ETAG: %s has no change, ignore check action\n", __func__, Private->Uri));
+    return EFI_SUCCESS;
+  }
+
+  Count = sizeof (mSecureBootSupportedAttributes) / sizeof (mSecureBootSupportedAttributes[0]);
+  if (Count == 0) {
+    return EFI_UNSUPPORTED;
+  }
+
+  Status = EFI_SUCCESS;
+  for (Index = 0; Index < Count; Index++) {
+    Property = mSecureBootSupportedAttributes[Index];
+    if (Property == NULL) {
+      continue;
+    }
+
+    DEBUG ((REDFISH_DEBUG_TRACE, "%a: [%d] check attribute for: %s\n", __func__, Index, Property));
+    if (!MatchPropertyWithJsonContext (Property, Json)) {
+      DEBUG ((REDFISH_DEBUG_TRACE, "%a: property is missing: %s\n", __func__, Property));
+      Status = EFI_NOT_FOUND;

Oh! I have a question about this condition.
Can we just break the loop here?
I'm asking mostly in context of Bios feature driver where the same loop exists.
While in this driver Count not greater than 3, but for Bios driver there could be a hundreds of iterations
and AFAIR during provisioning we have EFI_NOT_FOUND right after the first iteration.
MatchPropertyWithJsonContext() seems to be a heavy call.

The only useful thing this loop does in that case is printing missed property if enabled.

+    }
+  }
+
+  return Status;
+}
+
+/**
+  Update resource to Redfish service.
+
+  @param[in]   Private             Pointer to REDFISH_RESOURCE_COMMON_PRIVATE instance.
+  @param[in]   Json                The JSON data to be updated.
+
+  @retval EFI_SUCCESS              Update resource successfully.
+  @retval Others                   Some error happened.
+
+**/
+EFI_STATUS
+RedfishUpdateResourceCommon (
+  IN     REDFISH_RESOURCE_COMMON_PRIVATE  *Private,
+  IN     CHAR8                            *InputJson
+  )
+{
+  EFI_STATUS        Status;
+  CHAR8             *Json;
+  CHAR8             *JsonWithAddendum;
+  REDFISH_RESPONSE  Response;
+
+  if ((Private == NULL) || IS_EMPTY_STRING (InputJson)) {
+    return EFI_INVALID_PARAMETER;
+  }
+
+  ZeroMem (&Response, sizeof (REDFISH_RESPONSE));
+  Json = NULL;
+
+  Status = ProvisioningSecureBootProperties (
+             Private->JsonStructProtocol,
+             SecureBootEmptyJson,
+             NULL,
+             REDFISH_DUMMY_CONFIG_LANG,
+             TRUE,
+             &Json
+             );
+  if (EFI_ERROR (Status)) {
+    if (Status == EFI_NOT_FOUND) {
+      DEBUG ((REDFISH_DEBUG_TRACE, "%a: update resource for %s ignored. Nothing changed\n", __func__, REDFISH_DUMMY_CONFIG_LANG));
+      Status = EFI_SUCCESS;
+    } else {
+      DEBUG ((DEBUG_ERROR, "%a: update resource for %s failed: %r\n", __func__, REDFISH_DUMMY_CONFIG_LANG, Status));
+    }
+
+    goto ON_RELEASE;
+  }
+
+  //
+  // Check and see if platform has OEM data or not
+  //
+  Status = RedfishGetOemData (
+             Private->Uri,
+             RESOURCE_SCHEMA,
+             RESOURCE_SCHEMA_VERSION,
+             Json,
+             &JsonWithAddendum
+             );
+  if (!EFI_ERROR (Status) && (JsonWithAddendum != NULL)) {
+    FreePool (Json);
+    Json             = JsonWithAddendum;
+    JsonWithAddendum = NULL;
+  }
+
+  //
+  // Check and see if platform has addendum data or not
+  //
+  Status = RedfishGetAddendumData (
+             Private->Uri,
+             RESOURCE_SCHEMA,
+             RESOURCE_SCHEMA_VERSION,
+             Json,
+             &JsonWithAddendum
+             );
+  if (!EFI_ERROR (Status) && (JsonWithAddendum != NULL)) {
+    FreePool (Json);
+    Json             = JsonWithAddendum;
+    JsonWithAddendum = NULL;
+  }
+
+  DEBUG ((REDFISH_DEBUG_TRACE, "%a: update resource for %s\n", __func__, REDFISH_DUMMY_CONFIG_LANG));
+
+  //
+  // PATCH back to instance
+  //
+  Status = RedfishHttpPatchResource (Private->RedfishService, Private->Uri, Json, &Response);
+  if (EFI_ERROR (Status)) {
+    DEBUG ((DEBUG_ERROR, "%a: patch resource for %s failed: %r\n", __func__, REDFISH_DUMMY_CONFIG_LANG, Status));
+  }
+
+ON_RELEASE:
+
+  if (Json != NULL) {
+    FreePool (Json);
+  }
+
+  RedfishHttpFreeResponse (&Response);
+
+  return Status;
+}
+
+/**
+  Identify resource in given Json data.
+
+  @param[in]   Private             Pointer to REDFISH_RESOURCE_COMMON_PRIVATE instance.
+  @param[in]   Json                The JSON to be identified.
+
+  @retval EFI_SUCCESS              Identify resource successfully.
+  @retval Others                   Some error happened.
+
+**/
+EFI_STATUS
+RedfishIdentifyResourceCommon (
+  IN     REDFISH_RESOURCE_COMMON_PRIVATE  *Private,
+  IN     CHAR8                            *Json
+  )
+{
+  BOOLEAN  Supported;
+
+  Supported = RedfishIdentifyResource (Private->Uri, Private->Json);
+  if (Supported) {
+    //
+    // Keep URI and ConfigLang mapping
+    //
+    RedfishSetRedfishUri (REDFISH_DUMMY_CONFIG_LANG, Private->Uri);
+  }
+
+  return (Supported ? EFI_SUCCESS : EFI_UNSUPPORTED);
+}
+
+/**
+  Handle Redfish resource in Uri.
+
+  @param[in]   Private             Pointer to REDFISH_RESOURCE_COMMON_PRIVATE instance.
+  @param[in]   Uri                 URI to Redfish resource that we like to process.
+
+  @retval EFI_SUCCESS              Handle resource successfully.
+  @retval Others                   Some error happened.
+
+**/
+EFI_STATUS
+HandleResource (
+  IN  REDFISH_RESOURCE_COMMON_PRIVATE  *Private,
+  IN  EFI_STRING                       Uri
+  )
+{
+  EFI_STATUS           Status;
+  REDFISH_SCHEMA_INFO  SchemaInfo;
+  EFI_STRING           ConfigLang;
+
+  if ((Private == NULL) || IS_EMPTY_STRING (Uri)) {
+    return EFI_INVALID_PARAMETER;
+  }
+
+  //
+  // Resource match
+  //
+
+  DEBUG ((REDFISH_DEBUG_TRACE, "%a: process resource for: %s\n", __func__, Uri));
+
+  Status = GetRedfishSchemaInfo (Private->RedfishService, Private->JsonStructProtocol, Uri, NULL, &SchemaInfo);
+  if (EFI_ERROR (Status)) {
+    DEBUG ((DEBUG_ERROR, "%a: failed to get schema information from: %s %r\n", __func__, Uri, Status));
+    return Status;
+  }
+
+  //
+  // Check and see if this is target resource that we want to handle.
+  // Some resource is handled by other provider so we have to make sure this first.
+  //
+  DEBUG ((REDFISH_DEBUG_TRACE, "%a: Identify for %s\n", __func__, Uri));
+  ConfigLang = RedfishGetConfigLanguage (Uri);
+  if (ConfigLang == NULL) {
+    Status = EdkIIRedfishResourceConfigIdentify (&SchemaInfo, Uri, NULL, Private->InformationExchange);
+    if (EFI_ERROR (Status)) {
+      if (Status == EFI_UNSUPPORTED) {
+        DEBUG ((REDFISH_DEBUG_TRACE, "%a: \"%s\" is not handled by us\n", __func__, Uri));
+        return EFI_SUCCESS;
+      } else if (Status == EFI_NOT_FOUND) {
+        DEBUG ((REDFISH_DEBUG_TRACE, "%a: \"%s\" has nothing to handle\n", __func__, Uri));
+        return EFI_SUCCESS;
+      }
+
+      DEBUG ((DEBUG_ERROR, "%a: fail to identify resource: \"%s\": %r\n", __func__, Uri, Status));
+      return Status;
+    }
+  } else {
+    DEBUG ((REDFISH_DEBUG_TRACE, "%a: history record found: %s\n", __func__, ConfigLang));
+    FreePool (ConfigLang);
+  }
+
+  //
+  // Check and see if target property exist or not even when collection member exists.
+  // If not, we sill do provision.

%s/sill/still

+  //
+  DEBUG ((REDFISH_DEBUG_TRACE, "%a Check for %s\n", __func__, Uri));
+  Status = EdkIIRedfishResourceConfigCheck (&SchemaInfo, Uri, NULL);
+  if (EFI_ERROR (Status)) {
+    if (Status == EFI_UNSUPPORTED) {
+      DEBUG ((REDFISH_DEBUG_TRACE, "%a: \"%s\" is not handled by us\n", __func__, Uri));
+      return EFI_SUCCESS;
+    }
+
+    //
+    // The target property does not exist, do the provision to create property.
+    //
+    DEBUG ((REDFISH_DEBUG_TRACE, "%a provision for %s\n", __func__, Uri));
+    Status = EdkIIRedfishResourceConfigProvisioning (&SchemaInfo, Uri, NULL, Private->InformationExchange, FALSE);
+    if (EFI_ERROR (Status)) {
+      DEBUG ((DEBUG_ERROR, "%a: failed to provision with GET mode: %r\n", __func__, Status));
+    }
+
+    DEBUG ((REDFISH_DEBUG_TRACE, "%a: process resource for: %s finished\n", __func__, Uri));
+
+    return Status;
+  }
+
+  //
+  // Consume first.
+  //
+  DEBUG ((REDFISH_DEBUG_TRACE, "%a consume for %s\n", __func__, Uri));
+  Status = EdkIIRedfishResourceConfigConsume (&SchemaInfo, Uri, NULL);
+  if (EFI_ERROR (Status)) {
+    DEBUG ((DEBUG_ERROR, "%a: failed to consume resource for: %s: %r\n", __func__, Uri, Status));
+  }
+
+  //
+  // Patch.
+  //
+  DEBUG ((REDFISH_DEBUG_TRACE, "%a update for %s\n", __func__, Uri));
+  Status = EdkIIRedfishResourceConfigUpdate (&SchemaInfo, Uri, NULL);
+  if (EFI_ERROR (Status)) {
+    DEBUG ((DEBUG_ERROR, "%a: failed to update resource for: %s: %r\n", __func__, Uri, Status));
+  }
+
+  DEBUG ((REDFISH_DEBUG_TRACE, "%a: process resource for: %s finished\n", __func__, Uri));
+
+  return Status;
+}
diff --git a/RedfishClientPkg/Features/SecureBoot/v1_1_0/Dxe/SecureBootDxe.c b/RedfishClientPkg/Features/SecureBoot/v1_1_0/Dxe/SecureBootDxe.c
new file mode 100644
index 000000000..a0f4f3d14
--- /dev/null
+++ b/RedfishClientPkg/Features/SecureBoot/v1_1_0/Dxe/SecureBootDxe.c
@@ -0,0 +1,808 @@
+/** @file
+  Redfish feature driver implementation - SecureBoot
+
+  (C) Copyright 2020-2022 Hewlett Packard Enterprise Development LP<BR>
+  Copyright (c) 2023, NVIDIA CORPORATION & AFFILIATES. All rights reserved.
+
+  SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include "../Common/SecureBootCommon.h"
+
+extern REDFISH_RESOURCE_COMMON_PRIVATE  *mRedfishResourcePrivate;
+extern EFI_HANDLE                       mRedfishResourceConfigProtocolHandle;
+
+EFI_STATUS
+HandleResource (
+  IN  REDFISH_RESOURCE_COMMON_PRIVATE  *Private,
+  IN  EFI_STRING                       Uri
+  );
+
+/**
+  Provisioning redfish resource by given URI.
+
+  @param[in]   This                Pointer to EFI_HP_REDFISH_HII_PROTOCOL instance.
+  @param[in]   Uri                 Target URI to create resource.
+  @param[in]   PostMode            TRUE if the resource does not exist, post method is used.
+                                   FALSE if the resource exist but property is missing, put method is used.
+
+  @retval EFI_SUCCESS              Value is returned successfully.
+  @retval Others                   Some error happened.
+
+**/
+EFI_STATUS
+EFIAPI
+RedfishResourceProvisioningResource (
+  IN     EDKII_REDFISH_RESOURCE_CONFIG_PROTOCOL  *This,
+  IN     EFI_STRING                              Uri,
+  IN     BOOLEAN                                 PostMode
+  )
+{
+  REDFISH_RESOURCE_COMMON_PRIVATE  *Private;
+  EFI_STATUS                       Status;
+  REDFISH_RESPONSE                 Response;
+
+  if ((This == NULL) || IS_EMPTY_STRING (Uri)) {
+    return EFI_INVALID_PARAMETER;
+  }
+
+  DEBUG ((REDFISH_DEBUG_TRACE, "%a: provisioning in %s mode\n", __func__, (PostMode ? L"POST" : L"PATCH")));


This message conflicts with PostMode parameter description.


+
+  ZeroMem (&Response, sizeof (REDFISH_RESPONSE));
+  Private = REDFISH_RESOURCE_COMMON_PRIVATE_DATA_FROM_RESOURCE_PROTOCOL (This);
+
+  if (Private->RedfishService == NULL) {
+    return EFI_NOT_READY;
+  }
+
+  Status = RedfishHttpGetResource (Private->RedfishService, Uri, NULL, &Response, TRUE);
+  if (EFI_ERROR (Status)) {
+    DEBUG ((DEBUG_ERROR, "%a: get resource from: %s failed\n", __func__, Uri));
+    return Status;
+  }
+
+  Private->Uri     = Uri;
+  Private->Payload = Response.Payload;
+  ASSERT (Private->Payload != NULL);
+
+  Status = RedfishProvisioningResourceCommon (Private, !PostMode);
+  if (EFI_ERROR (Status)) {
+    DEBUG ((DEBUG_ERROR, "%a: failed to provision resource to: %s: %r\n", __func__, Uri, Status));
+  } else {
+    //
+    // Get latest ETag on URI and keep it in variable.
+    //
+    SetEtagFromUri (Private->RedfishService, Private->Uri, TRUE);
+  }
+
+  //
+  // Release resource
+  //
+  RedfishHttpFreeResponse (&Response);
+  Private->Payload = NULL;
+
+  return Status;
+}
+
+/**
+  Consume resource from given URI.
+
+  @param[in]   This                Pointer to EFI_HP_REDFISH_HII_PROTOCOL instance.
+  @param[in]   Uri                 The target URI to consume.
+
+  @retval EFI_SUCCESS              Value is returned successfully.
+  @retval Others                   Some error happened.
+
+**/
+EFI_STATUS
+EFIAPI
+RedfishResourceConsumeResource (
+  IN     EDKII_REDFISH_RESOURCE_CONFIG_PROTOCOL  *This,
+  IN     EFI_STRING                              Uri
+  )
+{
+  REDFISH_RESOURCE_COMMON_PRIVATE  *Private;
+  EFI_STATUS                       Status;
+  REDFISH_RESPONSE                 Response;
+  EFI_STRING                       PendingSettingUri;
+  REDFISH_RESPONSE                 PendingSettingResponse;
+  REDFISH_RESPONSE                 *ExpectedResponse;
+  CHAR8                            *Etag;
+
+  if ((This == NULL) || IS_EMPTY_STRING (Uri)) {
+    return EFI_INVALID_PARAMETER;
+  }
+
+  ZeroMem (&Response, sizeof (REDFISH_RESPONSE));
+  ZeroMem (&PendingSettingResponse, sizeof (REDFISH_RESPONSE));
+  Private = REDFISH_RESOURCE_COMMON_PRIVATE_DATA_FROM_RESOURCE_PROTOCOL (This);
+
+  if (Private->RedfishService == NULL) {
+    return EFI_NOT_READY;
+  }
+
+  Status = RedfishHttpGetResource (Private->RedfishService, Uri, NULL, &Response, TRUE);
+  if (EFI_ERROR (Status)) {
+    DEBUG ((DEBUG_ERROR, "%a: get resource from: %s failed\n", __func__, Uri));
+    return Status;
+  }
+
+  //
+  // Check and see if "@Redfish.Settings" exist or not.
+  //
+  PendingSettingUri = NULL;
+  Status            = GetPendingSettings (
+                        Private->RedfishService,
+                        Response.Payload,
+                        &PendingSettingResponse,
+                        &PendingSettingUri
+                        );
+  if (!EFI_ERROR (Status)) {
+    DEBUG ((REDFISH_DEBUG_TRACE, "%a: @Redfish.Settings found: %s\n", __func__, PendingSettingUri));
+    Private->Uri     = PendingSettingUri;
+    ExpectedResponse = &PendingSettingResponse;
+  } else {
+    Private->Uri     = Uri;
+    ExpectedResponse = &Response;
+  }
+
+  Private->Payload = ExpectedResponse->Payload;
+  ASSERT (Private->Payload != NULL);
+
+  Private->Json = JsonDumpString (RedfishJsonInPayload (Private->Payload), EDKII_JSON_COMPACT);
+  ASSERT (Private->Json != NULL);
+
+  //
+  // Searching for etag in HTTP response header
+  //
+  Etag   = NULL;
+  Status = GetHttpResponseEtag (ExpectedResponse, &Etag);
+  if (EFI_ERROR (Status)) {
+    DEBUG ((DEBUG_ERROR, "%a: failed to get ETag from HTTP header\n", __func__));
+  }
+
+  Status = RedfishConsumeResourceCommon (Private, Private->Json, Etag);
+  if (EFI_ERROR (Status)) {
+    DEBUG ((DEBUG_ERROR, "%a: failed to consume resource from: %s: %r\n", __func__, Private->Uri, Status));
+  }
+
+  //
+  // Release resource
+  //
+  RedfishHttpFreeResponse (&Response);
+  RedfishHttpFreeResponse (&PendingSettingResponse);
+  Private->Payload = NULL;
+
+  if (Private->Json != NULL) {
+    FreePool (Private->Json);
+    Private->Json = NULL;
+  }
+
+  if (Etag != NULL) {
+    FreePool (Etag);
+  }
+
+  if (PendingSettingUri != NULL) {
+    FreePool (PendingSettingUri);
+  }
+
+  return Status;
+}
+
+/**
+  Get information about this protocol.
+
+  @param[in]   This                Pointer to EFI_HP_REDFISH_HII_PROTOCOL instance.
+  @param[out]  Schema              Supported schema.
+  @param[out]  Major               Supported major number.
+  @param[out]  Minor               Supported minor number.
+  @param[out]  Errata              Supported errata number.
+
+  @retval EFI_SUCCESS              Value is returned successfully.
+  @retval Others                   Some error happened.
+
+**/
+EFI_STATUS
+EFIAPI
+RedfishResourceGetInfo (
+  IN     EDKII_REDFISH_RESOURCE_CONFIG_PROTOCOL  *This,
+  OUT    REDFISH_SCHEMA_INFO                     *Info
+  )
+{
+  if ((This == NULL) || (Info == NULL)) {
+    return EFI_INVALID_PARAMETER;
+  }
+
+  AsciiStrCpyS (Info->Schema, REDFISH_SCHEMA_STRING_SIZE, RESOURCE_SCHEMA);
+  AsciiStrCpyS (Info->Major, REDFISH_SCHEMA_VERSION_SIZE, RESOURCE_SCHEMA_MAJOR);
+  AsciiStrCpyS (Info->Minor, REDFISH_SCHEMA_VERSION_SIZE, RESOURCE_SCHEMA_MINOR);
+  AsciiStrCpyS (Info->Errata, REDFISH_SCHEMA_VERSION_SIZE, RESOURCE_SCHEMA_ERRATA);
+
+  return EFI_SUCCESS;
+}
+
+/**
+  Update resource to given URI.
+
+  @param[in]   This                Pointer to EFI_HP_REDFISH_HII_PROTOCOL instance.
+  @param[in]   Uri                 The target URI to consume.
+
+  @retval EFI_SUCCESS              Value is returned successfully.
+  @retval Others                   Some error happened.
+
+**/
+EFI_STATUS
+EFIAPI
+RedfishResourceUpdate (
+  IN     EDKII_REDFISH_RESOURCE_CONFIG_PROTOCOL  *This,
+  IN     EFI_STRING                              Uri
+  )
+{
+  REDFISH_RESOURCE_COMMON_PRIVATE  *Private;
+  EFI_STATUS                       Status;
+  REDFISH_RESPONSE                 Response;
+
+  if ((This == NULL) || IS_EMPTY_STRING (Uri)) {
+    return EFI_INVALID_PARAMETER;
+  }
+
+  ZeroMem (&Response, sizeof (REDFISH_RESPONSE));
+  Private = REDFISH_RESOURCE_COMMON_PRIVATE_DATA_FROM_RESOURCE_PROTOCOL (This);
+
+  if (Private->RedfishService == NULL) {
+    return EFI_NOT_READY;
+  }
+
+  Status = RedfishHttpGetResource (Private->RedfishService, Uri, NULL, &Response, TRUE);
+  if (EFI_ERROR (Status)) {
+    DEBUG ((DEBUG_ERROR, "%a: get resource from: %s failed\n", __func__, Uri));
+    return Status;
+  }
+
+  Private->Uri     = Uri;
+  Private->Payload = Response.Payload;
+  ASSERT (Private->Payload != NULL);
+
+  Private->Json = JsonDumpString (RedfishJsonInPayload (Private->Payload), EDKII_JSON_COMPACT);
+  ASSERT (Private->Json != NULL);
+
+  Status = RedfishUpdateResourceCommon (Private, Private->Json);
+  if (EFI_ERROR (Status)) {
+    DEBUG ((DEBUG_ERROR, "%a: failed to update resource to: %s: %r\n", __func__, Uri, Status));
+  } else {
+    //
+    // Get latest ETag on URI and keep it in variable.
+    //
+    SetEtagFromUri (Private->RedfishService, Private->Uri, TRUE);
+  }
+
+  //
+  // Release resource
+  //
+  RedfishHttpFreeResponse (&Response);
+  Private->Payload = NULL;
+
+  if (Private->Json != NULL) {
+    FreePool (Private->Json);
+    Private->Json = NULL;
+  }
+
+  return Status;
+}
+
+/**
+  Check resource on given URI.
+
+  @param[in]   This                Pointer to EFI_HP_REDFISH_HII_PROTOCOL instance.
+  @param[in]   Uri                 The target URI to consume.
+
+  @retval EFI_SUCCESS              Value is returned successfully.
+  @retval Others                   Some error happened.
+
+**/
+EFI_STATUS
+EFIAPI
+RedfishResourceCheck (
+  IN     EDKII_REDFISH_RESOURCE_CONFIG_PROTOCOL  *This,
+  IN     EFI_STRING                              Uri
+  )
+{
+  REDFISH_RESOURCE_COMMON_PRIVATE  *Private;
+  EFI_STATUS                       Status;
+  REDFISH_RESPONSE                 Response;
+  CHAR8                            *Etag;
+
+  if ((This == NULL) || IS_EMPTY_STRING (Uri)) {
+    return EFI_INVALID_PARAMETER;
+  }
+
+  ZeroMem (&Response, sizeof (REDFISH_RESPONSE));
+  Private = REDFISH_RESOURCE_COMMON_PRIVATE_DATA_FROM_RESOURCE_PROTOCOL (This);
+
+  if (Private->RedfishService == NULL) {
+    return EFI_NOT_READY;
+  }
+
+  Status = RedfishHttpGetResource (Private->RedfishService, Uri, NULL, &Response, TRUE);
+  if (EFI_ERROR (Status)) {
+    DEBUG ((DEBUG_ERROR, "%a: get resource from: %s failed\n", __func__, Uri));
+    return Status;
+  }
+
+  Private->Uri     = Uri;
+  Private->Payload = Response.Payload;
+  ASSERT (Private->Payload != NULL);
+
+  Private->Json = JsonDumpString (RedfishJsonInPayload (Private->Payload), EDKII_JSON_COMPACT);
+  ASSERT (Private->Json != NULL);
+
+  //
+  // Find etag in HTTP response header
+  //
+  Etag   = NULL;
+  Status = GetHttpResponseEtag (&Response, &Etag);
+  if (EFI_ERROR (Status)) {
+    DEBUG ((DEBUG_ERROR, "%a: failed to get ETag from HTTP header\n", __func__));
+  }
+
+  Status = RedfishCheckResourceCommon (Private, Private->Json, Etag);
+  if (EFI_ERROR (Status)) {
+    DEBUG ((DEBUG_ERROR, "%a: failed to check resource from: %s: %r\n", __func__, Uri, Status));
+  }
+
+  //
+  // Release resource
+  //
+  if (Etag != NULL) {
+    FreePool (Etag);
+  }
+
+  RedfishHttpFreeResponse (&Response);
+  Private->Payload = NULL;
+
+  if (Private->Json != NULL) {
+    FreePool (Private->Json);
+    Private->Json = NULL;
+  }
+
+  return Status;
+}
+
+/**
+  Identify resource on given URI.
+
+  @param[in]   This                Pointer to EDKII_REDFISH_RESOURCE_CONFIG_PROTOCOL instance.
+  @param[in]   Uri                 The target URI to consume.
+
+  @retval EFI_SUCCESS              This is target resource which we want to handle.
+  @retval EFI_UNSUPPORTED          This is not the target resource.
+  @retval Others                   Some error happened.
+
+**/
+EFI_STATUS
+EFIAPI
+RedfishResourceIdentify (
+  IN     EDKII_REDFISH_RESOURCE_CONFIG_PROTOCOL  *This,
+  IN     EFI_STRING                              Uri
+  )
+{
+  REDFISH_RESOURCE_COMMON_PRIVATE  *Private;
+  EFI_STATUS                       Status;
+  REDFISH_RESPONSE                 Response;
+
+  if ((This == NULL) || IS_EMPTY_STRING (Uri)) {
+    return EFI_INVALID_PARAMETER;
+  }
+
+  ZeroMem (&Response, sizeof (REDFISH_RESPONSE));
+  Private = REDFISH_RESOURCE_COMMON_PRIVATE_DATA_FROM_RESOURCE_PROTOCOL (This);
+
+  if (Private->RedfishService == NULL) {
+    return EFI_NOT_READY;
+  }
+
+  Status = RedfishHttpGetResource (Private->RedfishService, Uri, NULL, &Response, TRUE);
+  if (EFI_ERROR (Status)) {
+    DEBUG ((DEBUG_ERROR, "%a: get resource from: %s failed\n", __func__, Uri));
+    return Status;
+  }
+
+  Private->Uri     = Uri;
+  Private->Payload = Response.Payload;
+  ASSERT (Private->Payload != NULL);
+
+  Private->Json = JsonDumpString (RedfishJsonInPayload (Private->Payload), EDKII_JSON_COMPACT);
+  ASSERT (Private->Json != NULL);
+
+  Status = RedfishIdentifyResourceCommon (Private, Private->Json);
+  if (EFI_ERROR (Status)) {
+    DEBUG ((DEBUG_ERROR, "%a: identify %s failed: %r\n", __func__, Uri, Status));
+  }
+
+  //
+  // Release resource
+  //
+  RedfishHttpFreeResponse (&Response);
+  Private->Payload = NULL;
+
+  if (Private->Json != NULL) {
+    FreePool (Private->Json);
+    Private->Json = NULL;
+  }
+
+  return Status;
+}
+
+EDKII_REDFISH_RESOURCE_CONFIG_PROTOCOL  mRedfishResourceConfig = {
+  RedfishResourceProvisioningResource,
+  RedfishResourceConsumeResource,
+  RedfishResourceUpdate,
+  RedfishResourceCheck,
+  RedfishResourceIdentify,
+  RedfishResourceGetInfo
+};
+
+/**
+  Initialize a Redfish configure handler.
+
+  This function will be called by the Redfish config driver to initialize each Redfish configure
+  handler.
+
+  @param[in]   This                     Pointer to EDKII_REDFISH_CONFIG_HANDLER_PROTOCOL instance.
+  @param[in]   RedfishConfigServiceInfo Redfish service information.
+
+  @retval EFI_SUCCESS                  The handler has been initialized successfully.
+  @retval EFI_DEVICE_ERROR             Failed to create or configure the REST EX protocol instance.
+  @retval EFI_ALREADY_STARTED          This handler has already been initialized.
+  @retval Other                        Error happens during the initialization.
+
+**/
+EFI_STATUS
+EFIAPI
+RedfishResourceInit (
+  IN  EDKII_REDFISH_CONFIG_HANDLER_PROTOCOL  *This,
+  IN  REDFISH_CONFIG_SERVICE_INFORMATION     *RedfishConfigServiceInfo
+  )
+{
+  REDFISH_RESOURCE_COMMON_PRIVATE  *Private;
+
+  Private = REDFISH_RESOURCE_COMMON_PRIVATE_DATA_FROM_CONFIG_PROTOCOL (This);
+
+  Private->RedfishService = RedfishCreateService (RedfishConfigServiceInfo);
+  if (Private->RedfishService == NULL) {
+    return EFI_DEVICE_ERROR;
+  }
+
+  return EFI_SUCCESS;
+}
+
+/**
+  Stop a Redfish configure handler.
+
+  @param[in]   This                Pointer to EDKII_REDFISH_CONFIG_HANDLER_PROTOCOL instance.
+
+  @retval EFI_SUCCESS              This handler has been stoped successfully.
+  @retval Others                   Some error happened.
+
+**/
+EFI_STATUS
+EFIAPI
+RedfishResourceStop (
+  IN  EDKII_REDFISH_CONFIG_HANDLER_PROTOCOL  *This
+  )
+{
+  REDFISH_RESOURCE_COMMON_PRIVATE  *Private;
+
+  Private = REDFISH_RESOURCE_COMMON_PRIVATE_DATA_FROM_CONFIG_PROTOCOL (This);
+
+  if (Private->Event != NULL) {
+    gBS->CloseEvent (Private->Event);
+    Private->Event = NULL;
+  }
+
+  if (Private->RedfishService != NULL) {
+    RedfishCleanupService (Private->RedfishService);
+    Private->RedfishService = NULL;
+  }
+
+  return EFI_SUCCESS;
+}
+
+EDKII_REDFISH_CONFIG_HANDLER_PROTOCOL  mRedfishConfigHandler = {
+  RedfishResourceInit,
+  RedfishResourceStop
+};
+
+/**
+  Callback function when gEfiRestJsonStructureProtocolGuid is installed.
+
+  @param[in] Event    Event whose notification function is being invoked.
+  @param[in] Context  Pointer to the notification function's context.
+**/
+VOID
+EFIAPI
+EfiRestJsonStructureProtocolIsReady (
+  IN  EFI_EVENT  Event,
+  IN  VOID       *Context
+  )
+{
+  EFI_STATUS  Status;
+
+  if (mRedfishResourcePrivate == NULL) {
+    return;
+  }
+
+  if (mRedfishResourcePrivate->JsonStructProtocol != NULL) {
+    return;
+  }
+
+  Status = gBS->LocateProtocol (
+                  &gEfiRestJsonStructureProtocolGuid,
+                  NULL,
+                  (VOID **)&mRedfishResourcePrivate->JsonStructProtocol
+                  );
+  if (EFI_ERROR (Status)) {
+    DEBUG ((DEBUG_ERROR, "%a: failed to locate gEfiRestJsonStructureProtocolGuid: %r\n", __func__, Status));
+  }
+
+  gBS->CloseEvent (Event);
+}
+
+/**
+  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
+RedfishResourceUnload (
+  IN EFI_HANDLE  ImageHandle
+  )
+{
+  EFI_STATUS                             Status;
+  EDKII_REDFISH_CONFIG_HANDLER_PROTOCOL  *ConfigHandler;
+
+  if (mRedfishResourcePrivate == NULL) {
+    return EFI_NOT_READY;
+  }
+
+  ConfigHandler = NULL;
+
+  //
+  // Firstly, find ConfigHandler Protocol interface in this ImageHandle.
+  //
+  Status = gBS->OpenProtocol (
+                  ImageHandle,
+                  &gEdkIIRedfishConfigHandlerProtocolGuid,
+                  (VOID **)&ConfigHandler,
+                  NULL,
+                  NULL,
+                  EFI_OPEN_PROTOCOL_BY_HANDLE_PROTOCOL
+                  );
+  if (EFI_ERROR (Status) || (ConfigHandler == NULL)) {
+    return Status;
+  }
+
+  ConfigHandler->Stop (ConfigHandler);
+
+  //
+  // Last, uninstall ConfigHandler Protocol and resource protocol.
+  //
+  Status = gBS->UninstallMultipleProtocolInterfaces (
+                  ImageHandle,
+                  &gEdkIIRedfishConfigHandlerProtocolGuid,
+                  ConfigHandler,
+                  &gEdkIIRedfishResourceConfigProtocolGuid,
+                  &mRedfishResourcePrivate->RedfishResourceConfig,
+                  NULL
+                  );
+
+  FreePool (mRedfishResourcePrivate);
+  mRedfishResourcePrivate = NULL;
+
+  return Status;
+}
+
+/**
+  The callback function provided by Redfish Feature driver.
+
+  @param[in]     This                Pointer to EDKII_REDFISH_FEATURE_PROTOCOL instance.
+  @param[in]     FeatureAction       The action Redfish feature driver should take.
+  @param[in]     Uri                 The collection URI.
+  @param[in]     Context             The context of Redfish feature driver.
+  @param[in,out] InformationExchange The pointer to RESOURCE_INFORMATION_EXCHANGE
+
+  @retval EFI_SUCCESS              Redfish feature driver callback is executed successfully.
+  @retval Others                   Some errors happened.
+
+  @retval EFI_SUCCESS              Redfish feature driver callback is executed successfully.
+  @retval Others                   Some errors happened.
+
+**/
+EFI_STATUS
+EFIAPI
+RedfishExternalResourceResourceFeatureCallback (
+  IN     EDKII_REDFISH_FEATURE_PROTOCOL  *This,
+  IN     FEATURE_CALLBACK_ACTION         FeatureAction,
+  IN     VOID                            *Context,
+  IN OUT RESOURCE_INFORMATION_EXCHANGE   *InformationExchange
+  )
+{
+  EFI_STATUS                       Status;
+  REDFISH_SERVICE                  RedfishService;
+  REDFISH_RESOURCE_COMMON_PRIVATE  *Private;
+  EFI_STRING                       ResourceUri;
+  EFI_STRING                       SecureBootUri;
+
+  if (FeatureAction != CallbackActionStartOperation) {
+    return EFI_UNSUPPORTED;
+  }
+
+  Private = (REDFISH_RESOURCE_COMMON_PRIVATE *)Context;
+
+  RedfishService = Private->RedfishService;
+  if (RedfishService == NULL) {
+    DEBUG ((DEBUG_ERROR, "%a: no Redfish service configured\n", __func__));
+    return EFI_NOT_READY;
+  }
+
+  //
+  // Save in private structure.
+  //
+  Private->InformationExchange = InformationExchange;
+
+  //
+  // Find Redfish version on Redfish ser
+  //
+  Private->RedfishVersion = RedfishGetVersion (RedfishService);
+
+  //
+  // Create the full URI from Redfish service root.
+  //
+  ResourceUri = (EFI_STRING)AllocateZeroPool (MAX_URI_LENGTH * sizeof (CHAR16));
+  if (ResourceUri == NULL) {
+    DEBUG ((DEBUG_ERROR, "%a: Fail to allocate memory for full URI.\n", __func__));
+    return EFI_OUT_OF_RESOURCES;
+  }
+
+  StrCatS (ResourceUri, MAX_URI_LENGTH, Private->RedfishVersion);
+  StrCatS (ResourceUri, MAX_URI_LENGTH, InformationExchange->SendInformation.FullUri);
+
+  //
+  // Initialize collection path
+  //
+  SecureBootUri = RedfishGetUri (ResourceUri);
+  if (SecureBootUri == NULL) {
+    ASSERT (FALSE);
+    FreePool (ResourceUri);
+    return EFI_OUT_OF_RESOURCES;
+  }
+
+  Status = HandleResource (Private, SecureBootUri);
+  if (EFI_ERROR (Status)) {
+    DEBUG ((DEBUG_ERROR, "%a: process external resource: %s failed: %r\n", __func__, SecureBootUri, Status));
+  }
+
+  FreePool (SecureBootUri);
+  FreePool (ResourceUri);
+  return Status;
+}
+
+/**
+  Callback function when gEdkIIRedfishFeatureProtocolGuid is installed.
+
+  @param[in] Event    Event whose notification function is being invoked.
+  @param[in] Context  Pointer to the notification function's context.
+**/
+VOID
+EFIAPI
+EdkIIRedfishFeatureProtocolIsReady (
+  IN  EFI_EVENT  Event,
+  IN  VOID       *Context
+  )
+{
+  EFI_STATUS                      Status;
+  EDKII_REDFISH_FEATURE_PROTOCOL  *FeatureProtocol;
+
+  if (mRedfishResourcePrivate == NULL) {
+    return;
+  }
+
+  if (mRedfishResourcePrivate->FeatureProtocol != NULL) {
+    return;
+  }
+
+  Status = gBS->LocateProtocol (
+                  &gEdkIIRedfishFeatureProtocolGuid,
+                  NULL,
+                  (VOID **)&FeatureProtocol
+                  );
+  if (EFI_ERROR (Status)) {
+    DEBUG ((DEBUG_ERROR, "%a: failed to locate gEdkIIRedfishFeatureProtocolGuid: %r\n", __func__, Status));
+    gBS->CloseEvent (Event);
+    return;
+  }
+
+  Status = FeatureProtocol->Register (
+                              FeatureProtocol,
+                              REDFISH_MANAGED_URI,
+                              RedfishExternalResourceResourceFeatureCallback,
+                              (VOID *)mRedfishResourcePrivate
+                              );
+  if (EFI_ERROR (Status)) {
+    DEBUG ((DEBUG_ERROR, "%a: failed to register %s: %r\n", __func__, REDFISH_MANAGED_URI, Status));
+  }
+
+  mRedfishResourcePrivate->FeatureProtocol = FeatureProtocol;
+
+  gBS->CloseEvent (Event);
+}
+
+/**
+  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. It initialize the global variables and
+  publish the driver binding protocol.
+
+  @param[in]   ImageHandle      The firmware allocated handle for the UEFI image.
+  @param[in]   SystemTable      A pointer to the EFI System Table.
+
+  @retval EFI_SUCCESS           The operation completed successfully.
+  @retval EFI_ACCESS_DENIED     EFI_ISCSI_INITIATOR_NAME_PROTOCOL was installed unexpectedly.
+  @retval Others                Other errors as indicated.
+**/
+EFI_STATUS
+EFIAPI
+RedfishResourceEntryPoint (
+  IN EFI_HANDLE        ImageHandle,
+  IN EFI_SYSTEM_TABLE  *SystemTable
+  )
+{
+  EFI_STATUS  Status;
+  VOID        *Registration;
+
+  if (mRedfishResourcePrivate != NULL) {
+    return EFI_ALREADY_STARTED;
+  }
+
+  mRedfishResourceConfigProtocolHandle = ImageHandle;
+
+  mRedfishResourcePrivate = AllocateZeroPool (sizeof (REDFISH_RESOURCE_COMMON_PRIVATE));
+  CopyMem (&mRedfishResourcePrivate->ConfigHandler, &mRedfishConfigHandler, sizeof (EDKII_REDFISH_CONFIG_HANDLER_PROTOCOL));
+  CopyMem (&mRedfishResourcePrivate->RedfishResourceConfig, &mRedfishResourceConfig, sizeof (EDKII_REDFISH_RESOURCE_CONFIG_PROTOCOL));
+
+  //
+  // Publish config handler protocol and resource protocol.
+  //
+  Status = gBS->InstallMultipleProtocolInterfaces (
+                  &ImageHandle,
+                  &gEdkIIRedfishConfigHandlerProtocolGuid,
+                  &mRedfishResourcePrivate->ConfigHandler,
+                  &gEdkIIRedfishResourceConfigProtocolGuid,
+                  &mRedfishResourcePrivate->RedfishResourceConfig,
+                  NULL
+                  );
+
+  EfiCreateProtocolNotifyEvent (
+    &gEfiRestJsonStructureProtocolGuid,
+    TPL_CALLBACK,
+    EfiRestJsonStructureProtocolIsReady,
+    NULL,
+    &Registration
+    );
+
+  EfiCreateProtocolNotifyEvent (
+    &gEdkIIRedfishFeatureProtocolGuid,
+    TPL_CALLBACK,
+    EdkIIRedfishFeatureProtocolIsReady,
+    (VOID *)mRedfishResourcePrivate,
+    &Registration
+    );
+
+  return Status;
+}
diff --git a/RedfishClientPkg/RedfishClient.fdf.inc b/RedfishClientPkg/RedfishClient.fdf.inc
index 59b8acba1..154f641b2 100644
--- a/RedfishClientPkg/RedfishClient.fdf.inc
+++ b/RedfishClientPkg/RedfishClient.fdf.inc
@@ -25,6 +25,7 @@
  INF RedfishClientPkg/HiiToRedfishBiosDxe/HiiToRedfishBiosDxe.inf
  INF RedfishClientPkg/Features/BootOptionCollection/BootOptionCollectionDxe.inf
  INF RedfishClientPkg/Features/BootOption/v1_0_4/Dxe/BootOptionDxe.inf
+  INF RedfishClientPkg/Features/SecureBoot/v1_1_0/Dxe/SecureBootDxe.inf

  !include RedfishClientPkg/RedfishJsonStructureDxe.fdf.inc
  #
--
2.34.1



Regards,
Mike


Regards,
Mike.



-=-=-=-=-=-=-=-=-=-=-=-
Groups.io Links: You receive all messages sent to this group.
View/Reply Online (#117294): https://edk2.groups.io/g/devel/message/117294
Mute This Topic: https://groups.io/mt/104927848/7686176
Group Owner: devel+owner@edk2.groups.io
Unsubscribe: https://edk2.groups.io/g/devel/unsub [rebecca@openfw.io]
-=-=-=-=-=-=-=-=-=-=-=-



[-- Attachment #2: Type: text/html, Size: 124913 bytes --]

^ permalink raw reply related	[flat|nested] 5+ messages in thread

end of thread, other threads:[~2024-04-01 14:25 UTC | newest]

Thread overview: 5+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2024-03-14 14:53 [edk2-devel] [edk2-redfish-client][PATCH 1/2] RedfishClientPkg/Features: support Redfish Secure Boot Nickle Wang via groups.io
2024-03-14 19:38 ` Mike Maslenkin
2024-03-26 13:57   ` Nickle Wang via groups.io
2024-03-26 22:56     ` Mike Maslenkin
2024-04-01 14:25       ` Nickle Wang via groups.io

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox