Implement command GetDateTime

This commit implements the GetDateTime command which is
defined in PLDM Bios Control and Configuration Specification.

Change-Id: Iced21bbad7be07d357b6885b1b1e03b07a3da165
Signed-off-by: Sampa Misra <sampmisr@in.ibm.com>
diff --git a/libpldm/Makefile.am b/libpldm/Makefile.am
index e778094..821f390 100644
--- a/libpldm/Makefile.am
+++ b/libpldm/Makefile.am
@@ -1,13 +1,15 @@
 nobase_include_HEADERS = \
 	base.h \
 	pldm_types.h \
-	platform.h
+	platform.h \
+	bios.h
 
 libpldm_LTLIBRARIES = libpldm.la
 libpldmdir = ${libdir}
 libpldm_la_SOURCES = \
 	base.c \
-	platform.c
+	platform.c \
+	bios.c
 libpldm_la_LDFLAGS = -version-info 1:0:0 -shared
 libpldm_la_CFLAGS = $(CODE_COVERAGE_CFLAGS)
 libpldm_la_LIBADD = $(CODE_COVERAGE_LIBS)
diff --git a/libpldm/base.h b/libpldm/base.h
index 3673e9f..77b1045 100644
--- a/libpldm/base.h
+++ b/libpldm/base.h
@@ -16,6 +16,7 @@
 enum pldm_supported_types {
 	PLDM_BASE = 0x00,
 	PLDM_PLATFORM = 0x02,
+	PLDM_BIOS = 0x03,
 };
 
 /** @brief PLDM Commands
diff --git a/libpldm/bios.c b/libpldm/bios.c
new file mode 100644
index 0000000..c757df3
--- /dev/null
+++ b/libpldm/bios.c
@@ -0,0 +1,88 @@
+#include <endian.h>
+#include <string.h>
+
+#include "bios.h"
+
+int encode_get_date_time_req(uint8_t instance_id, struct pldm_msg *msg)
+{
+	struct pldm_header_info header = {0};
+
+	if (msg == NULL) {
+		return PLDM_ERROR_INVALID_DATA;
+	}
+
+	header.msg_type = PLDM_REQUEST;
+	header.instance = instance_id;
+	header.pldm_type = PLDM_BIOS;
+	header.command = PLDM_GET_DATE_TIME;
+	return pack_pldm_header(&header, &(msg->hdr));
+}
+
+int encode_get_date_time_resp(uint8_t instance_id, uint8_t completion_code,
+			      uint8_t seconds, uint8_t minutes, uint8_t hours,
+			      uint8_t day, uint8_t month, uint16_t year,
+			      struct pldm_msg *msg)
+{
+	struct pldm_header_info header = {0};
+	int rc = PLDM_SUCCESS;
+
+	if (msg == NULL) {
+		return PLDM_ERROR_INVALID_DATA;
+	}
+
+	msg->body.payload[0] = completion_code;
+
+	header.msg_type = PLDM_RESPONSE;
+	header.instance = instance_id;
+	header.pldm_type = PLDM_BIOS;
+	header.command = PLDM_GET_DATE_TIME;
+	if ((rc = pack_pldm_header(&header, &(msg->hdr))) > PLDM_SUCCESS) {
+		return rc;
+	}
+
+	uint8_t *dst = msg->body.payload + sizeof(msg->body.payload[0]);
+
+	memcpy(dst, &seconds, sizeof(seconds));
+	dst += sizeof(seconds);
+	memcpy(dst, &minutes, sizeof(minutes));
+	dst += sizeof(minutes);
+	memcpy(dst, &hours, sizeof(hours));
+	dst += sizeof(hours);
+	memcpy(dst, &day, sizeof(day));
+	dst += sizeof(day);
+	memcpy(dst, &month, sizeof(month));
+	dst += sizeof(month);
+	uint16_t local_year = htole16(year);
+	memcpy(dst, &local_year, sizeof(local_year));
+
+	return PLDM_SUCCESS;
+}
+
+int decode_get_date_time_resp(const struct pldm_msg_payload *msg,
+			      uint8_t *completion_code, uint8_t *seconds,
+			      uint8_t *minutes, uint8_t *hours, uint8_t *day,
+			      uint8_t *month, uint16_t *year)
+{
+	if (msg == NULL || seconds == NULL || minutes == NULL ||
+	    hours == NULL || day == NULL || month == NULL || year == NULL ||
+	    completion_code == NULL) {
+		return PLDM_ERROR_INVALID_DATA;
+	}
+
+	*completion_code = msg->payload[0];
+	if (PLDM_SUCCESS != *completion_code) {
+		return PLDM_SUCCESS;
+	}
+	const uint8_t *start = msg->payload + sizeof(uint8_t);
+	*seconds = *start;
+	*minutes = *(start + sizeof(*seconds));
+	*hours = *(start + sizeof(*seconds) + sizeof(*minutes));
+	*day = *(start + sizeof(*seconds) + sizeof(*minutes) + sizeof(*hours));
+	*month = *(start + sizeof(*seconds) + sizeof(*minutes) +
+		   sizeof(*hours) + sizeof(*day));
+	*year = le16toh(
+	    *((uint16_t *)(start + sizeof(*seconds) + sizeof(*minutes) +
+			   sizeof(*hours) + sizeof(*day) + sizeof(*month))));
+
+	return PLDM_SUCCESS;
+}
diff --git a/libpldm/bios.h b/libpldm/bios.h
new file mode 100644
index 0000000..d173aeb
--- /dev/null
+++ b/libpldm/bios.h
@@ -0,0 +1,80 @@
+#ifndef BIOS_H
+#define BIOS_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include <asm/byteorder.h>
+#include <stddef.h>
+#include <stdint.h>
+
+#include "base.h"
+
+/* Response lengths are inclusive of completion code */
+#define PLDM_GET_DATE_TIME_RESP_BYTES 8
+
+enum pldm_bios_commands { PLDM_GET_DATE_TIME = 0x0c };
+
+/* Requester */
+
+/* GetDateTime */
+
+/** @brief Create a PLDM request message for GetDateTime
+ *
+ *  @param[in] instance_id - Message's instance id
+ *  @param[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_date_time_req(uint8_t instance_id, struct pldm_msg *msg);
+
+/** @brief Decode a GetDateTime response message
+ *
+ *  @param[in] msg - Response message payload
+ *  @param[out] completion_code - Pointer to response msg's PLDM completion code
+ *  @param[out] seconds - Seconds in BCD format
+ *  @param[out] minutes - minutes in BCD format
+ *  @param[out] hours - hours in BCD format
+ *  @param[out] day - day of month in BCD format
+ *  @param[out] month - number of month in BCD format
+ *  @param[out] year - year in BCD format
+ *  @return pldm_completion_codes
+ */
+int decode_get_date_time_resp(const struct pldm_msg_payload *msg,
+			      uint8_t *completion_code, uint8_t *seconds,
+			      uint8_t *minutes, uint8_t *hours, uint8_t *day,
+			      uint8_t *month, uint16_t *year);
+
+/* Responder */
+
+/* GetDateTime */
+
+/** @brief Create a PLDM response message for GetDateTime
+ *
+ *  @param[in] instance_id - Message's instance id
+ *  @param[in] completion_code - PLDM completion code
+ *  @param[in] seconds - seconds in BCD format
+ *  @param[in] minutes - minutes in BCD format
+ *  @param[in] hours - hours in BCD format
+ *  @param[in] day - day of the month in BCD format
+ *  @param[in] month - number of month in BCD format
+ *  @param[in] year - year in BCD format
+ *  @param[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_date_time_resp(uint8_t instance_id, uint8_t completion_code,
+			      uint8_t seconds, uint8_t minutes, uint8_t hours,
+			      uint8_t day, uint8_t month, uint16_t year,
+			      struct pldm_msg *msg);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* BIOS_H */