platform: Add decode_pldm_cper_event_data() API
Support decoder for `cperEvent` event class as table `Table 27 -
CPEREvent class eventData format` in DSP0248 V1.3.0.
Change-Id: I6165980e0570bbb21158af9e6adee15894b3bf3a
Signed-off-by: Thu Nguyen <thu@os.amperecomputing.com>
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 172f604..9665996 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -26,6 +26,7 @@
5. pdr: Add pldm_pdr_get_terminus_handle() API
6. pdr: Add related decode_entity_auxiliary_names_pdr() APIs
7. fw_update: Add encode req & decode resp for get_downstream_fw_params
+8. platform: Add decode_pldm_platform_cper_event_data() API
### Changed
diff --git a/include/libpldm/platform.h b/include/libpldm/platform.h
index 159e514..589970f 100644
--- a/include/libpldm/platform.h
+++ b/include/libpldm/platform.h
@@ -13,6 +13,7 @@
#include <uchar.h>
#include <libpldm/base.h>
+#include <libpldm/compiler.h>
#include <libpldm/pdr.h>
#include <libpldm/pldm_types.h>
@@ -74,6 +75,8 @@
/* Minimum length of sensor event data */
#define PLDM_MSG_POLL_EVENT_LENGTH 7
+/* Minimum data length of CPER event type */
+#define PLDM_PLATFORM_CPER_EVENT_MIN_LENGTH 4
/* Minimum length of sensor event data */
#define PLDM_SENSOR_EVENT_DATA_MIN_LENGTH 5
@@ -280,7 +283,8 @@
PLDM_REDFISH_MESSAGE_EVENT = 0x03,
PLDM_PDR_REPOSITORY_CHG_EVENT = 0x04,
PLDM_MESSAGE_POLL_EVENT = 0x05,
- PLDM_HEARTBEAT_TIMER_ELAPSED_EVENT = 0x06
+ PLDM_HEARTBEAT_TIMER_ELAPSED_EVENT = 0x06,
+ PLDM_CPER_EVENT = 0x07
};
/** @brief PLDM sensorEventClass states
@@ -1143,6 +1147,25 @@
uint32_t data_transfer_handle;
};
+/** @struct pldm_platform_cper_event
+ *
+ * structure representing cperEvent fields
+ */
+struct pldm_platform_cper_event {
+ uint8_t format_version;
+ uint8_t format_type;
+ uint16_t event_data_length;
+#ifndef __cplusplus
+ uint8_t event_data[] LIBPLDM_CC_COUNTED_BY(event_data_length);
+#endif
+};
+
+/** @brief PLDM CPER event format type */
+enum pldm_platform_cper_event_format {
+ PLDM_PLATFORM_CPER_EVENT_WITH_HEADER = 0x00,
+ PLDM_PLATFORM_CPER_EVENT_WITHOUT_HEADER = 0x01
+};
+
/** @struct pldm_platform_event_message_req
*
* structure representing PlatformEventMessage command request data
@@ -2428,6 +2451,26 @@
*/
int decode_pldm_entity_auxiliary_names_pdr_index(
struct pldm_entity_auxiliary_names_pdr *pdr_value);
+
+/** @brief Decode PLDM Platform CPER event data type
+ *
+ * @param[in] event_data - event data from the response message
+ * @param[in] event_data_length - length of the event data
+ * @param[out] cper_event - the decoded pldm_platform_cper_event struct
+ * @param[in] cper_event_length - the length of cper event
+ * @return error code
+ */
+int decode_pldm_platform_cper_event_data(
+ const void *event_data, size_t event_data_length,
+ struct pldm_platform_cper_event *cper_event, size_t cper_event_length);
+
+/** @brief Helper function to response CPER event event data
+ *
+ * @param[in] cper_event - the decoded pldm_platform_cper_event struct
+ * @return cper event event data array pointer
+ */
+uint8_t *
+pldm_platform_cper_event_event_data(struct pldm_platform_cper_event *event);
#ifdef __cplusplus
}
#endif
diff --git a/src/dsp/platform.c b/src/dsp/platform.c
index f826f3c..9439e12 100644
--- a/src/dsp/platform.c
+++ b/src/dsp/platform.c
@@ -2856,3 +2856,60 @@
return pldm_msgbuf_destroy_consumed(buf);
}
+
+LIBPLDM_ABI_TESTING
+int decode_pldm_platform_cper_event_data(
+ const void *event_data, size_t event_data_length,
+ struct pldm_platform_cper_event *cper_event, size_t cper_event_length)
+{
+ struct pldm_msgbuf _buf;
+ struct pldm_msgbuf *buf = &_buf;
+ int rc;
+
+ if (!cper_event || !event_data) {
+ return -EINVAL;
+ }
+
+ if (cper_event_length < sizeof(*cper_event)) {
+ return -EINVAL;
+ }
+
+ rc = pldm_msgbuf_init_errno(buf, PLDM_PLATFORM_CPER_EVENT_MIN_LENGTH,
+ event_data, event_data_length);
+ if (rc) {
+ return rc;
+ }
+
+ pldm_msgbuf_extract(buf, cper_event->format_version);
+ rc = pldm_msgbuf_extract(buf, cper_event->format_type);
+ if (rc) {
+ return rc;
+ }
+ if (cper_event->format_type != PLDM_PLATFORM_CPER_EVENT_WITH_HEADER &&
+ cper_event->format_type !=
+ PLDM_PLATFORM_CPER_EVENT_WITHOUT_HEADER) {
+ return -EPROTO;
+ }
+
+ rc = pldm_msgbuf_extract(buf, cper_event->event_data_length);
+ if (rc) {
+ return rc;
+ }
+
+ if (cper_event->event_data_length >
+ (cper_event_length - sizeof(*cper_event))) {
+ return -EOVERFLOW;
+ }
+
+ pldm_msgbuf_extract_array_uint8(buf, cper_event->event_data,
+ cper_event->event_data_length);
+
+ return pldm_msgbuf_destroy_consumed(buf);
+}
+
+LIBPLDM_ABI_TESTING
+uint8_t *
+pldm_platform_cper_event_event_data(struct pldm_platform_cper_event *event)
+{
+ return event->event_data;
+}
diff --git a/tests/dsp/platform.cpp b/tests/dsp/platform.cpp
index f5ae4fd..dfc5506 100644
--- a/tests/dsp/platform.cpp
+++ b/tests/dsp/platform.cpp
@@ -5190,3 +5190,125 @@
EXPECT_EQ(-EBADMSG, rc);
free(decodedPdr);
}
+
+#ifdef LIBPLDM_API_TESTING
+TEST(PlatformEventMessage, testGoodCperEventDataDecodeRequest)
+{
+ constexpr const size_t eventDataSize = 4;
+ constexpr const size_t eventSize =
+ PLDM_PLATFORM_CPER_EVENT_MIN_LENGTH + eventDataSize;
+ std::array<uint8_t, eventSize> eventData{
+ 0x1, // format version
+ 0x0, // format type
+ 0x4, 0x0, // event data length
+ 0x44, 0x33, 0x22, 0x11 // data
+ };
+
+ uint8_t expectedFormatVersion = 1;
+ uint8_t expectedFormatType = 0;
+ uint16_t expectedEventDataLength = 4;
+ uint8_t expectCperEventData[] = {0x44, 0x33, 0x22, 0x11};
+
+ size_t cperEventSize =
+ sizeof(struct pldm_platform_cper_event) + eventDataSize;
+ auto cper_event = reinterpret_cast<struct pldm_platform_cper_event*>(
+ malloc(cperEventSize));
+
+ auto rc = decode_pldm_platform_cper_event_data(
+ reinterpret_cast<const void*>(eventData.data()), eventData.size(),
+ cper_event, cperEventSize);
+
+ EXPECT_EQ(rc, 0);
+ EXPECT_EQ(cper_event->format_version, expectedFormatVersion);
+ EXPECT_EQ(cper_event->format_type, expectedFormatType);
+ EXPECT_EQ(cper_event->event_data_length, expectedEventDataLength);
+
+ auto cperEventData = pldm_platform_cper_event_event_data(cper_event);
+ EXPECT_NE(cperEventData, nullptr);
+ if (cperEventData)
+ {
+ EXPECT_EQ(0, memcmp(expectCperEventData, cperEventData,
+ expectedEventDataLength));
+ }
+
+ free(cper_event);
+}
+#endif
+
+#ifdef LIBPLDM_API_TESTING
+TEST(PlatformEventMessage, testBadCperEventDataDecodeRequest)
+{
+
+ constexpr const size_t eventDataSize = 4;
+ constexpr const size_t eventSize =
+ PLDM_PLATFORM_CPER_EVENT_MIN_LENGTH + eventDataSize;
+ std::array<uint8_t, eventSize> eventData{
+ 0x1, // format version
+ 0x0, // format type
+ 0x4, 0x0, // event data length
+ 0x44, 0x33, 0x22, 0x11 // data
+ };
+
+ size_t cperEventSize =
+ sizeof(struct pldm_platform_cper_event) + eventDataSize;
+ auto cperEvent = reinterpret_cast<struct pldm_platform_cper_event*>(
+ malloc(cperEventSize));
+
+ auto rc = decode_pldm_platform_cper_event_data(NULL, eventData.size(),
+ cperEvent, cperEventSize);
+ EXPECT_EQ(rc, -EINVAL);
+
+ rc = decode_pldm_platform_cper_event_data(
+ reinterpret_cast<const void*>(eventData.data()), eventData.size(), NULL,
+ cperEventSize);
+ EXPECT_EQ(rc, -EINVAL);
+
+#ifdef NDEBUG
+ rc = decode_pldm_platform_cper_event_data(
+ reinterpret_cast<uint8_t*>(eventData.data()), eventData.size() - 1,
+ cperEvent, cperEventSize);
+ EXPECT_EQ(rc, -EBADMSG);
+#else
+ EXPECT_DEATH(decode_pldm_platform_cper_event_data(
+ reinterpret_cast<uint8_t*>(eventData.data()),
+ eventData.size() - 1, cperEvent, cperEventSize),
+ "ctx->remaining >= 0");
+#endif
+
+ rc = decode_pldm_platform_cper_event_data(
+ reinterpret_cast<uint8_t*>(eventData.data()), eventData.size(),
+ cperEvent, cperEventSize - 1);
+ EXPECT_EQ(rc, -EOVERFLOW);
+
+ rc = decode_pldm_platform_cper_event_data(
+ reinterpret_cast<uint8_t*>(eventData.data()), eventData.size(),
+ cperEvent, cperEventSize + 1);
+ EXPECT_EQ(rc, 0);
+
+ // Invalid CPER Event Format Type
+ eventData[1] = 0x2;
+ rc = decode_pldm_platform_cper_event_data(
+ reinterpret_cast<const void*>(eventData.data()), eventData.size(),
+ cperEvent, cperEventSize);
+
+ EXPECT_EQ(rc, -EPROTO);
+
+ // Invalid cper event data size
+ eventData[1] = 0x1;
+ eventData[2] = 3;
+ rc = decode_pldm_platform_cper_event_data(
+ reinterpret_cast<const void*>(eventData.data()), eventData.size(),
+ cperEvent, cperEventSize);
+
+ EXPECT_EQ(rc, -EBADMSG);
+
+ eventData[2] = 5;
+ rc = decode_pldm_platform_cper_event_data(
+ reinterpret_cast<const void*>(eventData.data()), eventData.size(),
+ cperEvent, cperEventSize);
+
+ EXPECT_EQ(rc, -EOVERFLOW);
+
+ free(cperEvent);
+}
+#endif