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 72F4994117A for ; Thu, 4 Jan 2024 05:10:05 +0000 (UTC) DKIM-Signature: a=rsa-sha256; bh=ehi9VQiOqtmAi+YnN8RxUQEVvnCb54zeoWwDMZ0qT8A=; c=relaxed/simple; d=groups.io; h=ARC-Seal:ARC-Message-Signature:ARC-Authentication-Results:Received-SPF:From:To:CC:Subject:Date:Message-ID:MIME-Version:Precedence:List-Subscribe:List-Help:Sender:List-Id:Mailing-List:Delivered-To:Reply-To:List-Unsubscribe-Post:List-Unsubscribe:Content-Transfer-Encoding:Content-Type; s=20140610; t=1704345004; v=1; b=uysFBL22i2z2m2FqHRyZyDal2jWoo5Ykibhp7tMKZng6xyqeKck1kSPzQp0is5BjSWJsv+80 pRIevVAu/YYQl1nTS1g6BdcZNwa+yveYv5FZi/yUhYvEii3TOwtCSdEYZn8XoESSd1+ZsbQonan nq/sbKXmgIdkS7iDytg4474c= X-Received: by 127.0.0.2 with SMTP id RzpKYY7687511xCGpif90PvC; Wed, 03 Jan 2024 21:10:04 -0800 X-Received: from NAM11-DM6-obe.outbound.protection.outlook.com (NAM11-DM6-obe.outbound.protection.outlook.com [40.107.223.60]) by mx.groups.io with SMTP id smtpd.web11.47958.1704345003403670993 for ; Wed, 03 Jan 2024 21:10:03 -0800 ARC-Seal: i=1; a=rsa-sha256; s=arcselector9901; d=microsoft.com; cv=none; b=eAVMVThFd7b8lrb71Cy1l/B3syissk9Ywjhx33EPYZvgxTrPr4D2h9n8oVSKB84CXwPmOgP/FBJW8lUttycU9HQVAO/gEGu4EDYBc1IvYSr0dpKNYBPt6wPmSKlPjAq/b2LkF49Gc8E9c7RVBLdq9nMwTTtIKTq8oMLKy4r340CnNHGmLsqZZs+S8hAj8bUYpKD49NrwEYBOMogiM4c14oVdvBB096cyWOJdavImfzo6eFLXN8J7k/KU7pMQCgvWMRaqHIpcFuabmf682NQK/6U6tOcgVE+3dls4fqlHWRZHcPyxnJqLOa1b9X3OGnj4yeCkDn8PS7ouxeoFZy3nBg== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=microsoft.com; s=arcselector9901; h=From:Date:Subject:Message-ID:Content-Type:MIME-Version:X-MS-Exchange-AntiSpam-MessageData-ChunkCount:X-MS-Exchange-AntiSpam-MessageData-0:X-MS-Exchange-AntiSpam-MessageData-1; bh=CEg1vSFe4sr1/+kEyeMeS3Yuxja8dOb8QqNb+PA7um8=; b=loMu+lgQ+a9JKJksVg9lS4/nDvOonTzsl7kD3vTa4i48U6OjOt5UflfqoI+yqXBZ/UqcntY6QaI3xEUz6Z8MvnJXfZO8SQnYAnDUVCyP8D062g+CDuEC94BIu9e8lTZQv2Rnxhx7a15X//8lKZ3rHzn2pHV1teoBgQM6DvncILYLmWt18zcS6j+Wqo1x9ceM6kHxElAXYZMEIpXykPoYvj12PkTGPLJ1N5AnjT1IJGvxBDG+N67s33IBn7yepWWr85SvN+bW19VVq8rVibnbi5pxTREyYl8FG/mw4iPq3w/Kv6ACXb/ATzD5V6gt2tBAldXNEImZoIBObQSuwA/FBg== ARC-Authentication-Results: i=1; mx.microsoft.com 1; spf=pass (sender ip is 216.228.117.160) smtp.rcpttodomain=edk2.groups.io smtp.mailfrom=nvidia.com; dmarc=pass (p=reject sp=reject pct=100) action=none header.from=nvidia.com; dkim=none (message not signed); arc=none (0) X-Received: from BY5PR04CA0001.namprd04.prod.outlook.com (2603:10b6:a03:1d0::11) by DS7PR12MB8276.namprd12.prod.outlook.com (2603:10b6:8:da::19) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.20.7135.25; Thu, 4 Jan 2024 05:09:58 +0000 X-Received: from SJ5PEPF000001D7.namprd05.prod.outlook.com (2603:10b6:a03:1d0:cafe::d7) by BY5PR04CA0001.outlook.office365.com (2603:10b6:a03:1d0::11) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.20.7135.25 via Frontend Transport; Thu, 4 Jan 2024 05:09:56 +0000 X-MS-Exchange-Authentication-Results: spf=pass (sender IP is 216.228.117.160) 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.160 as permitted sender) receiver=protection.outlook.com; client-ip=216.228.117.160; helo=mail.nvidia.com; pr=C X-Received: from mail.nvidia.com (216.228.117.160) by SJ5PEPF000001D7.mail.protection.outlook.com (10.167.242.59) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.20.7159.9 via Frontend Transport; Thu, 4 Jan 2024 05:09:55 +0000 X-Received: from rnnvmail201.nvidia.com (10.129.68.8) by mail.nvidia.com (10.129.200.66) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.2.986.41; Wed, 3 Jan 2024 21:09:41 -0800 X-Received: from rnnvmail205.nvidia.com (10.129.68.10) by rnnvmail201.nvidia.com (10.129.68.8) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.2.986.41; Wed, 3 Jan 2024 21:09:41 -0800 X-Received: from NV-CL38DL3.nvidia.com (10.127.8.10) by mail.nvidia.com (10.129.68.10) with Microsoft SMTP Server id 15.2.986.41 via Frontend Transport; Wed, 3 Jan 2024 21:09:40 -0800 From: "Nickle Wang via groups.io" To: CC: Abner Chang , Igor Kulchytskyy , "Nick Ramirez" Subject: [edk2-devel] [edk2-redfish-client][PATCH 4/4] RedfishClientPkg/Features: introduce boot option Date: Thu, 4 Jan 2024 13:09:39 +0800 Message-ID: <20240104050939.70774-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: SJ5PEPF000001D7:EE_|DS7PR12MB8276:EE_ X-MS-Office365-Filtering-Correlation-Id: ef859819-c8ec-4407-9f4a-08dc0ce3642e X-MS-Exchange-SenderADCheck: 1 X-MS-Exchange-AntiSpam-Relay: 0 X-Microsoft-Antispam-Message-Info: zAmv0k5jabp4RZnvd4IUWZDAhVw3CwrbwpQ33nDcwEAwO9YAn91m+w3JosvnbpX658uOP0nJ2XEIylmBFTOIxefR7VsoEwtGrxcN85j3syQbl0G6+kyieyxIHIHzkAraBnwKF4JcVDHiVyVtUcGV9qyu+yLFXpc4YVfZS/R1guPB3TJqjDqhY37c7dj5FQKx4TngzhXX9zwor8Z6LA1+T8WTEcSvN8aaJEjig5QSxIlvYwVmJpHp/4C7TQmfELBcTWduHHSqbPc38YfkcEaCKLBVSiaa1EQ5MXpTcdwnA97njfGAY5l9u9Y+u1ztb6pmgV7ysjE0USQVSVnkZCKALEoPtYA7SElRQPhS288fx3WBRovKuFyLCDllivsOohUaKNtMOXiLmgrPjbT9PFngKmg8svyy4NW8eTz134v7eWmQbAPcPgSIyUNqFi+YsuVz7juJTmFe368ZGkC8Uo/dgo2YraiX1aI3thDZcrmRDuKE+0GRKJa3LwYcgjOFbeUMEMVeF4cR6MzlnBz6SFrQuJq8YzkuTDcvNPTzM8bbcnS7GRGvnOTPIuNHOhhRiJvQXtATcGeMK8MLiEF7uJt72a0XPyXMx3/pq9zwFtjukObJ8kx/V1XxPePrAfTjV+0b/89D/vWtjuDkVcOFMtZEhDTgMTgK1LkbMElMMrWSglob1t+WEQ7oSjTC6q5QypEmZSFSebHgpN34iQTDX+j1sGzVSDAGKzlLQ15BaXw+XTfOepVH93ci7i1Yk1GW2vgxiXLYLoR57QWF2fTcl3QEHQ== X-OriginatorOrg: Nvidia.com X-MS-Exchange-CrossTenant-OriginalArrivalTime: 04 Jan 2024 05:09:55.6404 (UTC) X-MS-Exchange-CrossTenant-Network-Message-Id: ef859819-c8ec-4407-9f4a-08dc0ce3642e 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.160];Helo=[mail.nvidia.com] X-MS-Exchange-CrossTenant-AuthSource: SJ5PEPF000001D7.namprd05.prod.outlook.com X-MS-Exchange-CrossTenant-AuthAs: Anonymous X-MS-Exchange-CrossTenant-FromEntityHeader: HybridOnPrem X-MS-Exchange-Transport-CrossTenantHeadersStamped: DS7PR12MB8276 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 Reply-To: devel@edk2.groups.io,nicklew@nvidia.com List-Unsubscribe-Post: List-Unsubscribe=One-Click List-Unsubscribe: X-Gm-Message-State: Sdzv0qwrOrXgcE4Nsi6Z5QCjx7686176AA= 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=20140610 header.b=uysFBL22; dmarc=none; 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 Redfish boot option driver and library. This is to support Redfish resource at: /redfish/v1/Systems/SYSTEM_ID/BootOptions - Make ETag parameter as optional parameter in CreatePayloadToPatchResource function. Signed-off-by: Nickle Wang Cc: Abner Chang Cc: Igor Kulchytskyy Cc: Nick Ramirez --- .../RedfishClientComponents.dsc.inc | 2 + RedfishClientPkg/RedfishClientLibs.dsc.inc | 1 + .../BootOption/v1_0_4/Dxe/BootOptionDxe.inf | 56 ++ .../v1_0_4/Common/BootOptionCommon.h | 33 + .../v1_0_4/Common/BootOptionCommon.c | 799 ++++++++++++++++++ .../BootOption/v1_0_4/Dxe/BootOptionDxe.c | 701 +++++++++++++++ .../RedfishFeatureUtilityLib.c | 4 +- RedfishClientPkg/RedfishClient.fdf.inc | 2 + 8 files changed, 1596 insertions(+), 2 deletions(-) create mode 100644 RedfishClientPkg/Features/BootOption/v1_0_4/Dxe/BootOpt= ionDxe.inf create mode 100644 RedfishClientPkg/Features/BootOption/v1_0_4/Common/Boot= OptionCommon.h create mode 100644 RedfishClientPkg/Features/BootOption/v1_0_4/Common/Boot= OptionCommon.c create mode 100644 RedfishClientPkg/Features/BootOption/v1_0_4/Dxe/BootOpt= ionDxe.c diff --git a/RedfishClientPkg/RedfishClientComponents.dsc.inc b/RedfishClie= ntPkg/RedfishClientComponents.dsc.inc index 300f2e21..ae2a4b02 100644 --- a/RedfishClientPkg/RedfishClientComponents.dsc.inc +++ b/RedfishClientPkg/RedfishClientComponents.dsc.inc @@ -33,6 +33,7 @@ RedfishClientPkg/Features/ComputerSystemCollectionDxe/ComputerSystemColl= ectionDxe.inf RedfishClientPkg/Features/Bios/v1_0_9/Dxe/BiosDxe.inf RedfishClientPkg/Features/BootOptionCollection/BootOptionCollectionDxe.i= nf + RedfishClientPkg/Features/BootOption/v1_0_4/Dxe/BootOptionDxe.inf =20 !include RedfishClientPkg/RedfishJsonStructureDxe.dsc.inc =20 @@ -45,3 +46,4 @@ RedfishClientPkg/Converter/ComputerSystemCollection/RedfishComputerSyste= mCollection_Dxe.inf 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 diff --git a/RedfishClientPkg/RedfishClientLibs.dsc.inc b/RedfishClientPkg/= RedfishClientLibs.dsc.inc index f961d697..9c7889d2 100644 --- a/RedfishClientPkg/RedfishClientLibs.dsc.inc +++ b/RedfishClientPkg/RedfishClientLibs.dsc.inc @@ -24,6 +24,7 @@ ComputerSystemCollectionLib|RedfishClientPkg/ConverterLib/edk2library/Co= mputerSystemCollection/Lib.inf 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 # # Above modules should be pulled in by build tool. # diff --git a/RedfishClientPkg/Features/BootOption/v1_0_4/Dxe/BootOptionDxe.= inf b/RedfishClientPkg/Features/BootOption/v1_0_4/Dxe/BootOptionDxe.inf new file mode 100644 index 00000000..00c1c5bb --- /dev/null +++ b/RedfishClientPkg/Features/BootOption/v1_0_4/Dxe/BootOptionDxe.inf @@ -0,0 +1,56 @@ +## @file +# +# (C) Copyright 2020-2022 Hewlett Packard Enterprise Development LP
+# Copyright (c) 2023, NVIDIA CORPORATION & AFFILIATES. All rights reserve= d. +# +# SPDX-License-Identifier: BSD-2-Clause-Patent +# +## + + +[Defines] + INF_VERSION =3D 0x00010005 + BASE_NAME =3D BootOptionDxe + FILE_GUID =3D 66F61747-ECF2-48E6-A221-D210C6382195 + 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 + RedfishPkg/RedfishPkg.dec + RedfishClientPkg/RedfishClientPkg.dec + +[Sources] + ../Common/BootOptionCommon.h + ../Common/BootOptionCommon.c + BootOptionDxe.c + +[LibraryClasses] + BaseMemoryLib + DebugLib + EdkIIRedfishResourceConfigLib + RedfishLib + RedfishFeatureUtilityLib + RedfishResourceIdentifyLib + UefiLib + UefiDriverEntryPoint + RedfishAddendumLib + RedfishHttpCacheLib + UefiBootManagerLib + DevicePathLib + BaseLib + +[Protocols] + gEdkIIRedfishConfigHandlerProtocolGuid ## PRODUCED + gEfiRestJsonStructureProtocolGuid ## CONSUMED + gEdkIIRedfishResourceConfigProtocolGuid ## PRODUCED + +[Pcd] + gEfiRedfishClientPkgTokenSpaceGuid.PcdMaxRedfishSchemaStringSize + gEfiRedfishClientPkgTokenSpaceGuid.PcdMaxRedfishSchemaVersionSize + +[Depex] + TRUE diff --git a/RedfishClientPkg/Features/BootOption/v1_0_4/Common/BootOptionC= ommon.h b/RedfishClientPkg/Features/BootOption/v1_0_4/Common/BootOptionComm= on.h new file mode 100644 index 00000000..83babf16 --- /dev/null +++ b/RedfishClientPkg/Features/BootOption/v1_0_4/Common/BootOptionCommon.h @@ -0,0 +1,33 @@ +/** @file + + Redfish feature driver implementation - internal header file + (C) Copyright 2020-2022 Hewlett Packard Enterprise Development LP
+ Copyright (c) 2022-2023, NVIDIA CORPORATION & AFFILIATES. All rights res= erved. + + SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#ifndef EFI_REDFISH_BOOT_OPTION_COMMON_H_ +#define EFI_REDFISH_BOOT_OPTION_COMMON_H_ + +#include +#include +#include +#include +#include + +// +// Schema information. +// +#define RESOURCE_SCHEMA "BootOption" +#define RESOURCE_SCHEMA_MAJOR "1" +#define RESOURCE_SCHEMA_MINOR "0" +#define RESOURCE_SCHEMA_ERRATA "4" +#define RESOURCE_SCHEMA_VERSION "v1_0_4" +#define REDPATH_ARRAY_PATTERN L"/BootOptions/\\{.*\\}/" +#define REDPATH_ARRAY_PREFIX L"/BootOptions/" +#define RESOURCE_SCHEMA_FULL "x-uefi-redfish-BootOption.v1_0_4= " +#define REDFISH_BOOT_OPTION_PARAMETER L"?name=3D" +#define REDFISH_BOOT_OPTION_DEBUG_TRACE DEBUG_INFO +#endif diff --git a/RedfishClientPkg/Features/BootOption/v1_0_4/Common/BootOptionC= ommon.c b/RedfishClientPkg/Features/BootOption/v1_0_4/Common/BootOptionComm= on.c new file mode 100644 index 00000000..0d4c2162 --- /dev/null +++ b/RedfishClientPkg/Features/BootOption/v1_0_4/Common/BootOptionCommon.c @@ -0,0 +1,799 @@ +/** @file + Redfish feature driver implementation - common functions + + (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 "BootOptionCommon.h" + +CHAR8 BootOptionEmptyJson[] =3D "{\"@odata.id\": \"\", \"@odata.type\": \= "#BootOption.v1_0_4.BootOption\", \"Id\": \"\", \"Name\": \"\", \"BootOptio= nEnabled\": false, \"BootOptionReference\": \"\", \"Description\":\"\", \"D= isplayName\": \"\", \"UefiDevicePath\":\"\"}"; + +REDFISH_RESOURCE_COMMON_PRIVATE *mRedfishResourcePrivate =3D NULL; + +/** + Get boot option variable name from BootOptionReference attribute in Boot= Option resource. + It's caller's responsibility to release BootOptionName by calling FreePo= ol(). + + @param[in] BootOptionCs Pointer to boot option structure. + @param[in] BootOptionName Boot option name read from boot option resou= rce. + + @retval EFI_SUCCESS Boot option name is read successfully. + @retval Others Some error happened. + +**/ +EFI_STATUS +GetBootOptionNameFromRedfish ( + IN EFI_REDFISH_BOOTOPTION_V1_0_4_CS *BootOptionCs, + OUT EFI_STRING *BootOptionName + ) +{ + if ((BootOptionCs =3D=3D NULL) || (BootOptionName =3D=3D NULL)) { + return EFI_INVALID_PARAMETER; + } + + *BootOptionName =3D NULL; + + if (BootOptionCs->BootOptionReference =3D=3D NULL) { + DEBUG ((DEBUG_ERROR, "%a: Missing BootOptionReference attribute which = is mandatory attribute, ignore this!\n", __func__)); + return EFI_PROTOCOL_ERROR; + } + + *BootOptionName =3D StrAsciiToUnicode (BootOptionCs->BootOptionReference= ); + if (*BootOptionName =3D=3D NULL) { + return EFI_OUT_OF_RESOURCES; + } + + return EFI_SUCCESS; +} + +/** + Consume resource from given URI. + + @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 Value is returned 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_BOOTOPTION_V1_0_4 *BootOption; + EFI_REDFISH_BOOTOPTION_V1_0_4_CS *BootOptionCs; + EFI_BOOT_MANAGER_LOAD_OPTION LoadOption; + BOOLEAN LoadOptionEnabled; + EFI_STRING BootOptionName; + + if ((Private =3D=3D NULL) || IS_EMPTY_STRING (Json)) { + return EFI_INVALID_PARAMETER; + } + + BootOption =3D NULL; + BootOptionCs =3D NULL; + BootOptionName =3D NULL; + + Status =3D Private->JsonStructProtocol->ToStructure ( + Private->JsonStructProtocol, + NULL, + Json, + (EFI_REST_JSON_STRUCTURE_HEADER = **)&BootOption + ); + if (EFI_ERROR (Status)) { + DEBUG ((DEBUG_ERROR, "%a: ToStructure() failed: %r\n", __func__, Statu= s)); + return Status; + } + + BootOptionCs =3D BootOption->BootOption; + + // + // Check ETAG to see if we need to consume it + // + if (CheckEtag (Private->Uri, HeaderEtag, NULL)) { + // + // No change + // + DEBUG ((REDFISH_BOOT_OPTION_DEBUG_TRACE, "%a: ETAG: %s has no change, = ignore consume action\n", __func__, Private->Uri)); + Status =3D EFI_SUCCESS; + goto ON_RELEASE; + } + + // + // Get boot option variable name from Redfish. + // + Status =3D GetBootOptionNameFromRedfish (BootOptionCs, &BootOptionName); + if (EFI_ERROR (Status)) { + DEBUG ((DEBUG_ERROR, "%a: can not get boot option name: %r\n", __func_= _, Status)); + goto ON_RELEASE; + } + + // + // Find corresponding Boot#### boot option. + // + Status =3D EfiBootManagerVariableToLoadOption (BootOptionName, &LoadOpti= on); + if (EFI_ERROR (Status)) { + DEBUG ((DEBUG_ERROR, "%a: can not load boot option: %s\n", __func__, B= ootOptionName)); + goto ON_RELEASE; + } + + // + // BootOptionEnabled is the only attribute that is not read-only. + // + if (BootOptionCs->BootOptionEnabled !=3D NULL) { + LoadOptionEnabled =3D ((LoadOption.Attributes & LOAD_OPTION_ACTIVE) = =3D=3D LOAD_OPTION_ACTIVE); + + if (*BootOptionCs->BootOptionEnabled !=3D LoadOptionEnabled) { + if (*BootOptionCs->BootOptionEnabled) { + LoadOption.Attributes |=3D LOAD_OPTION_ACTIVE; + } else { + LoadOption.Attributes &=3D ~LOAD_OPTION_ACTIVE; + } + + // + // Save to variable. + // + Status =3D EfiBootManagerLoadOptionToVariable (&LoadOption); + if (EFI_ERROR (Status)) { + DEBUG ((DEBUG_ERROR, "%a: can not %a boot option: %s: %r", __func_= _, (*BootOptionCs->BootOptionEnabled ? "enable" : "disable"), BootOptionNam= e, Status)); + } + } + } + + EfiBootManagerFreeLoadOption (&LoadOption); + +ON_RELEASE: + + // + // Release resource. + // + Private->JsonStructProtocol->DestoryStructure ( + Private->JsonStructProtocol, + (EFI_REST_JSON_STRUCTURE_HEADER *)BootOpt= ion + ); + + if (BootOptionName !=3D NULL) { + FreePool (BootOptionName); + } + + return EFI_SUCCESS; +} + +EFI_STATUS +ProvisioningBootOptionProperties ( + 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_BOOTOPTION_V1_0_4 *BootOption; + EFI_REDFISH_BOOTOPTION_V1_0_4_CS *BootOptionCs; + EFI_STATUS Status; + BOOLEAN PropertyChanged; + EFI_BOOT_MANAGER_LOAD_OPTION LoadOption; + EFI_STRING DevicePathString; + BOOLEAN LoadOptionEnabled; + CHAR8 *AsciiStringValue; + + if ((JsonStructProtocol =3D=3D NULL) || (ResultJson =3D=3D NULL) || IS_E= MPTY_STRING (InputJson) || IS_EMPTY_STRING (ConfigureLang)) { + return EFI_INVALID_PARAMETER; + } + + DEBUG ((REDFISH_BOOT_OPTION_DEBUG_TRACE, "%a: provision for %s with: %s\= n", __func__, ConfigureLang, (ProvisionMode ? L"Provision resource" : L"Upd= ate resource"))); + + *ResultJson =3D NULL; + PropertyChanged =3D FALSE; + DevicePathString =3D NULL; + AsciiStringValue =3D NULL; + BootOption =3D NULL; + + Status =3D JsonStructProtocol->ToStructure ( + JsonStructProtocol, + NULL, + InputJson, + (EFI_REST_JSON_STRUCTURE_HEADER **)&BootO= ption + ); + if (EFI_ERROR (Status)) { + DEBUG ((DEBUG_ERROR, "%a: ToStructure failure: %r\n", __func__, Status= )); + return Status; + } + + BootOptionCs =3D BootOption->BootOption; + + // + // Find corresponding Boot#### boot option. + // + Status =3D EfiBootManagerVariableToLoadOption (ConfigureLang, &LoadOptio= n); + if (EFI_ERROR (Status)) { + DEBUG ((DEBUG_ERROR, "%a: can not load boot option: %s\n", __func__, C= onfigureLang)); + goto ON_RELEASE; + } + + // + // ID + // + if (BootOptionCs->Id !=3D NULL) { + BootOptionCs->Id =3D NULL; + } + + // + // Name + // + if (BootOptionCs->Name !=3D NULL) { + BootOptionCs->Name =3D NULL; + } + + // + // BootOptionEnabled + // + if (PropertyChecker (BootOptionCs->BootOptionEnabled, ProvisionMode)) { + LoadOptionEnabled =3D ((LoadOption.Attributes & LOAD_OPTION_ACTIVE) = =3D=3D LOAD_OPTION_ACTIVE); + if (*BootOptionCs->BootOptionEnabled !=3D LoadOptionEnabled) { + *BootOptionCs->BootOptionEnabled =3D LoadOptionEnabled; + PropertyChanged =3D TRUE; + } + } + + // + // BootOptionReference + // + if (PropertyChecker (BootOptionCs->BootOptionReference, ProvisionMode)) = { + AsciiStringValue =3D StrUnicodeToAscii (ConfigureLang); + if (AsciiStringValue !=3D NULL) { + if ((BootOptionCs->BootOptionReference =3D=3D NULL) || (AsciiStrCmp = (AsciiStringValue, BootOptionCs->BootOptionReference) !=3D 0)) { + BootOptionCs->BootOptionReference =3D AsciiStringValue; + PropertyChanged =3D TRUE; + } else { + FreePool (AsciiStringValue); + AsciiStringValue =3D NULL; + BootOptionCs->BootOptionReference =3D NULL; + } + } + } + + // + // Description + // + if (PropertyChecker (BootOptionCs->Description, ProvisionMode)) { + AsciiStringValue =3D StrUnicodeToAscii (LoadOption.Description); + if (AsciiStringValue !=3D NULL) { + if ((BootOptionCs->Description =3D=3D NULL) || (AsciiStrCmp (AsciiSt= ringValue, BootOptionCs->Description) !=3D 0)) { + BootOptionCs->Description =3D AsciiStringValue; + PropertyChanged =3D TRUE; + } else { + FreePool (AsciiStringValue); + AsciiStringValue =3D NULL; + BootOptionCs->Description =3D NULL; + } + } + } + + // + // DisplayName + // + if (PropertyChecker (BootOptionCs->DisplayName, ProvisionMode)) { + AsciiStringValue =3D StrUnicodeToAscii (LoadOption.Description); + if (AsciiStringValue !=3D NULL) { + if ((BootOptionCs->DisplayName =3D=3D NULL) || (AsciiStrCmp (AsciiSt= ringValue, BootOptionCs->DisplayName) !=3D 0)) { + BootOptionCs->DisplayName =3D AsciiStringValue; + PropertyChanged =3D TRUE; + } else { + FreePool (AsciiStringValue); + AsciiStringValue =3D NULL; + BootOptionCs->DisplayName =3D NULL; + } + } + } + + // + // UefiDevicePath + // + if (PropertyChecker (BootOptionCs->UefiDevicePath, ProvisionMode)) { + DevicePathString =3D ConvertDevicePathToText (LoadOption.FilePath, TRU= E, FALSE); + if (DevicePathString !=3D NULL) { + AsciiStringValue =3D StrUnicodeToAscii (DevicePathString); + if (AsciiStringValue !=3D NULL) { + if ((BootOptionCs->UefiDevicePath =3D=3D NULL) || (AsciiStrCmp (As= ciiStringValue, BootOptionCs->UefiDevicePath) !=3D 0)) { + BootOptionCs->UefiDevicePath =3D AsciiStringValue; + PropertyChanged =3D TRUE; + } else { + FreePool (AsciiStringValue); + AsciiStringValue =3D NULL; + BootOptionCs->UefiDevicePath =3D NULL; + } + } + + FreePool (DevicePathString); + } + } + + EfiBootManagerFreeLoadOption (&LoadOption); + +ON_RELEASE: + + // + // Convert C structure back to JSON text. + // + Status =3D JsonStructProtocol->ToJson ( + JsonStructProtocol, + (EFI_REST_JSON_STRUCTURE_HEADER *)BootOpt= ion, + 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 *)BootOption + ); + + return (PropertyChanged ? EFI_SUCCESS : EFI_NOT_FOUND); +} + +/** + Provisioning redfish resource by given URI. + + @param[in] This Pointer to EFI_HP_REDFISH_HII_PROTOCOL = instance. + @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 Value is returned successfully. + @retval Others Some error happened. + +**/ +EFI_STATUS +RedfishProvisioningResourceCommon ( + IN REDFISH_RESOURCE_COMMON_PRIVATE *Private, + IN BOOLEAN ResourceExist + ) +{ + CHAR8 *Json; + CHAR8 *JsonWithAddendum; + EFI_STATUS Status; + EFI_STRING NewResourceLocation; + EFI_STRING BootOptionName; + REDFISH_RESPONSE Response; + + if (Private =3D=3D NULL) { + return EFI_INVALID_PARAMETER; + } + + Json =3D NULL; + JsonWithAddendum =3D NULL; + NewResourceLocation =3D NULL; + BootOptionName =3D NULL; + ZeroMem (&Response, sizeof (REDFISH_RESPONSE)); + + if (ResourceExist) { + DEBUG ((DEBUG_ERROR, "%a: dose not support the exist boot option resou= rce\n")); + return EFI_UNSUPPORTED; + } + + // + // Get boot option name from URI. The name is in the query parameter: "?= name=3D" + // + BootOptionName =3D StrStr (Private->Uri, REDFISH_BOOT_OPTION_PARAMETER); + if (BootOptionName =3D=3D NULL) { + DEBUG ((DEBUG_ERROR, "%a: can not get boot option name in: %s\n", __fu= nc__, Private->Uri)); + return EFI_DEVICE_ERROR; + } + + BootOptionName[0] =3D '\0'; + + BootOptionName +=3D StrLen (REDFISH_BOOT_OPTION_PARAMETER); + if (BootOptionName[0] =3D=3D '\0') { + DEBUG ((DEBUG_ERROR, "%a: empty boot option name in: %s\n", __func__, = Private->Uri)); + return EFI_DEVICE_ERROR; + } + + Status =3D ProvisioningBootOptionProperties ( + Private->JsonStructProtocol, + BootOptionEmptyJson, + NULL, + BootOptionName, + TRUE, + &Json + ); + if (EFI_ERROR (Status)) { + DEBUG ((DEBUG_ERROR, "%a: provisioning resource for %s failed: %r\n", = __func__, BootOptionName, Status)); + return Status; + } + + // + // 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; + } + + Status =3D CreatePayloadToPostResource (Private->RedfishService, Private= ->Payload, Json, NULL, NULL); + if (EFI_ERROR (Status)) { + DEBUG ((DEBUG_ERROR, "%a: post BootOption resource for %s failed: %r\n= ", __func__, BootOptionName, Status)); + goto RELEASE_RESOURCE; + } + + // + // per Redfish spec. the URL of new resource will be returned in "Locati= on" header. + // + Status =3D GetEtagAndLocation (&Response, NULL, &NewResourceLocation); + if (EFI_ERROR (Status)) { + DEBUG ((DEBUG_ERROR, "%a: cannot find new location: %r\n", __func__, S= tatus)); + goto RELEASE_RESOURCE; + } + + // + // Keep location of new resource. + // + if (NewResourceLocation !=3D NULL) { + DEBUG ((REDFISH_BOOT_OPTION_DEBUG_TRACE, "%a: Location: %s\n", __func_= _, NewResourceLocation)); + RedfishSetRedfishUri (BootOptionName, NewResourceLocation); + } + +RELEASE_RESOURCE: + + if (NewResourceLocation !=3D NULL) { + FreePool (NewResourceLocation); + } + + if (Json !=3D NULL) { + FreePool (Json); + } + + RedfishFreeResponse ( + Response.StatusCode, + Response.HeaderCount, + Response.Headers, + Response.Payload + ); + + return Status; +} + +/** + Check resource from given URI. + + @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 Value is returned successfully. + @retval Others Some error happened. + +**/ +EFI_STATUS +RedfishCheckResourceCommon ( + IN REDFISH_RESOURCE_COMMON_PRIVATE *Private, + IN CHAR8 *Json, + IN CHAR8 *HeaderEtag OPTIONAL + ) +{ + EFI_STATUS Status; + EFI_REDFISH_BOOTOPTION_V1_0_4 *BootOption; + EFI_REDFISH_BOOTOPTION_V1_0_4_CS *BootOptionCs; + EFI_STRING BootOptionName; + EFI_BOOT_MANAGER_LOAD_OPTION LoadOption; + REDFISH_RESPONSE Response; + BOOLEAN DeleteResourceRequired; + EFI_STRING DevicePathString; + CHAR8 *DevicePathAsciiString; + CHAR8 *AsciiUri; + + if ((Private =3D=3D NULL) || IS_EMPTY_STRING (Json)) { + return EFI_INVALID_PARAMETER; + } + + ZeroMem (&Response, sizeof (REDFISH_RESPONSE)); + DevicePathString =3D NULL; + DevicePathAsciiString =3D NULL; + DeleteResourceRequired =3D FALSE; + BootOptionName =3D NULL; + BootOption =3D NULL; + AsciiUri =3D NULL; + Response.Payload =3D NULL; + Status =3D Private->JsonStructProtocol->ToStructure ( + Private->JsonStr= uctProtocol, + NULL, + Json, + (EFI_REST_JSON_S= TRUCTURE_HEADER **)&BootOption + ); + if (EFI_ERROR (Status)) { + DEBUG ((DEBUG_ERROR, "%a: ToStructure() failed: %r\n", __func__, Statu= s)); + return Status; + } + + BootOptionCs =3D BootOption->BootOption; + + // + // Get boot option variable name from Redfish. + // + Status =3D GetBootOptionNameFromRedfish (BootOptionCs, &BootOptionName); + if (EFI_ERROR (Status)) { + DEBUG ((DEBUG_ERROR, "%a: can not get boot option name: %r\n", __func_= _, Status)); + goto ON_RELEASE; + } + + // + // Find corresponding Boot#### boot option. + // + Status =3D EfiBootManagerVariableToLoadOption (BootOptionName, &LoadOpti= on); + if (!EFI_ERROR (Status)) { + // + // Check the UefiDevicePath + // + if (BootOptionCs->UefiDevicePath !=3D NULL) { + DevicePathString =3D ConvertDevicePathToText (LoadOption.FilePath, T= RUE, FALSE); + if (DevicePathString !=3D NULL) { + DevicePathAsciiString =3D StrUnicodeToAscii (DevicePathString); + if (DevicePathAsciiString !=3D NULL) { + if (AsciiStrCmp (DevicePathAsciiString, BootOptionCs->UefiDevice= Path) !=3D 0) { + // + // The device path of this boot option is not the one in syste= m. + // + DeleteResourceRequired =3D TRUE; + } + + FreePool (DevicePathAsciiString); + } + + FreePool (DevicePathString); + } else { + DeleteResourceRequired =3D TRUE; + } + } + + EfiBootManagerFreeLoadOption (&LoadOption); + } else { + DeleteResourceRequired =3D TRUE; + } + + // + // This boot option is deleted in system. Remove it from BMC too. + // + if (DeleteResourceRequired) { + DEBUG ((REDFISH_BOOT_OPTION_DEBUG_TRACE, "%a: boot option %s is delete= d in system. Delete %s\n", __func__, BootOptionName, Private->Uri)); + AsciiUri =3D StrUnicodeToAscii (Private->Uri); + if (AsciiUri =3D=3D NULL) { + Status =3D EFI_OUT_OF_RESOURCES; + goto ON_RELEASE; + } + + Status =3D RedfishDeleteByUri (Private->RedfishService, AsciiUri, &Res= ponse); + if (EFI_ERROR (Status)) { + DEBUG ((DEBUG_ERROR, "%a: can not delete %s: %r\n", __func__, Privat= e->Uri, Status)); + } + + // + // We delete this resource. So this is not the resource that we suppor= ted. + // Return EFI_UNSUPPORTED and caller will ignore this resource. + // + Status =3D EFI_UNSUPPORTED; + } else { + // + // This is the boot option in system and we need further processing to= it. + // + Status =3D EFI_SUCCESS; + + // + // If configure language is missing due to default settings, + // create the record because this is the boot option that we + // handle. + // + if (RedfishGetConfigLanguage (Private->Uri) =3D=3D NULL) { + RedfishSetRedfishUri (BootOptionName, Private->Uri); + } + } + +ON_RELEASE: + + // + // Release resource + // + RedfishFreeResponse ( + Response.StatusCode, + Response.HeaderCount, + Response.Headers, + Response.Payload + ); + + // + // Release resource. + // + Private->JsonStructProtocol->DestoryStructure ( + Private->JsonStructProtocol, + (EFI_REST_JSON_STRUCTURE_HEADER *)BootOpt= ion + ); + + if (BootOptionName !=3D NULL) { + FreePool (BootOptionName); + } + + if (AsciiUri !=3D NULL) { + FreePool (AsciiUri); + } + + return Status; +} + +/** + Update resource to given URI. + + @param[in] This Pointer to REDFISH_RESOURCE_COMMON_PRIV= ATE instance. + @param[in] Json The JSON to consume. + + @retval EFI_SUCCESS Value is returned 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; + EFI_STRING ConfigureLang; + REDFISH_RESPONSE Response; + + if ((Private =3D=3D NULL) || IS_EMPTY_STRING (InputJson)) { + return EFI_INVALID_PARAMETER; + } + + Json =3D NULL; + ConfigureLang =3D NULL; + ZeroMem (&Response, sizeof (REDFISH_RESPONSE)); + + ConfigureLang =3D RedfishGetConfigLanguage (Private->Uri); + if (ConfigureLang =3D=3D NULL) { + return EFI_NOT_FOUND; + } + + Status =3D ProvisioningBootOptionProperties ( + Private->JsonStructProtocol, + InputJson, + NULL, + ConfigureLang, + FALSE, + &Json + ); + if (EFI_ERROR (Status)) { + if (Status =3D=3D EFI_NOT_FOUND) { + DEBUG ((REDFISH_BOOT_OPTION_DEBUG_TRACE, "%a: update resource for %s= ignored. Nothing changed\n", __func__, ConfigureLang)); + Status =3D EFI_SUCCESS; + } else { + DEBUG ((DEBUG_ERROR, "%a: update resource for %s failed: %r\n", __fu= nc__, ConfigureLang, 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_BOOT_OPTION_DEBUG_TRACE, "%a: update resource for %s\n",= __func__, ConfigureLang)); + + // + // PATCH back to instance + // + Status =3D CreatePayloadToPatchResource (Private->RedfishService, Privat= e->Payload, Json, NULL); + if (EFI_ERROR (Status)) { + DEBUG ((DEBUG_ERROR, "%a: patch resource for %s failed: %r\n", __func_= _, ConfigureLang, Status)); + } + +ON_RELEASE: + + if (Json !=3D NULL) { + FreePool (Json); + } + + if (ConfigureLang !=3D NULL) { + FreePool (ConfigureLang); + } + + RedfishFreeResponse ( + Response.StatusCode, + Response.HeaderCount, + Response.Headers, + Response.Payload + ); + + return Status; +} + +/** + Identify resource from given URI. + + @param[in] This Pointer to REDFISH_RESOURCE_COMMON_PRIV= ATE instance. + @param[in] Json The JSON to consume. + + @retval EFI_SUCCESS Value is returned 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) { + return EFI_SUCCESS; + } + + return EFI_UNSUPPORTED; +} diff --git a/RedfishClientPkg/Features/BootOption/v1_0_4/Dxe/BootOptionDxe.= c b/RedfishClientPkg/Features/BootOption/v1_0_4/Dxe/BootOptionDxe.c new file mode 100644 index 00000000..ba090c51 --- /dev/null +++ b/RedfishClientPkg/Features/BootOption/v1_0_4/Dxe/BootOptionDxe.c @@ -0,0 +1,701 @@ +/** @file + Redfish feature driver implementation - BootOption + + (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/BootOptionCommon.h" + +extern REDFISH_RESOURCE_COMMON_PRIVATE *mRedfishResourcePrivate; + +EFI_HANDLE mRedfishResourceConfigProtocolHandle; + +/** + Provision 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_BOOT_OPTION_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, &Respon= se, 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. + // + RedfishHttpResetResource (Private->Uri); + SetEtagFromUri (Private->RedfishService, Private->Uri, TRUE); + } + + if (Private->Payload !=3D NULL) { + RedfishFreeResponse ( + Response.StatusCode, + Response.HeaderCount, + Response.Headers, + Response.Payload + ); + 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; + } + + Private =3D REDFISH_RESOURCE_COMMON_PRIVATE_DATA_FROM_RESOURCE_PROTOCOL = (This); + ZeroMem (&Response, sizeof (REDFISH_RESPONSE)); + ZeroMem (&PendingSettingResponse, sizeof (REDFISH_RESPONSE)); + + if (Private->RedfishService =3D=3D NULL) { + return EFI_NOT_READY; + } + + Status =3D RedfishHttpGetResource (Private->RedfishService, Uri, &Respon= se, 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. + // + Status =3D GetPendingSettings ( + Private->RedfishService, + Response.Payload, + &PendingSettingResponse, + &PendingSettingUri + ); + if (!EFI_ERROR (Status)) { + DEBUG ((REDFISH_BOOT_OPTION_DEBUG_TRACE, "%a: @Redfish.Settings found:= %s\n", __func__, 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); + + // + // Find etag in HTTP response header + // + Etag =3D NULL; + Status =3D GetEtagAndLocation (ExpectedResponse, &Etag, NULL); + 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 + // + if (Etag !=3D NULL) { + FreePool (Etag); + } + + if (Private->Payload !=3D NULL) { + RedfishFreeResponse ( + Response.StatusCode, + Response.HeaderCount, + Response.Headers, + Response.Payload + ); + + if (PendingSettingResponse.Payload !=3D NULL) { + RedfishFreeResponse ( + PendingSettingResponse.StatusCode, + PendingSettingResponse.HeaderCount, + PendingSettingResponse.Headers, + PendingSettingResponse.Payload + ); + } + + Private->Payload =3D NULL; + } + + if (Private->Json !=3D NULL) { + FreePool (Private->Json); + Private->Json =3D NULL; + } + + 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, &Respon= se, 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. + // + RedfishHttpResetResource (Private->Uri); + SetEtagFromUri (Private->RedfishService, Private->Uri, TRUE); + } + + // + // Release resource + // + if (Private->Payload !=3D NULL) { + RedfishFreeResponse ( + Response.StatusCode, + Response.HeaderCount, + Response.Headers, + Response.Payload + ); + 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, &Respon= se, 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 GetEtagAndLocation (&Response, &Etag, NULL); + 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 ((REDFISH_BOOT_OPTION_DEBUG_TRACE, "%a: failed to check resource= from: %s: %r\n", __func__, Uri, Status)); + } + + // + // Release resource + // + if (Etag !=3D NULL) { + FreePool (Etag); + } + + if (Private->Payload !=3D NULL) { + RedfishFreeResponse ( + Response.StatusCode, + Response.HeaderCount, + Response.Headers, + Response.Payload + ); + 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, &Respon= se, 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 ((REDFISH_BOOT_OPTION_DEBUG_TRACE, "%a: identify %s failed: %r\n= ", __func__, Uri, Status)); + } + + // + // Release resource + // + if (Private->Payload !=3D NULL) { + RedfishFreeResponse ( + Response.StatusCode, + Response.HeaderCount, + Response.Headers, + Response.Payload + ); + 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; + } + + if (Private->Payload !=3D NULL) { + RedfishCleanupPayload (Private->Payload); + Private->Payload =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 +EfiRestJasonStructureProtocolIsReady ( + 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; +} + +/** + 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 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, + EfiRestJasonStructureProtocolIsReady, + NULL, + &Registration + ); + + return Status; +} diff --git a/RedfishClientPkg/Library/RedfishFeatureUtilityLib/RedfishFeatu= reUtilityLib.c b/RedfishClientPkg/Library/RedfishFeatureUtilityLib/RedfishF= eatureUtilityLib.c index cad91a41..1c2d40f6 100644 --- a/RedfishClientPkg/Library/RedfishFeatureUtilityLib/RedfishFeatureUtili= tyLib.c +++ b/RedfishClientPkg/Library/RedfishFeatureUtilityLib/RedfishFeatureUtili= tyLib.c @@ -1856,7 +1856,7 @@ CreatePayloadToPatchResource ( IN REDFISH_SERVICE *Service, IN REDFISH_PAYLOAD *TargetPayload, IN CHAR8 *Json, - OUT CHAR8 **Etag + OUT CHAR8 **Etag OPTIONAL ) { REDFISH_PAYLOAD Payload; @@ -1864,7 +1864,7 @@ CreatePayloadToPatchResource ( REDFISH_RESPONSE PostResponse; EFI_STATUS Status; =20 - if ((Service =3D=3D NULL) || (TargetPayload =3D=3D NULL) || IS_EMPTY_STR= ING (Json) || (Etag =3D=3D NULL)) { + if ((Service =3D=3D NULL) || (TargetPayload =3D=3D NULL) || IS_EMPTY_STR= ING (Json)) { return EFI_INVALID_PARAMETER; } =20 diff --git a/RedfishClientPkg/RedfishClient.fdf.inc b/RedfishClientPkg/Redf= ishClient.fdf.inc index b8619417..59b8acba 100644 --- a/RedfishClientPkg/RedfishClient.fdf.inc +++ b/RedfishClientPkg/RedfishClient.fdf.inc @@ -24,6 +24,7 @@ INF RedfishClientPkg/HiiToRedfishBootDxe/HiiToRedfishBootDxe.inf INF RedfishClientPkg/HiiToRedfishBiosDxe/HiiToRedfishBiosDxe.inf INF RedfishClientPkg/Features/BootOptionCollection/BootOptionCollectionD= xe.inf + INF RedfishClientPkg/Features/BootOption/v1_0_4/Dxe/BootOptionDxe.inf =20 !include RedfishClientPkg/RedfishJsonStructureDxe.fdf.inc # @@ -35,4 +36,5 @@ INF RedfishClientPkg/Converter/ComputerSystemCollection/RedfishComputerS= ystemCollection_Dxe.inf INF RedfishClientPkg/Converter/Bios/v1_0_9/RedfishBios_V1_0_9_Dxe.inf INF RedfishClientPkg/Converter/BootOptionCollection/RedfishBootOptionCol= lection_Dxe.inf + INF RedfishClientPkg/Converter/BootOption/v1_0_4/RedfishBootOption_V1_0_= 4_Dxe.inf !endif --=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 (#113135): https://edk2.groups.io/g/devel/message/113135 Mute This Topic: https://groups.io/mt/103517656/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-