[edk2-devel] [PATCH edk2-platforms 4/4] IpmiFeaturePkg: Add FRU drivers

Zhen Gong zhen.gong at intel.com
Fri Oct 27 20:11:16 UTC 2023


Add GenericFruDriver and generate data based on SMBIOS data.

Signed-off-by: Zhen Gong <zhen.gong at 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/1813853
Group Owner: devel+owner at edk2.groups.io
Unsubscribe: https://edk2.groups.io/g/devel/unsub [edk2-devel-archive at redhat.com]
-=-=-=-=-=-=-=-=-=-=-=-




More information about the edk2-devel-archive mailing list