Upstream-Status: Pending [Not submitted to upstream yet]
Signed-off-by: Vishnu Banavath <vishnu.banavath@arm.com>

From 318f0dda8d258f0184a4d8650045e02be02afce2 Mon Sep 17 00:00:00 2001
From: Vishnu Banavath <vishnu.banavath@arm.com>
Date: Fri, 3 Dec 2021 19:19:24 +0000
Subject: [PATCH] Add secure storage ipc backend

Add secure storage ipc ff-m implementation which may use
openamp as rpc to communicate with other processor.

Signed-off-by: Rui Miguel Silva <rui.silva@arm.com>

%% original patch: 0012-Add-secure-storage-ipc-backend.patch

diff --git a/components/service/common/psa_ipc/service_psa_ipc.c b/components/service/common/psa_ipc/service_psa_ipc.c
index e8093c2..95a07c1 100644
--- a/components/service/common/psa_ipc/service_psa_ipc.c
+++ b/components/service/common/psa_ipc/service_psa_ipc.c
@@ -16,6 +16,52 @@
 #include <psa/client.h>
 #include "service_psa_ipc_openamp_lib.h"
 
+static struct psa_invec *psa_call_in_vec_param(uint8_t *req)
+{
+	return (struct psa_invec *)(req + sizeof(struct ns_openamp_msg));
+}
+
+static struct psa_outvec *psa_call_out_vec_param(uint8_t *req, size_t in_len)
+{
+	return (struct psa_outvec *)(req + sizeof(struct ns_openamp_msg) +
+				     (in_len * sizeof(struct psa_invec)));
+}
+
+static size_t psa_call_header_len(const struct psa_invec *in_vec, size_t in_len,
+				  struct psa_outvec *out_vec, size_t out_len)
+{
+	return sizeof(struct ns_openamp_msg) + (in_len * sizeof(*in_vec)) +
+		(out_len * sizeof(*out_vec));
+}
+
+static size_t psa_call_in_vec_len(const struct psa_invec *in_vec, size_t in_len)
+{
+	size_t req_len = 0;
+	int i;
+
+	if (!in_vec || !in_len)
+		return 0;
+
+	for (i = 0; i < in_len; i++)
+		req_len += in_vec[i].len;
+
+	return req_len;
+}
+
+static size_t psa_call_out_vec_len(const struct psa_outvec *out_vec, size_t out_len)
+{
+	size_t resp_len = 0;
+	int i;
+
+	if (!out_vec || !out_len)
+		return 0;
+
+	for (i = 0; i < out_len; i++)
+		resp_len += out_vec[i].len;
+
+	return resp_len;
+}
+
 psa_handle_t psa_connect(struct rpc_caller *caller, uint32_t sid,
 			 uint32_t version)
 {
@@ -31,7 +77,7 @@ psa_handle_t psa_connect(struct rpc_caller *caller, uint32_t sid,
 	rpc_handle = rpc_caller_begin(caller, &req,
 				      sizeof(struct ns_openamp_msg));
 	if (!rpc_handle) {
-		EMSG("psa_connect: could not get handle");
+		EMSG("psa_connect: could not get rpc handle");
 		return PSA_ERROR_GENERIC_ERROR;
 	}
 
@@ -56,14 +102,100 @@ psa_handle_t psa_connect(struct rpc_caller *caller, uint32_t sid,
 	return resp_msg ? (psa_handle_t)resp_msg->reply : PSA_NULL_HANDLE;
 }
 
-psa_status_t psa_call(struct rpc_caller *caller, psa_handle_t handle,
+psa_status_t psa_call(struct rpc_caller *caller, psa_handle_t psa_handle,
 		      int32_t type, const struct psa_invec *in_vec,
 		      size_t in_len, struct psa_outvec *out_vec, size_t out_len)
 {
+	psa_status_t psa_status = PSA_SUCCESS;
+	struct s_openamp_msg *resp_msg = NULL;
+	struct psa_outvec *out_vec_param;
+	struct psa_invec *in_vec_param;
+	struct ns_openamp_msg *req_msg;
+	rpc_call_handle rpc_handle;
+	size_t out_vec_len;
+	size_t in_vec_len;
+	size_t header_len;
+	uint8_t *payload;
+	size_t resp_len;
+	uint8_t *resp;
+	uint8_t *req;
+	int ret;
+	int i;
+
+	if ((psa_handle == PSA_NULL_HANDLE) || !caller)
+		return PSA_ERROR_INVALID_ARGUMENT;
+
+	header_len = psa_call_header_len(in_vec, in_len, out_vec, out_len);
+	in_vec_len = psa_call_in_vec_len(in_vec, in_len);
+	out_vec_len = psa_call_out_vec_len(out_vec, out_len);
 
+	rpc_handle = rpc_caller_begin(caller, &req, header_len + in_vec_len);
+	if (!rpc_handle) {
+		EMSG("psa_call: could not get handle");
+		return PSA_ERROR_GENERIC_ERROR;
+	}
+
+	payload = req + header_len;
+
+	out_vec_param = psa_call_out_vec_param(req, in_len);
+	in_vec_param = psa_call_in_vec_param(req);
+
+	req_msg = (struct ns_openamp_msg *)req;
+
+	req_msg->call_type = OPENAMP_PSA_CALL;
+	req_msg->request_id = 1234;
+	req_msg->params.psa_call_params.handle = psa_handle;
+	req_msg->params.psa_call_params.type = type;
+	req_msg->params.psa_call_params.in_len = in_len;
+	req_msg->params.psa_call_params.in_vec = rpc_caller_virt_to_phys(caller, in_vec_param);
+	req_msg->params.psa_call_params.out_len = out_len;
+	req_msg->params.psa_call_params.out_vec = rpc_caller_virt_to_phys(caller, out_vec_param);
+
+	for (i = 0; i < in_len; i++) {
+		in_vec_param[i].base = rpc_caller_virt_to_phys(caller, payload);
+		in_vec_param[i].len = in_vec[i].len;
+
+		memcpy(payload, in_vec[i].base, in_vec[i].len);
+		payload += in_vec[i].len;
+	}
+
+	for (i = 0; i < out_len; i++) {
+		out_vec_param[i].base = NULL;
+		out_vec_param[i].len = out_vec[i].len;
+	}
+
+	ret = rpc_caller_invoke(caller, rpc_handle, 0, &psa_status, &resp,
+				&resp_len);
+	if (ret != TS_RPC_CALL_ACCEPTED) {
+		EMSG("psa_call: invoke failed: %d", ret);
+		return PSA_ERROR_GENERIC_ERROR;
+	}
+
+	if (psa_status != PSA_SUCCESS) {
+		EMSG("psa_call: psa_status invoke failed: %d", psa_status);
+		return PSA_ERROR_GENERIC_ERROR;
+	}
+
+	resp_msg = (struct s_openamp_msg *)resp;
+
+	if (!resp_msg || !out_len || resp_msg->reply != PSA_SUCCESS)
+		goto caller_end;
+
+	out_vec_param = (struct psa_outvec *)rpc_caller_phys_to_virt(caller,
+						     resp_msg->params.out_vec);
+
+	for (i = 0; i < resp_msg->params.out_len; i++) {
+		memcpy(out_vec[i].base, rpc_caller_phys_to_virt(caller, out_vec_param[i].base),
+		       out_vec[i].len);
+	}
+
+caller_end:
+	rpc_caller_end(caller, rpc_handle);
+
+	return resp_msg ? resp_msg->reply : PSA_ERROR_COMMUNICATION_FAILURE;
 }
 
-void psa_close(struct rpc_caller *caller, psa_handle_t handle)
+void psa_close(struct rpc_caller *caller, psa_handle_t psa_handle)
 {
 	psa_status_t psa_status = PSA_SUCCESS;
 	struct s_openamp_msg *resp_msg = NULL;
@@ -74,6 +206,9 @@ void psa_close(struct rpc_caller *caller, psa_handle_t handle)
 	uint8_t *req;
 	int ret;
 
+	if ((psa_handle == PSA_NULL_HANDLE) || !caller)
+		return;
+
 	rpc_handle = rpc_caller_begin(caller, &req,
 				      sizeof(struct ns_openamp_msg));
 	if (!rpc_handle) {
@@ -84,7 +219,7 @@ void psa_close(struct rpc_caller *caller, psa_handle_t handle)
 	req_msg = (struct ns_openamp_msg *)req;
 
 	req_msg->call_type = OPENAMP_PSA_CLOSE;
-	req_msg->params.psa_close_params.handle = handle;
+	req_msg->params.psa_close_params.handle = psa_handle;
 
 	ret = rpc_caller_invoke(caller, rpc_handle, 0, &psa_status, &resp,
 				&resp_len);
diff --git a/components/service/secure_storage/backend/secure_storage_ipc/component.cmake b/components/service/secure_storage/backend/secure_storage_ipc/component.cmake
new file mode 100644
index 0000000..5d8f671
--- /dev/null
+++ b/components/service/secure_storage/backend/secure_storage_ipc/component.cmake
@@ -0,0 +1,14 @@
+#-------------------------------------------------------------------------------
+# Copyright (c) 2020-2021, 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}/secure_storage_ipc.c"
+	)
+
diff --git a/components/service/secure_storage/backend/secure_storage_ipc/secure_storage_ipc.c b/components/service/secure_storage/backend/secure_storage_ipc/secure_storage_ipc.c
new file mode 100644
index 0000000..9b55f77
--- /dev/null
+++ b/components/service/secure_storage/backend/secure_storage_ipc/secure_storage_ipc.c
@@ -0,0 +1,214 @@
+/*
+ * Copyright (c) 2021, Arm Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <protocols/rpc/common/packed-c/status.h>
+#include "secure_storage_ipc.h"
+#include <psa/client.h>
+#include <psa/sid.h>
+#include <rpc_caller.h>
+#include <string.h>
+#include <trace.h>
+
+
+static psa_status_t secure_storage_ipc_set(void *context, uint32_t client_id,
+			 psa_storage_uid_t uid, size_t data_length,
+			 const void *p_data, psa_storage_create_flags_t create_flags)
+{
+	struct secure_storage_ipc *ipc = context;
+	struct rpc_caller *caller = ipc->client.caller;
+	psa_handle_t psa_handle;
+	psa_status_t psa_status;
+	struct psa_invec in_vec[] = {
+		{ .base = &uid, .len = sizeof(uid) },
+		{ .base = p_data, .len = data_length },
+		{ .base = &create_flags, .len = sizeof(create_flags) },
+	};
+
+	(void)client_id;
+
+	ipc->client.rpc_status = TS_RPC_CALL_ACCEPTED;
+
+	/* Validating input parameters */
+	if (p_data == NULL)
+		return PSA_ERROR_INVALID_ARGUMENT;
+
+	psa_status = psa_call(caller, TFM_PROTECTED_STORAGE_SERVICE_HANDLE,
+			      TFM_PS_SET, in_vec, IOVEC_LEN(in_vec), NULL, 0);
+	if (psa_status < 0)
+		EMSG("ipc_set: psa_call failed: %d", psa_status);
+
+	return psa_status;
+}
+
+static psa_status_t secure_storage_ipc_get(void *context,
+					   uint32_t client_id,
+					   psa_storage_uid_t uid,
+					   size_t data_offset,
+					   size_t data_size,
+					   void *p_data,
+					   size_t *p_data_length)
+{
+	struct secure_storage_ipc *ipc = context;
+	struct rpc_caller *caller = ipc->client.caller;
+	psa_handle_t psa_handle;
+	psa_status_t psa_status;
+	uint32_t offset = (uint32_t)data_offset;
+	struct psa_invec in_vec[] = {
+		{ .base = &uid, .len = sizeof(uid) },
+		{ .base = &offset, .len = sizeof(offset) },
+	};
+	struct psa_outvec out_vec[] = {
+		{ .base = p_data, .len = data_size },
+	};
+
+	if (!p_data_length) {
+		EMSG("ipc_get: p_data_length not defined");
+		return PSA_ERROR_INVALID_ARGUMENT;
+	}
+
+	psa_status = psa_call(caller, TFM_PROTECTED_STORAGE_SERVICE_HANDLE,
+			      TFM_PS_GET, in_vec, IOVEC_LEN(in_vec),
+			      out_vec, IOVEC_LEN(out_vec));
+	if (psa_status == PSA_SUCCESS)
+		*p_data_length = out_vec[0].len;
+
+	return psa_status;
+}
+
+static psa_status_t secure_storage_ipc_get_info(void *context,
+						uint32_t client_id,
+						psa_storage_uid_t uid,
+						struct psa_storage_info_t *p_info)
+{
+	struct secure_storage_ipc *ipc = context;
+	struct rpc_caller *caller = ipc->client.caller;
+	psa_handle_t psa_handle;
+	psa_status_t psa_status;
+	struct psa_invec in_vec[] = {
+		{ .base = &uid, .len = sizeof(uid) },
+	};
+	struct psa_outvec out_vec[] = {
+		{ .base = p_info, .len = sizeof(*p_info) },
+	};
+
+	(void)client_id;
+
+	/* Validating input parameters */
+	if (!p_info)
+		return PSA_ERROR_INVALID_ARGUMENT;
+
+	psa_status = psa_call(caller, TFM_PROTECTED_STORAGE_SERVICE_HANDLE,
+			      TFM_PS_GET_INFO, in_vec,
+			      IOVEC_LEN(in_vec), out_vec, IOVEC_LEN(out_vec));
+	if (psa_status != PSA_SUCCESS)
+		EMSG("ipc_get_info: failed to psa_call: %d", psa_status);
+
+	return psa_status;
+}
+
+static psa_status_t secure_storage_ipc_remove(void *context,
+						uint32_t client_id,
+						psa_storage_uid_t uid)
+{
+	struct secure_storage_ipc *ipc = context;
+	struct rpc_caller *caller = ipc->client.caller;
+	psa_handle_t psa_handle;
+	psa_status_t psa_status;
+	struct psa_invec in_vec[] = {
+		{ .base = &uid, .len = sizeof(uid) },
+	};
+
+	(void)client_id;
+
+	psa_status = psa_call(caller, TFM_PROTECTED_STORAGE_SERVICE_HANDLE,
+			      TFM_PS_REMOVE, in_vec,
+			      IOVEC_LEN(in_vec), NULL, 0);
+	if (psa_status != PSA_SUCCESS)
+		EMSG("ipc_remove: failed to psa_call: %d", psa_status);
+
+	return psa_status;
+}
+
+static psa_status_t secure_storage_ipc_create(void *context,
+					      uint32_t client_id,
+					      uint64_t uid,
+					      size_t capacity,
+					      uint32_t create_flags)
+{
+	(void)context;
+	(void)uid;
+	(void)client_id;
+	(void)capacity;
+	(void)create_flags;
+
+	return PSA_ERROR_NOT_SUPPORTED;
+}
+
+static psa_status_t secure_storage_set_extended(void *context,
+						uint32_t client_id,
+						uint64_t uid,
+						size_t data_offset,
+						size_t data_length,
+						const void *p_data)
+{
+	(void)context;
+	(void)uid;
+	(void)client_id;
+	(void)data_offset;
+	(void)data_length;
+	(void)p_data;
+
+	return PSA_ERROR_NOT_SUPPORTED;
+}
+
+static uint32_t secure_storage_get_support(void *context, uint32_t client_id)
+{
+	struct secure_storage_ipc *ipc = context;
+	struct rpc_caller *caller = ipc->client.caller;
+	psa_handle_t psa_handle;
+	psa_status_t psa_status;
+	uint32_t support_flags;
+	struct psa_outvec out_vec[] = {
+		{ .base = &support_flags, .len =  sizeof(support_flags) },
+	};
+
+	(void)client_id;
+
+	psa_status = psa_call(caller, TFM_PROTECTED_STORAGE_SERVICE_HANDLE,
+			      TFM_PS_GET_SUPPORT, NULL, 0,
+			      out_vec, IOVEC_LEN(out_vec));
+	if (psa_status != PSA_SUCCESS)
+		EMSG("ipc_get_support: failed to psa_call: %d", psa_status);
+
+	return psa_status;
+}
+
+struct storage_backend *secure_storage_ipc_init(struct secure_storage_ipc *context,
+						struct rpc_caller *caller)
+{
+	service_client_init(&context->client, caller);
+
+	static const struct storage_backend_interface interface =
+	{
+		.set = secure_storage_ipc_set,
+		.get = secure_storage_ipc_get,
+		.get_info = secure_storage_ipc_get_info,
+		.remove = secure_storage_ipc_remove,
+		.create = secure_storage_ipc_create,
+		.set_extended = secure_storage_set_extended,
+		.get_support = secure_storage_get_support,
+	};
+
+	context->backend.context = context;
+	context->backend.interface = &interface;
+
+	return &context->backend;
+}
+
+void secure_storage_ipc_deinit(struct secure_storage_ipc *context)
+{
+	service_client_deinit(&context->client);
+}
diff --git a/components/service/secure_storage/backend/secure_storage_ipc/secure_storage_ipc.h b/components/service/secure_storage/backend/secure_storage_ipc/secure_storage_ipc.h
new file mode 100644
index 0000000..e8c1e8f
--- /dev/null
+++ b/components/service/secure_storage/backend/secure_storage_ipc/secure_storage_ipc.h
@@ -0,0 +1,52 @@
+/*
+ * Copyright (c) 2020-2021, Arm Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef SECURE_STORAGE_IPC_H
+#define SECURE_STORAGE_IPC_H
+
+#include <service/secure_storage/backend/storage_backend.h>
+#include <service/common/client/service_client.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * @brief      Secure storage ipc instance
+ */
+struct secure_storage_ipc
+{
+    struct storage_backend backend;
+    struct service_client client;
+};
+
+/**
+ * @brief      Initialize a secure storage ipc client
+ *
+ * A secure storage client is a storage backend that makes RPC calls
+ * to a remote secure storage provider.
+ *
+ * @param[in]  context    Instance data
+ * @param[in]  rpc_caller RPC caller instance
+ *
+ *
+ * @return     Pointer to inialized storage backend or NULL on failure
+ */
+struct storage_backend *secure_storage_ipc_init(struct secure_storage_ipc *context,
+						struct rpc_caller *caller);
+
+/**
+ * @brief      Deinitialize a secure storage ipc client
+ *
+ * @param[in]  context   Instance data
+ */
+void secure_storage_ipc_deinit(struct secure_storage_ipc *context);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* SECURE_STORAGE_IPC_H */
diff --git a/deployments/se-proxy/opteesp/CMakeLists.txt b/deployments/se-proxy/opteesp/CMakeLists.txt
index e0e0e12..663177b 100644
--- a/deployments/se-proxy/opteesp/CMakeLists.txt
+++ b/deployments/se-proxy/opteesp/CMakeLists.txt
@@ -73,6 +73,7 @@ add_components(TARGET "se-proxy"
 		"components/service/crypto/factory/full"
 		"components/service/secure_storage/include"
 		"components/service/secure_storage/frontend/secure_storage_provider"
+		"components/service/secure_storage/backend/secure_storage_ipc"
 		"components/service/attestation/include"
 		"components/service/attestation/provider"
 		"components/service/attestation/provider/serializer/packed-c"
-- 
2.25.1

