libpldm: Add encode API for ActivateFirmware request

After all firmware components in the FD have been transferred and
applied, the UA sends this command to inform the FD to prepare all
successfully applied components to become active at the next
activation. This implementation works with DSP0267_1.1.0,
DSP0267_1.0.1 and DSP0267_1.0.0.

Tested: Unit tests passed

Signed-off-by: gokulsanker <gokul.sanker.v.g@intel.com>
Change-Id: I6b1627f5c783028ec310fa3c048c63dc9a9cf757
diff --git a/libpldm/firmware_update.c b/libpldm/firmware_update.c
index 8dd09d2..7a4fbba 100644
--- a/libpldm/firmware_update.c
+++ b/libpldm/firmware_update.c
@@ -168,6 +168,23 @@
 	}

 }

 

+/** @brief Check whether SelfContainedActivationRequest is valid

+ *

+ *  @return true if SelfContainedActivationRequest is valid, false if not

+ */

+static bool

+is_self_contained_activation_req_valid(bool8_t self_contained_activation_req)

+{

+	switch (self_contained_activation_req) {

+	case PLDM_NOT_ACTIVATE_SELF_CONTAINED_COMPONENTS:

+	case PLDM_ACTIVATE_SELF_CONTAINED_COMPONENTS:

+		return true;

+

+	default:

+		return false;

+	}

+}

+

 int decode_pldm_package_header_info(

     const uint8_t *data, size_t length,

     struct pldm_package_header_information *package_header_info,

@@ -1177,3 +1194,38 @@
 

 	return PLDM_SUCCESS;

 }

+

+int encode_activate_firmware_req(uint8_t instance_id,

+				 bool8_t self_contained_activation_req,

+				 struct pldm_msg *msg, size_t payload_length)

+{

+	if (msg == NULL) {

+		return PLDM_ERROR_INVALID_DATA;

+	}

+

+	if (payload_length != sizeof(struct pldm_activate_firmware_req)) {

+		return PLDM_ERROR_INVALID_LENGTH;

+	}

+

+	if (!is_self_contained_activation_req_valid(

+		self_contained_activation_req)) {

+		return PLDM_ERROR_INVALID_DATA;

+	}

+

+	struct pldm_header_info header = {0};

+	header.instance = instance_id;

+	header.msg_type = PLDM_REQUEST;

+	header.pldm_type = PLDM_FWUP;

+	header.command = PLDM_ACTIVATE_FIRMWARE;

+	uint8_t rc = pack_pldm_header(&header, &(msg->hdr));

+	if (rc) {

+		return rc;

+	}

+

+	struct pldm_activate_firmware_req *request =

+	    (struct pldm_activate_firmware_req *)msg->payload;

+

+	request->self_contained_activation_req = self_contained_activation_req;

+

+	return PLDM_SUCCESS;

+}

diff --git a/libpldm/firmware_update.h b/libpldm/firmware_update.h
index afa87fe..bffd296 100644
--- a/libpldm/firmware_update.h
+++ b/libpldm/firmware_update.h
@@ -5,6 +5,7 @@
 extern "C" {

 #endif

 #include "base.h"

+#include "stdbool.h"

 #include "utils.h"

 

 #define PLDM_FWUP_COMPONENT_BITMAP_MULTIPLE 8

@@ -29,7 +30,8 @@
 	PLDM_REQUEST_FIRMWARE_DATA = 0x15,

 	PLDM_TRANSFER_COMPLETE = 0x16,

 	PLDM_VERIFY_COMPLETE = 0x17,

-	PLDM_APPLY_COMPLETE = 0x18

+	PLDM_APPLY_COMPLETE = 0x18,

+	PLDM_ACTIVATE_FIRMWARE = 0x1A

 };

 

 /** @brief PLDM Firmware update completion codes

@@ -247,6 +249,13 @@
 	PLDM_FWUP_VENDOR_APPLY_RESULT_RANGE_MAX = 0xCF

 };

 

+/** @brief SelfContainedActivationRequest in the request of ActivateFirmware

+ */

