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