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.
Change-Id: I791f401d629f9cce74151410bb002b7e1b10b919
Signed-off-by: Harsimran Singh Tungal <harsimransingh.tungal@arm.com>
diff --git a/components/service/common/include/psa/sid.h b/components/service/common/include/psa/sid.h
index 5aaa659..0235764 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 @@
#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 0000000..cdc653a
--- /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 0000000..a47ae53
--- /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 0000000..867a1c9
--- /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 3830f9d..2bf6b36 100644
--- a/deployments/se-proxy/infra/corstone1000/infra.cmake
+++ b/deployments/se-proxy/infra/corstone1000/infra.cmake
@@ -26,7 +26,7 @@
"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 759983b..0e730e7 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 *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 rse_comms = { 0 };
+ static struct rpc_caller_session rpc_session = { 0 };
+
+ rpc_status = rse_comms_caller_init(&rse_comms);
+ if (rpc_status != RPC_SUCCESS)
+ return NULL;
+
+ rpc_status = rpc_caller_session_open(&rpc_session, &rse_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);
}