Core: Move IPC model SPM code to 'spm' folder

- APIs in 'tfm_svcalls.c' are actually part of SPM, so move them
  to 'secure_fw/spm/spm_ipc.c', and rename SPM APIs with 'tfm_spm'
  prefix.
- APIs in 'tfm_psa_client_call.c' are also a part of SPM, move
  the whole file and header file to SPM, and add 'tfm_spm' prefix
  to API names.
- Move API declaration into 'spm_api.h' header.
- Add static declaration to internal-used functions.
- Remove inclusion of some unused header files.

Change-Id: I90ff634987ce9e01ddb3a294b7f1f5f222792f8c
Signed-off-by: Mingyang Sun <mingyang.sun@arm.com>
diff --git a/secure_fw/spm/CMakeLists.inc b/secure_fw/spm/CMakeLists.inc
index 23d8e83..cb458d5 100644
--- a/secure_fw/spm/CMakeLists.inc
+++ b/secure_fw/spm/CMakeLists.inc
@@ -27,7 +27,8 @@
 set (SS_SPM_C_SRC "${SS_SPM_DIR}/spm_api.c")
 
 if(TFM_PSA_API)
-	list(APPEND SS_SPM_C_SRC "${SS_SPM_DIR}/spm_ipc.c")
+	list(APPEND SS_SPM_C_SRC "${SS_SPM_DIR}/spm_ipc.c"
+		"${SS_SPM_DIR}/spm_psa_client_call.c")
 else()
 	list(APPEND SS_SPM_C_SRC "${SS_SPM_DIR}/spm_func.c")
 endif()
@@ -41,7 +42,6 @@
 embedded_include_directories(PATH ${TFM_ROOT_DIR}/interface/include ABSOLUTE)
 embedded_include_directories(PATH ${TFM_ROOT_DIR}/secure_fw/spm ABSOLUTE)
 embedded_include_directories(PATH ${TFM_ROOT_DIR}/secure_fw/core/include ABSOLUTE)
-embedded_include_directories(PATH ${TFM_ROOT_DIR} ABSOLUTE)
 
 set(BUILD_CMSIS_CORE Off)
 set(BUILD_RETARGET Off)
diff --git a/secure_fw/spm/spm_api.c b/secure_fw/spm/spm_api.c
index f71db78..9dae74b 100644
--- a/secure_fw/spm/spm_api.c
+++ b/secure_fw/spm/spm_api.c
@@ -19,7 +19,6 @@
 #include "tfm_core.h"
 #include "tfm_peripherals_def.h"
 #include "spm_partition_defs.h"
-#include "psa/lifecycle.h"
 #include "region.h"
 
 #define NON_SECURE_INTERNAL_PARTITION_DB_IDX 0
@@ -108,15 +107,6 @@
         TFM_PARTITION_PRIVILEGED_MODE;
 }
 
