From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: from mail02.groups.io (mail02.groups.io [66.175.222.108]) by spool.mail.gandi.net (Postfix) with ESMTPS id C6A177803DB for ; Mon, 30 Oct 2023 17:13:43 +0000 (UTC) DKIM-Signature: a=rsa-sha256; bh=1+nknLY2cZBGR8MU9Came740q6JnjWhUU0fEsNb0Vd4=; c=relaxed/simple; d=groups.io; h=From:To:Cc:Subject:Date:Message-Id:In-Reply-To:References:MIME-Version:Precedence:List-Subscribe:List-Help:Sender:List-Id:Mailing-List:Delivered-To:Reply-To:List-Unsubscribe-Post:List-Unsubscribe:Content-Transfer-Encoding; s=20140610; t=1698686022; v=1; b=YMlpwMU+FbV2hNs9eGIXTrL6N4gb7XsS8neIVyrjhvGToUKygalOkfStTN5yCBr5mkbYCc9e pfi13pINWTbYTqreOyOFw6qCDZfUJSpd6FcCmoveVlFkH/sEo3KGzM7e69GkGQa55ZexOkt0qGq bF2NeloxHBsitJXxlGGUhs20= X-Received: by 127.0.0.2 with SMTP id QHNRYY7687511xAwZiUWiMYA; Mon, 30 Oct 2023 10:13:42 -0700 X-Received: from mgamail.intel.com (mgamail.intel.com [134.134.136.24]) by mx.groups.io with SMTP id smtpd.web10.80044.1698611271237553030 for ; Sun, 29 Oct 2023 13:27:51 -0700 X-IronPort-AV: E=McAfee;i="6600,9927,10878"; a="390840891" X-IronPort-AV: E=Sophos;i="6.03,261,1694761200"; d="scan'208";a="390840891" X-Received: from orsmga001.jf.intel.com ([10.7.209.18]) by orsmga102.jf.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 29 Oct 2023 13:27:50 -0700 X-ExtLoop1: 1 X-IronPort-AV: E=McAfee;i="6600,9927,10878"; a="795098455" X-IronPort-AV: E=Sophos;i="6.03,261,1694761200"; d="scan'208";a="795098455" X-Received: from scsrds0181.amr.corp.intel.com ([10.116.50.7]) by orsmga001.jf.intel.com with ESMTP; 29 Oct 2023 13:27:48 -0700 From: "Zhen Gong" To: devel@edk2.groups.io Cc: Zhen Gong Subject: [edk2-devel] [PATCH edk2-platforms v2 4/4] IpmiFeaturePkg: Add FRU drivers Date: Sun, 29 Oct 2023 13:27:40 -0700 Message-Id: <8d7ba08a231175486263cff47615fa81e76c0ce7.1698610713.git.zhen.gong@intel.com> In-Reply-To: References: MIME-Version: 1.0 Precedence: Bulk List-Subscribe: List-Help: Sender: devel@edk2.groups.io List-Id: Mailing-List: list devel@edk2.groups.io; contact devel+owner@edk2.groups.io Reply-To: devel@edk2.groups.io,zhen.gong@intel.com List-Unsubscribe-Post: List-Unsubscribe=One-Click List-Unsubscribe: X-Gm-Message-State: T30cnwU5RiqKbmvC9CXAJXAOx7686176AA= Content-Transfer-Encoding: 8bit X-GND-Status: LEGIT Authentication-Results: spool.mail.gandi.net; dkim=pass header.d=groups.io header.s=20140610 header.b=YMlpwMU+; dmarc=fail reason="SPF not aligned (relaxed), DKIM not aligned (relaxed)" header.from=intel.com (policy=none); spf=pass (spool.mail.gandi.net: domain of bounce@groups.io designates 66.175.222.108 as permitted sender) smtp.mailfrom=bounce@groups.io Add GenericFruDriver and generate data based on SMBIOS data. Signed-off-by: Zhen Gong # Conflicts: # Features/Intel/OutOfBandManagement/IpmiFeaturePkg/IpmiFru/IpmiFru.inf --- .../IpmiFeaturePkg/IpmiFeaturePkg.dec | 4 + .../IpmiFeaturePkg/Include/IpmiFeature.dsc | 3 +- .../IpmiFeaturePkg/Include/PostMemory.fdf | 3 +- .../IpmiFeaturePkg/GenericFru/GenericFru.inf | 42 ++ .../IpmiFeaturePkg/IpmiFru/IpmiFru.inf | 36 -- .../IpmiRedirFru/IpmiRedirFru.inf | 51 ++ .../GenericFru/GenericFruDriver.h | 178 ++++++ .../Include/Protocol/GenericFru.h | 103 ++++ .../Include/Protocol/RedirFru.h | 81 +++ .../IpmiRedirFru/IpmiRedirFru.h | 149 +++++ .../IpmiFeaturePkg/GenericFru/GenericFru.c | 68 +++ .../GenericFru/GenericFruDriver.c | 513 ++++++++++++++++++ .../IpmiFeaturePkg/IpmiFru/IpmiFru.c | 67 --- .../IpmiFeaturePkg/IpmiRedirFru/FruSmbios.c | 469 ++++++++++++++++ .../IpmiRedirFru/IpmiRedirFru.c | 479 ++++++++++++++++ 15 files changed, 2141 insertions(+), 105 deletions(-) create mode 100644 Features/Intel/OutOfBandManagement/IpmiFeaturePkg/GenericFru/GenericFru.inf delete mode 100644 Features/Intel/OutOfBandManagement/IpmiFeaturePkg/IpmiFru/IpmiFru.inf create mode 100644 Features/Intel/OutOfBandManagement/IpmiFeaturePkg/IpmiRedirFru/IpmiRedirFru.inf create mode 100644 Features/Intel/OutOfBandManagement/IpmiFeaturePkg/GenericFru/GenericFruDriver.h create mode 100644 Features/Intel/OutOfBandManagement/IpmiFeaturePkg/Include/Protocol/GenericFru.h create mode 100644 Features/Intel/OutOfBandManagement/IpmiFeaturePkg/Include/Protocol/RedirFru.h create mode 100644 Features/Intel/OutOfBandManagement/IpmiFeaturePkg/IpmiRedirFru/IpmiRedirFru.h create mode 100644 Features/Intel/OutOfBandManagement/IpmiFeaturePkg/GenericFru/GenericFru.c create mode 100644 Features/Intel/OutOfBandManagement/IpmiFeaturePkg/GenericFru/GenericFruDriver.c delete mode 100644 Features/Intel/OutOfBandManagement/IpmiFeaturePkg/IpmiFru/IpmiFru.c create mode 100644 Features/Intel/OutOfBandManagement/IpmiFeaturePkg/IpmiRedirFru/FruSmbios.c create mode 100644 Features/Intel/OutOfBandManagement/IpmiFeaturePkg/IpmiRedirFru/IpmiRedirFru.c diff --git a/Features/Intel/OutOfBandManagement/IpmiFeaturePkg/IpmiFeaturePkg.dec b/Features/Intel/OutOfBandManagement/IpmiFeaturePkg/IpmiFeaturePkg.dec index be0a11e2adb1..d586931a6d6f 100644 --- a/Features/Intel/OutOfBandManagement/IpmiFeaturePkg/IpmiFeaturePkg.dec +++ b/Features/Intel/OutOfBandManagement/IpmiFeaturePkg/IpmiFeaturePkg.dec @@ -63,6 +63,8 @@ [LibraryClasses] [Guids] gIpmiFeaturePkgTokenSpaceGuid = {0xc05283f6, 0xd6a8, 0x48f3, {0x9b, 0x59, 0xfb, 0xca, 0x71, 0x32, 0x0f, 0x12}} gPeiIpmiHobGuid = {0xcb4d3e13, 0x1e34, 0x4373, {0x8a, 0x81, 0xe9, 0x0, 0x10, 0xf1, 0xdb, 0xa4}} + gEfiIpmiFormatFruGuid = { 0x3531fdc6, 0xeae, 0x4cd2, { 0xb0, 0xa6, 0x5f, 0x48, 0xa0, 0xdf, 0xe3, 0x8 } } + gEfiSystemTypeFruGuid = { 0xaab16018, 0x679d, 0x4461, { 0xba, 0x20, 0xe7, 0xc, 0xf7, 0x86, 0x6a, 0x9b } } [Ppis] gPeiIpmiTransportPpiGuid = {0x7bf5fecc, 0xc5b5, 0x4b25, {0x81, 0x1b, 0xb4, 0xb5, 0xb, 0x28, 0x79, 0xf7}} @@ -80,6 +82,8 @@ [Protocols] gSmmGenericElogProtocolGuid = { 0x664ef1f6, 0x19bf, 0x4498, { 0xab, 0x6a, 0xfc, 0x05, 0x72, 0xfb, 0x98, 0x51 } } gEfiRedirElogProtocolGuid = { 0x16d11030, 0x71ba, 0x4e5e, { 0xa9, 0xf9, 0xb4, 0x75, 0xa5, 0x49, 0x4, 0x8a } } gSmmRedirElogProtocolGuid = { 0x79ac2d9c, 0x9216, 0x43c5, { 0xa0, 0x74, 0x0b, 0x45, 0xc7, 0x64, 0x22, 0xc1 } } + gEfiRedirFruProtocolGuid = { 0x28638cfa, 0xea88, 0x456c, { 0x92, 0xa5, 0xf2, 0x49, 0xca, 0x48, 0x85, 0x35 } } + gEfiGenericFruProtocolGuid = { 0xc8eebf0e, 0x0e10, 0x47f7, { 0x81, 0xbd, 0x39, 0xdb, 0x75, 0xca, 0x93, 0x9f } } [PcdsFeatureFlag] gIpmiFeaturePkgTokenSpaceGuid.PcdIpmiFeatureEnable|FALSE|BOOLEAN|0xA0000001 diff --git a/Features/Intel/OutOfBandManagement/IpmiFeaturePkg/Include/IpmiFeature.dsc b/Features/Intel/OutOfBandManagement/IpmiFeaturePkg/Include/IpmiFeature.dsc index 7e663236d9a1..3ceedb2fa3c4 100644 --- a/Features/Intel/OutOfBandManagement/IpmiFeaturePkg/Include/IpmiFeature.dsc +++ b/Features/Intel/OutOfBandManagement/IpmiFeaturePkg/Include/IpmiFeature.dsc @@ -129,7 +129,8 @@ [Components.X64] IpmiFeaturePkg/GenericElog/Dxe/GenericElog.inf IpmiFeaturePkg/GenericElog/Smm/GenericElog.inf IpmiFeaturePkg/Frb/FrbDxe.inf - IpmiFeaturePkg/IpmiFru/IpmiFru.inf + IpmiFeaturePkg/IpmiRedirFru/IpmiRedirFru.inf + IpmiFeaturePkg/GenericFru/GenericFru.inf IpmiFeaturePkg/IpmiInit/DxeIpmiInit.inf IpmiFeaturePkg/OsWdt/OsWdt.inf IpmiFeaturePkg/SolStatus/SolStatus.inf diff --git a/Features/Intel/OutOfBandManagement/IpmiFeaturePkg/Include/PostMemory.fdf b/Features/Intel/OutOfBandManagement/IpmiFeaturePkg/Include/PostMemory.fdf index 9b692f07dcd8..810a041983c1 100644 --- a/Features/Intel/OutOfBandManagement/IpmiFeaturePkg/Include/PostMemory.fdf +++ b/Features/Intel/OutOfBandManagement/IpmiFeaturePkg/Include/PostMemory.fdf @@ -15,8 +15,9 @@ INF IpmiFeaturePkg/BmcElog/DxeBmcElog.inf INF IpmiFeaturePkg/BmcElog/SmmBmcElog.inf INF IpmiFeaturePkg/Frb/FrbDxe.inf -INF IpmiFeaturePkg/IpmiFru/IpmiFru.inf +INF IpmiFeaturePkg/IpmiRedirFru/IpmiRedirFru.inf INF IpmiFeaturePkg/GenericElog/Dxe/GenericElog.inf INF IpmiFeaturePkg/GenericElog/Smm/GenericElog.inf +INF IpmiFeaturePkg/GenericFru/GenericFru.inf INF IpmiFeaturePkg/OsWdt/OsWdt.inf INF IpmiFeaturePkg/SolStatus/SolStatus.inf diff --git a/Features/Intel/OutOfBandManagement/IpmiFeaturePkg/GenericFru/GenericFru.inf b/Features/Intel/OutOfBandManagement/IpmiFeaturePkg/GenericFru/GenericFru.inf new file mode 100644 index 000000000000..f53642b1a476 --- /dev/null +++ b/Features/Intel/OutOfBandManagement/IpmiFeaturePkg/GenericFru/GenericFru.inf @@ -0,0 +1,42 @@ +### @file +# +# Copyright (c) 2023, Intel Corporation. All rights reserved.
+# +# SPDX-License-Identifier: BSD-2-Clause-Patent +# +### + + +[Defines] + INF_VERSION = 0x00010005 + BASE_NAME = GenericFru + FILE_GUID = 663FB335-25DE-45b0-A531-DF3627A13D29 + MODULE_TYPE = DXE_RUNTIME_DRIVER + ENTRY_POINT = InitializeSmFruLayer + +[Sources] + GenericFruDriver.h + GenericFruDriver.c + GenericFru.c + +[Packages] + IpmiFeaturePkg/IpmiFeaturePkg.dec + MdePkg/MdePkg.dec + MdeModulePkg/MdeModulePkg.dec + +[LibraryClasses] + UefiBootServicesTableLib + UefiRuntimeServicesTableLib + UefiRuntimeLib + UefiDriverEntryPoint + BaseMemoryLib + DebugLib + +[Protocols] + gEfiGenericFruProtocolGuid ##Produces + gEfiRedirFruProtocolGuid ##Consumes + +[Guids] + +[Depex] + gIpmiTransportProtocolGuid diff --git a/Features/Intel/OutOfBandManagement/IpmiFeaturePkg/IpmiFru/IpmiFru.inf b/Features/Intel/OutOfBandManagement/IpmiFeaturePkg/IpmiFru/IpmiFru.inf deleted file mode 100644 index f5778f3468df..000000000000 --- a/Features/Intel/OutOfBandManagement/IpmiFeaturePkg/IpmiFru/IpmiFru.inf +++ /dev/null @@ -1,36 +0,0 @@ -### @file -# Component description file for IPMI FRU. -# -# Copyright (c) 2018 - 2019, Intel Corporation. All rights reserved.
-# -# SPDX-License-Identifier: BSD-2-Clause-Patent -# -### - -[Defines] - INF_VERSION = 0x00010005 - BASE_NAME = IpmiFru - FILE_GUID = 3F1D6464-2B4C-4640-BAC4-3DD905D26CDA - MODULE_TYPE = DXE_DRIVER - PI_SPECIFICATION_VERSION = 0x0001000A - VERSION_STRING = 1.0 - ENTRY_POINT = InitializeFru - -[Sources] - IpmiFru.c - -[Packages] - MdePkg/MdePkg.dec - MdeModulePkg/MdeModulePkg.dec - IpmiFeaturePkg/IpmiFeaturePkg.dec - -[LibraryClasses] - UefiDriverEntryPoint - UefiLib - DebugLib - UefiBootServicesTableLib - BaseMemoryLib - IpmiCommandLib - -[Depex] - TRUE diff --git a/Features/Intel/OutOfBandManagement/IpmiFeaturePkg/IpmiRedirFru/IpmiRedirFru.inf b/Features/Intel/OutOfBandManagement/IpmiFeaturePkg/IpmiRedirFru/IpmiRedirFru.inf new file mode 100644 index 000000000000..24fbc94128da --- /dev/null +++ b/Features/Intel/OutOfBandManagement/IpmiFeaturePkg/IpmiRedirFru/IpmiRedirFru.inf @@ -0,0 +1,51 @@ +### @file +# +# Copyright (c) 2023, Intel Corporation. All rights reserved.
+# +# SPDX-License-Identifier: BSD-2-Clause-Patent +# +### + + +[Defines] + INF_VERSION = 0x00010005 + BASE_NAME = IpmiRedirFru + FILE_GUID = 3F1D6464-2B4C-4640-BAC4-3DD905D26CDA + MODULE_TYPE = DXE_DRIVER + PI_SPECIFICATION_VERSION = 0x0001000A + VERSION_STRING = 1.0 + ENTRY_POINT = InitializeSmRedirFruLayer + +[Sources] + FruSmbios.c + IpmiRedirFru.h + IpmiRedirFru.c + +[Packages] + IpmiFeaturePkg/IpmiFeaturePkg.dec + MdePkg/MdePkg.dec + MdeModulePkg/MdeModulePkg.dec + +[LibraryClasses] + UefiDriverEntryPoint + DebugLib + UefiBootServicesTableLib + BaseMemoryLib + MemoryAllocationLib + UefiLib + IpmiBaseLib + +[Guids] + gEfiIpmiFormatFruGuid + gEfiSystemTypeFruGuid + +[Protocols] + gEfiSmbiosProtocolGuid + gEfiRedirFruProtocolGuid # PROTOCOL ALWAYS_PRODUCED + gIpmiTransportProtocolGuid + +[Depex] + gIpmiTransportProtocolGuid AND + gEfiHiiDatabaseProtocolGuid AND + gEfiLoadedImageProtocolGuid + diff --git a/Features/Intel/OutOfBandManagement/IpmiFeaturePkg/GenericFru/GenericFruDriver.h b/Features/Intel/OutOfBandManagement/IpmiFeaturePkg/GenericFru/GenericFruDriver.h new file mode 100644 index 000000000000..1761e52dc453 --- /dev/null +++ b/Features/Intel/OutOfBandManagement/IpmiFeaturePkg/GenericFru/GenericFruDriver.h @@ -0,0 +1,178 @@ +/** @file + Generic FRU functions. + +Copyright (c) 2023, Intel Corporation. All rights reserved.
+SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#ifndef _EFI_GENEFRU_H_ +#define _EFI_GENEFRU_H_ + +#include +#include +#include +#include +#include +#include +#include + +#include "Protocol/GenericFru.h" +#include "Protocol/RedirFru.h" + +#define EFI_FRU_PHYSICAL 0 +#define EFI_FRU_VIRTUAL 1 +#define MAX_REDIR_DESCRIPTOR 10 +// +// A pointer to a function in IPF points to a plabel. +// +typedef struct { + UINT64 EntryPoint; + UINT64 GP; +} EFI_PLABEL; + +typedef struct { + EFI_PLABEL *Function; + EFI_PLABEL Plabel; +} FUNCTION_PTR; + +typedef struct { + EFI_SM_FRU_REDIR_PROTOCOL *This; + FUNCTION_PTR GetFruRedirInfo; + FUNCTION_PTR GetFruSlotInfo; + FUNCTION_PTR GetFruRedirData; + FUNCTION_PTR SetFruRedirData; +} REDIR_FRU_MODULE_PROC; + +typedef struct { + BOOLEAN Valid; + EFI_GUID FruTypeGuid; + UINTN StartSlot; + UINTN EndSlot; + REDIR_FRU_MODULE_PROC Command[2]; +} FRU_REDIR_MODULES; + +typedef struct { + FRU_REDIR_MODULES Redir[MAX_REDIR_DESCRIPTOR]; + UINTN MaxDescriptors; +} FRU_MODULE_GLOBAL; + +/** + Efi Convert Function. + + @param Function + + @retval EFI_SUCCESS + +**/ +EFI_STATUS +EfiConvertFunction ( + IN FUNCTION_PTR *Function + ); + +/** + Efi Set Function Entry. + + @param FunctionPointer + @param Function + + @retval EFI_SUCCESS + +**/ +EFI_STATUS +EfiSetFunctionEntry ( + IN FUNCTION_PTR *FunctionPointer, + IN VOID *Function + ); + +/** + Sm Fru Service Initialize. + + @param ImageHandle + @param SystemTable + + @retval EFI_SUCCESS + +**/ +EFI_STATUS +SmFruServiceInitialize ( + IN EFI_HANDLE ImageHandle, + IN EFI_SYSTEM_TABLE *SystemTable + ); + +/** + Efi Lib Get Fru Info. + + @param FruTypeGuid + @param FruInstance + @param FruFormatGuid + @param DataAccessGranularity + @param FruInformationString + @param Global + @param Virtual + + @retval EFI_SUCCESS + +**/ +EFI_STATUS +EfiLibGetFruInfo ( + IN EFI_GUID *FruTypeGuid, + IN UINTN FruInstance, + OUT EFI_GUID *FruFormatGuid, + OUT UINTN *DataAccessGranularity, + OUT CHAR16 **FruInformationString, + IN FRU_MODULE_GLOBAL *Global, + IN BOOLEAN Virtual + ); + +/** + Efi Lib Get Fru Data. + + @param FruTypeGuid + @param FruInstance + @param FruDataOffset + @param FruDataSize + @param FruData + @param Global + @param Virtual + + @retval EFI_SUCCESS + +**/ +EFI_STATUS +EfiLibGetFruData ( + IN EFI_GUID *FruTypeGuid, + IN UINTN FruInstance, + IN UINTN FruDataOffset, + IN UINTN FruDataSize, + IN UINT8 *FruData, + IN FRU_MODULE_GLOBAL *Global, + IN BOOLEAN Virtual + ); + +/** + Efi Lib Set Fru Data. + + @param FruTypeGuid + @param FruInstance + @param FruDataOffset + @param FruDataSize + @param FruData + @param Global + @param Virtual + + @retval EFI_SUCCESS + +**/ +EFI_STATUS +EfiLibSetFruData ( + IN EFI_GUID *FruTypeGuid, + IN UINTN FruInstance, + IN UINTN FruDataOffset, + IN UINTN FruDataSize, + IN UINT8 *FruData, + IN FRU_MODULE_GLOBAL *Global, + IN BOOLEAN Virtual + ); + +#endif diff --git a/Features/Intel/OutOfBandManagement/IpmiFeaturePkg/Include/Protocol/GenericFru.h b/Features/Intel/OutOfBandManagement/IpmiFeaturePkg/Include/Protocol/GenericFru.h new file mode 100644 index 000000000000..7fcc64ba5038 --- /dev/null +++ b/Features/Intel/OutOfBandManagement/IpmiFeaturePkg/Include/Protocol/GenericFru.h @@ -0,0 +1,103 @@ +/** @file + Generic FRU Protocol as defined in Tiano + This code abstracts the generic FRU Protocol + +Copyright (c) 2023, Intel Corporation. All rights reserved.
+SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#ifndef _GENERIC_FRU_H_ +#define _GENERIC_FRU_H_ + +#define EFI_SM_FRU_PROTOCOL_GUID \ + { \ + 0xc8eebf0e, 0xe10, 0x47f7, 0x81, 0xbd, 0x39, 0xdb, 0x75, 0xca, 0x93, 0x9f \ + } + +typedef struct _EFI_SM_FRU_PROTOCOL EFI_SM_FRU_PROTOCOL; + +// +// Common FRU Types +// +#define EFI_CPU_TYPE_FRU_GUID \ + { \ + 0xf064c91f, 0x188c, 0x4f56, 0xb7, 0xfd, 0x30, 0xa9, 0xb8, 0x6a, 0x29, 0xf3 \ + } + +#define EFI_MEMORY_TYPE_FRU_GUID \ + { \ + 0xd50234f4, 0x6f4b, 0x43e8, 0xa0, 0x13, 0x3c, 0x1e, 0x33, 0xd9, 0xb9, 0xb1 \ + } + +#define EFI_SYSTEM_TYPE_FRU_GUID \ + { \ + 0xaab16018, 0x679d, 0x4461, 0xba, 0x20, 0xe7, 0xc, 0xf7, 0x86, 0x6a, 0x9b \ + } + +// +// Common FRU Formats. +// +#define EFI_IPMI_FORMAT_FRU_GUID \ + { \ + 0x3531fdc6, 0xeae, 0x4cd2, 0xb0, 0xa6, 0x5f, 0x48, 0xa0, 0xdf, 0xe3, 0x8 \ + } + +#define EFI_DMI_FORMAT_FRU_GUID \ + { \ + 0x67ef7a73, 0x2594, 0x4a5e, 0x93, 0xa, 0xe1, 0x66, 0xfa, 0xbc, 0xd2, 0xc8 \ + } + +#define EFI_INTEL_MFG_FORMAT_FRU_GUID \ + { \ + 0x79e8c9c7, 0x1152, 0x4f00, 0xb8, 0x31, 0x14, 0xf1, 0xc4, 0x4, 0x1a, 0xe0 \ + } + +// +// Generic FRU Function Prototypes +// +typedef +EFI_STATUS +(EFIAPI *EFI_GET_FRU_INFO)( + IN EFI_SM_FRU_PROTOCOL *This, + IN EFI_GUID *FruTypeGuid, + IN UINTN FruInstance, + OUT EFI_GUID *FruFormatGuid, + OUT UINTN *DataAccessGranularity, + OUT CHAR16 **FruInformationString + ); + +typedef +EFI_STATUS +(EFIAPI *EFI_GET_FRU_DATA)( + IN EFI_SM_FRU_PROTOCOL *This, + IN EFI_GUID *FruTypeGuid, + IN UINTN FruInstance, + IN UINTN FruDataOffset, + IN UINTN FruDataSize, + IN UINT8 *FruData + ); + +typedef +EFI_STATUS +(EFIAPI *EFI_SET_FRU_DATA)( + IN EFI_SM_FRU_PROTOCOL *This, + IN EFI_GUID *FruTypeGuid, + IN UINTN FruInstance, + IN UINTN FruDataOffset, + IN UINTN FruDataSize, + IN UINT8 *FruData + ); + +// +// GENERIC FRU PROTOCOL +// +typedef struct _EFI_SM_FRU_PROTOCOL { + EFI_GET_FRU_INFO GetFruInfo; + EFI_GET_FRU_DATA GetFruData; + EFI_SET_FRU_DATA SetFruData; +} EFI_SM_FRU_PROTOCOL; + +extern EFI_GUID gEfiGenericFruProtocolGuid; + +#endif diff --git a/Features/Intel/OutOfBandManagement/IpmiFeaturePkg/Include/Protocol/RedirFru.h b/Features/Intel/OutOfBandManagement/IpmiFeaturePkg/Include/Protocol/RedirFru.h new file mode 100644 index 000000000000..30281ba9fa04 --- /dev/null +++ b/Features/Intel/OutOfBandManagement/IpmiFeaturePkg/Include/Protocol/RedirFru.h @@ -0,0 +1,81 @@ +/** @file + This code abstracts the generic FRU Protocol. + +Copyright (c) 2023, Intel Corporation. All rights reserved.
+SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#ifndef _REDIR_FRU_H_ +#define _REDIR_FRU_H_ + +typedef struct _EFI_SM_FRU_REDIR_PROTOCOL EFI_SM_FRU_REDIR_PROTOCOL; + +#define EFI_SM_FRU_REDIR_PROTOCOL_GUID \ + { \ + 0x28638cfa, 0xea88, 0x456c, 0x92, 0xa5, 0xf2, 0x49, 0xca, 0x48, 0x85, 0x35 \ + } + +// {41F49AE4-7FB0-4c54-994E-EA199171B0AC} +#define EFI_PRE_FRU_SMBIOS_DATA_GUID \ + { \ + 0x41f49ae4, 0x7fb0, 0x4c54, 0x99, 0x4e, 0xea, 0x19, 0x91, 0x71, 0xb0, 0xac \ + } + +#define EFI_SM_FRU_REDIR_SIGNATURE SIGNATURE_32 ('f', 'r', 'r', 'x') + +// +// Redir FRU Function Prototypes +// +typedef +EFI_STATUS +(EFIAPI *EFI_GET_FRU_REDIR_INFO)( + IN EFI_SM_FRU_REDIR_PROTOCOL *This, + IN UINTN FruSlotNumber, + OUT EFI_GUID *FruFormatGuid, + OUT UINTN *DataAccessGranularity, + OUT CHAR16 **FruInformationString + ); + +typedef +EFI_STATUS +(EFIAPI *EFI_GET_FRU_SLOT_INFO)( + IN EFI_SM_FRU_REDIR_PROTOCOL *This, + OUT EFI_GUID *FruTypeGuid, + OUT UINTN *StartFruSlotNumber, + OUT UINTN *NumSlots + ); + +typedef +EFI_STATUS +(EFIAPI *EFI_GET_FRU_REDIR_DATA)( + IN EFI_SM_FRU_REDIR_PROTOCOL *This, + IN UINTN FruSlotNumber, + IN UINTN FruDataOffset, + IN UINTN FruDataSize, + IN UINT8 *FruData + ); + +typedef +EFI_STATUS +(EFIAPI *EFI_SET_FRU_REDIR_DATA)( + IN EFI_SM_FRU_REDIR_PROTOCOL *This, + IN UINTN FruSlotNumber, + IN UINTN FruDataOffset, + IN UINTN FruDataSize, + IN UINT8 *FruData + ); + +// +// REDIR FRU PROTOCOL +// +struct _EFI_SM_FRU_REDIR_PROTOCOL { + EFI_GET_FRU_REDIR_INFO GetFruRedirInfo; + EFI_GET_FRU_SLOT_INFO GetFruSlotInfo; + EFI_GET_FRU_REDIR_DATA GetFruRedirData; + EFI_SET_FRU_REDIR_DATA SetFruRedirData; +}; + +extern EFI_GUID gEfiRedirFruProtocolGuid; + +#endif diff --git a/Features/Intel/OutOfBandManagement/IpmiFeaturePkg/IpmiRedirFru/IpmiRedirFru.h b/Features/Intel/OutOfBandManagement/IpmiFeaturePkg/IpmiRedirFru/IpmiRedirFru.h new file mode 100644 index 000000000000..9fd0067973a6 --- /dev/null +++ b/Features/Intel/OutOfBandManagement/IpmiFeaturePkg/IpmiRedirFru/IpmiRedirFru.h @@ -0,0 +1,149 @@ +/** @file + IPMI Redir Sensor functions. + +Copyright (c) 2023, Intel Corporation. All rights reserved.
+SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#ifndef _EFI_IPMI_REDIR_FRU_H_ +#define _EFI_IPMI_REDIR_FRU_H_ + +#include +#include +#include +#include + +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define MAX_FRU_SLOT 20 + +#define IPMI_RDWR_FRU_FRAGMENT_SIZE 0x10 + +#define CHASSIS_TYPE_LENGTH 1 +#define CHASSIS_TYPE_OFFSET 2 +#define CHASSIS_PART_NUMBER 3 + +#define PRODUCT_MFG_OFFSET 3 +#define BOARD_MFG_OFFSET 6 + +#define SMBIOSTYPE1 1 +#define SMBIOSTYPE2 2 +#define SMBIOSTYPE3 3 + +#define OFFSET0 0 +#define OFFSET1 1 +#define OFFSET2 2 +#define OFFSET3 3 +#define OFFSET4 4 +#define OFFSET5 5 +#define OFFSET6 6 +#define OFFSET7 7 +#define OFFSET8 8 +#define OFFSET9 9 + +#define STRING1 1 +#define STRING2 2 +#define STRING3 3 +#define STRING4 4 +#define STRING5 5 +#define STRING6 6 +#define STRING7 7 +#define STRING8 8 +#define STRING9 9 + +typedef struct { + BOOLEAN Valid; + IPMI_FRU_DATA_INFO FruDevice; +} EFI_FRU_DEVICE_INFO; + +typedef struct { + UINTN Signature; + UINT8 MaxFruSlots; + UINT8 NumSlots; + EFI_FRU_DEVICE_INFO FruDeviceInfo[MAX_FRU_SLOT]; + EFI_SM_FRU_REDIR_PROTOCOL IpmiRedirFruProtocol; +} EFI_IPMI_FRU_GLOBAL; + +/** + Get Fru Redir Data. + + @param This + @param FruSlotNumber + @param FruDataOffset + @param FruDataSize + @param FruData + + EFI_STATUS + +**/ +EFI_STATUS +EFIAPI +EfiGetFruRedirData ( + IN EFI_SM_FRU_REDIR_PROTOCOL *This, + IN UINTN FruSlotNumber, + IN UINTN FruDataOffset, + IN UINTN FruDataSize, + IN UINT8 *FruData + ); + +/** + This routine install a notify function listen to gEfiEventReadyToBootGuid. + + @param This - SM Fru Redir protocol + +**/ +VOID +GenerateFruSmbiosData ( + IN EFI_SM_FRU_REDIR_PROTOCOL *This + ); + +#define INSTANCE_FROM_EFI_SM_IPMI_FRU_THIS(a) \ + CR (a, \ + EFI_IPMI_FRU_GLOBAL, \ + IpmiRedirFruProtocol, \ + EFI_SM_FRU_REDIR_SIGNATURE \ + ) + +/** + Do a one byte IO write. + + @param Address - IO address to write + @param Data - Data to write to Address + +Returns: + NONE + +**/ +VOID +IoWrite8 ( + IN UINT64 Address, + IN UINT8 Data + ); + +/** + Do a one byte IO read. + + @param Address - IO address to read + + @retval Data read + +**/ +UINT8 +IoRead8 ( + IN UINT64 Address + ); + +#endif diff --git a/Features/Intel/OutOfBandManagement/IpmiFeaturePkg/GenericFru/GenericFru.c b/Features/Intel/OutOfBandManagement/IpmiFeaturePkg/GenericFru/GenericFru.c new file mode 100644 index 000000000000..8b91a4dd05bc --- /dev/null +++ b/Features/Intel/OutOfBandManagement/IpmiFeaturePkg/GenericFru/GenericFru.c @@ -0,0 +1,68 @@ +/** @file + Hooks for Generic FRU. + +Copyright (c) 2023, Intel Corporation. All rights reserved.
+SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#include "GenericFruDriver.h" + +// +// Don't use module globals after the SetVirtualAddress map is signaled +// +extern FRU_MODULE_GLOBAL *mFruModuleGlobal; + +/** + Efi Convert Function. + + @param Function + + @retval EFI_SUCCESS + +**/ +EFI_STATUS +EfiConvertFunction ( + IN FUNCTION_PTR *Function + ) +{ + gRT->ConvertPointer (0x02, (VOID **)&Function->Function); + return EFI_SUCCESS; +} + +/** + Efi Set Function Entry. + + @param FunctionPointer + @param Function + + @retval EFI_SUCCESS + +**/ +EFI_STATUS +EfiSetFunctionEntry ( + IN FUNCTION_PTR *FunctionPointer, + IN VOID *Function + ) +{ + FunctionPointer->Function = (EFI_PLABEL *)Function; + return EFI_SUCCESS; +} + +/** + SmFru Service Initialize. + + @param ImageHandle + @param SystemTable + + @retval EFI_SUCCESS + +**/ +EFI_STATUS +SmFruServiceInitialize ( + IN EFI_HANDLE ImageHandle, + IN EFI_SYSTEM_TABLE *SystemTable + ) +{ + return EFI_SUCCESS; +} diff --git a/Features/Intel/OutOfBandManagement/IpmiFeaturePkg/GenericFru/GenericFruDriver.c b/Features/Intel/OutOfBandManagement/IpmiFeaturePkg/GenericFru/GenericFruDriver.c new file mode 100644 index 000000000000..523630d452f9 --- /dev/null +++ b/Features/Intel/OutOfBandManagement/IpmiFeaturePkg/GenericFru/GenericFruDriver.c @@ -0,0 +1,513 @@ +/** @file + Server Management Generic FRU Driver. Each FRU REDIR driver attaches + to the Generic FRU driver which is coded in this section. A Runtime + protocol will bind to this and be able to access all the FRU transports + as well as their physical layers. + +Copyright (c) 2023, Intel Corporation. All rights reserved.
+SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#include "GenericFruDriver.h" + +FRU_MODULE_GLOBAL *mFruModuleGlobal; + +// +// Define module globals used to register for notification of when +// the FRU REDIR protocol has been produced. +// +VOID *mEfiFruRedirProtocolNotifyReg; +EFI_EVENT mEfiFruRedirProtocolEvent; + +/** + Efi Lib Get Fru Info. + + @param FruTypeGuid + @param FruInstance + @param FruFormatGuid + @param DataAccessGranularity + @param FruInformationString + @param Global + @param Virtual + + @retval EFI_SUCCESS + +**/ +EFI_STATUS +EfiLibGetFruInfo ( + IN EFI_GUID *FruTypeGuid, + IN UINTN FruInstance, + OUT EFI_GUID *FruFormatGuid, + OUT UINTN *DataAccessGranularity, + OUT CHAR16 **FruInformationString, + IN FRU_MODULE_GLOBAL *Global, + IN BOOLEAN Virtual + ) +{ + UINTN Index; + VOID *FruRedirCommand; + + // + // Get the FRU Type string first. + // + for (Index = 0; Index < Global->MaxDescriptors; Index++) { + if (Global->Redir[Index].Valid) { + if (CompareGuid (&Global->Redir[Index].FruTypeGuid, FruTypeGuid)) { + // + // We found our target, Now check the format it supports. + // + FruRedirCommand = Global->Redir[Index].Command[Virtual].GetFruRedirInfo.Function; + return (*((EFI_GET_FRU_REDIR_INFO *)&FruRedirCommand))( + Global->Redir[Index].Command[Virtual].This, + FruInstance, + FruFormatGuid, + DataAccessGranularity, + FruInformationString + ); + } + } + } + + return EFI_NOT_FOUND; +} + +/** + Efi Get Fru Info. + + @param This + @param FruTypeGuid + @param FruInstance + @param FruFormatGuid + @param DataAccessGranularity + @param FruInformationString + + @retval EFI_SUCCESS + +**/ +EFI_STATUS +EfiGetFruInfo ( + IN EFI_SM_FRU_PROTOCOL *This, + IN EFI_GUID *FruTypeGuid, + IN UINTN FruInstance, + OUT EFI_GUID *FruFormatGuid, + OUT UINTN *DataAccessGranularity, + OUT CHAR16 **FruInformationString + ) +{ + return EfiLibGetFruInfo ( + FruTypeGuid, + FruInstance, + FruFormatGuid, + DataAccessGranularity, + FruInformationString, + mFruModuleGlobal, + EfiGoneVirtual () + ); +} + +/** + Efi Lib Get Fru Data. + + @param FruTypeGuid + @param FruInstance + @param FruDataOffset + @param FruDataSize + @param FruData + @param Global + @param Virtual + + @retval EFI_SUCCESS + +**/ +EFI_STATUS +EfiLibGetFruData ( + IN EFI_GUID *FruTypeGuid, + IN UINTN FruInstance, + IN UINTN FruDataOffset, + IN UINTN FruDataSize, + IN UINT8 *FruData, + IN FRU_MODULE_GLOBAL *Global, + IN BOOLEAN Virtual + ) +{ + UINTN Index; + VOID *FruRedirCommand; + + // + // Get the FRU Type string first. + // + for (Index = 0; Index < Global->MaxDescriptors; Index++) { + if (Global->Redir[Index].Valid) { + if (CompareGuid (&Global->Redir[Index].FruTypeGuid, FruTypeGuid)) { + // + // We found our target, Now check the format it supports. + // + FruRedirCommand = Global->Redir[Index].Command[Virtual].GetFruRedirData.Function; + return (*((EFI_GET_FRU_REDIR_DATA *)&FruRedirCommand))( + Global->Redir[Index].Command[Virtual].This, + FruInstance, + FruDataOffset, + FruDataSize, + FruData + ); + } + } + } + + return EFI_NOT_FOUND; +} + +/** + Efi Get Fru Data. + + @param This + @param FruTypeGuid + @param FruInstance + @param FruDataOffset + @param FruDataSize + @param FruData + + @retval EFI_SUCCESS + +**/ +EFI_STATUS +EfiGetFruData ( + IN EFI_SM_FRU_PROTOCOL *This, + IN EFI_GUID *FruTypeGuid, + IN UINTN FruInstance, + IN UINTN FruDataOffset, + IN UINTN FruDataSize, + IN UINT8 *FruData + ) +{ + return EfiLibGetFruData ( + FruTypeGuid, + FruInstance, + FruDataOffset, + FruDataSize, + FruData, + mFruModuleGlobal, + EfiGoneVirtual () + ); +} + +/** + Efi Lib Set Fru Data. + + @param FruTypeGuid + @param FruInstance + @param FruDataOffset + @param FruDataSize + @param FruData + @param Global + @param Virtual + + @retval EFI_SUCCESS + +**/ +EFI_STATUS +EfiLibSetFruData ( + IN EFI_GUID *FruTypeGuid, + IN UINTN FruInstance, + IN UINTN FruDataOffset, + IN UINTN FruDataSize, + IN UINT8 *FruData, + IN FRU_MODULE_GLOBAL *Global, + IN BOOLEAN Virtual + ) +{ + UINTN Index; + VOID *FruRedirCommand; + + // + // Get the FRU Type string first. + // + for (Index = 0; Index < Global->MaxDescriptors; Index++) { + if (Global->Redir[Index].Valid) { + if (CompareGuid (&Global->Redir[Index].FruTypeGuid, FruTypeGuid)) { + // + // We found our target, Now check the format it supports. + // + FruRedirCommand = Global->Redir[Index].Command[Virtual].SetFruRedirData.Function; + return (*((EFI_SET_FRU_REDIR_DATA *)&FruRedirCommand))( + Global->Redir[Index].Command[Virtual].This, + FruInstance, + FruDataOffset, + FruDataSize, + FruData + ); + } + } + } + + return EFI_NOT_FOUND; +} + +/** + Efi Set Fru Data. + + @param This + @param FruTypeGuid + @param FruInstance + @param FruDataOffset + @param FruDataSize + @param FruData + + @retval EFI_SUCCESS + +**/ +EFI_STATUS +EfiSetFruData ( + IN EFI_SM_FRU_PROTOCOL *This, + IN EFI_GUID *FruTypeGuid, + IN UINTN FruInstance, + IN UINTN FruDataOffset, + IN UINTN FruDataSize, + IN UINT8 *FruData + ) +{ + return EfiLibSetFruData ( + FruTypeGuid, + FruInstance, + FruDataOffset, + FruDataSize, + FruData, + mFruModuleGlobal, + EfiGoneVirtual () + ); +} + +/** + Sm Fru Address Change Event. + + @param Event + @param Context +**/ +VOID +SmFruAddressChangeEvent ( + IN EFI_EVENT Event, + IN VOID *Context + ) +{ + UINTN Index; + REDIR_FRU_MODULE_PROC *RedirProc; + + // + // FRU REDIR Pointer Conversion + // + for (Index = 0; Index < mFruModuleGlobal->MaxDescriptors; Index++) { + if (mFruModuleGlobal->Redir[Index].Valid) { + RedirProc = (REDIR_FRU_MODULE_PROC *)&mFruModuleGlobal->Redir[Index].Command[EFI_FRU_VIRTUAL]; + EfiConvertFunction (&RedirProc->GetFruRedirInfo); + EfiConvertFunction (&RedirProc->GetFruSlotInfo); + EfiConvertFunction (&RedirProc->GetFruRedirData); + EfiConvertFunction (&RedirProc->SetFruRedirData); + EfiConvertPointer (0x02, (VOID **)&RedirProc->This); + } + } +} + +/** + Set Fru Redir Instances. + + @retval EFI_SUCCESS + +**/ +EFI_STATUS +SetFruRedirInstances ( + VOID + ) +{ + UINTN NumHandles; + UINTN Index, Instance, EmptyIndex; + EFI_HANDLE *Buffer; + EFI_STATUS Status; + EFI_SM_FRU_REDIR_PROTOCOL *Redir; + REDIR_FRU_MODULE_PROC *RedirProc; + + // + // Check for all IPMI Controllers + // + Status = gBS->LocateHandleBuffer ( + ByProtocol, + &gEfiRedirFruProtocolGuid, + NULL, + &NumHandles, + &Buffer + ); + + if (EFI_ERROR (Status) || (NumHandles == 0)) { + return EFI_SUCCESS; + } + + EmptyIndex = mFruModuleGlobal->MaxDescriptors; + + for (Index = 0; ((Index < NumHandles) && (Index < mFruModuleGlobal->MaxDescriptors)); Index++) { + Status = gBS->HandleProtocol ( + Buffer[Index], + &gEfiRedirFruProtocolGuid, + (VOID *)&Redir + ); + if (EFI_ERROR (Status) || (Redir == NULL)) { + continue; + } + + for (Instance = 0; Instance < mFruModuleGlobal->MaxDescriptors; Instance++) { + if (mFruModuleGlobal->Redir[Instance].Valid == FALSE) { + if (EmptyIndex >= mFruModuleGlobal->MaxDescriptors) { + EmptyIndex = Instance; + } + } else { + if (Redir == mFruModuleGlobal->Redir[Instance].Command->This) { + EmptyIndex = mFruModuleGlobal->MaxDescriptors; + continue; + } + } + } + + if (EmptyIndex < mFruModuleGlobal->MaxDescriptors) { + Redir->GetFruSlotInfo ( + Redir, + &mFruModuleGlobal->Redir[EmptyIndex].FruTypeGuid, + &mFruModuleGlobal->Redir[EmptyIndex].StartSlot, + &mFruModuleGlobal->Redir[EmptyIndex].EndSlot + ); + + mFruModuleGlobal->Redir[EmptyIndex].EndSlot += mFruModuleGlobal->Redir[EmptyIndex].StartSlot; + RedirProc = (REDIR_FRU_MODULE_PROC *)mFruModuleGlobal->Redir[EmptyIndex].Command; + mFruModuleGlobal->Redir[EmptyIndex].Valid = TRUE; + + EfiSetFunctionEntry (&RedirProc->GetFruRedirInfo, *((VOID **)&Redir->GetFruRedirInfo)); + EfiSetFunctionEntry (&RedirProc->GetFruSlotInfo, *((VOID **)&Redir->GetFruSlotInfo)); + EfiSetFunctionEntry (&RedirProc->GetFruRedirData, *((VOID **)&Redir->GetFruRedirData)); + EfiSetFunctionEntry (&RedirProc->SetFruRedirData, *((VOID **)&Redir->SetFruRedirData)); + RedirProc->This = Redir; + + CopyMem (&RedirProc[EFI_FRU_VIRTUAL], &RedirProc[EFI_FRU_PHYSICAL], sizeof (REDIR_FRU_MODULE_PROC)); + } + } + + if (Buffer != NULL) { + gBS->FreePool (Buffer); + } + + return EFI_SUCCESS; +} + +/** + This notification function is invoked when an instance of the + FRU REDIR protocol is produced. + + @param Event - The event that occurred + @param Context - For EFI compatibility. Not used. + +**/ +VOID +EFIAPI +NotifyFruRedirEventCallback ( + EFI_EVENT Event, + VOID *Context + ) +{ + SetFruRedirInstances (); +} + +/** + Initialize Sm Fru Layer. + + @param ImageHandle + @param SystemTable + + @retval EFI_SUCCESS + +**/ +EFI_STATUS +EFIAPI +InitializeSmFruLayer ( + IN EFI_HANDLE ImageHandle, + IN EFI_SYSTEM_TABLE *SystemTable + ) +{ + EFI_HANDLE NewHandle; + EFI_STATUS Status; + EFI_SM_FRU_PROTOCOL *FruProtocol; + + Status = gBS->AllocatePool ( + EfiRuntimeServicesData, + sizeof (FRU_MODULE_GLOBAL), + (VOID **)&mFruModuleGlobal + ); + + ASSERT_EFI_ERROR (Status); + if (Status != EFI_SUCCESS) { + return Status; + } + + ZeroMem (mFruModuleGlobal, sizeof (FRU_MODULE_GLOBAL)); + + SmFruServiceInitialize (ImageHandle, SystemTable); + + mFruModuleGlobal->MaxDescriptors = MAX_REDIR_DESCRIPTOR; + + // + // Check for all IPMI Controllers + // + SetFruRedirInstances (); + + Status = gBS->AllocatePool ( + EfiRuntimeServicesData, + sizeof (EFI_SM_FRU_PROTOCOL), + (VOID **)&FruProtocol + ); + ASSERT_EFI_ERROR (Status); + if (Status != EFI_SUCCESS) { + return Status; + } + + ZeroMem (FruProtocol, sizeof (EFI_SM_FRU_PROTOCOL)); + + FruProtocol->GetFruInfo = (EFI_GET_FRU_INFO)EfiGetFruInfo; + FruProtocol->GetFruData = (EFI_GET_FRU_DATA)EfiGetFruData; + FruProtocol->SetFruData = (EFI_SET_FRU_DATA)EfiSetFruData; + + NewHandle = NULL; + Status = gBS->InstallProtocolInterface ( + &NewHandle, + &gEfiGenericFruProtocolGuid, + EFI_NATIVE_INTERFACE, + FruProtocol + ); + + ASSERT_EFI_ERROR (Status); + if (Status != EFI_SUCCESS) { + return Status; + } + + // + // Register to be notified when the FRU REDIR protocol has been + // produced. + // + + Status = gBS->CreateEvent ( + EVT_NOTIFY_SIGNAL, + TPL_CALLBACK, + NotifyFruRedirEventCallback, + NULL, + &mEfiFruRedirProtocolEvent + ); + + ASSERT_EFI_ERROR (Status); + if (Status != EFI_SUCCESS) { + return Status; + } + + Status = gBS->RegisterProtocolNotify ( + &gEfiRedirFruProtocolGuid, + mEfiFruRedirProtocolEvent, + &mEfiFruRedirProtocolNotifyReg + ); + ASSERT_EFI_ERROR (Status); + + return Status; +} diff --git a/Features/Intel/OutOfBandManagement/IpmiFeaturePkg/IpmiFru/IpmiFru.c b/Features/Intel/OutOfBandManagement/IpmiFeaturePkg/IpmiFru/IpmiFru.c deleted file mode 100644 index 58e1fb4d7ef0..000000000000 --- a/Features/Intel/OutOfBandManagement/IpmiFeaturePkg/IpmiFru/IpmiFru.c +++ /dev/null @@ -1,67 +0,0 @@ -/** @file - IPMI FRU Driver. - -Copyright (c) 2018 - 2019, Intel Corporation. All rights reserved.
-SPDX-License-Identifier: BSD-2-Clause-Patent - -**/ - -#include -#include -#include -#include -#include -#include -#include - -EFI_STATUS -EFIAPI -InitializeFru ( - IN EFI_HANDLE ImageHandle, - IN EFI_SYSTEM_TABLE *SystemTable - ) -/*++ - -Routine Description: - - Initialize SM Redirection Fru Layer - -Arguments: - - ImageHandle - ImageHandle of the loaded driver - SystemTable - Pointer to the System Table - -Returns: - - EFI_STATUS - ---*/ -{ - EFI_STATUS Status; - IPMI_GET_DEVICE_ID_RESPONSE ControllerInfo; - IPMI_GET_FRU_INVENTORY_AREA_INFO_REQUEST GetFruInventoryAreaInfoRequest; - IPMI_GET_FRU_INVENTORY_AREA_INFO_RESPONSE GetFruInventoryAreaInfoResponse; - - // - // Get all the SDR Records from BMC and retrieve the Record ID from the structure for future use. - // - Status = IpmiGetDeviceId (&ControllerInfo); - if (EFI_ERROR (Status)) { - DEBUG((DEBUG_ERROR, "!!! IpmiFru IpmiGetDeviceId Status=%x\n", Status)); - return Status; - } - - DEBUG((DEBUG_ERROR, "!!! IpmiFru FruInventorySupport %x\n", ControllerInfo.DeviceSupport.Bits.FruInventorySupport)); - - if (ControllerInfo.DeviceSupport.Bits.FruInventorySupport) { - GetFruInventoryAreaInfoRequest.DeviceId = 0; - Status = IpmiGetFruInventoryAreaInfo (&GetFruInventoryAreaInfoRequest, &GetFruInventoryAreaInfoResponse); - if (EFI_ERROR (Status)) { - DEBUG((DEBUG_ERROR, "!!! IpmiFru IpmiGetFruInventoryAreaInfo Status=%x\n", Status)); - return Status; - } - DEBUG((DEBUG_ERROR, "!!! IpmiFru InventoryAreaSize=%x\n", GetFruInventoryAreaInfoResponse.InventoryAreaSize)); - } - - return EFI_SUCCESS; -} diff --git a/Features/Intel/OutOfBandManagement/IpmiFeaturePkg/IpmiRedirFru/FruSmbios.c b/Features/Intel/OutOfBandManagement/IpmiFeaturePkg/IpmiRedirFru/FruSmbios.c new file mode 100644 index 000000000000..bd4b35ba5793 --- /dev/null +++ b/Features/Intel/OutOfBandManagement/IpmiFeaturePkg/IpmiRedirFru/FruSmbios.c @@ -0,0 +1,469 @@ +/** @file + This code reads the FRU and publishes the data to SMBIOS Type 1,2,3 tables. + +Copyright (c) 2023, Intel Corporation. All rights reserved.
+SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#ifndef FRUMAXSTRING +#define FRUMAXSTRING 128 +#endif + +#include "IpmiRedirFru.h" + +EFI_SM_FRU_REDIR_PROTOCOL *mFruRedirProtocol; +EFI_SMBIOS_PROTOCOL *mSmbiosProtocol; + +extern EFI_GUID gEfiSmbiosProtocolGuid; + +/** + Fru Str Len. + + @param Str. + + @retval Length. + +**/ +UINT8 +FruStrLen ( + IN CHAR8 *Str + ) +{ + UINT8 Length; + CHAR8 *Ptr; + + Length = 0; + + if (Str != NULL) { + Ptr = Str; + while (*Ptr != '\0') { + Length++; + Ptr++; + } + } + + return Length; +} + +/** + This routine attempts to get a string out of the FRU at the designated offset in the + buffer pointed to by TempPtr. String type is ASCII. + + @param Offset - Offset of string in buffer pointed to by TempPtr, this is updated to the next + offset. + @param TempPtr - Pointer to a buffer containing the FRU. + @param StrPtr - the pointer to a buffer for retrieve the string get from FRU. + +**/ +VOID +GetStringFromFru ( + IN OUT UINTN *Offset, + IN UINT8 *TempPtr, + IN OUT UINT8 *StrPtr + ) +{ + UINTN Length; + UINT8 *SrcStrPtr; + + if ((Offset == NULL) || (TempPtr == NULL)) { + return; + } + + Length = 0x3F & TempPtr[*Offset]; + SrcStrPtr = &TempPtr[*Offset + 1]; + + ASSERT (Length < FRUMAXSTRING); + if (Length >= FRUMAXSTRING) { + return; + } + + if (StrPtr != NULL) { + if (Length > 0) { + CopyMem (StrPtr, SrcStrPtr, Length); + StrPtr[Length] = '\0'; + } else { + StrPtr[0] = '\0'; + } + } + + *Offset = *Offset + Length + 1; + return; +} + +/** + This routine gets the FRU info area specified by the offset and returns it in + an allocated buffer. It is the caller's responsibility to free the buffer. + + @param This - SM Fru Redir protocol. + @param Offset - Info Area starting offset in multiples of 8 bytes. + + @retval Buffer with FruInfo data or NULL if not found. + +**/ +UINT8 * +GetFruInfoArea ( + IN EFI_SM_FRU_REDIR_PROTOCOL *This, + IN UINTN Offset + ) +{ + EFI_STATUS Status; + UINT8 *TempPtr; + UINTN Length; + + TempPtr = NULL; + + Offset = Offset * 8; + if (Offset > 0) { + // + // Get Info area length, which is in multiples of 8 bytes + // + Length = 0; + Status = EfiGetFruRedirData (This, 0, (Offset + 1), 1, (UINT8 *)&Length); + if (EFI_ERROR (Status)) { + DEBUG ((DEBUG_ERROR, "EfiGetFruRedirData returned status %r\n", Status)); + return NULL; + } + + Length = Length * 8; + + if (Length > 0) { + TempPtr = AllocateRuntimePool (Length); + ASSERT (TempPtr != NULL); + if (TempPtr == NULL) { + return NULL; + } + + Status = EfiGetFruRedirData (This, 0, Offset, Length, TempPtr); + if (EFI_ERROR (Status)) { + DEBUG ((DEBUG_ERROR, "EfiGetFruRedirData returned status %r\n", Status)); + return NULL; + } + } + } + + return TempPtr; +} + +/** + Type1,2,3 only has one instance in SMBIOS tables for each. + + @param TypeNo - The number of SMBIOS TYPE. + + @retval Record the pointer of SMBIOS TYPE structure. + +**/ +UINT8 * +GetStructureByTypeNo ( + IN UINT16 TypeNo + ) +{ + EFI_STATUS Status; + EFI_SMBIOS_HANDLE SmbiosHandle; + EFI_SMBIOS_TABLE_HEADER *Record; + + SmbiosHandle = 0; + + Status = mSmbiosProtocol->GetNext ( + mSmbiosProtocol, + &SmbiosHandle, + (EFI_SMBIOS_TYPE *)&TypeNo, + &Record, + NULL + ); + if (EFI_ERROR (Status)) { + return NULL; + } + + return (UINT8 *)Record; +} + +/** + Smbios Check Sum. + + @param ChecksumSrc. + @param length. + + @retval Record the pointer of SMBIOS TYPE structure. + +**/ +UINT8 +SmbiosCheckSum ( + IN UINT8 *ChecksumSrc, + IN UINT8 length + ) +{ + UINT8 Checksum; + UINT8 Num; + + Checksum = 0; + + for (Num = 0; Num < length; Num++) { + Checksum = Checksum + *ChecksumSrc++; + } + + return (0 - Checksum); +} + +/** + Dynamic Update Type. + + @param TypeNo. + @param StringNo. + @param Data. + +**/ +VOID +DynamicUpdateType ( + IN UINT16 TypeNo, + IN UINTN StringNo, + IN UINT8 *Data + ) +{ + EFI_STATUS Status; + EFI_SMBIOS_HANDLE SmbiosHandle; + EFI_SMBIOS_TABLE_HEADER *Record; + + SmbiosHandle = 0; + + Status = mSmbiosProtocol->GetNext ( + mSmbiosProtocol, + &SmbiosHandle, + (EFI_SMBIOS_TYPE *)&TypeNo, + &Record, + NULL + ); + if (EFI_ERROR (Status)) { + return; + } + + mSmbiosProtocol->UpdateString ( + mSmbiosProtocol, + &SmbiosHandle, + &StringNo, + (CHAR8 *)Data + ); +} + +/** + This routine is notified by protocol gEfiEventReadyToBootGuid, and reads + strings out of the FRU and populates them into the appropriate Smbios tables. + + @param Event. + @param Context. + +**/ +VOID +EFIAPI +GenerateFruSmbiosType123DataNotified ( + IN EFI_EVENT Event, + IN VOID *Context + ) +{ + EFI_STATUS Status; + + UINT8 *FruHdrPtr; + UINT8 FruHdrChksum; + IPMI_FRU_COMMON_HEADER FruCommonHeader; + UINT8 Num; + UINTN Offset; + UINT8 *TempPtr; + UINT8 TempStr[FRUMAXSTRING]; + + UINT8 *TablePtr; + + DEBUG ((DEBUG_INFO, "[FRU SMBIOS]: Generate Fru Smbios Type 1,2,3 Data Notified.\n")); + gBS->CloseEvent (Event); + + SetMem ((UINT8 *)(&FruCommonHeader), sizeof (IPMI_FRU_COMMON_HEADER), 0); + SetMem (TempStr, FRUMAXSTRING, 0); + + Status = gBS->LocateProtocol (&gEfiSmbiosProtocolGuid, NULL, (VOID **)&mSmbiosProtocol); + ASSERT_EFI_ERROR (Status); + if (Status != EFI_SUCCESS) { + return; + } + + Status = EfiGetFruRedirData (mFruRedirProtocol, 0, 0, sizeof (IPMI_FRU_COMMON_HEADER), (UINT8 *)&FruCommonHeader); + + if (EFI_ERROR (Status)) { + DEBUG ((DEBUG_ERROR, "EfiGetFruRedirData returned status %r\n", Status)); + return; + } else { + // + // Do a validity check on the FRU header, since it may be all 0xFF(s) if + // there is no FRU programmed on the system. + // + FruHdrPtr = (UINT8 *)&FruCommonHeader; + for (Num = 0, FruHdrChksum = 0; Num < sizeof (FruCommonHeader); Num++) { + FruHdrChksum = (UINT8)(FruHdrChksum +*FruHdrPtr++); + } + + if (FruHdrChksum != 0) { + DEBUG ((DEBUG_ERROR, "FRU header invalid.\n")); + // + // The FRU information is bad so nothing need to do. + // + return; + } + } + + // + // SMBIOS Type 1, Product data + // + TempPtr = GetFruInfoArea (mFruRedirProtocol, FruCommonHeader.ProductInfoStartingOffset); + if (TempPtr != NULL) { + // + // Get the following fields in the specified order. DO NOT change this order unless the FRU file definition + // changes. Offset is initialized and then is incremented to the next field offset in GetStringFromFru. + // + // Product Manufacturer + // Product Name + // Product Model Number / System Part Number + // Product Version + // Product Serial Number + // Product Asset Tag + // + Offset = PRODUCT_MFG_OFFSET; + GetStringFromFru (&Offset, TempPtr, TempStr); // MiscSystemManufacturer.SystemManufacturer + if (FruStrLen ((CHAR8 *)(TempStr)) != 0) { + DynamicUpdateType (SMBIOSTYPE1, STRING1, TempStr); + } + + GetStringFromFru (&Offset, TempPtr, TempStr); // MiscSystemManufacturer.SystemProductName + if (FruStrLen ((CHAR8 *)(TempStr)) != 0) { + DynamicUpdateType (SMBIOSTYPE1, STRING2, TempStr); + } + + GetStringFromFru (&Offset, TempPtr, TempStr); // ***********************SystemPartNum + + GetStringFromFru (&Offset, TempPtr, TempStr); // MiscSystemManufacturer.SystemVersion + if (FruStrLen ((CHAR8 *)(TempStr)) != 0) { + DynamicUpdateType (SMBIOSTYPE1, STRING3, TempStr); + } + + GetStringFromFru (&Offset, TempPtr, TempStr); // MiscSystemManufacturer.SystemSerialNumber + if (FruStrLen ((CHAR8 *)(TempStr)) != 0) { + DynamicUpdateType (SMBIOSTYPE1, STRING4, TempStr); + } + + GetStringFromFru (&Offset, TempPtr, TempStr); // ***********************AssetTag + if (FruStrLen ((CHAR8 *)(TempStr)) != 0) { + DynamicUpdateType (SMBIOSTYPE3, STRING4, TempStr); // NOTICE: this Asset Tag can be used by type 3 table + } + + FreePool (TempPtr); + } + + // + // SMBIOS Type 2, Base Board data + // + TempPtr = GetFruInfoArea (mFruRedirProtocol, FruCommonHeader.BoardAreaStartingOffset); + if (TempPtr != NULL) { + // + // Get the following fields in the specified order. DO NOT change this order unless the FRU file definition + // changes. Offset is initialized and then is incremented to the next field offset in GetStringFromFru. + // + // Board Manufacturer + // Board Product Name + // Board Serial Number + // Board Part Number + // FRU Version Number + // + Offset = BOARD_MFG_OFFSET; + GetStringFromFru (&Offset, TempPtr, TempStr); // MiscBaseBoardManufacturer.BaseBoardManufacturer + if (FruStrLen ((CHAR8 *)(TempStr)) != 0) { + DynamicUpdateType (SMBIOSTYPE2, STRING1, TempStr); + } + + GetStringFromFru (&Offset, TempPtr, TempStr); // MiscBaseBoardManufacturer.BaseBoardProductName + if (FruStrLen ((CHAR8 *)(TempStr)) != 0) { + DynamicUpdateType (SMBIOSTYPE2, STRING2, TempStr); + } + + GetStringFromFru (&Offset, TempPtr, TempStr); // MiscBaseBoardManufacturer.BaseBoardSerialNumber + if (FruStrLen ((CHAR8 *)(TempStr)) != 0) { + DynamicUpdateType (SMBIOSTYPE2, STRING4, TempStr); + } + + GetStringFromFru (&Offset, TempPtr, TempStr); // MiscBaseBoardManufacturer.BoardPartNumber + if (FruStrLen ((CHAR8 *)(TempStr)) != 0) { + DynamicUpdateType (SMBIOSTYPE2, STRING3, TempStr); + } + + GetStringFromFru (&Offset, TempPtr, TempStr); // **************************FRU Version Number + if (FruStrLen ((CHAR8 *)(TempStr)) != 0) { + DynamicUpdateType (SMBIOSTYPE2, STRING3, TempStr); + } + + FreePool (TempPtr); + } + + // + // SMBIOS Type 3, Chassis data + // + TempPtr = GetFruInfoArea (mFruRedirProtocol, FruCommonHeader.ChassisInfoStartingOffset); + if (TempPtr != NULL) { + // special process: + TablePtr = GetStructureByTypeNo (SMBIOSTYPE3); + ASSERT (TablePtr != NULL); + if (TablePtr == NULL) { + return; + } + + ((SMBIOS_TABLE_TYPE3 *)TablePtr)->Type = TempPtr[CHASSIS_TYPE_OFFSET]; + // + // Get the following fields in the specified order. DO NOT change this order unless the FRU file definition + // changes. Offset is initialized and then is incremented to the next field offset in GetStringFromFru. + // + Offset = CHASSIS_PART_NUMBER; + GetStringFromFru (&Offset, TempPtr, TempStr); // MiscChassisManufacturer.ChassisVersion + if (FruStrLen ((CHAR8 *)(TempStr)) != 0) { + DynamicUpdateType (SMBIOSTYPE3, STRING2, TempStr); + } + + GetStringFromFru (&Offset, TempPtr, TempStr); // MiscChassisManufacturer.ChassisSerialNumber + if (FruStrLen ((CHAR8 *)(TempStr)) != 0) { + DynamicUpdateType (SMBIOSTYPE3, STRING3, TempStr); + } + + GetStringFromFru (&Offset, TempPtr, TempStr); // MiscChassisManufacturer.ChassisManufacturer + if (FruStrLen ((CHAR8 *)(TempStr)) != 0) { + DynamicUpdateType (SMBIOSTYPE3, STRING1, TempStr); + } + + FreePool (TempPtr); + } + + return; +} + +/** + This routine install a notify function listen to ReadyToBoot Event. + + @param This - SM Fru Redir protocol. + +**/ +VOID +GenerateFruSmbiosData ( + IN EFI_SM_FRU_REDIR_PROTOCOL *This + ) +{ + EFI_EVENT Event; + EFI_STATUS Status; + + mFruRedirProtocol = This; + + Status = EfiCreateEventReadyToBootEx ( + TPL_CALLBACK, + GenerateFruSmbiosType123DataNotified, + NULL, + &Event + ); + + if (EFI_ERROR (Status)) { + DEBUG ((DEBUG_ERROR, "GenerateFruSmbiosData(): EfiCreateEventReadyToBootEx failed with return value: %r\n", Status)); + } + + return; +} diff --git a/Features/Intel/OutOfBandManagement/IpmiFeaturePkg/IpmiRedirFru/IpmiRedirFru.c b/Features/Intel/OutOfBandManagement/IpmiFeaturePkg/IpmiRedirFru/IpmiRedirFru.c new file mode 100644 index 000000000000..ac3c8ca50022 --- /dev/null +++ b/Features/Intel/OutOfBandManagement/IpmiFeaturePkg/IpmiRedirFru/IpmiRedirFru.c @@ -0,0 +1,479 @@ +/** @file + Server Management IPMI Redir FRU Driver. This REDIR FRU driver attaches + to the Generic FRU driver. + +Copyright (c) 2023, Intel Corporation. All rights reserved.
+SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#include "IpmiRedirFru.h" +#include + +EFI_IPMI_FRU_GLOBAL *mIpmiFruGlobal; + +/** + Get Empty Fru Slot. + + @retval UINT8 + +**/ +UINT8 +GetEmptyFruSlot ( + VOID + ) +{ + UINT8 Num; + + for (Num = 1; Num < mIpmiFruGlobal->MaxFruSlots; Num++) { + if (!mIpmiFruGlobal->FruDeviceInfo[Num].Valid) { + return Num; + } + } + + return 0xFF; +} + +/** + Get Fru Redir Info. + + @param This + @param FruSlotNumber + @param FruFormatGuid + @param DataAccessGranularity + @param FruInformationString + + @retval EFI_NO_MAPPING + @retval EFI_SUCCESS + +**/ +EFI_STATUS +EFIAPI +EfiGetFruRedirInfo ( + IN EFI_SM_FRU_REDIR_PROTOCOL *This, + IN UINTN FruSlotNumber, + OUT EFI_GUID *FruFormatGuid, + OUT UINTN *DataAccessGranularity, + OUT CHAR16 **FruInformationString + ) +{ + EFI_IPMI_FRU_GLOBAL *FruPrivate; + + FruPrivate = INSTANCE_FROM_EFI_SM_IPMI_FRU_THIS (This); + + if ((FruSlotNumber + 1) > FruPrivate->NumSlots) { + return EFI_NO_MAPPING; + } + + CopyMem (FruFormatGuid, &gEfiIpmiFormatFruGuid, sizeof (EFI_GUID)); + + *DataAccessGranularity = 0x1; + *FruInformationString = NULL; + + return EFI_SUCCESS; +} + +/** + Get Fru Slot Info. + + @param This + @param FruTypeGuid + @param StartFruSlotNumber + @param NumSlots + + @retval EFI_SUCCESS + +**/ +EFI_STATUS +EFIAPI +EfiGetFruSlotInfo ( + IN EFI_SM_FRU_REDIR_PROTOCOL *This, + OUT EFI_GUID *FruTypeGuid, + OUT UINTN *StartFruSlotNumber, + OUT UINTN *NumSlots + ) +{ + EFI_IPMI_FRU_GLOBAL *FruPrivate; + + FruPrivate = NULL; + + FruPrivate = INSTANCE_FROM_EFI_SM_IPMI_FRU_THIS (This); + + CopyMem (FruTypeGuid, &gEfiSystemTypeFruGuid, sizeof (EFI_GUID)); + *StartFruSlotNumber = 0; + *NumSlots = FruPrivate->NumSlots; + return EFI_SUCCESS; +} + +/** + Get Fru Redir Data. + + @param This + @param FruSlotNumber + @param FruDataOffset + @param FruDataSize + @param FruData + + EFI_STATUS + +**/ +EFI_STATUS +EFIAPI +EfiGetFruRedirData ( + IN EFI_SM_FRU_REDIR_PROTOCOL *This, + IN UINTN FruSlotNumber, + IN UINTN FruDataOffset, + IN UINTN FruDataSize, + IN UINT8 *FruData + ) +{ + EFI_IPMI_FRU_GLOBAL *FruPrivate; + UINT32 ResponseDataSize; + UINT8 BackupCount; + UINT8 PointerOffset; + UINT8 DataToCopySize; + EFI_STATUS Status = EFI_SUCCESS; + IPMI_READ_FRU_DATA_REQUEST ReadFruDataRequest; + IPMI_READ_FRU_DATA_RESPONSE *ReadFruDataResponse; + + FruPrivate = NULL; + PointerOffset = 0; + + FruPrivate = INSTANCE_FROM_EFI_SM_IPMI_FRU_THIS (This); + + if ((FruSlotNumber + 1) > FruPrivate->NumSlots) { + Status = EFI_NO_MAPPING; + return Status; + } + + if (FruSlotNumber >= sizeof (FruPrivate->FruDeviceInfo) / sizeof (EFI_FRU_DEVICE_INFO)) { + Status = EFI_INVALID_PARAMETER; + return Status; + } + + if (FruPrivate->FruDeviceInfo[FruSlotNumber].FruDevice.Bits.LogicalFruDevice) { + // + // Create the FRU Read Command for the logical FRU Device. + // + ReadFruDataRequest.DeviceId = FruPrivate->FruDeviceInfo[FruSlotNumber].FruDevice.Bits.FruDeviceId; + ReadFruDataRequest.InventoryOffset = (UINT16)FruDataOffset; + ReadFruDataRequest.CountToRead = (UINT8)FruDataSize; + + ReadFruDataResponse = AllocateZeroPool (sizeof (ReadFruDataResponse) + IPMI_RDWR_FRU_FRAGMENT_SIZE); + + if (ReadFruDataResponse == NULL) { + DEBUG ((DEBUG_ERROR, " Null Pointer returned by AllocateZeroPool to Read Fru data\n")); + return EFI_OUT_OF_RESOURCES; + } + + // + // Collect the data till it is completely retrieved. + // + while (ReadFruDataRequest.CountToRead != 0) { + // + // Backup the count, since we are going to perform fragmented reads + // + BackupCount = ReadFruDataRequest.CountToRead; + if (ReadFruDataRequest.CountToRead > IPMI_RDWR_FRU_FRAGMENT_SIZE) { + ReadFruDataRequest.CountToRead = IPMI_RDWR_FRU_FRAGMENT_SIZE; + } + + ResponseDataSize = sizeof (ReadFruDataResponse) + ReadFruDataRequest.CountToRead; + + Status = IpmiSubmitCommand ( + IPMI_NETFN_STORAGE, + IPMI_STORAGE_READ_FRU_DATA, + (UINT8 *)&ReadFruDataRequest, + sizeof (ReadFruDataRequest), + (UINT8 *)ReadFruDataResponse, + &ResponseDataSize + ); + + if (Status == EFI_BUFFER_TOO_SMALL) { + DEBUG ((DEBUG_WARN, "%a: WARNING:: IpmiSubmitCommand returned EFI_BUFFER_TOO_SMALL \n", __func__)); + } + + if (EFI_ERROR (Status)) { + DEBUG ((DEBUG_ERROR, "%a: IpmiSubmitCommand returned status %r\n", __func__, Status)); + FreePool (ReadFruDataResponse); + return Status; + } + + // + // If the read FRU command returns a count of 0, then no FRU data was found, so exit. + // + if (ReadFruDataResponse->CountReturned == 0x00) { + Status = EFI_NOT_FOUND; + DEBUG ((DEBUG_ERROR, "%a: IpmiSubmitCommand Response data size is 0x0\n", __func__)); + FreePool (ReadFruDataResponse); + return Status; + } + + ReadFruDataRequest.CountToRead = BackupCount; + + // + // In case of partial retrieval; Data[0] contains the retrieved data size; + // + if (ReadFruDataRequest.CountToRead >= ReadFruDataResponse->CountReturned) { + DataToCopySize = ReadFruDataResponse->CountReturned; + ReadFruDataRequest.CountToRead = (UINT8)(ReadFruDataRequest.CountToRead - ReadFruDataResponse->CountReturned); // Remaining Count + } else { + DEBUG (( + DEBUG_WARN, + "%a: WARNING Command.Count (%d) is less than response data size (%d) received\n", + __func__, + ReadFruDataRequest.CountToRead, + ReadFruDataResponse->CountReturned + )); + DataToCopySize = ReadFruDataRequest.CountToRead; + ReadFruDataRequest.CountToRead = 0; // Remaining Count + } + + ReadFruDataRequest.InventoryOffset = (UINT16)(ReadFruDataRequest.InventoryOffset + DataToCopySize); // Next Offset to retrieve + + if (PointerOffset + DataToCopySize > FruDataSize) { + DEBUG (( + DEBUG_ERROR, + "Insufficient storage supplied to %a, need more than % bytes\n", + __func__, + PointerOffset + DataToCopySize + )); + Status = EFI_BUFFER_TOO_SMALL; + FreePool (ReadFruDataResponse); + return Status; + } + + ASSERT (PointerOffset < FruDataSize); + ASSERT (PointerOffset + DataToCopySize <= FruDataSize); + + CopyMem (&FruData[PointerOffset], &ReadFruDataResponse->Data[0], DataToCopySize); // Copy the partial data + PointerOffset = (UINT8)(PointerOffset + DataToCopySize); // Next offset to the iput pointer. + } + + FreePool (ReadFruDataResponse); + } else { + Status = EFI_UNSUPPORTED; + return Status; + } + + return Status; +} + +/** + Set Fru Redir Data. + + @retval This + @retval FruSlotNumber + @retval FruDataOffset + @retval FruDataSize + @retval FruData + + @retval EFI_STATUS + +**/ +EFI_STATUS +EFIAPI +EfiSetFruRedirData ( + IN EFI_SM_FRU_REDIR_PROTOCOL *This, + IN UINTN FruSlotNumber, + IN UINTN FruDataOffset, + IN UINTN FruDataSize, + IN UINT8 *FruData + ) +{ + EFI_IPMI_FRU_GLOBAL *FruPrivate; + UINT8 Count; + UINT8 BackupCount; + UINT32 ResponseDataSize; + UINT8 PointerOffset; + UINT8 DataToCopySize; + EFI_STATUS Status; + IPMI_WRITE_FRU_DATA_REQUEST *WriteFruDataRequest; + IPMI_WRITE_FRU_DATA_RESPONSE WriteFruDataResponse; + + FruPrivate = NULL; + PointerOffset = 0; + + FruPrivate = INSTANCE_FROM_EFI_SM_IPMI_FRU_THIS (This); + + if ((FruSlotNumber + 1) > FruPrivate->NumSlots) { + return EFI_NO_MAPPING; + } + + if (FruSlotNumber >= sizeof (FruPrivate->FruDeviceInfo) / sizeof (EFI_FRU_DEVICE_INFO)) { + return EFI_INVALID_PARAMETER; + } + + if (FruPrivate->FruDeviceInfo[FruSlotNumber].FruDevice.Bits.LogicalFruDevice) { + WriteFruDataRequest = AllocateZeroPool (sizeof (IPMI_WRITE_FRU_DATA_REQUEST) + IPMI_RDWR_FRU_FRAGMENT_SIZE); + + if (WriteFruDataRequest == NULL) { + DEBUG ((DEBUG_ERROR, " Null Pointer returned by AllocateZeroPool to Write Fru data\n")); + return EFI_OUT_OF_RESOURCES; + } + + // + // Create the FRU Write Command for the logical FRU Device. + // + WriteFruDataRequest->DeviceId = FruPrivate->FruDeviceInfo[FruSlotNumber].FruDevice.Bits.FruDeviceId; + WriteFruDataRequest->InventoryOffset = (UINT16)FruDataOffset; + Count = (UINT8)FruDataSize; + PointerOffset = 0; + + // + // Collect the data till it is completely retrieved. + // + while (Count != 0) { + // + // Backup the count, since we are going to perform fragmented reads + // + BackupCount = Count; + if (Count > IPMI_RDWR_FRU_FRAGMENT_SIZE) { + Count = IPMI_RDWR_FRU_FRAGMENT_SIZE; + } + + CopyMem (&WriteFruDataRequest->Data[0], &FruData[PointerOffset], Count); + + ResponseDataSize = sizeof (WriteFruDataResponse); + Status = IpmiSubmitCommand ( + IPMI_NETFN_STORAGE, + IPMI_STORAGE_WRITE_FRU_DATA, + (UINT8 *)WriteFruDataRequest, + (sizeof (WriteFruDataRequest) + Count), + (UINT8 *)&WriteFruDataResponse, + &ResponseDataSize + ); + + if (EFI_ERROR (Status)) { + DEBUG ((DEBUG_ERROR, "%a: IpmiSubmitCommand returned status %r\n", __func__, Status)); + FreePool (WriteFruDataRequest); + return Status; + } + + Count = BackupCount; + + if (Count >= WriteFruDataResponse.CountWritten) { + DataToCopySize = Count - WriteFruDataResponse.CountWritten; + Count = (UINT8)(Count - WriteFruDataResponse.CountWritten); // Remaining Count + } else { + DEBUG (( + DEBUG_WARN, + "%a: WARNING Count (%d) is less than response data size (%d) received\n", + __func__, + Count, + WriteFruDataResponse.CountWritten + )); + DataToCopySize = Count; + Count = 0; // Remaining Count + } + + // + // In case of partial retrieval; Data[0] contains the retrieved data size; + // + WriteFruDataRequest->InventoryOffset = (UINT16)(WriteFruDataRequest->InventoryOffset + DataToCopySize); // Next Offset to set + PointerOffset = (UINT8)(PointerOffset + DataToCopySize); // Next offset to the iput pointer. + } + + FreePool (WriteFruDataRequest); + } else { + return EFI_UNSUPPORTED; + } + + return EFI_SUCCESS; +} + +/** + Initialize SM Redirection Fru Layer. + + @param ImageHandle - ImageHandle of the loaded driver + @param SystemTable - Pointer to the System Table + + @retval EFI_STATUS + +**/ +EFI_STATUS +EFIAPI +InitializeSmRedirFruLayer ( + IN EFI_HANDLE ImageHandle, + IN EFI_SYSTEM_TABLE *SystemTable + ) +{ + EFI_HANDLE NewHandle; + EFI_STATUS Status; + IPMI_GET_DEVICE_ID_RESPONSE GetDeviceIdResponse; + UINT32 ResponseDataSize; + + gST = SystemTable; + gBS = gST->BootServices; + + // + // Initialize Global memory + // + mIpmiFruGlobal = AllocateRuntimePool (sizeof (EFI_IPMI_FRU_GLOBAL)); + ASSERT (mIpmiFruGlobal != NULL); + if (mIpmiFruGlobal == NULL) { + return EFI_OUT_OF_RESOURCES; + } + + mIpmiFruGlobal->NumSlots = 0; + mIpmiFruGlobal->IpmiRedirFruProtocol.GetFruRedirInfo = (EFI_GET_FRU_REDIR_INFO)EfiGetFruRedirInfo; + mIpmiFruGlobal->IpmiRedirFruProtocol.GetFruSlotInfo = (EFI_GET_FRU_SLOT_INFO)EfiGetFruSlotInfo; + mIpmiFruGlobal->IpmiRedirFruProtocol.GetFruRedirData = (EFI_GET_FRU_REDIR_DATA)EfiGetFruRedirData; + mIpmiFruGlobal->IpmiRedirFruProtocol.SetFruRedirData = (EFI_SET_FRU_REDIR_DATA)EfiSetFruRedirData; + mIpmiFruGlobal->Signature = EFI_SM_FRU_REDIR_SIGNATURE; + mIpmiFruGlobal->MaxFruSlots = MAX_FRU_SLOT; + // + // Get all the SDR Records from BMC and retrieve the Record ID from the structure for future use. + // + ResponseDataSize = sizeof (GetDeviceIdResponse); + Status = IpmiSubmitCommand ( + IPMI_NETFN_APP, + IPMI_APP_GET_DEVICE_ID, + (UINT8 *)NULL, + 0, + (UINT8 *)&GetDeviceIdResponse, + &ResponseDataSize + ); + + if (EFI_ERROR (Status)) { + DEBUG ((DEBUG_ERROR, "IpmiSubmitCommand Ipmi App Get DeviceId Failed %r\n", Status)); + return Status; + } + + if (GetDeviceIdResponse.DeviceSupport.Bits.FruInventorySupport) { + // + // Initialize all FRU slots + // Add a mandatory FRU Inventory device attached to the controller. + // + for (mIpmiFruGlobal->NumSlots = 0; mIpmiFruGlobal->NumSlots < mIpmiFruGlobal->MaxFruSlots; mIpmiFruGlobal->NumSlots++) { + mIpmiFruGlobal->FruDeviceInfo[mIpmiFruGlobal->NumSlots].Valid = TRUE; + ZeroMem (&mIpmiFruGlobal->FruDeviceInfo[mIpmiFruGlobal->NumSlots].FruDevice, sizeof (IPMI_FRU_DATA_INFO)); + mIpmiFruGlobal->FruDeviceInfo[mIpmiFruGlobal->NumSlots].FruDevice.Bits.LogicalFruDevice = 1; + mIpmiFruGlobal->FruDeviceInfo[mIpmiFruGlobal->NumSlots].FruDevice.Bits.FruDeviceId = mIpmiFruGlobal->NumSlots; + } + } + + // + // Install callback for ReadyToBoot event to generate FRU SMBIOS Data + // + + GenerateFruSmbiosData (&mIpmiFruGlobal->IpmiRedirFruProtocol); + + // + // Install the FRU Ipmi Redir protocol. + // + NewHandle = NULL; + Status = gBS->InstallProtocolInterface ( + &NewHandle, + &gEfiRedirFruProtocolGuid, + EFI_NATIVE_INTERFACE, + &mIpmiFruGlobal->IpmiRedirFruProtocol + ); + + ASSERT_EFI_ERROR (Status); + if (Status != EFI_SUCCESS) { + return Status; + } + + return EFI_SUCCESS; +} -- 2.39.2.windows.1 -=-=-=-=-=-=-=-=-=-=-=- Groups.io Links: You receive all messages sent to this group. View/Reply Online (#110329): https://edk2.groups.io/g/devel/message/110329 Mute This Topic: https://groups.io/mt/102279908/7686176 Group Owner: devel+owner@edk2.groups.io Unsubscribe: https://edk2.groups.io/g/devel/unsub [rebecca@openfw.io] -=-=-=-=-=-=-=-=-=-=-=-