+enum pldm_self_contained_activation_req {

+	PLDM_NOT_ACTIVATE_SELF_CONTAINED_COMPONENTS = false,

+	PLDM_ACTIVATE_SELF_CONTAINED_COMPONENTS = true

+};

+

 /** @struct pldm_package_header_information

  *

  *  Structure representing fixed part of package header information

@@ -447,6 +456,14 @@
 	bitfield16_t comp_activation_methods_modification;

 } __attribute__((packed));

 

+/** @struct pldm_activate_firmware_req

+ *

+ *  Structure representing ActivateFirmware request

+ */

+struct pldm_activate_firmware_req {

+	bool8_t self_contained_activation_req;

+} __attribute__((packed));

+

 /** @brief Decode the PLDM package header information

  *

  *  @param[in] data - pointer to package header information

@@ -883,6 +900,22 @@
 int encode_apply_complete_resp(uint8_t instance_id, uint8_t completion_code,

 			       struct pldm_msg *msg, size_t payload_length);

 

+/** @brief Create PLDM request message for ActivateFirmware

+ *

+ *  @param[in] instance_id - Message's instance id

+ *  @param[in] self_contained_activation_req SelfContainedActivationRequest

+ *  @param[in,out] msg - Message will be written to this

+ *  @param[in] payload_length - Length of request message payload

+ *

+ *  @return pldm_completion_codes

+ *

+ *  @note  Caller is responsible for memory alloc and dealloc of param

+ *         'msg.payload'

+ */

+int encode_activate_firmware_req(uint8_t instance_id,

+				 bool8_t self_contained_activation_req,

+				 struct pldm_msg *msg, size_t payload_length);

+

 #ifdef __cplusplus

 }

 #endif

diff --git a/libpldm/tests/libpldm_firmware_update_test.cpp b/libpldm/tests/libpldm_firmware_update_test.cpp
index a9829a2..89e1f4a 100644
--- a/libpldm/tests/libpldm_firmware_update_test.cpp
+++ b/libpldm/tests/libpldm_firmware_update_test.cpp
@@ -2349,3 +2349,39 @@
     rc = encode_apply_complete_resp(0, PLDM_SUCCESS, responseMsg, 0);

     EXPECT_EQ(rc, PLDM_ERROR_INVALID_LENGTH);

 }

+

+TEST(ActivateFirmware, goodPathEncodeRequest)

+{

+    constexpr uint8_t instanceId = 7;

+

+    std::array<uint8_t, hdrSize + sizeof(pldm_activate_firmware_req)> request{};

+    auto requestMsg = reinterpret_cast<pldm_msg*>(request.data());

+

+    auto rc = encode_activate_firmware_req(

+        instanceId, PLDM_ACTIVATE_SELF_CONTAINED_COMPONENTS, requestMsg,

+        sizeof(pldm_activate_firmware_req));

+    EXPECT_EQ(rc, PLDM_SUCCESS);

+

+    std::array<uint8_t, hdrSize + sizeof(pldm_activate_firmware_req)>

+        outRequest{0x87, 0x05, 0x1A, 0x01};

+    EXPECT_EQ(request, outRequest);

+}

+

+TEST(ActivateFirmware, errorPathEncodeRequest)

+{

+    std::array<uint8_t, hdrSize + sizeof(pldm_activate_firmware_req)> request{};

+    auto requestMsg = reinterpret_cast<pldm_msg*>(request.data());

+

+    auto rc = encode_activate_firmware_req(

+        0, PLDM_ACTIVATE_SELF_CONTAINED_COMPONENTS, nullptr,

+        sizeof(pldm_activate_firmware_req));

+    EXPECT_EQ(rc, PLDM_ERROR_INVALID_DATA);

+

+    rc = encode_activate_firmware_req(

+        0, PLDM_ACTIVATE_SELF_CONTAINED_COMPONENTS, requestMsg, 0);

+    EXPECT_EQ(rc, PLDM_ERROR_INVALID_LENGTH);

+

+    rc = encode_activate_firmware_req(0, 2, requestMsg,

+                                      sizeof(pldm_activate_firmware_req));

+    EXPECT_EQ(rc, PLDM_ERROR_INVALID_DATA);

+}