public inbox for devel@edk2.groups.io
 help / color / mirror / Atom feed
* [edk2-devel] [PATCH edk2-platforms v2 0/4] IpmiFeaturePkg: Add server management features
@ 2023-10-29 20:27 Zhen Gong
  2023-10-29 20:27 ` [edk2-devel] [PATCH edk2-platforms v2 1/4] IpmiFeaturePkg: Add Elog drivers Zhen Gong
                   ` (5 more replies)
  0 siblings, 6 replies; 7+ messages in thread
From: Zhen Gong @ 2023-10-29 20:27 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.

Notes:
    V2:
    - Rebased to resolve merge conflict from upstream changes

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}   |  19 +-
 .../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        |  36 -
 .../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, 7237 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} (60%)
 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 (#110325): https://edk2.groups.io/g/devel/message/110325
Mute This Topic: https://groups.io/mt/102279904/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 v2 1/4] IpmiFeaturePkg: Add Elog drivers
  2023-10-29 20:27 [edk2-devel] [PATCH edk2-platforms v2 0/4] IpmiFeaturePkg: Add server management features Zhen Gong
@ 2023-10-29 20:27 ` Zhen Gong
  2023-10-29 20:27 ` [edk2-devel] [PATCH edk2-platforms v2 2/4] IpmiFeaturePkg: Add ServerManagementLib Zhen Gong
                   ` (4 subsequent siblings)
  5 siblings, 0 replies; 7+ messages in thread
From: Zhen Gong @ 2023-10-29 20:27 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}   |  19 +-
 .../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, 3530 insertions(+), 243 deletions(-)
 rename Features/Intel/OutOfBandManagement/IpmiFeaturePkg/BmcElog/{BmcElog.inf => DxeBmcElog.inf} (60%)
 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 60%
rename from Features/Intel/OutOfBandManagement/IpmiFeaturePkg/BmcElog/BmcElog.inf
rename to Features/Intel/OutOfBandManagement/IpmiFeaturePkg/BmcElog/DxeBmcElog.inf
index 1e7a7658b7b0..7d8db9b633de 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,7 +17,10 @@ [Defines]
   ENTRY_POINT              = InitializeBmcElogLayer
 
 [Sources]
-  BmcElog.c
+  Dxe/BmcElog.c
+  Dxe/BmcElog.h
+  Common/BmcElogCommon.h
+  Common/BmcElogCommon.c
 
 [Packages]
   MdePkg/MdePkg.dec
@@ -28,7 +31,13 @@ [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 (#110326): https://edk2.groups.io/g/devel/message/110326
Mute This Topic: https://groups.io/mt/102279905/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 v2 2/4] IpmiFeaturePkg: Add ServerManagementLib
  2023-10-29 20:27 [edk2-devel] [PATCH edk2-platforms v2 0/4] IpmiFeaturePkg: Add server management features Zhen Gong
  2023-10-29 20:27 ` [edk2-devel] [PATCH edk2-platforms v2 1/4] IpmiFeaturePkg: Add Elog drivers Zhen Gong
@ 2023-10-29 20:27 ` Zhen Gong
  2023-10-29 20:27 ` [edk2-devel] [PATCH edk2-platforms v2 3/4] IpmiFeaturePkg: Add ACPI power state drivers Zhen Gong
                   ` (3 subsequent siblings)
  5 siblings, 0 replies; 7+ messages in thread
From: Zhen Gong @ 2023-10-29 20:27 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 (#110327): https://edk2.groups.io/g/devel/message/110327
Mute This Topic: https://groups.io/mt/102279906/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 v2 3/4] IpmiFeaturePkg: Add ACPI power state drivers
  2023-10-29 20:27 [edk2-devel] [PATCH edk2-platforms v2 0/4] IpmiFeaturePkg: Add server management features Zhen Gong
  2023-10-29 20:27 ` [edk2-devel] [PATCH edk2-platforms v2 1/4] IpmiFeaturePkg: Add Elog drivers Zhen Gong
  2023-10-29 20:27 ` [edk2-devel] [PATCH edk2-platforms v2 2/4] IpmiFeaturePkg: Add ServerManagementLib Zhen Gong
@ 2023-10-29 20:27 ` Zhen Gong
  2023-10-29 20:27 ` [edk2-devel] [PATCH edk2-platforms v2 4/4] IpmiFeaturePkg: Add FRU drivers Zhen Gong
                   ` (2 subsequent siblings)
  5 siblings, 0 replies; 7+ messages in thread
From: Zhen Gong @ 2023-10-29 20:27 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 (#110328): https://edk2.groups.io/g/devel/message/110328
Mute This Topic: https://groups.io/mt/102279907/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 v2 4/4] IpmiFeaturePkg: Add FRU drivers
  2023-10-29 20:27 [edk2-devel] [PATCH edk2-platforms v2 0/4] IpmiFeaturePkg: Add server management features Zhen Gong
                   ` (2 preceding siblings ...)
  2023-10-29 20:27 ` [edk2-devel] [PATCH edk2-platforms v2 3/4] IpmiFeaturePkg: Add ACPI power state drivers Zhen Gong
@ 2023-10-29 20:27 ` Zhen Gong
  2023-11-02 15:47 ` [edk2-devel] [PATCH edk2-platforms v2 0/4] IpmiFeaturePkg: Add server management features Nate DeSimone
  2023-11-03 19:06 ` Nate DeSimone
  5 siblings, 0 replies; 7+ messages in thread
From: Zhen Gong @ 2023-10-29 20:27 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>

# Conflicts:
#	Features/Intel/OutOfBandManagement/IpmiFeaturePkg/IpmiFru/IpmiFru.inf
---
 .../IpmiFeaturePkg/IpmiFeaturePkg.dec         |   4 +
 .../IpmiFeaturePkg/Include/IpmiFeature.dsc    |   3 +-
 .../IpmiFeaturePkg/Include/PostMemory.fdf     |   3 +-
 .../IpmiFeaturePkg/GenericFru/GenericFru.inf  |  42 ++
 .../IpmiFeaturePkg/IpmiFru/IpmiFru.inf        |  36 --
 .../IpmiRedirFru/IpmiRedirFru.inf             |  51 ++
 .../GenericFru/GenericFruDriver.h             | 178 ++++++
 .../Include/Protocol/GenericFru.h             | 103 ++++
 .../Include/Protocol/RedirFru.h               |  81 +++
 .../IpmiRedirFru/IpmiRedirFru.h               | 149 +++++
 .../IpmiFeaturePkg/GenericFru/GenericFru.c    |  68 +++
 .../GenericFru/GenericFruDriver.c             | 513 ++++++++++++++++++
 .../IpmiFeaturePkg/IpmiFru/IpmiFru.c          |  67 ---
 .../IpmiFeaturePkg/IpmiRedirFru/FruSmbios.c   | 469 ++++++++++++++++
 .../IpmiRedirFru/IpmiRedirFru.c               | 479 ++++++++++++++++
 15 files changed, 2141 insertions(+), 105 deletions(-)
 create mode 100644 Features/Intel/OutOfBandManagement/IpmiFeaturePkg/GenericFru/GenericFru.inf
 delete mode 100644 Features/Intel/OutOfBandManagement/IpmiFeaturePkg/IpmiFru/IpmiFru.inf
 create mode 100644 Features/Intel/OutOfBandManagement/IpmiFeaturePkg/IpmiRedirFru/IpmiRedirFru.inf
 create mode 100644 Features/Intel/OutOfBandManagement/IpmiFeaturePkg/GenericFru/GenericFruDriver.h
 create mode 100644 Features/Intel/OutOfBandManagement/IpmiFeaturePkg/Include/Protocol/GenericFru.h
 create mode 100644 Features/Intel/OutOfBandManagement/IpmiFeaturePkg/Include/Protocol/RedirFru.h
 create mode 100644 Features/Intel/OutOfBandManagement/IpmiFeaturePkg/IpmiRedirFru/IpmiRedirFru.h
 create mode 100644 Features/Intel/OutOfBandManagement/IpmiFeaturePkg/GenericFru/GenericFru.c
 create mode 100644 Features/Intel/OutOfBandManagement/IpmiFeaturePkg/GenericFru/GenericFruDriver.c
 delete mode 100644 Features/Intel/OutOfBandManagement/IpmiFeaturePkg/IpmiFru/IpmiFru.c
 create mode 100644 Features/Intel/OutOfBandManagement/IpmiFeaturePkg/IpmiRedirFru/FruSmbios.c
 create mode 100644 Features/Intel/OutOfBandManagement/IpmiFeaturePkg/IpmiRedirFru/IpmiRedirFru.c

diff --git a/Features/Intel/OutOfBandManagement/IpmiFeaturePkg/IpmiFeaturePkg.dec b/Features/Intel/OutOfBandManagement/IpmiFeaturePkg/IpmiFeaturePkg.dec
index be0a11e2adb1..d586931a6d6f 100644
--- a/Features/Intel/OutOfBandManagement/IpmiFeaturePkg/IpmiFeaturePkg.dec
+++ b/Features/Intel/OutOfBandManagement/IpmiFeaturePkg/IpmiFeaturePkg.dec
@@ -63,6 +63,8 @@ [LibraryClasses]
 [Guids]
   gIpmiFeaturePkgTokenSpaceGuid  =  {0xc05283f6, 0xd6a8, 0x48f3, {0x9b, 0x59, 0xfb, 0xca, 0x71, 0x32, 0x0f, 0x12}}
   gPeiIpmiHobGuid                = {0xcb4d3e13, 0x1e34, 0x4373, {0x8a, 0x81, 0xe9, 0x0, 0x10, 0xf1, 0xdb, 0xa4}}
+  gEfiIpmiFormatFruGuid          = { 0x3531fdc6, 0xeae,  0x4cd2, { 0xb0, 0xa6, 0x5f, 0x48, 0xa0, 0xdf, 0xe3, 0x8  } }
+  gEfiSystemTypeFruGuid          = { 0xaab16018, 0x679d, 0x4461, { 0xba, 0x20, 0xe7, 0xc,  0xf7, 0x86, 0x6a, 0x9b } }
 
 [Ppis]
   gPeiIpmiTransportPpiGuid = {0x7bf5fecc, 0xc5b5, 0x4b25, {0x81, 0x1b, 0xb4, 0xb5, 0xb, 0x28, 0x79, 0xf7}}
@@ -80,6 +82,8 @@ [Protocols]
   gSmmGenericElogProtocolGuid = { 0x664ef1f6, 0x19bf, 0x4498, { 0xab, 0x6a, 0xfc, 0x05, 0x72, 0xfb, 0x98, 0x51 } }
   gEfiRedirElogProtocolGuid = { 0x16d11030, 0x71ba, 0x4e5e, { 0xa9, 0xf9, 0xb4, 0x75, 0xa5, 0x49, 0x4, 0x8a } }
   gSmmRedirElogProtocolGuid = { 0x79ac2d9c, 0x9216, 0x43c5, { 0xa0, 0x74, 0x0b, 0x45, 0xc7, 0x64, 0x22, 0xc1 } }
+  gEfiRedirFruProtocolGuid  = { 0x28638cfa, 0xea88, 0x456c, { 0x92, 0xa5, 0xf2, 0x49, 0xca, 0x48, 0x85, 0x35 } }
+  gEfiGenericFruProtocolGuid = { 0xc8eebf0e, 0x0e10, 0x47f7, { 0x81, 0xbd, 0x39, 0xdb, 0x75, 0xca, 0x93, 0x9f } }
 
 [PcdsFeatureFlag]
   gIpmiFeaturePkgTokenSpaceGuid.PcdIpmiFeatureEnable|FALSE|BOOLEAN|0xA0000001
diff --git a/Features/Intel/OutOfBandManagement/IpmiFeaturePkg/Include/IpmiFeature.dsc b/Features/Intel/OutOfBandManagement/IpmiFeaturePkg/Include/IpmiFeature.dsc
index 7e663236d9a1..3ceedb2fa3c4 100644
--- a/Features/Intel/OutOfBandManagement/IpmiFeaturePkg/Include/IpmiFeature.dsc
+++ b/Features/Intel/OutOfBandManagement/IpmiFeaturePkg/Include/IpmiFeature.dsc
@@ -129,7 +129,8 @@ [Components.X64]
   IpmiFeaturePkg/GenericElog/Dxe/GenericElog.inf
   IpmiFeaturePkg/GenericElog/Smm/GenericElog.inf
   IpmiFeaturePkg/Frb/FrbDxe.inf
-  IpmiFeaturePkg/IpmiFru/IpmiFru.inf
+  IpmiFeaturePkg/IpmiRedirFru/IpmiRedirFru.inf
+  IpmiFeaturePkg/GenericFru/GenericFru.inf
   IpmiFeaturePkg/IpmiInit/DxeIpmiInit.inf
   IpmiFeaturePkg/OsWdt/OsWdt.inf
   IpmiFeaturePkg/SolStatus/SolStatus.inf
diff --git a/Features/Intel/OutOfBandManagement/IpmiFeaturePkg/Include/PostMemory.fdf b/Features/Intel/OutOfBandManagement/IpmiFeaturePkg/Include/PostMemory.fdf
index 9b692f07dcd8..810a041983c1 100644
--- a/Features/Intel/OutOfBandManagement/IpmiFeaturePkg/Include/PostMemory.fdf
+++ b/Features/Intel/OutOfBandManagement/IpmiFeaturePkg/Include/PostMemory.fdf
@@ -15,8 +15,9 @@
 INF IpmiFeaturePkg/BmcElog/DxeBmcElog.inf
 INF IpmiFeaturePkg/BmcElog/SmmBmcElog.inf
 INF IpmiFeaturePkg/Frb/FrbDxe.inf
-INF IpmiFeaturePkg/IpmiFru/IpmiFru.inf
+INF IpmiFeaturePkg/IpmiRedirFru/IpmiRedirFru.inf
 INF IpmiFeaturePkg/GenericElog/Dxe/GenericElog.inf
 INF IpmiFeaturePkg/GenericElog/Smm/GenericElog.inf
+INF IpmiFeaturePkg/GenericFru/GenericFru.inf
 INF IpmiFeaturePkg/OsWdt/OsWdt.inf
 INF IpmiFeaturePkg/SolStatus/SolStatus.inf
diff --git a/Features/Intel/OutOfBandManagement/IpmiFeaturePkg/GenericFru/GenericFru.inf b/Features/Intel/OutOfBandManagement/IpmiFeaturePkg/GenericFru/GenericFru.inf
new file mode 100644
index 000000000000..f53642b1a476
--- /dev/null
+++ b/Features/Intel/OutOfBandManagement/IpmiFeaturePkg/GenericFru/GenericFru.inf
@@ -0,0 +1,42 @@
+### @file
+#
+# Copyright (c) 2023, Intel Corporation. All rights reserved.<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 f5778f3468df..000000000000
--- a/Features/Intel/OutOfBandManagement/IpmiFeaturePkg/IpmiFru/IpmiFru.inf
+++ /dev/null
@@ -1,36 +0,0 @@
-### @file
-# Component description file for IPMI FRU.
-#
-# Copyright (c) 2018 - 2019, Intel Corporation. All rights reserved.<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
-  MdeModulePkg/MdeModulePkg.dec
-  IpmiFeaturePkg/IpmiFeaturePkg.dec
-
-[LibraryClasses]
-  UefiDriverEntryPoint
-  UefiLib
-  DebugLib
-  UefiBootServicesTableLib
-  BaseMemoryLib
-  IpmiCommandLib
-
-[Depex]
-  TRUE
diff --git a/Features/Intel/OutOfBandManagement/IpmiFeaturePkg/IpmiRedirFru/IpmiRedirFru.inf b/Features/Intel/OutOfBandManagement/IpmiFeaturePkg/IpmiRedirFru/IpmiRedirFru.inf
new file mode 100644
index 000000000000..24fbc94128da
--- /dev/null
+++ b/Features/Intel/OutOfBandManagement/IpmiFeaturePkg/IpmiRedirFru/IpmiRedirFru.inf
@@ -0,0 +1,51 @@
+### @file
+#
+# Copyright (c) 2023, Intel Corporation. All rights reserved.<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 (#110329): https://edk2.groups.io/g/devel/message/110329
Mute This Topic: https://groups.io/mt/102279908/7686176
Group Owner: devel+owner@edk2.groups.io
Unsubscribe: https://edk2.groups.io/g/devel/unsub [rebecca@openfw.io]
-=-=-=-=-=-=-=-=-=-=-=-



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

* Re: [edk2-devel] [PATCH edk2-platforms v2 0/4] IpmiFeaturePkg: Add server management features
  2023-10-29 20:27 [edk2-devel] [PATCH edk2-platforms v2 0/4] IpmiFeaturePkg: Add server management features Zhen Gong
                   ` (3 preceding siblings ...)
  2023-10-29 20:27 ` [edk2-devel] [PATCH edk2-platforms v2 4/4] IpmiFeaturePkg: Add FRU drivers Zhen Gong
@ 2023-11-02 15:47 ` Nate DeSimone
  2023-11-03 19:06 ` Nate DeSimone
  5 siblings, 0 replies; 7+ messages in thread
From: Nate DeSimone @ 2023-11-02 15:47 UTC (permalink / raw)
  To: devel@edk2.groups.io, Gong, Zhen

Good work Zhen!

Reviewed-by: Nate DeSimone <nathaniel.l.desimone@intel.com>

-----Original Message-----
From: devel@edk2.groups.io <devel@edk2.groups.io> On Behalf Of Zhen Gong
Sent: Sunday, October 29, 2023 1:28 PM
To: devel@edk2.groups.io
Cc: Gong, Zhen <zhen.gong@intel.com>
Subject: [edk2-devel] [PATCH edk2-platforms v2 0/4] IpmiFeaturePkg: Add server management features

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.

Notes:
    V2:
    - Rebased to resolve merge conflict from upstream changes

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}   |  19 +-
 .../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        |  36 -
 .../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, 7237 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} (60%)  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 (#110559): https://edk2.groups.io/g/devel/message/110559
Mute This Topic: https://groups.io/mt/102279904/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 v2 0/4] IpmiFeaturePkg: Add server management features
  2023-10-29 20:27 [edk2-devel] [PATCH edk2-platforms v2 0/4] IpmiFeaturePkg: Add server management features Zhen Gong
                   ` (4 preceding siblings ...)
  2023-11-02 15:47 ` [edk2-devel] [PATCH edk2-platforms v2 0/4] IpmiFeaturePkg: Add server management features Nate DeSimone
@ 2023-11-03 19:06 ` Nate DeSimone
  5 siblings, 0 replies; 7+ messages in thread
From: Nate DeSimone @ 2023-11-03 19:06 UTC (permalink / raw)
  To: devel@edk2.groups.io, Gong, Zhen

The series has been pushed as 0cedeab~..6d60278

-----Original Message-----
From: devel@edk2.groups.io <devel@edk2.groups.io> On Behalf Of Zhen Gong
Sent: Sunday, October 29, 2023 1:28 PM
To: devel@edk2.groups.io
Cc: Gong, Zhen <zhen.gong@intel.com>
Subject: [edk2-devel] [PATCH edk2-platforms v2 0/4] IpmiFeaturePkg: Add server management features

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.

Notes:
    V2:
    - Rebased to resolve merge conflict from upstream changes

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}   |  19 +-
 .../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        |  36 -
 .../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, 7237 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} (60%)  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 (#110666): https://edk2.groups.io/g/devel/message/110666
Mute This Topic: https://groups.io/mt/102279904/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-11-03 19:07 UTC | newest]

Thread overview: 7+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2023-10-29 20:27 [edk2-devel] [PATCH edk2-platforms v2 0/4] IpmiFeaturePkg: Add server management features Zhen Gong
2023-10-29 20:27 ` [edk2-devel] [PATCH edk2-platforms v2 1/4] IpmiFeaturePkg: Add Elog drivers Zhen Gong
2023-10-29 20:27 ` [edk2-devel] [PATCH edk2-platforms v2 2/4] IpmiFeaturePkg: Add ServerManagementLib Zhen Gong
2023-10-29 20:27 ` [edk2-devel] [PATCH edk2-platforms v2 3/4] IpmiFeaturePkg: Add ACPI power state drivers Zhen Gong
2023-10-29 20:27 ` [edk2-devel] [PATCH edk2-platforms v2 4/4] IpmiFeaturePkg: Add FRU drivers Zhen Gong
2023-11-02 15:47 ` [edk2-devel] [PATCH edk2-platforms v2 0/4] IpmiFeaturePkg: Add server management features Nate DeSimone
2023-11-03 19:06 ` Nate DeSimone

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