From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: from mail02.groups.io (mail02.groups.io [66.175.222.108]) by spool.mail.gandi.net (Postfix) with ESMTPS id BD4EC7803E8 for ; Thu, 14 Mar 2024 14:53:33 +0000 (UTC) DKIM-Signature: a=rsa-sha256; bh=SKkDedS6D5c9BTXe1Z9Vdxngpvf9ZAbcma4/7pG8/dM=; c=relaxed/simple; d=groups.io; h=Received-SPF:From:To:CC:Subject:Date:Message-ID:MIME-Version:Precedence:List-Subscribe:List-Help:Sender:List-Id:Mailing-List:Delivered-To:Resent-Date:Reply-To:List-Unsubscribe-Post:List-Unsubscribe:Content-Transfer-Encoding:Content-Type; s=20240206; t=1710428012; v=1; b=2hx7zrXpHGeHcxki2v0UzkCePCFIutzpmJ4NUI5MAXG3ZFC5Js8sLSj37u74GDCbtOlCYdyX 9K3wfhO2Ey5p55eUUEX/p0Z+j79XqlENNHbL5eedRSmmnKjm5SvKHxUq9/NnZqhkTFDhqhJbZxt gfAsV6xD2uptFfB3TtQijxC6oGh9wXeAu9jgEFyZSDMsBCJOGHXf8Wj+BdxbBJi9+DgA9fEXO09 orPIc71vX+H8idem4xdLh7GxKcpW8f59r/d0SRg++MqML3D5NUlBE6neX9B5jaW3T1QvMRyPyCQ UsOdEBNI1NXka7Y9Rupepgh/NIglfq8TdtCa/tiWA14Vg== X-Received: by 127.0.0.2 with SMTP id xLdjYY7687511xB64avZN9Uz; Thu, 14 Mar 2024 07:53:32 -0700 X-Received: from NAM10-MW2-obe.outbound.protection.outlook.com (NAM10-MW2-obe.outbound.protection.outlook.com [40.107.94.85]) by mx.groups.io with SMTP id smtpd.web11.14555.1710428011626161655 for ; Thu, 14 Mar 2024 07:53:31 -0700 X-Received: from BYAPR01CA0038.prod.exchangelabs.com (2603:10b6:a03:94::15) by IA0PR12MB9046.namprd12.prod.outlook.com (2603:10b6:208:405::17) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.20.7362.36; Thu, 14 Mar 2024 14:53:17 +0000 X-Received: from SJ5PEPF000001D6.namprd05.prod.outlook.com (2603:10b6:a03:94:cafe::38) by BYAPR01CA0038.outlook.office365.com (2603:10b6:a03:94::15) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.20.7386.21 via Frontend Transport; Thu, 14 Mar 2024 14:53:16 +0000 X-MS-Exchange-Authentication-Results: spf=pass (sender IP is 216.228.117.161) smtp.mailfrom=nvidia.com; dkim=none (message not signed) header.d=none;dmarc=pass action=none header.from=nvidia.com; Received-SPF: Pass (protection.outlook.com: domain of nvidia.com designates 216.228.117.161 as permitted sender) receiver=protection.outlook.com; client-ip=216.228.117.161; helo=mail.nvidia.com; pr=C X-Received: from mail.nvidia.com (216.228.117.161) by SJ5PEPF000001D6.mail.protection.outlook.com (10.167.242.58) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.20.7386.12 via Frontend Transport; Thu, 14 Mar 2024 14:53:16 +0000 X-Received: from rnnvmail203.nvidia.com (10.129.68.9) by mail.nvidia.com (10.129.200.67) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.2.986.41; Thu, 14 Mar 2024 07:53:03 -0700 X-Received: from rnnvmail202.nvidia.com (10.129.68.7) by rnnvmail203.nvidia.com (10.129.68.9) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.2.1258.12; Thu, 14 Mar 2024 07:53:02 -0700 X-Received: from NV-CL38DL3.nvidia.com (10.127.8.12) by mail.nvidia.com (10.129.68.7) with Microsoft SMTP Server id 15.2.1258.12 via Frontend Transport; Thu, 14 Mar 2024 07:53:01 -0700 From: "Nickle Wang via groups.io" To: CC: Abner Chang , Igor Kulchytskyy , "Nick Ramirez" Subject: [edk2-devel] [edk2-redfish-client][PATCH 1/2] RedfishClientPkg/Features: support Redfish Secure Boot Date: Thu, 14 Mar 2024 22:53:00 +0800 Message-ID: <20240314145300.153086-1-nicklew@nvidia.com> MIME-Version: 1.0 X-NVConfidentiality: public X-NV-OnPremToCloud: ExternallySecured X-EOPAttributedMessage: 0 X-MS-PublicTrafficType: Email X-MS-TrafficTypeDiagnostic: SJ5PEPF000001D6:EE_|IA0PR12MB9046:EE_ X-MS-Office365-Filtering-Correlation-Id: e13a9a00-7b73-49a2-e3b9-08dc44367b0f X-MS-Exchange-SenderADCheck: 1 X-MS-Exchange-AntiSpam-Relay: 0 X-Microsoft-Antispam-Message-Info: eiWgRoqtk8DddQQ0BOmPO56FLkiIbt8mtnSr7hPeHON0gT0KuKFU6UztUXg/bfbfvPPlZHEhkesH5E46aweHp7N6zu2GRInGPUCzu0EDA2k+dhs/P9rZBf/PVg9X7kYZB5+C6gDN37LgIzdfdPEfSn2AY/IB6gxTJjQEJEQ31SwtcQAseGlsWGtY4ELCRV3PKNeXo2P3zfqMu3/eYZg8KcuORxxVIsTq5KVD3wCMgbhhIqo9nHXWOqIshjrZqu+YxJnhDrE2HoiWSuEdYjrZi8FM/Uam5yHuag/NM7MuaBazGN4Ywm9LeUemHzkeH8sMB1iQ33UE5ANcWGeoAp1wlv5YCyIBUhr6x+YtETkI1zkvknxAdLGnv4VV+I9U3vBIyjL/uepIs9RwHRvH0B1gMVFZOGOjmLyRAarEww7ZjEHrEkqfPYNaWpoH6iMgZa150Oc1xx0YIkrtfJoM3SZegjjWf/pMmLd36jRVl0mjqmo8Tc47LyBiR1Z63PWmNF4czedOm1xNjzcS57AmppS4M3y31O2LlxpKNzYpcdPB/ZlaXSiTuDyzcHXB8iV+ftykzO4xPFFbPnXRBI9rMnyZ4pjyhLng9eR91Mgj3SAZE3w4FYvPJNECiNwalG2lnYozj+271kEg3nK0TC+Z3cOBL8fWs2wSyCahHnwi6i2T1SMyb3nJoh/6lQ1AtLcAPgyGvK3KQQ/N3yXkQjvHu8vfvsowqCV2fL+EbldUw2d+mRKETSMyjfRVI7Pfv9722/ez X-OriginatorOrg: Nvidia.com X-MS-Exchange-CrossTenant-OriginalArrivalTime: 14 Mar 2024 14:53:16.3173 (UTC) X-MS-Exchange-CrossTenant-Network-Message-Id: e13a9a00-7b73-49a2-e3b9-08dc44367b0f X-MS-Exchange-CrossTenant-Id: 43083d15-7273-40c1-b7db-39efd9ccc17a X-MS-Exchange-CrossTenant-OriginalAttributedTenantConnectingIp: TenantId=43083d15-7273-40c1-b7db-39efd9ccc17a;Ip=[216.228.117.161];Helo=[mail.nvidia.com] X-MS-Exchange-CrossTenant-AuthSource: SJ5PEPF000001D6.namprd05.prod.outlook.com X-MS-Exchange-CrossTenant-AuthAs: Anonymous X-MS-Exchange-CrossTenant-FromEntityHeader: HybridOnPrem X-MS-Exchange-Transport-CrossTenantHeadersStamped: IA0PR12MB9046 Precedence: Bulk List-Subscribe: List-Help: Sender: devel@edk2.groups.io List-Id: Mailing-List: list devel@edk2.groups.io; contact devel+owner@edk2.groups.io Resent-Date: Thu, 14 Mar 2024 07:53:31 -0700 Reply-To: devel@edk2.groups.io,nicklew@nvidia.com List-Unsubscribe-Post: List-Unsubscribe=One-Click List-Unsubscribe: X-Gm-Message-State: lnU4JSKx2oAuO0t3pPdwLusmx7686176AA= Content-Transfer-Encoding: quoted-printable Content-Type: text/plain X-GND-Status: LEGIT Authentication-Results: spool.mail.gandi.net; dkim=pass header.d=groups.io header.s=20240206 header.b=2hx7zrXp; dmarc=pass (policy=none) header.from=groups.io; spf=pass (spool.mail.gandi.net: domain of bounce@groups.io designates 66.175.222.108 as permitted sender) smtp.mailfrom=bounce@groups.io Introduce SecureBoot driver to support /redfish/v1/Systems/SYS/SecureBoot resource. Signed-off-by: Nickle Wang Cc: Abner Chang Cc: Igor Kulchytskyy Cc: Nick Ramirez --- .../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/SecureB= ootDxe.inf create mode 100644 RedfishClientPkg/Features/SecureBoot/v1_1_0/Common/Secu= reBootCommon.h create mode 100644 RedfishClientPkg/Features/SecureBoot/v1_1_0/Common/Secu= reBootCommon.c create mode 100644 RedfishClientPkg/Features/SecureBoot/v1_1_0/Dxe/SecureB= ootDxe.c diff --git a/RedfishClientPkg/RedfishClientComponents.dsc.inc b/RedfishClie= ntPkg/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.i= nf RedfishClientPkg/Features/BootOption/v1_0_4/Dxe/BootOptionDxe.inf + RedfishClientPkg/Features/SecureBoot/v1_1_0/Dxe/SecureBootDxe.inf =20 !include RedfishClientPkg/RedfishJsonStructureDxe.dsc.inc =20 @@ -47,3 +48,4 @@ RedfishClientPkg/Converter/Bios/v1_0_9/RedfishBios_V1_0_9_Dxe.inf RedfishClientPkg/Converter/BootOptionCollection/RedfishBootOptionCollect= ion_Dxe.inf RedfishClientPkg/Converter/BootOption/v1_0_4/RedfishBootOption_V1_0_4_Dx= e.inf + RedfishClientPkg/Converter/SecureBoot/v1_1_0/RedfishSecureBoot_V1_1_0_Dx= e.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/BootOp= tionCollection/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/RedfishAd= dendumLib.inf RedfishDebugLib|RedfishPkg/Library/RedfishDebugLib/RedfishDebugLib.inf RedfishHttpLib|RedfishPkg/Library/RedfishHttpLib/RedfishHttpLib.inf + SecureBootVariableLib|SecurityPkg/Library/SecureBootVariableLib/SecureBo= otVariableLib.inf + PlatformPKProtectionLib|SecurityPkg/Library/PlatformPKProtectionLibVarPo= licy/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
+# Copyright (c) 2022-2024, NVIDIA CORPORATION & AFFILIATES. All rights re= served. +# +# SPDX-License-Identifier: BSD-2-Clause-Patent +# +## + + +[Defines] + INF_VERSION =3D 0x00010005 + BASE_NAME =3D SecureBootDxe + FILE_GUID =3D 5E4025F8-DA42-468A-853E-6A1091D35052 + MODULE_TYPE =3D DXE_DRIVER + VERSION_STRING =3D 1.0 + ENTRY_POINT =3D RedfishResourceEntryPoint + UNLOAD_IMAGE =3D 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/SecureBootC= ommon.h b/RedfishClientPkg/Features/SecureBoot/v1_1_0/Common/SecureBootComm= on.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
+ Copyright (c) 2022-2024, NVIDIA CORPORATION & AFFILIATES. All rights res= erved. + + SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#ifndef EFI_REDFISH_SECUREBOOT_COMMON_H_ +#define EFI_REDFISH_SECUREBOOT_COMMON_H_ + +#include +#include +#include +#include +#include +#include +#include +#include + +// +// 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/SecureBootC= ommon.c b/RedfishClientPkg/Features/SecureBoot/v1_1_0/Common/SecureBootComm= on.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
+ Copyright (c) 2023-2024, NVIDIA CORPORATION & AFFILIATES. All rights res= erved. + + SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#include "SecureBootCommon.h" + +CHAR8 SecureBootEmptyJson[] =3D "{\"@odata.id\": \"\", \"@odata.type\": \= "#SecureBoot.v1_1_0.SecureBoot\", \"Id\": \"\", \"Name\": \"\", \"Attribute= s\":{}}"; + +REDFISH_RESOURCE_COMMON_PRIVATE *mRedfishResourcePrivate = =3D NULL; +EFI_HANDLE mRedfishResourceConfigProtocolHandle = =3D NULL; +CHAR16 *mSecureBootSupportedAttributes[SECURE_BO= OT_MODE_STR_LEN] =3D { + 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 SECUR= E_BOOT_DISABLE +**/ +BOOLEAN +RedfishReadSecureBootEnable ( + VOID + ) +{ + UINT8 *Buffer; + BOOLEAN SecureBootEnableValue; + + Buffer =3D NULL; + SecureBootEnableValue =3D FALSE; + + GetVariable2 ( + EFI_SECURE_BOOT_ENABLE_NAME, + &gEfiSecureBootEnableDisableGuid, + (VOID **)&Buffer, + NULL + ); + + if (Buffer !=3D NULL) { + if (*Buffer =3D=3D SECURE_BOOT_ENABLE) { + SecureBootEnableValue =3D TRUE; + } + + FreePool (Buffer); + } + + return SecureBootEnableValue; +} + +/** + Write EFI_SECURE_BOOT_ENABLE_NAME variable with given value. + + @param[in] SecureBootEnableValue Value to write. TRUE is SECURE_BOO= T_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 =3D (SecureBootEnableValue ? SECURE_BOOT_ENABLE : SECURE_BOOT_D= ISABLE); + Status =3D gRT->SetVariable ( + EFI_SECURE_BOOT_ENABLE_NAME, + &gEfiSecureBootEnableDisableGuid, + EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_A= CCESS, + sizeof (VarValue), + &VarValue + ); + + return Status; +} + +/** + Consume Redfish resource in given Json data. + + @param[in] This Pointer to REDFISH_RESOURCE_COMMON_PRIV= ATE 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 =3D=3D NULL) || IS_EMPTY_STRING (Json)) { + return EFI_INVALID_PARAMETER; + } + + SecureBoot =3D NULL; + SecureBootCs =3D NULL; + SecureBootEnableDisable =3D RedfishReadSecureBootEnable (); + + Status =3D 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__, Statu= s)); + return Status; + } + + SecureBootCs =3D 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 consu= me action\n", __func__, Private->Uri)); + Status =3D EFI_ALREADY_STARTED; + goto ON_RELEASE; + } + + // + // Secure boot enable + // + if (SecureBootCs->SecureBootEnable !=3D NULL) { + if (SecureBootEnableDisable !=3D *SecureBootCs->SecureBootEnable) { + // + // Write value to "SecureBootEnable" variable. AuthVariableLib will = enable or disable secure boot + // based on "SecureBootEnable" value. + // + Status =3D RedfishWriteSecureBootEnable (*SecureBootCs->SecureBootEn= able); + 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 *)SecureB= oot + ); + + 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 res= ource. + @param[in] ProvisionMode TRUE when this is to provision Redfish = attribute to + Redfish service. FALSE is to update Red= fish attribute + to Redfish service. + @param[out] ResultJson Json data on output. + + @retval EFI_SUCCESS Provision Redfish attribute successfull= y. + @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 =3D=3D NULL) || (ResultJson =3D=3D NULL) || IS_E= MPTY_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 =3D NULL; + PropertyChanged =3D FALSE; + AsciiStringValue =3D NULL; + SecureBootEnableDisable =3D RedfishReadSecureBootEnable (); + SecureBootEnabled =3D IsSecureBootEnabled (); + + SecureBoot =3D NULL; + Status =3D JsonStructProtocol->ToStructure ( + JsonStructProtocol, + NULL, + InputJson, + (EFI_REST_JSON_STRUCTURE_HEADER **)&S= ecureBoot + ); + if (EFI_ERROR (Status)) { + DEBUG ((DEBUG_ERROR, "%a: ToStructure failure: %r\n", __func__, Status= )); + return Status; + } + + SecureBootCs =3D SecureBoot->SecureBoot; + + // + // ID + // + if (SecureBootCs->Id !=3D NULL) { + SecureBootCs->Id =3D NULL; + } + + // + // Name + // + if (SecureBootCs->Name !=3D NULL) { + SecureBootCs->Name =3D 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 =3D AllocateZeroPool (SECURE_BOOT_MODE_STR_LEN * size= of (CHAR8)); + if (AsciiStringValue !=3D NULL) { + AsciiSPrint (AsciiStringValue, SECURE_BOOT_MODE_STR_LEN, "%a", (Secu= reBootEnabled ? SECURE_BOOT_ENABLED : SECURE_BOOT_DISABLED)); + if (ProvisionMode || (AsciiStrCmp (SecureBootCs->SecureBootCurrentBo= ot, AsciiStringValue) !=3D 0)) { + SecureBootCs->SecureBootCurrentBoot =3D AsciiStringValue; + PropertyChanged =3D TRUE; + } + } else { + DEBUG ((DEBUG_ERROR, "%a: out of resource\n", __func__)); + } + } + + // + // Secure boot enable + // + if (PropertyChecker (SecureBootCs->SecureBootEnable, ProvisionMode)) { + if (ProvisionMode || (*SecureBootCs->SecureBootEnable !=3D SecureBootE= nableDisable)) { + IntegerValue =3D AllocatePool (sizeof (*IntegerValue)); + if (IntegerValue !=3D NULL) { + *IntegerValue =3D (SecureBootEnableDisable ? 0x01= : 0x00); + SecureBootCs->SecureBootEnable =3D IntegerValue; + PropertyChanged =3D TRUE; + } else { + DEBUG ((DEBUG_ERROR, "%a: out of resource\n", __func__)); + } + } + } + + // + // Secure boot mode + // + if (PropertyChecker (SecureBootCs->SecureBootMode, ProvisionMode)) { + Status =3D GetSetupMode (&SetupMode); + if (!EFI_ERROR (Status)) { + AsciiStringValue =3D AllocateZeroPool (SECURE_BOOT_MODE_STR_LEN *siz= eof (CHAR8)); + if (AsciiStringValue !=3D NULL) { + AsciiSPrint (AsciiStringValue, SECURE_BOOT_MODE_STR_LEN *sizeof (C= HAR8), "%a", (SetupMode =3D=3D USER_MODE ? SECURE_BOOT_USER_MODE : SECURE_B= OOT_SETUP_MODE)); + if (ProvisionMode || (AsciiStrCmp (SecureBootCs->SecureBootMode, A= sciiStringValue) !=3D 0)) { + SecureBootCs->SecureBootMode =3D AsciiStringValue; + PropertyChanged =3D TRUE; + } + } + } else { + DEBUG ((DEBUG_ERROR, "%a: cannot read setup mode: %r\n", __func__, S= tatus)); + } + } + + // + // Convert C structure back to JSON text. + // + Status =3D JsonStructProtocol->ToJson ( + JsonStructProtocol, + (EFI_REST_JSON_STRUCTURE_HEADER *)SecureB= oot, + 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 func= tion + checks OEM data and platform addendum data before sending data to Redfis= h 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 =3D=3D NULL) { + return EFI_INVALID_PARAMETER; + } + + ZeroMem (&Response, sizeof (REDFISH_RESPONSE)); + Json =3D NULL; + + Status =3D ProvisioningSecureBootProperties ( + Private->JsonStructProtocol, + SecureBootEmptyJson, + NULL, + REDFISH_DUMMY_CONFIG_LANG, + TRUE, + &Json + ); + if (EFI_ERROR (Status)) { + if (Status =3D=3D EFI_NOT_FOUND) { + DEBUG ((REDFISH_DEBUG_TRACE, "%a: provisioning existing resource for= %s ignored. Nothing changed\n", __func__, REDFISH_DUMMY_CONFIG_LANG)); + Status =3D EFI_SUCCESS; + } else { + DEBUG ((DEBUG_ERROR, "%a: provisioning existing resource for %s fail= ed: %r\n", __func__, REDFISH_DUMMY_CONFIG_LANG, Status)); + } + + goto ON_RELEASE; + } + + // + // Check and see if platform has OEM data or not + // + Status =3D RedfishGetOemData ( + Private->Uri, + RESOURCE_SCHEMA, + RESOURCE_SCHEMA_VERSION, + Json, + &JsonWithAddendum + ); + if (!EFI_ERROR (Status) && (JsonWithAddendum !=3D NULL)) { + FreePool (Json); + Json =3D JsonWithAddendum; + JsonWithAddendum =3D NULL; + } + + // + // Check and see if platform has addendum data or not + // + Status =3D RedfishGetAddendumData ( + Private->Uri, + RESOURCE_SCHEMA, + RESOURCE_SCHEMA_VERSION, + Json, + &JsonWithAddendum + ); + if (!EFI_ERROR (Status) && (JsonWithAddendum !=3D NULL)) { + FreePool (Json); + Json =3D JsonWithAddendum; + JsonWithAddendum =3D NULL; + } + + DEBUG ((REDFISH_DEBUG_TRACE, "%a: provisioning existing resource for %s\= n", __func__, REDFISH_DUMMY_CONFIG_LANG)); + + // + // PATCH back to instance + // + Status =3D RedfishHttpPatchResource (Private->RedfishService, Private->U= ri, 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 !=3D 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 wil= l be used. + FALSE if resource does not exist POST m= ethod 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 =3D=3D NULL) { + return EFI_INVALID_PARAMETER; + } + + return ProvisioningSecureBootResource (Private); +} + +/** + Check resource from given Json data. + + @param[in] This Pointer to REDFISH_RESOURCE_COMMON_PRIV= ATE 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 =3D=3D 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 =3D sizeof (mSecureBootSupportedAttributes) / sizeof (mSecureBootS= upportedAttributes[0]); + if (Count =3D=3D 0) { + return EFI_UNSUPPORTED; + } + + Status =3D EFI_SUCCESS; + for (Index =3D 0; Index < Count; Index++) { + Property =3D mSecureBootSupportedAttributes[Index]; + if (Property =3D=3D NULL) { + continue; + } + + DEBUG ((REDFISH_DEBUG_TRACE, "%a: [%d] check attribute for: %s\n", __f= unc__, Index, Property)); + if (!MatchPropertyWithJsonContext (Property, Json)) { + DEBUG ((REDFISH_DEBUG_TRACE, "%a: property is missing: %s\n", __func= __, Property)); + Status =3D EFI_NOT_FOUND; + } + } + + return Status; +} + +/** + Update resource to Redfish service. + + @param[in] Private Pointer to REDFISH_RESOURCE_COMMON_PRIV= ATE 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 =3D=3D NULL) || IS_EMPTY_STRING (InputJson)) { + return EFI_INVALID_PARAMETER; + } + + ZeroMem (&Response, sizeof (REDFISH_RESPONSE)); + Json =3D NULL; + + Status =3D ProvisioningSecureBootProperties ( + Private->JsonStructProtocol, + SecureBootEmptyJson, + NULL, + REDFISH_DUMMY_CONFIG_LANG, + TRUE, + &Json + ); + if (EFI_ERROR (Status)) { + if (Status =3D=3D EFI_NOT_FOUND) { + DEBUG ((REDFISH_DEBUG_TRACE, "%a: update resource for %s ignored. No= thing changed\n", __func__, REDFISH_DUMMY_CONFIG_LANG)); + Status =3D EFI_SUCCESS; + } else { + DEBUG ((DEBUG_ERROR, "%a: update resource for %s failed: %r\n", __fu= nc__, REDFISH_DUMMY_CONFIG_LANG, Status)); + } + + goto ON_RELEASE; + } + + // + // Check and see if platform has OEM data or not + // + Status =3D RedfishGetOemData ( + Private->Uri, + RESOURCE_SCHEMA, + RESOURCE_SCHEMA_VERSION, + Json, + &JsonWithAddendum + ); + if (!EFI_ERROR (Status) && (JsonWithAddendum !=3D NULL)) { + FreePool (Json); + Json =3D JsonWithAddendum; + JsonWithAddendum =3D NULL; + } + + // + // Check and see if platform has addendum data or not + // + Status =3D RedfishGetAddendumData ( + Private->Uri, + RESOURCE_SCHEMA, + RESOURCE_SCHEMA_VERSION, + Json, + &JsonWithAddendum + ); + if (!EFI_ERROR (Status) && (JsonWithAddendum !=3D NULL)) { + FreePool (Json); + Json =3D JsonWithAddendum; + JsonWithAddendum =3D NULL; + } + + DEBUG ((REDFISH_DEBUG_TRACE, "%a: update resource for %s\n", __func__, R= EDFISH_DUMMY_CONFIG_LANG)); + + // + // PATCH back to instance + // + Status =3D RedfishHttpPatchResource (Private->RedfishService, Private->U= ri, 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 !=3D NULL) { + FreePool (Json); + } + + RedfishHttpFreeResponse (&Response); + + return Status; +} + +/** + Identify resource in given Json data. + + @param[in] Private Pointer to REDFISH_RESOURCE_COMMON_PRIV= ATE 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 =3D 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_PRIV= ATE 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 =3D=3D NULL) || IS_EMPTY_STRING (Uri)) { + return EFI_INVALID_PARAMETER; + } + + // + // Resource match + // + + DEBUG ((REDFISH_DEBUG_TRACE, "%a: process resource for: %s\n", __func__,= Uri)); + + Status =3D GetRedfishSchemaInfo (Private->RedfishService, Private->JsonS= tructProtocol, 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 th= is first. + // + DEBUG ((REDFISH_DEBUG_TRACE, "%a: Identify for %s\n", __func__, Uri)); + ConfigLang =3D RedfishGetConfigLanguage (Uri); + if (ConfigLang =3D=3D NULL) { + Status =3D EdkIIRedfishResourceConfigIdentify (&SchemaInfo, Uri, NULL,= Private->InformationExchange); + if (EFI_ERROR (Status)) { + if (Status =3D=3D EFI_UNSUPPORTED) { + DEBUG ((REDFISH_DEBUG_TRACE, "%a: \"%s\" is not handled by us\n", = __func__, Uri)); + return EFI_SUCCESS; + } else if (Status =3D=3D 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 me= mber exists. + // If not, we sill do provision. + // + DEBUG ((REDFISH_DEBUG_TRACE, "%a Check for %s\n", __func__, Uri)); + Status =3D EdkIIRedfishResourceConfigCheck (&SchemaInfo, Uri, NULL); + if (EFI_ERROR (Status)) { + if (Status =3D=3D 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 prop= erty. + // + DEBUG ((REDFISH_DEBUG_TRACE, "%a provision for %s\n", __func__, Uri)); + Status =3D EdkIIRedfishResourceConfigProvisioning (&SchemaInfo, Uri, N= ULL, 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 =3D 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 =3D 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
+ 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 mRedfishResourceConfigProtocolHand= le; + +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, po= st method is used. + FALSE if the resource exist but propert= y 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 =3D=3D 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 =3D REDFISH_RESOURCE_COMMON_PRIVATE_DATA_FROM_RESOURCE_PROTOCOL = (This); + + if (Private->RedfishService =3D=3D NULL) { + return EFI_NOT_READY; + } + + Status =3D RedfishHttpGetResource (Private->RedfishService, Uri, NULL, &= Response, TRUE); + if (EFI_ERROR (Status)) { + DEBUG ((DEBUG_ERROR, "%a: get resource from: %s failed\n", __func__, U= ri)); + return Status; + } + + Private->Uri =3D Uri; + Private->Payload =3D Response.Payload; + ASSERT (Private->Payload !=3D NULL); + + Status =3D 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 =3D 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 =3D=3D NULL) || IS_EMPTY_STRING (Uri)) { + return EFI_INVALID_PARAMETER; + } + + ZeroMem (&Response, sizeof (REDFISH_RESPONSE)); + ZeroMem (&PendingSettingResponse, sizeof (REDFISH_RESPONSE)); + Private =3D REDFISH_RESOURCE_COMMON_PRIVATE_DATA_FROM_RESOURCE_PROTOCOL = (This); + + if (Private->RedfishService =3D=3D NULL) { + return EFI_NOT_READY; + } + + Status =3D RedfishHttpGetResource (Private->RedfishService, Uri, NULL, &= Response, TRUE); + if (EFI_ERROR (Status)) { + DEBUG ((DEBUG_ERROR, "%a: get resource from: %s failed\n", __func__, U= ri)); + return Status; + } + + // + // Check and see if "@Redfish.Settings" exist or not. + // + PendingSettingUri =3D NULL; + Status =3D GetPendingSettings ( + Private->RedfishService, + Response.Payload, + &PendingSettingResponse, + &PendingSettingUri + ); + if (!EFI_ERROR (Status)) { + DEBUG ((REDFISH_DEBUG_TRACE, "%a: @Redfish.Settings found: %s\n", __fu= nc__, PendingSettingUri)); + Private->Uri =3D PendingSettingUri; + ExpectedResponse =3D &PendingSettingResponse; + } else { + Private->Uri =3D Uri; + ExpectedResponse =3D &Response; + } + + Private->Payload =3D ExpectedResponse->Payload; + ASSERT (Private->Payload !=3D NULL); + + Private->Json =3D JsonDumpString (RedfishJsonInPayload (Private->Payload= ), EDKII_JSON_COMPACT); + ASSERT (Private->Json !=3D NULL); + + // + // Searching for etag in HTTP response header + // + Etag =3D NULL; + Status =3D GetHttpResponseEtag (ExpectedResponse, &Etag); + if (EFI_ERROR (Status)) { + DEBUG ((DEBUG_ERROR, "%a: failed to get ETag from HTTP header\n", __fu= nc__)); + } + + Status =3D 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 =3D NULL; + + if (Private->Json !=3D NULL) { + FreePool (Private->Json); + Private->Json =3D NULL; + } + + if (Etag !=3D NULL) { + FreePool (Etag); + } + + if (PendingSettingUri !=3D 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 =3D=3D NULL) || (Info =3D=3D 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 =3D=3D NULL) || IS_EMPTY_STRING (Uri)) { + return EFI_INVALID_PARAMETER; + } + + ZeroMem (&Response, sizeof (REDFISH_RESPONSE)); + Private =3D REDFISH_RESOURCE_COMMON_PRIVATE_DATA_FROM_RESOURCE_PROTOCOL = (This); + + if (Private->RedfishService =3D=3D NULL) { + return EFI_NOT_READY; + } + + Status =3D RedfishHttpGetResource (Private->RedfishService, Uri, NULL, &= Response, TRUE); + if (EFI_ERROR (Status)) { + DEBUG ((DEBUG_ERROR, "%a: get resource from: %s failed\n", __func__, U= ri)); + return Status; + } + + Private->Uri =3D Uri; + Private->Payload =3D Response.Payload; + ASSERT (Private->Payload !=3D NULL); + + Private->Json =3D JsonDumpString (RedfishJsonInPayload (Private->Payload= ), EDKII_JSON_COMPACT); + ASSERT (Private->Json !=3D NULL); + + Status =3D RedfishUpdateResourceCommon (Private, Private->Json); + if (EFI_ERROR (Status)) { + DEBUG ((DEBUG_ERROR, "%a: failed to update resource to: %s: %r\n", __f= unc__, 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 =3D NULL; + + if (Private->Json !=3D NULL) { + FreePool (Private->Json); + Private->Json =3D 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 =3D=3D NULL) || IS_EMPTY_STRING (Uri)) { + return EFI_INVALID_PARAMETER; + } + + ZeroMem (&Response, sizeof (REDFISH_RESPONSE)); + Private =3D REDFISH_RESOURCE_COMMON_PRIVATE_DATA_FROM_RESOURCE_PROTOCOL = (This); + + if (Private->RedfishService =3D=3D NULL) { + return EFI_NOT_READY; + } + + Status =3D RedfishHttpGetResource (Private->RedfishService, Uri, NULL, &= Response, TRUE); + if (EFI_ERROR (Status)) { + DEBUG ((DEBUG_ERROR, "%a: get resource from: %s failed\n", __func__, U= ri)); + return Status; + } + + Private->Uri =3D Uri; + Private->Payload =3D Response.Payload; + ASSERT (Private->Payload !=3D NULL); + + Private->Json =3D JsonDumpString (RedfishJsonInPayload (Private->Payload= ), EDKII_JSON_COMPACT); + ASSERT (Private->Json !=3D NULL); + + // + // Find etag in HTTP response header + // + Etag =3D NULL; + Status =3D GetHttpResponseEtag (&Response, &Etag); + if (EFI_ERROR (Status)) { + DEBUG ((DEBUG_ERROR, "%a: failed to get ETag from HTTP header\n", __fu= nc__)); + } + + Status =3D 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 !=3D NULL) { + FreePool (Etag); + } + + RedfishHttpFreeResponse (&Response); + Private->Payload =3D NULL; + + if (Private->Json !=3D NULL) { + FreePool (Private->Json); + Private->Json =3D NULL; + } + + return Status; +} + +/** + Identify resource on given URI. + + @param[in] This Pointer to EDKII_REDFISH_RESOURCE_CONFI= G_PROTOCOL instance. + @param[in] Uri The target URI to consume. + + @retval EFI_SUCCESS This is target resource which we want t= o 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 =3D=3D NULL) || IS_EMPTY_STRING (Uri)) { + return EFI_INVALID_PARAMETER; + } + + ZeroMem (&Response, sizeof (REDFISH_RESPONSE)); + Private =3D REDFISH_RESOURCE_COMMON_PRIVATE_DATA_FROM_RESOURCE_PROTOCOL = (This); + + if (Private->RedfishService =3D=3D NULL) { + return EFI_NOT_READY; + } + + Status =3D RedfishHttpGetResource (Private->RedfishService, Uri, NULL, &= Response, TRUE); + if (EFI_ERROR (Status)) { + DEBUG ((DEBUG_ERROR, "%a: get resource from: %s failed\n", __func__, U= ri)); + return Status; + } + + Private->Uri =3D Uri; + Private->Payload =3D Response.Payload; + ASSERT (Private->Payload !=3D NULL); + + Private->Json =3D JsonDumpString (RedfishJsonInPayload (Private->Payload= ), EDKII_JSON_COMPACT); + ASSERT (Private->Json !=3D NULL); + + Status =3D RedfishIdentifyResourceCommon (Private, Private->Json); + if (EFI_ERROR (Status)) { + DEBUG ((DEBUG_ERROR, "%a: identify %s failed: %r\n", __func__, Uri, St= atus)); + } + + // + // Release resource + // + RedfishHttpFreeResponse (&Response); + Private->Payload =3D NULL; + + if (Private->Json !=3D NULL) { + FreePool (Private->Json); + Private->Json =3D NULL; + } + + return Status; +} + +EDKII_REDFISH_RESOURCE_CONFIG_PROTOCOL mRedfishResourceConfig =3D { + 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_HA= NDLER_PROTOCOL instance. + @param[in] RedfishConfigServiceInfo Redfish service information. + + @retval EFI_SUCCESS The handler has been initialized su= ccessfully. + @retval EFI_DEVICE_ERROR Failed to create or configure the R= EST EX protocol instance. + @retval EFI_ALREADY_STARTED This handler has already been initi= alized. + @retval Other Error happens during the initializa= tion. + +**/ +EFI_STATUS +EFIAPI +RedfishResourceInit ( + IN EDKII_REDFISH_CONFIG_HANDLER_PROTOCOL *This, + IN REDFISH_CONFIG_SERVICE_INFORMATION *RedfishConfigServiceInfo + ) +{ + REDFISH_RESOURCE_COMMON_PRIVATE *Private; + + Private =3D REDFISH_RESOURCE_COMMON_PRIVATE_DATA_FROM_CONFIG_PROTOCOL (T= his); + + Private->RedfishService =3D RedfishCreateService (RedfishConfigServiceIn= fo); + if (Private->RedfishService =3D=3D 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 successful= ly. + @retval Others Some error happened. + +**/ +EFI_STATUS +EFIAPI +RedfishResourceStop ( + IN EDKII_REDFISH_CONFIG_HANDLER_PROTOCOL *This + ) +{ + REDFISH_RESOURCE_COMMON_PRIVATE *Private; + + Private =3D REDFISH_RESOURCE_COMMON_PRIVATE_DATA_FROM_CONFIG_PROTOCOL (T= his); + + if (Private->Event !=3D NULL) { + gBS->CloseEvent (Private->Event); + Private->Event =3D NULL; + } + + if (Private->RedfishService !=3D NULL) { + RedfishCleanupService (Private->RedfishService); + Private->RedfishService =3D NULL; + } + + return EFI_SUCCESS; +} + +EDKII_REDFISH_CONFIG_HANDLER_PROTOCOL mRedfishConfigHandler =3D { + 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 =3D=3D NULL) { + return; + } + + if (mRedfishResourcePrivate->JsonStructProtocol !=3D NULL) { + return; + } + + Status =3D gBS->LocateProtocol ( + &gEfiRestJsonStructureProtocolGuid, + NULL, + (VOID **)&mRedfishResourcePrivate->JsonStructProtocol + ); + if (EFI_ERROR (Status)) { + DEBUG ((DEBUG_ERROR, "%a: failed to locate gEfiRestJsonStructureProtoc= olGuid: %r\n", __func__, Status)); + } + + gBS->CloseEvent (Event); +} + +/** + Unloads an image. + + @param ImageHandle Handle that identifies the image to be unl= oaded. + + @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 =3D=3D NULL) { + return EFI_NOT_READY; + } + + ConfigHandler =3D NULL; + + // + // Firstly, find ConfigHandler Protocol interface in this ImageHandle. + // + Status =3D gBS->OpenProtocol ( + ImageHandle, + &gEdkIIRedfishConfigHandlerProtocolGuid, + (VOID **)&ConfigHandler, + NULL, + NULL, + EFI_OPEN_PROTOCOL_BY_HANDLE_PROTOCOL + ); + if (EFI_ERROR (Status) || (ConfigHandler =3D=3D NULL)) { + return Status; + } + + ConfigHandler->Stop (ConfigHandler); + + // + // Last, uninstall ConfigHandler Protocol and resource protocol. + // + Status =3D gBS->UninstallMultipleProtocolInterfaces ( + ImageHandle, + &gEdkIIRedfishConfigHandlerProtocolGuid, + ConfigHandler, + &gEdkIIRedfishResourceConfigProtocolGuid, + &mRedfishResourcePrivate->RedfishResourceConfig, + NULL + ); + + FreePool (mRedfishResourcePrivate); + mRedfishResourcePrivate =3D NULL; + + return Status; +} + +/** + The callback function provided by Redfish Feature driver. + + @param[in] This Pointer to EDKII_REDFISH_FEATURE_PROT= OCOL instance. + @param[in] FeatureAction The action Redfish feature driver sho= uld 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_E= XCHANGE + + @retval EFI_SUCCESS Redfish feature driver callback is exec= uted successfully. + @retval Others Some errors happened. + + @retval EFI_SUCCESS Redfish feature driver callback is exec= uted 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 !=3D CallbackActionStartOperation) { + return EFI_UNSUPPORTED; + } + + Private =3D (REDFISH_RESOURCE_COMMON_PRIVATE *)Context; + + RedfishService =3D Private->RedfishService; + if (RedfishService =3D=3D NULL) { + DEBUG ((DEBUG_ERROR, "%a: no Redfish service configured\n", __func__))= ; + return EFI_NOT_READY; + } + + // + // Save in private structure. + // + Private->InformationExchange =3D InformationExchange; + + // + // Find Redfish version on Redfish ser + // + Private->RedfishVersion =3D RedfishGetVersion (RedfishService); + + // + // Create the full URI from Redfish service root. + // + ResourceUri =3D (EFI_STRING)AllocateZeroPool (MAX_URI_LENGTH * sizeof (C= HAR16)); + if (ResourceUri =3D=3D 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->SendInformati= on.FullUri); + + // + // Initialize collection path + // + SecureBootUri =3D RedfishGetUri (ResourceUri); + if (SecureBootUri =3D=3D NULL) { + ASSERT (FALSE); + FreePool (ResourceUri); + return EFI_OUT_OF_RESOURCES; + } + + Status =3D 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 =3D=3D NULL) { + return; + } + + if (mRedfishResourcePrivate->FeatureProtocol !=3D NULL) { + return; + } + + Status =3D gBS->LocateProtocol ( + &gEdkIIRedfishFeatureProtocolGuid, + NULL, + (VOID **)&FeatureProtocol + ); + if (EFI_ERROR (Status)) { + DEBUG ((DEBUG_ERROR, "%a: failed to locate gEdkIIRedfishFeatureProtoco= lGuid: %r\n", __func__, Status)); + gBS->CloseEvent (Event); + return; + } + + Status =3D FeatureProtocol->Register ( + FeatureProtocol, + REDFISH_MANAGED_URI, + RedfishExternalResourceResourceFeatureCallba= ck, + (VOID *)mRedfishResourcePrivate + ); + if (EFI_ERROR (Status)) { + DEBUG ((DEBUG_ERROR, "%a: failed to register %s: %r\n", __func__, REDF= ISH_MANAGED_URI, Status)); + } + + mRedfishResourcePrivate->FeatureProtocol =3D 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 includ= ing + 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 inst= alled 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 !=3D NULL) { + return EFI_ALREADY_STARTED; + } + + mRedfishResourceConfigProtocolHandle =3D ImageHandle; + + mRedfishResourcePrivate =3D AllocateZeroPool (sizeof (REDFISH_RESOURCE_C= OMMON_PRIVATE)); + CopyMem (&mRedfishResourcePrivate->ConfigHandler, &mRedfishConfigHandler= , sizeof (EDKII_REDFISH_CONFIG_HANDLER_PROTOCOL)); + CopyMem (&mRedfishResourcePrivate->RedfishResourceConfig, &mRedfishResou= rceConfig, sizeof (EDKII_REDFISH_RESOURCE_CONFIG_PROTOCOL)); + + // + // Publish config handler protocol and resource protocol. + // + Status =3D 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/Redf= ishClient.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/BootOptionCollectionD= xe.inf INF RedfishClientPkg/Features/BootOption/v1_0_4/Dxe/BootOptionDxe.inf + INF RedfishClientPkg/Features/SecureBoot/v1_1_0/Dxe/SecureBootDxe.inf =20 !include RedfishClientPkg/RedfishJsonStructureDxe.fdf.inc # --=20 2.34.1 -=3D-=3D-=3D-=3D-=3D-=3D-=3D-=3D-=3D-=3D-=3D- 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] -=3D-=3D-=3D-=3D-=3D-=3D-=3D-=3D-=3D-=3D-=3D-