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"