|
| 1 | +/* |
| 2 | + * Copyright (c) 2025 Intel Corporation |
| 3 | + * |
| 4 | + * SPDX-License-Identifier: Apache-2.0 |
| 5 | + */ |
| 6 | + |
| 7 | +#include <stdint.h> |
| 8 | +#include <stdlib.h> |
| 9 | +#include <stdio.h> |
| 10 | +#include <assert.h> |
| 11 | +#include <unistd.h> |
| 12 | +#include <zephyr/types.h> |
| 13 | +#include <zephyr/kernel.h> |
| 14 | +#include <libpldm/base.h> |
| 15 | +#include <libmctp.h> |
| 16 | +#include <zephyr/pmci/mctp/mctp_uart.h> |
| 17 | + |
| 18 | +#include <zephyr/logging/log.h> |
| 19 | +LOG_MODULE_REGISTER(pldm_endpoint); |
| 20 | + |
| 21 | +/* PLDM MCTP Message Type */ |
| 22 | +#define PLDM_MCTP_MESSAGE_TYPE 1 |
| 23 | + |
| 24 | +/* Local MCTP Endpoint ID that responds to requests */ |
| 25 | +#define LOCAL_EID 10 |
| 26 | +/* Local PLDM Terminus ID that responds to requests */ |
| 27 | +#define LOCAL_TID 2 |
| 28 | + |
| 29 | +/* Remote MCTP Endpoint ID that we request from to */ |
| 30 | +#define REMOTE_EID 20 |
| 31 | + |
| 32 | +#define MCTP_INTEGRITY_CHECK 0x80 |
| 33 | +#define MCTP_MESSAGE_TYPE_MASK 0x7F |
| 34 | + |
| 35 | +const char *MESSAGE_TYPE_TO_STRING[] = {"Response", "Request", "Reserved", "Async Request Notify"}; |
| 36 | + |
| 37 | +const char *COMMAND_TO_STRING[] = {"UNDEFINED", "SetTID", "GetTID", |
| 38 | + "GetPLDMVersion", "GetPLDMCommands", "SelectPLDMVersion"}; |
| 39 | + |
| 40 | +static struct mctp *mctp_ctx; |
| 41 | + |
| 42 | +static void pldm_rx_handler(uint8_t src_eid, void *data, struct pldm_msg_hdr *msg_hdr, void *msg, |
| 43 | + size_t msg_len) |
| 44 | +{ |
| 45 | + struct pldm_header_info hdr_info; |
| 46 | + const char *message_type_str = ""; |
| 47 | + const char *command_str = ""; |
| 48 | + int rc; |
| 49 | + |
| 50 | + rc = unpack_pldm_header(msg_hdr, &hdr_info); |
| 51 | + if (rc != 0) { |
| 52 | + LOG_ERR("Failed unpacking pldm header"); |
| 53 | + } |
| 54 | + |
| 55 | + if (hdr_info.msg_type < ARRAY_SIZE(MESSAGE_TYPE_TO_STRING)) { |
| 56 | + message_type_str = MESSAGE_TYPE_TO_STRING[hdr_info.msg_type]; |
| 57 | + } |
| 58 | + |
| 59 | + if (hdr_info.command < ARRAY_SIZE(COMMAND_TO_STRING)) { |
| 60 | + command_str = COMMAND_TO_STRING[hdr_info.command]; |
| 61 | + } |
| 62 | + |
| 63 | + LOG_INF("received pldm message from mctp endpoint %d len %zu message type %d (%s) command " |
| 64 | + "%d (%s)", |
| 65 | + src_eid, msg_len, hdr_info.msg_type, message_type_str, hdr_info.command, |
| 66 | + command_str); |
| 67 | + |
| 68 | + /* Handle the GetTID command */ |
| 69 | + if (hdr_info.command == PLDM_GET_TID && hdr_info.msg_type == PLDM_REQUEST) { |
| 70 | + /* Response buffer for the GetTID command needs |
| 71 | + * pldm response header (4 bytes) + 1 bytes (the tid is 1 byte) + 1 byte (mctp |
| 72 | + * message type byte) |
| 73 | + */ |
| 74 | + uint8_t resp_msg_buf[PLDM_MSG_SIZE(sizeof(struct pldm_get_tid_resp)) + 1]; |
| 75 | + |
| 76 | + resp_msg_buf[0] = PLDM_MCTP_MESSAGE_TYPE; |
| 77 | + |
| 78 | + rc = encode_get_tid_resp(hdr_info.instance, PLDM_SUCCESS, LOCAL_TID, |
| 79 | + (struct pldm_msg *)&resp_msg_buf[1]); |
| 80 | + __ASSERT(rc == PLDM_SUCCESS, "Encoding pldm response should succeed"); |
| 81 | + |
| 82 | + rc = mctp_message_tx(mctp_ctx, src_eid, false, 0, resp_msg_buf, |
| 83 | + sizeof(resp_msg_buf)); |
| 84 | + __ASSERT(rc == 0, "Sending response to GetTID should succeed"); |
| 85 | + } else if (hdr_info.command == PLDM_GET_PLDM_TYPES && hdr_info.msg_type == PLDM_REQUEST) { |
| 86 | + /* Response buffer for the GetTID command needs |
| 87 | + * pldm response header (4 bytes) + 1 bytes (the tid is 1 byte) + 1 byte (mctp |
| 88 | + * message type byte) |
| 89 | + */ |
| 90 | + uint8_t resp_msg_buf[PLDM_MSG_SIZE(PLDM_GET_TYPES_RESP_BYTES) + 1]; |
| 91 | + uint8_t types[8]; |
| 92 | + |
| 93 | + resp_msg_buf[0] = PLDM_MCTP_MESSAGE_TYPE; |
| 94 | + |
| 95 | + types[0] = PLDM_BASE; |
| 96 | + rc = encode_get_types_resp(hdr_info.instance, PLDM_SUCCESS, (const bitfield8_t *)types, |
| 97 | + (struct pldm_msg *)&resp_msg_buf[1]); |
| 98 | + __ASSERT(rc == PLDM_SUCCESS, "Encoding pldm response should succeed"); |
| 99 | + |
| 100 | + rc = mctp_message_tx(mctp_ctx, src_eid, false, 0, resp_msg_buf, |
| 101 | + sizeof(resp_msg_buf)); |
| 102 | + __ASSERT(rc == 0, "Sending response to GetTypes should succeed"); } else if (hdr_info.command == PLDM_GET_PLDM_COMMANDS && hdr_info.msg_type == PLDM_REQUEST) { |
| 103 | + |
| 104 | + } else if (hdr_info.command == PLDM_GET_PLDM_VERSION && hdr_info.msg_type == PLDM_REQUEST) { |
| 105 | + uint32_t transfer_handle; |
| 106 | + uint8_t transfer_opflag; |
| 107 | + uint8_t type; |
| 108 | + |
| 109 | + rc = decode_get_version_req(msg, PLDM_GET_VERSION_REQ_BYTES, &transfer_handle, &transfer_opflag, &type); |
| 110 | + __ASSERT(rc == PLDM_SUCCESS, "Decoding GetVersion request should succeed"); |
| 111 | + |
| 112 | + |
| 113 | + /* Response buffer for the GetTID command needs |
| 114 | + * pldm response header (4 bytes) + 1 bytes (the tid is 1 byte) + 1 byte (mctp |
| 115 | + * message type byte) |
| 116 | + */ |
| 117 | + uint8_t resp_msg_buf[PLDM_MSG_SIZE(PLDM_GET_VERSION_RESP_BYTES) + 1]; |
| 118 | + ver32_t version = { .major = 1 }; |
| 119 | + |
| 120 | + resp_msg_buf[0] = PLDM_MCTP_MESSAGE_TYPE; |
| 121 | + |
| 122 | + rc = encode_get_version_resp(hdr_info.instance, PLDM_SUCCESS, 0, 0, &version, sizeof(ver32_t), |
| 123 | + (struct pldm_msg *)&resp_msg_buf[1]); |
| 124 | + __ASSERT(rc == PLDM_SUCCESS, "Encoding pldm response should succeed"); |
| 125 | + |
| 126 | + rc = mctp_message_tx(mctp_ctx, src_eid, false, 0, resp_msg_buf, |
| 127 | + sizeof(resp_msg_buf)); |
| 128 | + __ASSERT(rc == 0, "Sending response to GetVersion should succeed"); } else if (hdr_info.command == PLDM_GET_PLDM_COMMANDS && hdr_info.msg_type == PLDM_REQUEST) { |
| 129 | + } else if (hdr_info.command == PLDM_GET_PLDM_COMMANDS && hdr_info.msg_type == PLDM_REQUEST) { |
| 130 | + uint8_t type; |
| 131 | + ver32_t vers; |
| 132 | + |
| 133 | + rc = decode_get_commands_req(msg, PLDM_GET_COMMANDS_REQ_BYTES, &type, &vers); |
| 134 | + |
| 135 | + __ASSERT(rc == PLDM_SUCCESS, "Decoding GetCommands request should succeed"); |
| 136 | + |
| 137 | + uint8_t resp_msg_buf[PLDM_MSG_SIZE(PLDM_GET_COMMANDS_RESP_BYTES) + 1]; |
| 138 | + uint8_t commands[32]; |
| 139 | + |
| 140 | + resp_msg_buf[0] = PLDM_MCTP_MESSAGE_TYPE; |
| 141 | + commands[0] = PLDM_GET_TID | PLDM_GET_PLDM_VERSION | PLDM_GET_PLDM_TYPES | PLDM_GET_PLDM_COMMANDS; |
| 142 | + rc = encode_get_commands_resp(hdr_info.instance, PLDM_SUCCESS, (const bitfield8_t *)commands, |
| 143 | + (struct pldm_msg *)&resp_msg_buf[1]); |
| 144 | + __ASSERT(rc == PLDM_SUCCESS, "Encoding pldm response should succeed"); |
| 145 | + |
| 146 | + rc = mctp_message_tx(mctp_ctx, src_eid, false, 0, resp_msg_buf, |
| 147 | + sizeof(resp_msg_buf)); |
| 148 | + __ASSERT(rc == 0, "Sending response to GetCommands should succeed"); } else if (hdr_info.command == PLDM_GET_PLDM_COMMANDS && hdr_info.msg_type == PLDM_REQUEST) { |
| 149 | + } else { |
| 150 | + LOG_WRN("Unhandled pldm message, command %d, type %d", hdr_info.command, hdr_info.msg_type); |
| 151 | + } |
| 152 | +} |
| 153 | + |
| 154 | +static void rx_message(uint8_t src_eid, bool tag_owner, uint8_t msg_tag, void *data, void *msg, |
| 155 | + size_t len) |
| 156 | +{ |
| 157 | + LOG_INF("received message from mctp endpoint %d, msg_tag %d, len %zu", src_eid, msg_tag, |
| 158 | + len); |
| 159 | + LOG_HEXDUMP_INF(msg, len, "mctp rx message"); |
| 160 | + if (len < 1) { |
| 161 | + LOG_ERR("MCTP Message should contain a message type and integrity check byte!"); |
| 162 | + return; |
| 163 | + } |
| 164 | + |
| 165 | + /* Treat data as a buffer for byte wise access */ |
| 166 | + uint8_t *msg_buf = msg; |
| 167 | + |
| 168 | + /* If the message endpoint ID matches our local endpoint ID, and its a pldm message, call |
| 169 | + * the pldm_rx_message call |
| 170 | + */ |
| 171 | + if ((msg_buf[0] & MCTP_MESSAGE_TYPE_MASK) == PLDM_MCTP_MESSAGE_TYPE) { |
| 172 | + /* HAZARD This is potentially error prone but libpldm provides little help here */ |
| 173 | + struct pldm_msg_hdr *pldm_hdr = (struct pldm_msg_hdr *)&(msg_buf[1]); |
| 174 | + size_t pldm_msg_body_len = len - (1 + sizeof(struct pldm_msg_hdr)); |
| 175 | + void *pldm_msg_body = &msg_buf[1 + sizeof(struct pldm_msg_hdr)]; |
| 176 | + |
| 177 | + pldm_rx_handler(src_eid, msg, pldm_hdr, pldm_msg_body, pldm_msg_body_len); |
| 178 | + } |
| 179 | +} |
| 180 | + |
| 181 | +MCTP_UART_DT_DEFINE(mctp_host, DEVICE_DT_GET(DT_NODELABEL(arduino_serial))); |
| 182 | + |
| 183 | +int main(void) |
| 184 | +{ |
| 185 | + LOG_INF("PLDM Endpoint EID:%d TID:%d on %s\n", LOCAL_EID, LOCAL_TID, CONFIG_BOARD_TARGET); |
| 186 | + |
| 187 | + mctp_set_alloc_ops(malloc, free, realloc); |
| 188 | + mctp_ctx = mctp_init(); |
| 189 | + __ASSERT_NO_MSG(mctp_ctx != NULL); |
| 190 | + mctp_register_bus(mctp_ctx, &mctp_host.binding, LOCAL_EID); |
| 191 | + mctp_set_rx_all(mctp_ctx, rx_message, NULL); |
| 192 | + mctp_uart_start_rx(&mctp_host); |
| 193 | + |
| 194 | + return 0; |
| 195 | +} |
0 commit comments