[Skiboot] [PATCH 5/8] core/pldm/test : Add tests for PLDM platform PDR requests
ABHISHEK SINGH TOMAR
abhishek.singh.tomar1 at ibm.com
Thu Feb 20 20:34:52 AEDT 2025
From: Abhishek Singh Tomar <abhishek at linux.ibm.com>
Introduce tests for the PLDM platform initialization
implementation and the retrieval of PDR records from the
table.
These tests validate the following platform commands:
1. PLDM_PLATFORM_EVENT_MESSAGE
2. PLDM_GET_PDR
Signed-off-by: Abhishek Singh Tomar <abhishek at linux.ibm.com>
---
core/pldm/test/Makefile.check | 3 +-
core/pldm/test/test-pldm-platform.c | 552 ++++++++++++++++++++++++++++
2 files changed, 554 insertions(+), 1 deletion(-)
create mode 100644 core/pldm/test/test-pldm-platform.c
diff --git a/core/pldm/test/Makefile.check b/core/pldm/test/Makefile.check
index b7df9e504..10a1752c0 100644
--- a/core/pldm/test/Makefile.check
+++ b/core/pldm/test/Makefile.check
@@ -1,6 +1,7 @@
# -*-Makefile-*-
CUR_DIR := core/pldm/test/
-PLDM_TEST := core/pldm/test/test-pldm-fileio-bios
+PLDM_TEST := core/pldm/test/test-pldm-fileio-bios \
+ core/pldm/test/test-pldm-platform
LCOV_EXCLUDE += $(PLDM_TEST:%=%.c)
.PHONY : core-pldm-check core-pldm-coverage
diff --git a/core/pldm/test/test-pldm-platform.c b/core/pldm/test/test-pldm-platform.c
new file mode 100644
index 000000000..212107c2a
--- /dev/null
+++ b/core/pldm/test/test-pldm-platform.c
@@ -0,0 +1,552 @@
+// SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later
+// Copyright 2024 IBM Corp.
+
+#include "test-pldm-common.c"
+
+#define STATESENSOR_RECORD_HANDLE 116
+
+#define EFFECTER1_RECORD_HANDLE 120
+#define EFFECTER2_RECORD_HANDLE 160
+
+enum platform_special_case_code {
+ NORMAL_CASE = 0x00,
+ PDR_REPLY_ERROR = 0x02,
+ PLATFORM_EVENT_ERROR = 0x03
+};
+
+enum platform_special_case_code platform_special_case = NORMAL_CASE;
+
+/*
+ * These structure duplicates BMC functionality for Pldm self test
+ * It include PDR entry to be send on behalf of BMC
+ */
+struct pldm_state_sensor_pdr sensor_test_0 = {
+ .hdr = {
+ .record_handle = STATESENSOR_RECORD_HANDLE
+ },
+ .terminus_handle = 1,
+ .sensor_id = 3,
+ .entity_type = PLDM_ENTITY_SLOT,
+ .entity_instance = 1,
+ .container_id = 4,
+ .sensor_init = 0,
+ .sensor_auxiliary_names_pdr = false,
+ .composite_sensor_count = 1
+};
+struct state_sensor_possible_states possible_states_sensor_0_test = {
+ .state_set_id = 3222,
+ .possible_states_size = 1,
+ .states = {
+ {.byte = 1}
+ }
+
+};
+
+
+/*
+ * These structure duplicates BMC functionality for Pldm self test
+ * It include PDR entry to be send on behalf of BMC
+ */
+struct pldm_state_effecter_pdr effecter_test_1 = {
+ .hdr = {
+ .record_handle = EFFECTER1_RECORD_HANDLE
+ },
+ .terminus_handle = 1,
+ .effecter_id = 38,
+ .entity_type = PLDM_ENTITY_SYS_FIRMWARE,
+ .entity_instance = 1,
+ .container_id = 1,
+ .effecter_semantic_id = 0,
+ .effecter_init = 0,
+ .has_description_pdr = 0,
+ .composite_effecter_count = 1
+};
+struct state_effecter_possible_states possible_states_effecter_1_test = {
+ .state_set_id = PLDM_STATE_SET_SW_TERMINATION_STATUS,
+ .possible_states_size = 1,
+ .states = {
+ {.byte = PLDM_SW_TERM_GRACEFUL_RESTART_REQUESTED}
+ }
+
+};
+
+
+/*
+ * These structure duplicates BMC functionality for Pldm self test
+ * It include PDR entry to be send on behalf of BMC
+ */
+struct pldm_state_effecter_pdr effecter_test_2 = {
+ .hdr = {
+ .record_handle = EFFECTER2_RECORD_HANDLE
+ },
+ .terminus_handle = 1,
+ .effecter_id = 31,
+ .entity_type = PLDM_ENTITY_SYSTEM_CHASSIS,
+ .entity_instance = 1,
+ .container_id = 1,
+ .effecter_semantic_id = 0,
+ .effecter_init = 0,
+ .has_description_pdr = 0,
+ .composite_effecter_count = 1
+};
+struct state_effecter_possible_states possible_states_effecter_2_test = {
+ .state_set_id = PLDM_STATE_SET_SYSTEM_POWER_STATE,
+ .possible_states_size = 1,
+ .states = {
+ {.byte = PLDM_STATE_SET_SYS_POWER_STATE_OFF_SOFT_GRACEFUL}
+ }
+};
+
+
+/*
+ * This function duplicates BMC functionality for Pldm self test
+ * It will handle pldm response message
+ * For now we don't have any response
+ */
+int pldm_test_verify_response(void *response_msg, size_t response_len)
+{
+ if (response_len > 0 || response_msg != NULL)
+ return OPAL_PARAMETER;
+ return OPAL_PARAMETER;
+
+}
+
+
+int encode_test_state_sensor_pdr(
+ struct pldm_state_sensor_pdr *sensor_test,
+ struct state_sensor_possible_states
+ *possible_states_sensor_test,
+ uint8_t **pdr, size_t *pdr_size)
+{
+ size_t possible_states_size = 0;
+ int rc;
+
+ /* calculate sizeof whole struct */
+ *pdr_size = sizeof(struct pldm_state_sensor_pdr)
+ + sizeof(struct state_sensor_possible_states) - 1;
+ *pdr = malloc(*pdr_size);
+ if (*pdr == NULL) {
+ perror("PLDM_TEST malloc");
+ return OPAL_RESOURCE;
+ }
+ memset(*pdr, 0, *pdr_size);
+
+ memcpy(*pdr, sensor_test, sizeof(struct pldm_state_sensor_pdr));
+
+ /* For PLDM Test consider only 1 possible state */
+ possible_states_size = sizeof(struct state_sensor_possible_states)
+ + possible_states_sensor_test->possible_states_size - 1;
+
+ rc = encode_state_sensor_pdr(
+ (struct pldm_state_sensor_pdr *)(*pdr),
+ *pdr_size,
+ possible_states_sensor_test,
+ possible_states_size, pdr_size);
+ if (rc != PLDM_SUCCESS)
+ return rc;
+ return OPAL_SUCCESS;
+}
+
+
+int encode_test_state_effector_pdr(
+ struct pldm_state_effecter_pdr *effecter_test,
+ struct state_effecter_possible_states
+ *possible_states_effecter_test,
+ uint8_t **pdr, size_t *pdr_size)
+{
+ size_t possible_states_size = 0;
+ int rc;
+
+ /* calculate sizeof whole struct */
+ *pdr_size = sizeof(struct pldm_state_effecter_pdr)
+ + sizeof(struct state_effecter_possible_states) - 1;
+ *pdr = malloc(*pdr_size);
+ if (*pdr == NULL) {
+ perror("PLDM_TEST malloc");
+ return OPAL_RESOURCE;
+ }
+
+ memcpy(*pdr, effecter_test, sizeof(struct pldm_state_effecter_pdr));
+
+ /* For PLDM Test consider only 1 possible state */
+ possible_states_size = sizeof(struct state_effecter_possible_states)
+ + possible_states_effecter_test->possible_states_size - 1;
+
+ rc = encode_state_effecter_pdr(
+ (struct pldm_state_effecter_pdr *)(*pdr),
+ *pdr_size, possible_states_effecter_test,
+ possible_states_size, pdr_size);
+ if (rc != PLDM_SUCCESS)
+ return rc;
+ return OPAL_SUCCESS;
+}
+
+/*
+ * This function duplicates BMC functionality for Pldm self test
+ * This generate pdr entry for self test
+ */
+int get_test_pdr_entry(uint32_t record_hndl, uint8_t **pdr,
+ size_t *pdr_len, uint32_t *next_record_hndl)
+{
+ int rc;
+
+ if (record_hndl == 0 || record_hndl == sensor_test_0.hdr.record_handle) {
+ rc = encode_test_state_sensor_pdr(
+ &sensor_test_0,
+ &possible_states_sensor_0_test,
+ pdr, pdr_len);
+ if (rc != PLDM_SUCCESS)
+ return rc;
+ /*
+ * if record_handle is equal to first record handle or 0
+ * then encode next data transfer handle with 1st record handle
+ */
+ *next_record_hndl = effecter_test_1.hdr.record_handle;
+
+
+ } else if (record_hndl == effecter_test_1.hdr.record_handle) {
+
+ rc = encode_test_state_effector_pdr(
+ &effecter_test_1,
+ &possible_states_effecter_1_test,
+ pdr, pdr_len);
+ if (rc != PLDM_SUCCESS)
+ return rc;
+ *next_record_hndl = effecter_test_2.hdr.record_handle;
+
+
+ } else if (record_hndl == effecter_test_2.hdr.record_handle) {
+ rc = encode_test_state_effector_pdr(
+ &effecter_test_2,
+ &possible_states_effecter_2_test,
+ pdr, pdr_len);
+ if (rc != PLDM_SUCCESS)
+ return rc;
+ /*
+ * if record_handle is equal to last record handle
+ * the encode next data transfer handle with 0
+ */
+ *next_record_hndl = 0;
+ } else
+ return OPAL_PARAMETER;
+
+ return OPAL_SUCCESS;
+
+}
+
+
+/*
+ * This function duplicates BMC functionality for Pldm self test
+ * it handle PLDM_REQUEST for PLDM_PLATFORM and reply with appropriate
+ * PLDM_RESPONSE message
+ */
+int pldm_test_reply_request_platform(void *request_msg, size_t request_len,
+ void **response_msg, size_t *response_len)
+{
+ uint8_t *pdr = NULL;
+ size_t pdr_len;
+ int rc = 0;
+ int payload_len = 0, completion_code = PLDM_SUCCESS;
+ uint32_t transfer_handle;
+ uint8_t transfer_opflag;
+ uint16_t request_cnt;
+ uint16_t record_chg_num;
+ uint32_t record_hndl;
+ uint8_t format_version, tid, event_class;
+ size_t event_data_offset;
+ uint32_t next_record_hndl;
+
+ /* check pldm command received and reply with appropriate pldm response message */
+ switch (((struct pldm_msg *)request_msg)->hdr.command) {
+ case PLDM_GET_PDR:
+ payload_len = request_len - sizeof(struct pldm_msg_hdr);
+ rc = decode_get_pdr_req(request_msg, payload_len, &record_hndl, &transfer_handle,
+ &transfer_opflag, &request_cnt, &record_chg_num);
+ if (rc != PLDM_SUCCESS)
+ return rc;
+
+ /* Get pdr entry for self test */
+ rc = get_test_pdr_entry(record_hndl, &pdr,
+ &pdr_len, &next_record_hndl);
+ if (rc != OPAL_SUCCESS)
+ return rc;
+
+ payload_len = (sizeof(struct pldm_get_pdr_resp) - 1)
+ + pdr_len;
+ *response_len = sizeof(struct pldm_msg_hdr)
+ + payload_len;
+
+ *response_msg = malloc(*response_len);
+ if (*response_msg == NULL) {
+ perror("PLDM_TEST malloc");
+ return OPAL_RESOURCE;
+ }
+
+ /*
+ * Check if special testcase to reply with
+ * error completion code.
+ */
+ if (platform_special_case == PDR_REPLY_ERROR)
+ completion_code = PLDM_ERROR;
+
+ rc = encode_get_pdr_resp(
+ ((struct pldm_msg *)request_msg)->hdr.instance_id,
+ completion_code, next_record_hndl,
+ PLDM_GET_NEXTPART, PLDM_START_AND_END,
+ pdr_len, pdr, 0, *response_msg);
+ if (rc != PLDM_SUCCESS)
+ return OPAL_PARAMETER;
+
+ free(pdr);
+ break;
+
+ case PLDM_PLATFORM_EVENT_MESSAGE:
+ payload_len = request_len - sizeof(struct pldm_msg_hdr);
+ rc = decode_platform_event_message_req(request_msg, payload_len, &format_version,
+ &tid, &event_class, &event_data_offset);
+ if (rc != PLDM_SUCCESS)
+ return OPAL_PARAMETER;
+
+ /* Test: if tid and event class same as that expected */
+ if (tid != HOST_TID || event_class != PLDM_PDR_REPOSITORY_CHG_EVENT)
+ return OPAL_PARAMETER;
+
+ *response_len = sizeof(struct pldm_msg_hdr) +
+ sizeof(struct pldm_platform_event_message_resp);
+ *response_msg = malloc(*response_len);
+ if (*response_msg == NULL) {
+ perror("PLDM_TEST malloc");
+ return OPAL_RESOURCE;
+ }
+
+
+ /*
+ * Check if special testcase to reply with
+ * error completion code.
+ */
+ if (platform_special_case == PLATFORM_EVENT_ERROR)
+ completion_code = PLDM_ERROR;
+ rc = encode_platform_event_message_resp(
+ ((struct pldm_msg *)request_msg)->hdr.instance_id,
+ completion_code, 0, *response_msg);
+ if (rc != PLDM_SUCCESS)
+ return OPAL_PARAMETER;
+
+ return PLDM_SUCCESS;
+
+ default:
+ return OPAL_PARAMETER;
+
+ }
+
+ return OPAL_SUCCESS;
+
+}
+
+
+int ast_mctp_message_tx(bool tag_owner __unused, uint8_t msg_tag __unused,
+ uint8_t *msg, int len)
+{
+ int rc;
+ uint8_t *pldm_received_msg = msg+1;
+ void *response_msg;
+ size_t response_len;
+
+ /* TEST Message TYPE: PLDM = 0x01 (000_0001b) as per MCTP - DSP0240 */
+ if (msg[0] != 0x01)
+ return OPAL_PARAMETER;
+
+ if (((struct pldm_msg *)pldm_received_msg)->hdr.request == PLDM_RESPONSE)
+ return OPAL_PARAMETER;
+
+ /* Reply to requests */
+ else if (((struct pldm_msg *)pldm_received_msg)->hdr.request == PLDM_REQUEST) {
+ rc = pldm_test_reply_request_platform(pldm_received_msg, len-1,
+ &response_msg, &response_len);
+ if (rc != OPAL_SUCCESS)
+ return rc;
+
+ if (response_len <= 0)
+ return OPAL_PARAMETER;
+
+ pldm_mctp_message_rx(BMC_EID, tag_owner,
+ msg_tag, response_msg,
+ response_len);
+ free(response_msg);
+ }
+ return OPAL_SUCCESS;
+}
+
+int test_platform_init_pdr_error(void)
+{
+ int rc;
+
+ platform_special_case = PDR_REPLY_ERROR;
+ rc = pldm_platform_init();
+ if (rc != OPAL_PARAMETER) {
+ printf("PLDM_TEST: %s failed :: rc = %d exp %d\n",
+ __func__, rc, OPAL_PARAMETER);
+ platform_special_case = NORMAL_CASE;
+ return OPAL_PARAMETER;
+ }
+ platform_special_case = NORMAL_CASE;
+ return OPAL_SUCCESS;
+
+}
+
+
+int test_platform_init_event_error(void)
+{
+ int rc;
+
+ platform_special_case = PLATFORM_EVENT_ERROR;
+ rc = pldm_platform_init();
+ if (rc != OPAL_PARAMETER) {
+ printf("PLDM_TEST: %s failed :: rc = %d exp %d\n",
+ __func__, rc, OPAL_PARAMETER);
+ platform_special_case = NORMAL_CASE;
+ return OPAL_PARAMETER;
+ }
+ platform_special_case = NORMAL_CASE;
+ return OPAL_SUCCESS;
+
+}
+
+
+int test_platform_init_success(void)
+{
+ int rc;
+
+ platform_special_case = NORMAL_CASE;
+ rc = pldm_platform_init();
+ if (rc != OPAL_SUCCESS) {
+ printf("PLDM_TEST: %s failed :: rc = %d exp %d\n",
+ __func__, rc, OPAL_SUCCESS);
+ return OPAL_PARAMETER;
+ }
+ return OPAL_SUCCESS;
+}
+
+
+
+int test_find_pdr_first_record(void)
+{
+ int rc;
+ uint8_t *pdr_data = NULL;
+ uint32_t pdr_size, next_record_handle;
+
+ /*
+ * try to find first pdr record send to repo
+ */
+ rc = pldm_platform_pdr_find_record(
+ STATESENSOR_RECORD_HANDLE,
+ &pdr_data, &pdr_size,
+ &next_record_handle);
+ if (rc != OPAL_SUCCESS) {
+ printf("PLDM_TEST: %s failed :: rc = %d exp %d\n",
+ __func__, rc, OPAL_SUCCESS);
+ return OPAL_PARAMETER;
+ }
+
+ if (pdr_data == NULL || pdr_size < 0) {
+ printf("PLDM_TEST: %s failed :: pdr_data = %p pdr size = %d\n",
+ __func__, pdr_data, pdr_size);
+ if (pdr_data)
+ free(pdr_data);
+ return OPAL_PARAMETER;
+ }
+
+ return OPAL_SUCCESS;
+}
+
+
+int test_find_pdr_existing_record(void)
+{
+ int rc;
+ uint8_t *pdr_data = NULL;
+ uint32_t pdr_size, next_record_handle;
+
+ /*
+ * try to find first pdr record send to repo
+ */
+ rc = pldm_platform_pdr_find_record(
+ EFFECTER1_RECORD_HANDLE,
+ &pdr_data, &pdr_size,
+ &next_record_handle);
+ if (rc != OPAL_SUCCESS) {
+ printf("PLDM_TEST: %s failed :: rc = %d exp %d\n",
+ __func__, rc, OPAL_SUCCESS);
+ return OPAL_PARAMETER;
+ }
+
+ if (pdr_data == NULL || pdr_size < 0) {
+ printf("PLDM_TEST: %s failed :: pdr_data = %p pdr size = %d\n",
+ __func__, pdr_data, pdr_size);
+ if (pdr_data)
+ free(pdr_data);
+ return OPAL_PARAMETER;
+ }
+
+ return OPAL_SUCCESS;
+}
+
+int test_find_pdr_non_existing_record(void)
+{
+ int rc;
+ uint8_t *pdr_data = NULL;
+ uint32_t pdr_size, next_record_handle;
+
+ rc = pldm_platform_pdr_find_record(
+ 400,
+ &pdr_data, &pdr_size,
+ &next_record_handle);
+ if (rc != OPAL_PARAMETER) {
+ printf("PLDM_TEST: %s failed :: rc = %d exp %d\n",
+ __func__, rc, OPAL_PARAMETER);
+ return OPAL_PARAMETER;
+ }
+ return OPAL_SUCCESS;
+}
+
+
+
+struct test_case {
+ const char *name;
+ int (*fn)(void);
+};
+
+#define TEST_CASE(x) { #x, x }
+
+struct test_case test_cases[] = {
+ TEST_CASE(test_platform_init_pdr_error),
+ TEST_CASE(test_platform_init_event_error),
+ TEST_CASE(test_platform_init_success),
+ TEST_CASE(test_find_pdr_first_record),
+ TEST_CASE(test_find_pdr_existing_record),
+ TEST_CASE(test_find_pdr_non_existing_record),
+ {NULL, NULL}
+};
+
+
+int main(void)
+{
+ struct test_case *tc = &test_cases[0];
+ int rc = 0;
+
+ /* Initialize test buffer for represent file with 0 */
+ pldm_requester_init();
+
+ do {
+ rc = tc->fn();
+ if (rc != OPAL_SUCCESS) {
+ printf("PLDM PLATFORM TEST :%s FAILED\n", tc->name);
+ return -1;
+ }
+ } while ((++tc)->fn);
+
+ // This is to kill thread running to take requests
+ kill_poller();
+
+ return OPAL_SUCCESS;
+}
+
--
2.48.1
More information about the Skiboot
mailing list