Implement discovery commands
This commit does the following
- Implements the GetPLDMTypes and GetPLDMCommands commands. These are
commands that need to be handled by a PLDM device as part of the
initial PLDM discovery.
- Sets up the build infrastructure: separate libraries for PLDM
encode/decode libs and the PLDM responder.
Change-Id: I65fa222d2a681c473f579c8e30d84faaf94fe754
Signed-off-by: Deepak Kodihalli <dkodihal@in.ibm.com>
diff --git a/libpldm/Makefile.am b/libpldm/Makefile.am
new file mode 100644
index 0000000..3ff405b
--- /dev/null
+++ b/libpldm/Makefile.am
@@ -0,0 +1,12 @@
+nobase_include_HEADERS = \
+ base.h
+
+libpldm_LTLIBRARIES = libpldm.la
+libpldmdir = ${libdir}
+libpldm_la_SOURCES = \
+ base.c
+libpldm_la_LDFLAGS = \
+ -version-info 1:0:0 -shared
+
+pkgconfiglibdir = ${libdir}/pkgconfig
+pkgconfiglib_DATA = libpldm.pc
diff --git a/libpldm/base.c b/libpldm/base.c
new file mode 100644
index 0000000..db32ca4
--- /dev/null
+++ b/libpldm/base.c
@@ -0,0 +1,104 @@
+#include <endian.h>
+#include <string.h>
+
+#include "base.h"
+
+int encode_get_types_req(uint8_t instance_id, struct pldm_msg *msg)
+{
+ if (msg == NULL) {
+ return PLDM_ERROR_INVALID_DATA;
+ }
+
+ return PLDM_SUCCESS;
+}
+
+int encode_get_commands_req(uint8_t instance_id, uint8_t type,
+ struct pldm_version version, struct pldm_msg *msg)
+{
+ if (msg == NULL) {
+ return PLDM_ERROR_INVALID_DATA;
+ }
+
+ uint8_t *dst = msg->body.payload;
+ memcpy(dst, &type, sizeof(type));
+ dst += sizeof(type);
+ memcpy(dst, &version, sizeof(version));
+
+ return PLDM_SUCCESS;
+}
+
+int encode_get_types_resp(uint8_t instance_id, uint8_t completion_code,
+ const uint8_t *types, struct pldm_msg *msg)
+{
+ if (msg == NULL) {
+ return PLDM_ERROR_INVALID_DATA;
+ }
+
+ msg->body.payload[0] = completion_code;
+ if (msg->body.payload[0] == PLDM_SUCCESS) {
+ if (types == NULL) {
+ return PLDM_ERROR_INVALID_DATA;
+ }
+ uint8_t *dst = msg->body.payload + sizeof(msg->body.payload[0]);
+ memcpy(dst, types, PLDM_MAX_TYPES / 8);
+ }
+
+ return PLDM_SUCCESS;
+}
+
+int decode_get_commands_req(const struct pldm_msg_payload *msg, uint8_t *type,
+ struct pldm_version *version)
+{
+ if (msg == NULL || type == NULL || version == NULL) {
+ return PLDM_ERROR_INVALID_DATA;
+ }
+
+ const uint8_t *start = msg->payload;
+ *type = *start;
+ memcpy(version, (struct pldm_version *)(start + sizeof(*type)),
+ sizeof(*version));
+
+ return PLDM_SUCCESS;
+}
+
+int encode_get_commands_resp(uint8_t instance_id, uint8_t completion_code,
+ const uint8_t *commands, struct pldm_msg *msg)
+{
+ if (msg == NULL) {
+ return PLDM_ERROR_INVALID_DATA;
+ }
+
+ msg->body.payload[0] = completion_code;
+ if (msg->body.payload[0] == PLDM_SUCCESS) {
+ if (commands == NULL) {
+ return PLDM_ERROR_INVALID_DATA;
+ }
+ uint8_t *dst = msg->body.payload + sizeof(msg->body.payload[0]);
+ memcpy(dst, commands, PLDM_MAX_CMDS_PER_TYPE / 8);
+ }
+
+ return PLDM_SUCCESS;
+}
+
+int decode_get_types_resp(const struct pldm_msg_payload *msg, uint8_t *types)
+{
+ if (msg == NULL || types == NULL) {
+ return PLDM_ERROR_INVALID_DATA;
+ }
+ const uint8_t *src = msg->payload + sizeof(uint8_t);
+ memcpy(types, src, PLDM_MAX_TYPES / 8);
+
+ return PLDM_SUCCESS;
+}
+
+int decode_get_commands_resp(const struct pldm_msg_payload *msg,
+ uint8_t *commands)
+{
+ if (msg == NULL || commands == NULL) {
+ return PLDM_ERROR_INVALID_DATA;
+ }
+ const uint8_t *src = msg->payload + sizeof(uint8_t);
+ memcpy(commands, src, PLDM_MAX_CMDS_PER_TYPE / 8);
+
+ return PLDM_SUCCESS;
+}
diff --git a/libpldm/base.h b/libpldm/base.h
new file mode 100644
index 0000000..29b2c87
--- /dev/null
+++ b/libpldm/base.h
@@ -0,0 +1,199 @@
+#ifndef BASE_H
+#define BASE_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include <asm/byteorder.h>
+#include <stddef.h>
+#include <stdint.h>
+
+/** @brief PLDM Types
+ */
+enum pldm_supported_types {
+ PLDM_BASE = 0x00,
+};
+
+/** @brief PLDM Commands
+ */
+enum pldm_supported_commands {
+ PLDM_GET_PLDM_TYPES = 0x4,
+ PLDM_GET_PLDM_COMMANDS = 0x5
+};
+
+/** @brief PLDM base codes
+ */
+enum pldm_completion_codes {
+ PLDM_SUCCESS = 0x00,
+ PLDM_ERROR = 0x01,
+ PLDM_ERROR_INVALID_DATA = 0x02,
+ PLDM_ERROR_INVALID_LENGTH = 0x03,
+ PLDM_ERROR_NOT_READY = 0x04,
+ PLDM_ERROR_UNSUPPORTED_PLDM_CMD = 0x05,
+ PLDM_ERROR_INVALID_PLDM_TYPE = 0x20
+};
+
+#define PLDM_MAX_TYPES 64
+#define PLDM_MAX_CMDS_PER_TYPE 256
+
+/* Message payload lengths */
+#define PLDM_GET_COMMANDS_REQ_BYTES 5
+
+/* Response lengths are inclusive of completion code */
+#define PLDM_GET_TYPES_RESP_BYTES 9
+#define PLDM_GET_COMMANDS_RESP_BYTES 33
+
+/** @struct pldm_msg_hdr
+ *
+ * Structure representing PLDM message header fields
+ */
+struct pldm_msg_hdr {
+#if defined(__LITTLE_ENDIAN_BITFIELD)
+ uint8_t instance_id : 5; //!< Instance ID
+ uint8_t reserved : 1; //!< Reserved
+ uint8_t datagram : 1; //!< Datagram bit
+ uint8_t request : 1; //!< Request bit
+#elif defined(__BIG_ENDIAN_BITFIELD)
+ uint8_t request : 1; //!< Request bit
+ uint8_t datagram : 1; //!< Datagram bit
+ uint8_t reserved : 1; //!< Reserved
+ uint8_t instance_id : 5; //!< Instance ID
+#endif
+
+#if defined(__LITTLE_ENDIAN_BITFIELD)
+ uint8_t type : 6; //!< PLDM type
+ uint8_t header_ver : 2; //!< Header version
+#elif defined(__BIG_ENDIAN_BITFIELD)
+ uint8_t header_ver : 2; //!< Header version
+ uint8_t type : 6; //!< PLDM type
+#endif
+ uint8_t command; //!< PLDM command code
+} __attribute__((packed));
+
+/** @struct pldm_msg_payload
+ *
+ * Structure representing PLDM message payload
+ */
+struct pldm_msg_payload {
+ uint8_t *payload; //!< Pointer to PLDM message payload
+ size_t payload_length; //!< PLDM message payload's length in bytes
+} __attribute__((packed));
+
+/** @struct pldm_msg
+ *
+ * Structure representing PLDM message
+ */
+struct pldm_msg {
+ struct pldm_msg_hdr hdr; //!< PLDM message header
+ struct pldm_msg_payload body; //!< PLDM message payload
+} __attribute__((packed));
+
+/** @struct pldm_version
+ *
+ * Structure representing PLDM ver32 type
+ */
+struct pldm_version {
+ uint8_t major;
+ uint8_t minor;
+ uint8_t update;
+ uint8_t alpha;
+} __attribute__((packed));
+
+/* Requester */
+
+/* GetPLDMTypes */
+
+/** @brief Create a PLDM request message for GetPLDMTypes
+ *
+ * @param[in] instance_id - Message's instance id
+ * @param[in,out] msg - Message will be written to this
+ * @return pldm_completion_codes
+ * @note Caller is responsible for memory alloc and dealloc of param
+ * 'msg.body.payload'
+ */
+int encode_get_types_req(uint8_t instance_id, struct pldm_msg *msg);
+
+/** @brief Decode a GetPLDMTypes response message
+ *
+ * @param[in] msg - Response message payload
+ * @param[out] types - pointer to array uint8_t[8] containing supported
+ * types (MAX_TYPES/8) = 8), as per DSP0240
+ * @return pldm_completion_codes
+ */
+int decode_get_types_resp(const struct pldm_msg_payload *msg, uint8_t *types);
+
+/* GetPLDMCommands */
+
+/** @brief Create a PLDM request message for GetPLDMCommands
+ *
+ * @param[in] instance_id - Message's instance id
+ * @param[in] type - PLDM Type
+ * @param[in] version - Version for PLDM Type
+ * @param[in,out] msg - Message will be written to this
+ * @return pldm_completion_codes
+ * @note Caller is responsible for memory alloc and dealloc of param
+ * 'msg.body.payload'
+ */
+int encode_get_commands_req(uint8_t instance_id, uint8_t type,
+ struct pldm_version version, struct pldm_msg *msg);
+
+/** @brief Decode a GetPLDMCommands response message
+ *
+ * @param[in] msg - Response message payload
+ * @param[in] commands - pointer to array uint8_t[32] containing supported
+ * commands (PLDM_MAX_CMDS_PER_TYPE/8) = 32), as per DSP0240
+ * @return pldm_completion_codes
+ */
+int decode_get_commands_resp(const struct pldm_msg_payload *msg,
+ uint8_t *commands);
+
+/* Responder */
+
+/* GetPLDMTypes */
+
+/** @brief Create a PLDM response message for GetPLDMTypes
+ *
+ * @param[in] instance_id - Message's instance id
+ * @param[in] completion_code - PLDM completion code
+ * @param[in] types - pointer to array uint8_t[8] containing supported
+ * types (MAX_TYPES/8) = 8), as per DSP0240
+ * @param[in,out] msg - Message will be written to this
+ * @return pldm_completion_codes
+ * @note Caller is responsible for memory alloc and dealloc of param
+ * 'msg.body.payload'
+ */
+int encode_get_types_resp(uint8_t instance_id, uint8_t completion_code,
+ const uint8_t *types, struct pldm_msg *msg);
+
+/* GetPLDMCommands */
+
+/** @brief Decode GetPLDMCommands' request data
+ *
+ * @param[in] msg - Request message payload
+ * @param[out] type - PLDM Type
+ * @param[out] version - Version for PLDM Type
+ * @return pldm_completion_codes
+ */
+int decode_get_commands_req(const struct pldm_msg_payload *msg, uint8_t *type,
+ struct pldm_version *version);
+
+/** @brief Create a PLDM response message for GetPLDMCommands
+ *
+ * @param[in] instance_id - Message's instance id
+ * @param[in] completion_code - PLDM completion code
+ * @param[in] commands - pointer to array uint8_t[32] containing supported
+ * commands (PLDM_MAX_CMDS_PER_TYPE/8) = 32), as per DSP0240
+ * @param[in,out] msg - Message will be written to this
+ * @return pldm_completion_codes
+ * @note Caller is responsible for memory alloc and dealloc of param
+ * 'msg.body.payload'
+ */
+int encode_get_commands_resp(uint8_t instance_id, uint8_t completion_code,
+ const uint8_t *commands, struct pldm_msg *msg);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* BASE_H */
diff --git a/libpldm/libpldm.pc.in b/libpldm/libpldm.pc.in
new file mode 100644
index 0000000..d6bdcf8
--- /dev/null
+++ b/libpldm/libpldm.pc.in
@@ -0,0 +1,14 @@
+prefix=@prefix@
+exec_prefix=@exec_prefix@
+libdir=@libdir@
+includedir=@includedir@
+
+Name: libpldm
+Description: PLDM encode/decode C library
+URL: https://github.com/openbmc/pldm/libpldm
+Version: @VERSION@
+Requires: @AX_PACKAGE_REQUIRES@
+Requires.private: @AX_PACKAGE_REQUIRES_PRIVATE@
+Libs: -L@libdir@ -lpldm
+Cflags: -I@includedir@
+