-uint32_t tfm_spm_get_lifecycle_state(void)
-{
-    /*
-     * FixMe: return PSA_LIFECYCLE_UNKNOWN to the caller directly. It will be
-     * implemented in the future.
-     */
-    return PSA_LIFECYCLE_UNKNOWN;
-}
-
 __attribute__((section("SFN")))
 void tfm_spm_partition_change_privilege(uint32_t privileged)
 {
diff --git a/secure_fw/spm/spm_api.h b/secure_fw/spm/spm_api.h
index b28cac7..0ed8893 100644
--- a/secure_fw/spm/spm_api.h
+++ b/secure_fw/spm/spm_api.h
@@ -387,28 +387,6 @@
 /*************************** IPC definitions **************************/
 
 /**
- * \brief Get bottom of stack region for a partition
- *
- * \param[in] partition_idx     Partition index
- *
- * \return Stack region bottom value
- *
- * \note This function doesn't check if partition_idx is valid.
- */
-uint32_t tfm_spm_partition_get_stack_bottom(uint32_t partition_idx);
-
-/**
- * \brief Get top of stack region for a partition
- *
- * \param[in] partition_idx     Partition index
- *
- * \return Stack region top value
- *
- * \note This function doesn't check if partition_idx is valid.
- */
-uint32_t tfm_spm_partition_get_stack_top(uint32_t partition_idx);
-
-/**
  * \brief   Get the running partition ID.
  *
  * \return  Returns the partition ID
@@ -441,52 +419,6 @@
 int32_t tfm_spm_validate_conn_handle(psa_handle_t conn_handle,
                                      int32_t client_id);
 
-/**
- * \brief                   Free connection handle which not used anymore.
- *
- * \param[in] service       Target service context pointer
- * \param[in] conn_handle   Connection handle created by
- *                          tfm_spm_create_conn_handle(), \ref psa_handle_t
- *
- * \retval IPC_SUCCESS      Success
- * \retval IPC_ERROR_BAD_PARAMETERS  Bad parameters input
- * \retval "Does not return"  Panic for not find service by handle
- */
-int32_t tfm_spm_free_conn_handle(struct tfm_spm_service_t *service,
-                                 psa_handle_t conn_handle);
-
-/**
- * \brief                   Set reverse handle value for connection.
- *
- * \param[in] service       Target service context pointer
- * \param[in] conn_handle   Connection handle created by
- *                          tfm_spm_create_conn_handle(), \ref psa_handle_t
- * \param[in] rhandle       rhandle need to save
- *
- * \retval IPC_SUCCESS      Success
- * \retval IPC_ERROR_BAD_PARAMETERS  Bad parameters input
- * \retval "Does not return"  Panic for not find handle node
- */
-int32_t tfm_spm_set_rhandle(struct tfm_spm_service_t *service,
-                            psa_handle_t conn_handle,
-                            void *rhandle);
-
-/**
- * \brief                   Get reverse handle value from connection hanlde.
- *
- * \param[in] service       Target service context pointer
- * \param[in] conn_handle   Connection handle created by
- *                          tfm_spm_create_conn_handle(), \ref psa_handle_t
- *
- * \retval void *           Success
- * \retval "Does not return"  Panic for those:
- *                              service pointer are NULL
- *                              hanlde is \ref PSA_NULL_HANDLE
- *                              handle node does not be found
- */
-void *tfm_spm_get_rhandle(struct tfm_spm_service_t *service,
-                          psa_handle_t conn_handle);
-
 /******************** Partition management functions *************************/
 
 /**
@@ -499,22 +431,6 @@
 struct spm_partition_desc_t *tfm_spm_get_running_partition(void);
 
 /**
- * \brief                   Get the service context by signal.
- *
- * \param[in] partition     Partition context pointer
- *                          \ref spm_partition_desc_t structures
- * \param[in] signal        Signal associated with inputs to the Secure
- *                          Partition, \ref psa_signal_t
- *
- * \retval NULL             Failed
- * \retval "Not NULL"       Target service context pointer,
- *                          \ref tfm_spm_service_t structures
- */
-struct tfm_spm_service_t *
-    tfm_spm_get_service_by_signal(struct spm_partition_desc_t *partition,
-                                  psa_signal_t signal);
-
-/**
  * \brief                   Get the service context by service ID.
  *
  * \param[in] sid           RoT Service identity
@@ -538,32 +454,9 @@
 struct tfm_spm_service_t *
     tfm_spm_get_service_by_handle(psa_handle_t conn_handle);
 
-/**
- * \brief                   Get the partition context by partition ID.
- *
- * \param[in] partition_id  Partition identity
- *
- * \retval NULL             Failed
- * \retval "Not NULL"       Target partition context pointer,
- *                          \ref spm_partition_desc_t structures
- */
-struct spm_partition_desc_t *
-    tfm_spm_get_partition_by_id(int32_t partition_id);
-
 /************************ Message functions **********************************/
 
 /**
- * \brief                   Get message context by message handle.
- *
- * \param[in] msg_handle    Message handle which is a reference generated
- *                          by the SPM to a specific message.
- *
- * \return                  The message body context pointer
- *                          \ref tfm_msg_body_t structures
- */
-struct tfm_msg_body_t *tfm_spm_get_msg_from_handle(psa_handle_t msg_handle);
-
-/**
  * \brief                   Get message context by connect handle.
  *
  * \param[in] conn_handle   Service connect handle.
@@ -687,7 +580,6 @@
  */
 uint32_t tfm_spm_init(void);
 
-
 /*
  * \brief This function get the current PSA RoT lifecycle state.
  *
@@ -699,6 +591,293 @@
  */
 uint32_t tfm_spm_get_lifecycle_state(void);
 
-#endif /* ifdef(TFM_PSA_API) */
+/* Svcall for PSA Client APIs */
+
+/**
+ * \brief SVC handler for \ref psa_framework_version.
+ *
+ * \return version              The version of the PSA Framework implementation
+ *                              that is providing the runtime services to the
+ *                              caller.
+ */
+uint32_t tfm_spm_psa_framework_version(void);
+
+/**
+ * \brief SVC handler for \ref psa_version.
+ *
+ * \param[in] args              Include all input arguments: sid.
+ * \param[in] ns_caller         If 'true', call from non-secure client.
+ *                              Or from secure client.
+ *
+ * \retval PSA_VERSION_NONE     The RoT Service is not implemented, or the
+ *                              caller is not permitted to access the service.
+ * \retval > 0                  The version of the implemented RoT Service.
+ */
+uint32_t tfm_spm_psa_version(uint32_t *args, bool ns_caller);
+
+/**
+ * \brief SVC handler for \ref psa_connect.
+ *
+ * \param[in] args              Include all input arguments:
+ *                              sid, version.
+ * \param[in] ns_caller         If 'true', call from non-secure client.
+ *                              Or from secure client.
+ *
+ * \retval PSA_SUCCESS          Success.
+ * \retval PSA_ERROR_CONNECTION_REFUSED The SPM or RoT Service has refused the
+ *                              connection.
+ * \retval PSA_ERROR_CONNECTION_BUSY The SPM or RoT Service cannot make the
+ *                              connection at the moment.
+ * \retval "Does not return"    The RoT Service ID and version are not
+ *                              supported, or the caller is not permitted to
+ *                              access the service.
+ */
+psa_status_t tfm_spm_psa_connect(uint32_t *args, bool ns_caller);
+
+/**
+ * \brief SVC handler for \ref psa_call.
+ *
+ * \param[in] args              Include all input arguments:
+ *                              handle, in_vec, in_len, out_vec, out_len.
+ * \param[in] ns_caller         If 'true', call from non-secure client.
+ *                              Or from secure client.
+ * \param[in] lr                EXC_RETURN value of the SVC.
+ *
+ * \retval >=0                  RoT Service-specific status value.
+ * \retval <0                   RoT Service-specific error code.
+ * \retval PSA_ERROR_PROGRAMMER_ERROR The connection has been terminated by the
+ *                              RoT Service. The call is a PROGRAMMER ERROR if
+ *                              one or more of the following are true:
+ * \arg                           An invalid handle was passed.
+ * \arg                           The connection is already handling a request.
+ * \arg                           type < 0.
+ * \arg                           An invalid memory reference was provided.
+ * \arg                           in_len + out_len > PSA_MAX_IOVEC.
+ * \arg                           The message is unrecognized by the RoT
+ *                                Service or incorrectly formatted.
+ */
+psa_status_t tfm_spm_psa_call(uint32_t *args, bool ns_caller, uint32_t lr);
+
+/**
+ * \brief SVC handler for \ref psa_close.
+ *
+ * \param[in] args              Include all input arguments: handle.
+ * \param[in] ns_caller         If 'true', call from non-secure client.
+ *                              Or from secure client.
+ *
+ * \retval void                 Success.
+ * \retval "Does not return"    The call is invalid, one or more of the
+ *                              following are true:
+ * \arg                           An invalid handle was provided that is not
+ *                                the null handle.
+ * \arg                           The connection is handling a request.
+ */
+void tfm_spm_psa_close(uint32_t *args, bool ns_caller);
+
+/* Svcall for PSA Service APIs */
+
+/**
+ * \brief SVC handler for \ref psa_wait.
+ *
+ * \param[in] args              Include all input arguments:
+ *                              signal_mask, timeout.
+ *
+ * \retval >0                   At least one signal is asserted.
+ * \retval 0                    No signals are asserted. This is only seen when
+ *                              a polling timeout is used.
+ */
+psa_signal_t tfm_spm_psa_wait(uint32_t *args);
+
+/**
+ * \brief SVC handler for \ref psa_get.
+ *
+ * \param[in] args              Include all input arguments: signal, msg.
+ *
+ * \retval PSA_SUCCESS          Success, *msg will contain the delivered
+ *                              message.
+ * \retval PSA_ERROR_DOES_NOT_EXIST Message could not be delivered.
+ * \retval "Does not return"    The call is invalid because one or more of the
+ *                              following are true:
+ * \arg                           signal has more than a single bit set.
+ * \arg                           signal does not correspond to an RoT Service.
+ * \arg                           The RoT Service signal is not currently
+ *                                asserted.
+ * \arg                           The msg pointer provided is not a valid memory
+ *                                reference.
+ */
+psa_status_t tfm_spm_psa_get(uint32_t *args);
+
+/**
+ * \brief SVC handler for \ref psa_set_rhandle.
+ *
+ * \param[in] args              Include all input arguments:
+ *                              msg_handle, rhandle.
+ *
+ * \retval void                 Success, rhandle will be provided with all
+ *                              subsequent messages delivered on this
+ *                              connection.
+ * \retval "Does not return"    msg_handle is invalid.
+ */
+void tfm_spm_psa_set_rhandle(uint32_t *args);
+
+/**
+ * \brief SVC handler for \ref psa_read.
+ *
+ * \param[in] args              Include all input arguments:
+ *                              msg_handle, invec_idx, buffer, num_bytes.
+ *
+ * \retval >0                   Number of bytes copied.
+ * \retval 0                    There was no remaining data in this input
+ *                              vector.
+ * \retval "Does not return"    The call is invalid, one or more of the
+ *                              following are true:
+ * \arg                           msg_handle is invalid.
+ * \arg                           msg_handle does not refer to a request
+ *                                message.
+ * \arg                           invec_idx is equal to or greater than
+ *                                \ref PSA_MAX_IOVEC.
+ * \arg                           the memory reference for buffer is invalid or
+ *                                not writable.
+ */
+size_t tfm_spm_psa_read(uint32_t *args);
+
+/**
+ * \brief SVC handler for \ref psa_skip.
+ *
+ * \param[in] args              Include all input arguments:
+ *                              msg_handle, invec_idx, num_bytes.
+ *
+ * \retval >0                   Number of bytes skipped.
+ * \retval 0                    There was no remaining data in this input
+ *                              vector.
+ * \retval "Does not return"    The call is invalid, one or more of the
+ *                              following are true:
+ * \arg                           msg_handle is invalid.
+ * \arg                           msg_handle does not refer to a request
+ *                                message.
+ * \arg                           invec_idx is equal to or greater than
+ *                                \ref PSA_MAX_IOVEC.
+ */
+size_t tfm_spm_psa_skip(uint32_t *args);
+
+/**
+ * \brief SVC handler for \ref psa_write.
+ *
+ * \param[in] args              Include all input arguments:
+ *                              msg_handle, outvec_idx, buffer, num_bytes.
+ *
+ * \retval void                 Success
+ * \retval "Does not return"    The call is invalid, one or more of the
+ *                              following are true:
+ * \arg                           msg_handle is invalid.
+ * \arg                           msg_handle does not refer to a request
+ *                                message.
+ * \arg                           outvec_idx is equal to or greater than
+ *                                \ref PSA_MAX_IOVEC.
+ * \arg                           The memory reference for buffer is invalid.
+ * \arg                           The call attempts to write data past the end
+ *                                of the client output vector.
+ */
+void tfm_spm_psa_write(uint32_t *args);
+
+/**
+ * \brief SVC handler for \ref psa_reply.
+ *
+ * \param[in] args              Include all input arguments:
+ *                              msg_handle, status.
+ *
+ * \retval void                 Success.
+ * \retval "Does not return"    The call is invalid, one or more of the
+ *                              following are true:
+ * \arg                         msg_handle is invalid.
+ * \arg                         An invalid status code is specified for the
+ *                              type of message.
+ */
+void tfm_spm_psa_reply(uint32_t *args);
+
+/**
+ * \brief SVC handler for \ref psa_notify.
+ *
+ * \param[in] args              Include all input arguments: partition_id.
+ *
+ * \retval void                 Success.
+ * \retval "Does not return"    partition_id does not correspond to a Secure
+ *                              Partition.
+ */
+void tfm_spm_psa_notify(uint32_t *args);
+
+/**
+ * \brief SVC handler for \ref psa_clear.
+ *
+ * \retval void                 Success.
+ * \retval "Does not return"    The Secure Partition's doorbell signal is not
+ *                              currently asserted.
+ */
+void tfm_spm_psa_clear(void);
+
+/**
+ * \brief SVC handler for \ref psa_eoi.
+ *
+ * \param[in] args              Include all input arguments: irq_signal.
+ *
+ * \retval void                 Success.
+ * \retval "Does not return"    The call is invalid, one or more of the
+ *                              following are true:
+ * \arg                           irq_signal is not an interrupt signal.
+ * \arg                           irq_signal indicates more than one signal.
+ * \arg                           irq_signal is not currently asserted.
+ */
+void tfm_spm_psa_eoi(uint32_t *args);
+
+/**
+ * \brief SVC hander of enabling irq_line of the specified irq_signal.
+ *
+ * \param[in] args              Include all input arguments: irq_signal.
+ *
+ * \retval void                 Success.
+ * \retval "Does not return"    The call is invalid, one or more of the
+ *                              following are true:
+ * \arg                           irq_signal is not an interrupt signal.
+ * \arg                           irq_signal indicates more than one signal.
+ */
+void tfm_spm_enable_irq(uint32_t *args);
+
+/**
+ * \brief SVC hander of disabling irq_line of the specified irq_signal.
+ *
+ * \param[in] args              Include all input arguments: irq_signal.
+ *
+ * \retval void                 Success.
+ * \retval "Does not return"    The call is invalid, one or more of the
+ *                              following are true:
+ * \arg                           irq_signal is not an interrupt signal.
+ * \arg                           irq_signal indicates more than one signal.
+ */
+void tfm_spm_disable_irq(uint32_t *args);
+
+/**
+ * \brief Validate the whether NS caller re-enter.
+ *
+ * \param[in] p_cur_sp          Pointer to current partition.
+ * \param[in] p_ctx             Pointer to current stack context.
+ * \param[in] exc_return        EXC_RETURN value.
+ * \param[in] ns_caller         If 'true', call from non-secure client.
+ *                              Or from secure client.
+ *
+ * \retval void                 Success.
+ */
+void tfm_spm_validate_caller(struct spm_partition_desc_t *p_cur_sp,
+                             uint32_t *p_ctx, uint32_t exc_return,
+                             bool ns_caller);
+
+/**
+ * \brief Terminate execution within the calling Secure Partition and will not
+ *        return.
+ *
+ * \retval "Does not return"
+ */
+void tfm_spm_psa_panic(void);
+
+#endif /* defined(TFM_PSA_API) */
 
 #endif /*__SPM_API_H__ */
diff --git a/secure_fw/spm/spm_ipc.c b/secure_fw/spm/spm_ipc.c
index b88d4a8..90e688f 100644
--- a/secure_fw/spm/spm_ipc.c
+++ b/secure_fw/spm/spm_ipc.c
@@ -5,32 +5,33 @@
  *
  */
 
-/* All the APIs defined in this file are used for IPC model. */
-
 #include <inttypes.h>
-#include <limits.h>
 #include <stdbool.h>
-#include <stdlib.h>
 #include "psa/client.h"
 #include "psa/service.h"
-#include "tfm_utils.h"
-#include "tfm_spm_hal.h"
-#include "spm_api.h"
-#include "spm_db.h"
-#include "tfm_api.h"
-#include "tfm_core_mem_check.h"
-#include "tfm_internal_defines.h"
+#include "psa/lifecycle.h"
+#include "tfm_thread.h"
 #include "tfm_wait.h"
+#include "tfm_utils.h"
+#include "tfm_internal_defines.h"
 #include "tfm_message_queue.h"
+#include "tfm_spm_hal.h"
+#include "tfm_irq_list.h"
+#include "tfm_api.h"
+#include "tfm_secure_api.h"
+#include "tfm_memory_utils.h"
+#include "spm_api.h"
+#include "tfm_peripherals_def.h"
+#include "spm_db.h"
+#include "tfm_core_utils.h"
+#include "spm_psa_client_call.h"
+#include "tfm_rpc.h"
+#include "tfm_internal.h"
+#include "tfm_core_trustzone.h"
+#include "tfm_core_mem_check.h"
 #include "tfm_list.h"
 #include "tfm_pools.h"
-#include "tfm_thread.h"
 #include "region_defs.h"
-#include "tfm_nspm.h"
-#include "tfm_memory_utils.h"
-#include "tfm_core_utils.h"
-#include "tfm_rpc.h"
-#include "tfm_irq_list.h"
 
 #include "secure_fw/services/tfm_service_list.inc"
 
@@ -45,7 +46,10 @@
 TFM_POOL_DECLARE(conn_handle_pool, sizeof(struct tfm_conn_handle_t),
                  TFM_CONN_HANDLE_MAX_NUM);
 
-/********************** SPM functions for handler mode ***********************/
+void tfm_irq_handler(uint32_t partition_id, psa_signal_t signal,
+                     int32_t irq_line);
+
+#include "tfm_secure_irq_handlers_ipc.inc"
 
 /* Service handle management functions */
 psa_handle_t tfm_spm_create_conn_handle(struct tfm_spm_service_t *service,
@@ -97,8 +101,19 @@
     return (struct tfm_conn_handle_t *)conn_handle;
 }
 
-int32_t tfm_spm_free_conn_handle(struct tfm_spm_service_t *service,
-                                 psa_handle_t conn_handle)
+/**
+ * \brief                   Free connection handle which not used anymore.
+ *
+ * \param[in] service       Target service context pointer
+ * \param[in] conn_handle   Connection handle created by
+ *                          tfm_spm_create_conn_handle(), \ref psa_handle_t
+ *
+ * \retval IPC_SUCCESS      Success
+ * \retval IPC_ERROR_BAD_PARAMETERS  Bad parameters input
+ * \retval "Does not return"  Panic for not find service by handle
+ */
+static int32_t tfm_spm_free_conn_handle(struct tfm_spm_service_t *service,
+                                        psa_handle_t conn_handle)
 {
     struct tfm_conn_handle_t *p_handle;
 
@@ -121,9 +136,21 @@
     return IPC_SUCCESS;
 }
 
-int32_t tfm_spm_set_rhandle(struct tfm_spm_service_t *service,
-                            psa_handle_t conn_handle,
-                            void *rhandle)
+/**
+ * \brief                   Set reverse handle value for connection.
+ *
+ * \param[in] service       Target service context pointer
+ * \param[in] conn_handle   Connection handle created by
+ *                          tfm_spm_create_conn_handle(), \ref psa_handle_t
+ * \param[in] rhandle       rhandle need to save
+ *
+ * \retval IPC_SUCCESS      Success
+ * \retval IPC_ERROR_BAD_PARAMETERS  Bad parameters input
+ * \retval "Does not return"  Panic for not find handle node
+ */
+static int32_t tfm_spm_set_rhandle(struct tfm_spm_service_t *service,
+                                   psa_handle_t conn_handle,
+                                   void *rhandle)
 {
     struct tfm_conn_handle_t *p_handle;
 
@@ -141,8 +168,21 @@
     return IPC_SUCCESS;
 }
 
-void *tfm_spm_get_rhandle(struct tfm_spm_service_t *service,
-                          psa_handle_t conn_handle)
+/**
+ * \brief                   Get reverse handle value from connection hanlde.
+ *
+ * \param[in] service       Target service context pointer
+ * \param[in] conn_handle   Connection handle created by
+ *                          tfm_spm_create_conn_handle(), \ref psa_handle_t
+ *
+ * \retval void *           Success
+ * \retval "Does not return"  Panic for those:
+ *                              service pointer are NULL
+ *                              hanlde is \ref PSA_NULL_HANDLE
+ *                              handle node does not be found
+ */
+static void *tfm_spm_get_rhandle(struct tfm_spm_service_t *service,
+                                 psa_handle_t conn_handle)
 {
     struct tfm_conn_handle_t *p_handle;
 
@@ -160,7 +200,20 @@
 }
 
 /* Partition management functions */
-struct tfm_spm_service_t *
+
+/**
+ * \brief                   Get the service context by signal.
+ *
+ * \param[in] partition     Partition context pointer
+ *                          \ref spm_partition_desc_t structures
+ * \param[in] signal        Signal associated with inputs to the Secure
+ *                          Partition, \ref psa_signal_t
+ *
+ * \retval NULL             Failed
+ * \retval "Not NULL"       Target service context pointer,
+ *                          \ref tfm_spm_service_t structures
+ */
+static struct tfm_spm_service_t *
     tfm_spm_get_service_by_signal(struct spm_partition_desc_t *partition,
                                   psa_signal_t signal)
 {
@@ -219,7 +272,17 @@
     return ((struct tfm_conn_handle_t *)conn_handle)->service;
 }
 
-struct spm_partition_desc_t *tfm_spm_get_partition_by_id(int32_t partition_id)
+/**
+ * \brief                   Get the partition context by partition ID.
+ *
+ * \param[in] partition_id  Partition identity
+ *
+ * \retval NULL             Failed
+ * \retval "Not NULL"       Target partition context pointer,
+ *                          \ref spm_partition_desc_t structures
+ */
+static struct spm_partition_desc_t *
+    tfm_spm_get_partition_by_id(int32_t partition_id)
 {
     uint32_t idx = get_partition_idx(partition_id);
 
@@ -293,7 +356,18 @@
 }
 
 /* Message functions */
-struct tfm_msg_body_t *tfm_spm_get_msg_from_handle(psa_handle_t msg_handle)
+
+/**
+ * \brief                   Get message context by message handle.
+ *
+ * \param[in] msg_handle    Message handle which is a reference generated
+ *                          by the SPM to a specific message.
+ *
+ * \return                  The message body context pointer
+ *                          \ref tfm_msg_body_t structures
+ */
+static struct tfm_msg_body_t *
+    tfm_spm_get_msg_from_handle(psa_handle_t msg_handle)
 {
     /*
      * The message handler passed by the caller is considered invalid in the
@@ -438,13 +512,31 @@
     return IPC_SUCCESS;
 }
 
-uint32_t tfm_spm_partition_get_stack_bottom(uint32_t partition_idx)
+/**
+ * \brief Get bottom of stack region for a partition
+ *
+ * \param[in] partition_idx     Partition index
+ *
+ * \return Stack region bottom value
+ *
+ * \note This function doesn't check if partition_idx is valid.
+ */
+static uint32_t tfm_spm_partition_get_stack_bottom(uint32_t partition_idx)
 {
     return g_spm_partition_db.partitions[partition_idx].
             memory_data->stack_bottom;
 }
 
-uint32_t tfm_spm_partition_get_stack_top(uint32_t partition_idx)
+/**
+ * \brief Get top of stack region for a partition
+ *
+ * \param[in] partition_idx     Partition index
+ *
+ * \return Stack region top value
+ *
+ * \note This function doesn't check if partition_idx is valid.
+ */
+static uint32_t tfm_spm_partition_get_stack_top(uint32_t partition_idx)
 {
     return g_spm_partition_db.partitions[partition_idx].memory_data->stack_top;
 }
@@ -514,8 +606,6 @@
     return IPC_ERROR_MEMORY_CHECK;
 }
 
-/********************** SPM functions for thread mode ************************/
-
 uint32_t tfm_spm_init(void)
 {
     uint32_t i, j, num;
@@ -666,3 +756,837 @@
      */
     tfm_rpc_client_call_handler();
 }
+
+/*********************** SPM functions for PSA Client APIs *******************/
+
+uint32_t tfm_spm_psa_framework_version(void)
+{
+    return tfm_spm_client_psa_framework_version();
+}
+
+uint32_t tfm_spm_psa_version(uint32_t *args, bool ns_caller)
+{
+    uint32_t sid;
+
+    TFM_CORE_ASSERT(args != NULL);
+    sid = (uint32_t)args[0];
+
+    return tfm_spm_client_psa_version(sid, ns_caller);
+}
+
+psa_status_t tfm_spm_psa_connect(uint32_t *args, bool ns_caller)
+{
+    uint32_t sid;
+    uint32_t version;
+
+    TFM_CORE_ASSERT(args != NULL);
+    sid = (uint32_t)args[0];
+    version = (uint32_t)args[1];
+
+    return tfm_spm_client_psa_connect(sid, version, ns_caller);
+}
+
+psa_status_t tfm_spm_psa_call(uint32_t *args, bool ns_caller, uint32_t lr)
+{
+    psa_handle_t handle;
+    psa_invec *inptr;
+    psa_outvec *outptr;
+    size_t in_num, out_num;
+    struct spm_partition_desc_t *partition = NULL;
+    uint32_t privileged;
+    int32_t type;
+    struct tfm_control_parameter_t ctrl_param;
+
+    TFM_CORE_ASSERT(args != NULL);
+    handle = (psa_handle_t)args[0];
+
+    partition = tfm_spm_get_running_partition();
+    if (!partition) {
+        tfm_core_panic();
+    }
+    privileged = tfm_spm_partition_get_privileged_mode(
+        partition->static_data->partition_flags);
+
+    /*
+     * Read parameters from the arguments. It is a fatal error if the
+     * memory reference for buffer is invalid or not readable.
+     */
+    if (tfm_memory_check((const void *)args[1],
+        sizeof(struct tfm_control_parameter_t), ns_caller,
+        TFM_MEMORY_ACCESS_RW, privileged) != IPC_SUCCESS) {
+        tfm_core_panic();
+    }
+
+    tfm_core_util_memcpy(&ctrl_param,
+                         (const void *)args[1],
+                         sizeof(ctrl_param));
+
+    type = ctrl_param.type;
+    in_num = ctrl_param.in_len;
+    out_num = ctrl_param.out_len;
+    inptr = (psa_invec *)args[2];
+    outptr = (psa_outvec *)args[3];
+
+    /* The request type must be zero or positive. */
+    if (type < 0) {
+        tfm_core_panic();
+    }
+
+    return tfm_spm_client_psa_call(handle, type, inptr, in_num, outptr, out_num,
+                                   ns_caller, privileged);
+}
+
+void tfm_spm_psa_close(uint32_t *args, bool ns_caller)
+{
+    psa_handle_t handle;
+
+    TFM_CORE_ASSERT(args != NULL);
+    handle = args[0];
+
+    tfm_spm_client_psa_close(handle, ns_caller);
+}
+
+uint32_t tfm_spm_get_lifecycle_state(void)
+{
+    /*
+     * FixMe: return PSA_LIFECYCLE_UNKNOWN to the caller directly. It will be
+     * implemented in the future.
+     */
+    return PSA_LIFECYCLE_UNKNOWN;
+}
+
+/********************* SPM functions for PSA Service APIs ********************/
+
+psa_signal_t tfm_spm_psa_wait(uint32_t *args)
+{
+    psa_signal_t signal_mask;
+    uint32_t timeout;
+    struct spm_partition_desc_t *partition = NULL;
+
+    TFM_CORE_ASSERT(args != NULL);
+    signal_mask = (psa_signal_t)args[0];
+    timeout = args[1];
+
+    /*
+     * Timeout[30:0] are reserved for future use.
+     * SPM must ignore the value of RES.
+     */
+    timeout &= PSA_TIMEOUT_MASK;
+
+    partition = tfm_spm_get_running_partition();
+    if (!partition) {
+        tfm_core_panic();
+    }
+
+    /*
+     * It is a PROGRAMMER ERROR if the signal_mask does not include any assigned
+     * signals.
+     */
+    if ((partition->runtime_data.assigned_signals & signal_mask) == 0) {
+        tfm_core_panic();
+    }
+
+    /*
+     * Expected signals are included in signal wait mask, ignored signals
+     * should not be set and affect caller thread state. Save this mask for
+     * further checking while signals are ready to be set.
+     */
+    partition->runtime_data.signal_mask = signal_mask;
+
+    /*
+     * tfm_event_wait() blocks the caller thread if no signals are available.
+     * In this case, the return value of this function is temporary set into
+     * runtime context. After new signal(s) are available, the return value
+     * is updated with the available signal(s) and blocked thread gets to run.
+     */
+    if (timeout == PSA_BLOCK &&
+        (partition->runtime_data.signals & signal_mask) == 0) {
+        tfm_event_wait(&partition->runtime_data.signal_evnt);
+    }
+
+    return partition->runtime_data.signals & signal_mask;
+}
+
+psa_status_t tfm_spm_psa_get(uint32_t *args)
+{
+    psa_signal_t signal;
+    psa_msg_t *msg = NULL;
+    struct tfm_spm_service_t *service = NULL;
+    struct tfm_msg_body_t *tmp_msg = NULL;
+    struct spm_partition_desc_t *partition = NULL;
+    uint32_t privileged;
+
+    TFM_CORE_ASSERT(args != NULL);
+    signal = (psa_signal_t)args[0];
+    msg = (psa_msg_t *)args[1];
+
+    /*
+     * Only one message could be retrieved every time for psa_get(). It is a
+     * fatal error if the input signal has more than a signal bit set.
+     */
+    if (tfm_bitcount(signal) != 1) {
+        tfm_core_panic();
+    }
+
+    partition = tfm_spm_get_running_partition();
+    if (!partition) {
+        tfm_core_panic();
+    }
+    privileged = tfm_spm_partition_get_privileged_mode(
+        partition->static_data->partition_flags);
+
+    /*
+     * Write the message to the service buffer. It is a fatal error if the
+     * input msg pointer is not a valid memory reference or not read-write.
+     */
+    if (tfm_memory_check(msg, sizeof(psa_msg_t), false, TFM_MEMORY_ACCESS_RW,
+        privileged) != IPC_SUCCESS) {
+        tfm_core_panic();
+    }
+
+    /*
+     * It is a fatal error if the caller call psa_get() when no message has
+     * been set. The caller must call this function after an RoT Service signal
+     * is returned by psa_wait().
+     */
+    if (partition->runtime_data.signals == 0) {
+        tfm_core_panic();
+    }
+
+    /*
+     * It is a fatal error if the RoT Service signal is not currently asserted.
+     */
+    if ((partition->runtime_data.signals & signal) == 0) {
+        tfm_core_panic();
+    }
+
+    /*
+     * Get RoT service by signal from partition. It is a fatal error if getting
+     * failed, which means the input signal is not correspond to an RoT service.
+     */
+    service = tfm_spm_get_service_by_signal(partition, signal);
+    if (!service) {
+        tfm_core_panic();
+    }
+
+    tmp_msg = tfm_msg_dequeue(&service->msg_queue);
+    if (!tmp_msg) {
+        return PSA_ERROR_DOES_NOT_EXIST;
+    }
+
+    ((struct tfm_conn_handle_t *)(tmp_msg->handle))->status =
+                                                       TFM_HANDLE_STATUS_ACTIVE;
+
+    tfm_core_util_memcpy(msg, &tmp_msg->msg, sizeof(psa_msg_t));
+
+    /*
+     * There may be multiple messages for this RoT Service signal, do not clear
+     * its mask until no remaining message.
+     */
+    if (tfm_msg_queue_is_empty(&service->msg_queue)) {
+        partition->runtime_data.signals &= ~signal;
+    }
+
+    return PSA_SUCCESS;
+}
+
+void tfm_spm_psa_set_rhandle(uint32_t *args)
+{
+    psa_handle_t msg_handle;
+    void *rhandle = NULL;
+    struct tfm_msg_body_t *msg = NULL;
+
+    TFM_CORE_ASSERT(args != NULL);
+    msg_handle = (psa_handle_t)args[0];
+    rhandle = (void *)args[1];
+
+    /* It is a fatal error if message handle is invalid */
+    msg = tfm_spm_get_msg_from_handle(msg_handle);
+    if (!msg) {
+        tfm_core_panic();
+    }
+
+    msg->msg.rhandle = rhandle;
+
+    /* Store reverse handle for following client calls. */
+    tfm_spm_set_rhandle(msg->service, msg->handle, rhandle);
+}
+
+size_t tfm_spm_psa_read(uint32_t *args)
+{
+    psa_handle_t msg_handle;
+    uint32_t invec_idx;
+    void *buffer = NULL;
+    size_t num_bytes;
+    size_t bytes;
+    struct tfm_msg_body_t *msg = NULL;
+    uint32_t privileged;
+    struct spm_partition_desc_t *partition = NULL;
+
+    TFM_CORE_ASSERT(args != NULL);
+    msg_handle = (psa_handle_t)args[0];
+    invec_idx = args[1];
+    buffer = (void *)args[2];
+    num_bytes = (size_t)args[3];
+
+    /* It is a fatal error if message handle is invalid */
+    msg = tfm_spm_get_msg_from_handle(msg_handle);
+    if (!msg) {
+        tfm_core_panic();
+    }
+
+    partition = msg->service->partition;
+    privileged = tfm_spm_partition_get_privileged_mode(
+        partition->static_data->partition_flags);
+
+    /*
+     * It is a fatal error if message handle does not refer to a request
+     * message
+     */
+    if (msg->msg.type < PSA_IPC_CALL) {
+        tfm_core_panic();
+    }
+
+    /*
+     * It is a fatal error if invec_idx is equal to or greater than
+     * PSA_MAX_IOVEC
+     */
+    if (invec_idx >= PSA_MAX_IOVEC) {
+        tfm_core_panic();
+    }
+
+    /* There was no remaining data in this input vector */
+    if (msg->msg.in_size[invec_idx] == 0) {
+        return 0;
+    }
+
+    /*
+     * Copy the client data to the service buffer. It is a fatal error
+     * if the memory reference for buffer is invalid or not read-write.
+     */
+    if (tfm_memory_check(buffer, num_bytes, false,
+        TFM_MEMORY_ACCESS_RW, privileged) != IPC_SUCCESS) {
+        tfm_core_panic();
+    }
+
+    bytes = num_bytes > msg->msg.in_size[invec_idx] ?
+                        msg->msg.in_size[invec_idx] : num_bytes;
+
+    tfm_core_util_memcpy(buffer, msg->invec[invec_idx].base, bytes);
+
+    /* There maybe some remaining data */
+    msg->invec[invec_idx].base = (char *)msg->invec[invec_idx].base + bytes;
+    msg->msg.in_size[invec_idx] -= bytes;
+
+    return bytes;
+}
+
+size_t tfm_spm_psa_skip(uint32_t *args)
+{
+    psa_handle_t msg_handle;
+    uint32_t invec_idx;
+    size_t num_bytes;
+    struct tfm_msg_body_t *msg = NULL;
+
+    TFM_CORE_ASSERT(args != NULL);
+    msg_handle = (psa_handle_t)args[0];
+    invec_idx = args[1];
+    num_bytes = (size_t)args[2];
+
+    /* It is a fatal error if message handle is invalid */
+    msg = tfm_spm_get_msg_from_handle(msg_handle);
+    if (!msg) {
+        tfm_core_panic();
+    }
+
+    /*
+     * It is a fatal error if message handle does not refer to a request
+     * message
+     */
+    if (msg->msg.type < PSA_IPC_CALL) {
+        tfm_core_panic();
+    }
+
+    /*
+     * It is a fatal error if invec_idx is equal to or greater than
+     * PSA_MAX_IOVEC
+     */
+    if (invec_idx >= PSA_MAX_IOVEC) {
+        tfm_core_panic();
+    }
+
+    /* There was no remaining data in this input vector */
+    if (msg->msg.in_size[invec_idx] == 0) {
+        return 0;
+    }
+
+    /*
+     * If num_bytes is greater than the remaining size of the input vector then
+     * the remaining size of the input vector is used.
+     */
+    if (num_bytes > msg->msg.in_size[invec_idx]) {
+        num_bytes = msg->msg.in_size[invec_idx];
+    }
+
+    /* There maybe some remaining data */
+    msg->invec[invec_idx].base = (char *)msg->invec[invec_idx].base +
+                                 num_bytes;
+    msg->msg.in_size[invec_idx] -= num_bytes;
+
+    return num_bytes;
+}
+
+void tfm_spm_psa_write(uint32_t *args)
+{
+    psa_handle_t msg_handle;
+    uint32_t outvec_idx;
+    void *buffer = NULL;
+    size_t num_bytes;
+    struct tfm_msg_body_t *msg = NULL;
+    uint32_t privileged;
+    struct spm_partition_desc_t *partition = NULL;
+
+    TFM_CORE_ASSERT(args != NULL);
+    msg_handle = (psa_handle_t)args[0];
+    outvec_idx = args[1];
+    buffer = (void *)args[2];
+    num_bytes = (size_t)args[3];
+
+    /* It is a fatal error if message handle is invalid */
+    msg = tfm_spm_get_msg_from_handle(msg_handle);
+    if (!msg) {
+        tfm_core_panic();
+    }
+
+    partition = msg->service->partition;
+    privileged = tfm_spm_partition_get_privileged_mode(
+        partition->static_data->partition_flags);
+
+    /*
+     * It is a fatal error if message handle does not refer to a request
+     * message
+     */
+    if (msg->msg.type < PSA_IPC_CALL) {
+        tfm_core_panic();
+    }
+
+    /*
+     * It is a fatal error if outvec_idx is equal to or greater than
+     * PSA_MAX_IOVEC
+     */
+    if (outvec_idx >= PSA_MAX_IOVEC) {
+        tfm_core_panic();
+    }
+
+    /*
+     * It is a fatal error if the call attempts to write data past the end of
+     * the client output vector
+     */
+    if (num_bytes > msg->msg.out_size[outvec_idx] -
+        msg->outvec[outvec_idx].len) {
+        tfm_core_panic();
+    }
+
+    /*
+     * Copy the service buffer to client outvecs. It is a fatal error
+     * if the memory reference for buffer is invalid or not readable.
+     */
+    if (tfm_memory_check(buffer, num_bytes, false,
+        TFM_MEMORY_ACCESS_RO, privileged) != IPC_SUCCESS) {
+        tfm_core_panic();
+    }
+
+    tfm_core_util_memcpy((char *)msg->outvec[outvec_idx].base +
+                         msg->outvec[outvec_idx].len, buffer, num_bytes);
+
+    /* Update the write number */
+    msg->outvec[outvec_idx].len += num_bytes;
+}
+
+static void update_caller_outvec_len(struct tfm_msg_body_t *msg)
+{
+    uint32_t i;
+
+    /*
+     * FixeMe: abstract these part into dedicated functions to avoid
+     * accessing thread context in psa layer
+     */
+    /* If it is a NS request via RPC, the owner of this message is not set */
+    if (!is_tfm_rpc_msg(msg)) {
+        TFM_CORE_ASSERT(msg->ack_evnt.owner->state == THRD_STATE_BLOCK);
+    }
+
+    for (i = 0; i < PSA_MAX_IOVEC; i++) {
+        if (msg->msg.out_size[i] == 0) {
+            continue;
+        }
+
+        TFM_CORE_ASSERT(msg->caller_outvec[i].base == msg->outvec[i].base);
+
+        msg->caller_outvec[i].len = msg->outvec[i].len;
+    }
+}
+
+void tfm_spm_psa_reply(uint32_t *args)
+{
+    psa_handle_t msg_handle;
+    psa_status_t status;
+    struct tfm_spm_service_t *service = NULL;
+    struct tfm_msg_body_t *msg = NULL;
+    int32_t ret = PSA_SUCCESS;
+
+    TFM_CORE_ASSERT(args != NULL);
+    msg_handle = (psa_handle_t)args[0];
+    status = (psa_status_t)args[1];
+
+    /* It is a fatal error if message handle is invalid */
+    msg = tfm_spm_get_msg_from_handle(msg_handle);
+    if (!msg) {
+        tfm_core_panic();
+    }
+
+    /*
+     * RoT Service information is needed in this function, stored it in message
+     * body structure. Only two parameters are passed in this function: handle
+     * and status, so it is useful and simply to do like this.
+     */
+    service = msg->service;
+    if (!service) {
+        tfm_core_panic();
+    }
+
+    /*
+     * Three type of message are passed in this function: CONNECTION, REQUEST,
+     * DISCONNECTION. It needs to process differently for each type.
+     */
+    switch (msg->msg.type) {
+    case PSA_IPC_CONNECT:
+        /*
+         * Reply to PSA_IPC_CONNECT message. Connect handle is returned if the
+         * input status is PSA_SUCCESS. Others return values are based on the
+         * input status.
+         */
+        if (status == PSA_SUCCESS) {
+            ret = msg->handle;
+        } else if (status == PSA_ERROR_CONNECTION_REFUSED) {
+            /* Refuse the client connection, indicating a permanent error. */
+            tfm_spm_free_conn_handle(service, msg->handle);
+            ret = PSA_ERROR_CONNECTION_REFUSED;
+        } else if (status == PSA_ERROR_CONNECTION_BUSY) {
+            /* Fail the client connection, indicating a transient error. */
+            ret = PSA_ERROR_CONNECTION_BUSY;
+        } else {
+            tfm_core_panic();
+        }
+        break;
+    case PSA_IPC_DISCONNECT:
+        /* Service handle is not used anymore */
+        tfm_spm_free_conn_handle(service, msg->handle);
+
+        /*
+         * If the message type is PSA_IPC_DISCONNECT, then the status code is
+         * ignored
+         */
+        break;
+    default:
+        if (msg->msg.type >= PSA_IPC_CALL) {
+            /* Reply to a request message. Return values are based on status */
+            ret = status;
+            /*
+             * The total number of bytes written to a single parameter must be
+             * reported to the client by updating the len member of the
+             * psa_outvec structure for the parameter before returning from
+             * psa_call().
+             */
+            update_caller_outvec_len(msg);
+        } else {
+            tfm_core_panic();
+        }
+    }
+
+    if (ret == PSA_ERROR_PROGRAMMER_ERROR) {
+        /*
+         * If the source of the programmer error is a Secure Partition, the SPM
+         * must panic the Secure Partition in response to a PROGRAMMER ERROR.
+         */
+        if (TFM_CLIENT_ID_IS_NS(msg->msg.client_id)) {
+            ((struct tfm_conn_handle_t *)(msg->handle))->status =
+                                                TFM_HANDLE_STATUS_CONNECT_ERROR;
+        } else {
+            tfm_core_panic();
+        }
+    } else {
+        ((struct tfm_conn_handle_t *)(msg->handle))->status =
+                                                         TFM_HANDLE_STATUS_IDLE;
+    }
+
+    if (is_tfm_rpc_msg(msg)) {
+        tfm_rpc_client_call_reply(msg, ret);
+    } else {
+        tfm_event_wake(&msg->ack_evnt, ret);
+    }
+}
+
+/**
+ * \brief   notify the partition with the signal.
+ *
+ * \param[in] partition_id      The ID of the partition to be notified.
+ * \param[in] signal            The signal that the partition is to be notified
+ *                              with.
+ *
+ * \retval void                 Success.
+ * \retval "Does not return"    If partition_id is invalid.
+ */
+static void notify_with_signal(int32_t partition_id, psa_signal_t signal)
+{
+    struct spm_partition_desc_t *partition = NULL;
+
+    /*
+     * The value of partition_id must be greater than zero as the target of
+     * notification must be a Secure Partition, providing a Non-secure
+     * Partition ID is a fatal error.
+     */
+    if (!TFM_CLIENT_ID_IS_S(partition_id)) {
+        tfm_core_panic();
+    }
+
+    /*
+     * It is a fatal error if partition_id does not correspond to a Secure
+     * Partition.
+     */
+    partition = tfm_spm_get_partition_by_id(partition_id);
+    if (!partition) {
+        tfm_core_panic();
+    }
+
+    partition->runtime_data.signals |= signal;
+
+    /*
+     * The target partition may be blocked with waiting for signals after
+     * called psa_wait(). Set the return value with the available signals
+     * before wake it up with tfm_event_signal().
+     */
+    tfm_event_wake(&partition->runtime_data.signal_evnt,
+                   partition->runtime_data.signals &
+                   partition->runtime_data.signal_mask);
+}
+
+void tfm_spm_psa_notify(uint32_t *args)
+{
+    int32_t partition_id;
+
+    TFM_CORE_ASSERT(args != NULL);
+    partition_id = (int32_t)args[0];
+
+    notify_with_signal(partition_id, PSA_DOORBELL);
+}
+
+/**
+ * \brief assert signal for a given IRQ line.
+ *
+ * \param[in] partition_id      The ID of the partition which handles this IRQ
+ * \param[in] signal            The signal associated with this IRQ
+ * \param[in] irq_line          The number of the IRQ line
+ *
+ * \retval void                 Success.
+ * \retval "Does not return"    Partition ID is invalid
+ */
+void tfm_irq_handler(uint32_t partition_id, psa_signal_t signal,
+                     int32_t irq_line)
+{
+    tfm_spm_hal_disable_irq(irq_line);
+    notify_with_signal(partition_id, signal);
+}
+
+void tfm_spm_psa_clear(void)
+{
+    struct spm_partition_desc_t *partition = NULL;
+
+    partition = tfm_spm_get_running_partition();
+    if (!partition) {
+        tfm_core_panic();
+    }
+
+    /*
+     * It is a fatal error if the Secure Partition's doorbell signal is not
+     * currently asserted.
+     */
+    if ((partition->runtime_data.signals & PSA_DOORBELL) == 0) {
+        tfm_core_panic();
+    }
+    partition->runtime_data.signals &= ~PSA_DOORBELL;
+}
+
+void tfm_spm_psa_panic(void)
+{
+    /*
+     * PSA FF recommends that the SPM causes the system to restart when a secure
+     * partition panics.
+     */
+    tfm_spm_hal_system_reset();
+}
+
+/**
+ * \brief Return the IRQ line number associated with a signal
+ *
+ * \param[in]      partition_id    The ID of the partition in which we look for
+ *                                 the signal.
+ * \param[in]      signal          The signal we do the query for.
+ * \param[out]     irq_line        The irq line associated with signal
+ *
+ * \retval IPC_SUCCESS          Execution successful, irq_line contains a valid
+ *                              value.
+ * \retval IPC_ERROR_GENERIC    There was an error finding the IRQ line for the
+ *                              signal. irq_line is unchanged.
+ */
+static int32_t get_irq_line_for_signal(int32_t partition_id,
+                                       psa_signal_t signal,
+                                       int32_t *irq_line)
+{
+    size_t i;
+
+    for (i = 0; i < tfm_core_irq_signals_count; ++i) {
+        if (tfm_core_irq_signals[i].partition_id == partition_id &&
+            tfm_core_irq_signals[i].signal_value == signal) {
+            *irq_line = tfm_core_irq_signals[i].irq_line;
+            return IPC_SUCCESS;
+        }
+    }
+    return IPC_ERROR_GENERIC;
+}
+
+void tfm_spm_psa_eoi(uint32_t *args)
+{
+    psa_signal_t irq_signal;
+    int32_t irq_line = 0;
+    int32_t ret;
+    struct spm_partition_desc_t *partition = NULL;
+
+    TFM_CORE_ASSERT(args != NULL);
+    irq_signal = (psa_signal_t)args[0];
+
+    /* It is a fatal error if passed signal indicates more than one signals. */
+    if (!tfm_is_one_bit_set(irq_signal)) {
+        tfm_core_panic();
+    }
+
+    partition = tfm_spm_get_running_partition();
+    if (!partition) {
+        tfm_core_panic();
+    }
+
+    ret = get_irq_line_for_signal(partition->static_data->partition_id,
+                                  irq_signal, &irq_line);
+    /* It is a fatal error if passed signal is not an interrupt signal. */
+    if (ret != IPC_SUCCESS) {
+        tfm_core_panic();
+    }
+
+    /* It is a fatal error if passed signal is not currently asserted */
+    if ((partition->runtime_data.signals & irq_signal) == 0) {
+        tfm_core_panic();
+    }
+
+    partition->runtime_data.signals &= ~irq_signal;
+
+    tfm_spm_hal_clear_pending_irq(irq_line);
+    tfm_spm_hal_enable_irq(irq_line);
+}
+
+void tfm_spm_enable_irq(uint32_t *args)
+{
+    struct tfm_state_context_t *svc_ctx = (struct tfm_state_context_t *)args;
+    psa_signal_t irq_signal = svc_ctx->r0;
+    int32_t irq_line = 0;
+    int32_t ret;
+    struct spm_partition_desc_t *partition = NULL;
+
+    /* It is a fatal error if passed signal indicates more than one signals. */
+    if (!tfm_is_one_bit_set(irq_signal)) {
+        tfm_core_panic();
+    }
+
+    partition = tfm_spm_get_running_partition();
+    if (!partition) {
+        tfm_core_panic();
+    }
+
+    ret = get_irq_line_for_signal(partition->static_data->partition_id,
+                                  irq_signal, &irq_line);
+    /* It is a fatal error if passed signal is not an interrupt signal. */
+    if (ret != IPC_SUCCESS) {
+        tfm_core_panic();
+    }
+
+    tfm_spm_hal_enable_irq(irq_line);
+}
+
+void tfm_spm_disable_irq(uint32_t *args)
+{
+    struct tfm_state_context_t *svc_ctx = (struct tfm_state_context_t *)args;
+    psa_signal_t irq_signal = svc_ctx->r0;
+    int32_t irq_line = 0;
+    int32_t ret;
+    struct spm_partition_desc_t *partition = NULL;
+
+    /* It is a fatal error if passed signal indicates more than one signals. */
+    if (!tfm_is_one_bit_set(irq_signal)) {
+        tfm_core_panic();
+    }
+
+    partition = tfm_spm_get_running_partition();
+    if (!partition) {
+        tfm_core_panic();
+    }
+
+    ret = get_irq_line_for_signal(partition->static_data->partition_id,
+                                  irq_signal, &irq_line);
+    /* It is a fatal error if passed signal is not an interrupt signal. */
+    if (ret != IPC_SUCCESS) {
+        tfm_core_panic();
+    }
+
+    tfm_spm_hal_disable_irq(irq_line);
+}
+
+void tfm_spm_validate_caller(struct spm_partition_desc_t *p_cur_sp,
+                             uint32_t *p_ctx, uint32_t exc_return,
+                             bool ns_caller)
+{
+    uintptr_t stacked_ctx_pos;
+
+    if (ns_caller) {
+        /*
+         * The background IRQ can't be supported, since if SP is executing,
+         * the preempted context of SP can be different with the one who
+         * preempts veneer.
+         */
+        if (p_cur_sp->static_data->partition_id != TFM_SP_NON_SECURE_ID) {
+            tfm_core_panic();
+        }
+
+        /*
+         * It is non-secure caller, check if veneer stack contains
+         * multiple contexts.
+         */
+        stacked_ctx_pos = (uintptr_t)p_ctx +
+                          sizeof(struct tfm_state_context_t) +
+                          TFM_VENEER_STACK_GUARD_SIZE;
+
+        if (is_stack_alloc_fp_space(exc_return)) {
+#if defined (__FPU_USED) && (__FPU_USED == 1U)
+            if (FPU->FPCCR & FPU_FPCCR_TS_Msk) {
+                stacked_ctx_pos += TFM_ADDTIONAL_FP_CONTEXT_WORDS *
+                                   sizeof(uint32_t);
+            }
+#endif
+            stacked_ctx_pos += TFM_BASIC_FP_CONTEXT_WORDS * sizeof(uint32_t);
+        }
+
+        if (stacked_ctx_pos != p_cur_sp->runtime_data.sp_thrd.stk_top) {
+            tfm_core_panic();
+        }
+    } else if (p_cur_sp->static_data->partition_id <= 0) {
+        tfm_core_panic();
+    }
+}
diff --git a/secure_fw/spm/spm_psa_client_call.c b/secure_fw/spm/spm_psa_client_call.c
new file mode 100644
index 0000000..ab29cb7
--- /dev/null
+++ b/secure_fw/spm/spm_psa_client_call.c
@@ -0,0 +1,302 @@
+/*
+ * Copyright (c) 2019-2020, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
+ */
+
+#include "psa/service.h"
+#include "spm_api.h"
+#include "tfm_core_utils.h"
+#include "tfm_internal_defines.h"
+#include "tfm_memory_utils.h"
+#include "tfm_message_queue.h"
+#include "spm_psa_client_call.h"
+#include "tfm_utils.h"
+#include "tfm_wait.h"
+#include "tfm_nspm.h"
+
+uint32_t tfm_spm_client_psa_framework_version(void)
+{
+    return PSA_FRAMEWORK_VERSION;
+}
+
+uint32_t tfm_spm_client_psa_version(uint32_t sid, bool ns_caller)
+{
+    struct tfm_spm_service_t *service;
+
+    /*
+     * It should return PSA_VERSION_NONE if the RoT Service is not
+     * implemented.
+     */
+    service = tfm_spm_get_service_by_sid(sid);
+    if (!service) {
+        return PSA_VERSION_NONE;
+    }
+
+    /*
+     * It should return PSA_VERSION_NONE if the caller is not authorized
+     * to access the RoT Service.
+     */
+    if (tfm_spm_check_authorization(sid, service, ns_caller) != IPC_SUCCESS) {
+        return PSA_VERSION_NONE;
+    }
+
+    return service->service_db->version;
+}
+
+psa_status_t tfm_spm_client_psa_connect(uint32_t sid, uint32_t version,
+                                        bool ns_caller)
+{
+    struct tfm_spm_service_t *service;
+    struct tfm_msg_body_t *msg;
+    psa_handle_t connect_handle;
+    int32_t client_id;
+
+    /* It is a fatal error if the RoT Service does not exist on the platform */
+    service = tfm_spm_get_service_by_sid(sid);
+    if (!service) {
+        tfm_core_panic();
+    }
+
+    if (ns_caller) {
+        client_id = tfm_nspm_get_current_client_id();
+    } else {
+        client_id = tfm_spm_partition_get_running_partition_id();
+    }
+
+    /*
+     * It is a fatal error if the caller is not authorized to access the RoT
+     * Service.
+     */
+    if (tfm_spm_check_authorization(sid, service, ns_caller) != IPC_SUCCESS) {
+        tfm_core_panic();
+    }
+
+    /*
+     * Create connection handle here since it is possible to return the error
+     * code to client when creation fails.
+     */
+    connect_handle = tfm_spm_create_conn_handle(service, client_id);
+    if (connect_handle == PSA_NULL_HANDLE) {
+        return PSA_ERROR_CONNECTION_BUSY;
+    }
+
+    /*
+     * It is a fatal error if the version of the RoT Service requested is not
+     * supported on the platform.
+     */
+    if (tfm_spm_check_client_version(service, version) != IPC_SUCCESS) {
+        tfm_core_panic();
+    }
+
+    msg = tfm_spm_get_msg_buffer_from_conn_handle(connect_handle);
+    if (!msg) {
+        /* Have no enough resource to create message */
+        return PSA_ERROR_CONNECTION_BUSY;
+    }
+
+    /* No input or output needed for connect message */
+    tfm_spm_fill_msg(msg, service, connect_handle, PSA_IPC_CONNECT,
+                     client_id, NULL, 0, NULL, 0, NULL);
+
+    /*
+     * Send message and wake up the SP who is waiting on message queue,
+     * and scheduler triggered
+     */
+    tfm_spm_send_event(service, msg);
+
+    return PSA_SUCCESS;
+}
+
+psa_status_t tfm_spm_client_psa_call(psa_handle_t handle, int32_t type,
+                                     const psa_invec *inptr, size_t in_num,
+                                     psa_outvec *outptr, size_t out_num,
+                                     bool ns_caller, uint32_t privileged)
+{
+    psa_invec invecs[PSA_MAX_IOVEC];
+    psa_outvec outvecs[PSA_MAX_IOVEC];
+    struct tfm_spm_service_t *service;
+    struct tfm_msg_body_t *msg;
+    int i, j;
+    int32_t client_id;
+
+    /* It is a fatal error if in_len + out_len > PSA_MAX_IOVEC. */
+    if ((in_num > PSA_MAX_IOVEC) ||
+        (out_num > PSA_MAX_IOVEC) ||
+        (in_num + out_num > PSA_MAX_IOVEC)) {
+        tfm_core_panic();
+    }
+
+    if (ns_caller) {
+        client_id = tfm_nspm_get_current_client_id();
+    } else {
+        client_id = tfm_spm_partition_get_running_partition_id();
+    }
+
+    /* It is a fatal error if an invalid handle was passed. */
+    if (tfm_spm_validate_conn_handle(handle, client_id) != IPC_SUCCESS) {
+        tfm_core_panic();
+    }
+    service = tfm_spm_get_service_by_handle(handle);
+    if (!service) {
+        /* FixMe: Need to implement one mechanism to resolve this failure. */
+        tfm_core_panic();
+    }
+
+    /* It is a fatal error if the connection is currently handling a request. */
+    if (((struct tfm_conn_handle_t *)handle)->status ==
+                                                     TFM_HANDLE_STATUS_ACTIVE) {
+        tfm_core_panic();
+    }
+
+    /*
+     * Return PSA_ERROR_PROGRAMMER_ERROR immediately for the connection
+     * has been terminated by the RoT Service.
+     */
+    if (((struct tfm_conn_handle_t *)handle)->status ==
+                                              TFM_HANDLE_STATUS_CONNECT_ERROR) {
+        return PSA_ERROR_PROGRAMMER_ERROR;
+    }
+
+    /*
+     * Read client invecs from the wrap input vector. It is a fatal error
+     * if the memory reference for the wrap input vector is invalid or not
+     * readable.
+     */
+    if (tfm_memory_check(inptr, in_num * sizeof(psa_invec), ns_caller,
+        TFM_MEMORY_ACCESS_RO, privileged) != IPC_SUCCESS) {
+        tfm_core_panic();
+    }
+
+    /*
+     * Read client outvecs from the wrap output vector and will update the
+     * actual length later. It is a fatal error if the memory reference for
+     * the wrap output vector is invalid or not read-write.
+     */
+    if (tfm_memory_check(outptr, out_num * sizeof(psa_outvec), ns_caller,
+        TFM_MEMORY_ACCESS_RW, privileged) != IPC_SUCCESS) {
+        tfm_core_panic();
+    }
+
+    tfm_core_util_memset(invecs, 0, sizeof(invecs));
+    tfm_core_util_memset(outvecs, 0, sizeof(outvecs));
+
+    /* Copy the address out to avoid TOCTOU attacks. */
+    tfm_core_util_memcpy(invecs, inptr, in_num * sizeof(psa_invec));
+    tfm_core_util_memcpy(outvecs, outptr, out_num * sizeof(psa_outvec));
+
+    /*
+     * For client input vector, it is a fatal error if the provided payload
+     * memory reference was invalid or not readable.
+     */
+    for (i = 0; i < in_num; i++) {
+        if (tfm_memory_check(invecs[i].base, invecs[i].len, ns_caller,
+            TFM_MEMORY_ACCESS_RO, privileged) != IPC_SUCCESS) {
+            tfm_core_panic();
+        }
+    }
+
+    /*
+     * Clients must never overlap input parameters because of the risk of a
+     * double-fetch inconsistency.
+     * Overflow is checked in tfm_memory_check functions.
+     */
+    for (i = 0; i + 1 < in_num; i++) {
+        for (j = i+1; j < in_num; j++) {
+            if (!((char *) invecs[j].base + invecs[j].len <=
+                  (char *) invecs[i].base ||
+                  (char *) invecs[j].base >=
+                  (char *) invecs[i].base + invecs[i].len)) {
+                tfm_core_panic();
+            }
+        }
+    }
+
+    /*
+     * For client output vector, it is a fatal error if the provided payload
+     * memory reference was invalid or not read-write.
+     */
+    for (i = 0; i < out_num; i++) {
+        if (tfm_memory_check(outvecs[i].base, outvecs[i].len,
+            ns_caller, TFM_MEMORY_ACCESS_RW, privileged) != IPC_SUCCESS) {
+            tfm_core_panic();
+        }
+    }
+
+    /*
+     * FixMe: Need to check if the message is unrecognized by the RoT
+     * Service or incorrectly formatted.
+     */
+    msg = tfm_spm_get_msg_buffer_from_conn_handle(handle);
+    if (!msg) {
+        /* FixMe: Need to implement one mechanism to resolve this failure. */
+        tfm_core_panic();
+    }
+
+    tfm_spm_fill_msg(msg, service, handle, type, client_id, invecs,
+                     in_num, outvecs, out_num, outptr);
+
+    /*
+     * Send message and wake up the SP who is waiting on message queue,
+     * and scheduler triggered
+     */
+    if (tfm_spm_send_event(service, msg) != IPC_SUCCESS) {
+        /* FixMe: Need to refine failure process here. */
+        tfm_core_panic();
+    }
+    return PSA_SUCCESS;
+}
+
+void tfm_spm_client_psa_close(psa_handle_t handle, bool ns_caller)
+{
+    struct tfm_spm_service_t *service;
+    struct tfm_msg_body_t *msg;
+    int32_t client_id;
+
+    /* It will have no effect if called with the NULL handle */
+    if (handle == PSA_NULL_HANDLE) {
+        return;
+    }
+
+    if (ns_caller) {
+        client_id = tfm_nspm_get_current_client_id();
+    } else {
+        client_id = tfm_spm_partition_get_running_partition_id();
+    }
+
+    /*
+     * It is a fatal error if an invalid handle was provided that is not the
+     * null handle.
+     */
+    if (tfm_spm_validate_conn_handle(handle, client_id) != IPC_SUCCESS) {
+        tfm_core_panic();
+    }
+    service = tfm_spm_get_service_by_handle(handle);
+    if (!service) {
+        /* FixMe: Need to implement one mechanism to resolve this failure. */
+        tfm_core_panic();
+    }
+
+    msg = tfm_spm_get_msg_buffer_from_conn_handle(handle);
+    if (!msg) {
+        /* FixMe: Need to implement one mechanism to resolve this failure. */
+        tfm_core_panic();
+    }
+
+    /* It is a fatal error if the connection is currently handling a request. */
+    if (((struct tfm_conn_handle_t *)handle)->status ==
+                                                     TFM_HANDLE_STATUS_ACTIVE) {
+        tfm_core_panic();
+    }
+
+    /* No input or output needed for close message */
+    tfm_spm_fill_msg(msg, service, handle, PSA_IPC_DISCONNECT, client_id,
+                     NULL, 0, NULL, 0, NULL);
+
+    /*
+     * Send message and wake up the SP who is waiting on message queue,
+     * and scheduler triggered
+     */
+    tfm_spm_send_event(service, msg);
+}
diff --git a/secure_fw/spm/spm_psa_client_call.h b/secure_fw/spm/spm_psa_client_call.h
new file mode 100644
index 0000000..5146e76
--- /dev/null
+++ b/secure_fw/spm/spm_psa_client_call.h
@@ -0,0 +1,110 @@
+/*
+ * Copyright (c) 2019-2020, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
+ */
+
+#ifndef __TFM_PSA_CLIENT_CALL_H__
+#define __TFM_PSA_CLIENT_CALL_H__
+
+#include <stdint.h>
+#include "psa/client.h"
+
+/* Common handlers for PSA client calls */
+
+/**
+ * \brief handler for \ref psa_framework_version.
+ *
+ * \return version              The version of the PSA Framework implementation
+ *                              that is providing the runtime services.
+ */
+uint32_t tfm_spm_client_psa_framework_version(void);
+
+/**
+ * \brief handler for \ref psa_version.
+ *
+ * \param[in] sid               RoT Service identity.
+ * \param[in] ns_caller         If 'true', call from non-secure client.
+ *                              Otherwise from secure client.
+ *
+ * \retval PSA_VERSION_NONE     The RoT Service is not implemented, or the
+ *                              caller is not permitted to access the service.
+ * \retval > 0                  The version of the implemented RoT Service.
+ */
+uint32_t tfm_spm_client_psa_version(uint32_t sid, bool ns_caller);
+
+/**
+ * \brief handler for \ref psa_connect.
+ *
+ * \param[in] sid               RoT Service identity.
+ * \param[in] version           The version of the RoT Service.
+ * \param[in] ns_caller         If 'true', call from non-secure client.
+ *                              Otherwise from secure client.
+ *
+ * \retval PSA_SUCCESS          Success.
+ * \retval PSA_ERROR_CONNECTION_REFUSED The SPM or RoT Service has refused the
+ *                              connection.
+ * \retval PSA_ERROR_CONNECTION_BUSY The SPM or RoT Service cannot make the
+ *                              connection at the moment.
+ * \retval "Does not return"    The RoT Service ID and version are not
+ *                              supported, or the caller is not permitted to
+ *                              access the service.
+ */
+psa_status_t tfm_spm_client_psa_connect(uint32_t sid, uint32_t version,
+                                        bool ns_caller);
+
+/**
+ * \brief handler for \ref psa_call.
+ *
+ * \param[in] handle            Service handle to the established connection,
+ *                              \ref psa_handle_t
+ * \param[in] type              The request type.
+ *                              Must be zero( \ref PSA_IPC_CALL) or positive.
+ * \param[in] inptr             Array of input psa_invec structures.
+ *                              \ref psa_invec
+ * \param[in] in_num            Number of input psa_invec structures.
+ *                              \ref psa_invec
+ * \param[in] outptr            Array of output psa_outvec structures.
+ *                              \ref psa_outvec
+ * \param[in] out_num           Number of outut psa_outvec structures.
+ *                              \ref psa_outvec
+ * \param[in] ns_caller         If 'true', call from non-secure client.
+ *                              Otherwise from secure client.
+ * \param[in] privileged        Privileged mode or unprivileged mode:
+ *                              \ref TFM_PARTITION_UNPRIVILEGED_MODE
+ *                              \ref TFM_PARTITION_PRIVILEGED_MODE
+ *
+ * \retval PSA_SUCCESS          Success.
+ * \retval "Does not return"    The call is invalid, one or more of the
+ *                              following are true:
+ * \arg                           An invalid handle was passed.
+ * \arg                           The connection is already handling a request.
+ * \arg                           An invalid memory reference was provided.
+ * \arg                           in_num + out_num > PSA_MAX_IOVEC.
+ * \arg                           The message is unrecognized by the RoT
+ *                                Service or incorrectly formatted.
+ */
+psa_status_t tfm_spm_client_psa_call(psa_handle_t handle, int32_t type,
+                                     const psa_invec *inptr, size_t in_num,
+                                     psa_outvec *outptr, size_t out_num,
+                                     bool ns_caller, uint32_t privileged);
+
+/**
+ * \brief handler for \ref psa_close.
+ *
+ * \param[in] handle            Service handle to the connection to be closed,
+ *                              \ref psa_handle_t
+ * \param[in] ns_caller         If 'true', call from non-secure client.
+ *                              Otherwise from secure client.
+ *
+ * \retval void                 Success.
+ * \retval "Does not return"    The call is invalid, one or more of the
+ *                              following are true:
+ * \arg                           An invalid handle was provided that is not
+ *                                the null handle.
+ * \arg                           The connection is handling a request.
+ */
+void tfm_spm_client_psa_close(psa_handle_t handle, bool ns_caller);
+
+#endif