public inbox for devel@edk2.groups.io
 help / color / mirror / Atom feed
* [edk2-devel] [PATCH edk2-platforms 0/4] IpmiFeaturePkg: Add server management features
@ 2023-10-27 20:11 Zhen Gong
  2023-10-27 20:11 ` [edk2-devel] [PATCH edk2-platforms 1/4] IpmiFeaturePkg: Add Elog drivers Zhen Gong
                   ` (4 more replies)
  0 siblings, 5 replies; 7+ messages in thread
From: Zhen Gong @ 2023-10-27 20:11 UTC (permalink / raw)
  To: devel; +Cc: Zhen Gong

This patch set adds serveral IPMI features to support server management:

BmcAcpiState: A DXE driver to notify BMC of S0 power state.
BmcAcpiSwChild: An SMM driver to notify BMC of ACPI power state changes and add
 SEL records.
BmcElog: PEI, DXE, and SMM drivers to support BMC event log functions.
GenericElog: DXE and SMM drivers to support generic event log functions.
GenericFru: A runtime driver to support generic FRU functions.
IpmiRedirFru: A DXE driver to support BMC FRU functions and generate data based
 on SMBIOS data.
ServerManagementLib: A library to provide essential functions for server
 management drivers.


Zhen Gong (4):
  IpmiFeaturePkg: Add Elog drivers
  IpmiFeaturePkg: Add ServerManagementLib
  IpmiFeaturePkg: Add ACPI power state drivers
  IpmiFeaturePkg: Add FRU drivers

 .../IpmiFeaturePkg/IpmiFeaturePkg.dec         |  10 +
 .../IpmiFeaturePkg/Include/IpmiFeature.dsc    |  13 +-
 .../IpmiFeaturePkg/Include/PostMemory.fdf     |  10 +-
 .../IpmiFeaturePkg/Include/PreMemory.fdf      |   1 +
 .../BmcAcpiState/BmcAcpiState.inf             |  40 +
 .../BmcAcpiSwChild/BmcAcpiSwChild.inf         |  39 +
 .../BmcElog/{BmcElog.inf => DxeBmcElog.inf}   |  25 +-
 .../IpmiFeaturePkg/BmcElog/PeiBmcElog.inf     |  43 ++
 .../IpmiFeaturePkg/BmcElog/SmmBmcElog.inf     |  44 ++
 .../GenericElog/Dxe/GenericElog.inf           |  38 +
 .../GenericElog/Smm/GenericElog.inf           |  38 +
 .../IpmiFeaturePkg/GenericFru/GenericFru.inf  |  42 ++
 .../IpmiFeaturePkg/IpmiFru/IpmiFru.inf        |  35 -
 .../IpmiRedirFru/IpmiRedirFru.inf             |  51 ++
 .../ServerManagementLib.inf                   |  35 +
 .../ServerManagementLibNull.inf               |  38 +
 .../BmcAcpiState/BmcAcpiState.h               |  26 +
 .../BmcAcpiSwChild/BmcAcpiSwChild.h           |  82 +++
 .../BmcElog/Common/BmcElogCommon.h            | 144 ++++
 .../IpmiFeaturePkg/BmcElog/Dxe/BmcElog.h      |  42 ++
 .../IpmiFeaturePkg/BmcElog/Pei/BmcElog.h      |  44 ++
 .../IpmiFeaturePkg/BmcElog/Smm/BmcElog.h      |  43 ++
 .../GenericElog/Dxe/GenericElog.h             | 194 +++++
 .../GenericElog/Smm/GenericElog.h             | 216 ++++++
 .../GenericFru/GenericFruDriver.h             | 178 +++++
 .../Include/Library/ServerMgmtRtLib.h         | 147 ++++
 .../IpmiFeaturePkg/Include/Ppi/GenericElog.h  |  84 +++
 .../Include/Protocol/BmcAcpiSwChildPolicy.h   |  31 +
 .../Include/Protocol/GenericElog.h            |  99 +++
 .../Include/Protocol/GenericFru.h             | 103 +++
 .../Include/Protocol/RedirFru.h               |  81 ++
 .../IpmiRedirFru/IpmiRedirFru.h               | 149 ++++
 .../BmcAcpiState/BmcAcpiState.c               |  93 +++
 .../BmcAcpiSwChild/BmcAcpiSwChild.c           | 189 +++++
 .../IpmiFeaturePkg/BmcElog/BmcElog.c          | 236 ------
 .../BmcElog/Common/BmcElogCommon.c            | 465 ++++++++++++
 .../IpmiFeaturePkg/BmcElog/Dxe/BmcElog.c      | 287 ++++++++
 .../IpmiFeaturePkg/BmcElog/Pei/BmcElog.c      | 297 ++++++++
 .../IpmiFeaturePkg/BmcElog/Smm/BmcElog.c      | 288 ++++++++
 .../GenericElog/Dxe/GenericElog.c             | 576 +++++++++++++++
 .../GenericElog/Smm/GenericElog.c             | 558 ++++++++++++++
 .../IpmiFeaturePkg/GenericFru/GenericFru.c    |  68 ++
 .../GenericFru/GenericFruDriver.c             | 513 +++++++++++++
 .../IpmiFeaturePkg/IpmiFru/IpmiFru.c          |  67 --
 .../IpmiFeaturePkg/IpmiRedirFru/FruSmbios.c   | 469 ++++++++++++
 .../IpmiRedirFru/IpmiRedirFru.c               | 479 ++++++++++++
 .../ServerManagementLib/ServerManagementLib.c | 696 ++++++++++++++++++
 .../ServerManagementLibNull.c                 | 144 ++++
 48 files changed, 7242 insertions(+), 348 deletions(-)
 create mode 100644 Features/Intel/OutOfBandManagement/IpmiFeaturePkg/BmcAcpiState/BmcAcpiState.inf
 create mode 100644 Features/Intel/OutOfBandManagement/IpmiFeaturePkg/BmcAcpiSwChild/BmcAcpiSwChild.inf
 rename Features/Intel/OutOfBandManagement/IpmiFeaturePkg/BmcElog/{BmcElog.inf => DxeBmcElog.inf} (56%)
 create mode 100644 Features/Intel/OutOfBandManagement/IpmiFeaturePkg/BmcElog/PeiBmcElog.inf
 create mode 100644 Features/Intel/OutOfBandManagement/IpmiFeaturePkg/BmcElog/SmmBmcElog.inf
 create mode 100644 Features/Intel/OutOfBandManagement/IpmiFeaturePkg/GenericElog/Dxe/GenericElog.inf
 create mode 100644 Features/Intel/OutOfBandManagement/IpmiFeaturePkg/GenericElog/Smm/GenericElog.inf
 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/Library/ServerManagementLib/ServerManagementLib.inf
 create mode 100644 Features/Intel/OutOfBandManagement/IpmiFeaturePkg/Library/ServerManagementLibNull/ServerManagementLibNull.inf
 create mode 100644 Features/Intel/OutOfBandManagement/IpmiFeaturePkg/BmcAcpiState/BmcAcpiState.h
 create mode 100644 Features/Intel/OutOfBandManagement/IpmiFeaturePkg/BmcAcpiSwChild/BmcAcpiSwChild.h
 create mode 100644 Features/Intel/OutOfBandManagement/IpmiFeaturePkg/BmcElog/Common/BmcElogCommon.h
 create mode 100644 Features/Intel/OutOfBandManagement/IpmiFeaturePkg/BmcElog/Dxe/BmcElog.h
 create mode 100644 Features/Intel/OutOfBandManagement/IpmiFeaturePkg/BmcElog/Pei/BmcElog.h
 create mode 100644 Features/Intel/OutOfBandManagement/IpmiFeaturePkg/BmcElog/Smm/BmcElog.h
 create mode 100644 Features/Intel/OutOfBandManagement/IpmiFeaturePkg/GenericElog/Dxe/GenericElog.h
 create mode 100644 Features/Intel/OutOfBandManagement/IpmiFeaturePkg/GenericElog/Smm/GenericElog.h
 create mode 100644 Features/Intel/OutOfBandManagement/IpmiFeaturePkg/GenericFru/GenericFruDriver.h
 create mode 100644 Features/Intel/OutOfBandManagement/IpmiFeaturePkg/Include/Library/ServerMgmtRtLib.h
 create mode 100644 Features/Intel/OutOfBandManagement/IpmiFeaturePkg/Include/Ppi/GenericElog.h
 create mode 100644 Features/Intel/OutOfBandManagement/IpmiFeaturePkg/Include/Protocol/BmcAcpiSwChildPolicy.h
 create mode 100644 Features/Intel/OutOfBandManagement/IpmiFeaturePkg/Include/Protocol/GenericElog.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/BmcAcpiState/BmcAcpiState.c
 create mode 100644 Features/Intel/OutOfBandManagement/IpmiFeaturePkg/BmcAcpiSwChild/BmcAcpiSwChild.c
 delete mode 100644 Features/Intel/OutOfBandManagement/IpmiFeaturePkg/BmcElog/BmcElog.c
 create mode 100644 Features/Intel/OutOfBandManagement/IpmiFeaturePkg/BmcElog/Common/BmcElogCommon.c
 create mode 100644 Features/Intel/OutOfBandManagement/IpmiFeaturePkg/BmcElog/Dxe/BmcElog.c
 create mode 100644 Features/Intel/OutOfBandManagement/IpmiFeaturePkg/BmcElog/Pei/BmcElog.c
 create mode 100644 Features/Intel/OutOfBandManagement/IpmiFeaturePkg/BmcElog/Smm/BmcElog.c
 create mode 100644 Features/Intel/OutOfBandManagement/IpmiFeaturePkg/GenericElog/Dxe/GenericElog.c
 create mode 100644 Features/Intel/OutOfBandManagement/IpmiFeaturePkg/GenericElog/Smm/GenericElog.c
 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
 create mode 100644 Features/Intel/OutOfBandManagement/IpmiFeaturePkg/Library/ServerManagementLib/ServerManagementLib.c
 create mode 100644 Features/Intel/OutOfBandManagement/IpmiFeaturePkg/Library/ServerManagementLibNull/ServerManagementLibNull.c

-- 
2.39.2.windows.1



