From: Zhen Gong <zhen.gong@intel.com>
To: devel@edk2.groups.io
Cc: Zhen Gong <zhen.gong@intel.com>
Subject: [edk2-devel] [PATCH edk2-platforms 4/4] IpmiFeaturePkg: Add FRU drivers
Date: Fri, 27 Oct 2023 13:11:16 -0700 [thread overview]
Message-ID: <9fa66c9a715169b11e039c774f2e791463f276ef.1698437221.git.zhen.gong@intel.com> (raw)
In-Reply-To: <cover.1698437221.git.zhen.gong@intel.com>
Add GenericFruDriver and generate data based on SMBIOS data.
Signed-off-by: Zhen Gong <zhen.gong@intel.com>
---
.../IpmiFeaturePkg/IpmiFeaturePkg.dec | 4 +
.../IpmiFeaturePkg/Include/IpmiFeature.dsc | 3 +-
.../IpmiFeaturePkg/Include/PostMemory.fdf | 3 +-
.../IpmiFeaturePkg/GenericFru/GenericFru.inf | 42 ++
.../IpmiFeaturePkg/IpmiFru/IpmiFru.inf | 35 --
.../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(+), 104 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.<BR>
+#
+# 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 322f061a0fff..000000000000
--- a/Features/Intel/OutOfBandManagement/IpmiFeaturePkg/IpmiFru/IpmiFru.inf
+++ /dev/null
@@ -1,35 +0,0 @@
-### @file
-# Component description file for IPMI FRU.
-#
-# Copyright (c) 2018 - 2019, Intel Corporation. All rights reserved.<BR>
-#
-# 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
- 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.<BR>
+#
+# 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.<BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#ifndef _EFI_GENEFRU_H_
+#define _EFI_GENEFRU_H_
+
+#include <PiDxe.h>
+#include <Library/DebugLib.h>
+#include <Library/BaseMemoryLib.h>
+#include <Library/UefiRuntimeLib.h>
+#include <Library/UefiDriverEntryPoint.h>
+#include <Library/UefiBootServicesTableLib.h>
+#include <Library/UefiRuntimeServicesTableLib.h>
+
+#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.<BR>
+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.<BR>
+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.<BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#ifndef _EFI_IPMI_REDIR_FRU_H_
+#define _EFI_IPMI_REDIR_FRU_H_
+
+#include <Uefi.h>
+#include <Library/BaseLib.h>
+#include <Library/DebugLib.h>
+#include <Library/UefiLib.h>
+
+#include <Library/BaseMemoryLib.h>
+#include <Library/MemoryAllocationLib.h>
+#include <Library/UefiBootServicesTableLib.h>
+
+#include <Protocol/RedirFru.h>
+#include <Protocol/GenericFru.h>
+#include <Protocol/HiiDatabase.h>
+#include <Protocol/HiiString.h>
+#include <IndustryStandard/SmBios.h>
+#include <Protocol/Smbios.h>
+#include <IndustryStandard/Ipmi.h>
+#include <Library/IpmiBaseLib.h>
+#include <Protocol/IpmiTransportProtocol.h>
+
+#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.<BR>
+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.<BR>
+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.<BR>
-SPDX-License-Identifier: BSD-2-Clause-Patent
-
-**/
-
-#include <Library/BaseLib.h>
-#include <Library/UefiBootServicesTableLib.h>
-#include <Library/MemoryAllocationLib.h>
-#include <Library/DebugLib.h>
-#include <Library/BaseMemoryLib.h>
-#include <Library/IpmiCommandLib.h>
-#include <IndustryStandard/Ipmi.h>
-
-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.<BR>
+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.<BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include "IpmiRedirFru.h"
+#include <Library/DebugLib.h>
+
+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 (#110232): https://edk2.groups.io/g/devel/message/110232
Mute This Topic: https://groups.io/mt/102231769/7686176
Group Owner: devel+owner@edk2.groups.io
Unsubscribe: https://edk2.groups.io/g/devel/unsub [rebecca@openfw.io]
-=-=-=-=-=-=-=-=-=-=-=-
next prev parent reply other threads:[~2023-10-27 22:38 UTC|newest]
Thread overview: 7+ messages / expand[flat|nested] mbox.gz Atom feed top
2023-10-27 20:11 [edk2-devel] [PATCH edk2-platforms 0/4] IpmiFeaturePkg: Add server management features Zhen Gong
2023-10-27 20:11 ` [edk2-devel] [PATCH edk2-platforms 1/4] IpmiFeaturePkg: Add Elog drivers Zhen Gong
2023-10-27 20:11 ` [edk2-devel] [PATCH edk2-platforms 2/4] IpmiFeaturePkg: Add ServerManagementLib Zhen Gong
2023-10-27 20:11 ` [edk2-devel] [PATCH edk2-platforms 3/4] IpmiFeaturePkg: Add ACPI power state drivers Zhen Gong
2023-10-27 20:11 ` Zhen Gong [this message]
2023-10-29 1:58 ` [edk2-devel] [PATCH edk2-platforms 0/4] IpmiFeaturePkg: Add server management features Chang, Abner via groups.io
2023-10-29 21:07 ` Zhen Gong
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-list from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=9fa66c9a715169b11e039c774f2e791463f276ef.1698437221.git.zhen.gong@intel.com \
--to=devel@edk2.groups.io \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox