From mboxrd@z Thu Jan 1 00:00:00 1970 Received: from NAM04-DM6-obe.outbound.protection.outlook.com (NAM04-DM6-obe.outbound.protection.outlook.com [40.107.102.51]) by mx.groups.io with SMTP id smtpd.web10.6133.1681366874358650407 for ; Wed, 12 Apr 2023 23:21:14 -0700 Authentication-Results: mx.groups.io; dkim=fail reason="body hash did not verify" header.i=@nvidia.com header.s=selector2 header.b=MZqTJvF+; spf=permerror, err=parse error for token &{10 18 %{i}._ip.%{h}._ehlo.%{d}._spf.vali.email}: invalid domain name (domain: nvidia.com, ip: 40.107.102.51, mailfrom: nicklew@nvidia.com) ARC-Seal: i=1; a=rsa-sha256; s=arcselector9901; d=microsoft.com; cv=none; b=FBkJlf+4o2iuXn4Bc3YVIMmTT4Cn3b5deiPm+ppDsnSiiRYXKMliXtS+cWRC3gVAD6nZCOasvXcRHwGDL/lMF3pJFsPhASbFfnymZxEAi0lU2wK9F6fyhzTz8asCK6X1Q7ODr4CjbaTJnaPCXHvSpr5IMTlP1Cx9FhKVbBE19UB4rDsJuHC3fzzX9Ee7UkyUN+Q4oq2mdzFMEgvBpZ197MO7M4WfwpFTYZxhVp3xr8kXnPoyWPrxdRbVxnp5K0OfpEm+22aCT22KMYPXZWlgq2MNSjd2l9/qefwMa4MMrgbYIBq8/iaQnORsd/JfEX/P+98OSNfZVHIdhFIFcgerxA== 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=bJwxsmEmAuKAZIdJ9ua1SQ1Yi1SgOkpSgb7RDTv0gtA=; b=KAu+Fu2s8JVnwuqGEdSA/3zRuB247wp6OtZ064Uc7mDXlgmhRf1OlQoIEpwhFDVfMokiv8aWjBaPH+AHVkMJduKLmECrY4RcVJN7+DZ0UPehncKnTtDnsTOQ6a2mi8VGwrpaWGYLsSpeW/rSjJs21JCSj50/+a8EAJoZGx3UpqouvpX01kQnL6QeUcvw2SXFQSbqEfZfDWsk8yHUriWINqJolz2Pt4Cg+9vofVyptfo3HmXT/sh1ua4evEbk3Artyw8grGnQ6OXkLotwaWHdXEVlygZQVrosVdcDlFlR0JMkXFkL+nP0dEpnWKKBeLPkB1WOVcSYZUF5BkGst8B1EQ== 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 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=Nvidia.com; s=selector2; h=From:Date:Subject:Message-ID:Content-Type:MIME-Version:X-MS-Exchange-SenderADCheck; bh=bJwxsmEmAuKAZIdJ9ua1SQ1Yi1SgOkpSgb7RDTv0gtA=; b=MZqTJvF+nrdjWSRzt1e/Tl3xFO8Y2wlJf+f6dIB+ghcK3/TF520G5rUcXictWDK6nv/zvgZzeKxCz07PDppsFomnJHhVT3eKbyHbvJu6OmCO7NDdVnvbIj4xHUsA/xlJj341bTBGDcOntnI7Xa29g9R6TcEQeB8MBFmw1yxRKlKBCDFLAIW/gxCyNt+61pQKiTSPplLsLzoaMGnI/kl1XppVPWo/9dGRdUOqUYK3sC9ZBxzkdWf6xsxYSxELeHV8zLgti095SSKELaL4wtk9zy2rfUjynn5CYqy3JjNHCoBFnAHF0rSVaFOEe3aNwWlNJXXto+DnfgI9o2SJW31CVQ== Received: from MW4PR03CA0262.namprd03.prod.outlook.com (2603:10b6:303:b4::27) by BL1PR12MB5876.namprd12.prod.outlook.com (2603:10b6:208:398::19) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.20.6298.30; Thu, 13 Apr 2023 06:21:08 +0000 Received: from CO1NAM11FT065.eop-nam11.prod.protection.outlook.com (2603:10b6:303:b4:cafe::79) by MW4PR03CA0262.outlook.office365.com (2603:10b6:303:b4::27) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.20.6298.30 via Frontend Transport; Thu, 13 Apr 2023 06:21:08 +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 Received: from mail.nvidia.com (216.228.117.160) by CO1NAM11FT065.mail.protection.outlook.com (10.13.174.62) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.20.6298.31 via Frontend Transport; Thu, 13 Apr 2023 06:21:08 +0000 Received: from rnnvmail204.nvidia.com (10.129.68.6) 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.5; Wed, 12 Apr 2023 23:20:56 -0700 Received: from rnnvmail205.nvidia.com (10.129.68.10) by rnnvmail204.nvidia.com (10.129.68.6) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.2.986.37; Wed, 12 Apr 2023 23:20:54 -0700 Received: from NV-CL38DL3.nvidia.com (10.127.8.11) by mail.nvidia.com (10.129.68.10) with Microsoft SMTP Server id 15.2.986.37 via Frontend Transport; Wed, 12 Apr 2023 23:20:53 -0700 From: "Nickle Wang" To: CC: Abner Chang , Igor Kulchytskyy , "Nick Ramirez" Subject: [PATCH 3/5] RedfishPkg: Implementation of EDKII_REDFISH_PLATFORM_CONFIG_PROTOCOL Date: Thu, 13 Apr 2023 14:20:52 +0800 Message-ID: <20230413062052.1700-1-nicklew@nvidia.com> X-Mailer: git-send-email 2.17.1 MIME-Version: 1.0 Return-Path: nicklew@nvidia.com X-EOPAttributedMessage: 0 X-MS-PublicTrafficType: Email X-MS-TrafficTypeDiagnostic: CO1NAM11FT065:EE_|BL1PR12MB5876:EE_ X-MS-Office365-Filtering-Correlation-Id: 8891c709-deca-486d-c3fe-08db3be74501 X-MS-Exchange-SenderADCheck: 1 X-MS-Exchange-AntiSpam-Relay: 0 X-Microsoft-Antispam: BCL:0; X-Microsoft-Antispam-Message-Info: +lvmbLtQ5Ibgsx7EAZm1SeZZZey5ZfbdKUumhalLcMtxi/uHsm0SL6H651W4dU7XItKulhYMyVLYtrhAcA2DF9TetBzxjZy92d442Sts/Oawc35Nt98ODtneAvf9hB9EU6t8eHi8Qr/jXtP26qBE7pgmUfaFfuHCSym8vPKRP0qLdwLEtgYWHHjn7aoJt6PRsd3CBrDIoJbz0f3aDE/HcSglFgbhA3zqL4XZqGZBAv+Vm1g6uYOuf3QsQKUEf+8qIAYISLDzbPJk5Ghs7CEkjFPL9RWnEJndQJBuKhYR8X2J/xvD7f9JVENnaSijwruQl1vzr5NX1dw36Ih+t9AaelB3OJ7EQlWLbakxcRTxr9Iq3VsTzc8AsewKXL3JFJO8+ou6rNUcUNTcgV7GCLr5bu1zR03OE2+YqIE0yVw3CI+ds0hq8Prkf2cVeRfv64a35GXTxJKv/x1w9haLZ36MIHHuz4LyZWs+ADM9Qi72/XJxaPErj9eCBoiBoYUuwQiAcPPfNkPgLGOJkQJBBPxgoSU2j0eYl5dSzjrk9GIvrC6N42yAOnMrngozjy8MhF7WfoR5pEZNYlsUEdOHIvmRqJ9lXJYUJ7vLqrSrYN3reRAtBKFy5mT+XKb+hGeNKusGqFMqwZ9nkW8Eqypps4fTb+InhEsT4DZ8iUKOGBHCSEizjSZL199OsQittY5ye3puSH6XwKBYQPvtgLwp2H8A0q+KInYI684S8ZstbgthGdoPP8ALQPwJBvGpsY8fgGdOvBuIRUb2qAwAHBrbcfwRvT4uUsjhF4A6eQja42AAOQ/sLQOgfAiNSTd1b9RIMHn4 X-Forefront-Antispam-Report: CIP:216.228.117.160;CTRY:US;LANG:en;SCL:1;SRV:;IPV:NLI;SFV:NSPM;H:mail.nvidia.com;PTR:dc6edge1.nvidia.com;CAT:NONE;SFS:(13230028)(4636009)(376002)(136003)(39860400002)(346002)(396003)(451199021)(46966006)(36840700001)(40470700004)(86362001)(54906003)(19627235002)(66899021)(34020700004)(40460700003)(478600001)(7636003)(356005)(316002)(41300700001)(82740400003)(8676002)(8936002)(5660300002)(6916009)(70206006)(40480700001)(70586007)(107886003)(36756003)(1076003)(26005)(426003)(336012)(186003)(36860700001)(4326008)(30864003)(83380400001)(2906002)(7696005)(2616005)(82310400005)(47076005)(403724002)(579004)(559001);DIR:OUT;SFP:1101; X-OriginatorOrg: Nvidia.com X-MS-Exchange-CrossTenant-OriginalArrivalTime: 13 Apr 2023 06:21:08.3347 (UTC) X-MS-Exchange-CrossTenant-Network-Message-Id: 8891c709-deca-486d-c3fe-08db3be74501 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: CO1NAM11FT065.eop-nam11.prod.protection.outlook.com X-MS-Exchange-CrossTenant-AuthAs: Anonymous X-MS-Exchange-CrossTenant-FromEntityHeader: HybridOnPrem X-MS-Exchange-Transport-CrossTenantHeadersStamped: BL1PR12MB5876 Content-Transfer-Encoding: quoted-printable Content-Type: text/plain This is the Implementation of EDKII_REDFISH_PLATFORM_CONFIG_PROTOCOL, which is the EDKII Redfish Platform Config driver instance that accesses EDK2 HII configuration format and storage. Signed-off-by: Nickle Wang Cc: Abner Chang Cc: Igor Kulchytskyy Cc: Nick Ramirez --- .../RedfishPlatformConfigDxe.inf | 53 + .../RedfishPlatformConfigDxe.h | 77 + .../RedfishPlatformConfigImpl.h | 334 +++ .../RedfishPlatformConfigDxe.c | 2495 +++++++++++++++++ .../RedfishPlatformConfigImpl.c | 1364 +++++++++ 5 files changed, 4323 insertions(+) create mode 100644 RedfishPkg/RedfishPlatformConfigDxe/RedfishPlatformConf= igDxe.inf create mode 100644 RedfishPkg/RedfishPlatformConfigDxe/RedfishPlatformConf= igDxe.h create mode 100644 RedfishPkg/RedfishPlatformConfigDxe/RedfishPlatformConf= igImpl.h create mode 100644 RedfishPkg/RedfishPlatformConfigDxe/RedfishPlatformConf= igDxe.c create mode 100644 RedfishPkg/RedfishPlatformConfigDxe/RedfishPlatformConf= igImpl.c diff --git a/RedfishPkg/RedfishPlatformConfigDxe/RedfishPlatformConfigDxe.i= nf b/RedfishPkg/RedfishPlatformConfigDxe/RedfishPlatformConfigDxe.inf new file mode 100644 index 000000000000..eb5872a4f29b --- /dev/null +++ b/RedfishPkg/RedfishPlatformConfigDxe/RedfishPlatformConfigDxe.inf @@ -0,0 +1,53 @@ +## @file +# Implementation of EDKII_REDFISH_PLATFORM_CONFIG_PROTOCOL interfaces. +# +# (C) Copyright 2021 Hewlett Packard Enterprise Development LP
+# SPDX-License-Identifier: BSD-2-Clause-Patent +# +## + +[Defines] + INF_VERSION =3D 0x00010005 + BASE_NAME =3D RedfishPlatformConfigDxe + FILE_GUID =3D BEAEFFE1-0633-41B5-913C-9389339C2927 + MODULE_TYPE =3D DXE_DRIVER + VERSION_STRING =3D 1.0 + ENTRY_POINT =3D RedfishPlatformConfigDxeEntryPoint + UNLOAD_IMAGE =3D RedfishPlatformConfigDxeUnload + +[Packages] + MdePkg/MdePkg.dec + MdeModulePkg/MdeModulePkg.dec + RedfishPkg/RedfishPkg.dec + +[Sources] + RedfishPlatformConfigDxe.h + RedfishPlatformConfigDxe.c + RedfishPlatformConfigImpl.h + RedfishPlatformConfigImpl.c + +[LibraryClasses] + BaseLib + BaseMemoryLib + DebugLib + DevicePathLib + HiiLib + HiiUtilityLib + MemoryAllocationLib + PrintLib + UefiLib + UefiBootServicesTableLib + UefiRuntimeServicesTableLib + UefiDriverEntryPoint + +[Protocols] + gEdkIIRedfishPlatformConfigProtocolGuid ## PRODUCED + gEfiHiiDatabaseProtocolGuid ## CONSUMED + gEfiHiiStringProtocolGuid ## CONSUMED + gEfiRegularExpressionProtocolGuid ## CONSUMED + +[Guids] + gEfiRegexSyntaxTypePerlGuid ## CONSUMED + +[Depex] + TRUE diff --git a/RedfishPkg/RedfishPlatformConfigDxe/RedfishPlatformConfigDxe.h= b/RedfishPkg/RedfishPlatformConfigDxe/RedfishPlatformConfigDxe.h new file mode 100644 index 000000000000..b3787134d46e --- /dev/null +++ b/RedfishPkg/RedfishPlatformConfigDxe/RedfishPlatformConfigDxe.h @@ -0,0 +1,77 @@ +/** @file + This file defines the EDKII Redfish Platform Config Protocol interface. + + (C) Copyright 2021 Hewlett Packard Enterprise Development LP
+ Copyright (c) 2022-2023, NVIDIA CORPORATION & AFFILIATES. All rights res= erved. + + SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#ifndef EDKII_REDFISH_PLATFORM_CONFIG_DXE_H_ +#define EDKII_REDFISH_PLATFORM_CONFIG_DXE_H_ + +#include + +// +// Libraries +// +#include +#include +#include +#include +#include +#include +#include +#include + +// +// Produced Protocols +// +#include +#include +#include +#include + +// +// Definition of EDKII_REDFISH_PLATFORM_CONFIG_NOTIFY. +// +typedef struct { + EFI_EVENT ProtocolEvent; // Protocol notification ev= ent. + VOID *Registration; // Protocol notification re= gistration. +} REDFISH_PLATFORM_CONFIG_NOTIFY; + +// +// Definition of REDFISH_PLATFORM_CONFIG_PRIVATE. +// +typedef struct { + EFI_HANDLE ImageHandle; //= Driver image handle. + EDKII_REDFISH_PLATFORM_CONFIG_PROTOCOL Protocol; + REDFISH_PLATFORM_CONFIG_NOTIFY HiiDbNotify; + EFI_HII_DATABASE_PROTOCOL *HiiDatabase; //= The HII database protocol. + REDFISH_PLATFORM_CONFIG_NOTIFY HiiStringNotify; + EFI_HII_STRING_PROTOCOL *HiiString; //= HII String Protocol. + REDFISH_PLATFORM_CONFIG_NOTIFY RegexNotify; + EFI_REGULAR_EXPRESSION_PROTOCOL *RegularExpressionProtocol; //= Regular Expression Protocol. + EFI_HANDLE NotifyHandle; //= The notify handle. + LIST_ENTRY FormsetList; //= The list to keep cached HII formset. + LIST_ENTRY PendingList; //= The list to keep updated HII handle. +} REDFISH_PLATFORM_CONFIG_PRIVATE; + +// +// Definition of REDFISH_STACK. +// +typedef struct { + VOID **Pool; + UINTN Size; + UINTN Index; +} REDFISH_STACK; + +#define REDFISH_PLATFORM_CONFIG_PRIVATE_FROM_THIS(a) BASE_CR (a, REDFISH_= PLATFORM_CONFIG_PRIVATE, Protocol) +#define REGULAR_EXPRESSION_INCLUDE_ALL L".*" +#define CONFIGURE_LANGUAGE_PREFIX "x-uefi-redfish-" +#define REDFISH_PLATFORM_CONFIG_VERSION 0x00010000 +#define REDFISH_PLATFORM_CONFIG_DEBUG DEBUG_VERBOSE +#define REDFISH_MENU_PATH_SIZE 8 + +#endif diff --git a/RedfishPkg/RedfishPlatformConfigDxe/RedfishPlatformConfigImpl.= h b/RedfishPkg/RedfishPlatformConfigDxe/RedfishPlatformConfigImpl.h new file mode 100644 index 000000000000..9ef032748663 --- /dev/null +++ b/RedfishPkg/RedfishPlatformConfigDxe/RedfishPlatformConfigImpl.h @@ -0,0 +1,334 @@ +/** @file + This file defines the EDKII Redfish Platform Config Protocol private str= ucture. + + (C) Copyright 2021-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 EDKII_REDFISH_PLATFORM_CONFIG_IMPL_H_ +#define EDKII_REDFISH_PLATFORM_CONFIG_IMPL_H_ + +#include + +// +// Libraries +// +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define IS_EMPTY_STRING(a) (a =3D=3D NULL || a[0] =3D=3D L'\0') +#define ENGLISH_LANGUAGE_CODE "en-US" +#define X_UEFI_SCHEMA_PREFIX "x-uefi-redfish-" + +// +// Definition of REDFISH_PLATFORM_CONFIG_PRIVATE. +// +typedef struct { + LIST_ENTRY Link; + EFI_HII_HANDLE HiiHandle; + BOOLEAN IsDeleted; +} REDFISH_PLATFORM_CONFIG_PENDING_LIST; + +#define REDFISH_PLATFORM_CONFIG_PENDING_LIST_FROM_LINK(a) BASE_CR (a, RED= FISH_PLATFORM_CONFIG_PENDING_LIST, Link) + +typedef struct { + UINTN Count; // Number of schema in lis= t + CHAR8 **SchemaList; // Schema list +} REDFISH_PLATFORM_CONFIG_SCHEMA; + +// +// Definition of REDFISH_PLATFORM_CONFIG_FORM_SET_PRIVATE +// +typedef struct { + LIST_ENTRY Link; + HII_FORMSET *HiiFormSet; // Pointer to HII for= mset data. + EFI_GUID Guid; // Formset GUID. + EFI_HII_HANDLE HiiHandle; // Hii Handle of this= formset. + LIST_ENTRY HiiFormList; // Form list that kee= p form data under this formset. + CHAR16 *DevicePathStr; // Device path of thi= s formset. + REDFISH_PLATFORM_CONFIG_SCHEMA SupportedSchema; // Schema that is sup= ported in this formset. +} REDFISH_PLATFORM_CONFIG_FORM_SET_PRIVATE; + +#define REDFISH_PLATFORM_CONFIG_FORMSET_FROM_LINK(a) BASE_CR (a, REDFISH_= PLATFORM_CONFIG_FORM_SET_PRIVATE, Link) + +// +// Definition of REDFISH_PLATFORM_CONFIG_FORM_PRIVATE +// +typedef struct { + LIST_ENTRY Link; + UINT16 Id; // Form ID. + EFI_STRING_ID Title; // String toke= n of form title. + REDFISH_PLATFORM_CONFIG_FORM_SET_PRIVATE *ParentFormset; + HII_FORM *HiiForm; // Pointer to= HII form data. + LIST_ENTRY StatementList; // Statement = list that keep statement under this form. + BOOLEAN Suppressed; // Form is su= ppressed +} REDFISH_PLATFORM_CONFIG_FORM_PRIVATE; + +#define REDFISH_PLATFORM_CONFIG_FORM_FROM_LINK(a) BASE_CR (a, REDFISH_PLA= TFORM_CONFIG_FORM_PRIVATE, Link) + +// +// Definition of REDFISH_PLATFORM_CONFIG_STATEMENT_DATA +// +typedef struct { + UINT64 NumMinimum; + UINT64 NumMaximum; + UINT64 NumStep; + UINT8 StrMinSize; + UINT8 StrMaxSize; +} REDFISH_PLATFORM_CONFIG_STATEMENT_DATA; + +// +// Definition of REDFISH_PLATFORM_CONFIG_STATEMENT_PRIVATE +// +typedef struct { + LIST_ENTRY Link; + REDFISH_PLATFORM_CONFIG_FORM_PRIVATE *ParentForm; + HII_STATEMENT *HiiStatement; // Pointer to = HII statement data. + EFI_QUESTION_ID QuestionId; // Question ID= of this statement. + EFI_STRING_ID Description; // String toke= n of this question. + EFI_STRING_ID Help; // String toke= n of help message. + EFI_STRING DesStringCache; // The string = cache for search function. + UINT8 Flags; // The stateme= nt flag. + REDFISH_PLATFORM_CONFIG_STATEMENT_DATA StatementData; // The max/min= for statement value. + BOOLEAN Suppressed; // Statement i= s suppressed. + BOOLEAN GrayedOut; // Statement i= s GrayedOut. +} REDFISH_PLATFORM_CONFIG_STATEMENT_PRIVATE; + +#define REDFISH_PLATFORM_CONFIG_STATEMENT_FROM_LINK(a) BASE_CR (a, REDFIS= H_PLATFORM_CONFIG_STATEMENT_PRIVATE, Link) + +// +// Definition of REDFISH_PLATFORM_CONFIG_STATEMENT_PRIVATE_REF +// +typedef struct { + LIST_ENTRY Link; + REDFISH_PLATFORM_CONFIG_STATEMENT_PRIVATE *Statement; +} REDFISH_PLATFORM_CONFIG_STATEMENT_PRIVATE_REF; + +#define REDFISH_PLATFORM_CONFIG_STATEMENT_REF_FROM_LINK(a) BASE_CR (a, RE= DFISH_PLATFORM_CONFIG_STATEMENT_PRIVATE_REF, Link) + +// +// Definition of REDFISH_PLATFORM_CONFIG_STATEMENT_PRIVATE_LIST +// +typedef struct { + LIST_ENTRY StatementList; // List of REDFISH_PLATFORM_CONFIG_STA= TEMENT_PRIVATE_REF + UINTN Count; +} REDFISH_PLATFORM_CONFIG_STATEMENT_PRIVATE_LIST; + +/** + Release formset list and all the forms that belong to this formset. + + @param[in] FormsetList Pointer to formset list that needs to be + released. + + @retval EFI_STATUS + +**/ +EFI_STATUS +ReleaseFormsetList ( + IN LIST_ENTRY *FormsetList + ); + +/** + Release formset list and all the forms that belong to this formset. + + @param[in] FormsetList Pointer to formset list that needs to be + released. + + @retval EFI_STATUS + +**/ +EFI_STATUS +LoadFormsetList ( + IN EFI_HII_HANDLE *HiiHandle, + OUT LIST_ENTRY *FormsetList + ); + +/** + When HII database is updated. Keep updated HII handle into pending list = so + we can process them later. + + @param[in] HiiHandle HII handle instance. + @param[in] PendingList Pending list to keep HII handle which is recentl= y updated. + + @retval EFI_SUCCESS HII handle is saved in pending list. + @retval EFI_INVALID_PARAMETER HiiHandle is NULL or PendingList is NULL= . + @retval EFI_OUT_OF_RESOURCES System is out of memory. + +**/ +EFI_STATUS +NotifyFormsetUpdate ( + IN EFI_HII_HANDLE *HiiHandle, + IN LIST_ENTRY *PendingList + ); + +/** + When HII database is updated and form-set is deleted. Keep deleted HII h= andle into pending list so + we can process them later. + + @param[in] HiiHandle HII handle instance. + @param[in] PendingList Pending list to keep HII handle which is recentl= y updated. + + @retval EFI_SUCCESS HII handle is saved in pending list. + @retval EFI_INVALID_PARAMETER HiiHandle is NULL or PendingList is NULL= . + @retval EFI_OUT_OF_RESOURCES System is out of memory. + +**/ +EFI_STATUS +NotifyFormsetDeleted ( + IN EFI_HII_HANDLE *HiiHandle, + IN LIST_ENTRY *PendingList + ); + +/** + Get statement private instance by the given configure language. + + @param[in] FormsetList Form-set list to search. + @param[in] Schema Schema to be matched. + @param[in] ConfigureLang Configure language. + + @retval REDFISH_PLATFORM_CONFIG_STATEMENT_PRIVATE * Pointer to stateme= nt private instance. + +**/ +REDFISH_PLATFORM_CONFIG_STATEMENT_PRIVATE * +GetStatementPrivateByConfigureLang ( + IN LIST_ENTRY *FormsetList, + IN CHAR8 *Schema, + IN EFI_STRING ConfigureLang + ); + +/** + Search and find statement private instance by given regular expression p= attern + which describes the Configure Language. + + @param[in] RegularExpressionProtocol Regular express protocol. + @param[in] FormsetList Form-set list to search. + @param[in] Schema Schema to be matched. + @param[in] Pattern Regular expression pattern. + @param[out] StatementList Statement list that match above = pattern. + + @retval EFI_SUCCESS Statement list is returned. + @retval EFI_INVALID_PARAMETER Input parameter is NULL. + @retval EFI_NOT_READY Regular express protocol is NULL. + @retval EFI_NOT_FOUND No statement is found. + @retval EFI_OUT_OF_RESOURCES System is out of memory. + +**/ +EFI_STATUS +GetStatementPrivateByConfigureLangRegex ( + IN EFI_REGULAR_EXPRESSION_PROTOCOL *RegularExpressionPr= otocol, + IN LIST_ENTRY *FormsetList, + IN CHAR8 *Schema, + IN EFI_STRING Pattern, + OUT REDFISH_PLATFORM_CONFIG_STATEMENT_PRIVATE_LIST *StatementList + ); + +/** + There are HII database update and we need to process them accordingly so= that we + won't use stale data. This function will parse updated HII handle again = in order + to get updated data-set. + + @param[in] FormsetList List to keep HII form-set. + @param[in] PendingList List to keep HII handle that is updated. + + @retval EFI_SUCCESS HII handle is saved in pending list. + @retval EFI_INVALID_PARAMETER FormsetList is NULL or PendingList is NU= LL. + +**/ +EFI_STATUS +ProcessPendingList ( + IN LIST_ENTRY *FormsetList, + IN LIST_ENTRY *PendingList + ); + +/** + Retrieves a unicode string from a string package in a given language. Th= e + returned string is allocated using AllocatePool(). The caller is respon= sible + for freeing the allocated buffer using FreePool(). + + If HiiHandle is NULL, then ASSERT(). + If StringId is 0, then ASSET. + + @param[in] HiiHandle A handle that was previously registered in= the HII Database. + @param[in] Language The specified configure language to get st= ring. + @param[in] StringId The identifier of the string to retrieved = from the string + package associated with HiiHandle. + + @retval NULL The string specified by StringId is not present in the st= ring package. + @retval Other The string was returned. + +**/ +EFI_STRING +HiiGetRedfishString ( + IN EFI_HII_HANDLE HiiHandle, + IN CHAR8 *Language, + IN EFI_STRING_ID StringId + ); + +/** + Retrieves a ASCII string from a string package in a given language. The + returned string is allocated using AllocatePool(). The caller is respon= sible + for freeing the allocated buffer using FreePool(). + + If HiiHandle is NULL, then ASSERT(). + If StringId is 0, then ASSET. + + @param[in] HiiHandle A handle that was previously registered in= the HII Database. + @param[in] Language The specified configure language to get st= ring. + @param[in] StringId The identifier of the string to retrieved = from the string + package associated with HiiHandle. + + @retval NULL The string specified by StringId is not present in the st= ring package. + @retval Other The string was returned. + +**/ +CHAR8 * +HiiGetRedfishAsciiString ( + IN EFI_HII_HANDLE HiiHandle, + IN CHAR8 *Language, + IN EFI_STRING_ID StringId + ); + +/** + Get ASCII string from HII database in English language. The returned str= ing is allocated + using AllocatePool(). The caller is responsible for freeing the allocate= d buffer using + FreePool(). + + @param[in] HiiHandle A handle that was previously registered in= the HII Database. + @param[in] StringId The identifier of the string to retrieved = from the string + package associated with HiiHandle. + + @retval NULL The string specified by StringId is not present in the st= ring package. + @retval Other The string was returned. + +**/ +CHAR8 * +HiiGetEnglishAsciiString ( + IN EFI_HII_HANDLE HiiHandle, + IN EFI_STRING_ID StringId + ); + +/** + Release all resource in statement list. + + @param[in] StatementList Statement list to be released. + + @retval EFI_SUCCESS All resource are released. + @retval EFI_INVALID_PARAMETER StatementList is NULL. + +**/ +EFI_STATUS +ReleaseStatementList ( + IN REDFISH_PLATFORM_CONFIG_STATEMENT_PRIVATE_LIST *StatementList + ); + +#endif diff --git a/RedfishPkg/RedfishPlatformConfigDxe/RedfishPlatformConfigDxe.c= b/RedfishPkg/RedfishPlatformConfigDxe/RedfishPlatformConfigDxe.c new file mode 100644 index 000000000000..64f1d2e57cfb --- /dev/null +++ b/RedfishPkg/RedfishPlatformConfigDxe/RedfishPlatformConfigDxe.c @@ -0,0 +1,2495 @@ +/** @file + The implementation of EDKII Redfish Platform Config Protocol. + + (C) Copyright 2021-2022 Hewlett Packard Enterprise Development LP
+ Copyright (c) 2022-2023, NVIDIA CORPORATION & AFFILIATES. All rights res= erved. + + SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#include "RedfishPlatformConfigDxe.h" +#include "RedfishPlatformConfigImpl.h" + +REDFISH_PLATFORM_CONFIG_PRIVATE *mRedfishPlatformConfigPrivate =3D NULL; + +/** + Create a new stack instance with given stack size. + + @param[in] StackSize The size of stack. + + @retval REDFISH_STACK * Pointer to created stack. + @retval NULL Out of resource. + +**/ +REDFISH_STACK * +NewRedfishStack ( + IN UINTN StackSize + ) +{ + REDFISH_STACK *Buffer; + + if (StackSize =3D=3D 0) { + return NULL; + } + + Buffer =3D AllocateZeroPool (sizeof (REDFISH_STACK)); + if (Buffer =3D=3D NULL) { + return NULL; + } + + Buffer->Pool =3D AllocateZeroPool (sizeof (VOID *) * StackSize); + if (Buffer->Pool =3D=3D NULL) { + FreePool (Buffer); + return NULL; + } + + Buffer->Size =3D StackSize; + Buffer->Index =3D 0; + + return Buffer; +} + +/** + Release stack buffer. + + @param[in] Stack Pointer to stack instance. + +**/ +VOID +ReleaseRedfishStack ( + IN REDFISH_STACK *Stack + ) +{ + if (Stack =3D=3D NULL) { + return; + } + + FreePool (Stack->Pool); + FreePool (Stack); +} + +/** + Check and see if stack is empty or not. + + @param[in] Stack Pointer to stack instance. + + @retval TRUE Stack is empty. + @retval FALSE Stack is not empty. + +**/ +BOOLEAN +IsEmptyRedfishStack ( + IN REDFISH_STACK *Stack + ) +{ + return (Stack->Index =3D=3D 0); +} + +/** + Push an item to stack. + + @param[in] Stack Pointer to stack instance. + @param[in] Data Pointer to data. + + @retval EFI_OUT_OF_RESOURCES Stack is full. + @retval EFI_SUCCESS Item is pushed successfully. + +**/ +EFI_STATUS +PushRedfishStack ( + IN REDFISH_STACK *Stack, + IN VOID *Data + ) +{ + if (Stack->Index =3D=3D Stack->Size) { + return EFI_OUT_OF_RESOURCES; + } + + Stack->Pool[Stack->Index] =3D Data; + Stack->Index +=3D 1; + + return EFI_SUCCESS; +} + +/** + Pop an item from stack. + + @param[in] Stack Pointer to stack instance. + + @retval VOID * Pointer to popped item. + @retval NULL Stack is empty. + +**/ +VOID * +PopRedfishStack ( + IN REDFISH_STACK *Stack + ) +{ + if (IsEmptyRedfishStack (Stack)) { + return NULL; + } + + Stack->Index -=3D 1; + return Stack->Pool[Stack->Index]; +} + +/** + Seach forms in this HII package and find which form links to give form. + + @param[in] FormPrivate Pointer to form private instance. + + @retval REDFISH_PLATFORM_CONFIG_FORM_PRIVATE Pointer to target form + @retval NULL No form links to give form. + +**/ +REDFISH_PLATFORM_CONFIG_FORM_PRIVATE * +FindFormLinkToThis ( + IN REDFISH_PLATFORM_CONFIG_FORM_PRIVATE *FormPrivate + ) +{ + LIST_ENTRY *HiiFormLink; + LIST_ENTRY *HiiNextFormLink; + REDFISH_PLATFORM_CONFIG_FORM_PRIVATE *HiiFormPrivate; + LIST_ENTRY *HiiStatementLink; + LIST_ENTRY *HiiNextStatementLink; + REDFISH_PLATFORM_CONFIG_STATEMENT_PRIVATE *HiiStatementPrivate; + REDFISH_PLATFORM_CONFIG_FORM_SET_PRIVATE *HiiFormsetPrivate; + + if (FormPrivate =3D=3D NULL) { + return NULL; + } + + HiiFormsetPrivate =3D FormPrivate->ParentFormset; + + if (IsListEmpty (&HiiFormsetPrivate->HiiFormList)) { + return NULL; + } + + HiiFormLink =3D GetFirstNode (&HiiFormsetPrivate->HiiFormList); + while (!IsNull (&HiiFormsetPrivate->HiiFormList, HiiFormLink)) { + HiiFormPrivate =3D REDFISH_PLATFORM_CONFIG_FORM_FROM_LINK (HiiFormLin= k); + HiiNextFormLink =3D GetNextNode (&HiiFormsetPrivate->HiiFormList, HiiF= ormLink); + + // + // Skip myself + // + if (HiiFormPrivate =3D=3D FormPrivate) { + HiiFormLink =3D HiiNextFormLink; + continue; + } + + HiiStatementLink =3D GetFirstNode (&HiiFormPrivate->StatementList); + while (!IsNull (&HiiFormPrivate->StatementList, HiiStatementLink)) { + HiiStatementPrivate =3D REDFISH_PLATFORM_CONFIG_STATEMENT_FROM_LINK= (HiiStatementLink); + HiiNextStatementLink =3D GetNextNode (&HiiFormPrivate->StatementList= , HiiStatementLink); + + // + // Check go-to opcode and find form ID. If form ID is the same ID as= given form, + // this go-to opcode links to given form. + // + if ((HiiStatementPrivate->HiiStatement->Operand =3D=3D EFI_IFR_REF_O= P) && + (HiiStatementPrivate->HiiStatement->Value.Value.ref.FormId =3D= =3D FormPrivate->HiiForm->FormId)) + { + return HiiFormPrivate; + } + + HiiStatementLink =3D HiiNextStatementLink; + } + + HiiFormLink =3D HiiNextFormLink; + } + + return NULL; +} + +/** + Build the menu path to given statement instance. It is caller's + responsibility to free returned string buffer. + + @param[in] StatementPrivate Pointer to statement private instance. + + @retval CHAR8 * Menu path to given statement. + @retval NULL Can not find menu path. + +**/ +CHAR8 * +BuildMenPath ( + IN REDFISH_PLATFORM_CONFIG_STATEMENT_PRIVATE *StatementPrivate + ) +{ + REDFISH_STACK *FormStack; + REDFISH_PLATFORM_CONFIG_FORM_PRIVATE *FormPrivate; + UINTN OldBufferSize; + UINTN NewBufferSize; + CHAR8 *Buffer; + CHAR8 *FormTitle; + EFI_STATUS Status; + + Buffer =3D NULL; + OldBufferSize =3D 0; + NewBufferSize =3D 0; + FormStack =3D NewRedfishStack (REDFISH_MENU_PATH_SIZE); + if (FormStack =3D=3D NULL) { + return NULL; + } + + // + // Build form link stack + // + FormPrivate =3D StatementPrivate->ParentForm; + Status =3D PushRedfishStack (FormStack, (VOID *)FormPrivate); + if (EFI_ERROR (Status)) { + goto RELEASE; + } + + do { + DEBUG ((REDFISH_PLATFORM_CONFIG_DEBUG, "F(%d) <-", FormPrivate->Id)); + FormPrivate =3D FindFormLinkToThis (FormPrivate); + if (FormPrivate =3D=3D NULL) { + break; + } + + PushRedfishStack (FormStack, (VOID *)FormPrivate); + if (EFI_ERROR (Status)) { + break; + } + } while (TRUE); + + if (IsEmptyRedfishStack (FormStack)) { + goto RELEASE; + } + + // + // Initial Buffer to empty string for error case. + // + OldBufferSize =3D AsciiStrSize (""); + Buffer =3D AllocateCopyPool (OldBufferSize, ""); + if (Buffer =3D=3D NULL) { + goto RELEASE; + } + + // + // Build menu path in string format + // + FormPrivate =3D (REDFISH_PLATFORM_CONFIG_FORM_PRIVATE *)PopRedfishStack = (FormStack); + while (FormPrivate !=3D NULL) { + FormTitle =3D HiiGetEnglishAsciiString (FormPrivate->ParentFormset->Hi= iHandle, FormPrivate->Title); + if (FormTitle !=3D NULL) { + NewBufferSize =3D AsciiStrSize (FormTitle) + OldBufferSize; + Buffer =3D ReallocatePool (OldBufferSize, NewBufferSize, Buff= er); + if (Buffer =3D=3D NULL) { + goto RELEASE; + } + + OldBufferSize =3D NewBufferSize; + AsciiStrCatS (Buffer, OldBufferSize, "/"); + AsciiStrCatS (Buffer, OldBufferSize, FormTitle); + FreePool (FormTitle); + DEBUG ((REDFISH_PLATFORM_CONFIG_DEBUG, " %a\n", Buffer)); + } + + FormPrivate =3D (REDFISH_PLATFORM_CONFIG_FORM_PRIVATE *)PopRedfishStac= k (FormStack); + } + +RELEASE: + + ReleaseRedfishStack (FormStack); + + return Buffer; +} + +/** + Get the attribute name from config language. + + For example: /Bios/Attributes/BiosOption1 is config language + and attribute name is BiosOption1. + + @param[in] ConfigLanguage Config language string. + + @retval CHAR8 * Attribute name string. + @retval NULL Can not find attribute name. + +**/ +CHAR8 * +GetAttributeNameFromConfigLanguage ( + IN CHAR8 *ConfigLanguage + ) +{ + CHAR8 *attributeName; + CHAR8 *Pointer; + UINTN StrLen; + UINTN Index; + UINTN AttrStrLen; + + if (IS_EMPTY_STRING (ConfigLanguage)) { + return NULL; + } + + attributeName =3D NULL; + Pointer =3D NULL; + AttrStrLen =3D 0; + StrLen =3D AsciiStrLen (ConfigLanguage); + + if (ConfigLanguage[StrLen - 1] =3D=3D '/') { + // + // wrong format + // + DEBUG ((DEBUG_ERROR, "%a, invalid format: %a\n", __FUNCTION__, ConfigL= anguage)); + ASSERT (FALSE); + return NULL; + } + + Index =3D StrLen; + while (TRUE) { + Index -=3D 1; + + if (ConfigLanguage[Index] =3D=3D '/') { + Pointer =3D &ConfigLanguage[Index + 1]; + break; + } + + if (Index =3D=3D 0) { + break; + } + } + + // + // Not found. There is no '/' in input string. + // + if (Pointer =3D=3D NULL) { + return NULL; + } + + AttrStrLen =3D StrLen - Index; + attributeName =3D AllocateCopyPool (AttrStrLen, Pointer); + + return attributeName; +} + +/** + Convert one-of options to string array in Redfish attribute. + + @param[in] HiiHandle HII handle. + @param[in] SchemaName Schema string. + @param[in] StatementPrivate Pointer to statement instance. + @param[out] Values Attribute value array. + + @retval EFI_SUCCESS Options are converted successfully. + @retval Other Error occurs. + +**/ +EFI_STATUS +OneOfStatementToAttributeValues ( + IN EFI_HII_HANDLE HiiHandle, + IN CHAR8 *SchemaName, + IN REDFISH_PLATFORM_CONFIG_STATEMENT_PRIVATE *StatementPrivate, + OUT EDKII_REDFISH_POSSIBLE_VALUES *Values + ) +{ + LIST_ENTRY *Link; + HII_QUESTION_OPTION *Option; + UINTN Index; + HII_STATEMENT *HiiStatement; + + if ((HiiHandle =3D=3D NULL) || (StatementPrivate =3D=3D NULL) || (Values= =3D=3D NULL)) { + return EFI_INVALID_PARAMETER; + } + + HiiStatement =3D StatementPrivate->HiiStatement; + ASSERT (HiiStatement !=3D NULL); + + if (IsListEmpty (&HiiStatement->OptionListHead)) { + return EFI_NOT_FOUND; + } + + // + // Loop through the option to get count + // + Values->ValueCount =3D 0; + Link =3D GetFirstNode (&HiiStatement->OptionListHead); + while (!IsNull (&HiiStatement->OptionListHead, Link)) { + Option =3D HII_QUESTION_OPTION_FROM_LINK (Link); + + if ((Option->SuppressExpression !=3D NULL) && + (EvaluateExpressionList (Option->SuppressExpression, TRUE, Stateme= ntPrivate->ParentForm->ParentFormset->HiiFormSet, StatementPrivate->ParentF= orm->HiiForm) !=3D ExpressFalse)) + { + Link =3D GetNextNode (&HiiStatement->OptionListHead, Link); + continue; + } + + Values->ValueCount +=3D 1; + Link =3D GetNextNode (&HiiStatement->OptionListHead, Li= nk); + } + + Values->ValueArray =3D AllocateZeroPool (sizeof (EDKII_REDFISH_ATTRIBUTE= _VALUE) * Values->ValueCount); + if (Values->ValueArray =3D=3D NULL) { + Values->ValueCount =3D 0; + return EFI_OUT_OF_RESOURCES; + } + + Index =3D 0; + Link =3D GetFirstNode (&HiiStatement->OptionListHead); + while (!IsNull (&HiiStatement->OptionListHead, Link)) { + Option =3D HII_QUESTION_OPTION_FROM_LINK (Link); + + if ((Option->SuppressExpression !=3D NULL) && + (EvaluateExpressionList (Option->SuppressExpression, FALSE, NULL, = NULL) !=3D ExpressFalse)) + { + Link =3D GetNextNode (&HiiStatement->OptionListHead, Link); + continue; + } + + if (Option->Text !=3D 0) { + Values->ValueArray[Index].ValueName =3D HiiGetRedfishAsciiStr= ing (HiiHandle, SchemaName, Option->Text); + Values->ValueArray[Index].ValueDisplayName =3D HiiGetEnglishAsciiStr= ing (HiiHandle, Option->Text); + } + + Index +=3D 1; + Link =3D GetNextNode (&HiiStatement->OptionListHead, Link); + } + + return EFI_SUCCESS; +} + +/** + Return Redfish attribute type from given HII statement operand. + + @param[in] HiiStatement Target HII statement. + + @retval EDKII_REDFISH_ATTRIBUTE_TYPES Attribute type. + +**/ +EDKII_REDFISH_ATTRIBUTE_TYPES +HiiStatementToAttributeType ( + IN HII_STATEMENT *HiiStatement + ) +{ + EDKII_REDFISH_ATTRIBUTE_TYPES type; + + if (HiiStatement =3D=3D NULL) { + return RedfishAttributeTypeUnknown; + } + + type =3D RedfishAttributeTypeUnknown; + switch (HiiStatement->Operand) { + case EFI_IFR_ONE_OF_OP: + case EFI_IFR_ORDERED_LIST_OP: + type =3D RedfishAttributeTypeEnumeration; + break; + case EFI_IFR_STRING_OP: + type =3D RedfishAttributeTypeString; + break; + case EFI_IFR_NUMERIC_OP: + type =3D RedfishAttributeTypeInteger; + break; + case EFI_IFR_CHECKBOX_OP: + type =3D RedfishAttributeTypeBoolean; + break; + case EFI_IFR_DATE_OP: + case EFI_IFR_TIME_OP: + default: + DEBUG ((DEBUG_ERROR, "%a, unsupported operand: 0x%x\n", __FUNCTION__= , HiiStatement->Operand)); + break; + } + + return type; +} + +/** + Zero extend integer/boolean to UINT64 for comparing. + + @param Value HII Value to be converted. + +**/ +UINT64 +ExtendHiiValueToU64 ( + IN HII_STATEMENT_VALUE *Value + ) +{ + UINT64 Temp; + + Temp =3D 0; + switch (Value->Type) { + case EFI_IFR_TYPE_NUM_SIZE_8: + Temp =3D Value->Value.u8; + break; + + case EFI_IFR_TYPE_NUM_SIZE_16: + Temp =3D Value->Value.u16; + break; + + case EFI_IFR_TYPE_NUM_SIZE_32: + Temp =3D Value->Value.u32; + break; + + case EFI_IFR_TYPE_BOOLEAN: + Temp =3D Value->Value.b; + break; + + case EFI_IFR_TYPE_TIME: + case EFI_IFR_TYPE_DATE: + default: + break; + } + + return Temp; +} + +/** + Set value of a data element in an Array by its Index in ordered list buf= fer. + + @param Array The data array. + @param Type Type of the data in this array. + @param Index Zero based index for data in this array. + @param Value The value to be set. + +**/ +VOID +OrderedListSetArrayData ( + IN VOID *Array, + IN UINT8 Type, + IN UINTN Index, + IN UINT64 Value + ) +{ + ASSERT (Array !=3D NULL); + + switch (Type) { + case EFI_IFR_TYPE_NUM_SIZE_8: + *(((UINT8 *)Array) + Index) =3D (UINT8)Value; + break; + + case EFI_IFR_TYPE_NUM_SIZE_16: + *(((UINT16 *)Array) + Index) =3D (UINT16)Value; + break; + + case EFI_IFR_TYPE_NUM_SIZE_32: + *(((UINT32 *)Array) + Index) =3D (UINT32)Value; + break; + + case EFI_IFR_TYPE_NUM_SIZE_64: + *(((UINT64 *)Array) + Index) =3D (UINT64)Value; + break; + + default: + break; + } +} + +/** + Return data element in an Array by its Index in ordered list array buffe= r. + + @param Array The data array. + @param Type Type of the data in this array. + @param Index Zero based index for data in this array. + + @retval Value The data to be returned + +**/ +UINT64 +OrderedListGetArrayData ( + IN VOID *Array, + IN UINT8 Type, + IN UINTN Index + ) +{ + UINT64 Data; + + ASSERT (Array !=3D NULL); + + Data =3D 0; + switch (Type) { + case EFI_IFR_TYPE_NUM_SIZE_8: + Data =3D (UINT64)*(((UINT8 *)Array) + Index); + break; + + case EFI_IFR_TYPE_NUM_SIZE_16: + Data =3D (UINT64)*(((UINT16 *)Array) + Index); + break; + + case EFI_IFR_TYPE_NUM_SIZE_32: + Data =3D (UINT64)*(((UINT32 *)Array) + Index); + break; + + case EFI_IFR_TYPE_NUM_SIZE_64: + Data =3D (UINT64)*(((UINT64 *)Array) + Index); + break; + + default: + break; + } + + return Data; +} + +/** + Find string ID of option if its value equals to given value. + + @param[in] HiiStatement Statement to search. + @param[in] Value Target value. + + @retval EFI_SUCCESS HII value is returned successfully. + @retval Others Errors occur + +**/ +EFI_STRING_ID +OrderedListOptionValueToStringId ( + IN HII_STATEMENT *HiiStatement, + IN UINT64 Value + ) +{ + LIST_ENTRY *Link; + HII_QUESTION_OPTION *Option; + UINT64 CurrentValue; + + if (HiiStatement =3D=3D NULL) { + return 0; + } + + if (HiiStatement->Operand !=3D EFI_IFR_ORDERED_LIST_OP) { + return 0; + } + + if (IsListEmpty (&HiiStatement->OptionListHead)) { + return 0; + } + + Link =3D GetFirstNode (&HiiStatement->OptionListHead); + while (!IsNull (&HiiStatement->OptionListHead, Link)) { + Option =3D HII_QUESTION_OPTION_FROM_LINK (Link); + + CurrentValue =3D ExtendHiiValueToU64 (&Option->Value); + if (Value =3D=3D CurrentValue) { + return Option->Text; + } + + Link =3D GetNextNode (&HiiStatement->OptionListHead, Link); + } + + return 0; +} + +/** + Compare two value in HII statement format. + + @param[in] Value1 First value to compare. + @param[in] Value2 Second value to be compared. + + @retval INTN 0 is returned when two values are equal. + 1 is returned when first value is greater than sec= ond value. + -1 is returned when second value is greater than f= irst value. + +**/ +INTN +CompareHiiStatementValue ( + IN HII_STATEMENT_VALUE *Value1, + IN HII_STATEMENT_VALUE *Value2 + ) +{ + INTN Result; + UINT64 Data1; + UINT64 Data2; + + if ((Value1 =3D=3D NULL) || (Value2 =3D=3D NULL)) { + return -1; + } + + switch (Value1->Type) { + case EFI_IFR_TYPE_NUM_SIZE_8: + Data1 =3D Value1->Value.u8; + break; + case EFI_IFR_TYPE_NUM_SIZE_16: + Data1 =3D Value1->Value.u16; + break; + case EFI_IFR_TYPE_NUM_SIZE_32: + Data1 =3D Value1->Value.u32; + break; + case EFI_IFR_TYPE_NUM_SIZE_64: + Data1 =3D Value1->Value.u64; + break; + case EFI_IFR_TYPE_BOOLEAN: + Data1 =3D (Value1->Value.b ? 1 : 0); + break; + default: + return -1; + } + + switch (Value2->Type) { + case EFI_IFR_TYPE_NUM_SIZE_8: + Data2 =3D Value2->Value.u8; + break; + case EFI_IFR_TYPE_NUM_SIZE_16: + Data2 =3D Value2->Value.u16; + break; + case EFI_IFR_TYPE_NUM_SIZE_32: + Data2 =3D Value2->Value.u32; + break; + case EFI_IFR_TYPE_NUM_SIZE_64: + Data2 =3D Value2->Value.u64; + break; + case EFI_IFR_TYPE_BOOLEAN: + Data2 =3D (Value2->Value.b ? 1 : 0); + break; + default: + return -1; + } + + Result =3D (Data1 =3D=3D Data2 ? 0 : (Data1 > Data2 ? 1 : -1)); + + return Result; +} + +/** + Convert HII value to the string in HII one-of opcode. + + @param[in] HiiStatement HII Statement private instance + @param[in] Value HII Statement value + + @retval EFI_STRING_ID The string ID in HII database. + 0 is returned when something goes wrong. + +**/ +EFI_STRING_ID +HiiValueToOneOfOptionStringId ( + IN HII_STATEMENT *HiiStatement, + IN HII_STATEMENT_VALUE *Value + ) +{ + LIST_ENTRY *Link; + HII_QUESTION_OPTION *Option; + + if ((HiiStatement =3D=3D NULL) || (Value =3D=3D NULL)) { + return 0; + } + + if (HiiStatement->Operand !=3D EFI_IFR_ONE_OF_OP) { + return 0; + } + + if (IsListEmpty (&HiiStatement->OptionListHead)) { + return 0; + } + + Link =3D GetFirstNode (&HiiStatement->OptionListHead); + while (!IsNull (&HiiStatement->OptionListHead, Link)) { + Option =3D HII_QUESTION_OPTION_FROM_LINK (Link); + + if (CompareHiiStatementValue (Value, &Option->Value) =3D=3D 0) { + return Option->Text; + } + + Link =3D GetNextNode (&HiiStatement->OptionListHead, Link); + } + + return 0; +} + +/** + Convert HII string to the value in HII one-of opcode. + + @param[in] Statement Statement private instance + @param[in] Schema Schema string + @param[in] HiiString Input string + @param[out] Value Value returned + + @retval EFI_SUCCESS HII value is returned successfully. + @retval Others Errors occur + +**/ +EFI_STATUS +HiiStringToOneOfOptionValue ( + IN REDFISH_PLATFORM_CONFIG_STATEMENT_PRIVATE *Statement, + IN CHAR8 *Schema, + IN EFI_STRING HiiString, + OUT HII_STATEMENT_VALUE *Value + ) +{ + LIST_ENTRY *Link; + HII_QUESTION_OPTION *Option; + EFI_STRING TmpString; + BOOLEAN Found; + + if ((Statement =3D=3D NULL) || IS_EMPTY_STRING (HiiString) || (Value =3D= =3D NULL)) { + return EFI_INVALID_PARAMETER; + } + + if (Statement->HiiStatement->Operand !=3D EFI_IFR_ONE_OF_OP) { + return EFI_UNSUPPORTED; + } + + if (IsListEmpty (&Statement->HiiStatement->OptionListHead)) { + return EFI_NOT_FOUND; + } + + Found =3D FALSE; + Link =3D GetFirstNode (&Statement->HiiStatement->OptionListHead); + while (!IsNull (&Statement->HiiStatement->OptionListHead, Link)) { + Option =3D HII_QUESTION_OPTION_FROM_LINK (Link); + + TmpString =3D HiiGetRedfishString (Statement->ParentForm->ParentFormse= t->HiiHandle, Schema, Option->Text); + if (TmpString !=3D NULL) { + if (StrCmp (TmpString, HiiString) =3D=3D 0) { + CopyMem (Value, &Option->Value, sizeof (HII_STATEMENT_VALUE)); + Found =3D TRUE; + } + + FreePool (TmpString); + } + + if (Found) { + return EFI_SUCCESS; + } + + Link =3D GetNextNode (&Statement->HiiStatement->OptionListHead, Link); + } + + return EFI_NOT_FOUND; +} + +/** + Convert HII value to numeric value in Redfish format. + + @param[in] Value Value to be converted. + @param[out] RedfishValue Value in Redfish format. + + @retval EFI_SUCCESS Redfish value is returned successfully. + @retval Others Errors occur + +**/ +EFI_STATUS +HiiValueToRedfishNumeric ( + IN HII_STATEMENT_VALUE *Value, + OUT EDKII_REDFISH_VALUE *RedfishValue + ) +{ + if ((Value =3D=3D NULL) || (RedfishValue =3D=3D NULL)) { + return EFI_INVALID_PARAMETER; + } + + switch (Value->Type) { + case EFI_IFR_TYPE_NUM_SIZE_8: + RedfishValue->Type =3D RedfishValueTypeInteger; + RedfishValue->Value.Integer =3D (INT64)Value->Value.u8; + break; + case EFI_IFR_TYPE_NUM_SIZE_16: + RedfishValue->Type =3D RedfishValueTypeInteger; + RedfishValue->Value.Integer =3D (INT64)Value->Value.u16; + break; + case EFI_IFR_TYPE_NUM_SIZE_32: + RedfishValue->Type =3D RedfishValueTypeInteger; + RedfishValue->Value.Integer =3D (INT64)Value->Value.u32; + break; + case EFI_IFR_TYPE_NUM_SIZE_64: + RedfishValue->Type =3D RedfishValueTypeInteger; + RedfishValue->Value.Integer =3D (INT64)Value->Value.u64; + break; + case EFI_IFR_TYPE_BOOLEAN: + RedfishValue->Type =3D RedfishValueTypeBoolean; + RedfishValue->Value.Boolean =3D Value->Value.b; + break; + default: + RedfishValue->Type =3D RedfishValueTypeUnknown; + break; + } + + return EFI_SUCCESS; +} + +/** + Convert numeric value in Redfish format to HII value. + + @param[in] RedfishValue Value in Redfish format to be converted. + @param[out] Value HII value returned. + + @retval EFI_SUCCESS HII value is returned successfully. + @retval Others Errors occur + +**/ +EFI_STATUS +RedfishNumericToHiiValue ( + IN EDKII_REDFISH_VALUE *RedfishValue, + OUT HII_STATEMENT_VALUE *Value + ) +{ + if ((Value =3D=3D NULL) || (RedfishValue =3D=3D NULL)) { + return EFI_INVALID_PARAMETER; + } + + switch (RedfishValue->Type) { + case RedfishValueTypeInteger: + Value->Type =3D EFI_IFR_TYPE_NUM_SIZE_64; + Value->Value.u64 =3D (UINT64)RedfishValue->Value.Integer; + break; + case RedfishValueTypeBoolean: + Value->Type =3D EFI_IFR_TYPE_BOOLEAN; + Value->Value.b =3D RedfishValue->Value.Boolean; + break; + default: + Value->Type =3D EFI_IFR_TYPE_UNDEFINED; + break; + } + + return EFI_SUCCESS; +} + +/** + Dump the value in ordered list buffer. + + @param[in] OrderedListStatement Ordered list statement. + +**/ +VOID +DumpOrderedListValue ( + IN HII_STATEMENT *OrderedListStatement + ) +{ + UINT8 *Value8; + UINT16 *Value16; + UINT32 *Value32; + UINT64 *Value64; + UINTN Count; + UINTN Index; + + if ((OrderedListStatement =3D=3D NULL) || (OrderedListStatement->Operand= !=3D EFI_IFR_ORDERED_LIST_OP)) { + return; + } + + DEBUG ((DEBUG_ERROR, "Value.Type=3D 0x%x\n", OrderedListStatement->Value= .Type)); + DEBUG ((DEBUG_ERROR, "Value.BufferValueType=3D 0x%x\n", OrderedListState= ment->Value.BufferValueType)); + DEBUG ((DEBUG_ERROR, "Value.BufferLen=3D 0x%x\n", OrderedListStatement->= Value.BufferLen)); + DEBUG ((DEBUG_ERROR, "Value.Buffer=3D 0x%x\n", OrderedListStatement->Val= ue.Buffer)); + DEBUG ((DEBUG_ERROR, "Value.MaxContainers=3D 0x%x\n", OrderedListStateme= nt->ExtraData.OrderListData.MaxContainers)); + DEBUG ((DEBUG_ERROR, "StorageWidth=3D 0x%x\n", OrderedListStatement->Sto= rageWidth)); + + if (OrderedListStatement->Value.Buffer =3D=3D NULL) { + return; + } + + Value8 =3D NULL; + Value16 =3D NULL; + Value32 =3D NULL; + Value64 =3D NULL; + Count =3D 0; + + switch (OrderedListStatement->Value.BufferValueType) { + case EFI_IFR_TYPE_NUM_SIZE_8: + Value8 =3D (UINT8 *)OrderedListStatement->Value.Buffer; + Count =3D OrderedListStatement->StorageWidth / sizeof (UINT8); + for (Index =3D 0; Index < Count; Index++) { + DEBUG ((DEBUG_ERROR, "%d ", Value8[Index])); + } + + break; + case EFI_IFR_TYPE_NUM_SIZE_16: + Value16 =3D (UINT16 *)OrderedListStatement->Value.Buffer; + Count =3D OrderedListStatement->StorageWidth / sizeof (UINT16); + for (Index =3D 0; Index < Count; Index++) { + DEBUG ((DEBUG_ERROR, "%d ", Value16[Index])); + } + + break; + case EFI_IFR_TYPE_NUM_SIZE_32: + Value32 =3D (UINT32 *)OrderedListStatement->Value.Buffer; + Count =3D OrderedListStatement->StorageWidth / sizeof (UINT32); + for (Index =3D 0; Index < Count; Index++) { + DEBUG ((DEBUG_ERROR, "%d ", Value32[Index])); + } + + break; + case EFI_IFR_TYPE_NUM_SIZE_64: + Value64 =3D (UINT64 *)OrderedListStatement->Value.Buffer; + Count =3D OrderedListStatement->StorageWidth / sizeof (UINT64); + for (Index =3D 0; Index < Count; Index++) { + DEBUG ((DEBUG_ERROR, "%d ", Value64[Index])); + } + + break; + default: + Value8 =3D (UINT8 *)OrderedListStatement->Value.Buffer; + Count =3D OrderedListStatement->StorageWidth / sizeof (UINT8); + for (Index =3D 0; Index < Count; Index++) { + DEBUG ((DEBUG_ERROR, "%d ", Value8[Index])); + } + + break; + } + + DEBUG ((DEBUG_ERROR, "\n")); +} + +/** + Convert HII value to the string in HII ordered list opcode. It's caller'= s + responsibility to free returned buffer using FreePool(). + + @param[in] HiiStatement HII Statement private instance + @param[out] ReturnSize The size of returned array + + @retval EFI_STRING_ID The string ID array for options in ordered lis= t. + +**/ +EFI_STRING_ID * +HiiValueToOrderedListOptionStringId ( + IN HII_STATEMENT *HiiStatement, + OUT UINTN *ReturnSize + ) +{ + LIST_ENTRY *Link; + UINTN OptionCount; + EFI_STRING_ID *ReturnedArray; + UINTN Index; + UINT64 Value; + + if ((HiiStatement =3D=3D NULL) || (ReturnSize =3D=3D NULL)) { + return NULL; + } + + *ReturnSize =3D 0; + + if (HiiStatement->Operand !=3D EFI_IFR_ORDERED_LIST_OP) { + return NULL; + } + + if (IsListEmpty (&HiiStatement->OptionListHead)) { + return NULL; + } + + DEBUG_CODE ( + DumpOrderedListValue (HiiStatement); + ); + + OptionCount =3D 0; + Link =3D GetFirstNode (&HiiStatement->OptionListHead); + while (!IsNull (&HiiStatement->OptionListHead, Link)) { + ++OptionCount; + Link =3D GetNextNode (&HiiStatement->OptionListHead, Link); + } + + *ReturnSize =3D OptionCount; + ReturnedArray =3D AllocatePool (sizeof (EFI_STRING_ID) * OptionCount); + if (ReturnedArray =3D=3D NULL) { + DEBUG ((DEBUG_ERROR, "%a, out of resource\n", __FUNCTION__)); + *ReturnSize =3D 0; + return NULL; + } + + for (Index =3D 0; Index < OptionCount; Index++) { + Value =3D OrderedListGetArrayData (HiiStatement->Value.= Buffer, HiiStatement->Value.BufferValueType, Index); + ReturnedArray[Index] =3D OrderedListOptionValueToStringId (HiiStatemen= t, Value); + } + + return ReturnedArray; +} + +/** + Convert HII string to the value in HII ordered list opcode. + + @param[in] Statement Statement private instance + @param[in] Schema Schema string + @param[in] HiiString Input string + @param[out] Value Value returned + + @retval EFI_SUCCESS HII value is returned successfully. + @retval Others Errors occur + +**/ +EFI_STATUS +HiiStringToOrderedListOptionValue ( + IN REDFISH_PLATFORM_CONFIG_STATEMENT_PRIVATE *Statement, + IN CHAR8 *Schema, + IN EFI_STRING HiiString, + OUT UINT64 *Value + ) +{ + LIST_ENTRY *Link; + HII_QUESTION_OPTION *Option; + EFI_STRING TmpString; + BOOLEAN Found; + + if ((Statement =3D=3D NULL) || IS_EMPTY_STRING (HiiString) || (Value =3D= =3D NULL)) { + return EFI_INVALID_PARAMETER; + } + + *Value =3D 0; + + if (Statement->HiiStatement->Operand !=3D EFI_IFR_ORDERED_LIST_OP) { + return EFI_UNSUPPORTED; + } + + if (IsListEmpty (&Statement->HiiStatement->OptionListHead)) { + return EFI_NOT_FOUND; + } + + Found =3D FALSE; + Link =3D GetFirstNode (&Statement->HiiStatement->OptionListHead); + while (!IsNull (&Statement->HiiStatement->OptionListHead, Link)) { + Option =3D HII_QUESTION_OPTION_FROM_LINK (Link); + + TmpString =3D HiiGetRedfishString (Statement->ParentForm->ParentFormse= t->HiiHandle, Schema, Option->Text); + if (TmpString !=3D NULL) { + if (StrCmp (TmpString, HiiString) =3D=3D 0) { + *Value =3D ExtendHiiValueToU64 (&Option->Value); + Found =3D TRUE; + } + + FreePool (TmpString); + } + + if (Found) { + return EFI_SUCCESS; + } + + Link =3D GetNextNode (&Statement->HiiStatement->OptionListHead, Link); + } + + return EFI_NOT_FOUND; +} + +/** + Convert HII value to Redfish value. + + @param[in] HiiHandle HII handle. + @param[in] FullSchema Schema string. + @param[in] HiiStatement HII statement. + @param[in] Value Value to be converted. + @param[out] RedfishValue Value in Redfish format. + + @retval EFI_SUCCESS Redfish value is returned successfully. + @retval Others Errors occur + +**/ +EFI_STATUS +HiiValueToRedfishValue ( + IN EFI_HII_HANDLE HiiHandle, + IN CHAR8 *FullSchema, + IN HII_STATEMENT *HiiStatement, + IN HII_STATEMENT_VALUE *Value, + OUT EDKII_REDFISH_VALUE *RedfishValue + ) +{ + EFI_STATUS Status; + EFI_STRING_ID StringId; + UINTN Index; + UINTN Count; + EFI_STRING_ID *StringIdArray; + + if ((HiiHandle =3D=3D NULL) || (HiiStatement =3D=3D NULL) || (Value =3D= =3D NULL) || (RedfishValue =3D=3D NULL) || IS_EMPTY_STRING (FullSchema)) { + return EFI_INVALID_PARAMETER; + } + + StringIdArray =3D NULL; + Count =3D 0; + Status =3D EFI_SUCCESS; + + switch (HiiStatement->Operand) { + case EFI_IFR_ONE_OF_OP: + StringId =3D HiiValueToOneOfOptionStringId (HiiStatement, Value); + if (StringId =3D=3D 0) { + ASSERT (FALSE); + Status =3D EFI_DEVICE_ERROR; + break; + } + + RedfishValue->Value.Buffer =3D HiiGetRedfishAsciiString (HiiHandle, = FullSchema, StringId); + if (RedfishValue->Value.Buffer =3D=3D NULL) { + Status =3D EFI_OUT_OF_RESOURCES; + break; + } + + RedfishValue->Type =3D RedfishValueTypeString; + break; + case EFI_IFR_STRING_OP: + if (Value->Type !=3D EFI_IFR_TYPE_STRING) { + ASSERT (FALSE); + Status =3D EFI_DEVICE_ERROR; + break; + } + + RedfishValue->Type =3D RedfishValueTypeString; + RedfishValue->Value.Buffer =3D AllocatePool (StrLen ((CHAR16 *)Value= ->Buffer) + 1); + UnicodeStrToAsciiStrS ((CHAR16 *)Value->Buffer, RedfishValue->Value.= Buffer, StrLen ((CHAR16 *)Value->Buffer) + 1); + break; + case EFI_IFR_CHECKBOX_OP: + case EFI_IFR_NUMERIC_OP: + Status =3D HiiValueToRedfishNumeric (Value, RedfishValue); + if (EFI_ERROR (Status)) { + DEBUG ((DEBUG_ERROR, "%a, failed to convert HII value to Redfish v= alue: %r\n", __FUNCTION__, Status)); + break; + } + + break; + case EFI_IFR_ACTION_OP: + if (Value->Type !=3D EFI_IFR_TYPE_ACTION) { + ASSERT (FALSE); + Status =3D EFI_DEVICE_ERROR; + break; + } + + // + // Action has no value. Just return unknown type. + // + RedfishValue->Type =3D RedfishValueTypeUnknown; + break; + case EFI_IFR_ORDERED_LIST_OP: + StringIdArray =3D HiiValueToOrderedListOptionStringId (HiiStatement,= &Count); + if (StringIdArray =3D=3D NULL) { + ASSERT (FALSE); + Status =3D EFI_DEVICE_ERROR; + break; + } + + RedfishValue->Value.StringArray =3D AllocatePool (sizeof (CHAR8 *) *= Count); + if (RedfishValue->Value.StringArray =3D=3D NULL) { + ASSERT (FALSE); + Status =3D EFI_OUT_OF_RESOURCES; + break; + } + + for (Index =3D 0; Index < Count; Index++) { + ASSERT (StringIdArray[Index] !=3D 0); + RedfishValue->Value.StringArray[Index] =3D HiiGetRedfishAsciiStrin= g (HiiHandle, FullSchema, StringIdArray[Index]); + ASSERT (RedfishValue->Value.StringArray[Index] !=3D NULL); + } + + RedfishValue->ArrayCount =3D Count; + RedfishValue->Type =3D RedfishValueTypeStringArray; + + FreePool (StringIdArray); + break; + default: + DEBUG ((DEBUG_ERROR, "%a, catch unsupported type: 0x%x! Please conta= ct with author if we need to support this type.\n", __FUNCTION__, HiiStatem= ent->Operand)); + ASSERT (FALSE); + Status =3D EFI_UNSUPPORTED; + break; + } + + return Status; +} + +/** + Convert input ascii string to unicode string. It's caller's + responsibility to free returned buffer using FreePool(). + + @param[in] AsciiString Ascii string to be converted. + + @retval CHAR16 * Unicode string on return. + +**/ +EFI_STRING +StrToUnicodeStr ( + IN CHAR8 *AsciiString + ) +{ + UINTN StringLen; + EFI_STRING Buffer; + EFI_STATUS Status; + + if ((AsciiString =3D=3D NULL) || (AsciiString[0] =3D=3D '\0')) { + return NULL; + } + + StringLen =3D AsciiStrLen (AsciiString) + 1; + Buffer =3D AllocatePool (StringLen * sizeof (CHAR16)); + if (Buffer =3D=3D NULL) { + return NULL; + } + + Status =3D AsciiStrToUnicodeStrS (AsciiString, Buffer, StringLen); + if (EFI_ERROR (Status)) { + FreePool (Buffer); + return NULL; + } + + return Buffer; +} + +/** + Return the full Redfish schema string from the given Schema and Version. + + Returned schema string is: Schema + '.' + Version + + @param[in] Schema Schema string + @param[in] Version Schema version string + + @retval CHAR8 * Schema string. NULL when errors occur. + +**/ +CHAR8 * +GetFullSchemaString ( + IN CHAR8 *Schema, + IN CHAR8 *Version + ) +{ + UINTN Size; + CHAR8 *FullName; + + if (IS_EMPTY_STRING (Schema) || IS_EMPTY_STRING (Version)) { + return NULL; + } + + Size =3D AsciiStrSize (CONFIGURE_LANGUAGE_PREFIX) + AsciiStrSize (Schema= ) + AsciiStrSize (Version); + + FullName =3D AllocatePool (Size); + if (FullName =3D=3D NULL) { + DEBUG ((DEBUG_ERROR, "%a, out-of-resource\n", __FUNCTION__)); + return NULL; + } + + AsciiSPrint (FullName, Size, "%a%a.%a", CONFIGURE_LANGUAGE_PREFIX, Schem= a, Version); + + return FullName; +} + +/** + Common implementation to get statement private instance. + + @param[in] RedfishPlatformConfigPrivate Private instance. + @param[in] Schema Redfish schema string. + @param[in] ConfigureLang Configure language that refe= rs to this statement. + @param[out] Statement Statement instance + + @retval EFI_SUCCESS HII value is returned successfully. + @retval Others Errors occur + +**/ +EFI_STATUS +RedfishPlatformConfigGetStatementCommon ( + IN REDFISH_PLATFORM_CONFIG_PRIVATE *RedfishPlatformConfig= Private, + IN CHAR8 *Schema, + IN EFI_STRING ConfigureLang, + OUT REDFISH_PLATFORM_CONFIG_STATEMENT_PRIVATE **Statement + ) +{ + EFI_STATUS Status; + REDFISH_PLATFORM_CONFIG_STATEMENT_PRIVATE *TargetStatement; + + if ((RedfishPlatformConfigPrivate =3D=3D NULL) || IS_EMPTY_STRING (Schem= a) || IS_EMPTY_STRING (ConfigureLang) || (Statement =3D=3D NULL)) { + return EFI_INVALID_PARAMETER; + } + + *Statement =3D NULL; + + Status =3D ProcessPendingList (&RedfishPlatformConfigPrivate->FormsetLis= t, &RedfishPlatformConfigPrivate->PendingList); + if (EFI_ERROR (Status)) { + DEBUG ((DEBUG_ERROR, "%a, ProcessPendingList failure: %r\n", __FUNCTIO= N__, Status)); + return Status; + } + + TargetStatement =3D GetStatementPrivateByConfigureLang (&RedfishPlatform= ConfigPrivate->FormsetList, Schema, ConfigureLang); + if (TargetStatement =3D=3D NULL) { + DEBUG ((DEBUG_ERROR, "%a, No match HII statement is found by the given= %s in schema %a\n", __FUNCTION__, ConfigureLang, Schema)); + return EFI_NOT_FOUND; + } + + // + // Find current HII question value. + // + Status =3D GetQuestionValue ( + TargetStatement->ParentForm->ParentFormset->HiiFormSet, + TargetStatement->ParentForm->HiiForm, + TargetStatement->HiiStatement, + GetSetValueWithHiiDriver + ); + if (EFI_ERROR (Status)) { + DEBUG ((DEBUG_ERROR, "%a, failed to get question current value: %r\n",= __FUNCTION__, Status)); + return Status; + } + + if (TargetStatement->HiiStatement->Value.Type =3D=3D EFI_IFR_TYPE_UNDEFI= NED) { + return EFI_DEVICE_ERROR; + } + + // + // Return Value. + // + *Statement =3D TargetStatement; + + return EFI_SUCCESS; +} + +/** + Get Redfish value with the given Schema and Configure Language. + + @param[in] This Pointer to EDKII_REDFISH_PLATFORM_CONFI= G_PROTOCOL instance. + @param[in] Schema The Redfish schema to query. + @param[in] Version The Redfish version to query. + @param[in] ConfigureLang The target value which match this confi= gure Language. + @param[out] Value The returned value. + + @retval EFI_SUCCESS Value is returned successfully. + @retval Others Some error happened. + +**/ +EFI_STATUS +EFIAPI +RedfishPlatformConfigProtocolGetValue ( + IN EDKII_REDFISH_PLATFORM_CONFIG_PROTOCOL *This, + IN CHAR8 *Schema, + IN CHAR8 *Version, + IN EFI_STRING ConfigureLang, + OUT EDKII_REDFISH_VALUE *Value + ) +{ + EFI_STATUS Status; + REDFISH_PLATFORM_CONFIG_PRIVATE *RedfishPlatformConfigPrivate= ; + REDFISH_PLATFORM_CONFIG_STATEMENT_PRIVATE *TargetStatement; + CHAR8 *FullSchema; + + if ((This =3D=3D NULL) || IS_EMPTY_STRING (Schema) || IS_EMPTY_STRING (V= ersion) || IS_EMPTY_STRING (ConfigureLang) || (Value =3D=3D NULL)) { + return EFI_INVALID_PARAMETER; + } + + RedfishPlatformConfigPrivate =3D REDFISH_PLATFORM_CONFIG_PRIVATE_FROM_TH= IS (This); + Value->Type =3D RedfishValueTypeUnknown; + Value->ArrayCount =3D 0; + FullSchema =3D NULL; + + FullSchema =3D GetFullSchemaString (Schema, Version); + if (FullSchema =3D=3D NULL) { + return EFI_OUT_OF_RESOURCES; + } + + Status =3D RedfishPlatformConfigGetStatementCommon (RedfishPlatformConfi= gPrivate, FullSchema, ConfigureLang, &TargetStatement); + if (EFI_ERROR (Status)) { + goto RELEASE_RESOURCE; + } + + if (TargetStatement->Suppressed) { + Status =3D EFI_ACCESS_DENIED; + goto RELEASE_RESOURCE; + } + + Status =3D HiiValueToRedfishValue ( + TargetStatement->ParentForm->ParentFormset->HiiHandle, + FullSchema, + TargetStatement->HiiStatement, + &TargetStatement->HiiStatement->Value, + Value + ); + if (EFI_ERROR (Status)) { + DEBUG ((DEBUG_ERROR, "%a, HiiValueToRedfishValue failed: %r\n", __FUNC= TION__, Status)); + } + +RELEASE_RESOURCE: + + if (FullSchema !=3D NULL) { + FreePool (FullSchema); + } + + return Status; +} + +/** + Function to save question value into HII database. + + @param[in] HiiFormset HII form-set instance + @param[in] HiiForm HII form instance + @param[in] HiiStatement HII statement that keeps new value. + @param[in] Value New value to apply. + + @retval EFI_SUCCESS HII value is returned successfully. + @retval Others Errors occur + +**/ +EFI_STATUS +RedfishPlatformConfigSaveQuestionValue ( + IN HII_FORMSET *HiiFormset, + IN HII_FORM *HiiForm, + IN HII_STATEMENT *HiiStatement, + IN HII_STATEMENT_VALUE *Value + ) +{ + EFI_STATUS Status; + + if ((HiiFormset =3D=3D NULL) || (HiiForm =3D=3D NULL) || (HiiStatement = =3D=3D NULL) || (Value =3D=3D NULL)) { + return EFI_INVALID_PARAMETER; + } + + Status =3D SetQuestionValue ( + HiiFormset, + HiiForm, + HiiStatement, + Value + ); + if (EFI_ERROR (Status)) { + DEBUG ((DEBUG_ERROR, "%a, failed to set question value: %r\n", __FUNCT= ION__, Status)); + return Status; + } + + Status =3D SubmitForm (HiiFormset, HiiForm); + if (EFI_ERROR (Status)) { + DEBUG ((DEBUG_ERROR, "%a, failed to submit form: %r\n", __FUNCTION__, = Status)); + return Status; + } + + return EFI_SUCCESS; +} + +/** + Common implementation to set statement private instance. + + @param[in] RedfishPlatformConfigPrivate Private instance. + @param[in] Schema Redfish schema string. + @param[in] ConfigureLang Configure language that refe= rs to this statement. + @param[in] StatementValue Statement value. + + @retval EFI_SUCCESS HII value is returned successfully. + @retval Others Errors occur + +**/ +EFI_STATUS +RedfishPlatformConfigSetStatementCommon ( + IN REDFISH_PLATFORM_CONFIG_PRIVATE *RedfishPlatformConfigPrivate, + IN CHAR8 *Schema, + IN EFI_STRING ConfigureLang, + IN HII_STATEMENT_VALUE *StatementValue + ) +{ + EFI_STATUS Status; + REDFISH_PLATFORM_CONFIG_STATEMENT_PRIVATE *TargetStatement; + EFI_STRING TempBuffer; + UINT8 *StringArray; + UINTN Index; + UINT64 Value; + CHAR8 **CharArray; + + if ((RedfishPlatformConfigPrivate =3D=3D NULL) || IS_EMPTY_STRING (Schem= a) || IS_EMPTY_STRING (ConfigureLang) || (StatementValue =3D=3D NULL)) { + return EFI_INVALID_PARAMETER; + } + + TempBuffer =3D NULL; + StringArray =3D NULL; + + Status =3D ProcessPendingList (&RedfishPlatformConfigPrivate->FormsetLis= t, &RedfishPlatformConfigPrivate->PendingList); + if (EFI_ERROR (Status)) { + DEBUG ((DEBUG_ERROR, "%a, ProcessPendingList failure: %r\n", __FUNCTIO= N__, Status)); + return Status; + } + + TargetStatement =3D GetStatementPrivateByConfigureLang (&RedfishPlatform= ConfigPrivate->FormsetList, Schema, ConfigureLang); + if (TargetStatement =3D=3D NULL) { + DEBUG ((DEBUG_ERROR, "%a, No match HII statement is found by the given= %s in schema %a\n", __FUNCTION__, ConfigureLang, Schema)); + return EFI_NOT_FOUND; + } + + if (StatementValue->Type !=3D TargetStatement->HiiStatement->Value.Type)= { + // + // We treat one-of type as string in Redfish. But one-of statement is = not + // in string format from HII point of view. Do a patch here. + // + if ((TargetStatement->HiiStatement->Operand =3D=3D EFI_IFR_ONE_OF_OP) = && (StatementValue->Type =3D=3D EFI_IFR_TYPE_STRING)) { + TempBuffer =3D StrToUnicodeStr ((CHAR8 *)StatementValue->Buffer); + if (TempBuffer =3D=3D NULL) { + return EFI_OUT_OF_RESOURCES; + } + + FreePool (StatementValue->Buffer); + StatementValue->Buffer =3D NULL; + StatementValue->BufferLen =3D 0; + + Status =3D HiiStringToOneOfOptionValue (TargetStatement, Schema, Tem= pBuffer, StatementValue); + if (EFI_ERROR (Status)) { + DEBUG ((DEBUG_ERROR, "%a, failed to find option value by the given= %s\n", __FUNCTION__, TempBuffer)); + FreePool (TempBuffer); + return EFI_NOT_FOUND; + } + + FreePool (TempBuffer); + } else if ((TargetStatement->HiiStatement->Operand =3D=3D EFI_IFR_ORDE= RED_LIST_OP) && (StatementValue->Type =3D=3D EFI_IFR_TYPE_STRING)) { + // + // We treat ordered list type as string in Redfish. But ordered list= statement is not + // in string format from HII point of view. Do a patch here. + // + StringArray =3D AllocateZeroPool (TargetStatement->HiiStatement->Sto= rageWidth); + if (StringArray =3D=3D NULL) { + return EFI_OUT_OF_RESOURCES; + } + + // + // Arrange new option order from input string array + // + CharArray =3D (CHAR8 **)StatementValue->Buffer; + for (Index =3D 0; Index < StatementValue->BufferLen; Index++) { + TempBuffer =3D StrToUnicodeStr (CharArray[Index]); + if (TempBuffer =3D=3D NULL) { + return EFI_OUT_OF_RESOURCES; + } + + Status =3D HiiStringToOrderedListOptionValue (TargetStatement, Sch= ema, TempBuffer, &Value); + if (EFI_ERROR (Status)) { + ASSERT (FALSE); + continue; + } + + FreePool (TempBuffer); + OrderedListSetArrayData (StringArray, TargetStatement->HiiStatemen= t->Value.BufferValueType, Index, Value); + } + + StatementValue->Type =3D EFI_IFR_TYPE_BUFFER; + StatementValue->Buffer =3D StringArray; + StatementValue->BufferLen =3D TargetStatement->HiiStatement->S= torageWidth; + StatementValue->BufferValueType =3D TargetStatement->HiiStatement->V= alue.BufferValueType; + } else if ((TargetStatement->HiiStatement->Operand =3D=3D EFI_IFR_NUME= RIC_OP) && (StatementValue->Type =3D=3D EFI_IFR_TYPE_NUM_SIZE_64)) { + // + // Redfish only has numeric value type and it does not care about th= e value size. + // Do a patch here so we have proper value size applied. + // + StatementValue->Type =3D TargetStatement->HiiStatement->Value.Type; + } else { + DEBUG ((DEBUG_ERROR, "%a, catch value type mismatch! input type: 0x%= x but target value type: 0x%x\n", __FUNCTION__, StatementValue->Type, Targe= tStatement->HiiStatement->Value.Type)); + ASSERT (FALSE); + } + } + + Status =3D RedfishPlatformConfigSaveQuestionValue ( + TargetStatement->ParentForm->ParentFormset->HiiFormSet, + TargetStatement->ParentForm->HiiForm, + TargetStatement->HiiStatement, + StatementValue + ); + if (EFI_ERROR (Status)) { + DEBUG ((DEBUG_ERROR, "%a, failed to save question value: %r\n", __FUNC= TION__, Status)); + return Status; + } + + return EFI_SUCCESS; +} + +/** + Set Redfish value with the given Schema and Configure Language. + + @param[in] This Pointer to EDKII_REDFISH_PLATFORM_CONFI= G_PROTOCOL instance. + @param[in] Schema The Redfish schema to query. + @param[in] Version The Redfish version to query. + @param[in] ConfigureLang The target value which match this confi= gure Language. + @param[in] Value The value to set. + + @retval EFI_SUCCESS Value is returned successfully. + @retval Others Some error happened. + +**/ +EFI_STATUS +EFIAPI +RedfishPlatformConfigProtocolSetValue ( + IN EDKII_REDFISH_PLATFORM_CONFIG_PROTOCOL *This, + IN CHAR8 *Schema, + IN CHAR8 *Version, + IN EFI_STRING ConfigureLang, + IN EDKII_REDFISH_VALUE Value + ) +{ + EFI_STATUS Status; + REDFISH_PLATFORM_CONFIG_PRIVATE *RedfishPlatformConfigPrivate; + CHAR8 *FullSchema; + HII_STATEMENT_VALUE NewValue; + + if ((This =3D=3D NULL) || IS_EMPTY_STRING (Schema) || IS_EMPTY_STRING (V= ersion) || IS_EMPTY_STRING (ConfigureLang)) { + return EFI_INVALID_PARAMETER; + } + + if ((Value.Type =3D=3D RedfishValueTypeUnknown) || (Value.Type >=3D Redf= ishValueTypeMax)) { + return EFI_INVALID_PARAMETER; + } + + RedfishPlatformConfigPrivate =3D REDFISH_PLATFORM_CONFIG_PRIVATE_FROM_TH= IS (This); + FullSchema =3D NULL; + + FullSchema =3D GetFullSchemaString (Schema, Version); + if (FullSchema =3D=3D NULL) { + return EFI_OUT_OF_RESOURCES; + } + + ZeroMem (&NewValue, sizeof (HII_STATEMENT_VALUE)); + + switch (Value.Type) { + case RedfishValueTypeInteger: + case RedfishValueTypeBoolean: + Status =3D RedfishNumericToHiiValue (&Value, &NewValue); + if (EFI_ERROR (Status)) { + DEBUG ((DEBUG_ERROR, "%a, failed to convert Redfish value to Hii v= alue: %r\n", __FUNCTION__, Status)); + goto RELEASE_RESOURCE; + } + + break; + case RedfishValueTypeString: + NewValue.Type =3D EFI_IFR_TYPE_STRING; + NewValue.BufferLen =3D (UINT16)AsciiStrSize (Value.Value.Buffer); + NewValue.Buffer =3D AllocateCopyPool (NewValue.BufferLen, Value.V= alue.Buffer); + if (NewValue.Buffer =3D=3D NULL) { + Status =3D EFI_OUT_OF_RESOURCES; + goto RELEASE_RESOURCE; + } + + break; + case RedfishValueTypeStringArray: + NewValue.Type =3D EFI_IFR_TYPE_STRING; + NewValue.BufferLen =3D (UINT16)Value.ArrayCount; + NewValue.Buffer =3D (UINT8 *)Value.Value.StringArray; + break; + default: + ASSERT (FALSE); + break; + } + + Status =3D RedfishPlatformConfigSetStatementCommon (RedfishPlatformConfi= gPrivate, FullSchema, ConfigureLang, &NewValue); + if (EFI_ERROR (Status)) { + DEBUG ((DEBUG_ERROR, "%a, failed to set value to statement: %r\n", __F= UNCTION__, Status)); + } + +RELEASE_RESOURCE: + + if (FullSchema !=3D NULL) { + FreePool (FullSchema); + } + + return Status; +} + +/** + Get the list of Configure Language from platform configuration by the gi= ven Schema and RegexPattern. + + @param[in] This Pointer to EDKII_REDFISH_PLATFORM_CONFI= G_PROTOCOL instance. + @param[in] Schema The Redfish schema to query. + @param[in] Version The Redfish version to query. + @param[in] RegexPattern The target Configure Language pattern. = This is used for regular expression matching. + @param[out] ConfigureLangList The list of Configure Language. + @param[out] Count The number of Configure Language in Con= figureLangList. + + @retval EFI_SUCCESS ConfigureLangList is returned successfu= lly. + @retval Others Some error happened. + +**/ +EFI_STATUS +EFIAPI +RedfishPlatformConfigProtocolGetConfigureLang ( + IN EDKII_REDFISH_PLATFORM_CONFIG_PROTOCOL *This, + IN CHAR8 *Schema, + IN CHAR8 *Version, + IN EFI_STRING RegexPattern, + OUT EFI_STRING **ConfigureLangList, + OUT UINTN *Count + ) +{ + REDFISH_PLATFORM_CONFIG_PRIVATE *RedfishPlatformConfigPr= ivate; + EFI_STATUS Status; + REDFISH_PLATFORM_CONFIG_STATEMENT_PRIVATE_LIST StatementList; + REDFISH_PLATFORM_CONFIG_STATEMENT_PRIVATE_REF *StatementRef; + LIST_ENTRY *NextLink; + EFI_STRING TmpString; + EFI_STRING *TmpConfigureLangList; + UINTN Index; + CHAR8 *FullSchema; + + if ((This =3D=3D NULL) || IS_EMPTY_STRING (Schema) || IS_EMPTY_STRING (V= ersion) || (Count =3D=3D NULL) || (ConfigureLangList =3D=3D NULL) || IS_EMP= TY_STRING (RegexPattern)) { + return EFI_INVALID_PARAMETER; + } + + *Count =3D 0; + *ConfigureLangList =3D NULL; + FullSchema =3D NULL; + TmpConfigureLangList =3D NULL; + RedfishPlatformConfigPrivate =3D REDFISH_PLATFORM_CONFIG_PRIVATE_FROM_TH= IS (This); + + Status =3D ProcessPendingList (&RedfishPlatformConfigPrivate->FormsetLis= t, &RedfishPlatformConfigPrivate->PendingList); + if (EFI_ERROR (Status)) { + DEBUG ((DEBUG_ERROR, "%a, ProcessPendingList failure: %r\n", __FUNCTIO= N__, Status)); + return Status; + } + + FullSchema =3D GetFullSchemaString (Schema, Version); + if (FullSchema =3D=3D NULL) { + return EFI_OUT_OF_RESOURCES; + } + + Status =3D GetStatementPrivateByConfigureLangRegex ( + RedfishPlatformConfigPrivate->RegularExpressionProtocol, + &RedfishPlatformConfigPrivate->FormsetList, + FullSchema, + RegexPattern, + &StatementList + ); + if (EFI_ERROR (Status)) { + DEBUG ((DEBUG_ERROR, "%a, GetStatementPrivateByConfigureLangRegex fail= ure: %r\n", __FUNCTION__, Status)); + goto RELEASE_RESOURCE; + } + + if (!IsListEmpty (&StatementList.StatementList)) { + TmpConfigureLangList =3D AllocateZeroPool (sizeof (CHAR16 *) * Stateme= ntList.Count); + if (TmpConfigureLangList =3D=3D NULL) { + Status =3D EFI_OUT_OF_RESOURCES; + goto RELEASE_RESOURCE; + } + + Index =3D 0; + NextLink =3D GetFirstNode (&StatementList.StatementList); + while (!IsNull (&StatementList.StatementList, NextLink)) { + StatementRef =3D REDFISH_PLATFORM_CONFIG_STATEMENT_REF_FROM_LINK (Ne= xtLink); + NextLink =3D GetNextNode (&StatementList.StatementList, NextLink= ); + + ASSERT (StatementRef->Statement->Description !=3D 0); + if (StatementRef->Statement->Description !=3D 0) { + TmpString =3D HiiGetRedfishString (StatementRef->Statement->Parent= Form->ParentFormset->HiiHandle, FullSchema, StatementRef->Statement->Descri= ption); + ASSERT (TmpString !=3D NULL); + if (TmpString !=3D NULL) { + TmpConfigureLangList[Index] =3D AllocateCopyPool (StrSize (TmpSt= ring), TmpString); + ASSERT (TmpConfigureLangList[Index] !=3D NULL); + FreePool (TmpString); + ++Index; + } + } + } + } + + *Count =3D StatementList.Count; + *ConfigureLangList =3D TmpConfigureLangList; + +RELEASE_RESOURCE: + + if (FullSchema !=3D NULL) { + FreePool (FullSchema); + } + + ReleaseStatementList (&StatementList); + + return Status; +} + +/** + Get the list of supported Redfish schema from platform configuration. + + @param[in] This Pointer to EDKII_REDFISH_PLATFORM_CONFI= G_PROTOCOL instance. + @param[out] SupportedSchema The supported schema list which is sepa= rated by ';'. + For example: "x-uefi-redfish-Memory.v1_= 7_1;x-uefi-redfish-Boot.v1_0_1" + The SupportedSchema is allocated by the= callee. It's caller's + responsibility to free this buffer usin= g FreePool(). + + @retval EFI_SUCCESS Schema is returned successfully. + @retval Others Some error happened. + +**/ +EFI_STATUS +EFIAPI +RedfishPlatformConfigProtocolGetSupportedSchema ( + IN EDKII_REDFISH_PLATFORM_CONFIG_PROTOCOL *This, + OUT CHAR8 **SupportedSchema + ) +{ + REDFISH_PLATFORM_CONFIG_PRIVATE *RedfishPlatformConfigPrivate; + EFI_STATUS Status; + LIST_ENTRY *HiiFormsetLink; + LIST_ENTRY *HiiFormsetNextLink; + REDFISH_PLATFORM_CONFIG_FORM_SET_PRIVATE *HiiFormsetPrivate; + UINTN Index; + UINTN StringSize; + CHAR8 *StringBuffer; + UINTN StringIndex; + + if ((This =3D=3D NULL) || (SupportedSchema =3D=3D NULL)) { + return EFI_INVALID_PARAMETER; + } + + *SupportedSchema =3D NULL; + + RedfishPlatformConfigPrivate =3D REDFISH_PLATFORM_CONFIG_PRIVATE_FROM_TH= IS (This); + + Status =3D ProcessPendingList (&RedfishPlatformConfigPrivate->FormsetLis= t, &RedfishPlatformConfigPrivate->PendingList); + if (EFI_ERROR (Status)) { + DEBUG ((DEBUG_ERROR, "%a, ProcessPendingList failure: %r\n", __FUNCTIO= N__, Status)); + return Status; + } + + if (IsListEmpty (&RedfishPlatformConfigPrivate->FormsetList)) { + return EFI_NOT_FOUND; + } + + // + // Calculate for string buffer size. + // + StringSize =3D 0; + HiiFormsetLink =3D GetFirstNode (&RedfishPlatformConfigPrivate->FormsetL= ist); + while (!IsNull (&RedfishPlatformConfigPrivate->FormsetList, HiiFormsetLi= nk)) { + HiiFormsetNextLink =3D GetNextNode (&RedfishPlatformConfigPrivate->For= msetList, HiiFormsetLink); + HiiFormsetPrivate =3D REDFISH_PLATFORM_CONFIG_FORMSET_FROM_LINK (HiiF= ormsetLink); + + if (HiiFormsetPrivate->SupportedSchema.Count > 0) { + for (Index =3D 0; Index < HiiFormsetPrivate->SupportedSchema.Count; = Index++) { + StringSize +=3D AsciiStrSize (HiiFormsetPrivate->SupportedSchema.S= chemaList[Index]); + } + } + + HiiFormsetLink =3D HiiFormsetNextLink; + } + + if (StringSize =3D=3D 0) { + return EFI_NOT_FOUND; + } + + StringBuffer =3D AllocatePool (StringSize); + if (StringBuffer =3D=3D NULL) { + return EFI_OUT_OF_RESOURCES; + } + + StringIndex =3D 0; + HiiFormsetLink =3D GetFirstNode (&RedfishPlatformConfigPrivate->FormsetL= ist); + while (!IsNull (&RedfishPlatformConfigPrivate->FormsetList, HiiFormsetLi= nk)) { + HiiFormsetNextLink =3D GetNextNode (&RedfishPlatformConfigPrivate->For= msetList, HiiFormsetLink); + HiiFormsetPrivate =3D REDFISH_PLATFORM_CONFIG_FORMSET_FROM_LINK (HiiF= ormsetLink); + + if (HiiFormsetPrivate->SupportedSchema.Count > 0) { + for (Index =3D 0; Index < HiiFormsetPrivate->SupportedSchema.Count; = Index++) { + AsciiStrCpyS (&StringBuffer[StringIndex], (StringSize - StringInde= x), HiiFormsetPrivate->SupportedSchema.SchemaList[Index]); + StringIndex +=3D AsciiStrLen (HiiFormsetPrivate->Supp= ortedSchema.SchemaList[Index]); + StringBuffer[StringIndex] =3D ';'; + ++StringIndex; + } + } + + HiiFormsetLink =3D HiiFormsetNextLink; + } + + StringBuffer[--StringIndex] =3D '\0'; + + *SupportedSchema =3D StringBuffer; + + return EFI_SUCCESS; +} + +/** + Get Redfish default value with the given Schema and Configure Language. + + @param[in] This Pointer to EDKII_REDFISH_PLATFORM_CONFI= G_PROTOCOL instance. + @param[in] Schema The Redfish schema to query. + @param[in] Version The Redfish version to query. + @param[in] ConfigureLang The target value which match this confi= gure Language. + @param[in] DefaultClass The UEFI defined default class. + Please refer to UEFI spec. 33.2.5.8 "de= faults" for details. + @param[out] Value The returned value. + + @retval EFI_SUCCESS Value is returned successfully. + @retval Others Some error happened. + +**/ +EFI_STATUS +EFIAPI +RedfishPlatformConfigProtocolGetDefaultValue ( + IN EDKII_REDFISH_PLATFORM_CONFIG_PROTOCOL *This, + IN CHAR8 *Schema, + IN CHAR8 *Version, + IN EFI_STRING ConfigureLang, + IN UINT16 DefaultClass, + OUT EDKII_REDFISH_VALUE *Value + ) +{ + EFI_STATUS Status; + REDFISH_PLATFORM_CONFIG_PRIVATE *RedfishPlatformConfigPrivate= ; + REDFISH_PLATFORM_CONFIG_STATEMENT_PRIVATE *TargetStatement; + CHAR8 *FullSchema; + HII_STATEMENT_VALUE DefaultValue; + + if ((This =3D=3D NULL) || IS_EMPTY_STRING (Schema) || IS_EMPTY_STRING (V= ersion) || IS_EMPTY_STRING (ConfigureLang) || (Value =3D=3D NULL)) { + return EFI_INVALID_PARAMETER; + } + + RedfishPlatformConfigPrivate =3D REDFISH_PLATFORM_CONFIG_PRIVATE_FROM_TH= IS (This); + ZeroMem (&DefaultValue, sizeof (HII_STATEMENT_VALUE)); + ZeroMem (Value, sizeof (EDKII_REDFISH_VALUE)); + + FullSchema =3D NULL; + FullSchema =3D GetFullSchemaString (Schema, Version); + if (FullSchema =3D=3D NULL) { + return EFI_OUT_OF_RESOURCES; + } + + Status =3D RedfishPlatformConfigGetStatementCommon (RedfishPlatformConfi= gPrivate, FullSchema, ConfigureLang, &TargetStatement); + if (EFI_ERROR (Status)) { + goto RELEASE_RESOURCE; + } + + if (TargetStatement->Suppressed) { + Status =3D EFI_ACCESS_DENIED; + goto RELEASE_RESOURCE; + } + + Status =3D GetQuestionDefault (TargetStatement->ParentForm->ParentFormse= t->HiiFormSet, TargetStatement->ParentForm->HiiForm, TargetStatement->HiiSt= atement, DefaultClass, &DefaultValue); + if (EFI_ERROR (Status)) { + DEBUG ((DEBUG_ERROR, "%a, GetQuestionDefault failed: %r\n", __FUNCTION= __, Status)); + goto RELEASE_RESOURCE; + } + + Status =3D HiiValueToRedfishValue ( + TargetStatement->ParentForm->ParentFormset->HiiHandle, + FullSchema, + TargetStatement->HiiStatement, + &DefaultValue, + Value + ); + if (EFI_ERROR (Status)) { + DEBUG ((DEBUG_ERROR, "%a, HiiValueToRedfishValue failed: %r\n", __FUNC= TION__, Status)); + } + +RELEASE_RESOURCE: + + if (FullSchema !=3D NULL) { + FreePool (FullSchema); + } + + return Status; +} + +/** + Get Redfish attribute value with the given Schema and Configure Language= . + + @param[in] This Pointer to EDKII_REDFISH_PLATFORM_CONFI= G_PROTOCOL instance. + @param[in] Schema The Redfish schema to query. + @param[in] Version The Redfish version to query. + @param[in] ConfigureLang The target value which match this confi= gure Language. + @param[out] AttributeValue The attribute value. + + @retval EFI_SUCCESS Value is returned successfully. + @retval Others Some error happened. + +**/ +EFI_STATUS +EFIAPI +RedfishPlatformConfigProtocolGetAttribute ( + IN EDKII_REDFISH_PLATFORM_CONFIG_PROTOCOL *This, + IN CHAR8 *Schema, + IN CHAR8 *Version, + IN EFI_STRING ConfigureLang, + OUT EDKII_REDFISH_ATTRIBUTE *AttributeValue + ) +{ + EFI_STATUS Status; + REDFISH_PLATFORM_CONFIG_PRIVATE *RedfishPlatformConfigPrivate= ; + REDFISH_PLATFORM_CONFIG_STATEMENT_PRIVATE *TargetStatement; + CHAR8 *FullSchema; + CHAR8 *Buffer; + + if ((This =3D=3D NULL) || IS_EMPTY_STRING (Schema) || IS_EMPTY_STRING (V= ersion) || IS_EMPTY_STRING (ConfigureLang) || (AttributeValue =3D=3D NULL))= { + return EFI_INVALID_PARAMETER; + } + + RedfishPlatformConfigPrivate =3D REDFISH_PLATFORM_CONFIG_PRIVATE_FROM_TH= IS (This); + ZeroMem (AttributeValue, sizeof (EDKII_REDFISH_ATTRIBUTE)); + FullSchema =3D NULL; + FullSchema =3D GetFullSchemaString (Schema, Version); + if (FullSchema =3D=3D NULL) { + return EFI_OUT_OF_RESOURCES; + } + + Status =3D RedfishPlatformConfigGetStatementCommon (RedfishPlatformConfi= gPrivate, FullSchema, ConfigureLang, &TargetStatement); + if (EFI_ERROR (Status)) { + goto RELEASE_RESOURCE; + } + + if (TargetStatement->Description !=3D 0) { + AttributeValue->AttributeName =3D HiiGetRedfishAsciiString (TargetStat= ement->ParentForm->ParentFormset->HiiHandle, FullSchema, TargetStatement->D= escription); + Buffer =3D GetAttributeNameFromConfigLanguage (= AttributeValue->AttributeName); + if (Buffer !=3D NULL) { + FreePool (AttributeValue->AttributeName); + AttributeValue->AttributeName =3D Buffer; + } + + AttributeValue->DisplayName =3D HiiGetEnglishAsciiString (TargetStatem= ent->ParentForm->ParentFormset->HiiHandle, TargetStatement->Description); + } + + if (TargetStatement->Help !=3D 0) { + AttributeValue->HelpText =3D HiiGetEnglishAsciiString (TargetStatement= ->ParentForm->ParentFormset->HiiHandle, TargetStatement->Help); + } + + AttributeValue->ReadOnly =3D ((TargetStatement->Flags & EFI_IFR_FLA= G_READ_ONLY) =3D=3D 0 ? FALSE : TRUE); + AttributeValue->ResetRequired =3D ((TargetStatement->Flags & EFI_IFR_FLA= G_RESET_REQUIRED) =3D=3D 0 ? FALSE : TRUE); + AttributeValue->Type =3D HiiStatementToAttributeType (TargetSta= tement->HiiStatement); + AttributeValue->Suppress =3D TargetStatement->Suppressed; + AttributeValue->GrayedOut =3D TargetStatement->GrayedOut; + + // + // Build up menu path + // + AttributeValue->MenuPath =3D BuildMenPath (TargetStatement); + if (AttributeValue->MenuPath =3D=3D NULL) { + DEBUG ((DEBUG_ERROR, "%a, failed to build menu path for \"%a\"\n", __F= UNCTION__, AttributeValue->AttributeName)); + } + + // + // Deal with maximum and minimum + // + if (AttributeValue->Type =3D=3D RedfishAttributeTypeString) { + AttributeValue->StrMaxSize =3D TargetStatement->StatementData.StrMaxSi= ze; + AttributeValue->StrMinSize =3D TargetStatement->StatementData.StrMinSi= ze; + } else if (AttributeValue->Type =3D=3D RedfishAttributeTypeInteger) { + AttributeValue->NumMaximum =3D TargetStatement->StatementData.NumMaxim= um; + AttributeValue->NumMinimum =3D TargetStatement->StatementData.NumMinim= um; + AttributeValue->NumStep =3D TargetStatement->StatementData.NumStep; + } + + // + // Provide value array if this is enumeration type. + // + if (TargetStatement->HiiStatement->Operand =3D=3D EFI_IFR_ONE_OF_OP) { + Status =3D OneOfStatementToAttributeValues (TargetStatement->ParentFor= m->ParentFormset->HiiHandle, FullSchema, TargetStatement, &AttributeValue->= Values); + if (EFI_ERROR (Status)) { + DEBUG ((DEBUG_ERROR, "%a, failed to convert one-of options to attrib= ute values: %r\n", __FUNCTION__, Status)); + } + } + +RELEASE_RESOURCE: + + if (FullSchema !=3D NULL) { + FreePool (FullSchema); + } + + return Status; +} + +/** + Functions which are registered to receive notification of + database events have this prototype. The actual event is encoded + in NotifyType. The following table describes how PackageType, + PackageGuid, Handle, and Package are used for each of the + notification types. + + @param[in] PackageType Package type of the notification. + @param[in] PackageGuid If PackageType is + EFI_HII_PACKAGE_TYPE_GUID, then this is + the pointer to the GUID from the Guid + field of EFI_HII_PACKAGE_GUID_HEADER. + Otherwise, it must be NULL. + @param[in] Package Points to the package referred to by the + notification Handle The handle of the package + list which contains the specified package. + @param[in] Handle The HII handle. + @param[in] NotifyType The type of change concerning the + database. See + EFI_HII_DATABASE_NOTIFY_TYPE. + +**/ +EFI_STATUS +EFIAPI +RedfishPlatformConfigFormUpdateNotify ( + IN UINT8 PackageType, + IN CONST EFI_GUID *PackageGuid, + IN CONST EFI_HII_PACKAGE_HEADER *Package, + IN EFI_HII_HANDLE Handle, + IN EFI_HII_DATABASE_NOTIFY_TYPE NotifyType + ) +{ + EFI_STATUS Status; + + if ((NotifyType =3D=3D EFI_HII_DATABASE_NOTIFY_NEW_PACK) || (NotifyType = =3D=3D EFI_HII_DATABASE_NOTIFY_ADD_PACK)) { + // + // HII formset on this handle is updated by driver during run-time. Th= e formset needs to be reloaded. + // + Status =3D NotifyFormsetUpdate (Handle, &mRedfishPlatformConfigPrivate= ->PendingList); + if (EFI_ERROR (Status)) { + DEBUG ((DEBUG_ERROR, "%a, failed to notify updated formset of HII ha= ndle: 0x%x\n", __FUNCTION__, Handle)); + return Status; + } + } else if (NotifyType =3D=3D EFI_HII_DATABASE_NOTIFY_REMOVE_PACK) { + // + // HII resource is removed. The formset is no longer exist. + // + Status =3D NotifyFormsetDeleted (Handle, &mRedfishPlatformConfigPrivat= e->PendingList); + if (EFI_ERROR (Status)) { + DEBUG ((DEBUG_ERROR, "%a, failed to notify deleted formset of HII ha= ndle: 0x%x\n", __FUNCTION__, Handle)); + return Status; + } + } + + return EFI_SUCCESS; +} + +/** + This is a EFI_HII_STRING_PROTOCOL notification event handler. + + Install HII package notification. + + @param[in] Event Event whose notification function is being invoked. + @param[in] Context Pointer to the notification function's context. + +**/ +VOID +EFIAPI +HiiStringProtocolInstalled ( + IN EFI_EVENT Event, + IN VOID *Context + ) +{ + EFI_STATUS Status; + + // + // Locate HII database protocol. + // + Status =3D gBS->LocateProtocol ( + &gEfiHiiStringProtocolGuid, + NULL, + (VOID **)&mRedfishPlatformConfigPrivate->HiiString + ); + if (EFI_ERROR (Status)) { + DEBUG ((DEBUG_ERROR, "%a, locate EFI_HII_STRING_PROTOCOL failure: %r\n= ", __FUNCTION__, Status)); + return; + } + + gBS->CloseEvent (Event); + mRedfishPlatformConfigPrivate->HiiStringNotify.ProtocolEvent =3D NULL; +} + +/** + This is a EFI_HII_DATABASE_PROTOCOL notification event handler. + + Install HII package notification. + + @param[in] Event Event whose notification function is being invoked. + @param[in] Context Pointer to the notification function's context. + +**/ +VOID +EFIAPI +HiiDatabaseProtocolInstalled ( + IN EFI_EVENT Event, + IN VOID *Context + ) +{ + EFI_STATUS Status; + + // + // Locate HII database protocol. + // + Status =3D gBS->LocateProtocol ( + &gEfiHiiDatabaseProtocolGuid, + NULL, + (VOID **)&mRedfishPlatformConfigPrivate->HiiDatabase + ); + if (EFI_ERROR (Status)) { + DEBUG ((DEBUG_ERROR, "%a, locate EFI_HII_DATABASE_PROTOCOL failure: %r= \n", __FUNCTION__, Status)); + return; + } + + // + // Register package notification when new form package is installed. + // + Status =3D mRedfishPlatformConfigPrivate->HiiDatabase->RegisterPackageNo= tify ( + mRedfishPlatformC= onfigPrivate->HiiDatabase, + EFI_HII_PACKAGE_F= ORMS, + NULL, + RedfishPlatformCo= nfigFormUpdateNotify, + EFI_HII_DATABASE_= NOTIFY_NEW_PACK, + &mRedfishPlatform= ConfigPrivate->NotifyHandle + ); + if (EFI_ERROR (Status)) { + DEBUG ((DEBUG_ERROR, "%a, RegisterPackageNotify for EFI_HII_DATABASE_N= OTIFY_NEW_PACK failure: %r\n", __FUNCTION__, Status)); + } + + // + // Register package notification when new form package is updated. + // + Status =3D mRedfishPlatformConfigPrivate->HiiDatabase->RegisterPackageNo= tify ( + mRedfishPlatformC= onfigPrivate->HiiDatabase, + EFI_HII_PACKAGE_F= ORMS, + NULL, + RedfishPlatformCo= nfigFormUpdateNotify, + EFI_HII_DATABASE_= NOTIFY_ADD_PACK, + &mRedfishPlatform= ConfigPrivate->NotifyHandle + ); + if (EFI_ERROR (Status)) { + DEBUG ((DEBUG_ERROR, "%a, RegisterPackageNotify for EFI_HII_DATABASE_N= OTIFY_NEW_PACK failure: %r\n", __FUNCTION__, Status)); + } + + gBS->CloseEvent (Event); + mRedfishPlatformConfigPrivate->HiiDbNotify.ProtocolEvent =3D NULL; +} + +/** + This is a EFI_REGULAR_EXPRESSION_PROTOCOL notification event handler. + + @param[in] Event Event whose notification function is being invoked. + @param[in] Context Pointer to the notification function's context. + +**/ +VOID +EFIAPI +RegexProtocolInstalled ( + IN EFI_EVENT Event, + IN VOID *Context + ) +{ + EFI_STATUS Status; + + // + // Locate regular expression protocol. + // + Status =3D gBS->LocateProtocol ( + &gEfiRegularExpressionProtocolGuid, + NULL, + (VOID **)&mRedfishPlatformConfigPrivate->RegularExpressi= onProtocol + ); + if (EFI_ERROR (Status)) { + DEBUG ((DEBUG_ERROR, "%a, locate EFI_REGULAR_EXPRESSION_PROTOCOL failu= re: %r\n", __FUNCTION__, Status)); + return; + } + + gBS->CloseEvent (Event); + mRedfishPlatformConfigPrivate->RegexNotify.ProtocolEvent =3D NULL; +} + +/** + 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 +RedfishPlatformConfigDxeUnload ( + IN EFI_HANDLE ImageHandle + ) +{ + EFI_STATUS Status; + + if (mRedfishPlatformConfigPrivate !=3D NULL) { + Status =3D gBS->UninstallProtocolInterface ( + mRedfishPlatformConfigPrivate->ImageHandle, + &gEdkIIRedfishPlatformConfigProtocolGuid, + (VOID *)&mRedfishPlatformConfigPrivate->Protocol + ); + if (EFI_ERROR (Status)) { + DEBUG ((DEBUG_ERROR, "%a, can not uninstall gEdkIIRedfishPlatformCon= figProtocolGuid: %r\n", __FUNCTION__, Status)); + ASSERT (FALSE); + } + + // + // Close events + // + if (mRedfishPlatformConfigPrivate->HiiDbNotify.ProtocolEvent !=3D NULL= ) { + gBS->CloseEvent (mRedfishPlatformConfigPrivate->HiiDbNotify.Protocol= Event); + } + + if (mRedfishPlatformConfigPrivate->HiiStringNotify.ProtocolEvent !=3D = NULL) { + gBS->CloseEvent (mRedfishPlatformConfigPrivate->HiiStringNotify.Prot= ocolEvent); + } + + if (mRedfishPlatformConfigPrivate->RegexNotify.ProtocolEvent !=3D NULL= ) { + gBS->CloseEvent (mRedfishPlatformConfigPrivate->RegexNotify.Protocol= Event); + } + + // + // Unregister package notification. + // + if (mRedfishPlatformConfigPrivate->NotifyHandle !=3D NULL) { + mRedfishPlatformConfigPrivate->HiiDatabase->UnregisterPackageNotify = ( + mRedfishPlatformConfig= Private->HiiDatabase, + mRedfishPlatformConfig= Private->NotifyHandle + ); + } + + ReleaseFormsetList (&mRedfishPlatformConfigPrivate->FormsetList); + FreePool (mRedfishPlatformConfigPrivate); + mRedfishPlatformConfigPrivate =3D NULL; + } + + return EFI_SUCCESS; +} + +/** + This is the declaration of an EFI image entry point. This entry point is + the same for UEFI Applications, UEFI OS Loaders, and UEFI Drivers includ= ing + both device drivers and bus drivers. + + @param ImageHandle The firmware allocated handle for the UEFI= image. + @param SystemTable A pointer to the EFI System Table. + + @retval EFI_SUCCESS The operation completed successfully. + @retval Others An unexpected error occurred. +**/ +EFI_STATUS +EFIAPI +RedfishPlatformConfigDxeEntryPoint ( + IN EFI_HANDLE ImageHandle, + IN EFI_SYSTEM_TABLE *SystemTable + ) +{ + EFI_STATUS Status; + + mRedfishPlatformConfigPrivate =3D (REDFISH_PLATFORM_CONFIG_PRIVATE *)All= ocateZeroPool (sizeof (REDFISH_PLATFORM_CONFIG_PRIVATE)); + if (mRedfishPlatformConfigPrivate =3D=3D NULL) { + DEBUG ((DEBUG_ERROR, "%a, can not allocate pool for REDFISH_PLATFORM_C= ONFIG_PRIVATE\n", __FUNCTION__)); + ASSERT (FALSE); + return EFI_OUT_OF_RESOURCES; + } + + // + // Protocol initialization + // + mRedfishPlatformConfigPrivate->ImageHandle =3D ImageHand= le; + mRedfishPlatformConfigPrivate->Protocol.Revision =3D REDFISH_P= LATFORM_CONFIG_VERSION; + mRedfishPlatformConfigPrivate->Protocol.GetValue =3D RedfishPl= atformConfigProtocolGetValue; + mRedfishPlatformConfigPrivate->Protocol.SetValue =3D RedfishPl= atformConfigProtocolSetValue; + mRedfishPlatformConfigPrivate->Protocol.GetConfigureLang =3D RedfishPl= atformConfigProtocolGetConfigureLang; + mRedfishPlatformConfigPrivate->Protocol.GetSupportedSchema =3D RedfishPl= atformConfigProtocolGetSupportedSchema; + mRedfishPlatformConfigPrivate->Protocol.GetAttribute =3D RedfishPl= atformConfigProtocolGetAttribute; + mRedfishPlatformConfigPrivate->Protocol.GetDefaultValue =3D RedfishPl= atformConfigProtocolGetDefaultValue; + + InitializeListHead (&mRedfishPlatformConfigPrivate->FormsetList); + InitializeListHead (&mRedfishPlatformConfigPrivate->PendingList); + + Status =3D gBS->InstallProtocolInterface ( + &ImageHandle, + &gEdkIIRedfishPlatformConfigProtocolGuid, + EFI_NATIVE_INTERFACE, + (VOID *)&mRedfishPlatformConfigPrivate->Protocol + ); + if (EFI_ERROR (Status)) { + DEBUG ((DEBUG_ERROR, "%a, can not install gEdkIIRedfishPlatformConfigP= rotocolGuid: %r\n", __FUNCTION__, Status)); + ASSERT (FALSE); + } + + // + // Install protocol notification if HII database protocol is installed. + // + mRedfishPlatformConfigPrivate->HiiDbNotify.ProtocolEvent =3D EfiCreatePr= otocolNotifyEvent ( + &gEfiHiiDat= abaseProtocolGuid, + TPL_CALLBAC= K, + HiiDatabase= ProtocolInstalled, + NULL, + &mRedfishPl= atformConfigPrivate->HiiDbNotify.Registration + ); + if (mRedfishPlatformConfigPrivate->HiiDbNotify.ProtocolEvent =3D=3D NULL= ) { + DEBUG ((DEBUG_ERROR, "%a, failed to create protocol notification for g= EfiHiiDatabaseProtocolGuid\n", __FUNCTION__)); + ASSERT (FALSE); + } + + // + // Install protocol notification if HII string protocol is installed. + // + mRedfishPlatformConfigPrivate->HiiStringNotify.ProtocolEvent =3D EfiCrea= teProtocolNotifyEvent ( + &gEfiHi= iStringProtocolGuid, + TPL_CAL= LBACK, + HiiStri= ngProtocolInstalled, + NULL, + &mRedfi= shPlatformConfigPrivate->HiiStringNotify.Registration + ); + if (mRedfishPlatformConfigPrivate->HiiStringNotify.ProtocolEvent =3D=3D = NULL) { + DEBUG ((DEBUG_ERROR, "%a, failed to create protocol notification for g= EfiHiiStringProtocolGuid\n", __FUNCTION__)); + ASSERT (FALSE); + } + + // + // Install protocol notification if regular expression protocol is insta= lled. + // + mRedfishPlatformConfigPrivate->RegexNotify.ProtocolEvent =3D EfiCreatePr= otocolNotifyEvent ( + &gEfiRegula= rExpressionProtocolGuid, + TPL_CALLBAC= K, + RegexProtoc= olInstalled, + NULL, + &mRedfishPl= atformConfigPrivate->RegexNotify.Registration + ); + if (mRedfishPlatformConfigPrivate->RegexNotify.ProtocolEvent =3D=3D NULL= ) { + DEBUG ((DEBUG_ERROR, "%a, failed to create protocol notification for g= EfiRegularExpressionProtocolGuid\n", __FUNCTION__)); + ASSERT (FALSE); + } + + return EFI_SUCCESS; +} diff --git a/RedfishPkg/RedfishPlatformConfigDxe/RedfishPlatformConfigImpl.= c b/RedfishPkg/RedfishPlatformConfigDxe/RedfishPlatformConfigImpl.c new file mode 100644 index 000000000000..8b8ff0ce4bda --- /dev/null +++ b/RedfishPkg/RedfishPlatformConfigDxe/RedfishPlatformConfigImpl.c @@ -0,0 +1,1364 @@ +/** @file + The implementation of EDKII Redfish Platform Config Protocol. + + (C) Copyright 2021-2022 Hewlett Packard Enterprise Development LP
+ Copyright (c) 2022-2023, NVIDIA CORPORATION & AFFILIATES. All rights res= erved. + + SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ +#include "RedfishPlatformConfigDxe.h" +#include "RedfishPlatformConfigImpl.h" + +extern REDFISH_PLATFORM_CONFIG_PRIVATE *mRedfishPlatformConfigPrivate; + +/** + Debug dump HII string. + + @param[in] HiiHandle HII handle instance + @param[in] StringId HII string to dump + + @retval EFI_SUCCESS Dump HII string successfully + @retval Others Errors occur + +**/ +EFI_STATUS +DumpHiiString ( + IN EFI_HII_HANDLE HiiHandle, + IN EFI_STRING_ID StringId + ) +{ + EFI_STRING String; + + if ((HiiHandle =3D=3D NULL) || (StringId =3D=3D 0)) { + DEBUG ((REDFISH_PLATFORM_CONFIG_DEBUG, "???")); + return EFI_INVALID_PARAMETER; + } + + String =3D HiiGetString (HiiHandle, StringId, NULL); + if (String =3D=3D NULL) { + return EFI_NOT_FOUND; + } + + DEBUG ((REDFISH_PLATFORM_CONFIG_DEBUG, "%s", String)); + FreePool (String); + + return EFI_SUCCESS; +} + +/** + Debug dump HII form-set data. + + @param[in] FormsetPrivate HII form-set private instance. + + @retval EFI_SUCCESS Dump form-set successfully + @retval Others Errors occur + +**/ +EFI_STATUS +DumpFormset ( + IN REDFISH_PLATFORM_CONFIG_FORM_SET_PRIVATE *FormsetPrivate + ) +{ + LIST_ENTRY *HiiFormLink; + LIST_ENTRY *HiiNextFormLink; + REDFISH_PLATFORM_CONFIG_FORM_PRIVATE *HiiFormPrivate; + LIST_ENTRY *HiiStatementLink; + LIST_ENTRY *HiiNextStatementLink; + REDFISH_PLATFORM_CONFIG_STATEMENT_PRIVATE *HiiStatementPrivate; + UINTN Index; + + if (FormsetPrivate =3D=3D NULL) { + return EFI_INVALID_PARAMETER; + } + + Index =3D 0; + HiiFormLink =3D GetFirstNode (&FormsetPrivate->HiiFormList); + while (!IsNull (&FormsetPrivate->HiiFormList, HiiFormLink)) { + HiiFormPrivate =3D REDFISH_PLATFORM_CONFIG_FORM_FROM_LINK (HiiFormLin= k); + HiiNextFormLink =3D GetNextNode (&FormsetPrivate->HiiFormList, HiiForm= Link); + + DEBUG ((REDFISH_PLATFORM_CONFIG_DEBUG, " [%d] form: %d title: ", ++In= dex, HiiFormPrivate->Id)); + DumpHiiString (FormsetPrivate->HiiHandle, HiiFormPrivate->Title); + DEBUG ((REDFISH_PLATFORM_CONFIG_DEBUG, "\n")); + + HiiStatementLink =3D GetFirstNode (&HiiFormPrivate->StatementList); + while (!IsNull (&HiiFormPrivate->StatementList, HiiStatementLink)) { + HiiStatementPrivate =3D REDFISH_PLATFORM_CONFIG_STATEMENT_FROM_LINK= (HiiStatementLink); + HiiNextStatementLink =3D GetNextNode (&HiiFormPrivate->StatementList= , HiiStatementLink); + + DEBUG ((REDFISH_PLATFORM_CONFIG_DEBUG, " QID: 0x%x Prompt: ", Hii= StatementPrivate->QuestionId)); + DumpHiiString (FormsetPrivate->HiiHandle, HiiStatementPrivate->Descr= iption); + DEBUG ((REDFISH_PLATFORM_CONFIG_DEBUG, "\n")); + + HiiStatementLink =3D HiiNextStatementLink; + } + + HiiFormLink =3D HiiNextFormLink; + } + + return EFI_SUCCESS; +} + +/** + Debug dump HII form-set list. + + @param[in] FormsetList Form-set list instance + + @retval EFI_SUCCESS Dump list successfully + @retval Others Errors occur + +**/ +EFI_STATUS +DumpFormsetList ( + IN LIST_ENTRY *FormsetList + ) +{ + LIST_ENTRY *HiiFormsetLink; + LIST_ENTRY *HiiFormsetNextLink; + REDFISH_PLATFORM_CONFIG_FORM_SET_PRIVATE *HiiFormsetPrivate; + UINTN Index; + + if (FormsetList =3D=3D NULL) { + return EFI_INVALID_PARAMETER; + } + + if (IsListEmpty (FormsetList)) { + DEBUG ((REDFISH_PLATFORM_CONFIG_DEBUG, "%a, Empty formset list\n", __F= UNCTION__)); + return EFI_SUCCESS; + } + + Index =3D 0; + HiiFormsetLink =3D GetFirstNode (FormsetList); + while (!IsNull (FormsetList, HiiFormsetLink)) { + HiiFormsetNextLink =3D GetNextNode (FormsetList, HiiFormsetLink); + HiiFormsetPrivate =3D REDFISH_PLATFORM_CONFIG_FORMSET_FROM_LINK (HiiF= ormsetLink); + + DEBUG ((REDFISH_PLATFORM_CONFIG_DEBUG, "[%d] HII Handle: 0x%x formset:= %g at %s\n", ++Index, HiiFormsetPrivate->HiiHandle, &HiiFormsetPrivate->Gu= id, HiiFormsetPrivate->DevicePathStr)); + DumpFormset (HiiFormsetPrivate); + + HiiFormsetLink =3D HiiFormsetNextLink; + } + + return EFI_SUCCESS; +} + +/** + Retrieves a unicode string from a string package in a given language. Th= e + returned string is allocated using AllocatePool(). The caller is respon= sible + for freeing the allocated buffer using FreePool(). + + If HiiHandle is NULL, then ASSERT(). + If StringId is 0, then ASSET. + + @param[in] HiiHandle A handle that was previously registered in= the HII Database. + @param[in] Language The specified configure language to get st= ring. + @param[in] StringId The identifier of the string to retrieved = from the string + package associated with HiiHandle. + + @retval NULL The string specified by StringId is not present in the st= ring package. + @retval Other The string was returned. + +**/ +EFI_STRING +HiiGetRedfishString ( + IN EFI_HII_HANDLE HiiHandle, + IN CHAR8 *Language, + IN EFI_STRING_ID StringId + ) +{ + EFI_STATUS Status; + UINTN StringSize; + CHAR16 TempString; + EFI_STRING String; + + if ((mRedfishPlatformConfigPrivate->HiiString =3D=3D NULL) || (HiiHandle= =3D=3D NULL) || (StringId =3D=3D 0) || IS_EMPTY_STRING (Language)) { + ASSERT (FALSE); + return NULL; + } + + // + // Retrieve the size of the string in the string package for the BestLan= guage + // + StringSize =3D 0; + Status =3D mRedfishPlatformConfigPrivate->HiiString->GetString ( + mRedfishPlatfor= mConfigPrivate->HiiString, + Language, + HiiHandle, + StringId, + &TempString, + &StringSize, + NULL + ); + // + // If GetString() returns EFI_SUCCESS for a zero size, + // then there are no supported languages registered for HiiHandle. If G= etString() + // returns an error other than EFI_BUFFER_TOO_SMALL, then HiiHandle is n= ot present + // in the HII Database + // + if (Status !=3D EFI_BUFFER_TOO_SMALL) { + return NULL; + } + + // + // Allocate a buffer for the return string + // + String =3D AllocateZeroPool (StringSize); + if (String =3D=3D NULL) { + return NULL; + } + + // + // Retrieve the string from the string package + // + Status =3D mRedfishPlatformConfigPrivate->HiiString->GetString ( + mRedfishPlatformCon= figPrivate->HiiString, + Language, + HiiHandle, + StringId, + String, + &StringSize, + NULL + ); + if (EFI_ERROR (Status)) { + // + // Free the buffer and return NULL if the supported languages can not = be retrieved. + // + FreePool (String); + String =3D NULL; + } + + // + // Return the Null-terminated Unicode string + // + return String; +} + +/** + Retrieves a ASCII string from a string package in a given language. The + returned string is allocated using AllocatePool(). The caller is respon= sible + for freeing the allocated buffer using FreePool(). + + If HiiHandle is NULL, then ASSERT(). + If StringId is 0, then ASSET. + + @param[in] HiiHandle A handle that was previously registered in= the HII Database. + @param[in] Language The specified configure language to get st= ring. + @param[in] StringId The identifier of the string to retrieved = from the string + package associated with HiiHandle. + + @retval NULL The string specified by StringId is not present in the st= ring package. + @retval Other The string was returned. + +**/ +CHAR8 * +HiiGetRedfishAsciiString ( + IN EFI_HII_HANDLE HiiHandle, + IN CHAR8 *Language, + IN EFI_STRING_ID StringId + ) +{ + EFI_STRING HiiString; + UINTN StringSize; + CHAR8 *AsciiString; + + HiiString =3D HiiGetRedfishString (HiiHandle, Language, StringId); + if (HiiString =3D=3D NULL) { + DEBUG ((DEBUG_ERROR, "%a, Can not find string ID: 0x%x with %a\n", __F= UNCTION__, StringId, Language)); + return NULL; + } + + StringSize =3D (StrLen (HiiString) + 1) * sizeof (CHAR8); + AsciiString =3D AllocatePool (StringSize); + if (AsciiString =3D=3D NULL) { + return NULL; + } + + UnicodeStrToAsciiStrS (HiiString, AsciiString, StringSize); + + FreePool (HiiString); + return AsciiString; +} + +/** + Get string from HII database in English language. The returned string is= allocated + using AllocatePool(). The caller is responsible for freeing the allocate= d buffer using + FreePool(). + + @param[in] HiiHandle A handle that was previously registered in= the HII Database. + @param[in] StringId The identifier of the string to retrieved = from the string + package associated with HiiHandle. + + @retval NULL The string specified by StringId is not present in the st= ring package. + @retval Other The string was returned. + +**/ +EFI_STRING +HiiGetEnglishString ( + IN EFI_HII_HANDLE HiiHandle, + IN EFI_STRING_ID StringId + ) +{ + return HiiGetRedfishString (HiiHandle, ENGLISH_LANGUAGE_CODE, StringId); +} + +/** + Get ASCII string from HII database in English language. The returned str= ing is allocated + using AllocatePool(). The caller is responsible for freeing the allocate= d buffer using + FreePool(). + + @param[in] HiiHandle A handle that was previously registered in= the HII Database. + @param[in] StringId The identifier of the string to retrieved = from the string + package associated with HiiHandle. + + @retval NULL The string specified by StringId is not present in the st= ring package. + @retval Other The string was returned. + +**/ +CHAR8 * +HiiGetEnglishAsciiString ( + IN EFI_HII_HANDLE HiiHandle, + IN EFI_STRING_ID StringId + ) +{ + EFI_STRING HiiString; + UINTN StringSize; + CHAR8 *AsciiString; + + HiiString =3D HiiGetRedfishString (HiiHandle, ENGLISH_LANGUAGE_CODE, Str= ingId); + if (HiiString =3D=3D NULL) { + DEBUG ((DEBUG_ERROR, "%a, Can not find string ID: 0x%x with %a\n", __F= UNCTION__, StringId, ENGLISH_LANGUAGE_CODE)); + return NULL; + } + + StringSize =3D (StrLen (HiiString) + 1) * sizeof (CHAR8); + AsciiString =3D AllocatePool (StringSize); + if (AsciiString =3D=3D NULL) { + return NULL; + } + + UnicodeStrToAsciiStrS (HiiString, AsciiString, StringSize); + + FreePool (HiiString); + return AsciiString; +} + +/** + Check and see if this is supported schema or not. + + @param[in] SupportedSchema The list of supported schema. + @param[in] Schema Schema string to be checked. + + @retval BOOLEAN TRUE if this is supported schema. FALSE ot= herwise. + +**/ +BOOLEAN +CheckSupportedSchema ( + IN REDFISH_PLATFORM_CONFIG_SCHEMA *SupportedSchema, + IN CHAR8 *Schema + ) +{ + UINTN Index; + + if ((SupportedSchema =3D=3D NULL) || IS_EMPTY_STRING (Schema)) { + return FALSE; + } + + if (SupportedSchema->Count =3D=3D 0) { + return FALSE; + } + + for (Index =3D 0; Index < SupportedSchema->Count; Index++) { + if (AsciiStrCmp (SupportedSchema->SchemaList[Index], Schema) =3D=3D 0)= { + return TRUE; + } + } + + return FALSE; +} + +/** + Get the list of supported schema from the given HII handle. + + @param[in] HiiHandle HII handle instance. + @param[out] SupportedSchema Supported schema on this HII handle. + + @retval EFI_SUCCESS Schema list is returned. + @retval EFI_INVALID_PARAMETER HiiHandle is NULL or SupportedSchema is NU= LL. + @retval EFI_NOT_FOUND No supported schema found. + @retval EFI_OUT_OF_RESOURCES System is out of memory. + +**/ +EFI_STATUS +GetSupportedSchema ( + IN EFI_HII_HANDLE HiiHandle, + OUT REDFISH_PLATFORM_CONFIG_SCHEMA *SupportedSchema + ) +{ + CHAR8 *SupportedLanguages; + UINTN Index; + UINTN LangIndex; + UINTN Count; + UINTN StrSize; + UINTN ListIndex; + + if ((HiiHandle =3D=3D NULL) || (SupportedSchema =3D=3D NULL)) { + return EFI_INVALID_PARAMETER; + } + + SupportedSchema->Count =3D 0; + + SupportedLanguages =3D HiiGetSupportedLanguages (HiiHandle); + if (SupportedLanguages =3D=3D NULL) { + return EFI_NOT_FOUND; + } + + Index =3D 0; + LangIndex =3D 0; + Count =3D 0; + while (TRUE) { + if ((SupportedLanguages[Index] =3D=3D ';') || (SupportedLanguages[Inde= x] =3D=3D '\0')) { + if (AsciiStrnCmp (&SupportedLanguages[LangIndex], X_UEFI_SCHEMA_PREF= IX, AsciiStrLen (X_UEFI_SCHEMA_PREFIX)) =3D=3D 0) { + ++Count; + } + + LangIndex =3D Index + 1; + } + + if (SupportedLanguages[Index] =3D=3D '\0') { + break; + } + + ++Index; + } + + if (Count =3D=3D 0) { + return EFI_NOT_FOUND; + } + + SupportedSchema->Count =3D Count; + SupportedSchema->SchemaList =3D AllocatePool (sizeof (CHAR8 *) * Count); + if (SupportedSchema->SchemaList =3D=3D NULL) { + return EFI_OUT_OF_RESOURCES; + } + + Index =3D 0; + LangIndex =3D 0; + ListIndex =3D 0; + while (TRUE) { + if ((SupportedLanguages[Index] =3D=3D ';') || (SupportedLanguages[Inde= x] =3D=3D '\0')) { + if (AsciiStrnCmp (&SupportedLanguages[LangIndex], X_UEFI_SCHEMA_PREF= IX, AsciiStrLen (X_UEFI_SCHEMA_PREFIX)) =3D=3D 0) { + StrSize =3D Index - LangIn= dex; + SupportedSchema->SchemaList[ListIndex] =3D AllocateCopyPo= ol ((StrSize + 1), &SupportedLanguages[LangIndex]); + SupportedSchema->SchemaList[ListIndex][StrSize] =3D '\0'; + ++ListIndex; + } + + LangIndex =3D Index + 1; + } + + if (SupportedLanguages[Index] =3D=3D '\0') { + break; + } + + ++Index; + } + + return EFI_SUCCESS; +} + +/** + Search and find statement private instance by given regular expression p= attern + which describes the Configure Language. + + @param[in] RegularExpressionProtocol Regular express protocol. + @param[in] FormsetList Form-set list to search. + @param[in] Schema Schema to be matched. + @param[in] Pattern Regular expression pattern. + @param[out] StatementList Statement list that match above = pattern. + + @retval EFI_SUCCESS Statement list is returned. + @retval EFI_INVALID_PARAMETER Input parameter is NULL. + @retval EFI_NOT_READY Regular express protocol is NULL. + @retval EFI_NOT_FOUND No statement is found. + @retval EFI_OUT_OF_RESOURCES System is out of memory. + +**/ +EFI_STATUS +GetStatementPrivateByConfigureLangRegex ( + IN EFI_REGULAR_EXPRESSION_PROTOCOL *RegularExpressionPr= otocol, + IN LIST_ENTRY *FormsetList, + IN CHAR8 *Schema, + IN EFI_STRING Pattern, + OUT REDFISH_PLATFORM_CONFIG_STATEMENT_PRIVATE_LIST *StatementList + ) +{ + LIST_ENTRY *HiiFormsetLink; + LIST_ENTRY *HiiFormsetNextLink; + REDFISH_PLATFORM_CONFIG_FORM_SET_PRIVATE *HiiFormsetPrivate; + LIST_ENTRY *HiiFormLink; + LIST_ENTRY *HiiNextFormLink; + REDFISH_PLATFORM_CONFIG_FORM_PRIVATE *HiiFormPrivate; + LIST_ENTRY *HiiStatementLink; + LIST_ENTRY *HiiNextStatementLink; + REDFISH_PLATFORM_CONFIG_STATEMENT_PRIVATE *HiiStatementPrivate; + EFI_STRING TmpString; + UINTN CaptureCount; + BOOLEAN IsMatch; + EFI_STATUS Status; + REDFISH_PLATFORM_CONFIG_STATEMENT_PRIVATE_REF *StatementRef; + + if ((FormsetList =3D=3D NULL) || IS_EMPTY_STRING (Schema) || IS_EMPTY_ST= RING (Pattern) || (StatementList =3D=3D NULL)) { + return EFI_INVALID_PARAMETER; + } + + if (RegularExpressionProtocol =3D=3D NULL) { + return EFI_NOT_READY; + } + + StatementList->Count =3D 0; + InitializeListHead (&StatementList->StatementList); + + if (IsListEmpty (FormsetList)) { + return EFI_NOT_FOUND; + } + + HiiFormsetLink =3D GetFirstNode (FormsetList); + while (!IsNull (FormsetList, HiiFormsetLink)) { + HiiFormsetNextLink =3D GetNextNode (FormsetList, HiiFormsetLink); + HiiFormsetPrivate =3D REDFISH_PLATFORM_CONFIG_FORMSET_FROM_LINK (HiiF= ormsetLink); + + // + // Performance check. + // If there is no desired Redfish schema found, skip this formset. + // + if (!CheckSupportedSchema (&HiiFormsetPrivate->SupportedSchema, Schema= )) { + HiiFormsetLink =3D HiiFormsetNextLink; + continue; + } + + HiiFormLink =3D GetFirstNode (&HiiFormsetPrivate->HiiFormList); + while (!IsNull (&HiiFormsetPrivate->HiiFormList, HiiFormLink)) { + HiiNextFormLink =3D GetNextNode (&HiiFormsetPrivate->HiiFormList, Hi= iFormLink); + HiiFormPrivate =3D REDFISH_PLATFORM_CONFIG_FORM_FROM_LINK (HiiFormL= ink); + + HiiStatementLink =3D GetFirstNode (&HiiFormPrivate->StatementList); + while (!IsNull (&HiiFormPrivate->StatementList, HiiStatementLink)) { + HiiNextStatementLink =3D GetNextNode (&HiiFormPrivate->StatementLi= st, HiiStatementLink); + HiiStatementPrivate =3D REDFISH_PLATFORM_CONFIG_STATEMENT_FROM_LI= NK (HiiStatementLink); + + if ((HiiStatementPrivate->Description !=3D 0) && !HiiStatementPriv= ate->Suppressed) { + TmpString =3D HiiGetRedfishString (HiiFormsetPrivate->HiiHandle,= Schema, HiiStatementPrivate->Description); + if (TmpString !=3D NULL) { + Status =3D RegularExpressionProtocol->MatchString ( + RegularExpressionProtoco= l, + TmpString, + Pattern, + &gEfiRegexSyntaxTypePerl= Guid, + &IsMatch, + NULL, + &CaptureCount + ); + if (EFI_ERROR (Status)) { + DEBUG ((DEBUG_ERROR, "%a, MatchString \"%s\" failed: %r\n", = __FUNCTION__, Pattern, Status)); + ASSERT (FALSE); + return Status; + } + + // + // Found + // + if (IsMatch) { + StatementRef =3D AllocateZeroPool (sizeof (REDFISH_PLATFORM_= CONFIG_STATEMENT_PRIVATE_REF)); + if (StatementRef =3D=3D NULL) { + return EFI_OUT_OF_RESOURCES; + } + + StatementRef->Statement =3D HiiStatementPrivate; + InsertTailList (&StatementList->StatementList, &StatementRef= ->Link); + ++StatementList->Count; + } + + FreePool (TmpString); + } + } + + HiiStatementLink =3D HiiNextStatementLink; + } + + HiiFormLink =3D HiiNextFormLink; + } + + HiiFormsetLink =3D HiiFormsetNextLink; + } + + return EFI_SUCCESS; +} + +/** + Get statement private instance by the given configure language. + + @param[in] FormsetList Form-set list to search. + @param[in] Schema Schema to be matched. + @param[in] ConfigureLang Configure language. + + @retval REDFISH_PLATFORM_CONFIG_STATEMENT_PRIVATE * Pointer to stateme= nt private instance. + +**/ +REDFISH_PLATFORM_CONFIG_STATEMENT_PRIVATE * +GetStatementPrivateByConfigureLang ( + IN LIST_ENTRY *FormsetList, + IN CHAR8 *Schema, + IN EFI_STRING ConfigureLang + ) +{ + LIST_ENTRY *HiiFormsetLink; + LIST_ENTRY *HiiFormsetNextLink; + REDFISH_PLATFORM_CONFIG_FORM_SET_PRIVATE *HiiFormsetPrivate; + LIST_ENTRY *HiiFormLink; + LIST_ENTRY *HiiNextFormLink; + REDFISH_PLATFORM_CONFIG_FORM_PRIVATE *HiiFormPrivate; + LIST_ENTRY *HiiStatementLink; + LIST_ENTRY *HiiNextStatementLink; + REDFISH_PLATFORM_CONFIG_STATEMENT_PRIVATE *HiiStatementPrivate; + EFI_STRING TmpString; + + if ((FormsetList =3D=3D NULL) || IS_EMPTY_STRING (Schema) || IS_EMPTY_ST= RING (ConfigureLang)) { + return NULL; + } + + if (IsListEmpty (FormsetList)) { + return NULL; + } + + HiiFormsetLink =3D GetFirstNode (FormsetList); + while (!IsNull (FormsetList, HiiFormsetLink)) { + HiiFormsetNextLink =3D GetNextNode (FormsetList, HiiFormsetLink); + HiiFormsetPrivate =3D REDFISH_PLATFORM_CONFIG_FORMSET_FROM_LINK (HiiF= ormsetLink); + + // + // Performance check. + // If there is no desired Redfish schema found, skip this formset. + // + if (!CheckSupportedSchema (&HiiFormsetPrivate->SupportedSchema, Schema= )) { + HiiFormsetLink =3D HiiFormsetNextLink; + continue; + } + + HiiFormLink =3D GetFirstNode (&HiiFormsetPrivate->HiiFormList); + while (!IsNull (&HiiFormsetPrivate->HiiFormList, HiiFormLink)) { + HiiNextFormLink =3D GetNextNode (&HiiFormsetPrivate->HiiFormList, Hi= iFormLink); + HiiFormPrivate =3D REDFISH_PLATFORM_CONFIG_FORM_FROM_LINK (HiiFormL= ink); + + HiiStatementLink =3D GetFirstNode (&HiiFormPrivate->StatementList); + while (!IsNull (&HiiFormPrivate->StatementList, HiiStatementLink)) { + HiiNextStatementLink =3D GetNextNode (&HiiFormPrivate->StatementLi= st, HiiStatementLink); + HiiStatementPrivate =3D REDFISH_PLATFORM_CONFIG_STATEMENT_FROM_LI= NK (HiiStatementLink); + + DEBUG_CODE ( + STATIC UINTN Index =3D 0; + DEBUG ((REDFISH_PLATFORM_CONFIG_DEBUG, "%a, [%d] search %s in QI= D: 0x%x form: 0x%x formset: %g\n", __FUNCTION__, ++Index, ConfigureLang, Hi= iStatementPrivate->QuestionId, HiiFormPrivate->Id, &HiiFormsetPrivate->Guid= )); + ); + + if (HiiStatementPrivate->Description !=3D 0) { + TmpString =3D HiiGetRedfishString (HiiFormsetPrivate->HiiHandle,= Schema, HiiStatementPrivate->Description); + if (TmpString !=3D NULL) { + if (StrCmp (TmpString, ConfigureLang) =3D=3D 0) { + FreePool (TmpString); + return HiiStatementPrivate; + } + + FreePool (TmpString); + } + } + + HiiStatementLink =3D HiiNextStatementLink; + } + + HiiFormLink =3D HiiNextFormLink; + } + + HiiFormsetLink =3D HiiFormsetNextLink; + } + + return NULL; +} + +/** + Get form-set private instance by the given HII handle. + + @param[in] HiiHandle HII handle instance. + @param[in] FormsetList Form-set list to search. + + @retval REDFISH_PLATFORM_CONFIG_FORM_SET_PRIVATE * Pointer to form-set= private instance. + +**/ +REDFISH_PLATFORM_CONFIG_FORM_SET_PRIVATE * +GetFormsetPrivateByHiiHandle ( + IN EFI_HII_HANDLE HiiHandle, + IN LIST_ENTRY *FormsetList + ) +{ + LIST_ENTRY *HiiFormsetLink; + LIST_ENTRY *HiiFormsetNextLink; + REDFISH_PLATFORM_CONFIG_FORM_SET_PRIVATE *HiiFormsetPrivate; + + if ((HiiHandle =3D=3D NULL) || (FormsetList =3D=3D NULL)) { + return NULL; + } + + if (IsListEmpty (FormsetList)) { + return NULL; + } + + HiiFormsetLink =3D GetFirstNode (FormsetList); + while (!IsNull (FormsetList, HiiFormsetLink)) { + HiiFormsetNextLink =3D GetNextNode (FormsetList, HiiFormsetLink); + HiiFormsetPrivate =3D REDFISH_PLATFORM_CONFIG_FORMSET_FROM_LINK (HiiF= ormsetLink); + + if (HiiFormsetPrivate->HiiHandle =3D=3D HiiHandle) { + return HiiFormsetPrivate; + } + + HiiFormsetLink =3D HiiFormsetNextLink; + } + + return NULL; +} + +/** + Release formset and all the forms and statements that belong to this for= mset. + + @param[in] FormsetPrivate Pointer to HP_HII_FORM_SET_PRIVATE + + @retval EFI_STATUS + +**/ +EFI_STATUS +ReleaseFormset ( + IN REDFISH_PLATFORM_CONFIG_FORM_SET_PRIVATE *FormsetPrivate + ) +{ + LIST_ENTRY *HiiFormLink; + LIST_ENTRY *HiiNextFormLink; + REDFISH_PLATFORM_CONFIG_FORM_PRIVATE *HiiFormPrivate; + LIST_ENTRY *HiiStatementLink; + LIST_ENTRY *HiiNextStatementLink; + REDFISH_PLATFORM_CONFIG_STATEMENT_PRIVATE *HiiStatementPrivate; + UINTN Index; + + if (FormsetPrivate =3D=3D NULL) { + return EFI_INVALID_PARAMETER; + } + + HiiFormLink =3D GetFirstNode (&FormsetPrivate->HiiFormList); + while (!IsNull (&FormsetPrivate->HiiFormList, HiiFormLink)) { + HiiFormPrivate =3D REDFISH_PLATFORM_CONFIG_FORM_FROM_LINK (HiiFormLin= k); + HiiNextFormLink =3D GetNextNode (&FormsetPrivate->HiiFormList, HiiForm= Link); + + HiiStatementLink =3D GetFirstNode (&HiiFormPrivate->StatementList); + while (!IsNull (&HiiFormPrivate->StatementList, HiiStatementLink)) { + HiiStatementPrivate =3D REDFISH_PLATFORM_CONFIG_STATEMENT_FROM_LINK= (HiiStatementLink); + HiiNextStatementLink =3D GetNextNode (&HiiFormPrivate->StatementList= , HiiStatementLink); + + // + // HiiStatementPrivate->HiiStatement will be released in DestroyForm= Set(). + // + + if (HiiStatementPrivate->DesStringCache !=3D NULL) { + FreePool (HiiStatementPrivate->DesStringCache); + HiiStatementPrivate->DesStringCache =3D NULL; + } + + RemoveEntryList (&HiiStatementPrivate->Link); + FreePool (HiiStatementPrivate); + HiiStatementLink =3D HiiNextStatementLink; + } + + // + // HiiStatementPrivate->HiiForm will be released in DestroyFormSet(). + // + + RemoveEntryList (&HiiFormPrivate->Link); + FreePool (HiiFormPrivate); + HiiFormLink =3D HiiNextFormLink; + } + + if (FormsetPrivate->HiiFormSet !=3D NULL) { + DestroyFormSet (FormsetPrivate->HiiFormSet); + FormsetPrivate->HiiFormSet =3D NULL; + } + + if (FormsetPrivate->DevicePathStr !=3D NULL) { + FreePool (FormsetPrivate->DevicePathStr); + } + + // + // Release schema list + // + if (FormsetPrivate->SupportedSchema.SchemaList !=3D NULL) { + for (Index =3D 0; Index < FormsetPrivate->SupportedSchema.Count; Index= ++) { + FreePool (FormsetPrivate->SupportedSchema.SchemaList[Index]); + } + + FreePool (FormsetPrivate->SupportedSchema.SchemaList); + FormsetPrivate->SupportedSchema.SchemaList =3D NULL; + FormsetPrivate->SupportedSchema.Count =3D 0; + } + + return EFI_SUCCESS; +} + +/** + Create new form-set instance. + + @retval REDFISH_PLATFORM_CONFIG_FORM_SET_PRIVATE * Pointer to newly cr= eated form-set private instance. + +**/ +REDFISH_PLATFORM_CONFIG_FORM_SET_PRIVATE * +NewFormsetPrivate ( + VOID + ) +{ + REDFISH_PLATFORM_CONFIG_FORM_SET_PRIVATE *NewFormsetPrivate; + + NewFormsetPrivate =3D AllocateZeroPool (sizeof (REDFISH_PLATFORM_CONFIG_= FORM_SET_PRIVATE)); + if (NewFormsetPrivate =3D=3D NULL) { + return NULL; + } + + // + // Initial newly created formset private data. + // + InitializeListHead (&NewFormsetPrivate->HiiFormList); + + return NewFormsetPrivate; +} + +/** + Load the HII formset from the given HII handle. + + @param[in] HiiHandle Target HII handle to load. + @param[out] FormsetPrivate The formset private data. + + @retval EFI_STATUS + +**/ +EFI_STATUS +LoadFormset ( + IN EFI_HII_HANDLE HiiHandle, + OUT REDFISH_PLATFORM_CONFIG_FORM_SET_PRIVATE *FormsetPrivate + ) +{ + EFI_STATUS Status; + HII_FORMSET *HiiFormSet; + HII_FORM *HiiForm; + LIST_ENTRY *HiiFormLink; + REDFISH_PLATFORM_CONFIG_FORM_PRIVATE *HiiFormPrivate; + HII_STATEMENT *HiiStatement; + LIST_ENTRY *HiiStatementLink; + REDFISH_PLATFORM_CONFIG_STATEMENT_PRIVATE *HiiStatementPrivate; + EFI_GUID ZeroGuid; + EXPRESS_RESULT ExpressionResult; + + if ((HiiHandle =3D=3D NULL) || (FormsetPrivate =3D=3D NULL)) { + return EFI_INVALID_PARAMETER; + } + + HiiFormSet =3D AllocateZeroPool (sizeof (HII_FORMSET)); + if (HiiFormSet =3D=3D NULL) { + return EFI_OUT_OF_RESOURCES; + } + + // + // Find HII formset by the given HII handle. + // + ZeroMem (&ZeroGuid, sizeof (ZeroGuid)); + Status =3D CreateFormSetFromHiiHandle (HiiHandle, &ZeroGuid, HiiFormSet)= ; + if (EFI_ERROR (Status) || IsListEmpty (&HiiFormSet->FormListHead)) { + Status =3D EFI_NOT_FOUND; + goto ErrorExit; + } + + // + // Initialize formset + // + InitializeFormSet (HiiFormSet); + + // + // Initialize formset private data. + // + FormsetPrivate->HiiFormSet =3D HiiFormSet; + FormsetPrivate->HiiHandle =3D HiiHandle; + CopyGuid (&FormsetPrivate->Guid, &HiiFormSet->Guid); + FormsetPrivate->DevicePathStr =3D ConvertDevicePathToText (HiiFormSet->D= evicePath, FALSE, FALSE); + Status =3D GetSupportedSchema (FormsetPrivate->Hi= iHandle, &FormsetPrivate->SupportedSchema); + if (EFI_ERROR (Status)) { + DEBUG ((DEBUG_WARN, "%a, No schema from HII handle: 0x%x found: %r\n",= __FUNCTION__, FormsetPrivate->HiiHandle, Status)); + } + + HiiFormLink =3D GetFirstNode (&HiiFormSet->FormListHead); + while (!IsNull (&HiiFormSet->FormListHead, HiiFormLink)) { + HiiForm =3D HII_FORM_FROM_LINK (HiiFormLink); + + HiiFormPrivate =3D AllocateZeroPool (sizeof (REDFISH_PLATFORM_CONFIG_F= ORM_PRIVATE)); + if (HiiFormPrivate =3D=3D NULL) { + Status =3D EFI_OUT_OF_RESOURCES; + goto ErrorExit; + } + + // + // Initialize form private data. + // + HiiFormPrivate->HiiForm =3D HiiForm; + HiiFormPrivate->Id =3D HiiForm->FormId; + HiiFormPrivate->Title =3D HiiForm->FormTitle; + HiiFormPrivate->ParentFormset =3D FormsetPrivate; + HiiFormPrivate->Suppressed =3D FALSE; + InitializeListHead (&HiiFormPrivate->StatementList); + + if ((HiiForm->SuppressExpression !=3D NULL) && + (EvaluateExpressionList (HiiForm->SuppressExpression, TRUE, HiiFor= mSet, HiiForm) =3D=3D ExpressSuppress)) + { + HiiFormPrivate->Suppressed =3D TRUE; + } + + HiiStatementLink =3D GetFirstNode (&HiiForm->StatementListHead); + while (!IsNull (&HiiForm->StatementListHead, HiiStatementLink)) { + HiiStatement =3D HII_STATEMENT_FROM_LINK (HiiStatementLink); + + HiiStatementPrivate =3D AllocateZeroPool (sizeof (REDFISH_PLATFORM_C= ONFIG_STATEMENT_PRIVATE)); + if (HiiStatementPrivate =3D=3D NULL) { + Status =3D EFI_OUT_OF_RESOURCES; + goto ErrorExit; + } + + // + // Initialize statement private data. + // + HiiStatementPrivate->HiiStatement =3D HiiStatement; + HiiStatementPrivate->QuestionId =3D HiiStatement->Ques= tionId; + HiiStatementPrivate->Description =3D HiiStatement->Prom= pt; + HiiStatementPrivate->Help =3D HiiStatement->Help= ; + HiiStatementPrivate->ParentForm =3D HiiFormPrivate; + HiiStatementPrivate->Flags =3D HiiStatement->Ques= tionFlags; + HiiStatementPrivate->StatementData.NumMaximum =3D HiiStatement->Extr= aData.NumData.Maximum; + HiiStatementPrivate->StatementData.NumMinimum =3D HiiStatement->Extr= aData.NumData.Minimum; + HiiStatementPrivate->StatementData.NumStep =3D HiiStatement->Extr= aData.NumData.Step; + HiiStatementPrivate->StatementData.StrMaxSize =3D HiiStatement->Extr= aData.StrData.MaxSize; + HiiStatementPrivate->StatementData.StrMinSize =3D HiiStatement->Extr= aData.StrData.MinSize; + HiiStatementPrivate->Suppressed =3D FALSE; + HiiStatementPrivate->GrayedOut =3D FALSE; + + // + // Expression + // + if (HiiFormPrivate->Suppressed) { + HiiStatementPrivate->Suppressed =3D TRUE; + } else { + if (HiiStatement->ExpressionList !=3D NULL) { + ExpressionResult =3D EvaluateExpressionList (HiiStatement->Expr= essionList, TRUE, HiiFormSet, HiiForm); + if (ExpressionResult =3D=3D ExpressGrayOut) { + HiiStatementPrivate->GrayedOut =3D TRUE; + } else if (ExpressionResult =3D=3D ExpressSuppress) { + HiiStatementPrivate->Suppressed =3D TRUE; + } + } + } + + // + // Attach to statement list. + // + InsertTailList (&HiiFormPrivate->StatementList, &HiiStatementPrivate= ->Link); + HiiStatementLink =3D GetNextNode (&HiiForm->StatementListHead, HiiSt= atementLink); + } + + // + // Attach to form list. + // + InsertTailList (&FormsetPrivate->HiiFormList, &HiiFormPrivate->Link); + HiiFormLink =3D GetNextNode (&HiiFormSet->FormListHead, HiiFormLink); + } + + return EFI_SUCCESS; + +ErrorExit: + + // + // Release HiiFormSet if HiiFormSet is not linked to FormsetPrivate yet. + // + if ((HiiFormSet !=3D NULL) && (FormsetPrivate->HiiFormSet !=3D HiiFormSe= t)) { + DestroyFormSet (HiiFormSet); + } + + // + // Release resource when error happens. + // + ReleaseFormset (FormsetPrivate); + + return Status; +} + +/** + Load formset list on given HII handle. + + @param[in] HiiHandle HII handle to load formset list. + @param[out] FormsetList Pointer to formset list returned on given hand= le. + + @retval EFI_STATUS + +**/ +EFI_STATUS +LoadFormsetList ( + IN EFI_HII_HANDLE *HiiHandle, + OUT LIST_ENTRY *FormsetList + ) +{ + EFI_STATUS Status; + REDFISH_PLATFORM_CONFIG_FORM_SET_PRIVATE *FormsetPrivate; + + if ((HiiHandle =3D=3D NULL) || (FormsetList =3D=3D NULL)) { + return EFI_INVALID_PARAMETER; + } + + FormsetPrivate =3D GetFormsetPrivateByHiiHandle (HiiHandle, FormsetList)= ; + if (FormsetPrivate !=3D NULL) { + return EFI_ALREADY_STARTED; + } + + FormsetPrivate =3D NewFormsetPrivate (); + if (FormsetPrivate =3D=3D NULL) { + DEBUG ((DEBUG_ERROR, "%a, out of resource\n", __FUNCTION__)); + return EFI_OUT_OF_RESOURCES; + } + + // + // Load formset on the given HII handle. + // + Status =3D LoadFormset (HiiHandle, FormsetPrivate); + if (EFI_ERROR (Status)) { + DEBUG ((DEBUG_ERROR, "%a, failed to load formset: %r\n", __FUNCTION__,= Status)); + FreePool (FormsetPrivate); + return Status; + } + + // + // Attach to cache list. + // + InsertTailList (FormsetList, &FormsetPrivate->Link); + + DEBUG_CODE ( + DumpFormsetList (FormsetList); + ); + + return EFI_SUCCESS; +} + +/** + Release formset list and all the forms that belong to this formset. + + @param[in] FormsetList Pointer to formset list that needs to be + released. + + @retval EFI_STATUS + +**/ +EFI_STATUS +ReleaseFormsetList ( + IN LIST_ENTRY *FormsetList + ) +{ + LIST_ENTRY *HiiFormsetLink; + LIST_ENTRY *HiiFormsetNextLink; + REDFISH_PLATFORM_CONFIG_FORM_SET_PRIVATE *HiiFormsetPrivate; + + if (FormsetList =3D=3D NULL) { + return EFI_INVALID_PARAMETER; + } + + if (IsListEmpty (FormsetList)) { + return EFI_SUCCESS; + } + + HiiFormsetLink =3D GetFirstNode (FormsetList); + while (!IsNull (FormsetList, HiiFormsetLink)) { + HiiFormsetNextLink =3D GetNextNode (FormsetList, HiiFormsetLink); + HiiFormsetPrivate =3D REDFISH_PLATFORM_CONFIG_FORMSET_FROM_LINK (HiiF= ormsetLink); + + // + // Detach from list. + // + RemoveEntryList (&HiiFormsetPrivate->Link); + ReleaseFormset (HiiFormsetPrivate); + FreePool (HiiFormsetPrivate); + HiiFormsetLink =3D HiiFormsetNextLink; + } + + return EFI_SUCCESS; +} + +/** + Get all pending list. + + @param[in] HiiHandle HII handle instance. + @param[in] PendingList Pending list to keep pending data. + + @retval REDFISH_PLATFORM_CONFIG_PENDING_LIST * Pointer to pending list= data. + +**/ +REDFISH_PLATFORM_CONFIG_PENDING_LIST * +GetPendingList ( + IN EFI_HII_HANDLE *HiiHandle, + IN LIST_ENTRY *PendingList + ) +{ + LIST_ENTRY *PendingListLink; + REDFISH_PLATFORM_CONFIG_PENDING_LIST *Target; + + if ((HiiHandle =3D=3D NULL) || (PendingList =3D=3D NULL)) { + return NULL; + } + + if (IsListEmpty (PendingList)) { + return NULL; + } + + PendingListLink =3D GetFirstNode (PendingList); + while (!IsNull (PendingList, PendingListLink)) { + Target =3D REDFISH_PLATFORM_CONFIG_PENDING_LIST_FROM_LINK (PendingList= Link); + + if (Target->HiiHandle =3D=3D HiiHandle) { + return Target; + } + + PendingListLink =3D GetNextNode (PendingList, PendingListLink); + } + + return NULL; +} + +/** + When HII database is updated. Keep updated HII handle into pending list = so + we can process them later. + + @param[in] HiiHandle HII handle instance. + @param[in] PendingList Pending list to keep HII handle which is recentl= y updated. + + @retval EFI_SUCCESS HII handle is saved in pending list. + @retval EFI_INVALID_PARAMETER HiiHandle is NULL or PendingList is NULL= . + @retval EFI_OUT_OF_RESOURCES System is out of memory. + +**/ +EFI_STATUS +NotifyFormsetUpdate ( + IN EFI_HII_HANDLE *HiiHandle, + IN LIST_ENTRY *PendingList + ) +{ + REDFISH_PLATFORM_CONFIG_PENDING_LIST *TargetPendingList; + + if ((HiiHandle =3D=3D NULL) || (PendingList =3D=3D NULL)) { + return EFI_INVALID_PARAMETER; + } + + // + // Check and see if this HII handle is processed already. + // + TargetPendingList =3D GetPendingList (HiiHandle, PendingList); + if (TargetPendingList !=3D NULL) { + TargetPendingList->IsDeleted =3D FALSE; + DEBUG_CODE ( + DEBUG ((REDFISH_PLATFORM_CONFIG_DEBUG, "%a, HII handle: 0x%x is upda= ted\n", __FUNCTION__, HiiHandle)); + ); + return EFI_SUCCESS; + } + + TargetPendingList =3D AllocateZeroPool (sizeof (REDFISH_PLATFORM_CONFIG_= PENDING_LIST)); + if (TargetPendingList =3D=3D NULL) { + return EFI_OUT_OF_RESOURCES; + } + + TargetPendingList->HiiHandle =3D HiiHandle; + TargetPendingList->IsDeleted =3D FALSE; + + InsertTailList (PendingList, &TargetPendingList->Link); + + DEBUG_CODE ( + DEBUG ((REDFISH_PLATFORM_CONFIG_DEBUG, "%a, HII handle: 0x%x is create= d\n", __FUNCTION__, HiiHandle)); + ); + + return EFI_SUCCESS; +} + +/** + When HII database is updated and form-set is deleted. Keep deleted HII h= andle into pending list so + we can process them later. + + @param[in] HiiHandle HII handle instance. + @param[in] PendingList Pending list to keep HII handle which is recentl= y updated. + + @retval EFI_SUCCESS HII handle is saved in pending list. + @retval EFI_INVALID_PARAMETER HiiHandle is NULL or PendingList is NULL= . + @retval EFI_OUT_OF_RESOURCES System is out of memory. + +**/ +EFI_STATUS +NotifyFormsetDeleted ( + IN EFI_HII_HANDLE *HiiHandle, + IN LIST_ENTRY *PendingList + ) +{ + REDFISH_PLATFORM_CONFIG_PENDING_LIST *TargetPendingList; + + if ((HiiHandle =3D=3D NULL) || (PendingList =3D=3D NULL)) { + return EFI_INVALID_PARAMETER; + } + + // + // Check and see if this HII handle is processed already. + // + TargetPendingList =3D GetPendingList (HiiHandle, PendingList); + if (TargetPendingList !=3D NULL) { + TargetPendingList->IsDeleted =3D TRUE; + DEBUG_CODE ( + DEBUG ((REDFISH_PLATFORM_CONFIG_DEBUG, "%a, HII handle: 0x%x is upda= ted and deleted\n", __FUNCTION__, HiiHandle)); + ); + return EFI_SUCCESS; + } + + TargetPendingList =3D AllocateZeroPool (sizeof (REDFISH_PLATFORM_CONFIG_= PENDING_LIST)); + if (TargetPendingList =3D=3D NULL) { + return EFI_OUT_OF_RESOURCES; + } + + TargetPendingList->HiiHandle =3D HiiHandle; + TargetPendingList->IsDeleted =3D TRUE; + + InsertTailList (PendingList, &TargetPendingList->Link); + + DEBUG_CODE ( + DEBUG ((REDFISH_PLATFORM_CONFIG_DEBUG, "%a, HII handle: 0x%x is delete= d\n", __FUNCTION__, HiiHandle)); + ); + + return EFI_SUCCESS; +} + +/** + There are HII database update and we need to process them accordingly so= that we + won't use stale data. This function will parse updated HII handle again = in order + to get updated data-set. + + @param[in] FormsetList List to keep HII form-set. + @param[in] PendingList List to keep HII handle that is updated. + + @retval EFI_SUCCESS HII handle is saved in pending list. + @retval EFI_INVALID_PARAMETER FormsetList is NULL or PendingList is NU= LL. + +**/ +EFI_STATUS +ProcessPendingList ( + IN LIST_ENTRY *FormsetList, + IN LIST_ENTRY *PendingList + ) +{ + LIST_ENTRY *PendingListLink; + LIST_ENTRY *PendingListNextLink; + REDFISH_PLATFORM_CONFIG_PENDING_LIST *Target; + REDFISH_PLATFORM_CONFIG_FORM_SET_PRIVATE *FormsetPrivate; + EFI_STATUS Status; + + if ((FormsetList =3D=3D NULL) || (PendingList =3D=3D NULL)) { + return EFI_INVALID_PARAMETER; + } + + if (IsListEmpty (PendingList)) { + return EFI_SUCCESS; + } + + PendingListLink =3D GetFirstNode (PendingList); + while (!IsNull (PendingList, PendingListLink)) { + PendingListNextLink =3D GetNextNode (PendingList, PendingListLink); + Target =3D REDFISH_PLATFORM_CONFIG_PENDING_LIST_FROM_LINK= (PendingListLink); + + if (Target->IsDeleted) { + // + // The HII resource on this HII handle is removed. Release the forms= et. + // + FormsetPrivate =3D GetFormsetPrivateByHiiHandle (Target->HiiHandle, = FormsetList); + if (FormsetPrivate !=3D NULL) { + DEBUG ((REDFISH_PLATFORM_CONFIG_DEBUG, "%a, formset: %g is removed= because driver release HII resource it already\n", __FUNCTION__, FormsetPr= ivate->Guid)); + RemoveEntryList (&FormsetPrivate->Link); + ReleaseFormset (FormsetPrivate); + FreePool (FormsetPrivate); + } else { + DEBUG ((DEBUG_WARN, "%a, formset on HII handle 0x%x was removed al= ready\n", __FUNCTION__, Target->HiiHandle)); + } + } else { + // + // The HII resource on this HII handle is updated/removed. + // + FormsetPrivate =3D GetFormsetPrivateByHiiHandle (Target->HiiHandle, = FormsetList); + if (FormsetPrivate !=3D NULL) { + // + // HII formset already exist, release it and query again. + // + DEBUG ((REDFISH_PLATFORM_CONFIG_DEBUG, "%a, formset: %g is updated= . Release current formset\n", __FUNCTION__, &FormsetPrivate->Guid)); + RemoveEntryList (&FormsetPrivate->Link); + ReleaseFormset (FormsetPrivate); + FreePool (FormsetPrivate); + } + + Status =3D LoadFormsetList (Target->HiiHandle, FormsetList); + if (EFI_ERROR (Status)) { + DEBUG ((DEBUG_ERROR, "%a, load formset from HII handle: 0x%x faile= d: %r\n", __FUNCTION__, Target->HiiHandle, Status)); + } + } + + // + // Detach it from list first. + // + RemoveEntryList (&Target->Link); + FreePool (Target); + + PendingListLink =3D PendingListNextLink; + } + + return EFI_SUCCESS; +} + +/** + Release all resource in statement list. + + @param[in] StatementList Statement list to be released. + + @retval EFI_SUCCESS All resource are released. + @retval EFI_INVALID_PARAMETER StatementList is NULL. + +**/ +EFI_STATUS +ReleaseStatementList ( + IN REDFISH_PLATFORM_CONFIG_STATEMENT_PRIVATE_LIST *StatementList + ) +{ + REDFISH_PLATFORM_CONFIG_STATEMENT_PRIVATE_REF *StatementRef; + LIST_ENTRY *NextLink; + + if (StatementList =3D=3D NULL) { + return EFI_INVALID_PARAMETER; + } + + if (IsListEmpty (&StatementList->StatementList)) { + return EFI_SUCCESS; + } + + NextLink =3D GetFirstNode (&StatementList->StatementList); + while (!IsNull (&StatementList->StatementList, NextLink)) { + StatementRef =3D REDFISH_PLATFORM_CONFIG_STATEMENT_REF_FROM_LINK (Next= Link); + NextLink =3D GetNextNode (&StatementList->StatementList, NextLink)= ; + + RemoveEntryList (&StatementRef->Link); + FreePool (StatementRef); + } + + return EFI_SUCCESS; +} --=20 2.17.1