oem-meta: Add event manager

Add OEM Meta event manager for handling meta oem 0xFB event class.

Tested: Verified in yosemite4 platform, all events are handled
correctly.

Change-Id: Idcf4be755124c4a361d4eeb93cc494c36aff6d10
Signed-off-by: Lora Lin <lora.lin.wiwynn@gmail.com>
Signed-off-by: Kay YC Huang <kay.yc.huang.wiwynn@gmail.com>
Signed-off-by: Sora Su <baxiche@gmail.com>
diff --git a/oem/meta/event/meson.build b/oem/meta/event/meson.build
new file mode 100644
index 0000000..900fafc
--- /dev/null
+++ b/oem/meta/event/meson.build
@@ -0,0 +1 @@
+oem_files += files('oem_event_manager.cpp')
diff --git a/oem/meta/event/oem_event_manager.cpp b/oem/meta/event/oem_event_manager.cpp
new file mode 100644
index 0000000..5cdd890
--- /dev/null
+++ b/oem/meta/event/oem_event_manager.cpp
@@ -0,0 +1,683 @@
+#include "oem_event_manager.hpp"
+
+#include <com/meta/IPMI/UnifiedSEL/event.hpp>
+#include <oem/meta/utils.hpp>
+#include <phosphor-logging/commit.hpp>
+#include <phosphor-logging/lg2.hpp>
+#include <xyz/openbmc_project/Inventory/Decorator/Slot/client.hpp>
+
+#include <cstdint>
+#include <iostream>
+#include <sstream>
+
+namespace pldm
+{
+namespace oem_meta
+{
+
+int OemEventManager::processOemMetaEvent(
+    pldm_tid_t tid, const uint8_t* eventData, size_t eventDataSize) const
+{
+    RecordType recordType = static_cast<RecordType>(eventData[0]);
+    std::string errorLog;
+    switch (recordType)
+    {
+        case RecordType::SYSTEM_EVENT_RECORD:
+        {
+            handleSystemEvent(eventData, errorLog);
+            break;
+        }
+        case RecordType::UNIFIED_BIOS_SEL:
+        {
+            handleUnifiedBIOSEvent(eventData, errorLog);
+            break;
+        }
+        default:
+        {
+            return PLDM_ERROR;
+        }
+    }
+
+    std::string slotNumber = getSlotNumberStringByTID(tid);
+    std::string message =
+        "SEL Entry: Host: " + slotNumber + ", Record: " + errorLog;
+    lg2::error("{ERROR}", "ERROR", message); // Create log in journal
+
+    std::string rawLog = [eventData, eventDataSize]() {
+        std::stringstream stream;
+        stream << std::hex << std::uppercase << std::setfill('0');
+        for (int i = 0; i < static_cast<int>(eventDataSize); ++i)
+        {
+            stream << std::setw(2) << static_cast<int>(eventData[i]);
+        }
+        return stream.str();
+    }();
+
+    std::string source = "/xyz/openbmc_project/state/host" + slotNumber;
+    {
+        namespace Errors = sdbusplus::error::com::meta::ipmi::UnifiedSEL;
+        lg2::commit(Errors::UnifiedSELEvent("SOURCE", source, "EVENT", errorLog,
+                                            "RAW_EVENT", rawLog));
+    }
+
+    return 0;
+}
+
+int OemEventManager::handleOemEvent(
+    const pldm_msg* request, size_t payloadLength, uint8_t /* formatVersion */,
+    pldm_tid_t tid, size_t eventDataOffset) const
+{
+    auto eventData =
+        reinterpret_cast<const uint8_t*>(request->payload) + eventDataOffset;
+    auto eventDataSize = payloadLength - eventDataOffset;
+    if (!pldm::oem_meta::checkMetaIana(tid))
+    {
+        lg2::error("Recieve OEM Meta event from not Meta specific device");
+        return PLDM_ERROR;
+    }
+    if (!processOemMetaEvent(tid, eventData, eventDataSize))
+    {
+        return PLDM_ERROR;
+    }
+
+    return PLDM_SUCCESS;
+}
+
+void OemEventManager::handleSystemEvent(const uint8_t* eventData,
+                                        std::string& errorLog) const
+{
+    errorLog = "Standard (0x02), ";
+    switch (auto se = static_cast<SystemError>(eventData[8]); se)
+    {
+        case SystemError::SYSTEM_PROCESSOR_ERR:
+        {
+            switch (auto pe = static_cast<ProcessorError>(eventData[9]); pe)
+            {
+                case ProcessorError::MACHINE_CHK_ERR:
+                {
+                    errorLog += "MACHINE_CHK_ERR (" +
+                                to_hex_string(eventData[9]) + "), ";
+                    errorLog += "Event Data: (" + to_hex_string(eventData[11]) +
+                                to_hex_string(eventData[12]) +
+                                to_hex_string(eventData[13]) + ") ";
+
+                    switch (auto ps = static_cast<ProcessorSeverity>(
+                                eventData[11] & 0x0F);
+                            ps)
+                    {
+                        case ProcessorSeverity::UNCORRECT_SYSTEM_FATAL_ERR:
+                            errorLog += "Uncorrected System Fatal Error, ";
+                            break;
+                        case ProcessorSeverity::CORRECTABLE_SYSTEM_ERR:
+                            errorLog += "Correctable System Error, ";
+                            break;
+                        default:
+                            errorLog += "Unknown Error, ";
+                            break;
+                    }
+
+                    if (eventData[12] == 0x1D)
+                    {
+                        errorLog += "Bank Number " +
+                                    std::to_string(eventData[12]) +
+                                    " (SMU/MPDMA), ";
+                    }
+
+                    errorLog += "CPU " + std::to_string(eventData[13] >> 5) +
+                                ", CCD " + std::to_string(eventData[13] & 0x1F);
+                    break;
+                }
+            }
+            break;
+        }
+        case SystemError::SYSTEM_POST_ERR:
+        {
+            errorLog += "POST_ERROR:";
+            if ((eventData[11] & 0x0F) == 0x0)
+                errorLog += ", System Firmware Error";
+
+            if (((eventData[11] >> 6) & 0x03) == 0x2)
+            {
+                errorLog += ", OEM Post Code 0x" +
+                            to_hex_string(eventData[13]) +
+                            to_hex_string(eventData[12]);
+            }
+
+            if (((eventData[13] << 8) | eventData[12]) == 0xD9)
+            {
+                errorLog +=
+                    ", Error loading Boot Option (Load image returned error)";
+            }
+            break;
+        }
+        case SystemError::SYSTEM_CXL_ERR:
+        {
+            errorLog += "CXL 1.1 Error, ";
+            switch (auto ce = static_cast<CxlError>(eventData[9]); ce)
+            {
+                case CxlError::PROTOCOL_ERR:
+                {
+                    errorLog += ", Protocol Error(0x1), ";
+                    break;
+                }
+                case CxlError::COMPONENT_ERR:
+                {
+                    errorLog += ", Component Error(0x2), ";
+                    break;
+                }
+            }
+
+            errorLog += "Severity: ";
+            errorLog +=
+                (eventData[11] & 0x01) ? "Uncorrectable" : "Correctable";
+            errorLog += ", Detected By: ";
+            errorLog += (eventData[11] & 0x02) ? "CXL 1.1 Host Downstream Port"
+                                               : "CXL 1.1 Device";
+
+            uint8_t errorType = (eventData[11] >> 2) & 0x03;
+
+            errorLog += ", Error Type: " + std::string(cxlError[errorType]) +
+                        ", Bus " + to_hex_string(eventData[12]) + "/Dev " +
+                        to_hex_string(eventData[13] >> 3) + "/Fun " +
+                        to_hex_string(eventData[13] & 0x7);
+            break;
+        }
+        case SystemError::SYSTEM_CXL_ERR_2_0:
+        {
+            errorLog += "CXL 2.0 Error, ";
+            switch (auto ce = static_cast<CxlError2>(eventData[9]); ce)
+            {
+                case CxlError2::PROTOCOL_ERR:
+                {
+                    errorLog += ", Protocol Error(0x1), ";
+                    break;
+                }
+                case CxlError2::COMPONENT_ERR:
+                {
+                    errorLog += ", Component Error(0x2), ";
+                    break;
+                }
+            }
+
+            errorLog += "Severity: ";
+            errorLog +=
+                (eventData[11] & 0x01) ? "Uncorrectable" : "Correctable";
+            // root port only
+            errorLog += ", Detected By: CXL Root Port";
+
+            uint8_t errorType = (eventData[11] >> 2) & 0x03;
+
+            errorLog += ", Error Type: " + std::string(cxlError[errorType]) +
+                        ", Bus " + to_hex_string(eventData[12]) + "/Dev " +
+                        to_hex_string(eventData[13] >> 3) + "/Fun " +
+                        to_hex_string(eventData[13] & 0x7);
+            break;
+        }
+        default:
+        { // Not supported
+            errorLog +=
+                "Raw: " + to_hex_string(eventData[1]) +
+                to_hex_string(eventData[2]) + to_hex_string(eventData[3]) +
+                to_hex_string(eventData[4]) + to_hex_string(eventData[5]) +
+                to_hex_string(eventData[6]) + to_hex_string(eventData[7]) +
+                to_hex_string(eventData[8]) + to_hex_string(eventData[9]) +
+                to_hex_string(eventData[10]) + to_hex_string(eventData[11]) +
+                to_hex_string(eventData[12]) + to_hex_string(eventData[13]);
+        }
+    }
+}
+
+void OemEventManager::handleUnifiedBIOSEvent(const uint8_t* eventData,
+                                             std::string& errorLog) const
+{
+    errorLog = "Meta Unified SEL (0xFB), ";
+
+    DimmInfo dimmInfo = {
+        static_cast<uint8_t>((eventData[6] >> 4) & 0x03), // Sled
+        static_cast<uint8_t>(eventData[6] & 0x0F),        // Socket
+        static_cast<uint8_t>(eventData[7]),               // Channel
+        static_cast<uint8_t>(eventData[8])                // Slot
+    };
+
+    uint8_t generalInfo = eventData[1];
+    UnifiedError errorType = static_cast<UnifiedError>(generalInfo & 0xF);
+    switch (errorType)
+    {
+        case UnifiedError::UNIFIED_PCIE_ERR:
+        {
+            uint8_t plat = (generalInfo & 0x10) >> 4;
+            if (plat == 0)
+            { // x86
+                errorLog +=
+                    "GeneralInfo: x86/PCIeErr(0x" + to_hex_string(generalInfo) +
+                    "), Bus " + to_hex_string(eventData[9]) + "/Dev " +
+                    to_hex_string(eventData[8] >> 3) + "/Fun " +
+                    to_hex_string(eventData[8] & 0x7) + ", ErrID2: 0x" +
+                    to_hex_string(eventData[12]) + ", ErrID1: 0x" +
+                    to_hex_string(eventData[13]);
+            }
+            else
+            {
+                errorLog +=
+                    "GeneralInfo: ARM/PCIeErr(0x" + to_hex_string(generalInfo) +
+                    "), Aux. Info: 0x" +
+                    to_hex_string((eventData[7] << 8) | eventData[6], 4) +
+                    ", Bus " + to_hex_string(eventData[9]) + "/Dev " +
+                    to_hex_string(eventData[8] >> 3) + "/Fun " +
+                    to_hex_string(eventData[8] & 0x7) + ", ErrID2: 0x" +
+                    to_hex_string(eventData[12]) + ", ErrID1: 0x" +
+                    to_hex_string(eventData[13]);
+            }
+            break;
+        }
+        case UnifiedError::UNIFIED_MEM_ERR:
+        {
+            handleMemoryError(eventData, errorLog, dimmInfo, generalInfo);
+            break;
+        }
+        case UnifiedError::UNIFIED_UPI_ERR:
+        {
+            UpiError eventType = static_cast<UpiError>(eventData[10] & 0xF);
+            uint8_t estrIdx =
+                (static_cast<uint8_t>(eventType) < upiError.size())
+                    ? static_cast<uint8_t>(eventType)
+                    : (upiError.size() - 1);
+
+            switch (eventType)
+            {
+                case UpiError::UPI_INIT_ERR:
+                {
+                    errorLog +=
+                        "GeneralInfo: UPIErr(0x" + to_hex_string(generalInfo) +
+                        "), UPI Port Location: Sled " +
+                        std::to_string(dimmInfo.sled) + "/Socket " +
+                        std::to_string(dimmInfo.socket) + ", Port " +
+                        std::to_string(eventData[4] & 0xF) +
+                        ", UPI Failure Event: " + upiError[estrIdx] +
+                        ", Major Code: 0x" + to_hex_string(eventData[8]) +
+                        ", Minor Code: 0x" + to_hex_string(eventData[9]);
+                    break;
+                }
+                default:
+                {
+                    errorLog +=
+                        "GeneralInfo: UPIErr(0x" + to_hex_string(generalInfo) +
+                        "), UPI Port Location: Sled " +
+                        std::to_string(dimmInfo.sled) + "/Socket " +
+                        std::to_string(dimmInfo.socket) + ", Port " +
+                        std::to_string(eventData[4] & 0xF) +
+                        ", UPI Failure Event: " + upiError[estrIdx];
+                    break;
+                }
+            }
+            break;
+        }
+        case UnifiedError::UNIFIED_IIO_ERR:
+        {
+            uint8_t stack = eventData[7];
+            uint8_t selErrorType = eventData[11];
+            uint8_t selErrorSeverity = eventData[12];
+            uint8_t selErrorId = eventData[13];
+
+            errorLog +=
+                "GeneralInfo: IIOErr(0x" + to_hex_string(generalInfo) +
+                "), IIO Port Location: Sled " + std::to_string(dimmInfo.sled) +
+                "/Socket " + std::to_string(dimmInfo.socket) + ", Stack 0x" +
+                to_hex_string(stack) + ", Error Type: 0x" +
+                to_hex_string(selErrorType) + ", Error Severity: 0x" +
+                to_hex_string(selErrorSeverity) + ", Error ID: 0x" +
+                to_hex_string(selErrorId);
+            break;
+        }
+        case UnifiedError::UNIFIED_MCA_ERR:
+        {
+            uint8_t mcaSeverity = ((eventData[6] >> 4) & 0x07);
+            uint8_t cpuNumber = (eventData[7] >> 5) & 0x07;
+            uint8_t coreNumber = eventData[7] & 0x1F;
+            uint8_t machineCheckBankNumber = eventData[8];
+            uint32_t errorInfo = (static_cast<uint32_t>(eventData[9]) << 16) |
+                                 (static_cast<uint32_t>(eventData[10]) << 8) |
+                                 static_cast<uint32_t>(eventData[11]);
+            uint8_t errorCode = eventData[12];
+            uint8_t errorStatus = eventData[13];
+
+            errorLog +=
+                "GeneralInfo: MCAErr(0x" + to_hex_string(generalInfo) +
+                "), MCA Severity: " + errorSeverityDetail[mcaSeverity] +
+                ", CPU Number: " + std::to_string(cpuNumber) +
+                ", Core Number: " + std::to_string(coreNumber) +
+                ", Machine Check Bank: " +
+                machineCheckBank[machineCheckBankNumber] + ", Error Info: 0x" +
+                to_hex_string(errorInfo, 6) + ", Error Code: 0x" +
+                to_hex_string(errorCode) + ", Error Status: 0x" +
+                to_hex_string(errorStatus);
+            break;
+        }
+        case UnifiedError::UNIFIED_MCA_ERR_EXT:
+        {
+            uint8_t mcaSeverity = ((eventData[6] >> 4) & 0x07);
+            uint8_t cpuNumber = (eventData[7] >> 5) & 0x07;
+            uint8_t coreNumber = eventData[7] & 0x1F;
+            uint8_t machineCheckBankNumber = eventData[8];
+            uint16_t errorCode = (eventData[9] << 8) | eventData[10];
+
+            errorLog +=
+                "GeneralInfo: MCAErrExt(0x" + to_hex_string(generalInfo) +
+                "), MCA Severity: " + errorSeverityDetail[mcaSeverity] +
+                ", CPU Number: " + std::to_string(cpuNumber) +
+                ", Core Number: " + std::to_string(coreNumber) +
+                ", Machine Check Bank: " +
+                machineCheckBank[machineCheckBankNumber] + ", Error Code: 0x" +
+                to_hex_string(errorCode, 4);
+            break;
+        }
+        case UnifiedError::UNIFIED_RP_PIO_1st:
+        case UnifiedError::UNIFIED_RP_PIO_2nd:
+        {
+            auto offset =
+                static_cast<uint8_t>(errorType) -
+                static_cast<uint8_t>(UnifiedError::UNIFIED_RP_PIO_1st);
+            errorLog +=
+                "GeneralInfo: RP_PIOEvent(0x" + to_hex_string(generalInfo) +
+                "), RP_PIO Header Log" + std::to_string(1 + offset * 2) +
+                ": 0x" + to_hex_string(eventData[9]) +
+                to_hex_string(eventData[8]) + to_hex_string(eventData[7]) +
+                to_hex_string(eventData[6]) + ", RP_PIO Header Log" +
+                std::to_string(2 + offset * 2) + ": 0x" +
+                to_hex_string(eventData[13]) + to_hex_string(eventData[12]) +
+                to_hex_string(eventData[11]) + to_hex_string(eventData[10]);
+            break;
+        }
+        case UnifiedError::UNIFIED_POST_EVENT:
+        {
+            handleSystemPostEvent(eventData, errorLog, generalInfo);
+            break;
+        }
+        case UnifiedError::UNIFIED_PCIE_EVENT:
+        {
+            PcieEvent eventType = static_cast<PcieEvent>(eventData[6] & 0xF);
+            uint8_t estrIdx =
+                (static_cast<uint8_t>(eventType) < pcieEvent.size())
+                    ? static_cast<uint8_t>(eventType)
+                    : (pcieEvent.size() - 1);
+            switch (eventType)
+            {
+                case PcieEvent::PCIE_DPC:
+                {
+                    errorLog +=
+                        "GeneralInfo: PCIeEvent(0x" +
+                        to_hex_string(generalInfo) +
+                        "), PCIe Failure Event: " + pcieEvent[estrIdx] +
+                        ", Status: 0x" +
+                        to_hex_string((eventData[9] << 8) | eventData[8], 4) +
+                        ", Source ID: 0x" +
+                        to_hex_string((eventData[11] << 8) | eventData[10], 4);
+                    break;
+                }
+                default:
+                {
+                    errorLog += "GeneralInfo: PCIeEvent(0x" +
+                                to_hex_string(generalInfo) +
+                                "), PCIe Failure Event: " + pcieEvent[estrIdx];
+                    break;
+                }
+            }
+            break;
+        }
+        case UnifiedError::UNIFIED_MEM_EVENT:
+        {
+            // get dimm location data string.
+            std::string dimmLocation, dimm;
+            getCommonDimmLocation(dimmInfo, dimmLocation, dimm);
+
+            // Event-Type Bit[3:0]
+            MemoryEvent eventType =
+                static_cast<MemoryEvent>(eventData[10] & 0x0F);
+            switch (eventType)
+            {
+                case MemoryEvent::MEM_PPR:
+                {
+                    errorLog += "GeneralInfo: MemEvent(0x" +
+                                to_hex_string(generalInfo) + "), " +
+                                dimmLocation + ", DIMM Failure Event: " +
+                                memoryPprRepairTime[eventData[11] >> 2 & 0x03] +
+                                ", " + memoryPprEvent[eventData[11] & 0x03];
+                    break;
+                }
+                case MemoryEvent::MEM_ADDDC:
+                {
+                    uint8_t estrIdx = eventData[12] & 0x03;
+                    if (estrIdx >= memoryAdddcEvent.size())
+                        estrIdx = memoryAdddcEvent.size() - 1;
+                    errorLog += "GeneralInfo: MemEvent(0x" +
+                                to_hex_string(generalInfo) + "), " +
+                                dimmLocation + ", DIMM Failure Event: " +
+                                memoryEvent[static_cast<uint8_t>(eventType)] +
+                                " " + memoryAdddcEvent[estrIdx];
+                    break;
+                }
+                case MemoryEvent::MEM_NO_DIMM:
+                {
+                    errorLog += "GeneralInfo: MemEvent(0x" +
+                                to_hex_string(generalInfo) +
+                                "), DIMM Failure Event: " +
+                                memoryEvent[static_cast<uint8_t>(eventType)];
+                    break;
+                }
+                case MemoryEvent::MEM_CXL_POST_PPR:
+                {
+                    errorLog +=
+                        "GeneralInfo: MemEvent(0x" +
+                        to_hex_string(generalInfo) + "), Bus " +
+                        to_hex_string(eventData[12]) + "/Dev " +
+                        to_hex_string(eventData[13] >> 3) + "/Fun " +
+                        to_hex_string(eventData[13] & 0x7) +
+                        ", DIMM Failure Event: " +
+                        memoryEvent[static_cast<uint8_t>(eventType)] + ", " +
+                        memoryCXLPostPprEvent[eventData[11] >> 7 & 0x1] + ", " +
+                        getDimmDeviceName(eventData, 12) +
+                        memoryCxlEvent[eventData[11] & 0x3];
+                    break;
+                }
+                default:
+                {
+                    uint8_t estrIdx =
+                        (static_cast<uint8_t>(eventType) < memoryEvent.size())
+                            ? static_cast<uint8_t>(eventType)
+                            : (memoryEvent.size() - 1);
+                    errorLog += "GeneralInfo: MemEvent(0x" +
+                                to_hex_string(generalInfo) + "), " +
+                                dimmLocation +
+                                ", DIMM Failure Event: " + memoryEvent[estrIdx];
+                    break;
+                }
+            }
+            break;
+        }
+        case UnifiedError::UNIFIED_UPI_EVENT:
+        {
+            uint8_t eventType = eventData[10] & 0x0F;
+            uint8_t estrIdx = (eventType < upiEvent.size())
+                                  ? eventType
+                                  : (upiEvent.size() - 1);
+            errorLog +=
+                "GeneralInfo: UPIEvent(0x" + to_hex_string(generalInfo) +
+                "), UPI Port Location: Sled " + std::to_string(dimmInfo.sled) +
+                "/Socket " + std::to_string(dimmInfo.socket) + ", Port " +
+                std::to_string(eventData[7] & 0xF) +
+                ", UPI Failure Event: " + upiEvent[estrIdx];
+            break;
+        }
+        case UnifiedError::UNIFIED_BOOT_GUARD:
+        {
+            errorLog +=
+                "GeneralInfo: Boot Guard ACM Failure Events(0x" +
+                to_hex_string(generalInfo) + "), Error Class(0x" +
+                to_hex_string(eventData[10]) + "), Major Error Code(0x" +
+                to_hex_string(eventData[11]) + "), Minor Error Code(0x" +
+                to_hex_string(eventData[12]) + ")";
+            break;
+        }
+        case UnifiedError::UNIFIED_PPR_EVENT:
+        {
+            uint8_t eventType = eventData[6] & 0x0F;
+            errorLog +=
+                "GeneralInfo: PPR Events(0x" + to_hex_string(generalInfo) +
+                "), " + pprEvent[eventType] + ". DIMM Info: (" +
+                to_hex_string(eventData[7]) + to_hex_string(eventData[8]) +
+                to_hex_string(eventData[9]) + to_hex_string(eventData[10]) +
+                to_hex_string(eventData[11]) + to_hex_string(eventData[12]) +
+                to_hex_string(eventData[13]) + ")";
+            break;
+        }
+        case UnifiedError::UNIFIED_CXL_MEM_ERR:
+        {
+            uint8_t eventType = eventData[10] & 0xF;
+
+            errorLog += "GeneralInfo: CXL Memory Error(0x" +
+                        to_hex_string(generalInfo) + "), Bus " +
+                        to_hex_string(eventData[7]) + "/Dev " +
+                        to_hex_string(eventData[8] >> 3) + "/Fun " +
+                        to_hex_string(eventData[8] & 0x7) +
+                        ", DIMM Failure Event: " + memoryError[eventType] +
+                        ", " + getDimmDeviceName(eventData, 7) +
+                        memoryCxlEvent[eventData[11] & 0x7];
+            break;
+        }
+        default:
+        {
+            errorLog +=
+                "Undefined Error Type(0x" +
+                to_hex_string(static_cast<uint8_t>(errorType)) +
+                "), Raw: " + to_hex_string(eventData[1]) +
+                to_hex_string(eventData[2]) + to_hex_string(eventData[3]) +
+                to_hex_string(eventData[4]) + to_hex_string(eventData[5]) +
+                to_hex_string(eventData[6]) + to_hex_string(eventData[7]) +
+                to_hex_string(eventData[8]) + to_hex_string(eventData[9]) +
+                to_hex_string(eventData[10]) + to_hex_string(eventData[11]) +
+                to_hex_string(eventData[12]) + to_hex_string(eventData[13]);
+            break;
+        }
+    }
+}
+
+void OemEventManager::handleMemoryError(
+    const uint8_t* eventData, std::string& errorLog, const DimmInfo& dimmInfo,
+    uint8_t generalInfo) const
+{
+    std::string dimmLocation, dimm;
+    getCommonDimmLocation(dimmInfo, dimmLocation, dimm);
+    uint8_t plat = (eventData[10] & 0x80) >> 7;
+    MemoryError eventType = static_cast<MemoryError>(eventData[10] & 0xF);
+    switch (eventType)
+    {
+        case MemoryError::MEMORY_TRAINING_ERR:
+        case MemoryError::MEMORY_PMIC_ERR:
+        {
+            if (plat == 0)
+            { // Intel
+                errorLog += "GeneralInfo: MEMORY_ECC_ERR(0x" +
+                            to_hex_string(generalInfo) + "), " + dimmLocation +
+                            ", DIMM Failure Event: " +
+                            memoryError[static_cast<uint8_t>(eventType)] +
+                            ", Major Code: 0x" + to_hex_string(eventData[11]) +
+                            ", Minor Code: 0x" + to_hex_string(eventData[12]);
+            }
+            else
+            { // AMD
+                errorLog +=
+                    "GeneralInfo: MEMORY_ECC_ERR(0x" +
+                    to_hex_string(generalInfo) + "), " + dimmLocation +
+                    ", DIMM Failure Event: " +
+                    memoryError[static_cast<uint8_t>(eventType)] +
+                    ", Major Code: 0x" + to_hex_string(eventData[11]) +
+                    ", Minor Code: 0x" +
+                    to_hex_string((eventData[13] << 8) | eventData[12], 4);
+            }
+            break;
+        }
+        default:
+            convertToDimmString(dimmInfo.socket, dimmInfo.channel,
+                                dimmInfo.slot, dimm);
+            uint8_t estrIdx =
+                (static_cast<uint8_t>(eventType) < memoryError.size())
+                    ? static_cast<uint8_t>(eventType)
+                    : (memoryError.size() - 1);
+            errorLog += "GeneralInfo: MEMORY_ECC_ERR(0x" +
+                        to_hex_string(generalInfo) + "), " + dimmLocation +
+                        ", DIMM Failure Event: " + memoryError[estrIdx];
+            break;
+    }
+}
+
+void OemEventManager::handleSystemPostEvent(
+    const uint8_t* eventData, std::string& errorLog, uint8_t generalInfo) const
+{
+    uint8_t certEventIdx = (eventData[10] < certEvent.size())
+                               ? eventData[10]
+                               : (certEvent.size() - 1);
+    uint8_t failType = eventData[11] & 0xF;
+    uint8_t errCode = eventData[12];
+    PostError eventType = static_cast<PostError>(eventData[6] & 0xF);
+    uint8_t estrIdx = (static_cast<uint8_t>(eventType) < postError.size())
+                          ? static_cast<uint8_t>(eventType)
+                          : (postError.size() - 1);
+
+    switch (eventType)
+    {
+        case PostError::POST_PXE_BOOT_FAIL:
+        case PostError::POST_HTTP_BOOT_FAIL:
+        {
+            std::string tempLog;
+            if (failType == 4 || failType == 6)
+            {
+                tempLog = "IPv" + std::to_string(failType) + " fail";
+            }
+            else
+            {
+                tempLog = "0x" + to_hex_string(eventData[11]);
+            }
+            errorLog += "GeneralInfo: POST(0x" + to_hex_string(generalInfo) +
+                        "), POST Failure Event: " + postError[estrIdx] +
+                        ", Fail Type: " + tempLog + ", Error Code: 0x" +
+                        to_hex_string(errCode);
+            break;
+        }
+        case PostError::POST_GET_CERT_FAIL:
+        {
+            errorLog += "GeneralInfo: POST(0x" + to_hex_string(generalInfo) +
+                        "), POST Failure Event: " + postError[estrIdx] +
+                        ", Failure Detail: " + certEvent[certEventIdx];
+            break;
+        }
+        case PostError::POST_AMD_ABL_FAIL:
+        {
+            uint16_t ablErrCode = (eventData[13] << 8) | eventData[12];
+            errorLog += "GeneralInfo: POST(0x" + to_hex_string(generalInfo) +
+                        "), POST Failure Event: " + postError[estrIdx] +
+                        ", ABL Error Code: 0x" + to_hex_string(ablErrCode, 4);
+            break;
+        }
+        case PostError::POST_BOOT_DRIVE_FAIL:
+        case PostError::POST_DATA_DRIVE_FAIL:
+        case PostError::POST_CXL_NOT_READY:
+        case PostError::POST_CXL_ERR_RECORD_CLEARED_BY_BIOS:
+        {
+            errorLog += "GeneralInfo: POST(0x" + to_hex_string(generalInfo) +
+                        "), Bus " + to_hex_string(eventData[7]) + "/Dev " +
+                        to_hex_string(eventData[8] >> 3) + "/Fun " +
+                        to_hex_string(eventData[8] & 0x7) +
+                        ", POST Failure Event: " + postError[estrIdx];
+            break;
+        }
+        default:
+        {
+            errorLog += "GeneralInfo: POST(0x" + to_hex_string(generalInfo) +
+                        "), POST Failure Event: " + postError[estrIdx];
+            break;
+        }
+    }
+}
+
+} // namespace oem_meta
+} // namespace pldm
diff --git a/oem/meta/event/oem_event_manager.hpp b/oem/meta/event/oem_event_manager.hpp
new file mode 100644
index 0000000..d810e5a
--- /dev/null
+++ b/oem/meta/event/oem_event_manager.hpp
@@ -0,0 +1,181 @@
+#pragma once
+
+#define PLDM_OEM_EVENT_CLASS_0xFB 0xFB
+
+#include "oem/meta/event/types.hpp"
+#include "platform-mc/manager.hpp"
+
+#include <libpldm/base.h>
+
+namespace pldm::oem_meta
+{
+
+class OemEventManager
+{
+  public:
+    OemEventManager() = default;
+    OemEventManager(const OemEventManager&) = delete;
+    OemEventManager(OemEventManager&&) = delete;
+    OemEventManager& operator=(const OemEventManager&) = delete;
+    OemEventManager& operator=(OemEventManager&&) = delete;
+    virtual ~OemEventManager() = default;
+
+    /** @brief Handle a PLDM OEM event.
+     *
+     *  @param[in] request - The PLDM request message.
+     *  @param[in] payloadLength - The length of the PLDM request payload.
+     *  @param[in] formatVersion - The format version of the event message.
+     *  @param[in] tid - The PLDM terminal ID.
+     *  @param[in] eventDataOffset - The offset of the event data in the
+     * request.
+     *
+     *  @return 0 on success, error code on failure.
+     */
+    int handleOemEvent(const pldm_msg* request, size_t payloadLength,
+                       uint8_t /* formatVersion */, pldm_tid_t tid,
+                       size_t eventDataOffset) const;
+
+  private:
+    /** @brief Process an OEM Meta event.
+     *
+     *  @param[in] tid - The PLDM terminal ID.
+     *  @param[in] eventData - A pointer to the event data.
+     *  @param[in] eventDataSize - The size of the event data.
+     *
+     *  @return 0 on success, error code on failure.
+     */
+    int processOemMetaEvent(pldm_tid_t tid, const uint8_t* eventData,
+                            size_t eventDataSize) const;
+
+    /** @brief Handle a system event.
+     *
+     *  @param[in] eventData - A pointer to the event data.
+     *  @param[out] message - The resulting event message.
+     */
+    void handleSystemEvent(const uint8_t* eventData,
+                           std::string& message) const;
+
+    /** @brief Handle a unified BIOS event.
+     *
+     *  @param[in] eventData - A pointer to the event data.
+     *  @param[out] message - The resulting event message.
+     */
+    void handleUnifiedBIOSEvent(const uint8_t* eventData,
+                                std::string& message) const;
+
+    /** @brief Handle a memory error event.
+     *
+     *  @param[in] eventData - A pointer to the event data.
+     *  @param[out] message - The resulting event message.
+     *  @param[in] dimmInfo - Information about the DIMM.
+     *  @param[in] generalInfo - General information about the event.
+     */
+    void handleMemoryError(const uint8_t* eventData, std::string& message,
+                           const DimmInfo& dimmInfo, uint8_t generalInfo) const;
+
+    /** @brief Handle a system POST event.
+     *
+     *  @param[in] eventData - A pointer to the event data.
+     *  @param[out] message - The resulting event message.
+     *  @param[in] generalInfo - General information about the event.
+     */
+    void handleSystemPostEvent(const uint8_t* eventData, std::string& message,
+                               uint8_t generalInfo) const;
+
+    /** @brief Get the DIMM device name.
+     *
+     *  @param[in] eventData - A pointer to the event data.
+     *  @param[in] bdfIdx - The index of the BDF (Bus/Device/Function).
+     *
+     *  @return The DIMM device name.
+     */
+    std::string getDimmDeviceName(const uint8_t* eventData, int bdfIdx) const
+    {
+        std::string dimmDevName = "";
+        for (size_t i = 0; i < cxlBdfMap.size(); i++)
+        {
+            if ((eventData[bdfIdx] == cxlBdfMap[i].Bus) &&
+                ((eventData[bdfIdx + 1] >> 3) == cxlBdfMap[i].Dev) &&
+                ((eventData[bdfIdx + 1] & 0x7) == cxlBdfMap[i].Fun))
+            {
+                dimmDevName = std::string(cxlBdfMap[i].Name) + "_";
+                break;
+            }
+        }
+        return dimmDevName;
+    };
+
+    /** @brief Convert a byte to a hex string.
+     *
+     *  @param[in] value - The byte value to convert.
+     *  @param[in] len - The length of the resulting string.
+     *
+     *  @return The hex string representation of the byte.
+     */
+    inline auto to_hex_string(uint8_t value, size_t len = 2) const
+    {
+        return std::format("{:02x}", value, len);
+    }
+
+    /** @brief Convert CPU, channel, and slot to a DIMM string.
+     *
+     *  @param[in] cpu - The CPU number.
+     *  @param[in] channel - The channel number.
+     *  @param[in] slot - The slot number.
+     *  @param[out] str - The resulting DIMM string.
+     */
+    void convertToDimmString(uint8_t cpu, uint8_t channel, uint8_t slot,
+                             std::string& str) const
+    {
+        constexpr char label[] = {'A', 'C', 'B', 'D'};
+        constexpr size_t labelSize = sizeof(label);
+
+        size_t idx = cpu * 2 + slot;
+        if (idx < labelSize)
+        {
+            str = label[idx] + std::to_string(channel);
+        }
+        else
+        {
+            str = "NA";
+        }
+    }
+
+    /** @brief Get the common DIMM location string.
+     *
+     *  @param[in] dimmInfo - Information about the DIMM.
+     *  @param[out] dimmLocation - The resulting DIMM location string.
+     *  @param[out] dimm - The resulting DIMM string.
+     */
+    void getCommonDimmLocation(const DimmInfo& dimmInfo,
+                               std::string& dimmLocation,
+                               std::string& dimm) const
+    {
+        std::string sled_str = std::to_string(dimmInfo.sled);
+        std::string socket_str = std::to_string(dimmInfo.socket);
+
+        // Check Channel and Slot
+        if (dimmInfo.channel == 0xFF && dimmInfo.slot == 0xFF)
+        {
+            dimm = "unknown";
+            dimmLocation = "DIMM Slot Location: Sled " + sled_str + "/Socket " +
+                           socket_str +
+                           ", Channel unknown, Slot unknown, DIMM unknown";
+        }
+        else
+        {
+            uint8_t channel = dimmInfo.channel & 0x0F;
+            uint8_t slot = dimmInfo.slot & 0x07;
+            convertToDimmString(dimmInfo.socket, channel, slot, dimm);
+
+            std::string channel_str = std::to_string(channel);
+            std::string slot_str = std::to_string(slot);
+
+            dimmLocation = "DIMM Slot Location: Sled " + sled_str + "/Socket " +
+                           socket_str + ", Channel " + channel_str + ", Slot " +
+                           slot_str + ", DIMM " + dimm;
+        }
+    }
+};
+
+} // namespace pldm::oem_meta
diff --git a/oem/meta/event/types.hpp b/oem/meta/event/types.hpp
new file mode 100644
index 0000000..88a875f
--- /dev/null
+++ b/oem/meta/event/types.hpp
@@ -0,0 +1,243 @@
+#pragma once
+
+#include <array>
+#include <cstdint>
+
+namespace pldm::oem_meta
+{
+
+enum class RecordType : uint8_t
+{
+    SYSTEM_EVENT_RECORD = 0x02,
+    UNIFIED_BIOS_SEL = 0xFB,
+};
+
+enum class SystemError : uint8_t
+{
+    SYSTEM_PROCESSOR_ERR = 0x7,
+    SYSTEM_POST_ERR = 0x2B,
+    SYSTEM_CXL_ERR = 0xC1,
+    SYSTEM_CXL_ERR_2_0 = 0xC2,
+};
+
+enum class CxlError : uint8_t
+{
+    PROTOCOL_ERR = 0x1,
+    COMPONENT_ERR = 0x2
+};
+
+enum class CxlError2 : uint8_t
+{
+    PROTOCOL_ERR = 0x1,
+    COMPONENT_ERR = 0x2
+};
+
+enum class ProcessorError : uint8_t
+{
+    MACHINE_CHK_ERR = 0x40,
+};
+
+enum class ProcessorSeverity : uint8_t
+{
+    UNCORRECT_SYSTEM_FATAL_ERR = 0xB,
+    CORRECTABLE_SYSTEM_ERR = 0xC,
+};
+
+enum class UnifiedError : uint8_t
+{
+    UNIFIED_PCIE_ERR = 0x0,
+    UNIFIED_MEM_ERR = 0x1,
+    UNIFIED_UPI_ERR = 0x2,
+    UNIFIED_IIO_ERR = 0x3,
+    UNIFIED_MCA_ERR = 0x4,
+    UNIFIED_MCA_ERR_EXT = 0x5,
+    UNIFIED_RP_PIO_1st = 0x6,
+    UNIFIED_RP_PIO_2nd = 0x7,
+    UNIFIED_POST_EVENT = 0x8,
+    UNIFIED_PCIE_EVENT = 0x9,
+    UNIFIED_MEM_EVENT = 0xA,
+    UNIFIED_UPI_EVENT = 0xB,
+    UNIFIED_BOOT_GUARD = 0xC,
+    UNIFIED_PPR_EVENT = 0xD,
+    UNIFIED_CXL_MEM_ERR = 0xE,
+};
+
+enum class MemoryError : uint8_t
+{
+    MEMORY_TRAINING_ERR = 0x0,
+    MEMORY_CORRECTABLE_ERR = 0x1,
+    MEMORY_UNCORRECTABLE_ERR = 0x2,
+    MEMORY_CORR_ERR_PTRL_SCR = 0x3,
+    MEMORY_UNCORR_ERR_PTRL_SCR = 0x4,
+    MEMORY_PARITY_ERR_PCC0 = 0x5,
+    MEMORY_PARITY_ERR_PCC1 = 0x6,
+    MEMORY_PMIC_ERR = 0x7,
+    MEMORY_CXL_TRAINNING_ERR = 0x8,
+    MEMORY_CXL_MEM_SPD_CRC_ERR = 0x9,
+    MEMORY_CXL_MEM_SPD_NULL_DATA_ERR = 0xA,
+    MEMORY_CXL_MEM_INIT_TIMEOUT_ERR = 0xB,
+};
+
+enum class PostError : uint8_t
+{
+    POST_PXE_BOOT_FAIL = 0x0,
+    POST_CMOS_CLEARED = 0x1,
+    POST_TPM_SELF_TEST_FAIL = 0x2,
+    POST_BOOT_DRIVE_FAIL = 0x3,
+    POST_DATA_DRIVE_FAIL = 0x4,
+    POST_INVALID_BOOT_ORDER = 0x5,
+    POST_HTTP_BOOT_FAIL = 0x6,
+    POST_GET_CERT_FAIL = 0x7,
+    POST_PASSWD_CLEARED_BY_JUMPER = 0x8,
+    POST_DXE_FV_CHK_FAIL = 0x9,
+    POST_AMD_ABL_FAIL = 0xA,
+    POST_DRAM_PAGE_RETIRED = 0xB,
+    POST_DRAM_CHANNEL_RETIRED = 0xC,
+    POST_CXL_NOT_READY = 0xD,
+    POST_CXL_ERR_RECORD_CLEARED_BY_BIOS = 0xE,
+};
+
+enum class PcieEvent : uint8_t
+{
+    PCIE_DPC = 0x0,
+};
+
+enum class MemoryEvent : uint8_t
+{
+    MEM_PPR = 0x0,
+    MEM_ADDDC = 0x5,
+    MEM_NO_DIMM = 0x7,
+    MEM_CXL_POST_PPR = 0x8,
+};
+
+enum class UpiError : uint8_t
+{
+    UPI_INIT_ERR = 0x0,
+};
+
+static constexpr auto errorSeverityDetail = std::to_array(
+    {"Correctable Error", "Deferred Error", "Uncorrected Recoverable Error",
+     "Uncorrected Thread Fatal Error", "Uncorrected System Fatal Error"});
+
+static constexpr auto machineCheckBank = std::to_array(
+    {"LS",
+     "IF",
+     "L2",
+     "DE",
+     "RAZ",
+     "EX",
+     "FP",
+     "L3",
+     "L3",
+     "L3",
+     "L3",
+     "L3",
+     "L3",
+     "L3",
+     "L3",
+     "MP5",
+     "PCS_GMI",
+     "PCS_GMI",
+     "KPX_GMI",
+     "KPX_GMI",
+     "MPDMA",
+     "UMC",
+     "UMC",
+     "CS/RAZ",
+     "CS/RAZ",
+     "PCIE",
+     "SATA/USB/PCIE",
+     "NBIF",
+     "PIE/PSP/KPX_WALF/NBIF/USB/RAZ",
+     "SMU/SHUB",
+     "PIE/PSP/PCS_XGMI",
+     "KPX_SERDES/RAZ"});
+
+static constexpr auto memoryError = std::to_array(
+    {"Memory training failure", "Memory correctable error",
+     "Memory uncorrectable error", "Memory correctable error (Patrol scrub)",
+     "Memory uncorrectable error (Patrol scrub)", "Memory Parity Error (PCC=0)",
+     "Memory Parity Error (PCC=1)", "Memory PMIC Error",
+     "CXL Memory training error", "CXL Memory SPD CRC error",
+     "CXL Memory SPD NULL DATA error", "CXL Memory initialized timeout error",
+     "Reserved"});
+
+static constexpr auto certEvent =
+    std::to_array({"No certificate at BMC", "IPMI transaction fail",
+                   "Certificate data corrupted", "Reserved"});
+
+static constexpr auto postError = std::to_array(
+    {"System PXE boot fail", "CMOS/NVRAM configuration cleared",
+     "TPM Self-Test Fail", "Boot Drive failure", "Data Drive failure",
+     "Received invalid boot order request from BMC", "System HTTP boot fail",
+     "BIOS fails to get the certificate from BMC", "Password cleared by jumper",
+     "DXE FV check failure", "AMD ABL failure", "DRAM Page Retired",
+     "DRAM Channel Retired", "CXL not ready",
+     "CXL error record cleared by BIOS", "Reserved"});
+
+static constexpr auto cxlError = std::to_array(
+    {"CXL_ELOG_IO", "CXL_ELOG_CACHE_MEM", "CXL_ELOG_COMPONENT_EVENT",
+     "Reserved"});
+
+static constexpr auto pcieEvent = std::to_array(
+    {"PCIe DPC Event", "PCIe LER Event", "PCIe Link Retraining and Recovery",
+     "PCIe Link CRC Error Check and Retry", "PCIe Corrupt Data Containment",
+     "PCIe Express ECRC", "Reserved"});
+
+static constexpr auto memoryEvent = std::to_array(
+    {"Memory PPR event", "Memory Correctable Error logging limit reached",
+     "Memory disable/map-out for FRB", "Memory SDDC",
+     "Memory Address range/Partial mirroring", "Memory ADDDC",
+     "Memory SMBus hang recovery", "No DIMM in System", "CXL POST PPR event",
+     "Reserved"});
+
+static constexpr auto memoryPprRepairTime =
+    std::to_array({"Boot time", "Autonomous", "Run time", "Reserved"});
+
+static constexpr auto memoryPprEvent =
+    std::to_array({"PPR success", "PPR fail", "PPR request", "Reserved"});
+
+static constexpr auto memoryCXLPostPprEvent =
+    std::to_array({"PPR success", "PPR full"});
+
+static constexpr auto memoryAdddcEvent =
+    std::to_array({"Bank VLS", "r-Bank VLS + re-buddy", "r-Bank VLS + Rank VLS",
+                   "r-Rank VLS + re-buddy"});
+
+static constexpr auto upiEvent = std::to_array(
+    {"Successful LLR without Phy Reinit", "Successful LLR with Phy Reinit",
+     "COR Phy Lane failure, recovery in x8 width", "Reserved"});
+
+static constexpr auto pprEvent =
+    std::to_array({"PPR disable", "Soft PPR", "Hard PPR"});
+
+static constexpr auto upiError = std::to_array({"UPI Init error", "Reserved"});
+
+static constexpr auto memoryCxlEvent =
+    std::to_array({"DIMM A0", "DIMM B0", "DIMM A1", "DIMM B1", "Unknown"});
+
+struct DimmInfo
+{
+    uint8_t sled;
+    uint8_t socket;
+    uint8_t channel;
+    uint8_t slot;
+};
+
+struct BdfInfo
+{
+    uint8_t Bus;
+    uint8_t Dev;
+    uint8_t Fun;
+    const char* Name;
+};
+
+static constexpr auto cxlBdfMap = std::to_array<BdfInfo>(
+    {// Before Y4401D BIOS
+     {0xA9, 0x00, 0x00, "MCIO3"},
+     {0xD3, 0x00, 0x00, "MCIO4"},
+     // After Y4401D BIOS
+     {0xA1, 0x00, 0x00, "MCIO3"},
+     {0xC1, 0x00, 0x00, "MCIO4"}});
+
+} // namespace pldm::oem_meta
diff --git a/oem/meta/meson.build b/oem/meta/meson.build
index e0b0da2..13d3a8e 100644
--- a/oem/meta/meson.build
+++ b/oem/meta/meson.build
@@ -1 +1,3 @@
-oem_files += files('utils.cpp')
+oem_files += files('oem_meta.cpp', 'utils.cpp')
+
+subdir('event')
diff --git a/oem/meta/oem_meta.cpp b/oem/meta/oem_meta.cpp
new file mode 100644
index 0000000..540b334
--- /dev/null
+++ b/oem/meta/oem_meta.cpp
@@ -0,0 +1,27 @@
+
+#include "oem_meta.hpp"
+
+#include <libpldm/base.h>
+
+namespace pldm::oem_meta
+{
+
+OemMETA::OemMETA(pldm::responder::platform::Handler* platformHandler)
+{
+    oemEventManager = std::make_unique<oem_meta::OemEventManager>();
+    registerOemEventHandler(platformHandler);
+}
+
+void OemMETA::registerOemEventHandler(
+    pldm::responder::platform::Handler* platformHandler)
+{
+    platformHandler->registerEventHandlers(
+        PLDM_OEM_EVENT_CLASS_0xFB,
+        {[this](const pldm_msg* request, size_t payloadLength,
+                uint8_t formatVersion, pldm_tid_t tid, size_t eventDataOffset) {
+            return this->oemEventManager->handleOemEvent(
+                request, payloadLength, formatVersion, tid, eventDataOffset);
+        }});
+}
+
+} // namespace pldm::oem_meta
diff --git a/oem/meta/oem_meta.hpp b/oem/meta/oem_meta.hpp
index dfcf4aa..266a8bf 100644
--- a/oem/meta/oem_meta.hpp
+++ b/oem/meta/oem_meta.hpp
@@ -1,5 +1,8 @@
 #pragma once
 
+#include "libpldmresponder/platform.hpp"
+#include "oem/meta/event/oem_event_manager.hpp"
+
 namespace pldm::oem_meta
 {
 
@@ -13,11 +16,23 @@
 class OemMETA
 {
   public:
-    OemMETA() = default;
+    OemMETA() = delete;
     OemMETA(const OemMETA&) = delete;
     OemMETA& operator=(const OemMETA&) = delete;
     OemMETA(OemMETA&&) = delete;
     OemMETA& operator=(OemMETA&&) = delete;
+
+  public:
+    /** @brief Constucts OemMETA object
+     *  @param[in] platformHandler - platformHandler handler
+     */
+    explicit OemMETA(pldm::responder::platform::Handler* platformHandler);
+
+  private:
+    void registerOemEventHandler(
+        pldm::responder::platform::Handler* platformHandler);
+
+    std::unique_ptr<oem_meta::OemEventManager> oemEventManager{};
 };
 
 } // namespace pldm::oem_meta