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/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 */