Add fwu_provider
Adds the fwu_provider that implements the public service interface
for the FWU service.
Signed-off-by: Julian Hall <julian.hall@arm.com>
Change-Id: I515998401086681e218c90e9a4a54606e3177ce2
diff --git a/components/service/fwu/provider/component.cmake b/components/service/fwu/provider/component.cmake
new file mode 100644
index 0000000..bf15460
--- /dev/null
+++ b/components/service/fwu/provider/component.cmake
@@ -0,0 +1,13 @@
+#-------------------------------------------------------------------------------
+# Copyright (c) 2022, Arm Limited and Contributors. All rights reserved.
+#
+# SPDX-License-Identifier: BSD-3-Clause
+#
+#-------------------------------------------------------------------------------
+if (NOT DEFINED TGT)
+ message(FATAL_ERROR "mandatory parameter TGT is not defined.")
+endif()
+
+target_sources(${TGT} PRIVATE
+ "${CMAKE_CURRENT_LIST_DIR}/fwu_provider.c"
+ )
diff --git a/components/service/fwu/provider/fwu_provider.c b/components/service/fwu/provider/fwu_provider.c
new file mode 100644
index 0000000..fe750f5
--- /dev/null
+++ b/components/service/fwu/provider/fwu_provider.c
@@ -0,0 +1,276 @@
+/*
+ * Copyright (c) 2022, Arm Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <stddef.h>
+#include <common/uuid/uuid.h>
+#include <protocols/service/fwu/packed-c/opcodes.h>
+#include <protocols/rpc/common/packed-c/status.h>
+#include <service/fwu/agent/update_agent.h>
+#include <service/fwu/provider/serializer/fwu_provider_serializer.h>
+#include "fwu_provider.h"
+
+/* Service request handlers */
+static rpc_status_t begin_staging_handler(void *context, struct call_req *req);
+static rpc_status_t end_staging_handler(void *context, struct call_req *req);
+static rpc_status_t cancel_staging_handler(void *context, struct call_req *req);
+static rpc_status_t open_handler(void *context, struct call_req *req);
+static rpc_status_t write_stream_handler(void *context, struct call_req *req);
+static rpc_status_t read_stream_handler(void *context, struct call_req *req);
+static rpc_status_t commit_handler(void *context, struct call_req *req);
+static rpc_status_t accept_image_handler(void *context, struct call_req *req);
+static rpc_status_t select_previous_handler(void *context, struct call_req *req);
+
+/* Handler mapping table for service */
+static const struct service_handler handler_table[] = {
+ {TS_FWU_OPCODE_BEGIN_STAGING, begin_staging_handler},
+ {TS_FWU_OPCODE_END_STAGING, end_staging_handler},
+ {TS_FWU_OPCODE_CANCEL_STAGING, cancel_staging_handler},
+ {TS_FWU_OPCODE_OPEN, open_handler},
+ {TS_FWU_OPCODE_WRITE_STREAM, write_stream_handler},
+ {TS_FWU_OPCODE_READ_STREAM, read_stream_handler},
+ {TS_FWU_OPCODE_COMMIT, commit_handler},
+ {TS_FWU_OPCODE_ACCEPT_IMAGE, accept_image_handler},
+ {TS_FWU_OPCODE_SELECT_PREVIOUS, select_previous_handler}
+};
+
+struct rpc_interface *fwu_provider_init(
+ struct fwu_provider *context,
+ struct update_agent *update_agent)
+{
+ /* Initialise the fwu_provider */
+ context->update_agent = update_agent;
+
+ for (size_t encoding = 0; encoding < TS_RPC_ENCODING_LIMIT; ++encoding)
+ context->serializers[encoding] = NULL;
+
+ service_provider_init(&context->base_provider, context,
+ handler_table, sizeof(handler_table)/sizeof(struct service_handler));
+
+ /* Initialise the associated discovery_provider and attach it */
+ discovery_provider_init(&context->discovery_provider);
+ service_provider_extend(
+ &context->base_provider,
+ &context->discovery_provider.base_provider);
+
+ return service_provider_get_rpc_interface(&context->base_provider);
+}
+
+void fwu_provider_deinit(
+ struct fwu_provider *context)
+{
+ discovery_provider_deinit(&context->discovery_provider);
+}
+
+void fwu_provider_register_serializer(
+ struct fwu_provider *context,
+ unsigned int encoding,
+ const struct fwu_provider_serializer *serializer)
+{
+ if (encoding < TS_RPC_ENCODING_LIMIT) {
+
+ context->serializers[encoding] = serializer;
+ discovery_provider_register_supported_encoding(
+ &context->discovery_provider, encoding);
+ }
+}
+
+static const struct fwu_provider_serializer* get_fwu_serializer(
+ struct fwu_provider *this_instance,
+ const struct call_req *req)
+{
+ const struct fwu_provider_serializer* serializer = NULL;
+ unsigned int encoding = call_req_get_encoding(req);
+
+ if (encoding < TS_RPC_ENCODING_LIMIT)
+ serializer = this_instance->serializers[encoding];
+
+ return serializer;
+}
+
+static rpc_status_t begin_staging_handler(void *context, struct call_req *req)
+{
+ struct fwu_provider *this_instance = (struct fwu_provider *)context;
+
+ int op_status = update_agent_begin_staging(this_instance->update_agent);
+
+ call_req_set_opstatus(req, op_status);
+
+ return TS_RPC_CALL_ACCEPTED;
+}
+
+static rpc_status_t end_staging_handler(void *context, struct call_req *req)
+{
+ struct fwu_provider *this_instance = (struct fwu_provider *)context;
+
+ int op_status = update_agent_end_staging(this_instance->update_agent);
+
+ call_req_set_opstatus(req, op_status);
+
+ return TS_RPC_CALL_ACCEPTED;
+}
+
+static rpc_status_t cancel_staging_handler(void *context, struct call_req *req)
+{
+ struct fwu_provider *this_instance = (struct fwu_provider *)context;
+
+ int op_status = update_agent_cancel_staging(this_instance->update_agent);
+
+ call_req_set_opstatus(req, op_status);
+
+ return TS_RPC_CALL_ACCEPTED;
+}
+
+static rpc_status_t open_handler(void *context, struct call_req *req)
+{
+ rpc_status_t rpc_status = TS_RPC_ERROR_SERIALIZATION_NOT_SUPPORTED;
+ struct call_param_buf *req_buf = call_req_get_req_buf(req);
+ struct fwu_provider *this_instance = (struct fwu_provider *)context;
+ const struct fwu_provider_serializer *serializer = get_fwu_serializer(this_instance, req);
+ struct uuid_octets image_type_uuid;
+
+ if (serializer)
+ rpc_status = serializer->deserialize_open_req(req_buf, &image_type_uuid);
+
+ if (rpc_status == TS_RPC_CALL_ACCEPTED) {
+
+ uint32_t handle = 0;
+ int op_status = update_agent_open(this_instance->update_agent,
+ &image_type_uuid, &handle);
+
+ if (!op_status) {
+
+ struct call_param_buf *resp_buf = call_req_get_resp_buf(req);
+ rpc_status = serializer->serialize_open_resp(resp_buf, handle);
+ }
+
+ call_req_set_opstatus(req, op_status);
+ }
+
+ return rpc_status;
+}
+
+static rpc_status_t write_stream_handler(void *context, struct call_req *req)
+{
+ rpc_status_t rpc_status = TS_RPC_ERROR_SERIALIZATION_NOT_SUPPORTED;
+ struct call_param_buf *req_buf = call_req_get_req_buf(req);
+ struct fwu_provider *this_instance = (struct fwu_provider *)context;
+ const struct fwu_provider_serializer *serializer = get_fwu_serializer(this_instance, req);
+ uint32_t handle = 0;
+ size_t data_len = 0;
+ const uint8_t *data = NULL;
+
+ if (serializer)
+ rpc_status = serializer->deserialize_write_stream_req(
+ req_buf, &handle, &data_len, &data);
+
+ if (rpc_status == TS_RPC_CALL_ACCEPTED) {
+
+ int op_status = update_agent_write_stream(this_instance->update_agent,
+ handle, data, data_len);
+
+ call_req_set_opstatus(req, op_status);
+ }
+
+ return rpc_status;
+}
+
+static rpc_status_t read_stream_handler(void *context, struct call_req *req)
+{
+ rpc_status_t rpc_status = TS_RPC_ERROR_SERIALIZATION_NOT_SUPPORTED;
+ struct call_param_buf *req_buf = call_req_get_req_buf(req);
+ struct fwu_provider *this_instance = (struct fwu_provider *)context;
+ const struct fwu_provider_serializer *serializer = get_fwu_serializer(this_instance, req);
+ uint32_t handle = 0;
+
+ if (serializer)
+ rpc_status = serializer->deserialize_read_stream_req(req_buf, &handle);
+
+ if (rpc_status == TS_RPC_CALL_ACCEPTED) {
+
+ struct call_param_buf *resp_buf = call_req_get_resp_buf(req);
+ uint8_t *payload_buf;
+ size_t max_payload;
+ size_t read_len = 0;
+ size_t total_len = 0;
+
+ serializer->read_stream_resp_payload(resp_buf, &payload_buf, &max_payload);
+
+ int op_status = update_agent_read_stream(this_instance->update_agent,
+ handle, payload_buf, max_payload,
+ &read_len, &total_len);
+
+ if (!op_status)
+ rpc_status = serializer->serialize_read_stream_resp(resp_buf,
+ read_len, total_len);
+
+ call_req_set_opstatus(req, op_status);
+ }
+
+ return rpc_status;
+}
+
+static rpc_status_t commit_handler(void *context, struct call_req *req)
+{
+ rpc_status_t rpc_status = TS_RPC_ERROR_SERIALIZATION_NOT_SUPPORTED;
+ struct call_param_buf *req_buf = call_req_get_req_buf(req);
+ struct fwu_provider *this_instance = (struct fwu_provider *)context;
+ const struct fwu_provider_serializer *serializer = get_fwu_serializer(this_instance, req);
+ uint32_t handle = 0;
+ bool accepted = false;
+ size_t max_atomic_len = 0;
+
+ if (serializer)
+ rpc_status = serializer->deserialize_commit_req(req_buf,
+ &handle, &accepted, &max_atomic_len);
+
+ if (rpc_status == TS_RPC_CALL_ACCEPTED) {
+
+ int op_status = update_agent_commit(
+ this_instance->update_agent, handle, accepted);
+
+ if (!op_status) {
+
+ struct call_param_buf *resp_buf = call_req_get_resp_buf(req);
+ rpc_status = serializer->serialize_commit_resp(resp_buf, 0, 0);
+ }
+
+ call_req_set_opstatus(req, op_status);
+ }
+
+ return rpc_status;
+}
+
+static rpc_status_t accept_image_handler(void *context, struct call_req *req)
+{
+ rpc_status_t rpc_status = TS_RPC_ERROR_SERIALIZATION_NOT_SUPPORTED;
+ struct call_param_buf *req_buf = call_req_get_req_buf(req);
+ struct fwu_provider *this_instance = (struct fwu_provider *)context;
+ const struct fwu_provider_serializer *serializer = get_fwu_serializer(this_instance, req);
+ struct uuid_octets image_type_uuid;
+
+ if (serializer)
+ rpc_status = serializer->deserialize_accept_req(req_buf, &image_type_uuid);
+
+ if (rpc_status == TS_RPC_CALL_ACCEPTED) {
+
+ int op_status = update_agent_accept(this_instance->update_agent, &image_type_uuid);
+
+ call_req_set_opstatus(req, op_status);
+ }
+
+ return rpc_status;
+}
+
+static rpc_status_t select_previous_handler(void *context, struct call_req *req)
+{
+ struct fwu_provider *this_instance = (struct fwu_provider *)context;
+
+ int op_status = update_agent_select_previous(this_instance->update_agent);
+
+ call_req_set_opstatus(req, op_status);
+
+ return TS_RPC_CALL_ACCEPTED;
+}
diff --git a/components/service/fwu/provider/fwu_provider.h b/components/service/fwu/provider/fwu_provider.h
new file mode 100644
index 0000000..3141f54
--- /dev/null
+++ b/components/service/fwu/provider/fwu_provider.h
@@ -0,0 +1,78 @@
+/*
+ * Copyright (c) 2022, Arm Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef FWU_PROVIDER_H
+#define FWU_PROVIDER_H
+
+#include <rpc/common/endpoint/rpc_interface.h>
+#include <service/common/provider/service_provider.h>
+#include <service/discovery/provider/discovery_provider.h>
+#include <protocols/rpc/common/packed-c/encoding.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * Interface dependencies
+ */
+struct fwu_provider_serializer;
+struct update_agent;
+
+/**
+ * \brief fwu_provider instance structure
+ *
+ * An instance of the fwu_provider presents the service level interface for
+ * remote access to the fwu service. In addition to handling incoming call
+ * requests, the fwu_provider is responsible for access control, call parameter
+ * serialization/deserialization and parameter sanitation. Request are delegated
+ * to the associated update_agent.
+ */
+struct fwu_provider
+{
+ struct service_provider base_provider;
+ const struct fwu_provider_serializer *serializers[TS_RPC_ENCODING_LIMIT];
+ struct discovery_provider discovery_provider;
+ struct update_agent *update_agent;
+};
+
+/**
+ * \brief Initialise a fwu_provider
+ *
+ * \param[in] context The subject fwu_provider context
+ * \param[in] update_agent The associated update_agent
+ *
+ * \return A pointer to the exposed rpc_interface or NULL on failure
+ */
+struct rpc_interface *fwu_provider_init(
+ struct fwu_provider *context,
+ struct update_agent *update_agent);
+
+/**
+ * \brief De-initialise a fwu_provider
+ *
+ * \param[in] context The subject fwu_provider context
+ */
+void fwu_provider_deinit(
+ struct fwu_provider *context);
+
+/**
+ * \brief Register a serializer
+ *
+ * \param[in] context The subject fwu_provider context
+ * \param[in] encoding The encoding scheme
+ * \param[in] serializer The serializer
+ */
+void fwu_provider_register_serializer(
+ struct fwu_provider *context,
+ unsigned int encoding,
+ const struct fwu_provider_serializer *serializer);
+
+#ifdef __cplusplus
+} /* extern "C" */
+#endif
+
+#endif /* FWU_PROVIDER_H */
diff --git a/components/service/fwu/provider/serializer/fwu_provider_serializer.h b/components/service/fwu/provider/serializer/fwu_provider_serializer.h
new file mode 100644
index 0000000..3c61bfd
--- /dev/null
+++ b/components/service/fwu/provider/serializer/fwu_provider_serializer.h
@@ -0,0 +1,73 @@
+/*
+ * Copyright (c) 2022, Arm Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef FWU_PROVIDER_SERIALIZER_H
+#define FWU_PROVIDER_SERIALIZER_H
+
+#include <stddef.h>
+#include <stdbool.h>
+#include <stdint.h>
+#include <common/uuid/uuid.h>
+#include <rpc/common/endpoint/rpc_interface.h>
+
+/* Provides a common interface for parameter serialization operations
+ * for the fwu service provider. Allows alternative serialization
+ * protocols to be used without hard-wiring a particular protocol
+ * into the service provider code. A concrete serializer must
+ * implement this interface.
+ */
+struct fwu_provider_serializer {
+
+ /* Operation: open */
+ rpc_status_t (*deserialize_open_req)(
+ const struct call_param_buf *req_buf,
+ struct uuid_octets *image_type_uuid);
+
+ rpc_status_t (*serialize_open_resp)(
+ struct call_param_buf *resp_buf,
+ uint32_t handle);
+
+ /* Operation: write_stream */
+ rpc_status_t (*deserialize_write_stream_req)(
+ const struct call_param_buf *req_buf,
+ uint32_t *handle,
+ size_t *data_len,
+ const uint8_t **data);
+
+ /* Operation: read_stream */
+ rpc_status_t (*deserialize_read_stream_req)(
+ const struct call_param_buf *req_buf,
+ uint32_t *handle);
+
+ void (*read_stream_resp_payload)(
+ const struct call_param_buf *resp_buf,
+ uint8_t **payload_buf,
+ size_t *max_payload);
+
+ rpc_status_t (*serialize_read_stream_resp)(
+ struct call_param_buf *resp_buf,
+ size_t read_bytes,
+ size_t total_bytes);
+
+ /* Operation: commit */
+ rpc_status_t (*deserialize_commit_req)(
+ const struct call_param_buf *req_buf,
+ uint32_t *handle,
+ bool *accepted,
+ size_t *max_atomic_len);
+
+ rpc_status_t (*serialize_commit_resp)(
+ struct call_param_buf *resp_buf,
+ size_t progress,
+ size_t total_work);
+
+ /* Operation: accept_image */
+ rpc_status_t (*deserialize_accept_req)(
+ const struct call_param_buf *req_buf,
+ struct uuid_octets *image_type_uuid);
+};
+
+#endif /* FWU_PROVIDER_SERIALIZER_H */
diff --git a/components/service/fwu/provider/serializer/packed-c/component.cmake b/components/service/fwu/provider/serializer/packed-c/component.cmake
new file mode 100644
index 0000000..4209cae
--- /dev/null
+++ b/components/service/fwu/provider/serializer/packed-c/component.cmake
@@ -0,0 +1,13 @@
+#-------------------------------------------------------------------------------
+# Copyright (c) 2022, Arm Limited and Contributors. All rights reserved.
+#
+# SPDX-License-Identifier: BSD-3-Clause
+#
+#-------------------------------------------------------------------------------
+if (NOT DEFINED TGT)
+ message(FATAL_ERROR "mandatory parameter TGT is not defined.")
+endif()
+
+target_sources(${TGT} PRIVATE
+ "${CMAKE_CURRENT_LIST_DIR}/packedc_fwu_provider_serializer.c"
+ )
diff --git a/components/service/fwu/provider/serializer/packed-c/packedc_fwu_provider_serializer.c b/components/service/fwu/provider/serializer/packed-c/packedc_fwu_provider_serializer.c
new file mode 100644
index 0000000..9413417
--- /dev/null
+++ b/components/service/fwu/provider/serializer/packed-c/packedc_fwu_provider_serializer.c
@@ -0,0 +1,221 @@
+/*
+ * Copyright (c) 2022, Arm Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+#include <string.h>
+#include <protocols/rpc/common/packed-c/status.h>
+#include <protocols/service/fwu/packed-c/fwu_proto.h>
+#include "packedc_fwu_provider_serializer.h"
+
+
+static rpc_status_t deserialize_open_req(
+ const struct call_param_buf *req_buf,
+ struct uuid_octets *image_type_uuid)
+{
+ rpc_status_t rpc_status = TS_RPC_ERROR_INVALID_REQ_BODY;
+ size_t expected_fixed_len = sizeof(struct ts_fwu_open_in);
+
+ if (expected_fixed_len <= req_buf->data_len) {
+
+ const struct ts_fwu_open_in *recv_msg =
+ (const struct ts_fwu_open_in *)req_buf->data;
+
+ memcpy(image_type_uuid->octets,
+ recv_msg->image_type_uuid, UUID_OCTETS_LEN);
+
+ rpc_status = TS_RPC_CALL_ACCEPTED;
+ }
+
+ return rpc_status;
+}
+
+static rpc_status_t serialize_open_resp(
+ struct call_param_buf *resp_buf,
+ uint32_t handle)
+{
+ rpc_status_t rpc_status = TS_RPC_ERROR_INTERNAL;
+ size_t fixed_len = sizeof(struct ts_fwu_open_out);
+
+ if (fixed_len <= resp_buf->size) {
+
+ struct ts_fwu_open_out *resp_msg =
+ (struct ts_fwu_open_out *)resp_buf->data;
+
+ resp_msg->handle = handle;
+
+ resp_buf->data_len = fixed_len;
+ rpc_status = TS_RPC_CALL_ACCEPTED;
+ }
+
+ return rpc_status;
+}
+
+/* Operation: write_stream */
+static rpc_status_t deserialize_write_stream_req(
+ const struct call_param_buf *req_buf,
+ uint32_t *handle,
+ size_t *data_len,
+ const uint8_t **data)
+{
+ rpc_status_t rpc_status = TS_RPC_ERROR_INVALID_REQ_BODY;
+ size_t expected_fixed_len = sizeof(struct ts_fwu_write_stream_in);
+
+ if (expected_fixed_len <= req_buf->data_len) {
+
+ const struct ts_fwu_write_stream_in *recv_msg =
+ (const struct ts_fwu_write_stream_in *)req_buf->data;
+
+ *handle = recv_msg->handle;
+ *data_len = recv_msg->data_len;
+ *data = recv_msg->payload;
+ rpc_status = TS_RPC_CALL_ACCEPTED;
+ }
+
+ return rpc_status;
+}
+
+/* Operation: read_stream */
+static rpc_status_t deserialize_read_stream_req(
+ const struct call_param_buf *req_buf,
+ uint32_t *handle)
+{
+ rpc_status_t rpc_status = TS_RPC_ERROR_INVALID_REQ_BODY;
+ size_t expected_fixed_len = sizeof(struct ts_fwu_read_stream_in);
+
+ if (expected_fixed_len <= req_buf->data_len) {
+
+ const struct ts_fwu_read_stream_in *recv_msg =
+ (const struct ts_fwu_read_stream_in *)req_buf->data;
+
+ *handle = recv_msg->handle;
+ rpc_status = TS_RPC_CALL_ACCEPTED;
+ }
+
+ return rpc_status;
+}
+
+static void read_stream_resp_payload(
+ const struct call_param_buf *resp_buf,
+ uint8_t **payload_buf,
+ size_t *max_payload)
+{
+ struct ts_fwu_read_stream_out *resp_msg = (struct ts_fwu_read_stream_out *)resp_buf->data;
+ size_t fixed_len = offsetof(struct ts_fwu_read_stream_out, payload);
+
+ *max_payload = 0;
+ *payload_buf = resp_msg->payload;
+
+ if (fixed_len < resp_buf->size)
+ *max_payload = resp_buf->size - fixed_len;
+}
+
+static rpc_status_t serialize_read_stream_resp(
+ struct call_param_buf *resp_buf,
+ size_t read_bytes,
+ size_t total_bytes)
+{
+ rpc_status_t rpc_status = TS_RPC_ERROR_INTERNAL;
+ struct ts_fwu_read_stream_out *resp_msg = (struct ts_fwu_read_stream_out *)resp_buf->data;
+ size_t proto_overhead = offsetof(struct ts_fwu_read_stream_out, payload);
+
+ if (read_bytes > (SIZE_MAX - proto_overhead))
+ return TS_RPC_ERROR_INVALID_PARAMETER;
+
+ size_t required_len = proto_overhead + read_bytes;
+
+ if (required_len <= resp_buf->size) {
+
+ resp_msg->read_bytes = read_bytes;
+ resp_msg->total_bytes = total_bytes;
+
+ resp_buf->data_len = required_len;
+ rpc_status = TS_RPC_CALL_ACCEPTED;
+ }
+
+ return rpc_status;
+}
+
+/* Operation: commit */
+static rpc_status_t deserialize_commit_req(
+ const struct call_param_buf *req_buf,
+ uint32_t *handle,
+ bool *accepted,
+ size_t *max_atomic_len)
+{
+ rpc_status_t rpc_status = TS_RPC_ERROR_INVALID_REQ_BODY;
+ size_t expected_fixed_len = sizeof(struct ts_fwu_commit_in);
+
+ if (expected_fixed_len <= req_buf->data_len) {
+
+ const struct ts_fwu_commit_in *recv_msg =
+ (const struct ts_fwu_commit_in *)req_buf->data;
+
+ *handle = recv_msg->handle;
+ *accepted = (recv_msg->acceptance_req == 0);
+ *max_atomic_len = recv_msg->max_atomic_len;
+ rpc_status = TS_RPC_CALL_ACCEPTED;
+ }
+
+ return rpc_status;
+}
+
+static rpc_status_t serialize_commit_resp(
+ struct call_param_buf *resp_buf,
+ size_t progress,
+ size_t total_work)
+{
+ rpc_status_t rpc_status = TS_RPC_ERROR_INTERNAL;
+ struct ts_fwu_commit_out *resp_msg = (struct ts_fwu_commit_out *)resp_buf->data;
+
+ size_t required_len = sizeof(struct ts_fwu_commit_out);
+
+ if (required_len <= resp_buf->size) {
+
+ resp_msg->progress = progress;
+ resp_msg->total_work = total_work;
+
+ resp_buf->data_len = required_len;
+ rpc_status = TS_RPC_CALL_ACCEPTED;
+ }
+
+ return rpc_status;
+}
+
+/* Operation: accept_image */
+static rpc_status_t deserialize_accept_req(
+ const struct call_param_buf *req_buf,
+ struct uuid_octets *image_type_uuid)
+{
+ rpc_status_t rpc_status = TS_RPC_ERROR_INVALID_REQ_BODY;
+ size_t expected_fixed_len = sizeof(struct ts_fwu_accept_image_in);
+
+ if (expected_fixed_len <= req_buf->data_len) {
+
+ const struct ts_fwu_accept_image_in *recv_msg =
+ (const struct ts_fwu_accept_image_in *)req_buf->data;
+
+ memcpy(image_type_uuid->octets, recv_msg->image_type_uuid, UUID_OCTETS_LEN);
+ rpc_status = TS_RPC_CALL_ACCEPTED;
+ }
+
+ return rpc_status;
+}
+
+/* Singleton method to provide access to the serializer instance */
+const struct fwu_provider_serializer *packedc_fwu_provider_serializer_instance(void)
+{
+ static const struct fwu_provider_serializer instance = {
+ deserialize_open_req,
+ serialize_open_resp,
+ deserialize_write_stream_req,
+ deserialize_read_stream_req,
+ read_stream_resp_payload,
+ serialize_read_stream_resp,
+ deserialize_commit_req,
+ serialize_commit_resp,
+ deserialize_accept_req
+ };
+
+ return &instance;
+}
diff --git a/components/service/fwu/provider/serializer/packed-c/packedc_fwu_provider_serializer.h b/components/service/fwu/provider/serializer/packed-c/packedc_fwu_provider_serializer.h
new file mode 100644
index 0000000..b9ced37
--- /dev/null
+++ b/components/service/fwu/provider/serializer/packed-c/packedc_fwu_provider_serializer.h
@@ -0,0 +1,25 @@
+/*
+ * Copyright (c) 2022, Arm Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef PACKEDC_FWU_PROVIDER_SERIALIZER_H
+#define PACKEDC_FWU_PROVIDER_SERIALIZER_H
+
+#include <service/fwu/provider/serializer/fwu_provider_serializer.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* Singleton method to provide access to the packed-c serializer
+ * for the fwu service provider.
+ */
+const struct fwu_provider_serializer *packedc_fwu_provider_serializer_instance(void);
+
+#ifdef __cplusplus
+} /* extern "C" */
+#endif
+
+#endif /* PACKEDC_FWU_PROVIDER_SERIALIZER_H */
diff --git a/components/service/fwu/test/fwu_dut/sim/sim_fwu_dut.cpp b/components/service/fwu/test/fwu_dut/sim/sim_fwu_dut.cpp
index ae4c1c0..3ae06de 100644
--- a/components/service/fwu/test/fwu_dut/sim/sim_fwu_dut.cpp
+++ b/components/service/fwu/test/fwu_dut/sim/sim_fwu_dut.cpp
@@ -4,14 +4,18 @@
* SPDX-License-Identifier: BSD-3-Clause
*/
+#include <cstring>
#include <sstream>
#include <CppUTest/TestHarness.h>
#include <media/volume/index/volume_index.h>
#include <media/disk/guid.h>
+#include <service/discovery/provider/discovery_provider.h>
+#include <service/discovery/provider/serializer/packed-c/packedc_discovery_provider_serializer.h>
#include <service/fwu/installer/installer_index.h>
#include <service/fwu/fw_store/banked/volume_id.h>
#include <service/fwu/fw_store/banked/metadata_serializer/v1/metadata_serializer_v1.h>
#include <service/fwu/inspector/direct/direct_fw_inspector.h>
+#include <service/fwu/provider/serializer/packed-c/packedc_fwu_provider_serializer.h>
#include <service/fwu/test/fwu_client/direct/direct_fwu_client.h>
#include <service/fwu/test/metadata_fetcher/volume/volume_metadata_fetcher.h>
#include "sim_fwu_dut.h"
@@ -25,6 +29,7 @@
m_boot_info(),
m_metadata_checker(NULL),
m_num_locations(num_locations),
+ m_service_iface(NULL),
m_fw_flash(),
m_partitioned_block_store(),
m_block_store(NULL),
@@ -35,7 +40,8 @@
m_copy_installer_used_count(0),
m_copy_installer_pool(),
m_update_agent(),
- m_fw_store()
+ m_fw_store(),
+ m_fwu_provider()
{
m_boot_info = {0};
@@ -48,6 +54,29 @@
install_factory_images(num_locations);
+ /* Initialise fwu service provider prior to boot to ensure that a
+ * viable service interface exists to safely handle an incoming
+ * request that occurs prior to the boot method being called.
+ * Note that the update_agent is in the de-initialized state so
+ * any operations will be denied.
+ */
+ memset(&m_update_agent, 0, sizeof(m_update_agent));
+ m_update_agent.state = FWU_STATE_DEINITIALZED;
+
+ m_service_iface = fwu_provider_init(
+ &m_fwu_provider,
+ &m_update_agent);
+
+ fwu_provider_register_serializer(
+ &m_fwu_provider,
+ TS_RPC_ENCODING_PACKED_C,
+ packedc_fwu_provider_serializer_instance());
+
+ discovery_provider_register_serializer(
+ &m_fwu_provider.discovery_provider,
+ TS_RPC_ENCODING_PACKED_C,
+ packedc_discovery_provider_serializer_instance());
+
m_metadata_checker = create_metadata_checker();
}
@@ -58,6 +87,8 @@
delete m_metadata_checker;
m_metadata_checker = NULL;
+ fwu_provider_deinit(&m_fwu_provider);
+
destroy_installers();
destroy_fw_volumes();
destroy_storage();
@@ -126,6 +157,11 @@
m_is_booted = false;
}
+struct rpc_interface *sim_fwu_dut::get_service_interface(void)
+{
+ return m_service_iface;
+}
+
struct boot_info sim_fwu_dut::get_boot_info(void) const
{
return m_boot_info;
diff --git a/components/service/fwu/test/fwu_dut/sim/sim_fwu_dut.h b/components/service/fwu/test/fwu_dut/sim/sim_fwu_dut.h
index 5d94834..b30e32b 100644
--- a/components/service/fwu/test/fwu_dut/sim/sim_fwu_dut.h
+++ b/components/service/fwu/test/fwu_dut/sim/sim_fwu_dut.h
@@ -19,6 +19,7 @@
#include <service/fwu/fw_store/banked/bank_scheme.h>
#include <service/fwu/installer/raw/raw_installer.h>
#include <service/fwu/installer/copy/copy_installer.h>
+#include <service/fwu/provider/fwu_provider.h>
#include <service/fwu/test/metadata_checker/metadata_checker.h>
#include <service/fwu/test/fwu_client/fwu_client.h>
#include <service/fwu/test/fwu_dut/fwu_dut.h>
@@ -55,6 +56,8 @@
metadata_checker *create_metadata_checker(bool is_primary = true) const;
fwu_client *create_fwu_client(void);
+ struct rpc_interface *get_service_interface(void);
+
private:
/* Maximum locations supported */
@@ -100,6 +103,7 @@
struct boot_info m_boot_info;
metadata_checker *m_metadata_checker;
unsigned int m_num_locations;
+ struct rpc_interface *m_service_iface;
/* Firmware storage */
struct ram_block_store m_fw_flash;
@@ -120,6 +124,7 @@
/* The core fwu service components */
struct update_agent m_update_agent;
struct fw_store m_fw_store;
+ struct fwu_provider m_fwu_provider;
};
#endif /* SIM_FWU_DUT_H */
diff --git a/deployments/component-test/component-test.cmake b/deployments/component-test/component-test.cmake
index 465175a..b23c778 100644
--- a/deployments/component-test/component-test.cmake
+++ b/deployments/component-test/component-test.cmake
@@ -121,6 +121,8 @@
"components/service/fwu/installer/factory/default/test"
"components/service/fwu/inspector/mock"
"components/service/fwu/inspector/direct"
+ "components/service/fwu/provider"
+ "components/service/fwu/provider/serializer/packed-c"
"components/service/fwu/test/fwu_client/direct"
"components/service/fwu/test/fwu_dut"
"components/service/fwu/test/fwu_dut/sim"