dsp: firmware update: Add encode/decode APIs for DD update
encode/decode command RequestDownstreamDeviceUpdate, based on
DSP0267 1.3.0.
Change-Id: I904a7229fe4a440904e6cf95c8e46b5956c3476c
Signed-off-by: Sora Su <baxiche@gmail.com>
diff --git a/CHANGELOG.md b/CHANGELOG.md
index cef81ea..511ea85 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -32,6 +32,8 @@
This ID is used to notify the remote PLDM terminus about the boot side change
that occurs during an out-of-band code update.
+- firmware update: Add encode/decode API for downstream device update command
+
### Changed
- clang-format: update latest spec and reformat with clang-20
diff --git a/include/libpldm/firmware_update.h b/include/libpldm/firmware_update.h
index 1610bd8..3571b9b 100644
--- a/include/libpldm/firmware_update.h
+++ b/include/libpldm/firmware_update.h
@@ -121,10 +121,16 @@
PLDM_TRANSFER_COMPLETE = 0x16,
PLDM_VERIFY_COMPLETE = 0x17,
PLDM_APPLY_COMPLETE = 0x18,
+ PLDM_GET_META_DATA = 0x19,
PLDM_ACTIVATE_FIRMWARE = 0x1a,
PLDM_GET_STATUS = 0x1b,
PLDM_CANCEL_UPDATE_COMPONENT = 0x1c,
- PLDM_CANCEL_UPDATE = 0x1d
+ PLDM_CANCEL_UPDATE = 0x1d,
+ PLDM_ACTIVATE_PENDING_COMPONENT_IMAGE_SET = 0x1e,
+ PLDM_ACTIVATE_PENDING_COMPONENT_IMAGE = 0x1f,
+ PLDM_REQUEST_DOWNSTREAM_DEVICE_UPDATE = 0x20,
+ PLDM_GET_COMPONENT_OPAQUE_DATA = 0x21,
+ PLDM_UPTATE_SECURITY_REVISION = 0x22
};
/** @brief PLDM Firmware update completion codes
@@ -889,6 +895,29 @@
uint8_t fd_will_send_pkg_data;
} __attribute__((packed));
+/** @struct pldm_request_downstream_dev_update_req
+ *
+ * Structure representing Request Downstream Device Update request
+ */
+struct pldm_request_downstream_device_update_req {
+ uint32_t maximum_downstream_device_transfer_size;
+ uint8_t maximum_outstanding_transfer_requests;
+ uint16_t downstream_device_package_data_length;
+};
+#define PLDM_DOWNSTREAM_DEVICE_UPDATE_REQUEST_BYTES 7
+
+/** @struct pldm_request_downstream_dev_update_resp
+ *
+ * Structure representing Request Downstream Device Update response
+ */
+struct pldm_request_downstream_device_update_resp {
+ uint8_t completion_code;
+ uint16_t downstream_device_meta_data_length;
+ uint8_t downstream_device_will_send_get_package_data;
+ uint16_t get_package_data_maximum_transfer_size;
+};
+#define PLDM_DOWNSTREAM_DEVICE_UPDATE_RESPONSE_BYTES 6
+
/** @struct pldm_pass_component_table_req
*
* Structure representing PassComponentTable request, wire format.
@@ -1538,6 +1567,81 @@
const struct pldm_request_update_resp *resp_data,
struct pldm_msg *msg, size_t *payload_length);
+/** @brief Create PLDM request message for RequestDownstreamDeviceUpdate
+ *
+ * @param[in] instance_id - Message's instance id
+ * @param[in] req_data - Request data.
+ * @param[in,out] msg - Message will be written to this
+ * @param[in,out] payload_length - Length of response message payload
+ *
+ * @return 0 on success,
+ * -EINVAL if any argument is invalid,
+ * -ENOMSG if the message type is incorrect,
+ * -EOVERFLOW if the payload length is invalid
+ *
+ * @note Caller is responsible for memory alloc and dealloc of param
+ * 'msg.payload'
+ */
+int encode_request_downstream_device_update_req(
+ uint8_t instance_id,
+ const struct pldm_request_downstream_device_update_req *req_data,
+ struct pldm_msg *msg, size_t *payload_length);
+
+/** @brief Decode PLDM request message for RequestDownstreamDeviceUpdate
+ *
+ * @param[in] msg - Message
+ * @param[in] payload_length - Length of request message payload
+ * @param[out] req_data - RequestDownstreamDeviceUpdate request parameters
+ *
+ * @return 0 on success,
+ * -EINVAL if any argument is invalid,
+ * -ENOMSG if the message type is incorrect,
+ * -EOVERFLOW if the payload length is invalid,
+ * -EBADMSG if the message buffer was not fully consumed
+ *
+ * @note Caller is responsible for memory alloc and dealloc of param
+ * 'msg.payload'
+ */
+int decode_request_downstream_device_update_req(
+ const struct pldm_msg *msg, size_t payload_length,
+ struct pldm_request_downstream_device_update_req *req_data);
+
+/** @brief Create PLDM response message for RequestDownstreamDeviceUpdate
+ *
+ * @param[in] instance_id - Message's instance id
+ * @param[in] resp_data - Response data
+ * @param[out] msg - Message will be written to this
+ * @param[inout] payload_length - Length of response message payload
+ *
+ * @return 0 on success,
+ * -EINVAL if any argument is invalid,
+ * -ENOMSG if the message type is incorrect,
+ * -EOVERFLOW if the payload length is invalid
+ *
+ * @note Caller is responsible for memory alloc and dealloc of param
+ * 'msg.payload'
+ */
+int encode_request_downstream_device_update_resp(
+ uint8_t instance_id,
+ const struct pldm_request_downstream_device_update_resp *resp_data,
+ struct pldm_msg *msg, size_t *payload_length);
+
+/** @brief Decode a RequestDownstreamDeviceUpdate response message
+ *
+ * @param[in] msg - Response message
+ * @param[in] payload_length - Length of response message payload
+ * @param[out] resp_data - RequestDownstreamDeviceUpdate respond parameters
+ *
+ * @return 0 on success,
+ * -EINVAL if any argument is invalid,
+ * -ENOMSG if the message type is incorrect,
+ * -EOVERFLOW if the payload length is invalid,
+ * -EBADMSG if the message buffer was not fully consumed
+ */
+int decode_request_downstream_device_update_resp(
+ const struct pldm_msg *msg, size_t payload_length,
+ struct pldm_request_downstream_device_update_resp *resp_data);
+
/** @brief Create PLDM request message for PassComponentTable
*
* @param[in] instance_id - Message's instance id
diff --git a/src/dsp/firmware_update.c b/src/dsp/firmware_update.c
index 25b29a7..7534e3a 100644
--- a/src/dsp/firmware_update.c
+++ b/src/dsp/firmware_update.c
@@ -1555,6 +1555,146 @@
return pldm_msgbuf_complete(buf);
}
+LIBPLDM_ABI_TESTING
+int encode_request_downstream_device_update_req(
+ uint8_t instance_id,
+ const struct pldm_request_downstream_device_update_req *req_data,
+ struct pldm_msg *msg, size_t *payload_length)
+{
+ PLDM_MSGBUF_DEFINE_P(buf);
+ int rc;
+
+ if (!req_data || !msg || !payload_length ||
+ req_data->maximum_downstream_device_transfer_size <
+ PLDM_FWUP_BASELINE_TRANSFER_SIZE ||
+ req_data->maximum_outstanding_transfer_requests <
+ PLDM_FWUP_MIN_OUTSTANDING_REQ) {
+ return -EINVAL;
+ }
+
+ rc = encode_pldm_header_only_errno(
+ PLDM_REQUEST, instance_id, PLDM_FWUP,
+ PLDM_REQUEST_DOWNSTREAM_DEVICE_UPDATE, msg);
+ if (rc) {
+ return rc;
+ }
+
+ rc = pldm_msgbuf_init_errno(buf,
+ PLDM_DOWNSTREAM_DEVICE_UPDATE_REQUEST_BYTES,
+ msg->payload, *payload_length);
+ if (rc) {
+ return rc;
+ }
+
+ pldm_msgbuf_insert(buf,
+ req_data->maximum_downstream_device_transfer_size);
+ pldm_msgbuf_insert(buf,
+ req_data->maximum_outstanding_transfer_requests);
+ pldm_msgbuf_insert(buf,
+ req_data->downstream_device_package_data_length);
+
+ return pldm_msgbuf_complete_used(buf, *payload_length, payload_length);
+}
+
+LIBPLDM_ABI_TESTING
+int decode_request_downstream_device_update_req(
+ const struct pldm_msg *msg, size_t payload_length,
+ struct pldm_request_downstream_device_update_req *req)
+{
+ int rc;
+ PLDM_MSGBUF_DEFINE_P(buf);
+
+ if (!msg || !req) {
+ return -EINVAL;
+ }
+
+ rc = pldm_msgbuf_init_errno(buf,
+ PLDM_DOWNSTREAM_DEVICE_UPDATE_REQUEST_BYTES,
+ msg->payload, payload_length);
+ if (rc) {
+ return rc;
+ }
+
+ pldm_msgbuf_extract(buf, req->maximum_downstream_device_transfer_size);
+ pldm_msgbuf_extract(buf, req->maximum_outstanding_transfer_requests);
+ pldm_msgbuf_extract(buf, req->downstream_device_package_data_length);
+
+ return pldm_msgbuf_complete_consumed(buf);
+}
+
+LIBPLDM_ABI_TESTING
+int encode_request_downstream_device_update_resp(
+ uint8_t instance_id,
+ const struct pldm_request_downstream_device_update_resp *resp_data,
+ struct pldm_msg *msg, size_t *payload_length)
+{
+ PLDM_MSGBUF_DEFINE_P(buf);
+ int rc;
+
+ if (!resp_data || !msg || !payload_length) {
+ return -EINVAL;
+ }
+
+ rc = encode_pldm_header_only_errno(
+ PLDM_RESPONSE, instance_id, PLDM_FWUP,
+ PLDM_REQUEST_DOWNSTREAM_DEVICE_UPDATE, msg);
+ if (rc) {
+ return rc;
+ }
+
+ rc = pldm_msgbuf_init_errno(
+ buf, PLDM_DOWNSTREAM_DEVICE_UPDATE_RESPONSE_BYTES, msg->payload,
+ *payload_length);
+ if (rc) {
+ return rc;
+ }
+
+ pldm_msgbuf_insert(buf, resp_data->completion_code);
+ pldm_msgbuf_insert(buf, resp_data->downstream_device_meta_data_length);
+ pldm_msgbuf_insert(
+ buf, resp_data->downstream_device_will_send_get_package_data);
+ pldm_msgbuf_insert(buf,
+ resp_data->get_package_data_maximum_transfer_size);
+
+ return pldm_msgbuf_complete_used(buf, *payload_length, payload_length);
+}
+
+LIBPLDM_ABI_TESTING
+int decode_request_downstream_device_update_resp(
+ const struct pldm_msg *msg, size_t payload_length,
+ struct pldm_request_downstream_device_update_resp *resp_data)
+{
+ PLDM_MSGBUF_DEFINE_P(buf);
+ int rc;
+
+ if (!msg || !resp_data) {
+ return -EINVAL;
+ }
+
+ rc = pldm_msg_has_error(msg,
+ PLDM_DOWNSTREAM_DEVICE_UPDATE_RESPONSE_BYTES);
+ if (rc) {
+ resp_data->completion_code = rc;
+ return 0;
+ }
+
+ rc = pldm_msgbuf_init_errno(
+ buf, PLDM_DOWNSTREAM_DEVICE_UPDATE_RESPONSE_BYTES, msg->payload,
+ payload_length);
+ if (rc) {
+ return rc;
+ }
+
+ pldm_msgbuf_extract(buf, resp_data->completion_code);
+ pldm_msgbuf_extract(buf, resp_data->downstream_device_meta_data_length);
+ pldm_msgbuf_extract(
+ buf, resp_data->downstream_device_will_send_get_package_data);
+ pldm_msgbuf_extract(buf,
+ resp_data->get_package_data_maximum_transfer_size);
+
+ return pldm_msgbuf_complete_consumed(buf);
+}
+
LIBPLDM_ABI_STABLE
int encode_request_update_req(uint8_t instance_id, uint32_t max_transfer_size,
uint16_t num_of_comp,
diff --git a/tests/dsp/firmware_update.cpp b/tests/dsp/firmware_update.cpp
index 01ea091..fa2d60c 100644
--- a/tests/dsp/firmware_update.cpp
+++ b/tests/dsp/firmware_update.cpp
@@ -2957,6 +2957,180 @@
EXPECT_EQ(rc, PLDM_ERROR_INVALID_LENGTH);
}
+#ifdef LIBPLDM_API_TESTING
+TEST(RequestDownstreamDeviceUpdate, goodPathEncodeRequest)
+{
+ constexpr uint8_t instanceId = 1;
+
+ std::array<uint8_t, hdrSize + PLDM_DOWNSTREAM_DEVICE_UPDATE_REQUEST_BYTES>
+ request{};
+
+ auto requestMsg = new (request.data()) pldm_msg;
+
+ constexpr struct pldm_request_downstream_device_update_req req_data = {
+ .maximum_downstream_device_transfer_size = 512,
+ .maximum_outstanding_transfer_requests = 2,
+ .downstream_device_package_data_length = 0x1234,
+ };
+ size_t enc_payload_len = PLDM_DOWNSTREAM_DEVICE_UPDATE_REQUEST_BYTES;
+
+ auto rc = encode_request_downstream_device_update_req(
+ instanceId, &req_data, requestMsg, &enc_payload_len);
+
+ EXPECT_EQ(rc, 0);
+
+ std::array<uint8_t, hdrSize + PLDM_DOWNSTREAM_DEVICE_UPDATE_REQUEST_BYTES>
+ outRequest{0x81, 0x05, 0x20, 0x00, 0x02, 0x00, 0x00, 0x02, 0x34, 0x12};
+ EXPECT_EQ(request, outRequest);
+}
+#endif // LIBPLDM_API_TESTING
+
+#ifdef LIBPLDM_API_TESTING
+TEST(RequestDownstreamDeviceUpdate, errorPathEncodeRequest)
+{
+ constexpr uint8_t instanceId = 1;
+ size_t enc_payload_len = PLDM_DOWNSTREAM_DEVICE_UPDATE_REQUEST_BYTES;
+
+ std::array<uint8_t, hdrSize + PLDM_DOWNSTREAM_DEVICE_UPDATE_REQUEST_BYTES>
+ request{};
+
+ struct pldm_request_downstream_device_update_req req_data = {
+ .maximum_downstream_device_transfer_size = 512,
+ .maximum_outstanding_transfer_requests = 2,
+ .downstream_device_package_data_length = 0x1234,
+ };
+
+ auto requestMsg = new (request.data()) pldm_msg;
+
+ auto rc = encode_request_downstream_device_update_req(
+ instanceId, nullptr, requestMsg, &enc_payload_len);
+ EXPECT_EQ(rc, -EINVAL);
+ rc = encode_request_downstream_device_update_req(
+ instanceId, &req_data, requestMsg, &enc_payload_len);
+ EXPECT_EQ(rc, 0);
+
+ rc = encode_request_downstream_device_update_req(instanceId, &req_data,
+ nullptr, &enc_payload_len);
+ EXPECT_EQ(rc, -EINVAL);
+ rc = encode_request_downstream_device_update_req(
+ instanceId, &req_data, requestMsg, &enc_payload_len);
+ EXPECT_EQ(rc, 0);
+
+ rc = encode_request_downstream_device_update_req(instanceId, &req_data,
+ requestMsg, nullptr);
+ EXPECT_EQ(rc, -EINVAL);
+ rc = encode_request_downstream_device_update_req(
+ instanceId, &req_data, requestMsg, &enc_payload_len);
+ EXPECT_EQ(rc, 0);
+
+ enc_payload_len =
+ static_cast<size_t>(PLDM_DOWNSTREAM_DEVICE_UPDATE_REQUEST_BYTES) - 1;
+ rc = encode_request_downstream_device_update_req(
+ instanceId, &req_data, requestMsg, &enc_payload_len);
+ EXPECT_EQ(rc, -EOVERFLOW);
+ enc_payload_len =
+ static_cast<size_t>(PLDM_DOWNSTREAM_DEVICE_UPDATE_REQUEST_BYTES);
+ rc = encode_request_downstream_device_update_req(
+ instanceId, &req_data, requestMsg, &enc_payload_len);
+ EXPECT_EQ(rc, 0);
+
+ req_data.maximum_downstream_device_transfer_size = 31;
+ rc = encode_request_downstream_device_update_req(
+ instanceId, &req_data, requestMsg, &enc_payload_len);
+ EXPECT_EQ(rc, -EINVAL);
+ req_data.maximum_downstream_device_transfer_size =
+ PLDM_FWUP_BASELINE_TRANSFER_SIZE;
+
+ req_data.maximum_outstanding_transfer_requests = 0;
+ rc = encode_request_downstream_device_update_req(
+ instanceId, &req_data, requestMsg, &enc_payload_len);
+ EXPECT_EQ(rc, -EINVAL);
+ req_data.maximum_outstanding_transfer_requests = 2;
+ rc = encode_request_downstream_device_update_req(
+ instanceId, &req_data, requestMsg, &enc_payload_len);
+ EXPECT_EQ(rc, 0);
+}
+#endif // LIBPLDM_API_TESTING
+
+#ifdef LIBPLDM_API_TESTING
+TEST(RequestDownstreamDeviceUpdate, goodPathDecodeResponse)
+{
+ /* Test a success completion code */
+ constexpr uint16_t ddMetaDataLen = 1024;
+ constexpr uint8_t ddWillSendPkgData = 1;
+ constexpr uint16_t getPkgDataMaxTransferSize = 512;
+ std::array<uint8_t, hdrSize + PLDM_DOWNSTREAM_DEVICE_UPDATE_RESPONSE_BYTES>
+ requestUpdateResponse1{0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x04, 0x01, 0x00, 0x02};
+
+ auto responseMsg1 = new (requestUpdateResponse1.data()) pldm_msg;
+
+ struct pldm_request_downstream_device_update_resp resp_data1 = {
+ .completion_code = 0,
+ .downstream_device_meta_data_length = 0,
+ .downstream_device_will_send_get_package_data = 0,
+ .get_package_data_maximum_transfer_size = 0};
+
+ auto rc = decode_request_downstream_device_update_resp(
+ responseMsg1, PLDM_DOWNSTREAM_DEVICE_UPDATE_RESPONSE_BYTES,
+ &resp_data1);
+ EXPECT_EQ(rc, 0);
+ EXPECT_EQ(resp_data1.completion_code, PLDM_SUCCESS);
+ EXPECT_EQ(resp_data1.downstream_device_meta_data_length, ddMetaDataLen);
+ EXPECT_EQ(resp_data1.downstream_device_will_send_get_package_data,
+ ddWillSendPkgData);
+ EXPECT_EQ(resp_data1.get_package_data_maximum_transfer_size,
+ getPkgDataMaxTransferSize);
+
+ /* Test a failure completion code */
+ std::array<uint8_t, hdrSize + PLDM_DOWNSTREAM_DEVICE_UPDATE_RESPONSE_BYTES>
+ requestUpdateResponse2{0x00, 0x00, 0x00, 0x81};
+
+ auto responseMsg2 = new (requestUpdateResponse2.data()) pldm_msg;
+
+ struct pldm_request_downstream_device_update_resp resp_data2 = {
+ .completion_code = 0,
+ .downstream_device_meta_data_length = 0,
+ .downstream_device_will_send_get_package_data = 0,
+ .get_package_data_maximum_transfer_size = 0};
+
+ rc = decode_request_downstream_device_update_resp(
+ responseMsg2, PLDM_DOWNSTREAM_DEVICE_UPDATE_RESPONSE_BYTES,
+ &resp_data2);
+ EXPECT_EQ(rc, 0);
+ EXPECT_EQ(resp_data2.completion_code, PLDM_FWUP_ALREADY_IN_UPDATE_MODE);
+}
+#endif // LIBPLDM_API_TESTING
+
+#ifdef LIBPLDM_API_TESTING
+TEST(RequestDownstreamDeviceUpdate, errorPathDecodeResponse)
+{
+ std::array<uint8_t, hdrSize + PLDM_DOWNSTREAM_DEVICE_UPDATE_RESPONSE_BYTES>
+ requestUpdateResponse{0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x04, 0x01, 0x00, 0x02};
+
+ auto responseMsg = new (requestUpdateResponse.data()) pldm_msg;
+
+ struct pldm_request_downstream_device_update_resp resp_data = {
+ .completion_code = 0,
+ .downstream_device_meta_data_length = 0,
+ .downstream_device_will_send_get_package_data = 0,
+ .get_package_data_maximum_transfer_size = 0};
+
+ auto rc = decode_request_downstream_device_update_resp(
+ nullptr, PLDM_DOWNSTREAM_DEVICE_UPDATE_RESPONSE_BYTES, &resp_data);
+ EXPECT_EQ(rc, -EINVAL);
+
+ rc = decode_request_downstream_device_update_resp(
+ responseMsg, PLDM_DOWNSTREAM_DEVICE_UPDATE_RESPONSE_BYTES, nullptr);
+ EXPECT_EQ(rc, -EINVAL);
+
+ rc = decode_request_downstream_device_update_resp(responseMsg, 0,
+ &resp_data);
+ EXPECT_EQ(rc, -EOVERFLOW);
+}
+#endif // LIBPLDM_API_TESTING
+
TEST(PassComponentTable, goodPathEncodeRequest)
{
constexpr uint8_t instanceId = 1;