From f385ddacc8cc62842f7c9c91622d59959c41e718 Mon Sep 17 00:00:00 2001
From: Harsimran Singh Tungal <harsimransingh.tungal@arm.com>
Date: Thu, 28 Nov 2024 12:02:28 +0000
Subject: [PATCH 04/11] Integrate PSA FWU IPC framework for Corstone-1000

Integrate IPC framework for PSA FWU calls between Cortex-A side and Cortex-M subsystems.

IPC framework is required to bridge the PSA FWU calls for the platforms which have
both Cortex-A and Cortex-M subsystems. Corstone-1000 falls under this category of
platforms. In these platforms, the PSA FWU client and PSA FWU provider exist on
Cortex-A and all the PSA FWU services are implemented on Cortex-M side. This IPC
framework forwards the PSA FWU calls from Cortex-A to Cortex-M subsystem.

Upstream-Status: Submitted [https://review.trustedfirmware.org/c/TS/trusted-services/+/33826]
Signed-off-by: Harsimran Singh Tungal <harsimransingh.tungal@arm.com>
---
 components/service/common/include/psa/sid.h   |   6 +-
 .../interface/psa_ipc/component.cmake         |  13 +
 .../psa_fwu_m/interface/psa_ipc/psa_fwu_ipc.c | 253 ++++++++++++++++++
 .../psa_fwu_m/interface/psa_ipc/psa_fwu_ipc.h |  49 ++++
 .../se-proxy/infra/corstone1000/infra.cmake   |   2 +-
 .../corstone1000/service_proxy_factory.c      |  16 ++
 6 files changed, 337 insertions(+), 2 deletions(-)
 create mode 100644 components/service/fwu/psa_fwu_m/interface/psa_ipc/component.cmake
 create mode 100644 components/service/fwu/psa_fwu_m/interface/psa_ipc/psa_fwu_ipc.c
 create mode 100644 components/service/fwu/psa_fwu_m/interface/psa_ipc/psa_fwu_ipc.h

diff --git a/components/service/common/include/psa/sid.h b/components/service/common/include/psa/sid.h
index 5aaa659d..0235764d 100644
--- a/components/service/common/include/psa/sid.h
+++ b/components/service/common/include/psa/sid.h
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2019-2023, Arm Limited. All rights reserved.
+ * Copyright (c) 2019-2024, Arm Limited. All rights reserved.
  *
  * SPDX-License-Identifier: BSD-3-Clause
  *
@@ -58,6 +58,10 @@ extern "C" {
 #define TFM_ATTEST_GET_TOKEN_SIZE  1002
 
 /******** TFM_SP_FWU ********/
+#define TFM_FIRMWARE_UPDATE_SERVICE_SID                            (0x000000A0U)
+#define TFM_FIRMWARE_UPDATE_SERVICE_VERSION                        (1U)
+#define TFM_FIRMWARE_UPDATE_SERVICE_HANDLE                         (0x40000104U)
+
 #define TFM_FWU_WRITE_SID                                          (0x000000A0U)
 #define TFM_FWU_WRITE_VERSION                                      (1U)
 #define TFM_FWU_INSTALL_SID                                        (0x000000A1U)
diff --git a/components/service/fwu/psa_fwu_m/interface/psa_ipc/component.cmake b/components/service/fwu/psa_fwu_m/interface/psa_ipc/component.cmake
new file mode 100644
index 00000000..cdc653a6
--- /dev/null
+++ b/components/service/fwu/psa_fwu_m/interface/psa_ipc/component.cmake
@@ -0,0 +1,13 @@
+#-------------------------------------------------------------------------------
+# Copyright (c) 2024, 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}/psa_fwu_ipc.c"
+)
diff --git a/components/service/fwu/psa_fwu_m/interface/psa_ipc/psa_fwu_ipc.c b/components/service/fwu/psa_fwu_m/interface/psa_ipc/psa_fwu_ipc.c
new file mode 100644
index 00000000..a47ae539
--- /dev/null
+++ b/components/service/fwu/psa_fwu_m/interface/psa_ipc/psa_fwu_ipc.c
@@ -0,0 +1,253 @@
+/*
+ * Copyright (c) 2024, Arm Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <stddef.h>
+#include <string.h>
+#include <trace.h>
+
+#include <protocols/rpc/common/packed-c/status.h>
+#include <psa/client.h>
+#include <psa/sid.h>
+#include <service/common/client/service_client.h>
+#include "service/fwu/psa_fwu_m/interface/psa_ipc/psa_fwu_ipc.h"
+#include "service/fwu/psa_fwu_m/interface/tfm_fwu_defs.h"
+#include "service/fwu/psa_fwu_m/interface/update.h"
+
+/**
+ * @brief      The singleton psa_fwu_ipc instance
+ *
+ * The psa attestation C API assumes a single backend service provider.
+ */
+static struct service_client instance;
+
+psa_status_t psa_fwu_ipc_init(struct rpc_caller_session *session)
+{
+	return service_client_init(&instance, session);
+}
+
+void psa_fwu_ipc_deinit(void)
+{
+	service_client_deinit(&instance);
+}
+
+int psa_fwu_rpc_status(void)
+{
+	return instance.rpc_status;
+}
+
+psa_status_t psa_fwu_query(psa_fwu_component_t component,
+			   psa_fwu_component_info_t *info)
+{
+	if (!instance.session)
+		return PSA_ERROR_BAD_STATE;
+	if (!info)
+		return PSA_ERROR_INVALID_ARGUMENT;
+
+	psa_status_t status = PSA_ERROR_INVALID_ARGUMENT;
+	struct rpc_caller_interface *caller = instance.session->caller;
+	struct psa_invec in_vec[] = {
+		{ .base = psa_ptr_to_u32(&component), .len = sizeof(component) },
+	};
+	struct psa_outvec out_vec[] = {
+		{ .base = psa_ptr_to_u32(info), .len = sizeof(*info) },
+	};
+
+	status = psa_call(caller, TFM_FIRMWARE_UPDATE_SERVICE_HANDLE,
+			  TFM_FWU_QUERY, in_vec, IOVEC_LEN(in_vec),
+			  out_vec, IOVEC_LEN(out_vec));
+	if (status != PSA_SUCCESS)
+		EMSG("failed to psa_call: %d", status);
+
+	return status;
+}
+
+psa_status_t psa_fwu_start(psa_fwu_component_t component,
+			   const void *manifest,
+			   size_t manifest_size)
+{
+	if(manifest_size > UINT32_MAX)
+		return PSA_ERROR_INVALID_ARGUMENT;
+	if (!instance.session)
+		return PSA_ERROR_BAD_STATE;
+
+	psa_status_t status = PSA_ERROR_INVALID_ARGUMENT;
+	struct rpc_caller_interface *caller = instance.session->caller;
+	struct psa_invec in_vec[] = {
+		{ .base = psa_ptr_to_u32(&component), .len = sizeof(component) },
+		{ .base = psa_ptr_const_to_u32(manifest), .len = manifest_size },
+	};
+
+	status = psa_call(caller, TFM_FIRMWARE_UPDATE_SERVICE_HANDLE,
+			  TFM_FWU_START, in_vec, IOVEC_LEN(in_vec),
+			  NULL, 0);
+	if (status != PSA_SUCCESS)
+		EMSG("failed to psa_call: %d", status);
+
+	return status;
+}
+
+psa_status_t psa_fwu_write(psa_fwu_component_t component,
+			   size_t image_offset,
+			   const void *block,
+			   size_t block_size)
+{
+	if (!instance.session)
+		return PSA_ERROR_BAD_STATE;
+	if (!block || !block_size)
+		return PSA_ERROR_INVALID_ARGUMENT;
+	if((image_offset > UINT32_MAX) || (block_size > UINT32_MAX))
+		return PSA_ERROR_INVALID_ARGUMENT;
+
+	psa_status_t status = PSA_ERROR_INVALID_ARGUMENT;
+	struct rpc_caller_interface *caller = instance.session->caller;
+	struct psa_invec in_vec[] = {
+		{ .base = psa_ptr_to_u32(&component), .len = sizeof(component) },
+		{ .base = psa_ptr_to_u32(&image_offset), .len = sizeof(uint32_t) },
+		{ .base = psa_ptr_const_to_u32(block), .len = block_size },
+	};
+
+	status = psa_call(caller, TFM_FIRMWARE_UPDATE_SERVICE_HANDLE,
+			  TFM_FWU_WRITE, in_vec, IOVEC_LEN(in_vec),
+			  NULL, 0);
+	if (status != PSA_SUCCESS)
+		EMSG("failed to psa_call: %d", status);
+
+	return status;
+}
+
+psa_status_t psa_fwu_finish(psa_fwu_component_t component)
+{
+	if (!instance.session)
+		return PSA_ERROR_BAD_STATE;
+
+	psa_status_t status = PSA_ERROR_INVALID_ARGUMENT;
+	struct rpc_caller_interface *caller = instance.session->caller;
+	struct psa_invec in_vec[] = {
+		{ .base = psa_ptr_to_u32(&component), .len = sizeof(component) },
+	};
+
+	status = psa_call(caller, TFM_FIRMWARE_UPDATE_SERVICE_HANDLE,
+			  TFM_FWU_FINISH, in_vec, IOVEC_LEN(in_vec),
+			  NULL, 0);
+	if (status != PSA_SUCCESS)
+		EMSG("failed to psa_call: %d", status);
+
+	return status;
+}
+
+psa_status_t psa_fwu_cancel(psa_fwu_component_t component)
+{
+	if (!instance.session)
+		return PSA_ERROR_BAD_STATE;
+
+	psa_status_t status = PSA_ERROR_INVALID_ARGUMENT;
+	struct rpc_caller_interface *caller = instance.session->caller;
+	struct psa_invec in_vec[] = {
+		{ .base = psa_ptr_to_u32(&component), .len = sizeof(component) },
+	};
+
+	status = psa_call(caller, TFM_FIRMWARE_UPDATE_SERVICE_HANDLE,
+			  TFM_FWU_CANCEL, in_vec, IOVEC_LEN(in_vec),
+			  NULL, 0);
+	if (status != PSA_SUCCESS)
+		EMSG("failed to psa_call: %d", status);
+
+	return status;
+}
+
+psa_status_t psa_fwu_clean(psa_fwu_component_t component)
+{
+	if (!instance.session)
+		return PSA_ERROR_BAD_STATE;
+
+	psa_status_t status = PSA_ERROR_INVALID_ARGUMENT;
+	struct rpc_caller_interface *caller = instance.session->caller;
+	struct psa_invec in_vec[] = {
+		{ .base = psa_ptr_to_u32(&component), .len = sizeof(component) },
+	};
+
+	status = psa_call(caller, TFM_FIRMWARE_UPDATE_SERVICE_HANDLE,
+			  TFM_FWU_CLEAN, in_vec, IOVEC_LEN(in_vec),
+			  NULL, 0);
+	if (status != PSA_SUCCESS)
+		EMSG("failed to psa_call: %d", status);
+
+	return status;
+}
+
+psa_status_t psa_fwu_install(void)
+{
+	if (!instance.session)
+		return PSA_ERROR_BAD_STATE;
+
+	psa_status_t status = PSA_ERROR_INVALID_ARGUMENT;
+	struct rpc_caller_interface *caller = instance.session->caller;
+	struct psa_invec in_vec[] = {};
+
+	status = psa_call(caller, TFM_FIRMWARE_UPDATE_SERVICE_HANDLE,
+			  TFM_FWU_INSTALL, in_vec, 0,
+			  NULL, 0);
+	if (status != PSA_SUCCESS)
+		EMSG("failed to psa_call: %d", status);
+
+	return status;
+}
+
+psa_status_t psa_fwu_request_reboot(void)
+{
+	if (!instance.session)
+		return PSA_ERROR_BAD_STATE;
+
+	psa_status_t status = PSA_ERROR_INVALID_ARGUMENT;
+	struct rpc_caller_interface *caller = instance.session->caller;
+	struct psa_invec in_vec[] = {};
+
+	status = psa_call(caller, TFM_FIRMWARE_UPDATE_SERVICE_HANDLE,
+			  TFM_FWU_REQUEST_REBOOT, in_vec, 0,
+			  NULL, 0);
+	if (status != PSA_SUCCESS)
+		EMSG("failed to psa_call: %d", status);
+
+	return status;
+}
+
+psa_status_t psa_fwu_reject(psa_status_t error)
+{
+	if (!instance.session)
+		return PSA_ERROR_BAD_STATE;
+
+	psa_status_t status = PSA_ERROR_INVALID_ARGUMENT;
+	struct rpc_caller_interface *caller = instance.session->caller;
+	struct psa_invec in_vec[] = {
+		{ .base = psa_ptr_to_u32(&error), .len = sizeof(error) },
+	};
+
+	status = psa_call(caller, TFM_FIRMWARE_UPDATE_SERVICE_HANDLE,
+			  TFM_FWU_REJECT, in_vec, IOVEC_LEN(in_vec),
+			  NULL, 0);
+	if (status != PSA_SUCCESS)
+		EMSG("failed to psa_call: %d", status);
+
+	return status;
+}
+
+psa_status_t psa_fwu_accept(void)
+{
+	if (!instance.session)
+		return PSA_ERROR_BAD_STATE;
+
+	psa_status_t status = PSA_ERROR_INVALID_ARGUMENT;
+	struct rpc_caller_interface *caller = instance.session->caller;
+	struct psa_invec in_vec[] = {};
+
+	status = psa_call(caller, TFM_FIRMWARE_UPDATE_SERVICE_HANDLE,
+			  TFM_FWU_ACCEPT, in_vec, 0,
+			  NULL, 0);
+	if (status != PSA_SUCCESS)
+		EMSG("failed to psa_call: %d", status);
+
+	return status;
+}
diff --git a/components/service/fwu/psa_fwu_m/interface/psa_ipc/psa_fwu_ipc.h b/components/service/fwu/psa_fwu_m/interface/psa_ipc/psa_fwu_ipc.h
new file mode 100644
index 00000000..867a1c9c
--- /dev/null
+++ b/components/service/fwu/psa_fwu_m/interface/psa_ipc/psa_fwu_ipc.h
@@ -0,0 +1,49 @@
+/*
+ * Copyright (c) 2024, Arm Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef PSA_FWU_IPC_H
+#define PSA_FWU_IPC_H
+
+#include <psa/error.h>
+#include "rpc_caller_session.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * @brief      Initialize a PSA FWU ipc client
+ *
+ * A PSA FWU ipc client makes RPC calls to a remote FWU service.
+ *
+ * @param[in]  rpc_caller RPC caller instance
+ *
+ * @return     A status indicating the success/failure of the operation
+ */
+psa_status_t psa_fwu_ipc_init(struct rpc_caller_session *session);
+
+/**
+ * @brief      Deinitialize a PSA FWU ipc client
+ *
+ */
+void psa_fwu_ipc_deinit(void);
+
+/**
+ * @brief      Return the most recent RPC status
+ *
+ * May be used to obtain information about an RPC error that resulted
+ * in an API operation failure
+ *
+ * @return     Most recent RPC operation status
+ */
+int psa_fwu_rpc_status(void);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* PSA_FWU_IPC_H */
+
diff --git a/deployments/se-proxy/infra/corstone1000/infra.cmake b/deployments/se-proxy/infra/corstone1000/infra.cmake
index 3830f9d6..2bf6b36e 100644
--- a/deployments/se-proxy/infra/corstone1000/infra.cmake
+++ b/deployments/se-proxy/infra/corstone1000/infra.cmake
@@ -26,7 +26,7 @@ add_components(TARGET "se-proxy"
 		"components/service/fwu/provider"
 		"components/service/fwu/provider/serializer"
 		"components/service/fwu/psa_fwu_m/agent"
-		"components/service/fwu/psa_fwu_m/interface/stub"
+		"components/service/fwu/psa_fwu_m/interface/psa_ipc"
 		"components/service/secure_storage/backend/secure_storage_ipc"
 )
 
diff --git a/deployments/se-proxy/infra/corstone1000/service_proxy_factory.c b/deployments/se-proxy/infra/corstone1000/service_proxy_factory.c
index 759983b4..547e84bc 100644
--- a/deployments/se-proxy/infra/corstone1000/service_proxy_factory.c
+++ b/deployments/se-proxy/infra/corstone1000/service_proxy_factory.c
@@ -14,6 +14,7 @@
 #include <service/crypto/factory/crypto_provider_factory.h>
 #include "service/fwu/psa_fwu_m/agent/psa_fwu_m_update_agent.h"
 #include "service/fwu/provider/fwu_provider.h"
+#include "service/fwu/psa_fwu_m/interface/psa_ipc/psa_fwu_ipc.h"
 #include <service/secure_storage/frontend/secure_storage_provider/secure_storage_provider.h>
 #include "service/secure_storage/frontend/secure_storage_provider/secure_storage_uuid.h"
 #include <trace.h>
@@ -134,10 +135,25 @@ struct rpc_service_interface *its_proxy_create(void)
 
 struct rpc_service_interface *fwu_proxy_create(void)
 {
+	rpc_status_t rpc_status = RPC_ERROR_INTERNAL;
 	static struct update_agent *agent;
 	static struct fwu_provider fwu_provider = { 0 };
 
+	/* Static objects for proxy instance */
+	static struct rpc_caller_interface rss_comms = { 0 };
+	static struct rpc_caller_session rpc_session = { 0 };
+
+	rpc_status = rss_comms_caller_init(&rss_comms);
+	if (rpc_status != RPC_SUCCESS)
+		return NULL;
+
+	rpc_status = rpc_caller_session_open(&rpc_session, &rss_comms, &dummy_uuid, 0, 0);
+	if (rpc_status != RPC_SUCCESS)
+		return NULL;
+
 	agent = psa_fwu_m_update_agent_init(NULL, 0, 4096);
+	if (psa_fwu_ipc_init(&rpc_session) != PSA_SUCCESS)
+		return NULL;
 
 	return fwu_provider_init(&fwu_provider, agent);
 }
-- 
2.34.1