-=-=-=-=-=-=-=-=-=-=-=-
Groups.io Links: You receive all messages sent to this group.
View/Reply Online (#110228): https://edk2.groups.io/g/devel/message/110228
Mute This Topic: https://groups.io/mt/102231765/7686176
Group Owner: devel+owner@edk2.groups.io
Unsubscribe: https://edk2.groups.io/g/devel/unsub [rebecca@openfw.io]
-=-=-=-=-=-=-=-=-=-=-=-



^ permalink raw reply	[flat|nested] 7+ messages in thread

* [edk2-devel] [PATCH edk2-platforms 1/4] IpmiFeaturePkg: Add Elog drivers
  2023-10-27 20:11 [edk2-devel] [PATCH edk2-platforms 0/4] IpmiFeaturePkg: Add server management features Zhen Gong
@ 2023-10-27 20:11 ` Zhen Gong
  2023-10-27 20:11 ` [edk2-devel] [PATCH edk2-platforms 2/4] IpmiFeaturePkg: Add ServerManagementLib Zhen Gong
                   ` (3 subsequent siblings)
  4 siblings, 0 replies; 7+ messages in thread
From: Zhen Gong @ 2023-10-27 20:11 UTC (permalink / raw)
  To: devel; +Cc: Zhen Gong

Add generic Elog driver and support BMC Elog operations.

Signed-off-by: Zhen Gong <zhen.gong@intel.com>
---
 .../IpmiFeaturePkg/IpmiFeaturePkg.dec         |   5 +
 .../IpmiFeaturePkg/Include/IpmiFeature.dsc    |   7 +-
 .../IpmiFeaturePkg/Include/PostMemory.fdf     |   5 +-
 .../IpmiFeaturePkg/Include/PreMemory.fdf      |   1 +
 .../BmcElog/{BmcElog.inf => DxeBmcElog.inf}   |  25 +-
 .../IpmiFeaturePkg/BmcElog/PeiBmcElog.inf     |  43 ++
 .../IpmiFeaturePkg/BmcElog/SmmBmcElog.inf     |  44 ++
 .../GenericElog/Dxe/GenericElog.inf           |  38 ++
 .../GenericElog/Smm/GenericElog.inf           |  38 ++
 .../BmcElog/Common/BmcElogCommon.h            | 144 +++++
 .../IpmiFeaturePkg/BmcElog/Dxe/BmcElog.h      |  42 ++
 .../IpmiFeaturePkg/BmcElog/Pei/BmcElog.h      |  44 ++
 .../IpmiFeaturePkg/BmcElog/Smm/BmcElog.h      |  43 ++
 .../GenericElog/Dxe/GenericElog.h             | 194 ++++++
 .../GenericElog/Smm/GenericElog.h             | 216 +++++++
 .../IpmiFeaturePkg/Include/Ppi/GenericElog.h  |  84 +++
 .../Include/Protocol/GenericElog.h            |  99 +++
 .../IpmiFeaturePkg/BmcElog/BmcElog.c          | 236 -------
 .../BmcElog/Common/BmcElogCommon.c            | 465 ++++++++++++++
 .../IpmiFeaturePkg/BmcElog/Dxe/BmcElog.c      | 287 +++++++++
 .../IpmiFeaturePkg/BmcElog/Pei/BmcElog.c      | 297 +++++++++
 .../IpmiFeaturePkg/BmcElog/Smm/BmcElog.c      | 288 +++++++++
 .../GenericElog/Dxe/GenericElog.c             | 576 ++++++++++++++++++
 .../GenericElog/Smm/GenericElog.c             | 558 +++++++++++++++++
 24 files changed, 3535 insertions(+), 244 deletions(-)
 rename Features/Intel/OutOfBandManagement/IpmiFeaturePkg/BmcElog/{BmcElog.inf => DxeBmcElog.inf} (56%)
 create mode 100644 Features/Intel/OutOfBandManagement/IpmiFeaturePkg/BmcElog/PeiBmcElog.inf
 create mode 100644 Features/Intel/OutOfBandManagement/IpmiFeaturePkg/BmcElog/SmmBmcElog.inf
 create mode 100644 Features/Intel/OutOfBandManagement/IpmiFeaturePkg/GenericElog/Dxe/GenericElog.inf
 create mode 100644 Features/Intel/OutOfBandManagement/IpmiFeaturePkg/GenericElog/Smm/GenericElog.inf
 create mode 100644 Features/Intel/OutOfBandManagement/IpmiFeaturePkg/BmcElog/Common/BmcElogCommon.h
 create mode 100644 Features/Intel/OutOfBandManagement/IpmiFeaturePkg/BmcElog/Dxe/BmcElog.h
 create mode 100644 Features/Intel/OutOfBandManagement/IpmiFeaturePkg/BmcElog/Pei/BmcElog.h
 create mode 100644 Features/Intel/OutOfBandManagement/IpmiFeaturePkg/BmcElog/Smm/BmcElog.h
 create mode 100644 Features/Intel/OutOfBandManagement/IpmiFeaturePkg/GenericElog/Dxe/GenericElog.h
 create mode 100644 Features/Intel/OutOfBandManagement/IpmiFeaturePkg/GenericElog/Smm/GenericElog.h
 create mode 100644 Features/Intel/OutOfBandManagement/IpmiFeaturePkg/Include/Ppi/GenericElog.h
 create mode 100644 Features/Intel/OutOfBandManagement/IpmiFeaturePkg/Include/Protocol/GenericElog.h
 delete mode 100644 Features/Intel/OutOfBandManagement/IpmiFeaturePkg/BmcElog/BmcElog.c
 create mode 100644 Features/Intel/OutOfBandManagement/IpmiFeaturePkg/BmcElog/Common/BmcElogCommon.c
 create mode 100644 Features/Intel/OutOfBandManagement/IpmiFeaturePkg/BmcElog/Dxe/BmcElog.c
 create mode 100644 Features/Intel/OutOfBandManagement/IpmiFeaturePkg/BmcElog/Pei/BmcElog.c
 create mode 100644 Features/Intel/OutOfBandManagement/IpmiFeaturePkg/BmcElog/Smm/BmcElog.c
 create mode 100644 Features/Intel/OutOfBandManagement/IpmiFeaturePkg/GenericElog/Dxe/GenericElog.c
 create mode 100644 Features/Intel/OutOfBandManagement/IpmiFeaturePkg/GenericElog/Smm/GenericElog.c

diff --git a/Features/Intel/OutOfBandManagement/IpmiFeaturePkg/IpmiFeaturePkg.dec b/Features/Intel/OutOfBandManagement/IpmiFeaturePkg/IpmiFeaturePkg.dec
index 5df71300cbd1..22bc4e69be8a 100644
--- a/Features/Intel/OutOfBandManagement/IpmiFeaturePkg/IpmiFeaturePkg.dec
+++ b/Features/Intel/OutOfBandManagement/IpmiFeaturePkg/IpmiFeaturePkg.dec
@@ -67,6 +67,7 @@ [Guids]
 [Ppis]
   gPeiIpmiTransportPpiGuid = {0x7bf5fecc, 0xc5b5, 0x4b25, {0x81, 0x1b, 0xb4, 0xb5, 0xb, 0x28, 0x79, 0xf7}}
   gPeiIpmiTransport2PpiGuid = {0x8122CEBD, 0xF4FD, 0x4EA8, { 0x97, 0x6C, 0xF0, 0x30, 0xAD, 0xDC, 0x4C, 0xB4 }}
+  gPeiRedirElogPpiGuid = { 0x7a7c1591, 0xfc67, 0x4f69, { 0xa3, 0x78, 0xfc, 0x3d, 0x4a, 0xd7, 0x92, 0xf7 } }
 
 [Protocols]
   gIpmiTransportProtocolGuid  = {0x6bb945e8, 0x3743, 0x433e, {0xb9, 0x0e, 0x29, 0xb3, 0x0d, 0x5d, 0xc6, 0x30}}
@@ -74,6 +75,10 @@ [Protocols]
   gEfiVideoPrintProtocolGuid     = {0x3dbf3e06, 0x9d0c, 0x40d3, {0xb2, 0x17, 0x45, 0x5f, 0x33, 0x9e, 0x29, 0x09}}
   gIpmiTransport2ProtocolGuid = { 0x4A1D0E66, 0x5271, 0x4E22, { 0x83, 0xFE, 0x90, 0x92, 0x1B, 0x74, 0x82, 0x13 }}
   gSmmIpmiTransport2ProtocolGuid = { 0x1DBD1503, 0x0A60, 0x4230, { 0xAA, 0xA3, 0x80, 0x16, 0xD8, 0xC3, 0xDE, 0x2F }}
+  gEfiGenericElogProtocolGuid = { 0x59d02fcd, 0x9233, 0x4d34, { 0xbc, 0xfe, 0x87, 0xca, 0x81, 0xd3, 0xdd, 0xa7 } }
+  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 } }
 
 [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 0401974b82e2..fa98e5672d83 100644
--- a/Features/Intel/OutOfBandManagement/IpmiFeaturePkg/Include/IpmiFeature.dsc
+++ b/Features/Intel/OutOfBandManagement/IpmiFeaturePkg/Include/IpmiFeature.dsc
@@ -57,6 +57,7 @@ [LibraryClasses.common.DXE_RUNTIME_DRIVER, LibraryClasses.common.DXE_DRIVER]
   IpmbInterfaceLib|IpmiFeaturePkg/Library/BmcInterfaceCommonAccess/IpmbInterfaceLib/DxeIpmbInterfaceLib.inf
 
 [LibraryClasses.common.DXE_SMM_DRIVER]
+  IpmiBaseLib|IpmiFeaturePkg/Library/SmmIpmiBaseLib/SmmIpmiBaseLib.inf
   SsifInterfaceLib|IpmiFeaturePkg/Library/BmcInterfaceCommonAccess/SsifInterfaceLib/SmmSsifInterfaceLib.inf
   IpmbInterfaceLib|IpmiFeaturePkg/Library/BmcInterfaceCommonAccess/IpmbInterfaceLib/SmmIpmbInterfaceLib.inf
 
@@ -96,6 +97,7 @@ [Components.IA32]
   IpmiFeaturePkg/GenericIpmi/Pei/PeiGenericIpmi.inf
   IpmiFeaturePkg/Frb/FrbPei.inf
   IpmiFeaturePkg/IpmiInit/PeiIpmiInit.inf
+  IpmiFeaturePkg/BmcElog/PeiBmcElog.inf
 
 #
 # Feature DXE Components
@@ -119,7 +121,10 @@ [Components.X64]
   IpmiFeaturePkg/GenericIpmi/Dxe/GenericIpmi.inf
   IpmiFeaturePkg/Library/SmmIpmiBaseLib/SmmIpmiBaseLib.inf
   IpmiFeaturePkg/BmcAcpi/BmcAcpi.inf
-  IpmiFeaturePkg/BmcElog/BmcElog.inf
+  IpmiFeaturePkg/BmcElog/DxeBmcElog.inf
+  IpmiFeaturePkg/BmcElog/SmmBmcElog.inf
+  IpmiFeaturePkg/GenericElog/Dxe/GenericElog.inf
+  IpmiFeaturePkg/GenericElog/Smm/GenericElog.inf
   IpmiFeaturePkg/Frb/FrbDxe.inf
   IpmiFeaturePkg/IpmiFru/IpmiFru.inf
   IpmiFeaturePkg/IpmiInit/DxeIpmiInit.inf
diff --git a/Features/Intel/OutOfBandManagement/IpmiFeaturePkg/Include/PostMemory.fdf b/Features/Intel/OutOfBandManagement/IpmiFeaturePkg/Include/PostMemory.fdf
index e0f3bbe158d9..f29810bc0b34 100644
--- a/Features/Intel/OutOfBandManagement/IpmiFeaturePkg/Include/PostMemory.fdf
+++ b/Features/Intel/OutOfBandManagement/IpmiFeaturePkg/Include/PostMemory.fdf
@@ -10,8 +10,11 @@
 INF IpmiFeaturePkg/GenericIpmi/Dxe/GenericIpmi.inf
 INF IpmiFeaturePkg/IpmiInit/DxeIpmiInit.inf
 INF RuleOverride = DRIVER_ACPITABLE IpmiFeaturePkg/BmcAcpi/BmcAcpi.inf
-INF IpmiFeaturePkg/BmcElog/BmcElog.inf
+INF IpmiFeaturePkg/BmcElog/DxeBmcElog.inf
+INF IpmiFeaturePkg/BmcElog/SmmBmcElog.inf
 INF IpmiFeaturePkg/Frb/FrbDxe.inf
 INF IpmiFeaturePkg/IpmiFru/IpmiFru.inf
+INF IpmiFeaturePkg/GenericElog/Dxe/GenericElog.inf
+INF IpmiFeaturePkg/GenericElog/Smm/GenericElog.inf
 INF IpmiFeaturePkg/OsWdt/OsWdt.inf
 INF IpmiFeaturePkg/SolStatus/SolStatus.inf
diff --git a/Features/Intel/OutOfBandManagement/IpmiFeaturePkg/Include/PreMemory.fdf b/Features/Intel/OutOfBandManagement/IpmiFeaturePkg/Include/PreMemory.fdf
index d214988bd141..ca20546e9aa8 100644
--- a/Features/Intel/OutOfBandManagement/IpmiFeaturePkg/Include/PreMemory.fdf
+++ b/Features/Intel/OutOfBandManagement/IpmiFeaturePkg/Include/PreMemory.fdf
@@ -10,3 +10,4 @@
 INF IpmiFeaturePkg/GenericIpmi/Pei/PeiGenericIpmi.inf
 INF IpmiFeaturePkg/IpmiInit/PeiIpmiInit.inf
 INF IpmiFeaturePkg/Frb/FrbPei.inf
+INF IpmiFeaturePkg/BmcElog/PeiBmcElog.inf
diff --git a/Features/Intel/OutOfBandManagement/IpmiFeaturePkg/BmcElog/BmcElog.inf b/Features/Intel/OutOfBandManagement/IpmiFeaturePkg/BmcElog/DxeBmcElog.inf
similarity index 56%
rename from Features/Intel/OutOfBandManagement/IpmiFeaturePkg/BmcElog/BmcElog.inf
rename to Features/Intel/OutOfBandManagement/IpmiFeaturePkg/BmcElog/DxeBmcElog.inf
index 388dd2740c69..dce3bc42ce05 100644
--- a/Features/Intel/OutOfBandManagement/IpmiFeaturePkg/BmcElog/BmcElog.inf
+++ b/Features/Intel/OutOfBandManagement/IpmiFeaturePkg/BmcElog/DxeBmcElog.inf
@@ -1,12 +1,12 @@
 ### @file
-# Component description file for BMC ELOG.
 #
-# Copyright (c) 2018 - 2019, Intel Corporation. All rights reserved.<BR>
+# Copyright (c) 2023, Intel Corporation. All rights reserved.<BR>
 #
 # SPDX-License-Identifier: BSD-2-Clause-Patent
 #
 ###
 
+
 [Defines]
   INF_VERSION              = 0x00010005
   BASE_NAME                = BmcElog
@@ -17,17 +17,30 @@ [Defines]
   ENTRY_POINT              = InitializeBmcElogLayer
 
 [Sources]
-  BmcElog.c
+  Dxe/BmcElog.c
+  Dxe/BmcElog.h
+  Common/BmcElogCommon.h
+  Common/BmcElogCommon.c
 
 [Packages]
-  MdePkg/MdePkg.dec
   IpmiFeaturePkg/IpmiFeaturePkg.dec
+  MdePkg/MdePkg.dec
+  MdeModulePkg/MdeModulePkg.dec
 
 [LibraryClasses]
   UefiDriverEntryPoint
   DebugLib
   UefiBootServicesTableLib
-  IpmiCommandLib
+  ReportStatusCodeLib
+  MemoryAllocationLib
+  IpmiBaseLib
+
+[Protocols]
+  gEfiRedirElogProtocolGuid   # PROTOCOL ALWAYS_PRODUCED
 
 [Depex]
-  TRUE
+  gEfiLoadedImageProtocolGuid AND
+  gIpmiTransportProtocolGuid
+
+
+
diff --git a/Features/Intel/OutOfBandManagement/IpmiFeaturePkg/BmcElog/PeiBmcElog.inf b/Features/Intel/OutOfBandManagement/IpmiFeaturePkg/BmcElog/PeiBmcElog.inf
new file mode 100644
index 000000000000..8274033e42e6
--- /dev/null
+++ b/Features/Intel/OutOfBandManagement/IpmiFeaturePkg/BmcElog/PeiBmcElog.inf
@@ -0,0 +1,43 @@
+### @file
+#
+# Copyright (c) 2023, Intel Corporation. All rights reserved.<BR>
+#
+# SPDX-License-Identifier: BSD-2-Clause-Patent
+#
+###
+
+
+[Defines]
+  INF_VERSION              = 0x00010005
+  BASE_NAME                = BmcElog
+  FILE_GUID                = FD2A000E-09EA-4899-B40E-32BE30A58EBD
+  MODULE_TYPE              = PEIM
+  VERSION_STRING           = 1.0
+  ENTRY_POINT              = InitializeBmcElogLayer
+
+[Sources]
+  Pei/BmcElog.c
+  Pei/BmcElog.h
+  Common/BmcElogCommon.h
+  Common/BmcElogCommon.c
+
+[Packages]
+  IpmiFeaturePkg/IpmiFeaturePkg.dec
+  MdePkg/MdePkg.dec
+  MdeModulePkg/MdeModulePkg.dec
+
+[LibraryClasses]
+  DebugLib
+  ReportStatusCodeLib
+  MemoryAllocationLib
+  PeiServicesLib
+  PeimEntryPoint
+  IpmiBaseLib
+
+[Ppis]
+  gPeiRedirElogPpiGuid   # PPI ALWAYS_PRODUCED
+  gPeiIpmiTransportPpiGuid
+
+[Depex]
+  TRUE
+
diff --git a/Features/Intel/OutOfBandManagement/IpmiFeaturePkg/BmcElog/SmmBmcElog.inf b/Features/Intel/OutOfBandManagement/IpmiFeaturePkg/BmcElog/SmmBmcElog.inf
new file mode 100644
index 000000000000..d6880f8baa1b
--- /dev/null
+++ b/Features/Intel/OutOfBandManagement/IpmiFeaturePkg/BmcElog/SmmBmcElog.inf
@@ -0,0 +1,44 @@
+### @file
+#
+# Copyright (c) 2023, Intel Corporation. All rights reserved.<BR>
+#
+# SPDX-License-Identifier: BSD-2-Clause-Patent
+#
+###
+
+
+[Defines]
+  INF_VERSION              = 0x00010005
+  BASE_NAME                = SmBmcElog
+  FILE_GUID                = BE29A700-9D5A-4bb9-86B1-D1DB7A05D594
+  MODULE_TYPE              = DXE_SMM_DRIVER
+  PI_SPECIFICATION_VERSION = 0x0001000A
+  VERSION_STRING           = 1.0
+  ENTRY_POINT              = InitializeSmBmcElogLayer
+
+[Sources]
+  Smm/BmcElog.c
+  Smm/BmcElog.h
+  Common/BmcElogCommon.h
+  Common/BmcElogCommon.c
+
+[Packages]
+  IpmiFeaturePkg/IpmiFeaturePkg.dec
+  MdePkg/MdePkg.dec
+  MdeModulePkg/MdeModulePkg.dec
+
+[LibraryClasses]
+  UefiDriverEntryPoint
+  DebugLib
+  UefiBootServicesTableLib
+  ReportStatusCodeLib
+  SmmServicesTableLib
+  IpmiBaseLib
+
+[Protocols]
+  gSmmRedirElogProtocolGuid   # PROTOCOL ALWAYS_PRODUCED
+
+[Depex]
+  gEfiLoadedImageProtocolGuid AND
+  gSmmIpmiTransportProtocolGuid
+
diff --git a/Features/Intel/OutOfBandManagement/IpmiFeaturePkg/GenericElog/Dxe/GenericElog.inf b/Features/Intel/OutOfBandManagement/IpmiFeaturePkg/GenericElog/Dxe/GenericElog.inf
new file mode 100644
index 000000000000..1073d3687d38
--- /dev/null
+++ b/Features/Intel/OutOfBandManagement/IpmiFeaturePkg/GenericElog/Dxe/GenericElog.inf
@@ -0,0 +1,38 @@
+### @file
+#
+# Copyright (c) 2023, Intel Corporation. All rights reserved.<BR>
+#
+# SPDX-License-Identifier: BSD-2-Clause-Patent
+#
+###
+
+
+[Defines]
+  INF_VERSION              = 0x00010005
+  BASE_NAME                = GenericElog
+  FILE_GUID                = FD2D7E66-C5A7-47de-BDCC-4F1B5DC6ADA8
+  MODULE_TYPE              = DXE_DRIVER
+  VERSION_STRING           = 1.0
+  ENTRY_POINT              = InitializeElogLayer
+
+[Sources]
+  GenericElog.c
+  GenericElog.h
+
+[Packages]
+  IpmiFeaturePkg/IpmiFeaturePkg.dec
+  MdePkg/MdePkg.dec
+
+[LibraryClasses]
+  UefiDriverEntryPoint
+  BaseMemoryLib
+  DebugLib
+  UefiBootServicesTableLib
+  MemoryAllocationLib
+
+[Protocols]
+  gEfiGenericElogProtocolGuid   # PROTOCOL ALWAYS_PRODUCED
+  gEfiRedirElogProtocolGuid       #PROTOCOL ALWAYS_COMSUMED
+
+[Depex]
+  gEfiRedirElogProtocolGuid
diff --git a/Features/Intel/OutOfBandManagement/IpmiFeaturePkg/GenericElog/Smm/GenericElog.inf b/Features/Intel/OutOfBandManagement/IpmiFeaturePkg/GenericElog/Smm/GenericElog.inf
new file mode 100644
index 000000000000..00f4154cdd39
--- /dev/null
+++ b/Features/Intel/OutOfBandManagement/IpmiFeaturePkg/GenericElog/Smm/GenericElog.inf
@@ -0,0 +1,38 @@
+### @file
+#
+# Copyright (c) 2023, Intel Corporation. All rights reserved.<BR>
+#
+# SPDX-License-Identifier: BSD-2-Clause-Patent
+#
+###
+
+
+[Defines]
+  INF_VERSION              = 0x00010005
+  BASE_NAME                = SmGenericElog
+  FILE_GUID                = 870B000E-D3AD-4fb2-B846-AB0ADE8799CB
+  MODULE_TYPE              = DXE_SMM_DRIVER
+  PI_SPECIFICATION_VERSION = 0x0001000A
+  VERSION_STRING           = 1.0
+  ENTRY_POINT              = InitializeSmElogLayer
+
+[Sources]
+  GenericElog.c
+  GenericElog.h
+
+[Packages]
+  IpmiFeaturePkg/IpmiFeaturePkg.dec
+  MdePkg/MdePkg.dec
+
+[LibraryClasses]
+  UefiDriverEntryPoint
+  DebugLib
+  SmmServicesTableLib
+
+[Protocols]
+  gSmmGenericElogProtocolGuid     # PROTOCOL ALWAYS_PRODUCED
+  gSmmRedirElogProtocolGuid       #PROTOCOL ALWAYS_COMSUMED
+
+[Depex]
+  gSmmRedirElogProtocolGuid AND
+  gSmmIpmiTransportProtocolGuid
diff --git a/Features/Intel/OutOfBandManagement/IpmiFeaturePkg/BmcElog/Common/BmcElogCommon.h b/Features/Intel/OutOfBandManagement/IpmiFeaturePkg/BmcElog/Common/BmcElogCommon.h
new file mode 100644
index 000000000000..23c535d1dd6c
--- /dev/null
+++ b/Features/Intel/OutOfBandManagement/IpmiFeaturePkg/BmcElog/Common/BmcElogCommon.h
@@ -0,0 +1,144 @@
+/** @file
+  BMC Event Log functions.
+
+Copyright (c) 2023, Intel Corporation. All rights reserved.<BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#ifndef _BMCELOG_COMMON_H_
+#define _BMCELOG_COMMON_H_
+
+//
+// Statements that include other files
+//
+#include <Uefi.h>
+#include <Library/BaseLib.h>
+#include <Library/DebugLib.h>
+#include <Library/BaseMemoryLib.h>
+#include <Library/MemoryAllocationLib.h>
+#include <Library/ReportStatusCodeLib.h>
+#include "ServerManagement.h"
+#include <SmStatusCodes.h>
+#include <IndustryStandard/Ipmi.h>
+#include <Library/IpmiBaseLib.h>
+
+#define MAX_TEMP_DATA       160
+#define CLEAR_SEL_COUNTER   0x200
+#define SEL_RECORD_SIZE     0x10       // 16 bytes : Entire SEL Record size
+#define SEL_RECORD_ID_SIZE  0x2        // 2 bytes  : SEL Record-ID size
+
+#ifndef _EFI_SM_ELOG_TYPE
+#define _EFI_SM_ELOG_TYPE
+typedef enum {
+  EfiElogSmSMBIOS,
+  EfiElogSmIPMI,
+  EfiElogSmMachineCritical,
+  EfiElogSmASF,
+  EfiElogSmOEM,
+  EfiSmElogMax
+} EFI_SM_ELOG_TYPE;
+#endif
+
+/**
+  WaitTillClearSel.
+
+  @param ResvId               Reserved ID
+
+  @retval EFI_SUCCESS
+  @retval EFI_NO_RESPONSE
+
+**/
+EFI_STATUS
+WaitTillClearSel (
+  UINT8  *ResvId
+  );
+
+/**
+  Set Bmc Elog Data.
+
+
+  @param ElogData      Buffer for log storage
+  @param DataType      Event Log type
+  @param AlertEvent    If it is an alert event
+  @param Size          Log data size
+  @param RecordId      Indicate which recorder it is
+
+  @retval EFI_STATUS
+
+**/
+EFI_STATUS
+SetBmcElogRecord (
+  IN  UINT8             *ElogData,
+  IN  EFI_SM_ELOG_TYPE  DataType,
+  IN  BOOLEAN           AlertEvent,
+  IN  UINTN             Size,
+  OUT UINT64            *RecordId
+  );
+
+/**
+  Get Bmc Elog Data.
+
+  @param ElogData      Buffer for log data store
+  @param DataType      Event log type
+  @param Size          Size of log data
+  @param RecordId      indicate which recorder it is
+
+  @retval EFI_STATUS
+
+**/
+EFI_STATUS
+GetBmcElogRecord (
+  IN UINT8             *ElogData,
+  IN EFI_SM_ELOG_TYPE  DataType,
+  IN OUT UINTN         *Size,
+  IN OUT UINT64        *RecordId
+  );
+
+/**
+  Erase Bmc Elog Data.
+
+  @param This          Protocol pointer
+  @param DataType      Event log type
+  @param RecordId      return which recorder it is
+
+  @retval EFI_STATUS
+
+**/
+EFI_STATUS
+EraseBmcElogRecord (
+  IN EFI_SM_ELOG_TYPE  DataType,
+  IN OUT UINT64        *RecordId
+  );
+
+/**
+  Activate Bmc Elog.
+
+  @param DataType      indicate event log type
+  @param EnableElog    Enable/Disable event log
+  @param ElogStatus    return log status
+
+  @retval EFI_STATUS
+
+**/
+EFI_STATUS
+ActivateBmcElog (
+  IN  EFI_SM_ELOG_TYPE  DataType,
+  IN  BOOLEAN           *EnableElog,
+  OUT BOOLEAN           *ElogStatus
+  );
+
+/**
+  This function verifies the BMC SEL is full and When it is reports the error to the Error Manager.
+
+  @retval EFI_SUCCESS
+  @retval EFI_DEVICE_ERROR
+
+**/
+EFI_STATUS
+EFIAPI
+CheckIfSelIsFull (
+  VOID
+  );
+
+#endif
diff --git a/Features/Intel/OutOfBandManagement/IpmiFeaturePkg/BmcElog/Dxe/BmcElog.h b/Features/Intel/OutOfBandManagement/IpmiFeaturePkg/BmcElog/Dxe/BmcElog.h
new file mode 100644
index 000000000000..d70261c7c537
--- /dev/null
+++ b/Features/Intel/OutOfBandManagement/IpmiFeaturePkg/BmcElog/Dxe/BmcElog.h
@@ -0,0 +1,42 @@
+/** @file
+  BMC Event Log functions.
+
+Copyright (c) 2023, Intel Corporation. All rights reserved.<BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#ifndef _EFI_BMCELOG_H_
+#define _EFI_BMCELOG_H_
+
+//
+// Statements that include other files
+//
+
+#include <Library/UefiBootServicesTableLib.h>
+#include <Library/UefiRuntimeServicesTableLib.h>
+#include <Protocol/IpmiTransportProtocol.h>
+#include <Protocol/GenericElog.h>
+#include "BmcElogCommon.h"
+
+//
+// BMC Elog instance data
+//
+typedef struct {
+  UINTN                         Signature;
+  SM_COM_ADDRESS                ControllerAddress;
+  SM_COM_ADDRESS                TargetAddress;
+  UINT16                        Instance;
+  EFI_SM_ELOG_TYPE              DataType;
+  UINT8                         TempData[MAX_TEMP_DATA + 1];
+  EFI_SM_ELOG_REDIR_PROTOCOL    BmcElog;
+} EFI_BMC_ELOG_INSTANCE_DATA;
+
+//
+// BMC Elog Instance signature
+//
+#define EFI_ELOG_REDIR_SIGNATURE  SIGNATURE_32 ('e', 'e', 'l', 'g')
+
+#define INSTANCE_FROM_EFI_ELOG_REDIR_THIS(a)  CR (a, EFI_BMC_ELOG_INSTANCE_DATA, BmcElog, EFI_ELOG_REDIR_SIGNATURE)
+
+#endif
diff --git a/Features/Intel/OutOfBandManagement/IpmiFeaturePkg/BmcElog/Pei/BmcElog.h b/Features/Intel/OutOfBandManagement/IpmiFeaturePkg/BmcElog/Pei/BmcElog.h
new file mode 100644
index 000000000000..c1b53f3e468d
--- /dev/null
+++ b/Features/Intel/OutOfBandManagement/IpmiFeaturePkg/BmcElog/Pei/BmcElog.h
@@ -0,0 +1,44 @@
+/** @file
+  BMC Event Log functions.
+
+Copyright (c) 2023, Intel Corporation. All rights reserved.<BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#ifndef _EFI_PEIBMCELOG_H_
+#define _EFI_PEIBMCELOG_H_
+
+//
+// Statements that include other files
+//
+
+#include <Ppi/GenericElog.h>
+#include <Ppi/IpmiTransportPpi.h>
+#include <Library/PeiServicesLib.h>
+#include <Library/PeiServicesTablePointerLib.h>
+#include <IndustryStandard/Ipmi.h>
+#include "BmcElogCommon.h"
+
+//
+// BMC Elog instance data
+//
+typedef struct {
+  UINTN                     Signature;
+  SM_COM_ADDRESS            ControllerAddress;
+  SM_COM_ADDRESS            TargetAddress;
+  UINT16                    Instance;
+  EFI_SM_ELOG_TYPE          DataType;
+  UINT8                     TempData[MAX_TEMP_DATA + 1];
+  EFI_SM_ELOG_REDIR_PPI     BmcElogPpi;
+  EFI_PEI_PPI_DESCRIPTOR    BmcElog;
+} EFI_PEI_BMC_ELOG_INSTANCE_DATA;
+
+//
+// BMC Elog Instance signature
+//
+#define EFI_PEI_ELOG_REDIR_SIGNATURE  SIGNATURE_32 ('e', 'p', 'l', 'g')
+
+#define INSTANCE_FROM_EFI_PEI_ELOG_REDIR_THIS(a)  CR (a, EFI_PEI_BMC_ELOG_INSTANCE_DATA, BmcElogPpi, EFI_PEI_ELOG_REDIR_SIGNATURE)
+
+#endif
diff --git a/Features/Intel/OutOfBandManagement/IpmiFeaturePkg/BmcElog/Smm/BmcElog.h b/Features/Intel/OutOfBandManagement/IpmiFeaturePkg/BmcElog/Smm/BmcElog.h
new file mode 100644
index 000000000000..218af380a229
--- /dev/null
+++ b/Features/Intel/OutOfBandManagement/IpmiFeaturePkg/BmcElog/Smm/BmcElog.h
@@ -0,0 +1,43 @@
+/** @file
+  BMC Event Log functions.
+
+Copyright (c) 2023, Intel Corporation. All rights reserved.<BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#ifndef _SMM_BMCELOG_H_
+#define _SMM_BMCELOG_H_
+
+//
+// Statements that include other files
+//
+
+#include <Library/SmmServicesTableLib.h>
+#include <Library/SmmLib.h>
+#include <Library/UefiBootServicesTableLib.h>
+#include <Protocol/IpmiTransportProtocol.h>
+#include <Protocol/GenericElog.h>
+#include "BmcElogCommon.h"
+
+//
+// BMC Elog instance data
+//
+typedef struct {
+  UINTN                         Signature;
+  SM_COM_ADDRESS                ControllerAddress;
+  SM_COM_ADDRESS                TargetAddress;
+  UINT16                        Instance;
+  EFI_SM_ELOG_TYPE              DataType;
+  UINT8                         TempData[MAX_TEMP_DATA + 1];
+  EFI_SM_ELOG_REDIR_PROTOCOL    BmcElog;
+} EFI_BMC_ELOG_INSTANCE_DATA;
+
+//
+// BMC Elog Instance signature
+//
+#define SM_ELOG_REDIR_SIGNATURE  SIGNATURE_32 ('e', 'l', 'o', 'f')
+
+#define INSTANCE_FROM_EFI_SM_ELOG_REDIR_THIS(a)  CR (a, EFI_BMC_ELOG_INSTANCE_DATA, BmcElog, SM_ELOG_REDIR_SIGNATURE)
+
+#endif //_SMM_BMCELOG_H_
diff --git a/Features/Intel/OutOfBandManagement/IpmiFeaturePkg/GenericElog/Dxe/GenericElog.h b/Features/Intel/OutOfBandManagement/IpmiFeaturePkg/GenericElog/Dxe/GenericElog.h
new file mode 100644
index 000000000000..460185455648
--- /dev/null
+++ b/Features/Intel/OutOfBandManagement/IpmiFeaturePkg/GenericElog/Dxe/GenericElog.h
@@ -0,0 +1,194 @@
+/** @file
+  Generic Event Log functions.
+
+Copyright (c) 2023, Intel Corporation. All rights reserved.<BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#ifndef _EFI_GENELOG_H_
+#define _EFI_GENELOG_H_
+
+#include <Uefi.h>
+#include <Library/BaseLib.h>
+#include <Library/UefiLib.h>
+#include <Library/DebugLib.h>
+#include <Library/BaseMemoryLib.h>
+#include <Library/MemoryAllocationLib.h>
+#include <Library/UefiDriverEntryPoint.h>
+#include <Library/UefiBootServicesTableLib.h>
+
+#include "ServerManagement.h"
+
+#include <Protocol/IpmiTransportProtocol.h>
+#include <Protocol/GenericElog.h>
+
+#define EFI_ELOG_PHYSICAL     0
+#define EFI_ELOG_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_ELOG_REDIR_PROTOCOL    *This;
+  FUNCTION_PTR                  SetEventLogData;
+  FUNCTION_PTR                  GetEventLogData;
+  FUNCTION_PTR                  EraseEventLogData;
+  FUNCTION_PTR                  ActivateEventLog;
+} REDIR_MODULE_PROC;
+
+typedef struct {
+  BOOLEAN              Valid;
+  REDIR_MODULE_PROC    Command[2];
+} REDIR_MODULES;
+
+typedef struct {
+  REDIR_MODULES    Redir[MAX_REDIR_DESCRIPTOR];
+  UINTN            MaxDescriptors;
+} ELOG_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
+  );
+
+/**
+  Elog Service Initialize.
+
+  @param ImageHandle
+  @param SystemTable
+
+  @retval EFI_SUCCESS
+
+**/
+EFI_STATUS
+ElogServiceInitialize (
+  IN EFI_HANDLE        ImageHandle,
+  IN EFI_SYSTEM_TABLE  *SystemTable
+  );
+
+/**
+  Efi Lib Set Elog Data.
+
+  @param ElogData
+  @param DataType
+  @param AlertEvent
+  @param DataSize
+  @param RecordId
+  @param Global
+  @param Virtual
+
+  @retval EFI_SUCCESS
+
+**/
+EFI_STATUS
+EfiLibSetElogData (
+  IN  UINT8             *ElogData,
+  IN  EFI_SM_ELOG_TYPE  DataType,
+  IN  BOOLEAN           AlertEvent,
+  IN  UINTN             DataSize,
+  OUT UINT64            *RecordId,
+  ELOG_MODULE_GLOBAL    *Global,
+  BOOLEAN               Virtual
+  );
+
+/**
+  Efi Lib Get Elog Data.
+
+  @param ElogData
+  @param DataType
+  @param DataSize
+  @param RecordId
+  @param Global
+  @param Virtual
+
+  @retval EFI_SUCCESS
+
+**/
+EFI_STATUS
+EfiLibGetElogData (
+  IN UINT8             *ElogData,
+  IN EFI_SM_ELOG_TYPE  DataType,
+  IN OUT UINTN         *DataSize,
+  IN OUT UINT64        *RecordId,
+  ELOG_MODULE_GLOBAL   *Global,
+  BOOLEAN              Virtual
+  );
+
+/**
+  Efi Lib Erase Elog Data.
+
+  @param DataType
+  @param RecordId
+  @param Global
+  @param Virtual
+
+  @retval EFI_SUCCESS
+
+**/
+EFI_STATUS
+EfiLibEraseElogData (
+  IN EFI_SM_ELOG_TYPE  DataType,
+  IN OUT UINT64        *RecordId,
+  ELOG_MODULE_GLOBAL   *Global,
+  BOOLEAN              Virtual
+  );
+
+/**
+  This API enables/Disables Event Log.
+
+  @param DataType              - Type of Elog Data that is being Activated.
+  @param EnableElog            - Enables (TRUE) / Disables (FALSE) Event Log. If NULL just returns the
+                                 Current ElogStatus.
+  @param ElogStatus            - Current (New) Status of Event Log. Enabled (TRUE), Disabled (FALSE).
+  @param Global                - The module global variable pointer.
+  @param Virtual               - If this function is called in virtual mode or physical mode
+
+  @retval EFI_SUCCESS           - Event-Log was recorded successfully
+  @retval EFI_UNSUPPORTED       - The Data Type is unsupported
+
+**/
+
+EFI_STATUS
+EfiLibActivateElog (
+  IN  EFI_SM_ELOG_TYPE  DataType,
+  IN BOOLEAN            *EnableElog,
+  OUT BOOLEAN           *ElogStatus,
+  ELOG_MODULE_GLOBAL    *Global,
+  BOOLEAN               Virtual
+  );
+
+#endif //_EFI_GENELOG_H_
diff --git a/Features/Intel/OutOfBandManagement/IpmiFeaturePkg/GenericElog/Smm/GenericElog.h b/Features/Intel/OutOfBandManagement/IpmiFeaturePkg/GenericElog/Smm/GenericElog.h
new file mode 100644
index 000000000000..ad6530616309
--- /dev/null
+++ b/Features/Intel/OutOfBandManagement/IpmiFeaturePkg/GenericElog/Smm/GenericElog.h
@@ -0,0 +1,216 @@
+/** @file
+  Generic Event Log functions.
+
+Copyright (c) 2023, Intel Corporation. All rights reserved.<BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#ifndef _SMM_GENELOG_H_
+#define _SMM_GENELOG_H_
+
+#include <Uefi.h>
+#include <Library/BaseLib.h>
+#include <Library/SmmLib.h>
+#include <Library/DebugLib.h>
+
+#include <Library/BaseMemoryLib.h>
+#include <Library/SmmServicesTableLib.h>
+#include <Library/MemoryAllocationLib.h>
+
+#include "ServerManagement.h"
+#include <Protocol/IpmiTransportProtocol.h>
+#include <Protocol/GenericElog.h>
+
+#define EFI_ELOG_PHYSICAL     0
+#define EFI_ELOG_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_ELOG_REDIR_PROTOCOL    *This;
+  FUNCTION_PTR                  SetEventLogData;
+  FUNCTION_PTR                  GetEventLogData;
+  FUNCTION_PTR                  EraseEventLogData;
+  FUNCTION_PTR                  ActivateEventLog;
+} REDIR_MODULE_PROC;
+
+typedef struct {
+  BOOLEAN              Valid;
+  REDIR_MODULE_PROC    Command[2];
+} REDIR_MODULES;
+
+typedef struct {
+  REDIR_MODULES    Redir[MAX_REDIR_DESCRIPTOR];
+  UINTN            MaxDescriptors;
+} ELOG_MODULE_GLOBAL;
+
+/**
+  Efi Convert Function.
+
+  @param Function
+
+  @retval EFI_SUCCESS
+**/
+EFI_STATUS
+EfiConvertFunction (
+  IN  FUNCTION_PTR  *Function
+  );
+
+/**
+  Set the function entry.
+
+  @param FunctionPointer - The destination function pointer
+  @param Function        - The source function pointer
+
+  @retval EFI_SUCCESS - Set the function pointer successfully
+
+**/
+EFI_STATUS
+EfiSetFunctionEntry (
+  IN  FUNCTION_PTR  *FunctionPointer,
+  IN  VOID          *Function
+  );
+
+/**
+  Entry point of SM Elog service Driver
+
+  @param ImageHandle         - The Image handle of this driver.
+  @param SystemTable         - The pointer of EFI_SYSTEM_TABLE.
+
+  @retval EFI_SUCCESS - The driver successfully initialized
+
+**/
+EFI_STATUS
+SmElogServiceInitialize (
+  IN EFI_HANDLE        ImageHandle,
+  IN EFI_SYSTEM_TABLE  *SystemTable
+  );
+
+/**
+  Sm Redir Address Change Event.
+
+  @param Event
+  @param Context
+
+**/
+VOID
+SmRedirAddressChangeEvent (
+  IN EFI_EVENT  Event,
+  IN VOID       *Context
+  );
+
+/**
+  Sends the Event-Log data to the destination.
+
+  @param ElogData              - Pointer to the Event-Log data that needs to be recorded.
+  @param DataType              - Type of Elog Data that is being recorded.
+  @param AlertEvent            - This is an indication that the input data type is an Alert.
+  @param DataSize              - Data Size.
+  @param RecordId              - Record ID sent by the target.
+  @param Global                - The module global variable pointer.
+  @param Virtual               - If this function is called in virtual mode or physical mode
+
+  @retval EFI_SUCCESS            - Event-Log was recorded successfully.
+  @retval EFI_OUT_OF_RESOURCES   - Not enough resources to record data.
+  @retval EFI_UNSUPPORTED        - The Data Type is unsupported.
+
+**/
+EFI_STATUS
+EfiLibSetElogData (
+  IN  UINT8             *ElogData,
+  IN  EFI_SM_ELOG_TYPE  DataType,
+  IN  BOOLEAN           AlertEvent,
+  IN  UINTN             DataSize,
+  OUT UINT64            *RecordId,
+  ELOG_MODULE_GLOBAL    *Global,
+  BOOLEAN               Virtual
+  );
+
+/**
+  Gets the Event-Log data from the destination.
+
+  @param ElogData              - Pointer to the Event-Log data buffer that will contain the data to be retrieved.
+  @param DataType              - Type of Elog Data that is being recorded.
+  @param DataSize              - Data Size.
+  @param RecordId              - This is the RecordId of the next record. If ElogData is NULL,
+                                this gives the RecordId of the first record available in the database with the correct DataSize.
+                                A value of 0 on return indicates the last record if the EFI_STATUS indicates a success
+  @param Global                - The module global variable pointer.
+  @param Virtual               - If this function is called in virtual mode or physical mode
+
+  @retval EFI_SUCCESS           - Event-Log was retrieved successfully.
+  @retval EFI_NOT_FOUND         - Event-Log target not found.
+  @retval EFI_BUFFER_TOO_SMALL  - Target buffer is too small to retrieve the data.
+  @retval EFI_UNSUPPORTED       - The Data Type is unsupported
+
+**/
+EFI_STATUS
+EfiLibGetElogData (
+  IN UINT8             *ElogData,
+  IN EFI_SM_ELOG_TYPE  DataType,
+  IN OUT UINTN         *DataSize,
+  IN OUT UINT64        *RecordId,
+  ELOG_MODULE_GLOBAL   *Global,
+  BOOLEAN              Virtual
+  );
+
+/**
+  Erases the Event-Log data from the destination.
+
+  @param DataType              - Type of Elog Data that is being Erased.
+  @param RecordId              - This is the RecordId of the data to be erased. If RecordId is NULL, all
+                                 the records on the database are erased if permitted by the target.
+                                 Contains the deleted RecordId on return
+  @param Global                - The module global variable pointer.
+  @param Virtual               - If this function is called in virtual mode or physical mode
+
+  @retval EFI_SUCCESS           - Event-Log was erased successfully
+  @retval EFI_UNSUPPORTED       - The Data Type is unsupported
+  @retval EFI_NOT_FOUND         - Event-Log target not found
+
+**/
+EFI_STATUS
+EfiLibEraseElogData (
+  IN EFI_SM_ELOG_TYPE  DataType,
+  IN OUT UINT64        *RecordId,
+  ELOG_MODULE_GLOBAL   *Global,
+  BOOLEAN              Virtual
+  );
+
+/**
+  This API enables/Disables Event Log.
+
+  @param DataType              - Type of Elog Data that is being Activated.
+  @param EnableElog            - Enables (TRUE) / Disables (FALSE) Event Log. If NULL just returns the
+                                 Current ElogStatus.
+  @param ElogStatus            - Current (New) Status of Event Log. Enabled (TRUE), Disabled (FALSE).
+  @param Global                - The module global variable pointer.
+  @param Virtual               - If this function is called in virtual mode or physical mode
+
+  @retval EFI_SUCCESS           - Event-Log was recorded successfully
+  @retval EFI_UNSUPPORTED       - The Data Type is unsupported
+
+**/
+EFI_STATUS
+EfiLibActivateElog (
+  IN  EFI_SM_ELOG_TYPE  DataType,
+  IN BOOLEAN            *EnableElog,
+  OUT BOOLEAN           *ElogStatus,
+  ELOG_MODULE_GLOBAL    *Global,
+  BOOLEAN               Virtual
+  );
+
+#endif //_SMM_GENELOG_H_
diff --git a/Features/Intel/OutOfBandManagement/IpmiFeaturePkg/Include/Ppi/GenericElog.h b/Features/Intel/OutOfBandManagement/IpmiFeaturePkg/Include/Ppi/GenericElog.h
new file mode 100644
index 000000000000..4b3b3ee2af33
--- /dev/null
+++ b/Features/Intel/OutOfBandManagement/IpmiFeaturePkg/Include/Ppi/GenericElog.h
@@ -0,0 +1,84 @@
+/** @file
+  This code abstracts the generic ELOG Protocol.
+
+Copyright (c) 2023, Intel Corporation. All rights reserved.<BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#ifndef _GENERIC_ELOG_H_
+#define _GENERIC_ELOG_H_
+
+#include "ServerManagement.h"
+
+typedef struct _EFI_SM_ELOG_PPI EFI_SM_ELOG_REDIR_PPI;
+
+//
+// Common Defines
+//
+#ifndef _EFI_SM_ELOG_TYPE
+#define _EFI_SM_ELOG_TYPE
+typedef enum {
+  EfiElogSmSMBIOS,
+  EfiElogSmIPMI,
+  EfiElogSmMachineCritical,
+  EfiElogSmASF,
+  EfiElogSmOEM,
+  EfiSmElogMax
+} EFI_SM_ELOG_TYPE;
+#endif
+
+//
+//  Generic ELOG Function Prototypes
+//
+typedef
+EFI_STATUS
+(EFIAPI *EFI_SET_ELOG_DATA)(
+  IN  EFI_SM_ELOG_REDIR_PPI             *This,
+  IN  UINT8                             *ElogData,
+  IN  EFI_SM_ELOG_TYPE                  DataType,
+  IN  BOOLEAN                           AlertEvent,
+  IN  UINTN                             DataSize,
+  OUT UINT64                            *RecordId
+  );
+
+typedef
+EFI_STATUS
+(EFIAPI *EFI_GET_ELOG_DATA)(
+  IN  EFI_SM_ELOG_REDIR_PPI             *This,
+  IN  OUT UINT8                         *ElogData,
+  IN  EFI_SM_ELOG_TYPE                  DataType,
+  IN  OUT UINTN                         *DataSize,
+  IN  OUT UINT64                        *RecordId
+  );
+
+typedef
+EFI_STATUS
+(EFIAPI *EFI_ERASE_ELOG_DATA)(
+  IN EFI_SM_ELOG_REDIR_PPI              *This,
+  IN EFI_SM_ELOG_TYPE                   DataType,
+  IN OUT UINT64                         *RecordId
+  );
+
+typedef
+EFI_STATUS
+(EFIAPI *EFI_ACTIVATE_ELOG)(
+  IN EFI_SM_ELOG_REDIR_PPI              *This,
+  IN EFI_SM_ELOG_TYPE                   DataType,
+  IN BOOLEAN                            *EnableElog,
+  OUT BOOLEAN                           *ElogStatus
+  );
+
+//
+// IPMI TRANSPORT PPI
+//
+struct _EFI_SM_ELOG_PPI {
+  EFI_SET_ELOG_DATA      SetEventLogData;
+  EFI_GET_ELOG_DATA      GetEventLogData;
+  EFI_ERASE_ELOG_DATA    EraseEventlogData;
+  EFI_ACTIVATE_ELOG      ActivateEventLog;
+};
+
+extern EFI_GUID  gPeiRedirElogPpiGuid;
+
+#endif
diff --git a/Features/Intel/OutOfBandManagement/IpmiFeaturePkg/Include/Protocol/GenericElog.h b/Features/Intel/OutOfBandManagement/IpmiFeaturePkg/Include/Protocol/GenericElog.h
new file mode 100644
index 000000000000..19726ff58f0f
--- /dev/null
+++ b/Features/Intel/OutOfBandManagement/IpmiFeaturePkg/Include/Protocol/GenericElog.h
@@ -0,0 +1,99 @@
+/** @file
+  This code abstracts the generic ELOG Protocol.
+
+Copyright (c) 2023, Intel Corporation. All rights reserved.<BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#ifndef _GENERIC_ELOG_H_
+#define _GENERIC_ELOG_H_
+
+#include "ServerManagement.h"
+
+#define EFI_SM_ELOG_PROTOCOL_GUID \
+  { \
+    0x59d02fcd, 0x9233, 0x4d34, 0xbc, 0xfe, 0x87, 0xca, 0x81, 0xd3, 0xdd, 0xa7 \
+  }
+
+#define EFI_SM_ELOG_REDIR_PROTOCOL_GUID \
+  { \
+    0x16d11030, 0x71ba, 0x4e5e, 0xa9, 0xf9, 0xb4, 0x75, 0xa5, 0x49, 0x4, 0x8a \
+  }
+
+//
+// Common Defines
+//
+#ifndef _EFI_SM_ELOG_TYPE
+#define _EFI_SM_ELOG_TYPE
+typedef enum {
+  EfiElogSmSMBIOS,
+  EfiElogSmIPMI,
+  EfiElogSmMachineCritical,
+  EfiElogSmASF,
+  EfiElogSmOEM,
+  EfiSmElogMax
+} EFI_SM_ELOG_TYPE;
+#endif
+
+typedef struct _EFI_SM_ELOG_PROTOCOL EFI_SM_ELOG_PROTOCOL;
+
+typedef struct _EFI_SM_ELOG_PROTOCOL EFI_SM_ELOG_REDIR_PROTOCOL;
+
+//
+//  Generic ELOG Function Prototypes
+//
+typedef
+EFI_STATUS
+(EFIAPI *EFI_SET_ELOG_DATA)(
+  IN EFI_SM_ELOG_PROTOCOL               *This,
+  IN  UINT8                             *ElogData,
+  IN  EFI_SM_ELOG_TYPE                  DataType,
+  IN  BOOLEAN                           AlertEvent,
+  IN  UINTN                             DataSize,
+  OUT UINT64                            *RecordId
+  );
+
+typedef
+EFI_STATUS
+(EFIAPI *EFI_GET_ELOG_DATA)(
+  IN EFI_SM_ELOG_PROTOCOL               *This,
+  IN OUT UINT8                          *ElogData,
+  IN EFI_SM_ELOG_TYPE                   DataType,
+  IN OUT UINTN                          *DataSize,
+  IN OUT UINT64                         *RecordId
+  );
+
+typedef
+EFI_STATUS
+(EFIAPI *EFI_ERASE_ELOG_DATA)(
+  IN EFI_SM_ELOG_PROTOCOL               *This,
+  IN EFI_SM_ELOG_TYPE                   DataType,
+  IN OUT UINT64                         *RecordId
+  );
+
+typedef
+EFI_STATUS
+(EFIAPI *EFI_ACTIVATE_ELOG)(
+  IN EFI_SM_ELOG_PROTOCOL               *This,
+  IN EFI_SM_ELOG_TYPE                   DataType,
+  IN BOOLEAN                            *EnableElog,
+  OUT BOOLEAN                           *ElogStatus
+  );
+
+//
+// IPMI TRANSPORT PROTOCOL
+//
+struct _EFI_SM_ELOG_PROTOCOL {
+  EFI_SET_ELOG_DATA      SetEventLogData;
+  EFI_GET_ELOG_DATA      GetEventLogData;
+  EFI_ERASE_ELOG_DATA    EraseEventlogData;
+  EFI_ACTIVATE_ELOG      ActivateEventLog;
+};
+
+extern EFI_GUID  gEfiGenericElogProtocolGuid;
+extern EFI_GUID  gEfiRedirElogProtocolGuid;
+extern EFI_GUID  gSmmGenericElogProtocolGuid;
+extern EFI_GUID  gSmmRedirElogProtocolGuid;
+
+#endif
diff --git a/Features/Intel/OutOfBandManagement/IpmiFeaturePkg/BmcElog/BmcElog.c b/Features/Intel/OutOfBandManagement/IpmiFeaturePkg/BmcElog/BmcElog.c
deleted file mode 100644
index a6d075b19c49..000000000000
--- a/Features/Intel/OutOfBandManagement/IpmiFeaturePkg/BmcElog/BmcElog.c
+++ /dev/null
@@ -1,236 +0,0 @@
-/** @file
-  BMC Event Log functions.
-
-Copyright (c) 2018 - 2019, Intel Corporation. All rights reserved.<BR>
-SPDX-License-Identifier: BSD-2-Clause-Patent
-
-**/
-
-#include <Uefi.h>
-#include <Library/BaseLib.h>
-#include <Library/DebugLib.h>
-#include <Library/BaseMemoryLib.h>
-#include <Library/MemoryAllocationLib.h>
-#include <Library/UefiBootServicesTableLib.h>
-#include <Library/UefiRuntimeServicesTableLib.h>
-#include <Library/IpmiCommandLib.h>
-
-EFI_STATUS
-EFIAPI
-CheckIfSelIsFull (
-  VOID
-  );
-
-/*++
-
-  Routine Description:
-    This function verifies the BMC SEL is full and When it is reports the error to the Error Manager.
-
-  Arguments:
-    None
-
-  Returns:
-    EFI_SUCCESS
-    EFI_DEVICE_ERROR
-
---*/
-EFI_STATUS
-WaitTillErased (
-  UINT8                                 *ResvId
-  )
-/*++
-
-Routine Description:
-
-Arguments:
-
-  BmcElogPrivateData  - Bmc event log instance
-  ResvId              - Reserved ID
-
-Returns:
-
-  EFI_SUCCESS
-  EFI_NO_RESPONSE
-
---*/
-{
-  INTN                     Counter;
-  IPMI_CLEAR_SEL_REQUEST   ClearSel;
-  IPMI_CLEAR_SEL_RESPONSE  ClearSelResponse;
-
-  Counter   = 0x200;
-  ZeroMem (&ClearSelResponse, sizeof(ClearSelResponse));
-
-  while (TRUE) {
-    ZeroMem (&ClearSel, sizeof(ClearSel));
-    ClearSel.Reserve[0]  = ResvId[0];
-    ClearSel.Reserve[1]  = ResvId[1];
-    ClearSel.AscC        = 0x43;
-    ClearSel.AscL        = 0x4C;
-    ClearSel.AscR        = 0x52;
-    ClearSel.Erase       = 0x00;
-
-    IpmiClearSel (
-      &ClearSel,
-      &ClearSelResponse
-      );
-
-    if ((ClearSelResponse.ErasureProgress & 0xf) == 1) {
-      return EFI_SUCCESS;
-    }
-    //
-    //  If there is not a response from the BMC controller we need to return and not hang.
-    //
-    --Counter;
-    if (Counter == 0x0) {
-      return EFI_NO_RESPONSE;
-    }
-  }
-}
-
-EFI_STATUS
-EfiActivateBmcElog (
-  IN BOOLEAN                            *EnableElog,
-  OUT BOOLEAN                           *ElogStatus
-  )
-/*++
-
-Routine Description:
-
-Arguments:
-
-  This        - Protocol pointer
-  DataType    - indicate event log type
-  EnableElog  - Enable/Disable event log
-  ElogStatus  - return log status
-
-Returns:
-
-  EFI_STATUS
-
---*/
-{
-  EFI_STATUS                           Status;
-  UINT8                                ElogStat;
-  IPMI_SET_BMC_GLOBAL_ENABLES_REQUEST  SetBmcGlobalEnables;
-  IPMI_GET_BMC_GLOBAL_ENABLES_RESPONSE GetBmcGlobalEnables;
-  UINT8                                CompletionCode;
-
-  Status              = EFI_SUCCESS;
-  ElogStat            = 0;
-
-  Status = IpmiGetBmcGlobalEnables (&GetBmcGlobalEnables);
-  if (EFI_ERROR(Status)) {
-    return Status;
-  }
-
-  if (EnableElog == NULL) {
-    *ElogStatus = GetBmcGlobalEnables.GetEnables.Bits.SystemEventLogging;
-  } else {
-    if (Status == EFI_SUCCESS) {
-      if (*EnableElog) {
-        ElogStat = 1;
-      }
-
-      CopyMem (&SetBmcGlobalEnables, (UINT8 *)&GetBmcGlobalEnables + 1, sizeof(UINT8));
-      SetBmcGlobalEnables.SetEnables.Bits.SystemEventLogging = ElogStat;
-
-      Status = IpmiSetBmcGlobalEnables (&SetBmcGlobalEnables, &CompletionCode);
-    }
-  }
-
-  return Status;
-}
-
-EFI_STATUS
-SetElogRedirInstall (
-  VOID
-  )
-/*++
-
-Routine Description:
-
-Arguments:
-
-  None
-
-Returns:
-
-  EFI_SUCCESS
-
---*/
-{
-  BOOLEAN     EnableElog;
-  BOOLEAN     ElogStatus;
-
-  //
-  // Activate the Event Log (This should depend upon Setup).
-  //
-  EfiActivateBmcElog (&EnableElog, &ElogStatus);
-  return EFI_SUCCESS;
-}
-
-EFI_STATUS
-EFIAPI
-InitializeBmcElogLayer (
-  IN EFI_HANDLE             ImageHandle,
-  IN EFI_SYSTEM_TABLE       *SystemTable
-  )
-/*++
-
-Routine Description:
-
-Arguments:
-
-  ImageHandle - ImageHandle of the loaded driver
-  SystemTable - Pointer to the System Table
-
-Returns:
-
-  EFI_STATUS
-
---*/
-{
-  SetElogRedirInstall ();
-
-  CheckIfSelIsFull ();
-
-  return EFI_SUCCESS;
-}
-
-EFI_STATUS
-EFIAPI
-CheckIfSelIsFull (
-  VOID
-  )
-/*++
-
-  Routine Description:
-    This function verifies the BMC SEL is full and When it is reports the error to the Error Manager.
-
-  Arguments:
-    None
-
-  Returns:
-    EFI_SUCCESS
-    EFI_DEVICE_ERROR
-
---*/
-{
-  EFI_STATUS                  Status;
-  UINT8                       SelIsFull;
-  IPMI_GET_SEL_INFO_RESPONSE  SelInfo;
-
-  Status = IpmiGetSelInfo (&SelInfo);
-  if (EFI_ERROR (Status)) {
-    return EFI_DEVICE_ERROR;
-  }
-
-  //
-  // Check the Bit7 of the OperationByte if SEL is OverFlow.
-  //
-  SelIsFull = (SelInfo.OperationSupport & 0x80);
-  DEBUG ((DEBUG_INFO, "SelIsFull - 0x%x\n", SelIsFull));
-
-  return EFI_SUCCESS;
-}
diff --git a/Features/Intel/OutOfBandManagement/IpmiFeaturePkg/BmcElog/Common/BmcElogCommon.c b/Features/Intel/OutOfBandManagement/IpmiFeaturePkg/BmcElog/Common/BmcElogCommon.c
new file mode 100644
index 000000000000..b0688e3afb6c
--- /dev/null
+++ b/Features/Intel/OutOfBandManagement/IpmiFeaturePkg/BmcElog/Common/BmcElogCommon.c
@@ -0,0 +1,465 @@
+/** @file
+  BMC Event Log Common functions.
+
+Copyright (c) 2023, Intel Corporation. All rights reserved.<BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include "BmcElogCommon.h"
+
+/**
+  WaitTillClearSel.
+
+  @param ResvId              - Reserved ID
+
+  @retval EFI_SUCCESS
+  @retval EFI_NO_RESPONSE
+
+**/
+EFI_STATUS
+WaitTillClearSel (
+  UINT8  *ResvId
+  )
+{
+  INTN                     Counter;
+  UINT32                   ResponseDataSize;
+  IPMI_CLEAR_SEL_REQUEST   ClearSelRequest;
+  IPMI_CLEAR_SEL_RESPONSE  ClearSelResponse;
+  EFI_STATUS               Status;
+
+  Counter = 0x200;
+  Status  = EFI_SUCCESS;
+  while (TRUE) {
+    ClearSelRequest.Reserve[0] = ResvId[0];
+    ClearSelRequest.Reserve[1] = ResvId[1];
+    ClearSelRequest.AscC       = IPMI_CLEAR_SEL_REQUEST_C_CHAR_ASCII;
+    ClearSelRequest.AscL       = IPMI_CLEAR_SEL_REQUEST_L_CHAR_ASCII;
+    ClearSelRequest.AscR       = IPMI_CLEAR_SEL_REQUEST_R_CHAR_ASCII;
+    ClearSelRequest.Erase      = IPMI_CLEAR_SEL_REQUEST_GET_ERASE_STATUS;
+    ResponseDataSize           = sizeof (ClearSelResponse);
+
+    Status = IpmiSubmitCommand (
+               IPMI_NETFN_STORAGE,
+               IPMI_STORAGE_CLEAR_SEL,
+               (UINT8 *)&ClearSelRequest,
+               sizeof (ClearSelRequest),
+               (UINT8 *)&ClearSelResponse,
+               &ResponseDataSize
+               );
+    if (EFI_ERROR (Status)) {
+      DEBUG ((DEBUG_ERROR, "IpmiSubmitCommand ClearSelRequest Failed %r\n", Status));
+    }
+
+    if ((ClearSelResponse.ErasureProgress & 0xf) == IPMI_CLEAR_SEL_RESPONSE_ERASURE_COMPLETED) {
+      return EFI_SUCCESS;
+    }
+
+    //
+    //  If there is not a response from the BMC controller we need to return and not hang.
+    //
+    --Counter;
+    if (Counter == 0x0) {
+      return EFI_NO_RESPONSE;
+    }
+  }
+}
+
+/**
+  Set Bmc Elog Data.
+
+
+  @param ElogData    - Buffer for log storage
+  @param DataType    - Event Log type
+  @param AlertEvent  - If it is an alert event
+  @param Size        - Log data size
+  @param RecordId    - Indicate which recorder it is
+
+  @retval EFI_STATUS
+
+**/
+EFI_STATUS
+SetBmcElogRecord (
+  IN  UINT8             *ElogData,
+  IN  EFI_SM_ELOG_TYPE  DataType,
+  IN  BOOLEAN           AlertEvent,
+  IN  UINTN             Size,
+  OUT UINT64            *RecordId
+  )
+{
+  EFI_STATUS                                Status;
+  UINT32                                    ResponseDataSize;
+  UINT8                                     EvntMsgResponse;
+  IPMI_PLATFORM_EVENT_MESSAGE_DATA_REQUEST  EvntMsgRequest;
+  IPMI_ADD_SEL_ENTRY_REQUEST                AddSelRequest;
+  IPMI_ADD_SEL_ENTRY_RESPONSE               AddSelResponse;
+
+  Status = EFI_SUCCESS;
+  CopyMem (&AddSelRequest.RecordData, ElogData, Size);
+
+  *RecordId = 0;
+
+  if (AlertEvent) {
+    EvntMsgRequest.GeneratorId  = (UINT8)AddSelRequest.RecordData.GeneratorId;
+    EvntMsgRequest.EvMRevision  = AddSelRequest.RecordData.EvMRevision;
+    EvntMsgRequest.SensorType   = AddSelRequest.RecordData.SensorType;
+    EvntMsgRequest.SensorNumber = AddSelRequest.RecordData.SensorNumber;
+    EvntMsgRequest.EventDirType = AddSelRequest.RecordData.EventDirType;
+    EvntMsgRequest.OEMEvData1   = AddSelRequest.RecordData.OEMEvData1;
+    EvntMsgRequest.OEMEvData2   = AddSelRequest.RecordData.OEMEvData2;
+    EvntMsgRequest.OEMEvData3   = AddSelRequest.RecordData.OEMEvData3;
+
+    ResponseDataSize = sizeof (EvntMsgResponse);
+    Status           = IpmiSubmitCommand (
+                         IPMI_NETFN_SENSOR_EVENT,
+                         IPMI_SENSOR_PLATFORM_EVENT_MESSAGE,
+                         (UINT8 *)&EvntMsgRequest,
+                         sizeof (EvntMsgRequest),
+                         (UINT8 *)&EvntMsgResponse,
+                         &ResponseDataSize
+                         );
+  } else {
+    ResponseDataSize = sizeof (AddSelResponse);
+    Status           = IpmiSubmitCommand (
+                         IPMI_NETFN_STORAGE,
+                         IPMI_STORAGE_ADD_SEL_ENTRY,
+                         (UINT8 *)&AddSelRequest,
+                         sizeof (AddSelRequest),
+                         (UINT8 *)&AddSelResponse,
+                         &ResponseDataSize
+                         );
+
+    if (Status == EFI_SUCCESS) {
+      *RecordId = AddSelResponse.RecordId;
+    }
+  }
+
+  return Status;
+}
+
+/**
+  Get Bmc Elog Data.
+
+  @param ElogData    - Buffer for log data store
+  @param DataType    - Event log type
+  @param Size        - Size of log data
+  @param RecordId    - indicate which recorder it is
+
+  @retval EFI_STATUS
+
+**/
+EFI_STATUS
+GetBmcElogRecord (
+  IN UINT8             *ElogData,
+  IN EFI_SM_ELOG_TYPE  DataType,
+  IN OUT UINTN         *Size,
+  IN OUT UINT64        *RecordId
+  )
+{
+  UINT64                       ReceiveKey;
+  EFI_STATUS                   Status;
+  IPMI_GET_SEL_ENTRY_REQUEST   GetSelEntryRequest;
+  IPMI_GET_SEL_ENTRY_RESPONSE  GetSelEntryResponse;
+  UINT32                       ResponseDataSize;
+
+  Status                          = EFI_SUCCESS;
+  ReceiveKey                      = *RecordId;
+  GetSelEntryRequest.ReserveId[0] = 0;
+  GetSelEntryRequest.ReserveId[1] = 0;
+  GetSelEntryRequest.SelRecID[0]  = (UINT8)ReceiveKey;
+  ReceiveKey                      = DivU64x32 (ReceiveKey, (UINT32)(1 << 8));
+  GetSelEntryRequest.SelRecID[1]  = (UINT8)ReceiveKey;
+  GetSelEntryRequest.Offset       = 0;
+  GetSelEntryRequest.BytesToRead  = IPMI_COMPLETE_SEL_RECORD;
+  ResponseDataSize                = sizeof (GetSelEntryResponse);
+
+  Status = IpmiSubmitCommand (
+             IPMI_NETFN_STORAGE,
+             IPMI_STORAGE_GET_SEL_ENTRY,
+             (UINT8 *)&GetSelEntryRequest,
+             sizeof (GetSelEntryRequest),
+             (UINT8 *)&GetSelEntryResponse,
+             &ResponseDataSize
+             );
+  //
+  // Per IPMI spec, Entire Record is 16 Bytes
+  // If less than 16 bytes pointer is sent return buffer too small
+  //
+  if (Status == EFI_SUCCESS) {
+    if (*Size < (SEL_RECORD_SIZE)) {
+      return EFI_BUFFER_TOO_SMALL;
+    }
+
+    if (GetSelEntryResponse.NextSelRecordId == 0xFFFF) {
+      return EFI_NOT_FOUND;
+    }
+
+    *RecordId = GetSelEntryResponse.NextSelRecordId;
+    CopyMem (ElogData, &GetSelEntryResponse.RecordData, sizeof (GetSelEntryResponse.RecordData));
+    *Size = SEL_RECORD_SIZE;
+  }
+
+  return Status;
+}
+
+/**
+  Erase Bmc Elog Data.
+
+  @param DataType    - Event log type
+  @param RecordId    - return which recorder it is
+
+  @retval EFI_STATUS
+
+**/
+EFI_STATUS
+EraseBmcElogRecord (
+  IN EFI_SM_ELOG_TYPE  DataType,
+  IN OUT UINT64        *RecordId
+  )
+{
+  EFI_STATUS                      Status;
+  UINT64                          ReceiveKey;
+  UINT8                           ResvId[2];
+  BOOLEAN                         SelReserveIdIsSupported;
+  UINT8                           OperationSupport;
+  UINT8                           SelReserveIdvalue;
+  UINT32                          ResponseDataSize;
+  IPMI_GET_SEL_INFO_RESPONSE      GetSelInfoResponse;
+  IPMI_RESERVE_SEL_RESPONSE       ReserveSelResponse;
+  IPMI_DELETE_SEL_ENTRY_REQUEST   DeleteSelRequest;
+  IPMI_DELETE_SEL_ENTRY_RESPONSE  DeleteSelResponse;
+  IPMI_CLEAR_SEL_REQUEST          ClearSelRequest;
+  IPMI_CLEAR_SEL_RESPONSE         ClearSelResponse;
+
+  Status = EFI_SUCCESS;
+
+  //
+  // Before issuing this SEL reservation ID, Check whether this command is supported or not by issuing the
+  // GetSelInfoCommand. If it does not support ResvId should be 0000h
+  //
+  ResponseDataSize = sizeof (GetSelInfoResponse);
+  Status           = IpmiSubmitCommand (
+                       IPMI_NETFN_STORAGE,
+                       IPMI_STORAGE_GET_SEL_INFO,
+                       NULL,
+                       0,
+                       (UINT8 *)&GetSelInfoResponse,
+                       &ResponseDataSize
+                       );
+  if (EFI_ERROR (Status)) {
+    return Status;
+  }
+
+  OperationSupport  = GetSelInfoResponse.OperationSupport;
+  SelReserveIdvalue = (OperationSupport & IPMI_GET_SEL_INFO_OPERATION_SUPPORT_RESERVE_SEL_CMD);
+  if (SelReserveIdvalue == IPMI_GET_SEL_INFO_OPERATION_SUPPORT_RESERVE_SEL_CMD) {
+    SelReserveIdIsSupported = TRUE;
+  } else {
+    SelReserveIdIsSupported = FALSE;
+  }
+
+  //
+  // if SelReserveIdcommand not supported do not issue the RESERVE_SEL_ENTRY command, and set the ResvId value to 0000h
+  //
+
+  //
+  // Get the SEL reservation ID
+  //
+
+  if (SelReserveIdIsSupported) {
+    ResponseDataSize = sizeof (ReserveSelResponse);
+    Status           = IpmiSubmitCommand (
+                         IPMI_NETFN_STORAGE,
+                         IPMI_STORAGE_RESERVE_SEL,
+                         NULL,
+                         0,
+                         (UINT8 *)&ReserveSelResponse,
+                         &ResponseDataSize
+                         );
+
+    if (EFI_ERROR (Status)) {
+      return Status;
+    }
+
+    ResvId[0] = ReserveSelResponse.ReservationId[0];
+    ResvId[1] = ReserveSelResponse.ReservationId[1];
+  } else {
+    ResvId[0] = 0x00;
+    ResvId[1] = 0x00;
+  }
+
+  //
+  // Clear the SEL
+  //
+  if (RecordId != NULL) {
+    ReceiveKey                         = *RecordId;
+    DeleteSelRequest.ReserveId[0]      = ResvId[0];
+    DeleteSelRequest.ReserveId[1]      = ResvId[1];
+    DeleteSelRequest.RecordToDelete[0] = (UINT8)ReceiveKey;
+    ReceiveKey                         = DivU64x32 (ReceiveKey, (UINT32)(1 << 8));
+    DeleteSelRequest.RecordToDelete[1] = (UINT8)ReceiveKey;
+
+    ResponseDataSize = sizeof (DeleteSelResponse);
+    Status           = IpmiSubmitCommand (
+                         IPMI_NETFN_STORAGE,
+                         IPMI_STORAGE_DELETE_SEL_ENTRY,
+                         (UINT8 *)&DeleteSelRequest,
+                         sizeof (DeleteSelRequest),
+                         (UINT8 *)&DeleteSelResponse,
+                         &ResponseDataSize
+                         );
+  } else {
+    ClearSelRequest.Reserve[0] = ResvId[0];
+    ClearSelRequest.Reserve[1] = ResvId[1];
+    ClearSelRequest.AscC       = IPMI_CLEAR_SEL_REQUEST_C_CHAR_ASCII;
+    ClearSelRequest.AscL       = IPMI_CLEAR_SEL_REQUEST_L_CHAR_ASCII;
+    ClearSelRequest.AscR       = IPMI_CLEAR_SEL_REQUEST_R_CHAR_ASCII;
+    ClearSelRequest.Erase      = IPMI_CLEAR_SEL_REQUEST_INITIALIZE_ERASE;
+    ResponseDataSize           = sizeof (ClearSelResponse);
+
+    Status = IpmiSubmitCommand (
+               IPMI_NETFN_STORAGE,
+               IPMI_STORAGE_CLEAR_SEL,
+               (UINT8 *)&ClearSelRequest,
+               sizeof (ClearSelRequest),
+               (UINT8 *)&ClearSelResponse,
+               &ResponseDataSize
+               );
+  }
+
+  if (Status == EFI_SUCCESS) {
+    if (RecordId == NULL) {
+      WaitTillClearSel (ResvId);
+    }
+  }
+
+  return Status;
+}
+
+/**
+  Activate Bmc Elog.
+
+  @param DataType    - indicate event log type
+  @param EnableElog  - Enable/Disable event log
+  @param ElogStatus  - return log status
+
+  @retval EFI_STATUS
+
+**/
+EFI_STATUS
+ActivateBmcElog (
+  IN  EFI_SM_ELOG_TYPE  DataType,
+  IN  BOOLEAN           *EnableElog,
+  OUT BOOLEAN           *ElogStatus
+  )
+{
+  EFI_STATUS                            Status;
+  UINT8                                 ElogStat;
+  IPMI_GET_BMC_GLOBAL_ENABLES_RESPONSE  GetBmcGlobalResponse;
+  IPMI_SET_BMC_GLOBAL_ENABLES_REQUEST   SetBmcGlobalRequest;
+  UINT8                                 SetBmcGlobalResponse;
+  UINT32                                ResponseDataSize;
+
+  Status   = EFI_SUCCESS;
+  ElogStat = 0;
+
+  ResponseDataSize = sizeof (GetBmcGlobalResponse);
+  Status           = IpmiSubmitCommand (
+                       IPMI_NETFN_APP,
+                       IPMI_APP_GET_BMC_GLOBAL_ENABLES,
+                       NULL,
+                       0,
+                       (UINT8 *)&GetBmcGlobalResponse,
+                       &ResponseDataSize
+                       );
+
+  if (EFI_ERROR (Status)) {
+    DEBUG ((DEBUG_ERROR, "IpmiSubmitCommand App Get Bmc Global Enables Failed %r\n", Status));
+  }
+
+  if (EnableElog == NULL) {
+    *ElogStatus = (UINT8)(GetBmcGlobalResponse.GetEnables.Bits.SystemEventLogging);
+  } else {
+    if (Status == EFI_SUCCESS) {
+      if (*EnableElog) {
+        ElogStat = 0x1; // Setting SystemEventLogging
+      }
+
+      SetBmcGlobalRequest.SetEnables.Uint8                   = GetBmcGlobalResponse.GetEnables.Uint8;
+      SetBmcGlobalRequest.SetEnables.Bits.SystemEventLogging = ElogStat;
+
+      ResponseDataSize = sizeof (SetBmcGlobalResponse);
+      Status           = IpmiSubmitCommand (
+                           IPMI_NETFN_APP,
+                           IPMI_APP_SET_BMC_GLOBAL_ENABLES,
+                           (UINT8 *)&SetBmcGlobalRequest,
+                           sizeof (SetBmcGlobalRequest),
+                           (UINT8 *)&SetBmcGlobalResponse,
+                           &ResponseDataSize
+                           );
+
+      if (EFI_ERROR (Status)) {
+        DEBUG ((DEBUG_ERROR, "IpmiSubmitCommand App Set Bmc Global Enables Failed %r\n", Status));
+      }
+    }
+  }
+
+  return Status;
+}
+
+/**
+  This function checks the BMC SEL is full and whether to report the error.
+
+  @retval EFI_SUCCESS
+  @retval EFI_DEVICE_ERROR
+
+**/
+EFI_STATUS
+EFIAPI
+CheckIfSelIsFull (
+  VOID
+  )
+{
+  EFI_STATUS                  Status;
+  UINT32                      ResponseDataSize;
+  UINT8                       OperationSupportByte;
+  UINT8                       SelIsFull;
+  IPMI_GET_SEL_INFO_RESPONSE  GetSelInfoResponse;
+
+  OperationSupportByte = 0;
+  SelIsFull            = 0;
+
+  ResponseDataSize = sizeof (GetSelInfoResponse);
+
+  Status = IpmiSubmitCommand (
+             IPMI_NETFN_STORAGE,
+             IPMI_STORAGE_GET_SEL_INFO,
+             NULL,
+             0,
+             (UINT8 *)&GetSelInfoResponse,
+             &ResponseDataSize
+             );
+
+  if (EFI_ERROR (Status)) {
+    return EFI_DEVICE_ERROR;
+  }
+
+  OperationSupportByte = GetSelInfoResponse.OperationSupport;
+
+  //
+  // Check the Bit7 of the OperationByte if SEL is OverFlow.
+  //
+  SelIsFull = (OperationSupportByte & IPMI_GET_SEL_INFO_OPERATION_SUPPORT_OVERFLOW_FLAG);
+
+  if (SelIsFull == IPMI_GET_SEL_INFO_OPERATION_SUPPORT_OVERFLOW_FLAG) {
+    //
+    // Report the Error code that SEL Log is full
+    //
+    ReportStatusCode (
+      (EFI_ERROR_CODE | EFI_ERROR_MINOR),
+      (SOFTWARE_EFI_BMC | EFI_SW_EC_EVENT_LOG_FULL)
+      );
+  }
+
+  return EFI_SUCCESS;
+}
diff --git a/Features/Intel/OutOfBandManagement/IpmiFeaturePkg/BmcElog/Dxe/BmcElog.c b/Features/Intel/OutOfBandManagement/IpmiFeaturePkg/BmcElog/Dxe/BmcElog.c
new file mode 100644
index 000000000000..0b1e2f5b1355
--- /dev/null
+++ b/Features/Intel/OutOfBandManagement/IpmiFeaturePkg/BmcElog/Dxe/BmcElog.c
@@ -0,0 +1,287 @@
+/** @file
+  BMC Event Log functions.
+
+Copyright (c) 2023, Intel Corporation. All rights reserved.<BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include "BmcElog.h"
+
+//
+// Define module globals used to register for notification of when
+// the ELOG REDIR protocol has been produced.
+//
+EFI_EVENT                   mEfiBmcTransEvent;
+EFI_BMC_ELOG_INSTANCE_DATA  *mRedirProtoPrivate;
+
+/**
+  WaitTillErased.
+
+  @param BmcElogPrivateData  - Bmc event log instance
+  @param ResvId              - Reserved ID
+
+  @retval EFI_SUCCESS
+  @retval EFI_NO_RESPONSE
+
+**/
+EFI_STATUS
+WaitTillErased (
+  EFI_BMC_ELOG_INSTANCE_DATA  *BmcElogPrivateData,
+  UINT8                       *ResvId
+  )
+{
+  EFI_STATUS  Status;
+
+  Status = WaitTillClearSel (ResvId);
+  return Status;
+}
+
+/**
+  Efi Set Bmc Elog Data.
+
+  @param This        - Protocol pointer
+  @param ElogData    - Buffer for log storage
+  @param DataType    - Event Log type
+  @param AlertEvent  - If it is an alert event
+  @param Size        - Log data size
+  @param RecordId    - Indicate which recorder it is
+
+  @retval EFI_STATUS
+
+**/
+EFI_STATUS
+EfiSetBmcElogData (
+  IN  EFI_SM_ELOG_REDIR_PROTOCOL  *This,
+  IN  UINT8                       *ElogData,
+  IN  EFI_SM_ELOG_TYPE            DataType,
+  IN  BOOLEAN                     AlertEvent,
+  IN  UINTN                       Size,
+  OUT UINT64                      *RecordId
+  )
+{
+  EFI_BMC_ELOG_INSTANCE_DATA  *BmcElogPrivateData;
+  EFI_STATUS                  Status;
+
+  Status             = EFI_SUCCESS;
+  BmcElogPrivateData = INSTANCE_FROM_EFI_ELOG_REDIR_THIS (This);
+
+  if (DataType >= EfiSmElogMax) {
+    return EFI_INVALID_PARAMETER;
+  }
+
+  if (Size > SEL_RECORD_SIZE) {
+    return EFI_OUT_OF_RESOURCES;
+  }
+
+  if (BmcElogPrivateData->DataType == DataType) {
+    Status = SetBmcElogRecord (ElogData, DataType, AlertEvent, Size, RecordId);
+  }
+
+  return Status;
+}
+
+/**
+  Efi Get Bmc Elog Data.
+
+  @param This        - Protocol pointer
+  @param ElogData    - Buffer for log data store
+  @param DataType    - Event log type
+  @param Size        - Size of log data
+  @param RecordId    - indicate which recorder it is
+
+  @retval EFI_STATUS
+
+**/
+EFI_STATUS
+EfiGetBmcElogData (
+  IN EFI_SM_ELOG_REDIR_PROTOCOL  *This,
+  IN OUT UINT8                   *ElogData,
+  IN EFI_SM_ELOG_TYPE            DataType,
+  IN OUT UINTN                   *Size,
+  IN OUT UINT64                  *RecordId
+  )
+{
+  EFI_BMC_ELOG_INSTANCE_DATA  *BmcElogPrivateData;
+  EFI_STATUS                  Status;
+
+  Status             = EFI_SUCCESS;
+  BmcElogPrivateData = INSTANCE_FROM_EFI_ELOG_REDIR_THIS (This);
+
+  if (DataType >= EfiSmElogMax) {
+    return EFI_INVALID_PARAMETER;
+  }
+
+  if (BmcElogPrivateData->DataType == DataType) {
+    Status = GetBmcElogRecord (ElogData, DataType, Size, RecordId);
+  }
+
+  return Status;
+}
+
+/**
+  Efi Erase Bmc Elog Data.
+
+  @param This        - Protocol pointer
+  @param DataType    - Event log type
+  @param RecordId    - return which recorder it is
+
+  @retval EFI_STATUS
+
+**/
+EFI_STATUS
+EfiEraseBmcElogData (
+  IN EFI_SM_ELOG_REDIR_PROTOCOL  *This,
+  IN EFI_SM_ELOG_TYPE            DataType,
+  IN OUT UINT64                  *RecordId
+  )
+{
+  EFI_BMC_ELOG_INSTANCE_DATA  *BmcElogPrivateData;
+  EFI_STATUS                  Status;
+
+  Status             = EFI_SUCCESS;
+  BmcElogPrivateData = INSTANCE_FROM_EFI_ELOG_REDIR_THIS (This);
+
+  if (DataType >= EfiSmElogMax) {
+    return EFI_INVALID_PARAMETER;
+  }
+
+  if (BmcElogPrivateData->DataType == DataType) {
+    Status = EraseBmcElogRecord (DataType, RecordId);
+
+    if (Status == EFI_SUCCESS) {
+      if (RecordId != NULL) {
+        *RecordId = (UINT16)(*((UINT16 *)&BmcElogPrivateData->TempData[0]));
+      }
+    }
+  }
+
+  return EFI_SUCCESS;
+}
+
+/**
+  Efi Activate Bmc Elog.
+
+  @param This        - Protocol pointer
+  @param DataType    - indicate event log type
+  @param EnableElog  - Enable/Disable event log
+  @param ElogStatus  - return log status
+
+  @retval EFI_STATUS
+
+**/
+EFI_STATUS
+EfiActivateBmcElog (
+  IN EFI_SM_ELOG_REDIR_PROTOCOL  *This,
+  IN EFI_SM_ELOG_TYPE            DataType,
+  IN BOOLEAN                     *EnableElog,
+  OUT BOOLEAN                    *ElogStatus
+  )
+{
+  EFI_BMC_ELOG_INSTANCE_DATA  *BmcElogPrivateData;
+  EFI_STATUS                  Status;
+
+  Status             = EFI_SUCCESS;
+  BmcElogPrivateData = INSTANCE_FROM_EFI_ELOG_REDIR_THIS (This);
+
+  if (DataType >= EfiSmElogMax) {
+    return EFI_INVALID_PARAMETER;
+  }
+
+  if (BmcElogPrivateData->DataType == DataType) {
+    Status = ActivateBmcElog (DataType, EnableElog, ElogStatus);
+  }
+
+  return Status;
+}
+
+/**
+  Set Elog Redir Install.
+
+  @retval EFI_SUCCESS
+
+**/
+EFI_STATUS
+SetElogRedirInstall (
+  VOID
+  )
+{
+  EFI_HANDLE  NewHandle;
+  EFI_STATUS  Status;
+  BOOLEAN     EnableElog;
+  BOOLEAN     ElogStatus;
+  UINT16      Instance;
+
+  Status     = EFI_SUCCESS;
+  EnableElog = TRUE;
+  ElogStatus = TRUE;
+  Instance   = 0;
+
+  mRedirProtoPrivate->Signature                 = EFI_ELOG_REDIR_SIGNATURE;
+  mRedirProtoPrivate->DataType                  = EfiElogSmIPMI;
+  mRedirProtoPrivate->BmcElog.ActivateEventLog  = EfiActivateBmcElog;
+  mRedirProtoPrivate->BmcElog.EraseEventlogData = EfiEraseBmcElogData;
+  mRedirProtoPrivate->BmcElog.GetEventLogData   = EfiGetBmcElogData;
+  mRedirProtoPrivate->BmcElog.SetEventLogData   = EfiSetBmcElogData;
+  mRedirProtoPrivate->Instance                  = Instance;
+  //
+  // Now install the Protocol
+  //
+  NewHandle = NULL;
+
+  Status = gBS->InstallProtocolInterface (
+                  &NewHandle,
+                  &gEfiRedirElogProtocolGuid,
+                  EFI_NATIVE_INTERFACE,
+                  &mRedirProtoPrivate->BmcElog
+                  );
+  ASSERT_EFI_ERROR (Status);
+  if (Status != EFI_SUCCESS) {
+    return Status;
+  }
+
+  //
+  // Activate the Event Log (This should depend upon Setup).
+  //
+  EfiActivateBmcElog (&mRedirProtoPrivate->BmcElog, EfiElogSmIPMI, &EnableElog, &ElogStatus);
+
+  return EFI_SUCCESS;
+}
+
+/**
+  InitializeBmcElogLayer.
+
+  @param ImageHandle - ImageHandle of the loaded driver
+  @param SystemTable - Pointer to the System Table
+
+  @retval EFI_STATUS
+
+**/
+EFI_STATUS
+InitializeBmcElogLayer (
+  IN EFI_HANDLE        ImageHandle,
+  IN EFI_SYSTEM_TABLE  *SystemTable
+  )
+{
+  EFI_STATUS  Status;
+
+  Status = EFI_SUCCESS;
+
+  InitializeIpmiBase ();
+
+  mRedirProtoPrivate = AllocatePool (sizeof (EFI_BMC_ELOG_INSTANCE_DATA));
+  ASSERT (mRedirProtoPrivate != NULL);
+  if (mRedirProtoPrivate == NULL) {
+    return EFI_OUT_OF_RESOURCES;
+  }
+
+  SetElogRedirInstall ();
+
+  //
+  // Check if the BMC System Event Log (SEL) is full and whether to report the error.
+  //
+
+  CheckIfSelIsFull ();
+
+  return Status;
+}
diff --git a/Features/Intel/OutOfBandManagement/IpmiFeaturePkg/BmcElog/Pei/BmcElog.c b/Features/Intel/OutOfBandManagement/IpmiFeaturePkg/BmcElog/Pei/BmcElog.c
new file mode 100644
index 000000000000..f791d872b7a1
--- /dev/null
+++ b/Features/Intel/OutOfBandManagement/IpmiFeaturePkg/BmcElog/Pei/BmcElog.c
@@ -0,0 +1,297 @@
+/** @file
+  BMC Event Log functions.
+
+Copyright (c) 2023, Intel Corporation. All rights reserved.<BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include "BmcElog.h"
+
+//
+// Define module globals used to register for notification of when
+// the ELOG REDIR protocol has been produced.
+//
+
+EFI_STATUS
+NotifyPeiBmcElogCallback (
+  IN EFI_PEI_SERVICES           **PeiServices,
+  IN EFI_PEI_NOTIFY_DESCRIPTOR  *NotifyDescriptor,
+  IN VOID                       *Ppi
+  );
+
+EFI_PEI_NOTIFY_DESCRIPTOR  mNotifyList[] = {
+  {
+    EFI_PEI_PPI_DESCRIPTOR_NOTIFY_CALLBACK | EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST,
+    &gPeiIpmiTransportPpiGuid,
+    NotifyPeiBmcElogCallback
+  }
+};
+
+/**
+  Efi Set Bmc Elog Data.
+
+  @param This        - Protocol pointer
+  @param ElogData    - Buffer for log storage
+  @param DataType    - Event Log type
+  @param AlertEvent  - If it is an alert event
+  @param Size        - Log data size
+  @param RecordId    - Indicate which recorder it is
+
+  @retval EFI_STATUS
+
+**/
+EFI_STATUS
+EfiSetBmcElogData (
+  IN  EFI_SM_ELOG_REDIR_PPI  *This,
+  IN  UINT8                  *ElogData,
+  IN  EFI_SM_ELOG_TYPE       DataType,
+  IN  BOOLEAN                AlertEvent,
+  IN  UINTN                  Size,
+  OUT UINT64                 *RecordId
+  )
+{
+  EFI_PEI_BMC_ELOG_INSTANCE_DATA  *BmcElogPrivateData;
+  EFI_STATUS                      Status;
+
+  Status             = EFI_SUCCESS;
+  BmcElogPrivateData = INSTANCE_FROM_EFI_PEI_ELOG_REDIR_THIS (This);
+
+  if (DataType >= EfiSmElogMax) {
+    return EFI_INVALID_PARAMETER;
+  }
+
+  if (Size > SEL_RECORD_SIZE) {
+    return EFI_OUT_OF_RESOURCES;
+  }
+
+  if (BmcElogPrivateData->DataType == DataType) {
+    Status = SetBmcElogRecord (ElogData, DataType, AlertEvent, Size, RecordId);
+  }
+
+  return Status;
+}
+
+/**
+  Efi Get Bmc Elog Data.
+
+  @param This        - Protocol pointer
+  @param ElogData    - Buffer for log data store
+  @param DataType    - Event log type
+  @param Size        - Size of log data
+  @param RecordId    - indicate which recorder it is
+
+  @retval EFI_STATUS
+
+**/
+EFI_STATUS
+EfiGetBmcElogData (
+  IN EFI_SM_ELOG_REDIR_PPI  *This,
+  IN OUT UINT8              *ElogData,
+  IN EFI_SM_ELOG_TYPE       DataType,
+  IN OUT UINTN              *Size,
+  IN OUT UINT64             *RecordId
+  )
+{
+  EFI_PEI_BMC_ELOG_INSTANCE_DATA  *BmcElogPrivateData;
+  EFI_STATUS                      Status;
+
+  Status             = EFI_SUCCESS;
+  BmcElogPrivateData = INSTANCE_FROM_EFI_PEI_ELOG_REDIR_THIS (This);
+
+  if (DataType >= EfiSmElogMax) {
+    return EFI_INVALID_PARAMETER;
+  }
+
+  if (BmcElogPrivateData->DataType == DataType) {
+    Status = GetBmcElogRecord (ElogData, DataType, Size, RecordId);
+  }
+
+  return Status;
+}
+
+/**
+  Efi Erase Bmc Elog Data.
+
+  @param This        - Protocol pointer
+  @param DataType    - Event log type
+  @param RecordId    - return which recorder it is
+
+  @retval EFI_STATUS
+
+**/
+EFI_STATUS
+EfiEraseBmcElogData (
+  IN EFI_SM_ELOG_REDIR_PPI  *This,
+  IN EFI_SM_ELOG_TYPE       DataType,
+  IN OUT UINT64             *RecordId
+  )
+{
+  EFI_PEI_BMC_ELOG_INSTANCE_DATA  *BmcElogPrivateData;
+  EFI_STATUS                      Status;
+
+  Status             = EFI_SUCCESS;
+  BmcElogPrivateData = INSTANCE_FROM_EFI_PEI_ELOG_REDIR_THIS (This);
+
+  if (DataType >= EfiSmElogMax) {
+    return EFI_INVALID_PARAMETER;
+  }
+
+  if (BmcElogPrivateData->DataType == DataType) {
+    Status = EraseBmcElogRecord (DataType, RecordId);
+
+    if (Status == EFI_SUCCESS) {
+      if (RecordId != NULL) {
+        *RecordId = (UINT16)(*((UINT16 *)&BmcElogPrivateData->TempData[0]));
+      }
+    }
+  }
+
+  return EFI_SUCCESS;
+}
+
+/**
+  Efi Activate Bmc Elog.
+
+  @param This        - Protocol pointer
+  @param DataType    - indicate event log type
+  @param EnableElog  - Enable/Disable event log
+  @param ElogStatus  - return log status
+
+  @retval EFI_STATUS
+
+**/
+EFI_STATUS
+EfiActivateBmcElog (
+  IN EFI_SM_ELOG_REDIR_PPI  *This,
+  IN EFI_SM_ELOG_TYPE       DataType,
+  IN BOOLEAN                *EnableElog,
+  OUT BOOLEAN               *ElogStatus
+  )
+{
+  EFI_PEI_BMC_ELOG_INSTANCE_DATA  *BmcElogPrivateData;
+  EFI_STATUS                      Status;
+
+  Status             = EFI_SUCCESS;
+  BmcElogPrivateData = INSTANCE_FROM_EFI_PEI_ELOG_REDIR_THIS (This);
+
+  if (DataType >= EfiSmElogMax) {
+    return EFI_INVALID_PARAMETER;
+  }
+
+  if (BmcElogPrivateData->DataType == DataType) {
+    Status = ActivateBmcElog (DataType, EnableElog, ElogStatus);
+  }
+
+  return Status;
+}
+
+/**
+  Set Elog Redir Install.
+
+  @retval EFI_SUCCESS
+
+**/
+EFI_STATUS
+SetElogRedirInstall (
+  EFI_PEI_BMC_ELOG_INSTANCE_DATA  *mRedirPeiProtoPrivate
+  )
+{
+  EFI_STATUS  Status;
+  BOOLEAN     EnableElog;
+  BOOLEAN     ElogStatus;
+  UINT16      Instance;
+
+  Status     = EFI_SUCCESS;
+  EnableElog = TRUE;
+  ElogStatus = TRUE;
+  Instance   = 0;
+
+  mRedirPeiProtoPrivate->Signature                    = EFI_PEI_ELOG_REDIR_SIGNATURE;
+  mRedirPeiProtoPrivate->DataType                     = EfiElogSmIPMI;
+  mRedirPeiProtoPrivate->BmcElogPpi.ActivateEventLog  = EfiActivateBmcElog;
+  mRedirPeiProtoPrivate->BmcElogPpi.EraseEventlogData = EfiEraseBmcElogData;
+  mRedirPeiProtoPrivate->BmcElogPpi.GetEventLogData   = EfiGetBmcElogData;
+  mRedirPeiProtoPrivate->BmcElogPpi.SetEventLogData   = EfiSetBmcElogData;
+
+  mRedirPeiProtoPrivate->BmcElog.Guid  = &gPeiRedirElogPpiGuid;
+  mRedirPeiProtoPrivate->BmcElog.Flags = EFI_PEI_PPI_DESCRIPTOR_PPI | EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST;
+  mRedirPeiProtoPrivate->BmcElog.Ppi   = (VOID *)&mRedirPeiProtoPrivate->BmcElogPpi;
+  mRedirPeiProtoPrivate->Instance      = Instance;
+  //
+  // Now install the Protocol
+  //
+
+  Status = PeiServicesInstallPpi (&mRedirPeiProtoPrivate->BmcElog);
+  ASSERT_EFI_ERROR (Status);
+  if (Status != EFI_SUCCESS) {
+    return Status;
+  }
+
+  //
+  // Activate the Event Log (This should depend upon Setup).
+  //
+  EfiActivateBmcElog (&mRedirPeiProtoPrivate->BmcElogPpi, EfiElogSmIPMI, &EnableElog, &ElogStatus);
+
+  return EFI_SUCCESS;
+}
+
+/**
+  InitializeBmcElogLayer.
+
+  @param ImageHandle - ImageHandle of the loaded driver
+  @param SystemTable - Pointer to the System Table
+
+  @retval EFI_STATUS
+
+**/
+EFI_STATUS
+InitializeBmcElogLayer (
+  IN       EFI_PEI_FILE_HANDLE  FileHandle,
+  IN CONST EFI_PEI_SERVICES     **PeiServices
+  )
+{
+  EFI_STATUS  Status;
+
+  Status = EFI_SUCCESS;
+
+  Status = PeiServicesNotifyPpi (&mNotifyList[0]);
+  return Status;
+}
+
+/**
+  NotifyPeiBmcElogCallback   This notification function is invoked when an instance of the
+  IPMI Transport layer at PEI is produced.
+
+  @param PeiServices      - Pointer to the PEI Services table
+  @param NotifyDescriptor - Pointer to the NotifyPpi Descriptor
+  @param Ppi              - Pointer to the PPI passed during Notify
+
+  @retval EFI_STATUS
+
+**/
+EFI_STATUS
+NotifyPeiBmcElogCallback (
+  IN EFI_PEI_SERVICES           **PeiServices,
+  IN EFI_PEI_NOTIFY_DESCRIPTOR  *NotifyDescriptor,
+  IN VOID                       *Ppi
+  )
+{
+  EFI_STATUS                      Status;
+  EFI_PEI_BMC_ELOG_INSTANCE_DATA  *mRedirPeiProtoPrivate;
+
+  Status = EFI_SUCCESS;
+
+  mRedirPeiProtoPrivate = AllocateZeroPool (sizeof (EFI_PEI_BMC_ELOG_INSTANCE_DATA));
+
+  if (mRedirPeiProtoPrivate == NULL) {
+    DEBUG ((DEBUG_ERROR, "IPMI BMCELog Peim:EFI_OUT_OF_RESOURCES of memory allocation\n"));
+    return EFI_OUT_OF_RESOURCES;
+  }
+
+  SetElogRedirInstall (mRedirPeiProtoPrivate);
+
+  CheckIfSelIsFull ();
+
+  return Status;
+}
diff --git a/Features/Intel/OutOfBandManagement/IpmiFeaturePkg/BmcElog/Smm/BmcElog.c b/Features/Intel/OutOfBandManagement/IpmiFeaturePkg/BmcElog/Smm/BmcElog.c
new file mode 100644
index 000000000000..efaa61f43869
--- /dev/null
+++ b/Features/Intel/OutOfBandManagement/IpmiFeaturePkg/BmcElog/Smm/BmcElog.c
@@ -0,0 +1,288 @@
+/** @file
+  BMC Event Log functions.
+
+Copyright (c) 2023, Intel Corporation. All rights reserved.<BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include "BmcElog.h"
+
+//
+// Define module globals used to register for notification of when
+// the ELOG REDIR protocol has been produced.
+//
+EFI_EVENT                   mEfiBmcTransEvent;
+EFI_BMC_ELOG_INSTANCE_DATA  *mRedirProtoPrivate;
+
+/**
+  WaitTillErased.
+
+  @param BmcElogPrivateData  - Bmc event log instance
+  @param ResvId              - Reserved ID
+
+  @retval EFI_SUCCESS
+  @retval EFI_NO_RESPONSE
+
+**/
+EFI_STATUS
+WaitTillErased (
+  EFI_BMC_ELOG_INSTANCE_DATA  *BmcElogPrivateData,
+  UINT8                       *ResvId
+  )
+{
+  EFI_STATUS  Status;
+
+  Status = WaitTillClearSel (ResvId);
+  return Status;
+}
+
+/**
+  Efi Set Bmc Elog Data.
+
+  @param This        - Protocol pointer
+  @param ElogData    - Buffer for log storage
+  @param DataType    - Event Log type
+  @param AlertEvent  - If it is an alert event
+  @param Size        - Log data size
+  @param RecordId    - Indicate which recorder it is
+
+  @retval EFI_STATUS
+
+**/
+EFI_STATUS
+EfiSetBmcElogData (
+  IN  EFI_SM_ELOG_REDIR_PROTOCOL  *This,
+  IN  UINT8                       *ElogData,
+  IN  EFI_SM_ELOG_TYPE            DataType,
+  IN  BOOLEAN                     AlertEvent,
+  IN  UINTN                       Size,
+  OUT UINT64                      *RecordId
+  )
+{
+  EFI_BMC_ELOG_INSTANCE_DATA  *BmcElogPrivateData;
+  EFI_STATUS                  Status;
+
+  Status             = EFI_SUCCESS;
+  BmcElogPrivateData = INSTANCE_FROM_EFI_SM_ELOG_REDIR_THIS (This);
+
+  if (DataType >= EfiSmElogMax) {
+    return EFI_INVALID_PARAMETER;
+  }
+
+  if (Size > SEL_RECORD_SIZE) {
+    return EFI_OUT_OF_RESOURCES;
+  }
+
+  if (BmcElogPrivateData->DataType == DataType) {
+    Status = SetBmcElogRecord (ElogData, DataType, AlertEvent, Size, RecordId);
+  }
+
+  return Status;
+}
+
+/**
+  Efi Get Bmc Elog Data.
+
+  @param This        - Protocol pointer
+  @param ElogData    - Buffer for log data store
+  @param DataType    - Event log type
+  @param Size        - Size of log data
+  @param RecordId    - indicate which recorder it is
+
+  @retval EFI_STATUS
+
+**/
+EFI_STATUS
+EfiGetBmcElogData (
+  IN EFI_SM_ELOG_REDIR_PROTOCOL  *This,
+  IN OUT UINT8                   *ElogData,
+  IN EFI_SM_ELOG_TYPE            DataType,
+  IN OUT UINTN                   *Size,
+  IN OUT UINT64                  *RecordId
+  )
+{
+  EFI_BMC_ELOG_INSTANCE_DATA  *BmcElogPrivateData;
+  EFI_STATUS                  Status;
+
+  Status             = EFI_SUCCESS;
+  BmcElogPrivateData = INSTANCE_FROM_EFI_SM_ELOG_REDIR_THIS (This);
+
+  if (DataType >= EfiSmElogMax) {
+    return EFI_INVALID_PARAMETER;
+  }
+
+  if (BmcElogPrivateData->DataType == DataType) {
+    Status = GetBmcElogRecord (ElogData, DataType, Size, RecordId);
+  }
+
+  return Status;
+}
+
+/**
+  Efi Erase Bmc Elog Data.
+
+  @param This        - Protocol pointer
+  @param DataType    - Event log type
+  @param RecordId    - return which recorder it is
+
+  @retval EFI_STATUS
+
+**/
+EFI_STATUS
+EfiEraseBmcElogData (
+  IN EFI_SM_ELOG_REDIR_PROTOCOL  *This,
+  IN EFI_SM_ELOG_TYPE            DataType,
+  IN OUT UINT64                  *RecordId
+  )
+{
+  EFI_BMC_ELOG_INSTANCE_DATA  *BmcElogPrivateData;
+  EFI_STATUS                  Status;
+
+  Status             = EFI_SUCCESS;
+  BmcElogPrivateData = INSTANCE_FROM_EFI_SM_ELOG_REDIR_THIS (This);
+
+  if (DataType >= EfiSmElogMax) {
+    return EFI_INVALID_PARAMETER;
+  }
+
+  if (BmcElogPrivateData->DataType == DataType) {
+    Status = EraseBmcElogRecord (DataType, RecordId);
+
+    if (Status == EFI_SUCCESS) {
+      if (RecordId != NULL) {
+        *RecordId = (UINT16)(*((UINT16 *)&BmcElogPrivateData->TempData[0]));
+      }
+    }
+  }
+
+  return EFI_SUCCESS;
+}
+
+/**
+  Efi Activate Bmc Elog.
+
+  @param This        - Protocol pointer
+  @param DataType    - indicate event log type
+  @param EnableElog  - Enable/Disable event log
+  @param ElogStatus  - return log status
+
+  @retval EFI_STATUS
+
+**/
+EFI_STATUS
+EfiActivateBmcElog (
+  IN EFI_SM_ELOG_REDIR_PROTOCOL  *This,
+  IN EFI_SM_ELOG_TYPE            DataType,
+  IN BOOLEAN                     *EnableElog,
+  OUT BOOLEAN                    *ElogStatus
+  )
+{
+  EFI_BMC_ELOG_INSTANCE_DATA  *BmcElogPrivateData;
+  EFI_STATUS                  Status;
+
+  Status             = EFI_SUCCESS;
+  BmcElogPrivateData = INSTANCE_FROM_EFI_SM_ELOG_REDIR_THIS (This);
+
+  if (DataType >= EfiSmElogMax) {
+    return EFI_INVALID_PARAMETER;
+  }
+
+  if (BmcElogPrivateData->DataType == DataType) {
+    Status = ActivateBmcElog (DataType, EnableElog, ElogStatus);
+  }
+
+  return Status;
+}
+
+/**
+  Set Elog Redir Install.
+
+  @retval EFI_SUCCESS
+
+**/
+EFI_STATUS
+SetElogRedirInstall (
+  VOID
+  )
+{
+  EFI_HANDLE  NewHandle;
+  EFI_STATUS  Status;
+  BOOLEAN     EnableElog;
+  BOOLEAN     ElogStatus;
+  UINT16      Instance;
+
+  Status     = EFI_SUCCESS;
+  EnableElog = TRUE;
+  ElogStatus = TRUE;
+  Instance   = 0;
+
+  mRedirProtoPrivate->Signature                 = SM_ELOG_REDIR_SIGNATURE;
+  mRedirProtoPrivate->DataType                  = EfiElogSmIPMI;
+  mRedirProtoPrivate->BmcElog.ActivateEventLog  = (EFI_ACTIVATE_ELOG)EfiActivateBmcElog;
+  mRedirProtoPrivate->BmcElog.EraseEventlogData = (EFI_ERASE_ELOG_DATA)EfiEraseBmcElogData;
+  mRedirProtoPrivate->BmcElog.GetEventLogData   = (EFI_GET_ELOG_DATA)EfiGetBmcElogData;
+  mRedirProtoPrivate->BmcElog.SetEventLogData   = (EFI_SET_ELOG_DATA)EfiSetBmcElogData;
+  mRedirProtoPrivate->Instance                  = Instance;
+  //
+  // Now install the Protocol
+  //
+  NewHandle = NULL;
+  Status    = gSmst->SmmInstallProtocolInterface (
+                       &NewHandle,
+                       &gSmmRedirElogProtocolGuid,
+                       EFI_NATIVE_INTERFACE,
+                       &mRedirProtoPrivate->BmcElog
+                       );
+
+  ASSERT_EFI_ERROR (Status);
+  if (Status != EFI_SUCCESS) {
+    return Status;
+  }
+
+  //
+  // Activate the Event Log (This should depend upon Setup).
+  //
+  EfiActivateBmcElog (&mRedirProtoPrivate->BmcElog, EfiElogSmIPMI, &EnableElog, &ElogStatus);
+
+  return EFI_SUCCESS;
+}
+
+/**
+  InitializeBmcElogLayer.
+
+  @param ImageHandle - ImageHandle of the loaded driver
+  @param SystemTable - Pointer to the System Table
+
+  @retval EFI_STATUS
+
+**/
+EFI_STATUS
+EFIAPI
+InitializeSmBmcElogLayer (
+  IN EFI_HANDLE        ImageHandle,
+  IN EFI_SYSTEM_TABLE  *SystemTable
+  )
+{
+  EFI_STATUS  Status;
+
+  Status = EFI_SUCCESS;
+
+  gST = SystemTable;
+  gBS = gST->BootServices;
+
+  mRedirProtoPrivate = AllocatePool (sizeof (EFI_BMC_ELOG_INSTANCE_DATA));
+  ASSERT (mRedirProtoPrivate != NULL);
+  if (mRedirProtoPrivate == NULL) {
+    return EFI_OUT_OF_RESOURCES;
+  }
+
+  SetElogRedirInstall ();
+  //
+  // Check if the BMC System Event Log (SEL) is full and whether to report the error.
+  //
+
+  CheckIfSelIsFull ();
+
+  return Status;
+}
diff --git a/Features/Intel/OutOfBandManagement/IpmiFeaturePkg/GenericElog/Dxe/GenericElog.c b/Features/Intel/OutOfBandManagement/IpmiFeaturePkg/GenericElog/Dxe/GenericElog.c
new file mode 100644
index 000000000000..d432b2151664
--- /dev/null
+++ b/Features/Intel/OutOfBandManagement/IpmiFeaturePkg/GenericElog/Dxe/GenericElog.c
@@ -0,0 +1,576 @@
+/** @file
+  Generic Event Log functions of DXE driver.
+
+Copyright (c) 2023, Intel Corporation. All rights reserved.<BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include "GenericElog.h"
+
+ELOG_MODULE_GLOBAL  *mElogModuleGlobal;
+
+//
+// Define module globals used to register for notification of when
+// the ELOG REDIR protocol has been produced.
+//
+EFI_EVENT  mEfiElogRedirProtocolEvent;
+
+/**
+  Sends the Event-Log data to the destination.
+
+  @param[in] ElogData Pointer to the Event-Log data that needs to be recorded.
+  @param[in] DataType Type of Elog Data that is being recorded.
+  @param[in] AlertEvent This is an indication that the input data type is an Alert.
+  @param[in] DataSize
+  @param[out] RecordId Record ID sent by the target.
+  @param[in] Global The module global variable pointer.
+  @param[in] Virtual If this function is called in virtual mode or physical mode
+
+  @retval EFI_SUCCESS Event-Log was recorded successfully.
+  @retval EFI_OUT_OF_RESOURCES Not enough resources to record data.
+  @retval EFI_UNSUPPORTED The Data Type is unsupported.
+
+**/
+EFI_STATUS
+EfiLibSetElogData (
+  IN  UINT8               *ElogData,
+  IN  EFI_SM_ELOG_TYPE    DataType,
+  IN  BOOLEAN             AlertEvent,
+  IN  UINTN               DataSize,
+  OUT UINT64              *RecordId,
+  IN  ELOG_MODULE_GLOBAL  *Global,
+  IN  BOOLEAN             Virtual
+  )
+{
+  UINT8       Index;
+  VOID        *ElogRedirCommand;
+  EFI_STATUS  Status;
+  EFI_STATUS  RetStatus;
+
+  RetStatus = EFI_UNSUPPORTED;
+
+  if (DataType >= EfiSmElogMax) {
+    RetStatus = EFI_INVALID_PARAMETER;
+    return RetStatus;
+  }
+
+  for (Index = 0; Index < Global->MaxDescriptors; Index++) {
+    if (Global->Redir[Index].Valid) {
+      ElogRedirCommand = Global->Redir[Index].Command[Virtual].SetEventLogData.Function;
+      Status           = (*((EFI_SET_ELOG_DATA *)&ElogRedirCommand))(Global->Redir[Index].Command[Virtual].This, ElogData, DataType, AlertEvent, DataSize, RecordId);
+
+      if (!EFI_ERROR (Status)) {
+        RetStatus = EFI_SUCCESS;
+        break;
+      } else if (Status != EFI_UNSUPPORTED) {
+        RetStatus = Status;
+        break;
+      }
+    }
+  }
+
+  return RetStatus;
+}
+
+/**
+  Add function description.
+
+  @param This        -  add argument description
+  @param ElogData    -  add argument description
+  @param DataType    -  add argument description
+  @param AlertEvent  -  add argument description
+  @param DataSize    -  add argument description
+  @param RecordId    -  add argument description
+
+  @retval EFI_SUCCESS
+
+**/
+EFI_STATUS
+EfiSetElogData (
+  IN  EFI_SM_ELOG_PROTOCOL  *This,
+  IN  UINT8                 *ElogData,
+  IN  EFI_SM_ELOG_TYPE      DataType,
+  IN  BOOLEAN               AlertEvent,
+  IN  UINTN                 DataSize,
+  OUT UINT64                *RecordId
+  )
+{
+  if (DataType >= EfiSmElogMax) {
+    return EFI_INVALID_PARAMETER;
+  }
+
+  return EfiLibSetElogData (
+           ElogData,
+           DataType,
+           AlertEvent,
+           DataSize,
+           RecordId,
+           mElogModuleGlobal,
+           FALSE
+           );
+}
+
+/**
+  Gets the Event-Log data from the destination.
+
+  @param[in] ElogData Pointer to the Event-Log data buffer that will contain the data to be retrieved.
+  @param[in] DataType Type of Elog Data that is being recorded.
+  @param[in, out] DataSize
+  @param[in, out] RecordId This is the RecordId of the next record. If ElogData is NULL,
+                       this gives the RecordId of the first record available in the database with the correct DataSize.
+                        A value of 0 on return indicates the last record if the EFI_STATUS indicates a success
+  @param[in] Global The module global variable pointer.
+  @param[in] Virtual If this function is called in virtual mode or physical mode
+
+  @retval EFI_SUCCESS Event-Log was retrieved successfully.
+  @retval EFI_NOT_FOUND Event-Log target not found.
+  @retval EFI_BUFFER_TOO_SMALL Target buffer is too small to retrieve the data.
+  @retval EFI_UNSUPPORTED The Data Type is unsupported
+
+**/
+EFI_STATUS
+EfiLibGetElogData (
+  IN UINT8               *ElogData,
+  IN EFI_SM_ELOG_TYPE    DataType,
+  IN OUT UINTN           *DataSize,
+  IN OUT UINT64          *RecordId,
+  IN ELOG_MODULE_GLOBAL  *Global,
+  IN BOOLEAN             Virtual
+  )
+{
+  UINT8       Index;
+  VOID        *ElogRedirCommand;
+  EFI_STATUS  Status;
+  EFI_STATUS  RetStatus;
+
+  RetStatus = EFI_UNSUPPORTED;
+
+  if (DataType >= EfiSmElogMax) {
+    RetStatus = EFI_INVALID_PARAMETER;
+    return RetStatus;
+  }
+
+  for (Index = 0; Index < Global->MaxDescriptors; Index++) {
+    if (Global->Redir[Index].Valid) {
+      ElogRedirCommand = Global->Redir[Index].Command[Virtual].GetEventLogData.Function;
+      Status           = (*((EFI_GET_ELOG_DATA *)&ElogRedirCommand))(Global->Redir[Index].Command[Virtual].This, ElogData, DataType, DataSize, RecordId);
+
+      if (!EFI_ERROR (Status)) {
+        RetStatus = EFI_SUCCESS;
+        break;
+      } else if (Status != EFI_UNSUPPORTED) {
+        RetStatus = Status;
+        break;
+      }
+    }
+  }
+
+  return RetStatus;
+}
+
+/**
+  Add function description.
+
+  @param This      - Protocol instance pointer.
+  @param ElogData  - Pointer to the Event-Log data buffer that will contain the data to be retrieved.
+  @param DataType  - Type of Elog Data that is being recorded.
+  @param DataSize  - Size of Elog Data in bytes.
+  @param RecordId  - This is the RecordId of the next record. If ElogData is NULL,
+                     this gives the RecordId of the first record available in the database with the correct DataSize.
+                     A value of 0 on return indicates the last record if the EFI_STATUS indicates a success
+
+  @retval EFI_SUCCESS add return values
+
+**/
+EFI_STATUS
+EfiGetElogData (
+  IN EFI_SM_ELOG_PROTOCOL  *This,
+  IN UINT8                 *ElogData,
+  IN EFI_SM_ELOG_TYPE      DataType,
+  IN OUT UINTN             *DataSize,
+  IN OUT UINT64            *RecordId
+  )
+{
+  if (DataType >= EfiSmElogMax) {
+    return EFI_INVALID_PARAMETER;
+  }
+
+  return EfiLibGetElogData (ElogData, DataType, DataSize, RecordId, mElogModuleGlobal, FALSE);
+}
+
+/**
+  Erases the Event-Log data from the destination.
+
+  @param DataType              - Type of Elog Data that is being Erased.
+  @param RecordId              - This is the RecordId of the data to be erased. If RecordId is NULL, all
+                                 the records on the database are erased if permitted by the target.
+                                 Contains the deleted RecordId on return
+  @param Global                - The module global variable pointer.
+  @param Virtual               - If this function is called in virtual mode or physical mode
+
+  @retval EFI_SUCCESS           - Event-Log was erased successfully
+  @retval EFI_UNSUPPORTED       - The Data Type is unsupported
+  @retval EFI_NOT_FOUND         - Event-Log target not found
+
+**/
+EFI_STATUS
+EfiLibEraseElogData (
+  IN EFI_SM_ELOG_TYPE    DataType,
+  IN OUT UINT64          *RecordId,
+  IN ELOG_MODULE_GLOBAL  *Global,
+  IN BOOLEAN             Virtual
+  )
+{
+  UINT8       Index;
+  VOID        *ElogRedirCommand;
+  EFI_STATUS  Status;
+  EFI_STATUS  RetStatus;
+
+  RetStatus = EFI_UNSUPPORTED;
+
+  if (DataType >= EfiSmElogMax) {
+    RetStatus = EFI_INVALID_PARAMETER;
+    return RetStatus;
+  }
+
+  for (Index = 0; Index < Global->MaxDescriptors; Index++) {
+    if (Global->Redir[Index].Valid) {
+      ElogRedirCommand = Global->Redir[Index].Command[Virtual].EraseEventLogData.Function;
+      Status           = (*((EFI_ERASE_ELOG_DATA *)&ElogRedirCommand))(Global->Redir[Index].Command[Virtual].This, DataType, RecordId);
+
+      if (!EFI_ERROR (Status)) {
+        RetStatus = EFI_SUCCESS;
+        break;
+      } else if (Status != EFI_UNSUPPORTED) {
+        RetStatus = Status;
+        break;
+      }
+    }
+  }
+
+  return RetStatus;
+}
+
+/**
+  Efi Erase Elog Data.
+
+  @param This
+  @param DataType
+  @param RecordId
+
+  @retval EFI_SUCCESS
+
+**/
+EFI_STATUS
+EfiEraseElogData (
+  IN EFI_SM_ELOG_PROTOCOL  *This,
+  IN EFI_SM_ELOG_TYPE      DataType,
+  IN OUT UINT64            *RecordId
+  )
+{
+  return EfiLibEraseElogData (DataType, RecordId, mElogModuleGlobal, FALSE);
+}
+
+/**
+  This API enables/Disables Event Log.
+
+  @param DataType              - Type of Elog Data that is being Activated.
+  @param EnableElog            - Enables (TRUE) / Disables (FALSE) Event Log. If NULL just returns the
+                                 Current ElogStatus.
+  @param ElogStatus            - Current (New) Status of Event Log. Enabled (TRUE), Disabled (FALSE).
+  @param Global                - The module global variable pointer.
+  @param Virtual               - If this function is called in virtual mode or physical mode
+
+  @retval EFI_SUCCESS           - Event-Log was recorded successfully
+  @retval EFI_UNSUPPORTED       - The Data Type is unsupported
+
+**/
+EFI_STATUS
+EfiLibActivateElog (
+  IN  EFI_SM_ELOG_TYPE  DataType,
+  IN BOOLEAN            *EnableElog,
+  OUT BOOLEAN           *ElogStatus,
+  ELOG_MODULE_GLOBAL    *Global,
+  BOOLEAN               Virtual
+  )
+{
+  UINT8       Index;
+  VOID        *ElogRedirCommand;
+  EFI_STATUS  Status;
+  EFI_STATUS  RetStatus;
+
+  RetStatus = EFI_UNSUPPORTED;
+  if (DataType >= EfiSmElogMax) {
+    RetStatus = EFI_INVALID_PARAMETER;
+    return RetStatus;
+  }
+
+  for (Index = 0; Index < Global->MaxDescriptors; Index++) {
+    if (Global->Redir[Index].Valid) {
+      ElogRedirCommand = Global->Redir[Index].Command[Virtual].ActivateEventLog.Function;
+      Status           = (*((EFI_ACTIVATE_ELOG *)&ElogRedirCommand))(Global->Redir[Index].Command[Virtual].This, DataType, EnableElog, ElogStatus);
+
+      if (!EFI_ERROR (Status)) {
+        RetStatus = EFI_SUCCESS;
+        break;
+      } else if (Status != EFI_UNSUPPORTED) {
+        RetStatus = Status;
+        break;
+      }
+    }
+  }
+
+  return RetStatus;
+}
+
+/**
+  Efi Activate Elog.
+
+  @param This
+  @param DataType
+  @param EnableElog
+  @param ElogStatus
+
+  @retval EFI_SUCCESS
+
+**/
+EFI_STATUS
+EfiActivateElog (
+  IN EFI_SM_ELOG_PROTOCOL  *This,
+  IN  EFI_SM_ELOG_TYPE     DataType,
+  IN BOOLEAN               *EnableElog,
+  OUT BOOLEAN              *ElogStatus
+  )
+{
+  if (DataType >= EfiSmElogMax) {
+    return EFI_INVALID_PARAMETER;
+  }
+
+  return EfiLibActivateElog (DataType, EnableElog, ElogStatus, mElogModuleGlobal, FALSE);
+}
+
+/**
+  SetElogRedirInstances.
+
+  @retval EFI_SUCCESS - The Redir instances were successfully set.
+  @retval Other       - Failed to set Redir instances.
+
+**/
+EFI_STATUS
+SetElogRedirInstances (
+  VOID
+  )
+{
+  UINTN                       NumHandles;
+  UINTN                       Index;
+  UINTN                       Instance;
+  UINTN                       EmptyIndex;
+  EFI_HANDLE                  *Buffer;
+  EFI_STATUS                  Status;
+  EFI_SM_ELOG_REDIR_PROTOCOL  *Redir;
+  REDIR_MODULE_PROC           *RedirProc;
+
+  Buffer = NULL;
+
+  //
+  // Check for all IPMI Controllers
+  //
+  Status = gBS->LocateHandleBuffer (
+                  ByProtocol,
+                  &gEfiRedirElogProtocolGuid,
+                  NULL,
+                  &NumHandles,
+                  &Buffer
+                  );
+
+  if (EFI_ERROR (Status) || (NumHandles == 0)) {
+    return EFI_SUCCESS;
+  }
+
+  for (Index = 0; ((Index < NumHandles) && (Index < mElogModuleGlobal->MaxDescriptors)); Index++) {
+    EmptyIndex = mElogModuleGlobal->MaxDescriptors;
+
+    Status = gBS->HandleProtocol (
+                    Buffer[Index],
+                    &gEfiRedirElogProtocolGuid,
+                    (VOID *)&Redir
+                    );
+    if (EFI_ERROR (Status) || (Redir == NULL)) {
+      continue;
+    }
+
+    for (Instance = 0; Instance < mElogModuleGlobal->MaxDescriptors; Instance++) {
+      if (mElogModuleGlobal->Redir[Instance].Valid == FALSE) {
+        if (EmptyIndex >= mElogModuleGlobal->MaxDescriptors) {
+          EmptyIndex = Instance;
+        }
+      } else {
+        if (Redir == mElogModuleGlobal->Redir[Instance].Command->This) {
+          EmptyIndex = mElogModuleGlobal->MaxDescriptors;
+          break;
+          //
+          // FIX: changed continue to break.
+          //
+        }
+      }
+    }
+
+    if (EmptyIndex < mElogModuleGlobal->MaxDescriptors) {
+      RedirProc                                  = (REDIR_MODULE_PROC *)mElogModuleGlobal->Redir[EmptyIndex].Command;
+      mElogModuleGlobal->Redir[EmptyIndex].Valid = TRUE;
+
+      EfiSetFunctionEntry (&RedirProc->ActivateEventLog, *((VOID **)&Redir->ActivateEventLog));
+      EfiSetFunctionEntry (&RedirProc->EraseEventLogData, *((VOID **)&Redir->EraseEventlogData));
+      EfiSetFunctionEntry (&RedirProc->GetEventLogData, *((VOID **)&Redir->GetEventLogData));
+      EfiSetFunctionEntry (&RedirProc->SetEventLogData, *((VOID **)&Redir->SetEventLogData));
+      RedirProc->This = Redir;
+
+      CopyMem (&RedirProc[EFI_ELOG_VIRTUAL], &RedirProc[EFI_ELOG_PHYSICAL], sizeof (REDIR_MODULE_PROC));
+    }
+  }
+
+  if (Buffer != NULL) {
+    FreePool (Buffer);
+  }
+
+  return EFI_SUCCESS;
+}
+
+/**
+  This notification function is invoked when an instance of the
+  ELOG REDIR protocol is produced.
+
+  @param Event - The event that occurred
+  @param Context - For EFI compatibility.  Not used.
+
+**/
+VOID
+EFIAPI
+NotifyElogRedirEventCallback (
+  IN EFI_EVENT  Event,
+  IN VOID       *Context
+  )
+{
+  SetElogRedirInstances ();
+}
+
+/**
+  Initialize the generic Elog driver of server management.
+
+  @param ImageHandle  - The image handle of this driver
+  @param SystemTable  - The pointer of EFI_SYSTEM_TABLE
+
+  @retval EFI_SUCCESS - The driver initialized successfully
+
+**/
+EFI_STATUS
+EFIAPI
+InitializeElogLayer (
+  IN EFI_HANDLE        ImageHandle,
+  IN EFI_SYSTEM_TABLE  *SystemTable
+  )
+{
+  EFI_HANDLE            NewHandle;
+  EFI_STATUS            Status;
+  EFI_SM_ELOG_PROTOCOL  *ElogProtocol;
+  EFI_EVENT             Event;
+
+  mElogModuleGlobal = AllocateZeroPool (sizeof (ELOG_MODULE_GLOBAL));
+  ASSERT (mElogModuleGlobal != NULL);
+  if (mElogModuleGlobal == NULL) {
+    return EFI_OUT_OF_RESOURCES;
+  }
+
+  ElogServiceInitialize (ImageHandle, SystemTable);
+
+  mElogModuleGlobal->MaxDescriptors = MAX_REDIR_DESCRIPTOR;
+
+  //
+  // Check for all IPMI Controllers
+  //
+  SetElogRedirInstances ();
+
+  ElogProtocol = AllocatePool (sizeof (EFI_SM_ELOG_PROTOCOL));
+  ASSERT (ElogProtocol != NULL);
+  if (ElogProtocol == NULL) {
+    return EFI_OUT_OF_RESOURCES;
+  }
+
+  ElogProtocol->ActivateEventLog  = EfiActivateElog;
+  ElogProtocol->EraseEventlogData = EfiEraseElogData;
+  ElogProtocol->GetEventLogData   = EfiGetElogData;
+  ElogProtocol->SetEventLogData   = EfiSetElogData;
+
+  NewHandle = NULL;
+  Status    = gBS->InstallProtocolInterface (
+                     &NewHandle,
+                     &gEfiGenericElogProtocolGuid,
+                     EFI_NATIVE_INTERFACE,
+                     ElogProtocol
+                     );
+
+  ASSERT_EFI_ERROR (Status);
+  if (Status != EFI_SUCCESS) {
+    return Status;
+  }
+
+  //
+  // Register to be notified when the ELOG REDIR protocol has been
+  // produced.
+  //
+  Status = gBS->CreateEvent (
+                  EVT_NOTIFY_SIGNAL,
+                  TPL_CALLBACK,
+                  NotifyElogRedirEventCallback,
+                  NULL,
+                  &Event
+                  );
+
+  if (!EFI_ERROR (Status)) {
+    Status = gBS->RegisterProtocolNotify (
+                    &gEfiRedirElogProtocolGuid,
+                    Event,
+                    &mEfiElogRedirProtocolEvent
+                    );
+  }
+
+  return Status;
+}
+
+/**
+  Set the function entry.
+
+  @param FunctionPointer - The destination function pointer
+  @param Function        - The source function pointer
+
+  @retval EFI_SUCCESS - Set the function pointer successfully
+
+**/
+EFI_STATUS
+EfiSetFunctionEntry (
+  IN  FUNCTION_PTR  *FunctionPointer,
+  IN  VOID          *Function
+  )
+{
+  FunctionPointer->Function = (EFI_PLABEL *)Function;
+  return EFI_SUCCESS;
+}
+
+/**
+  Initialize Dxe generic event log.
+
+  @param ImageHandle         - The Image handle of this driver.
+  @param SystemTable         - The pointer of EFI_SYSTEM_TABLE.
+
+  @retval EFI_SUCCESS - The driver successfully initialized
+
+**/
+EFI_STATUS
+ElogServiceInitialize (
+  IN EFI_HANDLE        ImageHandle,
+  IN EFI_SYSTEM_TABLE  *SystemTable
+  )
+{
+  return EFI_SUCCESS;
+}
diff --git a/Features/Intel/OutOfBandManagement/IpmiFeaturePkg/GenericElog/Smm/GenericElog.c b/Features/Intel/OutOfBandManagement/IpmiFeaturePkg/GenericElog/Smm/GenericElog.c
new file mode 100644
index 000000000000..d6a129a181fb
--- /dev/null
+++ b/Features/Intel/OutOfBandManagement/IpmiFeaturePkg/GenericElog/Smm/GenericElog.c
@@ -0,0 +1,558 @@
+/** @file
+  Generic Event Log functions of SMM driver.
+
+Copyright (c) 2023, Intel Corporation. All rights reserved.<BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include "GenericElog.h"
+
+ELOG_MODULE_GLOBAL  *mElogModuleGlobal;
+
+//
+// Define module globals used to register for notification of when
+// the ELOG REDIR protocol has been produced.
+//
+EFI_EVENT  mEfiElogRedirProtocolEvent;
+
+/**
+  Sends the Event-Log data to the destination.
+
+  @param ElogData              - Pointer to the Event-Log data that needs to be recorded.
+  @param DataType              - Type of Elog Data that is being recorded.
+  @param AlertEvent            - This is an indication that the input data type is an Alert.
+  @param DataSize              - Size of the data to be logged.
+  @param RecordId              - Record ID sent by the target.
+  @param Global                - The module global variable pointer.
+  @param Virtual               - If this function is called in virtual mode or physical mode
+
+  @retval EFI_SUCCESS            - Event-Log was recorded successfully.
+  @retval EFI_OUT_OF_RESOURCES   - Not enough resources to record data.
+  @retval EFI_UNSUPPORTED        - The Data Type is unsupported.
+
+**/
+EFI_STATUS
+EfiLibSetElogData (
+  IN  UINT8               *ElogData,
+  IN  EFI_SM_ELOG_TYPE    DataType,
+  IN  BOOLEAN             AlertEvent,
+  IN  UINTN               DataSize,
+  OUT UINT64              *RecordId,
+  IN  ELOG_MODULE_GLOBAL  *Global,
+  IN  BOOLEAN             Virtual
+  )
+{
+  UINT8       Index;
+  VOID        *ElogRedirCommand;
+  EFI_STATUS  Status;
+  EFI_STATUS  RetStatus;
+
+  RetStatus = EFI_UNSUPPORTED;
+
+  if (DataType >= EfiSmElogMax) {
+    RetStatus = EFI_INVALID_PARAMETER;
+    return RetStatus;
+  }
+
+  for (Index = 0; Index < Global->MaxDescriptors; Index++) {
+    if (Global->Redir[Index].Valid) {
+      ElogRedirCommand = Global->Redir[Index].Command[Virtual].SetEventLogData.Function;
+      Status           = (*((EFI_SET_ELOG_DATA *)&ElogRedirCommand))(Global->Redir[Index].Command[Virtual].This, ElogData, DataType, AlertEvent, DataSize, RecordId);
+
+      if (!EFI_ERROR (Status)) {
+        RetStatus = EFI_SUCCESS;
+        break;
+      } else if (Status != EFI_UNSUPPORTED) {
+        RetStatus = Status;
+        break;
+      }
+    }
+  }
+
+  return RetStatus;
+}
+
+/**
+  Efi Set Elog Data.
+
+  @param This
+  @param ElogData
+  @param DataType
+  @param AlertEvent
+  @param DataSize
+  @param RecordId
+
+  @retval EFI_SUCCESS
+
+**/
+EFI_STATUS
+EfiSetElogData (
+  IN  EFI_SM_ELOG_PROTOCOL  *This,
+  IN  UINT8                 *ElogData,
+  IN  EFI_SM_ELOG_TYPE      DataType,
+  IN  BOOLEAN               AlertEvent,
+  IN  UINTN                 DataSize,
+  OUT UINT64                *RecordId
+  )
+{
+  if (DataType >= EfiSmElogMax) {
+    return EFI_INVALID_PARAMETER;
+  }
+
+  return EfiLibSetElogData (
+           ElogData,
+           DataType,
+           AlertEvent,
+           DataSize,
+           RecordId,
+           mElogModuleGlobal,
+           FALSE
+           );
+}
+
+/**
+  Gets the Event-Log data from the destination.
+
+  @param ElogData              - Pointer to the Event-Log data buffer that will contain the data to be retrieved.
+  @param DataType              - Type of Elog Data that is being recorded.
+  @param DataSize              - Size of the data to be retrieved. .
+  @param RecordId              - This is the RecordId of the next record. If ElogData is NULL,
+                                this gives the RecordId of the first record available in the database with the correct DataSize.
+                                A value of 0 on return indicates the last record if the EFI_STATUS indicates a success
+  @param Global                - The module global variable pointer.
+  @param Virtual               - If this function is called in virtual mode or physical mode
+
+  @retval EFI_SUCCESS           - Event-Log was retrieved successfully.
+  @retval EFI_NOT_FOUND         - Event-Log target not found.
+  @retval EFI_BUFFER_TOO_SMALL  - Target buffer is too small to retrieve the data.
+  @retval EFI_UNSUPPORTED       - The Data Type is unsupported
+
+**/
+EFI_STATUS
+EfiLibGetElogData (
+  IN UINT8               *ElogData,
+  IN EFI_SM_ELOG_TYPE    DataType,
+  IN OUT UINTN           *DataSize,
+  IN OUT UINT64          *RecordId,
+  IN ELOG_MODULE_GLOBAL  *Global,
+  IN BOOLEAN             Virtual
+  )
+{
+  UINT8       Index;
+  VOID        *ElogRedirCommand;
+  EFI_STATUS  Status;
+  EFI_STATUS  RetStatus;
+
+  RetStatus = EFI_UNSUPPORTED;
+
+  if (DataType >= EfiSmElogMax) {
+    RetStatus = EFI_INVALID_PARAMETER;
+    return RetStatus;
+  }
+
+  for (Index = 0; Index < Global->MaxDescriptors; Index++) {
+    if (Global->Redir[Index].Valid) {
+      ElogRedirCommand = Global->Redir[Index].Command[Virtual].GetEventLogData.Function;
+      Status           = (*((EFI_GET_ELOG_DATA *)&ElogRedirCommand))(Global->Redir[Index].Command[Virtual].This, ElogData, DataType, DataSize, RecordId);
+
+      if (!EFI_ERROR (Status)) {
+        RetStatus = EFI_SUCCESS;
+        break;
+      } else if (Status != EFI_UNSUPPORTED) {
+        RetStatus = Status;
+        break;
+      }
+    }
+  }
+
+  return RetStatus;
+}
+
+/**
+  Efi Get Elog Data.
+
+  @param This
+  @param ElogData
+  @param DataType
+  @param DataSize
+  @param RecordId
+
+  @retval EFI_SUCCESS
+
+**/
+EFI_STATUS
+EfiGetElogData (
+  IN EFI_SM_ELOG_PROTOCOL  *This,
+  IN UINT8                 *ElogData,
+  IN EFI_SM_ELOG_TYPE      DataType,
+  IN OUT UINTN             *DataSize,
+  IN OUT UINT64            *RecordId
+  )
+{
+  if (DataType >= EfiSmElogMax) {
+    return EFI_INVALID_PARAMETER;
+  }
+
+  return EfiLibGetElogData (ElogData, DataType, DataSize, RecordId, mElogModuleGlobal, FALSE);
+}
+
+/**
+  Erases the Event-Log data from the destination.
+
+  @param DataType              - Type of Elog Data that is being Erased.
+  @param RecordId              - This is the RecordId of the data to be erased. If RecordId is NULL, all
+                                 the records on the database are erased if permitted by the target.
+                                 Contains the deleted RecordId on return
+  @param Global                - The module global variable pointer.
+  @param Virtual               - If this function is called in virtual mode or physical mode
+
+  @retval EFI_SUCCESS           - Event-Log was erased successfully
+  @retval EFI_UNSUPPORTED       - The Data Type is unsupported
+  @retval EFI_NOT_FOUND         - Event-Log target not found
+
+**/
+EFI_STATUS
+EfiLibEraseElogData (
+  IN EFI_SM_ELOG_TYPE    DataType,
+  IN OUT UINT64          *RecordId,
+  IN ELOG_MODULE_GLOBAL  *Global,
+  IN BOOLEAN             Virtual
+  )
+{
+  UINT8       Index;
+  VOID        *ElogRedirCommand;
+  EFI_STATUS  Status;
+  EFI_STATUS  RetStatus;
+
+  RetStatus = EFI_UNSUPPORTED;
+
+  if (DataType >= EfiSmElogMax) {
+    RetStatus = EFI_INVALID_PARAMETER;
+    return RetStatus;
+  }
+
+  for (Index = 0; Index < Global->MaxDescriptors; Index++) {
+    if (Global->Redir[Index].Valid) {
+      ElogRedirCommand = Global->Redir[Index].Command[Virtual].EraseEventLogData.Function;
+      Status           = (*((EFI_ERASE_ELOG_DATA *)&ElogRedirCommand))(Global->Redir[Index].Command[Virtual].This, DataType, RecordId);
+
+      if (!EFI_ERROR (Status)) {
+        RetStatus = EFI_SUCCESS;
+        break;
+      } else if (Status != EFI_UNSUPPORTED) {
+        RetStatus = Status;
+        break;
+      }
+    }
+  }
+
+  return RetStatus;
+}
+
+/**
+  Efi Erase Elog Data
+
+  @param This
+  @param DataType
+  @param RecordId
+
+  @retval EFI_SUCCESS
+
+**/
+EFI_STATUS
+EfiEraseElogData (
+  IN EFI_SM_ELOG_PROTOCOL  *This,
+  IN EFI_SM_ELOG_TYPE      DataType,
+  IN OUT UINT64            *RecordId
+  )
+{
+  return EfiLibEraseElogData (DataType, RecordId, mElogModuleGlobal, FALSE);
+}
+
+/**
+  This API enables/Disables Event Log.
+
+  @param DataType              - Type of Elog Data that is being Activated.
+  @param EnableElog            - Enables (TRUE) / Disables (FALSE) Event Log. If NULL just returns the
+                                 Current ElogStatus.
+  @param ElogStatus            - Current (New) Status of Event Log. Enabled (TRUE), Disabled (FALSE).
+  @param Global                - The module global variable pointer.
+  @param Virtual               - If this function is called in virtual mode or physical mode
+
+  @retval EFI_SUCCESS           - Event-Log was recorded successfully
+  @retval EFI_UNSUPPORTED       - The Data Type is unsupported
+
+**/
+EFI_STATUS
+EfiLibActivateElog (
+  IN  EFI_SM_ELOG_TYPE  DataType,
+  IN BOOLEAN            *EnableElog,
+  OUT BOOLEAN           *ElogStatus,
+  ELOG_MODULE_GLOBAL    *Global,
+  BOOLEAN               Virtual
+  )
+{
+  UINT8       Index;
+  VOID        *ElogRedirCommand;
+  EFI_STATUS  Status;
+  EFI_STATUS  RetStatus;
+
+  RetStatus = EFI_UNSUPPORTED;
+  if (DataType >= EfiSmElogMax) {
+    RetStatus = EFI_INVALID_PARAMETER;
+    return RetStatus;
+  }
+
+  for (Index = 0; Index < Global->MaxDescriptors; Index++) {
+    if (Global->Redir[Index].Valid) {
+      ElogRedirCommand = Global->Redir[Index].Command[Virtual].ActivateEventLog.Function;
+      Status           = (*((EFI_ACTIVATE_ELOG *)&ElogRedirCommand))(Global->Redir[Index].Command[Virtual].This, DataType, EnableElog, ElogStatus);
+
+      if (!EFI_ERROR (Status)) {
+        RetStatus = EFI_SUCCESS;
+        break;
+      } else if (Status != EFI_UNSUPPORTED) {
+        RetStatus = Status;
+        break;
+      }
+    }
+  }
+
+  return RetStatus;
+}
+
+/**
+  Efi Activate Elog.
+
+  @param This
+  @param DataType
+  @param EnableElog
+  @param ElogStatus
+
+  @retval EFI_SUCCESS
+
+**/
+EFI_STATUS
+EfiActivateElog (
+  IN EFI_SM_ELOG_PROTOCOL  *This,
+  IN  EFI_SM_ELOG_TYPE     DataType,
+  IN BOOLEAN               *EnableElog,
+  OUT BOOLEAN              *ElogStatus
+  )
+{
+  if (DataType >= EfiSmElogMax) {
+    return EFI_INVALID_PARAMETER;
+  }
+
+  return EfiLibActivateElog (DataType, EnableElog, ElogStatus, mElogModuleGlobal, FALSE);
+}
+
+/**
+  Set Elog Redir Instances.
+
+  @retval EFI_SUCCESS - The Redir instances were successfully set.
+  @retval Other       - Failed to set Redir instances.
+
+**/
+EFI_STATUS
+SetElogRedirInstances (
+  VOID
+  )
+{
+  UINTN                       NumHandles;
+  UINTN                       Index;
+  UINTN                       Instance;
+  UINTN                       EmptyIndex;
+  EFI_HANDLE                  *Buffer;
+  EFI_STATUS                  Status;
+  EFI_SM_ELOG_REDIR_PROTOCOL  *Redir;
+  REDIR_MODULE_PROC           *RedirProc;
+
+  Buffer = NULL;
+
+  //
+  // Check for all IPMI Controllers
+  //
+  Status = gSmst->SmmLocateHandle (
+                    ByProtocol,
+                    &gSmmRedirElogProtocolGuid,
+                    NULL,
+                    &NumHandles,
+                    Buffer
+                    );
+
+  if (EFI_ERROR (Status) || (NumHandles == 0) || (Buffer == NULL)) {
+    return Status;
+  }
+
+  for (Index = 0; ((Index < NumHandles) && (Index < mElogModuleGlobal->MaxDescriptors)); Index++) {
+    EmptyIndex = mElogModuleGlobal->MaxDescriptors;
+
+    Status = gSmst->SmmHandleProtocol (
+                      Buffer[Index],
+                      &gSmmRedirElogProtocolGuid,
+                      (VOID *)&Redir
+                      );
+    if (EFI_ERROR (Status) || (Redir == NULL)) {
+      continue;
+    }
+
+    for (Instance = 0; Instance < mElogModuleGlobal->MaxDescriptors; Instance++) {
+      if (mElogModuleGlobal->Redir[Instance].Valid == FALSE) {
+        if (EmptyIndex >= mElogModuleGlobal->MaxDescriptors) {
+          EmptyIndex = Instance;
+        }
+      } else {
+        if (Redir == mElogModuleGlobal->Redir[Instance].Command->This) {
+          EmptyIndex = mElogModuleGlobal->MaxDescriptors;
+          break;
+          //
+          // FIX: changed continue to break.
+          //
+        }
+      }
+    }
+
+    if (EmptyIndex < mElogModuleGlobal->MaxDescriptors) {
+      RedirProc                                  = (REDIR_MODULE_PROC *)mElogModuleGlobal->Redir[EmptyIndex].Command;
+      mElogModuleGlobal->Redir[EmptyIndex].Valid = TRUE;
+
+      EfiSetFunctionEntry (&RedirProc->ActivateEventLog, *((VOID **)&Redir->ActivateEventLog));
+      EfiSetFunctionEntry (&RedirProc->EraseEventLogData, *((VOID **)&Redir->EraseEventlogData));
+      EfiSetFunctionEntry (&RedirProc->GetEventLogData, *((VOID **)&Redir->GetEventLogData));
+      EfiSetFunctionEntry (&RedirProc->SetEventLogData, *((VOID **)&Redir->SetEventLogData));
+      RedirProc->This = Redir;
+
+      CopyMem (&RedirProc[EFI_ELOG_VIRTUAL], &RedirProc[EFI_ELOG_PHYSICAL], sizeof (REDIR_MODULE_PROC));
+    }
+  }
+
+  return EFI_SUCCESS;
+}
+
+/**
+    This notification function is invoked when an instance of the
+    ELOG REDIR protocol is produced.
+
+    @param Event - The event that occurred
+    @param Context - For EFI compatibility.  Not used.
+
+**/
+VOID
+EFIAPI
+NotifyElogRedirEventCallback (
+  IN EFI_EVENT  Event,
+  IN VOID       *Context
+  )
+{
+  SetElogRedirInstances ();
+}
+
+/**
+  Initialize the generic Elog driver of server management.
+
+  @param ImageHandle  - The image handle of this driver
+  @param SystemTable  - The pointer of EFI_SYSTEM_TABLE
+
+  @retval EFI_SUCCESS - The driver initialized successfully
+
+**/
+EFI_STATUS
+EFIAPI
+InitializeSmElogLayer (
+  IN EFI_HANDLE        ImageHandle,
+  IN EFI_SYSTEM_TABLE  *SystemTable
+  )
+{
+  EFI_HANDLE            NewHandle;
+  EFI_STATUS            Status;
+  EFI_SM_ELOG_PROTOCOL  *ElogProtocol;
+
+  mElogModuleGlobal = AllocatePool (sizeof (ELOG_MODULE_GLOBAL));
+  ASSERT (mElogModuleGlobal != NULL);
+  if (mElogModuleGlobal == NULL) {
+    return EFI_OUT_OF_RESOURCES;
+  }
+
+  SmElogServiceInitialize (ImageHandle, SystemTable);
+
+  mElogModuleGlobal->MaxDescriptors = MAX_REDIR_DESCRIPTOR;
+
+  //
+  // Check for all IPMI Controllers
+  //
+  SetElogRedirInstances ();
+
+  ElogProtocol = AllocatePool (sizeof (EFI_SM_ELOG_PROTOCOL));
+  ASSERT (ElogProtocol != NULL);
+  if (ElogProtocol == NULL) {
+    return EFI_OUT_OF_RESOURCES;
+  }
+
+  ElogProtocol->ActivateEventLog  = (EFI_ACTIVATE_ELOG)EfiActivateElog;
+  ElogProtocol->EraseEventlogData = (EFI_ERASE_ELOG_DATA)EfiEraseElogData;
+  ElogProtocol->GetEventLogData   = (EFI_GET_ELOG_DATA)EfiGetElogData;
+  ElogProtocol->SetEventLogData   = (EFI_SET_ELOG_DATA)EfiSetElogData;
+
+  NewHandle = NULL;
+  Status    = gSmst->SmmInstallProtocolInterface (
+                       &NewHandle,
+                       &gSmmGenericElogProtocolGuid,
+                       EFI_NATIVE_INTERFACE,
+                       ElogProtocol
+                       );
+
+  ASSERT_EFI_ERROR (Status);
+  if (Status != EFI_SUCCESS) {
+    return Status;
+  }
+
+  //
+  // Register to be notified when the ELOG REDIR protocol has been
+  // produced.
+  //
+  Status = gSmst->SmmRegisterProtocolNotify (
+                    &gSmmRedirElogProtocolGuid,
+                    NULL,
+                    &mEfiElogRedirProtocolEvent
+                    );
+  return Status;
+}
+
+/**
+  Set the function entry.
+
+  @param FunctionPointer - The destination function pointer
+  @param Function        - The source function pointer
+
+  @retval EFI_SUCCESS - Set the function pointer successfully
+
+**/
+EFI_STATUS
+EfiSetFunctionEntry (
+  IN  FUNCTION_PTR  *FunctionPointer,
+  IN  VOID          *Function
+  )
+{
+  FunctionPointer->Function = (EFI_PLABEL *)Function;
+  return EFI_SUCCESS;
+}
+
+/**
+  Entry point of SM Elog service Driver
+
+  @param ImageHandle         - The Image handle of this driver.
+  @param SystemTable         - The pointer of EFI_SYSTEM_TABLE.
+
+  @retval EFI_SUCCESS - The driver successfully initialized
+
+**/
+EFI_STATUS
+SmElogServiceInitialize (
+  IN EFI_HANDLE        ImageHandle,
+  IN EFI_SYSTEM_TABLE  *SystemTable
+  )
+{
+  return EFI_SUCCESS;
+}
-- 
2.39.2.windows.1



-=-=-=-=-=-=-=-=-=-=-=-
Groups.io Links: You receive all messages sent to this group.
View/Reply Online (#110229): https://edk2.groups.io/g/devel/message/110229
Mute This Topic: https://groups.io/mt/102231766/7686176
Group Owner: devel+owner@edk2.groups.io
Unsubscribe: https://edk2.groups.io/g/devel/unsub [rebecca@openfw.io]
-=-=-=-=-=-=-=-=-=-=-=-



^ permalink raw reply related	[flat|nested] 7+ messages in thread

* [edk2-devel] [PATCH edk2-platforms 2/4] IpmiFeaturePkg: Add ServerManagementLib
  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 ` Zhen Gong
  2023-10-27 20:11 ` [edk2-devel] [PATCH edk2-platforms 3/4] IpmiFeaturePkg: Add ACPI power state drivers Zhen Gong
                   ` (2 subsequent siblings)
  4 siblings, 0 replies; 7+ messages in thread
From: Zhen Gong @ 2023-10-27 20:11 UTC (permalink / raw)
  To: devel; +Cc: Zhen Gong

Lightweight lib to support Server Management drivers.

Signed-off-by: Zhen Gong <zhen.gong@intel.com>
---
 .../IpmiFeaturePkg/Include/IpmiFeature.dsc    |   1 +
 .../ServerManagementLib.inf                   |  35 +
 .../ServerManagementLibNull.inf               |  38 +
 .../Include/Library/ServerMgmtRtLib.h         | 147 ++++
 .../ServerManagementLib/ServerManagementLib.c | 696 ++++++++++++++++++
 .../ServerManagementLibNull.c                 | 144 ++++
 6 files changed, 1061 insertions(+)
 create mode 100644 Features/Intel/OutOfBandManagement/IpmiFeaturePkg/Library/ServerManagementLib/ServerManagementLib.inf
 create mode 100644 Features/Intel/OutOfBandManagement/IpmiFeaturePkg/Library/ServerManagementLibNull/ServerManagementLibNull.inf
 create mode 100644 Features/Intel/OutOfBandManagement/IpmiFeaturePkg/Include/Library/ServerMgmtRtLib.h
 create mode 100644 Features/Intel/OutOfBandManagement/IpmiFeaturePkg/Library/ServerManagementLib/ServerManagementLib.c
 create mode 100644 Features/Intel/OutOfBandManagement/IpmiFeaturePkg/Library/ServerManagementLibNull/ServerManagementLibNull.c

diff --git a/Features/Intel/OutOfBandManagement/IpmiFeaturePkg/Include/IpmiFeature.dsc b/Features/Intel/OutOfBandManagement/IpmiFeaturePkg/Include/IpmiFeature.dsc
index fa98e5672d83..fc9001e98473 100644
--- a/Features/Intel/OutOfBandManagement/IpmiFeaturePkg/Include/IpmiFeature.dsc
+++ b/Features/Intel/OutOfBandManagement/IpmiFeaturePkg/Include/IpmiFeature.dsc
@@ -51,6 +51,7 @@ [LibraryClasses.common.DXE_DRIVER,LibraryClasses.common.UEFI_DRIVER]
 [LibraryClasses.common]
   BmcCommonInterfaceLib|IpmiFeaturePkg/Library/BmcInterfaceCommonAccess/BmcCommonInterfaceLib.inf
   BtInterfaceLib|IpmiFeaturePkg/Library/BmcInterfaceCommonAccess/BtInterfaceLib/BtInterfaceLib.inf
+  ServerManagementLib|IpmiFeaturePkg/Library/ServerManagementLib/ServerManagementLib.inf
 
 [LibraryClasses.common.DXE_RUNTIME_DRIVER, LibraryClasses.common.DXE_DRIVER]
   SsifInterfaceLib|IpmiFeaturePkg/Library/BmcInterfaceCommonAccess/SsifInterfaceLib/DxeSsifInterfaceLib.inf
diff --git a/Features/Intel/OutOfBandManagement/IpmiFeaturePkg/Library/ServerManagementLib/ServerManagementLib.inf b/Features/Intel/OutOfBandManagement/IpmiFeaturePkg/Library/ServerManagementLib/ServerManagementLib.inf
new file mode 100644
index 000000000000..25a3a7540762
--- /dev/null
+++ b/Features/Intel/OutOfBandManagement/IpmiFeaturePkg/Library/ServerManagementLib/ServerManagementLib.inf
@@ -0,0 +1,35 @@
+### @file
+#
+# Copyright (c) 2023, Intel Corporation. All rights reserved.<BR>
+#
+# SPDX-License-Identifier: BSD-2-Clause-Patent
+#
+###
+
+
+[Defines]
+  INF_VERSION                = 0x00010005
+  BASE_NAME                  = ServerManagementLib
+  FILE_GUID                  = D43C86F0-7C8B-4992-9593-8CB6FBC66A0A
+  MODULE_TYPE                = BASE
+  VERSION_STRING             = 1.0
+  PI_SPECIFICATION_VERSION   = 0x0001000A
+  LIBRARY_CLASS              = ServerManagementLib
+
+[Sources]
+  ServerManagementLib.c
+
+[Packages]
+  IpmiFeaturePkg/IpmiFeaturePkg.dec
+  MdePkg/MdePkg.dec
+
+[LibraryClasses]
+  IoLib
+  DebugLib
+  UefiBootServicesTableLib
+
+[Protocols]
+  gEfiGenericElogProtocolGuid
+
+
+
diff --git a/Features/Intel/OutOfBandManagement/IpmiFeaturePkg/Library/ServerManagementLibNull/ServerManagementLibNull.inf b/Features/Intel/OutOfBandManagement/IpmiFeaturePkg/Library/ServerManagementLibNull/ServerManagementLibNull.inf
new file mode 100644
index 000000000000..6b66b44857f3
--- /dev/null
+++ b/Features/Intel/OutOfBandManagement/IpmiFeaturePkg/Library/ServerManagementLibNull/ServerManagementLibNull.inf
@@ -0,0 +1,38 @@
+### @file
+#
+# Copyright (c) 2023, Intel Corporation. All rights reserved.<BR>
+#
+# SPDX-License-Identifier: BSD-2-Clause-Patent
+#
+###
+
+
+[Defines]
+  INF_VERSION                   = 0x00010005
+  BASE_NAME                     = ServerManagementLibNull
+  FILE_GUID                     = 3AC01DE9-5A96-4df5-A645-ECD092C29AF9
+  MODULE_TYPE                   = BASE
+  VERSION_STRING                = 1.0
+  PI_SPECIFICATION_VERSION      = 0x0001000A
+  LIBRARY_CLASS                 = ServerManagementLib
+
+#
+# The following information is for reference only and not required by the build tools.
+#
+#  VALID_ARCHITECTURES          = IA32 X64
+#
+
+[Sources.common]
+  ServerManagementLibNull.c
+
+
+[Packages]
+  MdePkg/MdePkg.dec
+  ServerPlatformPkg/PlatformPkg.dec
+
+[LibraryClasses]
+  DebugLib
+
+[Protocols]
+
+
diff --git a/Features/Intel/OutOfBandManagement/IpmiFeaturePkg/Include/Library/ServerMgmtRtLib.h b/Features/Intel/OutOfBandManagement/IpmiFeaturePkg/Include/Library/ServerMgmtRtLib.h
new file mode 100644
index 000000000000..12b2e82f9e6e
--- /dev/null
+++ b/Features/Intel/OutOfBandManagement/IpmiFeaturePkg/Include/Library/ServerMgmtRtLib.h
@@ -0,0 +1,147 @@
+/** @file
+  Server Management Driver Lib.
+
+Copyright (c) 2023, Intel Corporation. All rights reserved.<BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#ifndef _SERVER_MGMT_LIB_H_
+#define _SERVER_MGMT_LIB_H_
+
+#include <Protocol/GenericElog.h>
+
+/**
+  ELOG Library Initializer.
+**/
+
+/**
+  The function will set up a notification on the ELOG protocol.  This function is required to be called prior
+  to utilizing the ELOG protocol from within this library.
+  @param None
+
+  @retval EFI_SUCCESS  After the notification has been setup.
+  @retval Other        Failure in constructor.
+
+**/
+EFI_STATUS
+EfiInitializeGenericElog (
+  VOID
+  );
+
+/**
+
+  This function sends event log data to the destination such as LAN, ICMB, BMC etc.
+  @param[in] ElogData A pointer to the event log data that needs to be recorded
+  @param[in] DataType Type of Elog data that is being recorded.  The Elog is redirected based on this
+               parameter.
+  @param[in] AlertEvent An indication that the input data type is an alert.  The underlying
+                 drivers need to decide if they need to listen to the DataType and send it on
+                 an appropriate channel as an alert use of the information.
+  @param[in] DataSize The size of the data to be logged
+  @param[out] RecordId The array of record IDs sent by the target.  This can be used to retrieve the
+               records or erase the records.
+
+  @retval EFI_SUCCESS If the data was logged.
+  @retval EFI_INVALID_PARAMETER If the DataType is >= EfiSmElogMax
+  @retval EFI_OUT_OF_RESOURCES If the DataSize is larger than the Elog temp buffer and we cannot log the record
+  @retval EFI_NOT_FOUND The event log target was not found
+  @retval EFI_PROTOCOL_ERROR There was a data formatting error
+
+**/
+EFI_STATUS
+EfiSmSetEventLogData (
+  IN  UINT8             *ElogData,
+  IN  EFI_SM_ELOG_TYPE  DataType,
+  IN  BOOLEAN           AlertEvent,
+  IN  UINTN             DataSize,
+  OUT UINT64            *RecordId
+  );
+
+/**
+
+  This function gets event log data from the destination dependent on the DataType.  The destination
+  can be a remote target such as LAN, ICMB, IPMI, or a FV.  The ELOG redir driver will resolve the
+  destination.
+  @param[in] ElogData Pointer to the event log data buffer to contain the data to be retrieved.
+  @param[in] DataType This is the type of Elog data to be gotten.  Elog is redirected based upon this
+             information.
+  @param[in, out] DataSize This is the size of the data to be retrieved.
+  @param[in, out] RecordId The RecordId of the next record.  If ElogData is NULL, this gives the RecordId of the first
+                  record available in the database with the correct DataSize.  A value of 0 on return indicates
+                  that it was last record if the Status is EFI_SUCCESS.
+
+  @retval EFI_SUCCESS If the event log was retrieved successfully.
+  @retval EFI_NOT_FOUND If the event log target was not found.
+  @retval EFI_NO_RESPONSE If the event log target is not responding.  This is done by the redir driver.
+  @retval EFI_INVALID_PARAMETER DataType or another parameter was invalid.
+  @retval EFI_BUFFER_TOO_SMALL The ElogData buffer is too small to be filled with the requested data.
+
+**/
+EFI_STATUS
+EfiSmGetEventLogData (
+  IN  UINT8             *ElogData,
+  IN  EFI_SM_ELOG_TYPE  DataType,
+  IN  OUT UINTN         *DataSize,
+  IN OUT UINT64         *RecordId
+  );
+
+/**
+  This function erases the event log data defined by the DataType.  The redir driver associated with
+  the DataType resolves the path to the record.
+
+  @param[in] DataType The type of Elog data that is to be erased.
+  @param[in, out] RecordId The RecordId of the data to be erased.  If RecordId is NULL, all records in the
+                  database are erased if permitted by the target.  RecordId will contain the deleted
+                  RecordId on return.
+
+  @retval EFI_SUCCESS The record or collection of records were erased.
+  @retval EFI_NOT_FOUND The event log target was not found.
+  @retval EFI_NO_RESPONSE The event log target was found but did not respond.
+  @retval EFI_INVALID_PARAMETER One of the parameters was invalid.
+
+**/
+EFI_STATUS
+EfiSmEraseEventlogData (
+  IN EFI_SM_ELOG_TYPE  DataType,
+  IN OUT UINT64        *RecordId
+  );
+
+/**
+
+  This function enables or disables the event log defined by the DataType.
+  @param[in] DataType The type of Elog data that is being activated.
+  @param[in] EnableElog Enables or disables the event log defined by the DataType.  If it is NULL
+             it returns the current status of the DataType log.
+  @param[out] ElogStatus Is the current status of the Event log defined by the DataType.  Enabled is
+              TRUE and Disabled is FALSE.
+
+  @retval EFI_SUCCESS If the event log was successfully enabled or disabled.
+  @retval EFI_NOT_FOUND The event log target was not found.
+  @retval EFI_NO_RESPONSE The event log target was found but did not respond.
+  @retval EFI_INVALID_PARAMETER One of the parameters was invalid.
+
+**/
+EFI_STATUS
+EfiSmActivateEventLog (
+  IN EFI_SM_ELOG_TYPE  DataType,
+  IN BOOLEAN           *EnableElog,
+  OUT BOOLEAN          *ElogStatus
+  );
+
+/**
+
+  Return Date and Time from RTC in Unix format which fits in 32 bit format.
+
+  @param[out] NumOfSeconds Pointer to return calculated time.
+
+  @retval EFI_SUCCESS
+  @retval Other EFI status if error occurred.
+
+**/
+EFI_STATUS
+EfiSmGetTimeStamp (
+  OUT UINT32  *NumOfSeconds
+  );
+
+#endif // _SERVER_MGMT_LIB_H_
diff --git a/Features/Intel/OutOfBandManagement/IpmiFeaturePkg/Library/ServerManagementLib/ServerManagementLib.c b/Features/Intel/OutOfBandManagement/IpmiFeaturePkg/Library/ServerManagementLib/ServerManagementLib.c
new file mode 100644
index 000000000000..66a481fa57b4
--- /dev/null
+++ b/Features/Intel/OutOfBandManagement/IpmiFeaturePkg/Library/ServerManagementLib/ServerManagementLib.c
@@ -0,0 +1,696 @@
+/** @file
+  Lightweight lib to support EFI Server Management drivers.
+
+Copyright (c) 2023, Intel Corporation. All rights reserved.<BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include <PiDxe.h>
+#include <Library/IoLib.h>
+#include <Library/DebugLib.h>
+#include <Library/UefiBootServicesTableLib.h>
+#include <Protocol/GenericElog.h>
+
+#include <Library/ServerMgmtRtLib.h>
+
+// #include EFI_PROTOCOL_DEPENDENCY (CpuIo)
+
+#define PCAT_RTC_ADDRESS_REGISTER  0x70
+#define PCAT_RTC_DATA_REGISTER     0x71
+
+#define RTC_ADDRESS_SECONDS           0   // R/W  Range 0..59
+#define RTC_ADDRESS_MINUTES           2   // R/W  Range 0..59
+#define RTC_ADDRESS_HOURS             4   // R/W  Range 1..12 or 0..23 Bit 7 is AM/PM
+#define RTC_ADDRESS_DAY_OF_THE_MONTH  7   // R/W  Range 1..31
+#define RTC_ADDRESS_MONTH             8   // R/W  Range 1..12
+#define RTC_ADDRESS_YEAR              9   // R/W  Range 0..99
+#define RTC_ADDRESS_REGISTER_A        10  // R/W[0..6]  R0[7]
+#define RTC_ADDRESS_REGISTER_B        11  // R/W
+#define RTC_ADDRESS_REGISTER_C        12  // RO
+#define RTC_ADDRESS_REGISTER_D        13  // RO
+#define RTC_ADDRESS_CENTURY           50  // R/W  Range 19..20 Bit 8 is R/W
+
+//
+// Register A
+//
+typedef struct {
+  UINT8    RS  : 4; // Rate Selection Bits
+  UINT8    DV  : 3; // Divisor
+  UINT8    UIP : 1; // Update in progress
+} RTC_REGISTER_A_BITS;
+
+typedef union {
+  RTC_REGISTER_A_BITS    Bits;
+  UINT8                  Data;
+} RTC_REGISTER_A;
+
+//
+// Register B
+//
+typedef struct {
+  UINT8    DSE  : 1; // 0 - Daylight saving disabled  1 - Daylight savings enabled
+  UINT8    MIL  : 1; // 0 - 12 hour mode              1 - 24 hour mode
+  UINT8    DM   : 1; // 0 - BCD Format                1 - Binary Format
+  UINT8    SQWE : 1; // 0 - Disable SQWE output       1 - Enable SQWE output
+  UINT8    UIE  : 1; // 0 - Update INT disabled       1 - Update INT enabled
+  UINT8    AIE  : 1; // 0 - Alarm INT disabled        1 - Alarm INT Enabled
+  UINT8    PIE  : 1; // 0 - Periodic INT disabled     1 - Periodic INT Enabled
+  UINT8    SET  : 1; // 0 - Normal operation.         1 - Updates inhibited
+} RTC_REGISTER_B_BITS;
+
+typedef union {
+  RTC_REGISTER_B_BITS    Bits;
+  UINT8                  Data;
+} RTC_REGISTER_B;
+
+//
+// Register D
+//
+typedef struct {
+  UINT8    Reserved : 7; // Read as zero.  Can not be written.
+  UINT8    VRT      : 1; // Valid RAM and Time
+} RTC_REGISTER_D_BITS;
+
+typedef union {
+  RTC_REGISTER_D_BITS    Bits;
+  UINT8                  Data;
+} RTC_REGISTER_D;
+
+//
+// Module Globals
+//
+EFI_SM_ELOG_PROTOCOL  *mGenericElogProtocol     = NULL;
+VOID                  *mGenericElogRegistration = NULL;
+
+INTN  DaysOfMonth[12] = { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };
+
+/**
+  This function is called whenever an instance of ELOG protocol is created.  When the function is notified
+  it initializes the module global data.
+
+  @param Event                  This is used only for EFI compatibility.
+  @param Context                This is used only for EFI compatibility.
+
+**/
+VOID
+EFIAPI
+GenericElogNotificationFunction (
+  IN  EFI_EVENT  Event,
+  IN  VOID       *Context
+  )
+{
+  EFI_STATUS  Status;
+
+  Status = gBS->LocateProtocol (&gEfiGenericElogProtocolGuid, NULL, (VOID **)&mGenericElogProtocol);
+  if (EFI_ERROR (Status)) {
+    mGenericElogProtocol = NULL;
+  }
+}
+
+/**
+  The function will set up a notification on the ELOG protocol.  This function is required to be called prior
+  to utilizing the ELOG protocol from within this library.
+
+  @retval EFI_SUCCESS          after the notification has been setup.
+**/
+EFI_STATUS
+EfiInitializeGenericElog (
+  VOID
+  )
+{
+  EFI_EVENT   Event;
+  EFI_STATUS  Status;
+
+  Status = gBS->CreateEvent (EVT_NOTIFY_SIGNAL, TPL_CALLBACK, GenericElogNotificationFunction, NULL, &Event);
+  ASSERT_EFI_ERROR (Status);
+  if (Status != EFI_SUCCESS) {
+    return Status;
+  }
+
+  Status = gBS->RegisterProtocolNotify (&gEfiGenericElogProtocolGuid, Event, &mGenericElogRegistration);
+  ASSERT_EFI_ERROR (Status);
+  if (Status != EFI_SUCCESS) {
+    return Status;
+  }
+
+  gBS->SignalEvent (Event);
+
+  return EFI_SUCCESS;
+}
+
+/**
+  This function sends event log data to the destination such as LAN, ICMB, BMC etc.
+
+  @param ElogData     is a pointer to the event log data that needs to be recorded
+  @param DataType     type of Elog data that is being recorded.  The Elog is redirected based on this parameter.
+  @param AlertEvent   is an indication that the input data type is an alert.  The underlying
+                      drivers need to decide if they need to listen to the DataType and send it on
+                      an appropriate channel as an alert use of the information.
+  @param DataSize     is the size of the data to be logged
+  @param RecordId     is the array of record IDs sent by the target.  This can be used to retrieve the
+                      records or erase the records.
+  @retval EFI_SUCCESS - if the data was logged.
+  @retval EFI_INVALID_PARAMETER - if the DataType is >= EfiSmElogMax
+  @retval EFI_NOT_FOUND - the event log target was not found
+  @retval EFI_PROTOCOL_ERROR - there was a data formatting error
+
+**/
+EFI_STATUS
+EfiSmSetEventLogData (
+  IN  UINT8             *ElogData,
+  IN  EFI_SM_ELOG_TYPE  DataType,
+  IN  BOOLEAN           AlertEvent,
+  IN  UINTN             DataSize,
+  OUT UINT64            *RecordId
+  )
+{
+  //
+  // If the protocol is not found return EFI_NOT_FOUND
+  //
+  if (mGenericElogProtocol == NULL) {
+    return EFI_NOT_FOUND;
+  }
+
+  return mGenericElogProtocol->SetEventLogData (
+                                 mGenericElogProtocol,
+                                 ElogData,
+                                 DataType,
+                                 AlertEvent,
+                                 DataSize,
+                                 RecordId
+                                 );
+}
+
+/**
+  This function gets event log data from the destination dependent on the DataType.  The destination
+  can be a remote target such as LAN, ICMB, IPMI, or a FV.  The ELOG redir driver will resolve the
+  destination.
+
+  @param ElogData - pointer to the event log data buffer to contain the data to be retrieved.
+  @param DataType - this is the type of Elog data to be gotten.  Elog is redirected based upon this
+                    information.
+  @param DataSize - this is the size of the data to be retrieved.
+  @param RecordId - the RecordId of the next record.  If ElogData is NULL, this gives the RecordId of the first
+                    record available in the database with the correct DataSize.  A value of 0 on return indicates
+                    that it was last record if the Status is EFI_SUCCESS.
+
+  @retval EFI_SUCCESS - if the event log was retrieved successfully.
+  @retval EFI_NOT_FOUND - if the event log target was not found.
+  @retval EFI_NO_RESPONSE - if the event log target is not responding.  This is done by the redir driver.
+  @retval EFI_INVALID_PARAMETER - DataType or another parameter was invalid.
+  @retval EFI_BUFFER_TOO_SMALL -the ElogData buffer is too small to be filled with the requested data.
+
+**/
+EFI_STATUS
+EfiSmGetEventLogData (
+  IN  UINT8             *ElogData,
+  IN  EFI_SM_ELOG_TYPE  DataType,
+  IN  OUT UINTN         *DataSize,
+  IN OUT UINT64         *RecordId
+  )
+{
+  //
+  // If the protocol is not found return EFI_NOT_FOUND
+  //
+  if (mGenericElogProtocol == NULL) {
+    return EFI_NOT_FOUND;
+  }
+
+  return mGenericElogProtocol->GetEventLogData (
+                                 mGenericElogProtocol,
+                                 ElogData,
+                                 DataType,
+                                 DataSize,
+                                 RecordId
+                                 );
+}
+
+/**
+  This function erases the event log data defined by the DataType.  The redir driver associated with
+  the DataType resolves the path to the record.
+
+  @param DataType - the type of Elog data that is to be erased.
+  @param RecordId - the RecordId of the data to be erased.  If RecordId is NULL, all records in the
+                    database are erased if permitted by the target.  RecordId will contain the deleted
+                    RecordId on return.
+
+  @retval EFI_SUCCESS - the record or collection of records were erased.
+  @retval EFI_NOT_FOUND - the event log target was not found.
+  @retval EFI_NO_RESPONSE - the event log target was found but did not respond.
+  @retval EFI_INVALID_PARAMETER - one of the parameters was invalid.
+
+**/
+EFI_STATUS
+EfiSmEraseEventlogData (
+  IN EFI_SM_ELOG_TYPE  DataType,
+  IN OUT UINT64        *RecordId
+  )
+{
+  //
+  // If the protocol is not found return EFI_NOT_FOUND
+  //
+  if (mGenericElogProtocol == NULL) {
+    return EFI_NOT_FOUND;
+  }
+
+  return mGenericElogProtocol->EraseEventlogData (
+                                 mGenericElogProtocol,
+                                 DataType,
+                                 RecordId
+                                 );
+}
+
+/**
+  This function enables or disables the event log defined by the DataType.
+
+
+  @param DataType   - the type of Elog data that is being activated.
+  @param EnableElog - enables or disables the event log defined by the DataType.  If it is NULL
+                      it returns the current status of the DataType log.
+  @param ElogStatus - is the current status of the Event log defined by the DataType.  Enabled is
+                      TRUE and Disabled is FALSE.
+
+  @retval EFI_SUCCESS - if the event log was successfully enabled or disabled.
+  @retval EFI_NOT_FOUND - the event log target was not found.
+  @retval EFI_NO_RESPONSE - the event log target was found but did not respond.
+  @retval EFI_INVALID_PARAMETER - one of the parameters was invalid.
+
+**/
+EFI_STATUS
+EfiSmActivateEventLog (
+  IN EFI_SM_ELOG_TYPE  DataType,
+  IN BOOLEAN           *EnableElog,
+  OUT BOOLEAN          *ElogStatus
+  )
+{
+  //
+  // If the protocol is not found return EFI_NOT_FOUND
+  //
+  if (mGenericElogProtocol == NULL) {
+    return EFI_NOT_FOUND;
+  }
+
+  return mGenericElogProtocol->ActivateEventLog (
+                                 mGenericElogProtocol,
+                                 DataType,
+                                 EnableElog,
+                                 ElogStatus
+                                 );
+}
+
+/**
+  This function verifies the leap year
+
+  @param  Year    year in YYYY format.
+
+  @retval TRUE if the year is a leap year
+
+**/
+STATIC
+BOOLEAN
+IsLeapYear (
+  IN UINT16  Year
+  )
+{
+  if (Year % 4 == 0) {
+    if (Year % 100 == 0) {
+      if (Year % 400 == 0) {
+        return TRUE;
+      } else {
+        return FALSE;
+      }
+    } else {
+      return TRUE;
+    }
+  } else {
+    return FALSE;
+  }
+}
+
+/**
+  This function calculates the total number leap days from 1970 to the current year
+
+  @param  Time    - Current Time
+
+  @retval Returns the number of leap days since the base year, 1970.
+
+**/
+STATIC
+UINTN
+CountNumOfLeapDays (
+  IN EFI_TIME  *Time
+  )
+{
+  UINT16  NumOfYear;
+  UINT16  BaseYear;
+  UINT16  Index;
+  UINTN   Count;
+
+  Count     = 0;
+  BaseYear  = 1970;
+  NumOfYear = Time->Year - 1970;
+
+  for (Index = 0; Index <= NumOfYear; Index++) {
+    if (IsLeapYear (BaseYear + Index)) {
+      Count++;
+    }
+  }
+
+  //
+  // If the current year is a leap year but the month is January or February,
+  // then the leap day has not occurred and should not be counted. If it is
+  // February 29, the leap day is accounted for in CalculateNumOfDayPassedThisYear( )
+  //
+  if (IsLeapYear (Time->Year)) {
+    if ((Count > 0) && (Time->Month < 3)) {
+      Count--;
+    }
+  }
+
+  return Count;
+}
+
+/**
+  This function calculates the total number of days passed till the day in a year.
+  If the year is a leap year, an extra day is not added since the number of leap
+  days is calculated in CountNumOfLeapDays.
+
+  @param  Time    This structure contains detailed information about date and time
+
+  @retval Returns the number of days passed until the input day.
+
+**/
+STATIC
+UINTN
+CalculateNumOfDayPassedThisYear (
+  IN  EFI_TIME  Time
+  )
+{
+  UINTN  Index;
+  UINTN  NumOfDays;
+
+  NumOfDays = 0;
+  for (Index = 1; Index < Time.Month; Index++) {
+    NumOfDays += DaysOfMonth[Index - 1];
+  }
+
+  NumOfDays += Time.Day;
+  return NumOfDays;
+}
+
+/**
+  Function converts a BCD to a decimal value.
+
+  @param[in] BcdValue   An 8 bit BCD value
+
+  @return The decimal value of the BcdValue
+**/
+STATIC
+UINT8
+BcdToDecimal (
+  IN  UINT8  BcdValue
+  )
+{
+  UINTN  High;
+  UINTN  Low;
+
+  High = BcdValue >> 4;
+  Low  = BcdValue - (High << 4);
+
+  return (UINT8)(Low + (High * 10));
+}
+
+//
+// RTC read functions were copied here since we need to get the time
+// in both DXE and runtime code.  The PcRtc driver is not currently a
+// dual mode driver, this is more efficient since making PcRtc dual mode
+// would unnecessarily bloat the SMM code space.
+//
+
+/**
+  Read data register and return contents.
+
+  @param Address - Register address to read
+
+  @retval Value of data register contents
+
+**/
+STATIC
+UINT8
+RtcRead (
+  IN  UINT8  Address
+  )
+{
+  IoWrite8 (PCAT_RTC_ADDRESS_REGISTER, (UINT8)(Address | (UINT8)(IoRead8 (PCAT_RTC_ADDRESS_REGISTER) & 0x80)));
+  return IoRead8 (PCAT_RTC_DATA_REGISTER);
+}
+
+/**
+  Write data to register address.
+
+  @param Address - Register address to write
+  @param Data   - Data to write to register
+
+**/
+STATIC
+VOID
+RtcWrite (
+  IN  UINT8  Address,
+  IN  UINT8  Data
+  )
+{
+  IoWrite8 (PCAT_RTC_ADDRESS_REGISTER, (UINT8)(Address | (UINT8)(IoRead8 (PCAT_RTC_ADDRESS_REGISTER) & 0x80)));
+  IoWrite8 (PCAT_RTC_DATA_REGISTER, Data);
+}
+
+/**
+  Convert Rtc Time To Efi Time.
+
+  @param Time
+  @param RegisterB
+
+**/
+STATIC
+VOID
+ConvertRtcTimeToEfiTime (
+  IN EFI_TIME        *Time,
+  IN RTC_REGISTER_B  RegisterB
+  )
+{
+  BOOLEAN  Pm;
+
+  if ((Time->Hour) & 0x80) {
+    Pm = TRUE;
+  } else {
+    Pm = FALSE;
+  }
+
+  Time->Hour = (UINT8)(Time->Hour & 0x7f);
+
+  if (RegisterB.Bits.DM == 0) {
+    Time->Year   = BcdToDecimal ((UINT8)Time->Year);
+    Time->Month  = BcdToDecimal (Time->Month);
+    Time->Day    = BcdToDecimal (Time->Day);
+    Time->Hour   = BcdToDecimal (Time->Hour);
+    Time->Minute = BcdToDecimal (Time->Minute);
+    Time->Second = BcdToDecimal (Time->Second);
+  }
+
+  //
+  // If time is in 12 hour format, convert it to 24 hour format
+  //
+  if (RegisterB.Bits.MIL == 0) {
+    if (Pm && (Time->Hour < 12)) {
+      Time->Hour = (UINT8)(Time->Hour + 12);
+    }
+
+    if (!Pm && (Time->Hour == 12)) {
+      Time->Hour = 0;
+    }
+  }
+
+  Time->Nanosecond = 0;
+  Time->TimeZone   = EFI_UNSPECIFIED_TIMEZONE;
+  Time->Daylight   = 0;
+}
+
+/**
+  Test Century Register.
+
+  @retval EFI_SUCCESS
+  @retval EFI_DEVICE_ERROR
+
+**/
+STATIC
+EFI_STATUS
+RtcTestCenturyRegister (
+  VOID
+  )
+{
+  UINT8  Century;
+  UINT8  Temp;
+
+  Century = RtcRead (RTC_ADDRESS_CENTURY);
+
+  //
+  // Always sync-up the Bit7 "semaphore"...this maintains
+  // consistency across the different chips/implementations of
+  // the RTC...
+  //
+  RtcWrite (RTC_ADDRESS_CENTURY, 0x00);
+  Temp = (UINT8)(RtcRead (RTC_ADDRESS_CENTURY) & 0x7f);
+  RtcWrite (RTC_ADDRESS_CENTURY, Century);
+  if ((Temp == 0x19) || (Temp == 0x20)) {
+    return EFI_SUCCESS;
+  }
+
+  return EFI_DEVICE_ERROR;
+}
+
+/**
+  Waits until RTC register A and D show data is valid.
+
+  @param Timeout - Maximum time to wait
+
+  @retval EFI_DEVICE_ERROR
+  @retval EFI_SUCCESS
+
+**/
+STATIC
+EFI_STATUS
+RtcWaitToUpdate (
+  UINTN  Timeout
+  )
+{
+  RTC_REGISTER_A  RegisterA;
+  RTC_REGISTER_D  RegisterD;
+
+  //
+  // See if the RTC is functioning correctly
+  //
+  RegisterD.Data = RtcRead (RTC_ADDRESS_REGISTER_D);
+
+  if (RegisterD.Bits.VRT == 0) {
+    return EFI_DEVICE_ERROR;
+  }
+
+  //
+  // Wait for up to 0.1 seconds for the RTC to be ready.
+  //
+  Timeout        = (Timeout / 10) + 1;
+  RegisterA.Data = RtcRead (RTC_ADDRESS_REGISTER_A);
+  while (RegisterA.Bits.UIP == 1 && Timeout > 0) {
+    gBS->Stall (10);
+    RegisterA.Data = RtcRead (RTC_ADDRESS_REGISTER_A);
+    Timeout--;
+  }
+
+  RegisterD.Data = RtcRead (RTC_ADDRESS_REGISTER_D);
+  if ((Timeout == 0) || (RegisterD.Bits.VRT == 0)) {
+    return EFI_DEVICE_ERROR;
+  }
+
+  return EFI_SUCCESS;
+}
+
+/**
+  Get time from RTC.
+
+  @param Time - pointer to time structure
+
+  @retval EFI_INVALID_PARAMETER
+  @retval EFI_SUCCESS
+
+**/
+STATIC
+EFI_STATUS
+RtcGetTime (
+  OUT EFI_TIME  *Time
+  )
+{
+  RTC_REGISTER_B  RegisterB;
+  UINT8           Century;
+  EFI_STATUS      Status;
+
+  //
+  // Check parameters for null pointer
+  //
+  if (Time == NULL) {
+    return EFI_INVALID_PARAMETER;
+  }
+
+  //
+  // Wait for up to 0.1 seconds for the RTC to be updated
+  //
+  Status = RtcWaitToUpdate (100000);
+  if (EFI_ERROR (Status)) {
+    return Status;
+  }
+
+  //
+  // Read Register B
+  //
+  RegisterB.Data = RtcRead (RTC_ADDRESS_REGISTER_B);
+
+  //
+  // Get the Time/Date/Daylight Savings values.
+  //
+  Time->Second = RtcRead (RTC_ADDRESS_SECONDS);
+  Time->Minute = RtcRead (RTC_ADDRESS_MINUTES);
+  Time->Hour   = RtcRead (RTC_ADDRESS_HOURS);
+  Time->Day    = RtcRead (RTC_ADDRESS_DAY_OF_THE_MONTH);
+  Time->Month  = RtcRead (RTC_ADDRESS_MONTH);
+  Time->Year   = RtcRead (RTC_ADDRESS_YEAR);
+
+  ConvertRtcTimeToEfiTime (Time, RegisterB);
+
+  if (RtcTestCenturyRegister () == EFI_SUCCESS) {
+    Century = BcdToDecimal ((UINT8)(RtcRead (RTC_ADDRESS_CENTURY) & 0x7f));
+  } else {
+    Century = BcdToDecimal (RtcRead (RTC_ADDRESS_CENTURY));
+  }
+
+  Time->Year = (UINT16)(Century * 100 + Time->Year);
+
+  return EFI_SUCCESS;
+}
+
+/**
+  Return Date and Time from RTC in Unix format which fits in 32 bit format.
+
+  @param NumOfSeconds - pointer to return calculated time
+
+  @retval EFI_SUCCESS
+  @retval EFI status if error occurred
+
+**/
+EFI_STATUS
+EfiSmGetTimeStamp (
+  OUT UINT32  *NumOfSeconds
+  )
+{
+  UINT16      NumOfYears;
+  UINTN       NumOfLeapDays;
+  UINTN       NumOfDays;
+  EFI_TIME    Time;
+  EFI_STATUS  Status;
+
+  Status = RtcGetTime (&Time);
+  if (EFI_ERROR (Status)) {
+    return Status;
+  }
+
+  NumOfYears    = Time.Year - 1970;
+  NumOfLeapDays = CountNumOfLeapDays (&Time);
+  NumOfDays     = CalculateNumOfDayPassedThisYear (Time);
+
+  //
+  // Add 365 days for all years. Add additional days for Leap Years. Subtract off current day.
+  //
+  NumOfDays += (NumOfLeapDays + (365 * NumOfYears) - 1);
+
+  *NumOfSeconds = (UINT32)(3600 * 24 * NumOfDays + (Time.Hour * 3600) + (60 * Time.Minute) + Time.Second);
+
+  return EFI_SUCCESS;
+}
diff --git a/Features/Intel/OutOfBandManagement/IpmiFeaturePkg/Library/ServerManagementLibNull/ServerManagementLibNull.c b/Features/Intel/OutOfBandManagement/IpmiFeaturePkg/Library/ServerManagementLibNull/ServerManagementLibNull.c
new file mode 100644
index 000000000000..7dd27f34878e
--- /dev/null
+++ b/Features/Intel/OutOfBandManagement/IpmiFeaturePkg/Library/ServerManagementLibNull/ServerManagementLibNull.c
@@ -0,0 +1,144 @@
+/** @file
+  Lightweight lib to support EFI Server Management drivers.
+
+Copyright (c) 2023, Intel Corporation. All rights reserved.<BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include <PiDxe.h>
+#include <Library/DebugLib.h>
+#include <Library/ServerMgmtRtLib.h>
+
+/**
+  The function will set up a notification on the ELOG protocol.  This function is required to be called prior
+  to utilizing the ELOG protocol from within this library.
+
+  @retval EFI_SUCCESS          after the notification has been setup.
+**/
+EFI_STATUS
+EfiInitializeGenericElog (
+  VOID
+  )
+{
+  return EFI_UNSUPPORTED;
+}
+
+/**
+  This function sends event log data to the destination such as LAN, ICMB, BMC etc.
+
+  @param ElogData     is a pointer to the event log data that needs to be recorded
+  @param DataType     type of Elog data that is being recorded.  The Elog is redirected based on this parameter.
+  @param AlertEvent   is an indication that the input data type is an alert.  The underlying
+                      drivers need to decide if they need to listen to the DataType and send it on
+                      an appropriate channel as an alert use of the information.
+  @param DataSize     is the size of the data to be logged
+  @param RecordId     is the array of record IDs sent by the target.  This can be used to retrieve the
+                      records or erase the records.
+  @retval EFI_NOT_FOUND - the event log target was not found
+
+**/
+EFI_STATUS
+EfiSmSetEventLogData (
+  IN  UINT8             *ElogData,
+  IN  EFI_SM_ELOG_TYPE  DataType,
+  IN  BOOLEAN           AlertEvent,
+  IN  UINTN             DataSize,
+  OUT UINT64            *RecordId
+  )
+{
+  return EFI_NOT_FOUND;
+}
+
+/**
+  This function gets event log data from the destination dependent on the DataType.  The destination
+  can be a remote target such as LAN, ICMB, IPMI, or a FV.  The ELOG redir driver will resolve the
+  destination.
+
+  @param ElogData - pointer to the event log data buffer to contain the data to be retrieved.
+  @param DataType - this is the type of Elog data to be gotten.  Elog is redirected based upon this
+                    information.
+  @param DataSize - this is the size of the data to be retrieved.
+  @param RecordId - the RecordId of the next record.  If ElogData is NULL, this gives the RecordId of the first
+                    record available in the database with the correct DataSize.  A value of 0 on return indicates
+                    that it was last record if the Status is EFI_SUCCESS.
+
+  @retval EFI_NOT_FOUND - if the event log target was not found.
+
+**/
+EFI_STATUS
+EfiSmGetEventLogData (
+  IN  UINT8             *ElogData,
+  IN  EFI_SM_ELOG_TYPE  DataType,
+  IN  OUT UINTN         *DataSize,
+  IN OUT UINT64         *RecordId
+  )
+{
+  return EFI_NOT_FOUND;
+}
+
+/**
+  This function erases the event log data defined by the DataType.  The redir driver associated with
+  the DataType resolves the path to the record.
+
+  @param DataType - the type of Elog data that is to be erased.
+  @param RecordId - the RecordId of the data to be erased.  If RecordId is NULL, all records in the
+                    database are erased if permitted by the target.  RecordId will contain the deleted
+                    RecordId on return.
+
+  @retval EFI_SUCCESS - the record or collection of records were erased.
+  @retval EFI_NOT_FOUND - the event log target was not found.
+  @retval EFI_NO_RESPONSE - the event log target was found but did not respond.
+  @retval EFI_INVALID_PARAMETER - one of the parameters was invalid.
+
+**/
+EFI_STATUS
+EfiSmEraseEventlogData (
+  IN EFI_SM_ELOG_TYPE  DataType,
+  IN OUT UINT64        *RecordId
+  )
+{
+  return EFI_NOT_FOUND;
+}
+
+/**
+  This function enables or disables the event log defined by the DataType.
+
+
+  @param DataType   - the type of Elog data that is being activated.
+  @param EnableElog - enables or disables the event log defined by the DataType.  If it is NULL
+                      it returns the current status of the DataType log.
+  @param ElogStatus - is the current status of the Event log defined by the DataType.  Enabled is
+                      TRUE and Disabled is FALSE.
+
+  @retval EFI_NOT_FOUND - the event log target was not found.
+
+**/
+EFI_STATUS
+EfiSmActivateEventLog (
+  IN EFI_SM_ELOG_TYPE  DataType,
+  IN BOOLEAN           *EnableElog,
+  OUT BOOLEAN          *ElogStatus
+  )
+{
+  return EFI_NOT_FOUND;
+}
+
+/**
+  Return Date and Time from RTC in Unix format which fits in 32 bit format.
+
+  @param NumOfSeconds - pointer to return calculated time
+
+  @retval EFI_SUCCESS
+  @retval EFI status if error occurred
+
+**/
+EFI_STATUS
+EfiSmGetTimeStamp (
+  OUT UINT32  *NumOfSeconds
+  )
+{
+  *NumOfSeconds = 0;
+
+  return EFI_NOT_FOUND;
+}
-- 
2.39.2.windows.1



-=-=-=-=-=-=-=-=-=-=-=-
Groups.io Links: You receive all messages sent to this group.
View/Reply Online (#110230): https://edk2.groups.io/g/devel/message/110230
Mute This Topic: https://groups.io/mt/102231767/7686176
Group Owner: devel+owner@edk2.groups.io
Unsubscribe: https://edk2.groups.io/g/devel/unsub [rebecca@openfw.io]
-=-=-=-=-=-=-=-=-=-=-=-



^ permalink raw reply related	[flat|nested] 7+ messages in thread

* [edk2-devel] [PATCH edk2-platforms 3/4] IpmiFeaturePkg: Add ACPI power state drivers
  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 ` Zhen Gong
  2023-10-27 20:11 ` [edk2-devel] [PATCH edk2-platforms 4/4] IpmiFeaturePkg: Add FRU drivers Zhen Gong
  2023-10-29  1:58 ` [edk2-devel] [PATCH edk2-platforms 0/4] IpmiFeaturePkg: Add server management features Chang, Abner via groups.io
  4 siblings, 0 replies; 7+ messages in thread
From: Zhen Gong @ 2023-10-27 20:11 UTC (permalink / raw)
  To: devel; +Cc: Zhen Gong

Add DXE and SMM drivers that send "Set ACPI Power State" command to BMC.

Signed-off-by: Zhen Gong <zhen.gong@intel.com>
---
 .../IpmiFeaturePkg/IpmiFeaturePkg.dec         |   1 +
 .../IpmiFeaturePkg/Include/IpmiFeature.dsc    |   2 +
 .../IpmiFeaturePkg/Include/PostMemory.fdf     |   2 +
 .../BmcAcpiState/BmcAcpiState.inf             |  40 ++++
 .../BmcAcpiSwChild/BmcAcpiSwChild.inf         |  39 ++++
 .../BmcAcpiState/BmcAcpiState.h               |  26 +++
 .../BmcAcpiSwChild/BmcAcpiSwChild.h           |  82 ++++++++
 .../Include/Protocol/BmcAcpiSwChildPolicy.h   |  31 +++
 .../BmcAcpiState/BmcAcpiState.c               |  93 +++++++++
 .../BmcAcpiSwChild/BmcAcpiSwChild.c           | 189 ++++++++++++++++++
 10 files changed, 505 insertions(+)
 create mode 100644 Features/Intel/OutOfBandManagement/IpmiFeaturePkg/BmcAcpiState/BmcAcpiState.inf
 create mode 100644 Features/Intel/OutOfBandManagement/IpmiFeaturePkg/BmcAcpiSwChild/BmcAcpiSwChild.inf
 create mode 100644 Features/Intel/OutOfBandManagement/IpmiFeaturePkg/BmcAcpiState/BmcAcpiState.h
 create mode 100644 Features/Intel/OutOfBandManagement/IpmiFeaturePkg/BmcAcpiSwChild/BmcAcpiSwChild.h
 create mode 100644 Features/Intel/OutOfBandManagement/IpmiFeaturePkg/Include/Protocol/BmcAcpiSwChildPolicy.h
 create mode 100644 Features/Intel/OutOfBandManagement/IpmiFeaturePkg/BmcAcpiState/BmcAcpiState.c
 create mode 100644 Features/Intel/OutOfBandManagement/IpmiFeaturePkg/BmcAcpiSwChild/BmcAcpiSwChild.c

diff --git a/Features/Intel/OutOfBandManagement/IpmiFeaturePkg/IpmiFeaturePkg.dec b/Features/Intel/OutOfBandManagement/IpmiFeaturePkg/IpmiFeaturePkg.dec
index 22bc4e69be8a..be0a11e2adb1 100644
--- a/Features/Intel/OutOfBandManagement/IpmiFeaturePkg/IpmiFeaturePkg.dec
+++ b/Features/Intel/OutOfBandManagement/IpmiFeaturePkg/IpmiFeaturePkg.dec
@@ -75,6 +75,7 @@ [Protocols]
   gEfiVideoPrintProtocolGuid     = {0x3dbf3e06, 0x9d0c, 0x40d3, {0xb2, 0x17, 0x45, 0x5f, 0x33, 0x9e, 0x29, 0x09}}
   gIpmiTransport2ProtocolGuid = { 0x4A1D0E66, 0x5271, 0x4E22, { 0x83, 0xFE, 0x90, 0x92, 0x1B, 0x74, 0x82, 0x13 }}
   gSmmIpmiTransport2ProtocolGuid = { 0x1DBD1503, 0x0A60, 0x4230, { 0xAA, 0xA3, 0x80, 0x16, 0xD8, 0xC3, 0xDE, 0x2F }}
+  gEfiBmcAcpiSwChildPolicyProtocolGuid = { 0x89843c0b, 0x5701, 0x4ff6, { 0xa4, 0x73, 0x65, 0x75, 0x99, 0x04, 0xf7, 0x35 } }
   gEfiGenericElogProtocolGuid = { 0x59d02fcd, 0x9233, 0x4d34, { 0xbc, 0xfe, 0x87, 0xca, 0x81, 0xd3, 0xdd, 0xa7 } }
   gSmmGenericElogProtocolGuid = { 0x664ef1f6, 0x19bf, 0x4498, { 0xab, 0x6a, 0xfc, 0x05, 0x72, 0xfb, 0x98, 0x51 } }
   gEfiRedirElogProtocolGuid = { 0x16d11030, 0x71ba, 0x4e5e, { 0xa9, 0xf9, 0xb4, 0x75, 0xa5, 0x49, 0x4, 0x8a } }
diff --git a/Features/Intel/OutOfBandManagement/IpmiFeaturePkg/Include/IpmiFeature.dsc b/Features/Intel/OutOfBandManagement/IpmiFeaturePkg/Include/IpmiFeature.dsc
index fc9001e98473..7e663236d9a1 100644
--- a/Features/Intel/OutOfBandManagement/IpmiFeaturePkg/Include/IpmiFeature.dsc
+++ b/Features/Intel/OutOfBandManagement/IpmiFeaturePkg/Include/IpmiFeature.dsc
@@ -122,6 +122,8 @@ [Components.X64]
   IpmiFeaturePkg/GenericIpmi/Dxe/GenericIpmi.inf
   IpmiFeaturePkg/Library/SmmIpmiBaseLib/SmmIpmiBaseLib.inf
   IpmiFeaturePkg/BmcAcpi/BmcAcpi.inf
+  IpmiFeaturePkg/BmcAcpiState/BmcAcpiState.inf
+  IpmiFeaturePkg/BmcAcpiSwChild/BmcAcpiSwChild.inf
   IpmiFeaturePkg/BmcElog/DxeBmcElog.inf
   IpmiFeaturePkg/BmcElog/SmmBmcElog.inf
   IpmiFeaturePkg/GenericElog/Dxe/GenericElog.inf
diff --git a/Features/Intel/OutOfBandManagement/IpmiFeaturePkg/Include/PostMemory.fdf b/Features/Intel/OutOfBandManagement/IpmiFeaturePkg/Include/PostMemory.fdf
index f29810bc0b34..9b692f07dcd8 100644
--- a/Features/Intel/OutOfBandManagement/IpmiFeaturePkg/Include/PostMemory.fdf
+++ b/Features/Intel/OutOfBandManagement/IpmiFeaturePkg/Include/PostMemory.fdf
@@ -10,6 +10,8 @@
 INF IpmiFeaturePkg/GenericIpmi/Dxe/GenericIpmi.inf
 INF IpmiFeaturePkg/IpmiInit/DxeIpmiInit.inf
 INF RuleOverride = DRIVER_ACPITABLE IpmiFeaturePkg/BmcAcpi/BmcAcpi.inf
+INF IpmiFeaturePkg/BmcAcpiState/BmcAcpiState.inf
+INF IpmiFeaturePkg/BmcAcpiSwChild/BmcAcpiSwChild.inf
 INF IpmiFeaturePkg/BmcElog/DxeBmcElog.inf
 INF IpmiFeaturePkg/BmcElog/SmmBmcElog.inf
 INF IpmiFeaturePkg/Frb/FrbDxe.inf
diff --git a/Features/Intel/OutOfBandManagement/IpmiFeaturePkg/BmcAcpiState/BmcAcpiState.inf b/Features/Intel/OutOfBandManagement/IpmiFeaturePkg/BmcAcpiState/BmcAcpiState.inf
new file mode 100644
index 000000000000..f1b750d6a20a
--- /dev/null
+++ b/Features/Intel/OutOfBandManagement/IpmiFeaturePkg/BmcAcpiState/BmcAcpiState.inf
@@ -0,0 +1,40 @@
+### @file
+#
+# Copyright (c) 2023, Intel Corporation. All rights reserved.<BR>
+#
+# SPDX-License-Identifier: BSD-2-Clause-Patent
+#
+###
+
+
+[Defines]
+  INF_VERSION                    = 0x00010005
+  BASE_NAME                      = BmcAcpiState
+  FILE_GUID                      = 04103e59-48cc-417a-baec-9929c69c20f6
+  MODULE_TYPE                    = DXE_DRIVER
+  VERSION_STRING                 = 1.0
+  ENTRY_POINT                    = BmcAcpiStateEntryPoint
+
+[Sources]
+  BmcAcpiState.c
+  BmcAcpiState.h
+
+[Packages]
+  IpmiFeaturePkg/IpmiFeaturePkg.dec
+  MdePkg/MdePkg.dec
+  MdeModulePkg/MdeModulePkg.dec
+
+[LibraryClasses]
+  DebugLib
+  UefiDriverEntryPoint
+  UefiBootServicesTableLib
+  IpmiBaseLib
+
+[Protocols]
+  gIpmiTransportProtocolGuid
+
+[Guids]
+  gEfiEventExitBootServicesGuid                 ## CONSUMES ## Event
+
+[Depex]
+  gIpmiTransportProtocolGuid
diff --git a/Features/Intel/OutOfBandManagement/IpmiFeaturePkg/BmcAcpiSwChild/BmcAcpiSwChild.inf b/Features/Intel/OutOfBandManagement/IpmiFeaturePkg/BmcAcpiSwChild/BmcAcpiSwChild.inf
new file mode 100644
index 000000000000..59a9f77d9f10
--- /dev/null
+++ b/Features/Intel/OutOfBandManagement/IpmiFeaturePkg/BmcAcpiSwChild/BmcAcpiSwChild.inf
@@ -0,0 +1,39 @@
+### @file
+#
+# Copyright (c) 2023, Intel Corporation. All rights reserved.<BR>
+#
+# SPDX-License-Identifier: BSD-2-Clause-Patent
+#
+###
+
+
+[Defines]
+  INF_VERSION              = 0x00010005
+  BASE_NAME                = BmcAcpiSwChild
+  FILE_GUID                = BB5BEBD1-CE71-4cd0-9E2F-C07886502661
+  MODULE_TYPE              = DXE_SMM_DRIVER
+  PI_SPECIFICATION_VERSION = 0x0001000A
+  VERSION_STRING           = 1.0
+  ENTRY_POINT              = InitializeBmcAcpiSwChild
+
+[Sources]
+  BmcAcpiSwChild.c
+  BmcAcpiSwChild.h
+
+[Packages]
+  IpmiFeaturePkg/IpmiFeaturePkg.dec
+  MdePkg/MdePkg.dec
+  MdeModulePkg/MdeModulePkg.dec
+
+[LibraryClasses]
+  UefiDriverEntryPoint
+  DebugLib
+  SmmServicesTableLib
+  ServerManagementLib
+  IpmiBaseLib
+
+[Protocols]
+  gEfiBmcAcpiSwChildPolicyProtocolGuid   # PROTOCOL ALWAYS_PRODUCED
+
+[Depex]
+  gSmmIpmiTransportProtocolGuid
diff --git a/Features/Intel/OutOfBandManagement/IpmiFeaturePkg/BmcAcpiState/BmcAcpiState.h b/Features/Intel/OutOfBandManagement/IpmiFeaturePkg/BmcAcpiState/BmcAcpiState.h
new file mode 100644
index 000000000000..4352652a2bda
--- /dev/null
+++ b/Features/Intel/OutOfBandManagement/IpmiFeaturePkg/BmcAcpiState/BmcAcpiState.h
@@ -0,0 +1,26 @@
+/** @file
+
+Copyright (c) 2023, Intel Corporation. All rights reserved.<BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#ifndef _ACPI_BMC_STATE_H_
+#define _ACPI_BMC_STATE_H_
+
+//
+// Statements that include other header files
+//
+#include <Library/UefiDriverEntryPoint.h>
+#include <Library/UefiBootServicesTableLib.h>
+#include <Library/DebugLib.h>
+#include <Guid/EventGroup.h>
+#include <Protocol/IpmiTransportProtocol.h>
+#include <Include/IpmiNetFnAppDefinitions.h>
+#include <IndustryStandard/Ipmi.h>
+#include <Library/IpmiBaseLib.h>
+#include <Protocol/IpmiProtocol.h>
+
+EFI_EVENT  mExitBootServicesEvent = NULL;
+
+#endif
diff --git a/Features/Intel/OutOfBandManagement/IpmiFeaturePkg/BmcAcpiSwChild/BmcAcpiSwChild.h b/Features/Intel/OutOfBandManagement/IpmiFeaturePkg/BmcAcpiSwChild/BmcAcpiSwChild.h
new file mode 100644
index 000000000000..10d687ed2b84
--- /dev/null
+++ b/Features/Intel/OutOfBandManagement/IpmiFeaturePkg/BmcAcpiSwChild/BmcAcpiSwChild.h
@@ -0,0 +1,82 @@
+/** @file
+  This driver produces the ACPI enable and disable SMI handlers.
+
+Copyright (c) 2023, Intel Corporation. All rights reserved.<BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#ifndef _BMC_ACPI_SW_CHILD_H_
+#define _BMC_ACPI_SW_CHILD_H_
+
+//
+// Statements that include other files
+//
+#include <Uefi.h>
+#include <Library/BaseLib.h>
+#include <Library/SmmLib.h>
+#include <Library/DebugLib.h>
+#include <Library/BaseMemoryLib.h>
+#include <Library/SmmServicesTableLib.h>
+#include <Library/MemoryAllocationLib.h>
+
+#include "ServerManagement.h"
+
+#include <Library/ServerMgmtRtLib.h>
+#include <Protocol/IpmiTransportProtocol.h>
+#include <Protocol/BmcAcpiSwChildPolicy.h>
+#include <IndustryStandard/Ipmi.h>
+#include <Library/IpmiBaseLib.h>
+
+//
+// Module prototypes
+//
+
+/**
+  This is the standard EFI driver entrypoint. This function initializes
+  the BMC ACPI SW Child protocol.
+
+  @param ImageHandle - ImageHandle of the loaded driver
+  @param SystemTable - Pointer to the System Table
+
+  @retval EFI_SUCCESS - If all services discovered.
+  @retval Other       - Failure in constructor.
+
+**/
+EFI_STATUS
+EFIAPI
+InitializeBmcAcpiSwChild (
+  IN EFI_HANDLE        ImageHandle,
+  IN EFI_SYSTEM_TABLE  *SystemTable
+  );
+
+/**
+  Send the time to the BMC, in the UNIX 32 bit format.
+
+  @retval Status          - result of sending the time stamp
+
+**/
+EFI_STATUS
+SyncTimeStamp (
+  VOID
+  );
+
+/**
+  Send a command to BMC to set the present power state.
+
+  @param This
+  @param PowerState
+  @param DeviceState
+
+  @retval EFI_SUCCESS               if successful
+  @retval Other than EFI_SUCCESS    if not successful
+
+**/
+EFI_STATUS
+SetACPIPowerStateInBMC (
+  IN EFI_BMC_ACPI_SW_CHILD_POLICY_PROTOCOL  *This,
+  IN UINT8                                  PowerState,
+  IN UINT8                                  DeviceState
+  );
+
+#endif
diff --git a/Features/Intel/OutOfBandManagement/IpmiFeaturePkg/Include/Protocol/BmcAcpiSwChildPolicy.h b/Features/Intel/OutOfBandManagement/IpmiFeaturePkg/Include/Protocol/BmcAcpiSwChildPolicy.h
new file mode 100644
index 000000000000..7958f8c63899
--- /dev/null
+++ b/Features/Intel/OutOfBandManagement/IpmiFeaturePkg/Include/Protocol/BmcAcpiSwChildPolicy.h
@@ -0,0 +1,31 @@
+/** @file
+  This protocol produces BmcAcpiSwChildPolicy Protocol.
+
+Copyright (c) 2023, Intel Corporation. All rights reserved.<BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#ifndef _BMC_ACPI_SW_CHILD_POLICY_H_
+#define _BMC_ACPI_SW_CHILD_POLICY_H_
+
+typedef struct _EFI_BMC_ACPI_SW_CHILD_POLICY_PROTOCOL EFI_BMC_ACPI_SW_CHILD_POLICY_PROTOCOL;
+
+#define EFI_BMC_ACPI_SW_CHILD_POLICY_PROTOCOL_GUID \
+  { 0x89843c0b, 0x5701, 0x4ff6, 0xa4, 0x73, 0x65, 0x75, 0x99, 0x04, 0xf7, 0x35 }
+
+typedef
+EFI_STATUS
+(EFIAPI *EFI_SET_ACPI_POWER_STATE_IN_BMC)(
+  IN EFI_BMC_ACPI_SW_CHILD_POLICY_PROTOCOL   *This,
+  IN UINT8                                   PowerState,
+  IN UINT8                                   DeviceState
+  );
+
+struct _EFI_BMC_ACPI_SW_CHILD_POLICY_PROTOCOL {
+  EFI_SET_ACPI_POWER_STATE_IN_BMC    SetACPIPowerStateInBMC;
+};
+
+extern EFI_GUID  gEfiBmcAcpiSwChildPolicyProtocolGuid;
+
+#endif
diff --git a/Features/Intel/OutOfBandManagement/IpmiFeaturePkg/BmcAcpiState/BmcAcpiState.c b/Features/Intel/OutOfBandManagement/IpmiFeaturePkg/BmcAcpiState/BmcAcpiState.c
new file mode 100644
index 000000000000..04fe2d80307e
--- /dev/null
+++ b/Features/Intel/OutOfBandManagement/IpmiFeaturePkg/BmcAcpiState/BmcAcpiState.c
@@ -0,0 +1,93 @@
+/** @file
+
+Copyright (c) 2023, Intel Corporation. All rights reserved.<BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include <BmcAcpiState.h>
+
+/**
+  Notification function of Exit Boot Services event group.
+
+  Send a command to BMC to set power state to S0.
+
+  @param  Event         Event whose notification function is being invoked.
+  @param  Context        Pointer to the notification function's context.
+
+**/
+VOID
+EFIAPI
+BmcAcpiPowerStateS0Notify (
+  EFI_EVENT  Event,
+  VOID       *Context
+  )
+{
+  EFI_STATUS                         Status = EFI_SUCCESS;
+  IPMI_SET_ACPI_POWER_STATE_REQUEST  AcpiPowerStateRequest;
+  UINT8                              AcpiPowerStateResponse;
+  UINT32                             ResponseDataSize = 0;
+
+  AcpiPowerStateRequest.SystemPowerState.Bits.PowerState  = IPMI_SYSTEM_POWER_STATE_S0_G0;   // System Power State  S0
+  AcpiPowerStateRequest.SystemPowerState.Bits.StateChange = 1;
+  AcpiPowerStateRequest.DevicePowerState.Bits.PowerState  = IPMI_DEVICE_POWER_STATE_D0;   // Device State State  S0
+  AcpiPowerStateRequest.DevicePowerState.Bits.StateChange = 1;
+
+  ResponseDataSize = sizeof (AcpiPowerStateResponse);
+
+  //
+  // Send a command to BMC to set power state to S0.
+  //
+  Status = IpmiSubmitCommand (
+             IPMI_NETFN_APP,
+             IPMI_APP_SET_ACPI_POWERSTATE,
+             (UINT8 *)&AcpiPowerStateRequest,
+             sizeof (IPMI_SET_ACPI_POWER_STATE_REQUEST),
+             (UINT8 *)&AcpiPowerStateResponse,
+             &ResponseDataSize
+             );
+
+  if (EFI_ERROR (Status)) {
+    DEBUG ((DEBUG_ERROR, "IpmiSubmitCommand App Set Acpi Power State Failed %r\n", Status));
+  }
+}
+
+/**
+
+  Entry point for the Bmc Acpi State Dxe driver.
+  Use this function to replace previous ACPI Enable SMM handler to set BMC ACPI power state.
+
+  @param ImageHandle  -  Image Handle.
+  @param SystemTable  -  EFI System Table.
+
+  @retval EFI_SUCCESS  -  Function has completed successfully.
+
+**/
+EFI_STATUS
+EFIAPI
+BmcAcpiStateEntryPoint (
+  IN EFI_HANDLE        ImageHandle,
+  IN EFI_SYSTEM_TABLE  *SystemTable
+  )
+{
+  EFI_STATUS  Status;
+
+  //
+  // Create an Exit Boot Service to Send a command to BMC to set the present power state
+  //
+  Status = gBS->CreateEventEx (
+                  EVT_NOTIFY_SIGNAL,
+                  TPL_NOTIFY,
+                  BmcAcpiPowerStateS0Notify,
+                  NULL,
+                  &gEfiEventExitBootServicesGuid,
+                  &mExitBootServicesEvent
+                  );
+  if (EFI_ERROR (Status)) {
+    DEBUG ((DEBUG_ERROR, "Create Exit Boot Services Event Failed\n"));
+  } else {
+    return EFI_SUCCESS;
+  }
+
+  return EFI_UNSUPPORTED;
+}
diff --git a/Features/Intel/OutOfBandManagement/IpmiFeaturePkg/BmcAcpiSwChild/BmcAcpiSwChild.c b/Features/Intel/OutOfBandManagement/IpmiFeaturePkg/BmcAcpiSwChild/BmcAcpiSwChild.c
new file mode 100644
index 000000000000..ba134db8d50d
--- /dev/null
+++ b/Features/Intel/OutOfBandManagement/IpmiFeaturePkg/BmcAcpiSwChild/BmcAcpiSwChild.c
@@ -0,0 +1,189 @@
+/** @file
+  This driver publishes a protocol that is used by the ACPI SMM Platform
+  driver to notify the BMC of Power State transitions.
+
+Copyright (c) 2023, Intel Corporation. All rights reserved.<BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include "BmcAcpiSwChild.h"
+
+//
+// Global variables
+//
+EFI_BMC_ACPI_SW_CHILD_POLICY_PROTOCOL  mBmcAcpiSwChild;
+
+/**
+  This is the standard EFI driver entrypoint. This function initializes
+  the BMC ACPI SW Child protocol.
+
+  @param ImageHandle - ImageHandle of the loaded driver
+  @param SystemTable - Pointer to the System Table
+
+  @retval EFI_SUCCESS - If all services discovered.
+  @retval Other       - Failure in constructor.
+
+**/
+EFI_STATUS
+EFIAPI
+InitializeBmcAcpiSwChild (
+  IN EFI_HANDLE        ImageHandle,
+  IN EFI_SYSTEM_TABLE  *SystemTable
+  )
+{
+  EFI_STATUS  Status;
+  EFI_HANDLE  Handle;
+
+  Status = EFI_SUCCESS;
+
+  mBmcAcpiSwChild.SetACPIPowerStateInBMC = (EFI_SET_ACPI_POWER_STATE_IN_BMC)SetACPIPowerStateInBMC;
+
+  //
+  // Install protocol
+  //
+  Handle = NULL;
+  Status = gSmst->SmmInstallProtocolInterface (
+                    &Handle,
+                    &gEfiBmcAcpiSwChildPolicyProtocolGuid,
+                    EFI_NATIVE_INTERFACE,
+                    &mBmcAcpiSwChild
+                    );
+
+  return Status;
+}
+
+/**
+  Send the time to the BMC, in the UNIX 32 bit format.
+
+  @retval Status          - result of sending the time stamp
+
+**/
+EFI_STATUS
+SyncTimeStamp (
+  VOID
+  )
+{
+  EFI_STATUS                   Status;
+  UINT32                       ResponseDataSize;
+  IPMI_ADD_SEL_ENTRY_REQUEST   TimeStampEvtRecord;
+  IPMI_ADD_SEL_ENTRY_RESPONSE  AddSelEntryResponse;
+  IPMI_SET_SEL_TIME_REQUEST    SelTimeReq;
+  UINT8                        SelTimeResponse;
+
+  TimeStampEvtRecord.RecordData.RecordId     = 0;                                    // Record Id
+  TimeStampEvtRecord.RecordData.RecordType   = IPMI_SEL_SYSTEM_RECORD;               // Record Type
+  TimeStampEvtRecord.RecordData.TimeStamp    = 0;                                    // Time stamp
+  TimeStampEvtRecord.RecordData.GeneratorId  = 0x0003;                               // GenID:BIOS
+  TimeStampEvtRecord.RecordData.EvMRevision  = IPMI_EVM_REVISION;                    // EVM REV
+  TimeStampEvtRecord.RecordData.SensorType   = 0x12;                                 // Sensor Type
+  TimeStampEvtRecord.RecordData.SensorNumber = 0x83;                                 // Sensor No
+  TimeStampEvtRecord.RecordData.EventDirType = IPMI_SENSOR_TYPE_EVENT_CODE_DISCRETE; // Event Dir
+  TimeStampEvtRecord.RecordData.OEMEvData1   = 05;                                   // Sensor specific Offset for Timestamp Clock Synch Event.
+  TimeStampEvtRecord.RecordData.OEMEvData2   = 00;                                   // ED2
+  TimeStampEvtRecord.RecordData.OEMEvData3   = 0xFF;                                 // ED3
+
+  //
+  // Log Timestamp Clock Synch Event 1st pair.
+  //
+  ResponseDataSize = sizeof (AddSelEntryResponse);
+  Status           = IpmiSubmitCommand (
+                       IPMI_NETFN_STORAGE,
+                       IPMI_STORAGE_ADD_SEL_ENTRY,
+                       (UINT8 *)&TimeStampEvtRecord,
+                       sizeof (TimeStampEvtRecord),
+                       (UINT8 *)&AddSelEntryResponse,
+                       &ResponseDataSize
+                       );
+
+  if (EFI_ERROR (Status)) {
+    DEBUG ((DEBUG_ERROR, "IpmiSubmitCommand Storage Add SEL Entry Failed %r\n", Status));
+    return Status;
+  }
+
+  Status = EfiSmGetTimeStamp (&SelTimeReq.Timestamp);
+  if (EFI_ERROR (Status)) {
+    return Status;
+  }
+
+  ResponseDataSize = sizeof (SelTimeResponse);
+  Status           = IpmiSubmitCommand (
+                       IPMI_NETFN_STORAGE,
+                       IPMI_STORAGE_SET_SEL_TIME,
+                       (UINT8 *)&SelTimeReq,
+                       sizeof (SelTimeReq),
+                       (UINT8 *)&SelTimeResponse,
+                       &ResponseDataSize
+                       );
+
+  if (EFI_ERROR (Status)) {
+    DEBUG ((DEBUG_ERROR, "IpmiSubmitCommand Storage Set SEL Time Failed %r\n", Status));
+    return Status;
+  }
+
+  //
+  // Log Timestamp Clock Sync Event 2nd pair.
+  //
+  TimeStampEvtRecord.RecordData.OEMEvData2 = 0x80;
+  ResponseDataSize                         = sizeof (AddSelEntryResponse);
+  Status                                   = IpmiSubmitCommand (
+                                               IPMI_NETFN_STORAGE,
+                                               IPMI_STORAGE_ADD_SEL_ENTRY,
+                                               (UINT8 *)&TimeStampEvtRecord,
+                                               sizeof (TimeStampEvtRecord),
+                                               (UINT8 *)&AddSelEntryResponse,
+                                               &ResponseDataSize
+                                               );
+  if (EFI_ERROR (Status)) {
+    DEBUG ((DEBUG_ERROR, "IpmiSubmitCommand Storage Add SEL Entry Failed %r\n", Status));
+    return Status;
+  }
+
+  return EFI_SUCCESS;
+}
+
+/**
+  Send a command to BMC to set the present power state.
+
+  @param This
+  @param PowerState
+  @param DeviceState
+
+  @retval EFI_SUCCESS               if successful
+  @retval Other than EFI_SUCCESS    if not successful
+
+**/
+EFI_STATUS
+SetACPIPowerStateInBMC (
+  IN EFI_BMC_ACPI_SW_CHILD_POLICY_PROTOCOL  *This,
+  IN UINT8                                  PowerState,
+  IN UINT8                                  DeviceState
+  )
+{
+  EFI_STATUS                         Status;
+  IPMI_SET_ACPI_POWER_STATE_REQUEST  AcpiPowerStateRequest;
+  UINT8                              AcpiPowerStateResponse;
+  UINT32                             ResponseDataSize;
+
+  AcpiPowerStateRequest.SystemPowerState.Bits.PowerState  = PowerState;
+  AcpiPowerStateRequest.SystemPowerState.Bits.StateChange = 1;
+  AcpiPowerStateRequest.DevicePowerState.Bits.PowerState  = DeviceState;
+  AcpiPowerStateRequest.DevicePowerState.Bits.StateChange = 1;
+
+  ResponseDataSize =  sizeof (AcpiPowerStateResponse);
+
+  Status = IpmiSubmitCommand (
+             IPMI_NETFN_APP,
+             IPMI_APP_SET_ACPI_POWERSTATE,
+             (UINT8 *)&AcpiPowerStateRequest,
+             sizeof (AcpiPowerStateRequest),
+             (UINT8 *)&AcpiPowerStateResponse,
+             &ResponseDataSize
+             );
+
+  if (EFI_ERROR (Status)) {
+    DEBUG ((DEBUG_ERROR, "IpmiSubmitCommand App Set Acpi Power State Failed %r\n", Status));
+  }
+
+  return Status;
+}
-- 
2.39.2.windows.1



-=-=-=-=-=-=-=-=-=-=-=-
Groups.io Links: You receive all messages sent to this group.
View/Reply Online (#110231): https://edk2.groups.io/g/devel/message/110231
Mute This Topic: https://groups.io/mt/102231768/7686176
Group Owner: devel+owner@edk2.groups.io
Unsubscribe: https://edk2.groups.io/g/devel/unsub [rebecca@openfw.io]
-=-=-=-=-=-=-=-=-=-=-=-



^ permalink raw reply related	[flat|nested] 7+ messages in thread

* [edk2-devel] [PATCH edk2-platforms 4/4] IpmiFeaturePkg: Add FRU drivers
  2023-10-27 20:11 [edk2-devel] [PATCH edk2-platforms 0/4] IpmiFeaturePkg: Add server management features Zhen Gong
                   ` (2 preceding siblings ...)
  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
  2023-10-29  1:58 ` [edk2-devel] [PATCH edk2-platforms 0/4] IpmiFeaturePkg: Add server management features Chang, Abner via groups.io
  4 siblings, 0 replies; 7+ messages in thread
From: Zhen Gong @ 2023-10-27 20:11 UTC (permalink / raw)
  To: devel; +Cc: Zhen Gong

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]
-=-=-=-=-=-=-=-=-=-=-=-



^ permalink raw reply related	[flat|nested] 7+ messages in thread

* Re: [edk2-devel] [PATCH edk2-platforms 0/4] IpmiFeaturePkg: Add server management features
  2023-10-27 20:11 [edk2-devel] [PATCH edk2-platforms 0/4] IpmiFeaturePkg: Add server management features Zhen Gong
                   ` (3 preceding siblings ...)
  2023-10-27 20:11 ` [edk2-devel] [PATCH edk2-platforms 4/4] IpmiFeaturePkg: Add FRU drivers Zhen Gong
@ 2023-10-29  1:58 ` Chang, Abner via groups.io
  2023-10-29 21:07   ` Zhen Gong
  4 siblings, 1 reply; 7+ messages in thread
From: Chang, Abner via groups.io @ 2023-10-29  1:58 UTC (permalink / raw)
  To: devel@edk2.groups.io, zhen.gong@intel.com

[AMD Official Use Only - General]

Hi Gong,
Please note that your code may have conflict as IpmiCommandLib was removed (please check  https://edk2.groups.io/g/devel/message/109510), now we are using the one under MdeModulePKg.
Second, I had cleaned up those server management feature drivers and migrated those to under ManageabilityPkg with Issac RB, please check commit ID from b6a5124e to d6f18259. That would be not good if Intel keeps updating IpmiFeaturePkg. As those drivers are higher level applications on top of transport, It shouldn't have a problem to just update the changes against ManageabilityPkg. Is there any issues Intel met if uses IPMI feature drivers from Manageability? If yes, we can address the issue instead of making them diverging.


Thanks
Abner

> -----Original Message-----
> From: devel@edk2.groups.io <devel@edk2.groups.io> On Behalf Of Zhen
> Gong via groups.io
> Sent: Saturday, October 28, 2023 4:11 AM
> To: devel@edk2.groups.io
> Cc: Zhen Gong <zhen.gong@intel.com>
> Subject: [edk2-devel] [PATCH edk2-platforms 0/4] IpmiFeaturePkg: Add
> server management features
>
> Caution: This message originated from an External Source. Use proper caution
> when opening attachments, clicking links, or responding.
>
>
> This patch set adds serveral IPMI features to support server management:
>
> BmcAcpiState: A DXE driver to notify BMC of S0 power state.
> BmcAcpiSwChild: An SMM driver to notify BMC of ACPI power state changes
> and add
>  SEL records.
> BmcElog: PEI, DXE, and SMM drivers to support BMC event log functions.
> GenericElog: DXE and SMM drivers to support generic event log functions.
> GenericFru: A runtime driver to support generic FRU functions.
> IpmiRedirFru: A DXE driver to support BMC FRU functions and generate data
> based
>  on SMBIOS data.
> ServerManagementLib: A library to provide essential functions for server
>  management drivers.
>
>
> Zhen Gong (4):
>   IpmiFeaturePkg: Add Elog drivers
>   IpmiFeaturePkg: Add ServerManagementLib
>   IpmiFeaturePkg: Add ACPI power state drivers
>   IpmiFeaturePkg: Add FRU drivers
>
>  .../IpmiFeaturePkg/IpmiFeaturePkg.dec         |  10 +
>  .../IpmiFeaturePkg/Include/IpmiFeature.dsc    |  13 +-
>  .../IpmiFeaturePkg/Include/PostMemory.fdf     |  10 +-
>  .../IpmiFeaturePkg/Include/PreMemory.fdf      |   1 +
>  .../BmcAcpiState/BmcAcpiState.inf             |  40 +
>  .../BmcAcpiSwChild/BmcAcpiSwChild.inf         |  39 +
>  .../BmcElog/{BmcElog.inf => DxeBmcElog.inf}   |  25 +-
>  .../IpmiFeaturePkg/BmcElog/PeiBmcElog.inf     |  43 ++
>  .../IpmiFeaturePkg/BmcElog/SmmBmcElog.inf     |  44 ++
>  .../GenericElog/Dxe/GenericElog.inf           |  38 +
>  .../GenericElog/Smm/GenericElog.inf           |  38 +
>  .../IpmiFeaturePkg/GenericFru/GenericFru.inf  |  42 ++
>  .../IpmiFeaturePkg/IpmiFru/IpmiFru.inf        |  35 -
>  .../IpmiRedirFru/IpmiRedirFru.inf             |  51 ++
>  .../ServerManagementLib.inf                   |  35 +
>  .../ServerManagementLibNull.inf               |  38 +
>  .../BmcAcpiState/BmcAcpiState.h               |  26 +
>  .../BmcAcpiSwChild/BmcAcpiSwChild.h           |  82 +++
>  .../BmcElog/Common/BmcElogCommon.h            | 144 ++++
>  .../IpmiFeaturePkg/BmcElog/Dxe/BmcElog.h      |  42 ++
>  .../IpmiFeaturePkg/BmcElog/Pei/BmcElog.h      |  44 ++
>  .../IpmiFeaturePkg/BmcElog/Smm/BmcElog.h      |  43 ++
>  .../GenericElog/Dxe/GenericElog.h             | 194 +++++
>  .../GenericElog/Smm/GenericElog.h             | 216 ++++++
>  .../GenericFru/GenericFruDriver.h             | 178 +++++
>  .../Include/Library/ServerMgmtRtLib.h         | 147 ++++
>  .../IpmiFeaturePkg/Include/Ppi/GenericElog.h  |  84 +++
>  .../Include/Protocol/BmcAcpiSwChildPolicy.h   |  31 +
>  .../Include/Protocol/GenericElog.h            |  99 +++
>  .../Include/Protocol/GenericFru.h             | 103 +++
>  .../Include/Protocol/RedirFru.h               |  81 ++
>  .../IpmiRedirFru/IpmiRedirFru.h               | 149 ++++
>  .../BmcAcpiState/BmcAcpiState.c               |  93 +++
>  .../BmcAcpiSwChild/BmcAcpiSwChild.c           | 189 +++++
>  .../IpmiFeaturePkg/BmcElog/BmcElog.c          | 236 ------
>  .../BmcElog/Common/BmcElogCommon.c            | 465 ++++++++++++
>  .../IpmiFeaturePkg/BmcElog/Dxe/BmcElog.c      | 287 ++++++++
>  .../IpmiFeaturePkg/BmcElog/Pei/BmcElog.c      | 297 ++++++++
>  .../IpmiFeaturePkg/BmcElog/Smm/BmcElog.c      | 288 ++++++++
>  .../GenericElog/Dxe/GenericElog.c             | 576 +++++++++++++++
>  .../GenericElog/Smm/GenericElog.c             | 558 ++++++++++++++
>  .../IpmiFeaturePkg/GenericFru/GenericFru.c    |  68 ++
>  .../GenericFru/GenericFruDriver.c             | 513 +++++++++++++
>  .../IpmiFeaturePkg/IpmiFru/IpmiFru.c          |  67 --
>  .../IpmiFeaturePkg/IpmiRedirFru/FruSmbios.c   | 469 ++++++++++++
>  .../IpmiRedirFru/IpmiRedirFru.c               | 479 ++++++++++++
>  .../ServerManagementLib/ServerManagementLib.c | 696
> ++++++++++++++++++
>  .../ServerManagementLibNull.c                 | 144 ++++
>  48 files changed, 7242 insertions(+), 348 deletions(-)
>  create mode 100644
> Features/Intel/OutOfBandManagement/IpmiFeaturePkg/BmcAcpiState/Bmc
> AcpiState.inf
>  create mode 100644
> Features/Intel/OutOfBandManagement/IpmiFeaturePkg/BmcAcpiSwChild/B
> mcAcpiSwChild.inf
>  rename
> Features/Intel/OutOfBandManagement/IpmiFeaturePkg/BmcElog/{BmcElog.i
> nf => DxeBmcElog.inf} (56%)
>  create mode 100644
> Features/Intel/OutOfBandManagement/IpmiFeaturePkg/BmcElog/PeiBmcElo
> g.inf
>  create mode 100644
> Features/Intel/OutOfBandManagement/IpmiFeaturePkg/BmcElog/SmmBmc
> Elog.inf
>  create mode 100644
> Features/Intel/OutOfBandManagement/IpmiFeaturePkg/GenericElog/Dxe/Ge
> nericElog.inf
>  create mode 100644
> Features/Intel/OutOfBandManagement/IpmiFeaturePkg/GenericElog/Smm/
> GenericElog.inf
>  create mode 100644
> Features/Intel/OutOfBandManagement/IpmiFeaturePkg/GenericFru/Generic
> Fru.inf
>  delete mode 100644
> Features/Intel/OutOfBandManagement/IpmiFeaturePkg/IpmiFru/IpmiFru.inf
>  create mode 100644
> Features/Intel/OutOfBandManagement/IpmiFeaturePkg/IpmiRedirFru/IpmiR
> edirFru.inf
>  create mode 100644
> Features/Intel/OutOfBandManagement/IpmiFeaturePkg/Library/ServerMana
> gementLib/ServerManagementLib.inf
>  create mode 100644
> Features/Intel/OutOfBandManagement/IpmiFeaturePkg/Library/ServerMana
> gementLibNull/ServerManagementLibNull.inf
>  create mode 100644
> Features/Intel/OutOfBandManagement/IpmiFeaturePkg/BmcAcpiState/Bmc
> AcpiState.h
>  create mode 100644
> Features/Intel/OutOfBandManagement/IpmiFeaturePkg/BmcAcpiSwChild/B
> mcAcpiSwChild.h
>  create mode 100644
> Features/Intel/OutOfBandManagement/IpmiFeaturePkg/BmcElog/Common/
> BmcElogCommon.h
>  create mode 100644
> Features/Intel/OutOfBandManagement/IpmiFeaturePkg/BmcElog/Dxe/BmcE
> log.h
>  create mode 100644
> Features/Intel/OutOfBandManagement/IpmiFeaturePkg/BmcElog/Pei/BmcEl
> og.h
>  create mode 100644
> Features/Intel/OutOfBandManagement/IpmiFeaturePkg/BmcElog/Smm/Bmc
> Elog.h
>  create mode 100644
> Features/Intel/OutOfBandManagement/IpmiFeaturePkg/GenericElog/Dxe/Ge
> nericElog.h
>  create mode 100644
> Features/Intel/OutOfBandManagement/IpmiFeaturePkg/GenericElog/Smm/
> GenericElog.h
>  create mode 100644
> Features/Intel/OutOfBandManagement/IpmiFeaturePkg/GenericFru/Generic
> FruDriver.h
>  create mode 100644
> Features/Intel/OutOfBandManagement/IpmiFeaturePkg/Include/Library/Ser
> verMgmtRtLib.h
>  create mode 100644
> Features/Intel/OutOfBandManagement/IpmiFeaturePkg/Include/Ppi/Generic
> Elog.h
>  create mode 100644
> Features/Intel/OutOfBandManagement/IpmiFeaturePkg/Include/Protocol/B
> mcAcpiSwChildPolicy.h
>  create mode 100644
> Features/Intel/OutOfBandManagement/IpmiFeaturePkg/Include/Protocol/G
> enericElog.h
>  create mode 100644
> Features/Intel/OutOfBandManagement/IpmiFeaturePkg/Include/Protocol/G
> enericFru.h
>  create mode 100644
> Features/Intel/OutOfBandManagement/IpmiFeaturePkg/Include/Protocol/R
> edirFru.h
>  create mode 100644
> Features/Intel/OutOfBandManagement/IpmiFeaturePkg/IpmiRedirFru/IpmiR
> edirFru.h
>  create mode 100644
> Features/Intel/OutOfBandManagement/IpmiFeaturePkg/BmcAcpiState/Bmc
> AcpiState.c
>  create mode 100644
> Features/Intel/OutOfBandManagement/IpmiFeaturePkg/BmcAcpiSwChild/B
> mcAcpiSwChild.c
>  delete mode 100644
> Features/Intel/OutOfBandManagement/IpmiFeaturePkg/BmcElog/BmcElog.c
>  create mode 100644
> Features/Intel/OutOfBandManagement/IpmiFeaturePkg/BmcElog/Common/
> BmcElogCommon.c
>  create mode 100644
> Features/Intel/OutOfBandManagement/IpmiFeaturePkg/BmcElog/Dxe/BmcE
> log.c
>  create mode 100644
> Features/Intel/OutOfBandManagement/IpmiFeaturePkg/BmcElog/Pei/BmcEl
> og.c
>  create mode 100644
> Features/Intel/OutOfBandManagement/IpmiFeaturePkg/BmcElog/Smm/Bmc
> Elog.c
>  create mode 100644
> Features/Intel/OutOfBandManagement/IpmiFeaturePkg/GenericElog/Dxe/Ge
> nericElog.c
>  create mode 100644
> Features/Intel/OutOfBandManagement/IpmiFeaturePkg/GenericElog/Smm/
> GenericElog.c
>  create mode 100644
> Features/Intel/OutOfBandManagement/IpmiFeaturePkg/GenericFru/Generic
> Fru.c
>  create mode 100644
> Features/Intel/OutOfBandManagement/IpmiFeaturePkg/GenericFru/Generic
> FruDriver.c
>  delete mode 100644
> Features/Intel/OutOfBandManagement/IpmiFeaturePkg/IpmiFru/IpmiFru.c
>  create mode 100644
> Features/Intel/OutOfBandManagement/IpmiFeaturePkg/IpmiRedirFru/FruS
> mbios.c
>  create mode 100644
> Features/Intel/OutOfBandManagement/IpmiFeaturePkg/IpmiRedirFru/IpmiR
> edirFru.c
>  create mode 100644
> Features/Intel/OutOfBandManagement/IpmiFeaturePkg/Library/ServerMana
> gementLib/ServerManagementLib.c
>  create mode 100644
> Features/Intel/OutOfBandManagement/IpmiFeaturePkg/Library/ServerMana
> gementLibNull/ServerManagementLibNull.c
>
> --
> 2.39.2.windows.1
>
>
>
> 
>



-=-=-=-=-=-=-=-=-=-=-=-
Groups.io Links: You receive all messages sent to this group.
View/Reply Online (#110254): https://edk2.groups.io/g/devel/message/110254
Mute This Topic: https://groups.io/mt/102231765/7686176
Group Owner: devel+owner@edk2.groups.io
Unsubscribe: https://edk2.groups.io/g/devel/unsub [rebecca@openfw.io]
-=-=-=-=-=-=-=-=-=-=-=-



^ permalink raw reply	[flat|nested] 7+ messages in thread

* Re: [edk2-devel] [PATCH edk2-platforms 0/4] IpmiFeaturePkg: Add server management features
  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
  0 siblings, 0 replies; 7+ messages in thread
From: Zhen Gong @ 2023-10-29 21:07 UTC (permalink / raw)
  To: devel@edk2.groups.io, Chang, Abner

Hi Abner,

Thanks for the heads-up.
I caught your commit right before submitting the patch. MdeModulePKg is already consumed by all libraries referencing the header.
However there's a merge conflict now and I just sent out a v2 version to address it.

Regarding to the migration to ManageabilityPkg, we have evaluated whether to adopt it directly.
Given the long time frame of silicon development, we are not going to make big changes for current platforms.
And we chose to keep using IpmiFeaturePkg and upstream drivers with minimum changes required for now.

The decision is more about lifecycle management, other than technical standpoint.
Going forward, we will re-evaluate the open and bring it to newer platforms.

Thanks,
Zhen

-----Original Message-----
From: Chang, Abner <Abner.Chang@amd.com> 
Sent: Saturday, October 28, 2023 6:59 PM
To: devel@edk2.groups.io; Gong, Zhen <zhen.gong@intel.com>
Subject: RE: [edk2-devel] [PATCH edk2-platforms 0/4] IpmiFeaturePkg: Add server management features

[AMD Official Use Only - General]

Hi Gong,
Please note that your code may have conflict as IpmiCommandLib was removed (please check  https://edk2.groups.io/g/devel/message/109510), now we are using the one under MdeModulePKg.
Second, I had cleaned up those server management feature drivers and migrated those to under ManageabilityPkg with Issac RB, please check commit ID from b6a5124e to d6f18259. That would be not good if Intel keeps updating IpmiFeaturePkg. As those drivers are higher level applications on top of transport, It shouldn't have a problem to just update the changes against ManageabilityPkg. Is there any issues Intel met if uses IPMI feature drivers from Manageability? If yes, we can address the issue instead of making them diverging.


Thanks
Abner

> -----Original Message-----
> From: devel@edk2.groups.io <devel@edk2.groups.io> On Behalf Of Zhen 
> Gong via groups.io
> Sent: Saturday, October 28, 2023 4:11 AM
> To: devel@edk2.groups.io
> Cc: Zhen Gong <zhen.gong@intel.com>
> Subject: [edk2-devel] [PATCH edk2-platforms 0/4] IpmiFeaturePkg: Add 
> server management features
>
> Caution: This message originated from an External Source. Use proper 
> caution when opening attachments, clicking links, or responding.
>
>
> This patch set adds serveral IPMI features to support server management:
>
> BmcAcpiState: A DXE driver to notify BMC of S0 power state.
> BmcAcpiSwChild: An SMM driver to notify BMC of ACPI power state 
> changes and add  SEL records.
> BmcElog: PEI, DXE, and SMM drivers to support BMC event log functions.
> GenericElog: DXE and SMM drivers to support generic event log functions.
> GenericFru: A runtime driver to support generic FRU functions.
> IpmiRedirFru: A DXE driver to support BMC FRU functions and generate 
> data based  on SMBIOS data.
> ServerManagementLib: A library to provide essential functions for 
> server  management drivers.
>
>
> Zhen Gong (4):
>   IpmiFeaturePkg: Add Elog drivers
>   IpmiFeaturePkg: Add ServerManagementLib
>   IpmiFeaturePkg: Add ACPI power state drivers
>   IpmiFeaturePkg: Add FRU drivers
>
>  .../IpmiFeaturePkg/IpmiFeaturePkg.dec         |  10 +
>  .../IpmiFeaturePkg/Include/IpmiFeature.dsc    |  13 +-
>  .../IpmiFeaturePkg/Include/PostMemory.fdf     |  10 +-
>  .../IpmiFeaturePkg/Include/PreMemory.fdf      |   1 +
>  .../BmcAcpiState/BmcAcpiState.inf             |  40 +
>  .../BmcAcpiSwChild/BmcAcpiSwChild.inf         |  39 +
>  .../BmcElog/{BmcElog.inf => DxeBmcElog.inf}   |  25 +-
>  .../IpmiFeaturePkg/BmcElog/PeiBmcElog.inf     |  43 ++
>  .../IpmiFeaturePkg/BmcElog/SmmBmcElog.inf     |  44 ++
>  .../GenericElog/Dxe/GenericElog.inf           |  38 +
>  .../GenericElog/Smm/GenericElog.inf           |  38 +
>  .../IpmiFeaturePkg/GenericFru/GenericFru.inf  |  42 ++
>  .../IpmiFeaturePkg/IpmiFru/IpmiFru.inf        |  35 -
>  .../IpmiRedirFru/IpmiRedirFru.inf             |  51 ++
>  .../ServerManagementLib.inf                   |  35 +
>  .../ServerManagementLibNull.inf               |  38 +
>  .../BmcAcpiState/BmcAcpiState.h               |  26 +
>  .../BmcAcpiSwChild/BmcAcpiSwChild.h           |  82 +++
>  .../BmcElog/Common/BmcElogCommon.h            | 144 ++++
>  .../IpmiFeaturePkg/BmcElog/Dxe/BmcElog.h      |  42 ++
>  .../IpmiFeaturePkg/BmcElog/Pei/BmcElog.h      |  44 ++
>  .../IpmiFeaturePkg/BmcElog/Smm/BmcElog.h      |  43 ++
>  .../GenericElog/Dxe/GenericElog.h             | 194 +++++
>  .../GenericElog/Smm/GenericElog.h             | 216 ++++++
>  .../GenericFru/GenericFruDriver.h             | 178 +++++
>  .../Include/Library/ServerMgmtRtLib.h         | 147 ++++
>  .../IpmiFeaturePkg/Include/Ppi/GenericElog.h  |  84 +++
>  .../Include/Protocol/BmcAcpiSwChildPolicy.h   |  31 +
>  .../Include/Protocol/GenericElog.h            |  99 +++
>  .../Include/Protocol/GenericFru.h             | 103 +++
>  .../Include/Protocol/RedirFru.h               |  81 ++
>  .../IpmiRedirFru/IpmiRedirFru.h               | 149 ++++
>  .../BmcAcpiState/BmcAcpiState.c               |  93 +++
>  .../BmcAcpiSwChild/BmcAcpiSwChild.c           | 189 +++++
>  .../IpmiFeaturePkg/BmcElog/BmcElog.c          | 236 ------
>  .../BmcElog/Common/BmcElogCommon.c            | 465 ++++++++++++
>  .../IpmiFeaturePkg/BmcElog/Dxe/BmcElog.c      | 287 ++++++++
>  .../IpmiFeaturePkg/BmcElog/Pei/BmcElog.c      | 297 ++++++++
>  .../IpmiFeaturePkg/BmcElog/Smm/BmcElog.c      | 288 ++++++++
>  .../GenericElog/Dxe/GenericElog.c             | 576 +++++++++++++++
>  .../GenericElog/Smm/GenericElog.c             | 558 ++++++++++++++
>  .../IpmiFeaturePkg/GenericFru/GenericFru.c    |  68 ++
>  .../GenericFru/GenericFruDriver.c             | 513 +++++++++++++
>  .../IpmiFeaturePkg/IpmiFru/IpmiFru.c          |  67 --
>  .../IpmiFeaturePkg/IpmiRedirFru/FruSmbios.c   | 469 ++++++++++++
>  .../IpmiRedirFru/IpmiRedirFru.c               | 479 ++++++++++++
>  .../ServerManagementLib/ServerManagementLib.c | 696
> ++++++++++++++++++
>  .../ServerManagementLibNull.c                 | 144 ++++
>  48 files changed, 7242 insertions(+), 348 deletions(-)  create mode 
> 100644 
> Features/Intel/OutOfBandManagement/IpmiFeaturePkg/BmcAcpiState/Bmc
> AcpiState.inf
>  create mode 100644
> Features/Intel/OutOfBandManagement/IpmiFeaturePkg/BmcAcpiSwChild/B
> mcAcpiSwChild.inf
>  rename
> Features/Intel/OutOfBandManagement/IpmiFeaturePkg/BmcElog/{BmcElog.i
> nf => DxeBmcElog.inf} (56%)
>  create mode 100644
> Features/Intel/OutOfBandManagement/IpmiFeaturePkg/BmcElog/PeiBmcElo
> g.inf
>  create mode 100644
> Features/Intel/OutOfBandManagement/IpmiFeaturePkg/BmcElog/SmmBmc
> Elog.inf
>  create mode 100644
> Features/Intel/OutOfBandManagement/IpmiFeaturePkg/GenericElog/Dxe/Ge
> nericElog.inf
>  create mode 100644
> Features/Intel/OutOfBandManagement/IpmiFeaturePkg/GenericElog/Smm/
> GenericElog.inf
>  create mode 100644
> Features/Intel/OutOfBandManagement/IpmiFeaturePkg/GenericFru/Generic
> Fru.inf
>  delete mode 100644
> Features/Intel/OutOfBandManagement/IpmiFeaturePkg/IpmiFru/IpmiFru.inf
>  create mode 100644
> Features/Intel/OutOfBandManagement/IpmiFeaturePkg/IpmiRedirFru/IpmiR
> edirFru.inf
>  create mode 100644
> Features/Intel/OutOfBandManagement/IpmiFeaturePkg/Library/ServerMana
> gementLib/ServerManagementLib.inf
>  create mode 100644
> Features/Intel/OutOfBandManagement/IpmiFeaturePkg/Library/ServerMana
> gementLibNull/ServerManagementLibNull.inf
>  create mode 100644
> Features/Intel/OutOfBandManagement/IpmiFeaturePkg/BmcAcpiState/Bmc
> AcpiState.h
>  create mode 100644
> Features/Intel/OutOfBandManagement/IpmiFeaturePkg/BmcAcpiSwChild/B
> mcAcpiSwChild.h
>  create mode 100644
> Features/Intel/OutOfBandManagement/IpmiFeaturePkg/BmcElog/Common/
> BmcElogCommon.h
>  create mode 100644
> Features/Intel/OutOfBandManagement/IpmiFeaturePkg/BmcElog/Dxe/BmcE
> log.h
>  create mode 100644
> Features/Intel/OutOfBandManagement/IpmiFeaturePkg/BmcElog/Pei/BmcEl
> og.h
>  create mode 100644
> Features/Intel/OutOfBandManagement/IpmiFeaturePkg/BmcElog/Smm/Bmc
> Elog.h
>  create mode 100644
> Features/Intel/OutOfBandManagement/IpmiFeaturePkg/GenericElog/Dxe/Ge
> nericElog.h
>  create mode 100644
> Features/Intel/OutOfBandManagement/IpmiFeaturePkg/GenericElog/Smm/
> GenericElog.h
>  create mode 100644
> Features/Intel/OutOfBandManagement/IpmiFeaturePkg/GenericFru/Generic
> FruDriver.h
>  create mode 100644
> Features/Intel/OutOfBandManagement/IpmiFeaturePkg/Include/Library/Ser
> verMgmtRtLib.h
>  create mode 100644
> Features/Intel/OutOfBandManagement/IpmiFeaturePkg/Include/Ppi/Generic
> Elog.h
>  create mode 100644
> Features/Intel/OutOfBandManagement/IpmiFeaturePkg/Include/Protocol/B
> mcAcpiSwChildPolicy.h
>  create mode 100644
> Features/Intel/OutOfBandManagement/IpmiFeaturePkg/Include/Protocol/G
> enericElog.h
>  create mode 100644
> Features/Intel/OutOfBandManagement/IpmiFeaturePkg/Include/Protocol/G
> enericFru.h
>  create mode 100644
> Features/Intel/OutOfBandManagement/IpmiFeaturePkg/Include/Protocol/R
> edirFru.h
>  create mode 100644
> Features/Intel/OutOfBandManagement/IpmiFeaturePkg/IpmiRedirFru/IpmiR
> edirFru.h
>  create mode 100644
> Features/Intel/OutOfBandManagement/IpmiFeaturePkg/BmcAcpiState/Bmc
> AcpiState.c
>  create mode 100644
> Features/Intel/OutOfBandManagement/IpmiFeaturePkg/BmcAcpiSwChild/B
> mcAcpiSwChild.c
>  delete mode 100644
> Features/Intel/OutOfBandManagement/IpmiFeaturePkg/BmcElog/BmcElog.c
>  create mode 100644
> Features/Intel/OutOfBandManagement/IpmiFeaturePkg/BmcElog/Common/
> BmcElogCommon.c
>  create mode 100644
> Features/Intel/OutOfBandManagement/IpmiFeaturePkg/BmcElog/Dxe/BmcE
> log.c
>  create mode 100644
> Features/Intel/OutOfBandManagement/IpmiFeaturePkg/BmcElog/Pei/BmcEl
> og.c
>  create mode 100644
> Features/Intel/OutOfBandManagement/IpmiFeaturePkg/BmcElog/Smm/Bmc
> Elog.c
>  create mode 100644
> Features/Intel/OutOfBandManagement/IpmiFeaturePkg/GenericElog/Dxe/Ge
> nericElog.c
>  create mode 100644
> Features/Intel/OutOfBandManagement/IpmiFeaturePkg/GenericElog/Smm/
> GenericElog.c
>  create mode 100644
> Features/Intel/OutOfBandManagement/IpmiFeaturePkg/GenericFru/Generic
> Fru.c
>  create mode 100644
> Features/Intel/OutOfBandManagement/IpmiFeaturePkg/GenericFru/Generic
> FruDriver.c
>  delete mode 100644
> Features/Intel/OutOfBandManagement/IpmiFeaturePkg/IpmiFru/IpmiFru.c
>  create mode 100644
> Features/Intel/OutOfBandManagement/IpmiFeaturePkg/IpmiRedirFru/FruS
> mbios.c
>  create mode 100644
> Features/Intel/OutOfBandManagement/IpmiFeaturePkg/IpmiRedirFru/IpmiR
> edirFru.c
>  create mode 100644
> Features/Intel/OutOfBandManagement/IpmiFeaturePkg/Library/ServerMana
> gementLib/ServerManagementLib.c
>  create mode 100644
> Features/Intel/OutOfBandManagement/IpmiFeaturePkg/Library/ServerMana
> gementLibNull/ServerManagementLibNull.c
>
> --
> 2.39.2.windows.1
>
>
>
> 
>



-=-=-=-=-=-=-=-=-=-=-=-
Groups.io Links: You receive all messages sent to this group.
View/Reply Online (#110330): https://edk2.groups.io/g/devel/message/110330
Mute This Topic: https://groups.io/mt/102231765/7686176
Group Owner: devel+owner@edk2.groups.io
Unsubscribe: https://edk2.groups.io/g/devel/unsub [rebecca@openfw.io]
-=-=-=-=-=-=-=-=-=-=-=-



^ permalink raw reply	[flat|nested] 7+ messages in thread

end of thread, other threads:[~2023-10-30 17:13 UTC | newest]

Thread overview: 7+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
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 ` [edk2-devel] [PATCH edk2-platforms 4/4] IpmiFeaturePkg: Add FRU drivers Zhen Gong
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

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox