Merge remote-tracking branch 'feature-ipc' into 'master'

* Remote feature-ipc: (31 commits)
  Platform: Correct region name
  Core: Add ZI and RW regions for seucre data in memory check
  Core: free connection handle in psa_reply
  Core: Support set reverse handle during connecting
  Core: Fix thread list handling
  Core: Config isolation for partitions with PSA API
  Core: Implement the IPC Secure Client API
  Core: Implement PSA service functions
  Core: Add memory check function for IPC
  Core: Adapt PSA API veneer with implemented handler
  Platform: Align region name in armclang and gcc
  Core: Add secure partition manager for IPC
  Core: Enhance manifest to align with PSA
  Core: Add IPC Client and Service Secure Partition
  Core: Add list, message queue, and pool functions
  Core: Fundamental components for secure IPC
  Core: Update IPC implementation framework
  Core: Align with PSA FF specification 1.0-beta-0
  Crypto: Conditional reference PSA types by PSA FF version
  Cmake: Disable regression tests for IPC configuration
  ...

Change-Id: I6527765ab71fe30e7e9fe93c705d899730970789
Signed-off-by: Edison Ai <edison.ai@arm.com>
diff --git a/CommonConfig.cmake b/CommonConfig.cmake
index 3aaca75..1bbf95a 100644
--- a/CommonConfig.cmake
+++ b/CommonConfig.cmake
@@ -102,6 +102,9 @@
 set (SERVICES_TEST_ENABLED OFF)
 set (TEST_FRAMEWORK_S  OFF)
 set (TEST_FRAMEWORK_NS OFF)
+set (TFM_PSA_API OFF)
+set (TFM_LEGACY_API ON)
+set (CORE_TEST_IPC OFF)
 
 if(${TARGET_PLATFORM} STREQUAL "AN521" OR ${TARGET_PLATFORM} STREQUAL "AN519")
 	set (REFERENCE_PLATFORM ON)
@@ -114,6 +117,19 @@
 	set(SERVICES_TEST_ENABLED ON)
 endif()
 
+if (CORE_IPC)
+	set(TFM_PSA_API ON)
+	set(CORE_TEST_IPC ON)
+endif()
+
+if (TFM_PSA_API)
+	add_definitions(-DTFM_PSA_API)
+endif()
+
+if (TFM_LEGACY_API)
+	add_definitions(-DTFM_LEGACY_API)
+endif()
+
 if (SERVICES_TEST_ENABLED)
 	set(SERVICE_TEST_S ON)
 	set(SERVICE_TEST_NS ON)
@@ -141,13 +157,22 @@
 	set(TFM_PARTITION_TEST_CORE ON)
 endif()
 
+if (CORE_TEST_IPC)
+	add_definitions(-DCORE_TEST_IPC)
+	set(TFM_PARTITION_TEST_SECURE_SERVICES ON)
+	set(TEST_FRAMEWORK_NS ON)
+endif()
+
 if (SERVICE_TEST_S)
 	add_definitions(-DSERVICES_TEST_S)
-	add_definitions(-DTFM_PARTITION_TEST_SECURE_SERVICES)
 	set(TEST_FRAMEWORK_S ON)
 	set(TFM_PARTITION_TEST_SECURE_SERVICES ON)
 endif()
 
+if (TFM_PARTITION_TEST_SECURE_SERVICES)
+	add_definitions(-DTFM_PARTITION_TEST_SECURE_SERVICES)
+endif()
+
 if (SERVICE_TEST_NS)
 	add_definitions(-DSERVICES_TEST_NS)
 	set(TEST_FRAMEWORK_NS ON)
diff --git a/ConfigCoreIPC.cmake b/ConfigCoreIPC.cmake
new file mode 100644
index 0000000..545fd49
--- /dev/null
+++ b/ConfigCoreIPC.cmake
@@ -0,0 +1,49 @@
+#-------------------------------------------------------------------------------
+# Copyright (c) 2018-2019, Arm Limited. All rights reserved.
+#
+# SPDX-License-Identifier: BSD-3-Clause
+#
+#-------------------------------------------------------------------------------
+
+#This file holds information of a specific build configuration of this project.
+
+#Include board specific config (CPU, etc...), select platform specific build
+#system settings file
+if(NOT DEFINED TARGET_PLATFORM)
+	message(FATAL_ERROR "ERROR: TARGET_PLATFORM is not set in command line")
+elseif(${TARGET_PLATFORM} STREQUAL "AN521")
+	set(PLATFORM_CMAKE_FILE "${CMAKE_CURRENT_LIST_DIR}/platform/ext/Mps2AN521.cmake")
+elseif(${TARGET_PLATFORM} STREQUAL "AN519")
+	set(PLATFORM_CMAKE_FILE "${CMAKE_CURRENT_LIST_DIR}/platform/ext/Mps2AN519.cmake")
+elseif(${TARGET_PLATFORM} STREQUAL "MUSCA_A")
+	set(PLATFORM_CMAKE_FILE "${CMAKE_CURRENT_LIST_DIR}/platform/ext/musca_a.cmake")
+elseif(${TARGET_PLATFORM} STREQUAL "MUSCA_B1")
+	set(PLATFORM_CMAKE_FILE "${CMAKE_CURRENT_LIST_DIR}/platform/ext/musca_b1.cmake")
+else()
+	message(FATAL_ERROR "ERROR: Target \"${TARGET_PLATFORM}\" is not supported.")
+endif()
+
+##These variables select how the projects are built. Each project will set
+#various project specific settings (e.g. what files to build, macro
+#definitions) based on these.
+set (REGRESSION False)
+set (CORE_TEST False)
+set (CORE_IPC True)
+
+# TF-M isolation level: 1..3
+set (TFM_LVL 1)
+
+#BL2 bootloader(MCUBoot) related settings
+if(NOT DEFINED BL2)
+	set(BL2 True)
+endif()
+
+if(NOT DEFINED MCUBOOT_NO_SWAP)
+	set(MCUBOOT_NO_SWAP False)
+endif()
+
+if(NOT DEFINED MCUBOOT_RAM_LOADING)
+	set(MCUBOOT_RAM_LOADING False)
+endif()
+
+include ("${CMAKE_CURRENT_LIST_DIR}/CommonConfig.cmake")
diff --git a/app/CMakeLists.txt b/app/CMakeLists.txt
index e19051a..c9b9fa2 100755
--- a/app/CMakeLists.txt
+++ b/app/CMakeLists.txt
@@ -64,6 +64,12 @@
 	list(APPEND NS_APP_SRC "${APP_DIR}/psa_api_test.c")
 endif()
 
+if (NOT DEFINED TFM_PSA_API)
+	message(FATAL_ERROR "Incomplete build configuration: TFM_PSA_API is undefined. ")
+elseif (TFM_PSA_API)
+	list(APPEND NS_APP_SRC "${INTERFACE_DIR}/src/tfm_psa_ns_api.c")
+endif()
+
 set(BUILD_CMSIS_CORE On)
 set(BUILD_RETARGET On)
 set(BUILD_NATIVE_DRIVERS On)
diff --git a/interface/include/psa_client.h b/interface/include/psa_client.h
index 9fe25d9..71adb80 100644
--- a/interface/include/psa_client.h
+++ b/interface/include/psa_client.h
@@ -15,117 +15,125 @@
 #include <stdint.h>
 #include <stddef.h>
 
-/* ******** ******** PSA Common API ******** ******** */
+/*********************** PSA Client Macros and Types *************************/
 
-/* FixMe: PSA FF v0.9 has not been released. All PSA API subject to change */
-#define PSA_FRAMEWORK_VERSION  (0x0009)
+#define PSA_FRAMEWORK_VERSION  (0x0100)
 
 #define PSA_VERSION_NONE       (0)
 
 /* PSA response types */
 #define PSA_SUCCESS            (0)
 #define PSA_CONNECTION_REFUSED (INT32_MIN + 1)
+#define PSA_CONNECTION_BUSY    (INT32_MIN + 2)
 #define PSA_DROP_CONNECTION    (INT32_MIN)
 
 /* PSA message handles */
 #define PSA_NULL_HANDLE        ((psa_handle_t)0)
 
-typedef int32_t psa_error_t;
-typedef int32_t psa_handle_t;
 typedef int32_t psa_status_t;
+typedef int32_t psa_handle_t;
 
 /**
- * A read-only input memory region provided to a RoT Service.
+ * A read-only input memory region provided to an RoT Service.
  */
 typedef struct psa_invec {
-    const void *base;   /*!< the start address of the memory buffer */
-    size_t len;         /*!< the size in bytes */
+    const void *base;           /*!< the start address of the memory buffer */
+    size_t len;                 /*!< the size in bytes                      */
 } psa_invec;
 
 /**
- * A writable output memory region provided to a RoT Service.
+ * A writable output memory region provided to an RoT Service.
  */
 typedef struct psa_outvec {
-    void *base;         /*!< the start address of the memory buffer */
-    size_t len;         /*!< the size in bytes */
+    void *base;                 /*!< the start address of the memory buffer */
+    size_t len;                 /*!< the size in bytes                      */
 } psa_outvec;
 
+/*************************** PSA Client API **********************************/
+
 /**
  * \brief Retrieve the version of the PSA Framework API that is implemented.
  *
- * \return The version of the PSA Framework implementation that is providing
- *         the runtime services to the caller.
- * \return The major and minor version are encoded as follows:
- * \arg    version[15:8] -- major version number
- * \arg    version[7:0]  -- minor version number
+ * \return version              The version of the PSA Framework implementation
+ *                              that is providing the runtime services to the
+ *                              caller. The major and minor version are encoded
+ *                              as follows:
+ * \arg                           version[15:8] -- major version number.
+ * \arg                           version[7:0]  -- minor version number.
  */
 uint32_t psa_framework_version(void);
 
-/* ******** ******** PSA Client API ******** ******** */
-
 /**
- * \brief Retrieve the minor version of a RoT Service or indicate that
- *        it is not present on this system.
+ * \brief Retrieve the minor version of an RoT Service or indicate that it is
+ *        not present on this system.
  *
- * \param[in] sid              ID of the RoT Service to query
+ * \param[in] sid               ID of the RoT Service to query.
  *
- * \retval PSA_VERSION_NONE    The RoT Service is not implemented, or the
- *                             caller is not permitted to access the service
- * \retval >0                  The minor version of the implemented RoT Service
+ * \retval PSA_VERSION_NONE     The RoT Service is not implemented, or the
+ *                              caller is not permitted to access the service.
+ * \retval > 0                  The minor version of the implemented RoT
+ *                              Service.
  */
 uint32_t psa_version(uint32_t sid);
 
 /**
- * \brief Connect to a RoT Service by its SID.
+ * \brief Connect to an RoT Service by its SID.
  *
- * \param[in] sid                 ID of the RoT Service to connect to
- * \param[in] minor_version       Requested version of the RoT Service
+ * \param[in] sid               ID of the RoT Service to connect to.
+ * \param[in] minor_version     Requested version of the RoT Service.
  *
- * \retval >0                     A handle for the connection
- * \retval PSA_CONNECTION_REFUSED The RoT Service has refused the connection
- * \retval "Does not return"      The RoT Service ID and version are not
- *                                supported, or the caller is not permitted
- *                                to access the service
+ * \retval > 0                  A handle for the connection.
+ * \retval PSA_CONNECTION_REFUSED The SPM or RoT Service has refused the
+ *                              connection.
+ * \retval PSA_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_handle_t psa_connect(uint32_t sid, uint32_t minor_version);
 
 /**
- * \brief Calls a RoT Service on an established connection.
+ * \brief Call an RoT Service on an established connection.
  *
- * \param[in] handle           A handle to an established connection
- * \param[in] in_vec           Array of input \ref psa_invec structures
- * \param[in] in_len           Number of input \ref psa_invec structures
- * \param[in] out_vec          Array of input \ref psa_outvec structures
- * \param[in] out_len          Number of input \ref psa_outvec structures
+ * \param[in] handle            A handle to an established connection.
+ * \param[in] in_vec            Array of input \ref psa_invec structures.
+ * \param[in] in_len            Number of input \ref psa_invec structures.
+ * \param[in/out] out_vec       Array of output \ref psa_outvec structures.
+ * \param[in] out_len           Number of output \ref psa_outvec structures.
  *
- * \retval >=0                 Application-specific return code
- * \retval <0                  Application-specific error code
- * \retval PSA_DROP_CONNECTION The connection has been dropped by the RoT
- *                             Service. This indicates that either this or
- *                             a previous message was invalid
- * \retval "Does not return"   The call is invalid, one or more of the following
- *                             are true:
- * \arg                          An invalid handle was passed
- * \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
+ * \retval >=0                  RoT Service-specific status value.
+ * \retval <0                   RoT Service-specific error code.
+ * \retval PSA_DROP_CONNECTION  The connection has been dropped by the RoT
+ *                              Service. This indicates that either this or
+ *                              a previous message was invalid.
+ * \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_len + out_len > PSA_MAX_IOVEC.
+ * \arg                           The message is unrecognized by the RoT
+ *                                Service or incorrectly formatted.
  */
-psa_error_t psa_call(psa_handle_t handle,
-                    const psa_invec *in_vec,
-                    size_t in_len,
-                    const psa_outvec *out_vec,
-                    size_t out_len);
+psa_status_t psa_call(psa_handle_t handle,
+                      const psa_invec *in_vec,
+                      size_t in_len,
+                      psa_outvec *out_vec,
+                      size_t out_len);
 
 /**
- * \brief Closes a connection to a RoT Service.
+ * \brief Close a connection to an RoT Service.
  *
- * \param[in] handle         A handle to an established connection, or the
- *                           null handle
+ * \param[in] handle            A handle to an established connection, or the
+ *                              null handle.
  *
- * \retval void              Success
- * \retval "Does not return" An invalid handle was provided that is not the
- *                           null handle
+ * \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 psa_close(psa_handle_t handle);
 
diff --git a/interface/include/psa_service.h b/interface/include/psa_service.h
index e27b420..6453aed 100644
--- a/interface/include/psa_service.h
+++ b/interface/include/psa_service.h
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2018, Arm Limited. All rights reserved.
+ * Copyright (c) 2018-2019, Arm Limited. All rights reserved.
  *
  * SPDX-License-Identifier: BSD-3-Clause
  *
@@ -14,11 +14,16 @@
 
 #include <inttypes.h>
 
+/********************** PSA Secure Partition Macros and Types ****************/
+
 /* PSA wait timeouts */
 #define PSA_POLL                (0x00000000u)
 #define PSA_BLOCK               (0x80000000u)
 
-/* doorbell signal */
+/* A mask value that includes all Secure Partition signals */
+#define PSA_WAIT_ANY            (~0u)
+
+/* Doorbell signal */
 #define PSA_DOORBELL            (0x00000008u)
 
 /* PSA message types */
@@ -26,225 +31,217 @@
 #define PSA_IPC_CALL            (2)
 #define PSA_IPC_DISCONNECT      (3)
 
-/* PSA response types */
-#define PSA_CONNECTION_ACCEPTED (0)
-
-/* maximum number of input and output vectors */
+/* Maximum number of input and output vectors */
 #define PSA_MAX_IOVEC           (4)
 
+/* Return code from psa_get() */
+#define PSA_ERR_NOMSG           (INT32_MIN + 3)
+
+/* Store a set of one or more Secure Partition signals */
 typedef uint32_t psa_signal_t;
 
 /**
- * Describes a message received by a RoT Service after calling \ref psa_get().
+ * Describe a message received by an RoT Service after calling \ref psa_get().
  */
 typedef struct psa_msg_t {
-    uint32_t type;
-    psa_handle_t handle;
-    void *rhandle;
-    size_t in_size[PSA_MAX_IOVEC];
-    size_t out_size[PSA_MAX_IOVEC];
+    uint32_t type;              /* One of the following values:
+                                 * \ref PSA_IPC_CONNECT
+                                 * \ref PSA_IPC_CALL
+                                 * \ref PSA_IPC_DISCONNECT
+                                 */
+    psa_handle_t handle;        /* A reference generated by the SPM to the
+                                 * message returned by psa_get().
+                                 */
+    int32_t client_id;          /* Partition ID of the sender of the message */
+    void *rhandle;              /* Be useful for binding a connection to some
+                                 * application-specific data or function
+                                 * pointer within the RoT Service
+                                 * implementation.
+                                 */
+    size_t in_size[PSA_MAX_IOVEC]; /* Provide the size of each client input
+                                    * vector in bytes.
+                                    */
+    size_t out_size[PSA_MAX_IOVEC];/* Provide the size of each client output
+                                    * vector in bytes.
+                                    */
 } psa_msg_t;
 
-/* ******** ******** PSA Secure Function API ******** ******** */
+/************************* PSA Secure Partition API **************************/
 
 /**
- * \brief Returns the set of signals that have been asserted for a Sercure
- *        Partition.
+ * \brief Return the Secure Partition interrupt signals that have been asserted
+ *        from a subset of signals provided by the caller.
  *
- * \param[in] timeout   Specify either blocking or polling operation
+ * \param[in] signal_mask       A set of signals to query. Signals that are not
+ *                              in this set will be ignored.
+ * \param[in] timeout           Specify either blocking \ref PSA_BLOCK or
+ *                              polling \ref PSA_POLL operation.
  *
- * \retval >0           At least one signal is asserted
- * \retval 0            No signals are asserted. This is only seen if the
- *                      caller used a polling 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.
  */
-uint32_t psa_wait_any(uint32_t timeout);
+psa_signal_t psa_wait(psa_signal_t signal_mask, uint32_t timeout);
 
 /**
- * \brief Returns the Secure Partition interrupt signals that have been
- *        asserted from the subset of signals indicated in the bitmask provided.
- *
- * \param[in] signal_mask    A set of interrupt and doorbell signals to query.
- *                           Signals that are not in this set will be ignored
- * \param[in] timeout        Specify either blocking or polling operation
- *
- * \retval >0                At least one signal is asserted
- * \retval 0                 No signals are asserted. This case is only seen if
- *                           caller used a polling timeout
- * \retval "Does not return" The call is invalid, one or more of the following
- *                           are true:
- * \arg                          signal_mask does not include any interrupt or
- *                               doorbell signals
- * \arg                          signal_mask includes one or more RoT Service
- *                               signals
- */
-uint32_t psa_wait_interrupt(psa_signal_t signal_mask, uint32_t timeout);
-
-/**
- * \brief Get the message which corresponds to a given RoT Service signal
+ * \brief Retrieve the message which corresponds to a given RoT Service signal
  *        and remove the message from the RoT Service queue.
  *
- * \param[in]  signal        The signal value for an asserted RoT Service
- * \param[out] msg           Pointer to \ref psa_msg_t object for receiving
- *                           the message
+ * \param[in] signal            The signal value for an asserted RoT Service.
+ * \param[out] msg              Pointer to \ref psa_msg_t object for receiving
+ *                              the message.
  *
- * \retval void              Success
- * \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 a RoT Service
- * \arg                         The RoT Service signal is not currently asserted
- * \arg                         The msg pointer provided is not a valid memory
- *                              reference
+ * \retval PSA_SUCCESS          Success, *msg will contain the delivered
+ *                              message.
+ * \retval PSA_ERR_NOMSG        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.
  */
-void psa_get(psa_signal_t signal, psa_msg_t *msg);
+psa_status_t psa_get(psa_signal_t signal, psa_msg_t *msg);
 
 /**
- * \brief Get the Partition ID of the sender of a message.
+ * \brief Associate some RoT Service private data with a client connection.
  *
- * \param[in] msg_handle     Message handle for an incoming message
+ * \param[in] msg_handle        Handle for the client's message.
+ * \param[in] rhandle           Reverse handle allocated by the RoT Service.
  *
- * \retval >0                ID of a Secure Partition
- * \retval <0                ID of an NSPE client
- * \retval "Does not return" msg_handle is invalid
- *
- * \note Bit[31] is set if the caller is from the NSPE.
- */
-int32_t psa_identity(psa_handle_t msg_handle);
-
-/**
- * \brief Associates some caller-provided private data with a specified client
- *        connection.
- *
- * \param[in] msg_handle     Handle for the client's message
- * \param[in] rhandle        Reverse handle allocated by the RoT Service
- *
- * \retval void              Success, rhandle will be provided with all
- *                           subsequent messages delivered on this connection
- * \retval "Does not return" msg_handle is invalid
+ * \retval void                 Success, rhandle will be provided with all
+ *                              subsequent messages delivered on this
+ *                              connection.
+ * \retval "Does not return"    msg_handle is invalid.
  */
 void psa_set_rhandle(psa_handle_t msg_handle, void *rhandle);
 
 /**
- * \brief Read a message parameter or part of a message parameter from the
- *        client input vector.
+ * \brief Read a message parameter or part of a message parameter from a client
+ *        input vector.
  *
- * \param[in]  msg_handle    Handle for the client's message
- * \param[in]  invec_idx     Index of the input vector to read from. Must be
- *                           less than \ref PSA_MAX_IOVEC
- * \param[out] buffer        Buffer in the Secure Partition to copy the
- *                           requested data to
- * \param[in]  num_bytes     Maximum number of bytes to be read from the client
- *                           input vector
+ * \param[in] msg_handle        Handle for the client's message.
+ * \param[in] invec_idx         Index of the input vector to read from. Must be
+ *                              less than \ref PSA_MAX_IOVEC.
+ * \param[out] buffer           Buffer in the Secure Partition to copy the
+ *                              requested data to.
+ * \param[in] num_bytes         Maximum number of bytes to be read from the
+ *                              client input vector.
  *
- * \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 \ref PSA_IPC_CALL
- *                              message
- * \arg                         invec_idx is equal to or greater than
- *                              PSA_MAX_IOVEC
- * \arg                         the memory reference for buffer is invalid or
- *                              not writable
+ * \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
+ *                                \ref PSA_IPC_CALL 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 psa_read(psa_handle_t msg_handle, uint32_t invec_idx,
-                    void *buffer, size_t num_bytes);
+                void *buffer, size_t num_bytes);
 
 /**
- * \brief Skip a given number of bytes for an input vector.
+ * \brief Skip over part of a client input vector.
  *
- * \param[in] msg_handle     Handle for the client's message
- * \param[in] invec_idx      Index of input vector in message to skip from.
- *                           Must be less than \ref PSA_MAX_IOVEC
- * \param[in] num_bytes      Maximum number of bytes to skip in the client input
- *                           vector
+ * \param[in] msg_handle        Handle for the client's message.
+ * \param[in] invec_idx         Index of input vector to skip from. Must be
+ *                              less than \ref PSA_MAX_IOVEC.
+ * \param[in] num_bytes         Maximum number of bytes to skip in the client
+ *                              input vector.
  *
- * \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 \ref PSA_IPC_CALL
- *                              message
- * \arg                         invec_idx is equal to or greater than
- *                              PSA_MAX_IOVEC
+ * \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
+ *                                \ref PSA_IPC_CALL message.
+ * \arg                           invec_idx is equal to or greater than
+ *                                \ref PSA_MAX_IOVEC.
  */
 size_t psa_skip(psa_handle_t msg_handle, uint32_t invec_idx, size_t num_bytes);
 
 /**
- * \brief Write a message response to the client output vector.
+ * \brief Write a message response to a client output vector.
  *
- * \param[in]  msg_handle    Handle for the client's message
- * \param[out] outvec_idx    Index of output vector in message to write to.
- *                           Must be less than \ref PSA_MAX_IOVEC
- * \param[in]  buffer        Buffer with the data to write
- * \param[in]  num_bytes     Number of bytes to write to the client output
- *                           vector
+ * \param[in] msg_handle        Handle for the client's message.
+ * \param[out] outvec_idx       Index of output vector in message to write to.
+ *                              Must be less than \ref PSA_MAX_IOVEC.
+ * \param[in] buffer            Buffer with the data to write.
+ * \param[in] num_bytes         Number of bytes to write to the client output
+ *                              vector.
  *
- * \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 \ref PSA_IPC_CALL
- *                              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
+ * \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
+ *                                \ref PSA_IPC_CALL 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 psa_write(psa_handle_t msg_handle, uint32_t outvec_idx,
-                    const void *buffer, size_t num_bytes);
+               const void *buffer, size_t num_bytes);
 
 /**
- * \brief Completes handling of a specific message and unblocks the client.
+ * \brief Complete handling of a specific message and unblock the client.
  *
- * \param[in] msg_handle     Handle for the client's message or the null handle
- * \param[in] retval         Return value to be reported to the client
+ * \param[in] msg_handle        Handle for the client's message.
+ * \param[in] status            Message result value to be reported to the
+ *                              client.
  *
- * \retval void              Success
- * \retval "Does not return" The call is invalid, one or more of the following
- *                           are true:
- * \arg                         msg_handle is invalid and is not the null handle
- * \arg                         An invalid return code is specified for the type
- *                              of message
+ * \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 psa_end(psa_handle_t msg_handle, psa_error_t retval);
+void psa_reply(psa_handle_t msg_handle, psa_status_t status);
 
 /**
- * \brief Sends a PSA_DOORBELL signal to a specific Secure Partition.
+ * \brief Send a PSA_DOORBELL signal to a specific Secure Partition.
  *
- * \param[in] partition_id   Secure Partition ID of the target partition
+ * \param[in] partition_id      Secure Partition ID of the target partition.
  *
- * \retval void              Success
- * \retval "Does not return" partition_id does not correspond to a Secure
- *                           Partition
+ * \retval void                 Success.
+ * \retval "Does not return"    partition_id does not correspond to a Secure
+ *                              Partition.
  */
 void psa_notify(int32_t partition_id);
 
 /**
- * \brief Clears the PSA_DOORBELL signal.
+ * \brief Clear the PSA_DOORBELL signal.
  *
- * \retval void              Success
- * \retval "Does not return" The Secure Partition's doorbell signal is not
- *                           currently asserted
+ * \retval void                 Success.
+ * \retval "Does not return"    The Secure Partition's doorbell signal is not
+ *                              currently asserted.
  */
 void psa_clear(void);
 
 /**
- * \brief Informs the SPM that an interrupt has been handled (end of interrupt).
+ * \brief Inform the SPM that an interrupt has been handled (end of interrupt).
  *
- * \param[in] irq_signal     The interrupt signal that has been processed
+ * \param[in] irq_signal        The interrupt signal that has been processed.
  *
- * \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
+ * \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 psa_eoi(uint32_t irq_signal);
+void psa_eoi(psa_signal_t irq_signal);
 
 #ifdef __cplusplus
 }
diff --git a/interface/include/tfm_api.h b/interface/include/tfm_api.h
index be36e2e..2ba93c0 100644
--- a/interface/include/tfm_api.h
+++ b/interface/include/tfm_api.h
@@ -13,7 +13,6 @@
 #endif
 
 #include <stdint.h>
-
 #include "psa_client.h"
 
 #define TFM_INVALID_CLIENT_ID 0
@@ -80,6 +79,54 @@
  */
 enum tfm_status_e tfm_register_client_id (int32_t ns_client_id);
 
+/**
+ * \brief Retrieve the version of the PSA Framework API that is implemented
+ *
+ * \return The version of the PSA Framework
+ */
+uint32_t tfm_psa_framework_version_veneer(void);
+
+/**
+ * \brief Return version of secure function provided by secure binary
+ *
+ * \param[in]  sid          ID of secure service
+ *
+ * \return Version number of secure function
+ */
+uint32_t tfm_psa_version_veneer(uint32_t sid);
+
+/**
+ * \brief Connect to secure function
+ *
+ * \param[in]  sid              ID of secure service
+ * \param[in]  minor_version    Minor version of SF requested by client
+ *
+ * \return Returns handle to connection
+ */
+psa_handle_t tfm_psa_connect_veneer(uint32_t sid, uint32_t minor_version);
+
+/**
+ * \brief Call a secure function referenced by a connection handle
+ *
+ * \param[in]  handle   Handle to connection
+ * \param[in]  in_vecs  invec containing pointer/count of input vectors
+ * \param[in]  out_vecs invec containing pointer/count of output vectors
+ *
+ * \return Returns \ref psa_status_t status code
+ */
+psa_status_t tfm_psa_call_veneer(psa_handle_t handle,
+                                 const psa_invec *in_vecs,
+                                 const psa_invec *out_vecs);
+
+/**
+ * \brief Close connection to secure function referenced by a connection handle
+ *
+ * \param[in]  handle   Handle to connection
+ *
+ * \return Returns \ref psa_status_t status code
+ */
+psa_status_t tfm_psa_close_veneer(psa_handle_t handle);
+
 //================ End Secure function declarations ==========================//
 
 #ifdef __cplusplus
diff --git a/interface/include/tfm_veneers.h b/interface/include/tfm_veneers.h
index c238b35..966d8c1 100644
--- a/interface/include/tfm_veneers.h
+++ b/interface/include/tfm_veneers.h
@@ -35,6 +35,14 @@
 psa_status_t tfm_tfm_crypto_destroy_key_veneer(struct psa_invec *in_vec, size_t in_len, struct psa_outvec *out_vec, size_t out_len);
 psa_status_t tfm_tfm_crypto_get_key_information_veneer(struct psa_invec *in_vec, size_t in_len, struct psa_outvec *out_vec, size_t out_len);
 psa_status_t tfm_tfm_crypto_export_key_veneer(struct psa_invec *in_vec, size_t in_len, struct psa_outvec *out_vec, size_t out_len);
+psa_status_t tfm_tfm_crypto_key_policy_init_veneer(struct psa_invec *in_vec, size_t in_len, struct psa_outvec *out_vec, size_t out_len);
+psa_status_t tfm_tfm_crypto_key_policy_set_usage_veneer(struct psa_invec *in_vec, size_t in_len, struct psa_outvec *out_vec, size_t out_len);
+psa_status_t tfm_tfm_crypto_key_policy_get_usage_veneer(struct psa_invec *in_vec, size_t in_len, struct psa_outvec *out_vec, size_t out_len);
+psa_status_t tfm_tfm_crypto_key_policy_get_algorithm_veneer(struct psa_invec *in_vec, size_t in_len, struct psa_outvec *out_vec, size_t out_len);
+psa_status_t tfm_tfm_crypto_set_key_policy_veneer(struct psa_invec *in_vec, size_t in_len, struct psa_outvec *out_vec, size_t out_len);
+psa_status_t tfm_tfm_crypto_get_key_policy_veneer(struct psa_invec *in_vec, size_t in_len, struct psa_outvec *out_vec, size_t out_len);
+psa_status_t tfm_tfm_crypto_get_key_lifetime_veneer(struct psa_invec *in_vec, size_t in_len, struct psa_outvec *out_vec, size_t out_len);
+psa_status_t tfm_tfm_crypto_set_key_lifetime_veneer(struct psa_invec *in_vec, size_t in_len, struct psa_outvec *out_vec, size_t out_len);
 psa_status_t tfm_tfm_crypto_cipher_set_iv_veneer(struct psa_invec *in_vec, size_t in_len, struct psa_outvec *out_vec, size_t out_len);
 psa_status_t tfm_tfm_crypto_cipher_encrypt_setup_veneer(struct psa_invec *in_vec, size_t in_len, struct psa_outvec *out_vec, size_t out_len);
 psa_status_t tfm_tfm_crypto_cipher_decrypt_setup_veneer(struct psa_invec *in_vec, size_t in_len, struct psa_outvec *out_vec, size_t out_len);
@@ -46,6 +54,14 @@
 psa_status_t tfm_tfm_crypto_hash_finish_veneer(struct psa_invec *in_vec, size_t in_len, struct psa_outvec *out_vec, size_t out_len);
 psa_status_t tfm_tfm_crypto_hash_verify_veneer(struct psa_invec *in_vec, size_t in_len, struct psa_outvec *out_vec, size_t out_len);
 psa_status_t tfm_tfm_crypto_hash_abort_veneer(struct psa_invec *in_vec, size_t in_len, struct psa_outvec *out_vec, size_t out_len);
+psa_status_t tfm_tfm_crypto_mac_sign_setup_veneer(struct psa_invec *in_vec, size_t in_len, struct psa_outvec *out_vec, size_t out_len);
+psa_status_t tfm_tfm_crypto_mac_verify_setup_veneer(struct psa_invec *in_vec, size_t in_len, struct psa_outvec *out_vec, size_t out_len);
+psa_status_t tfm_tfm_crypto_mac_update_veneer(struct psa_invec *in_vec, size_t in_len, struct psa_outvec *out_vec, size_t out_len);
+psa_status_t tfm_tfm_crypto_mac_sign_finish_veneer(struct psa_invec *in_vec, size_t in_len, struct psa_outvec *out_vec, size_t out_len);
+psa_status_t tfm_tfm_crypto_mac_verify_finish_veneer(struct psa_invec *in_vec, size_t in_len, struct psa_outvec *out_vec, size_t out_len);
+psa_status_t tfm_tfm_crypto_mac_abort_veneer(struct psa_invec *in_vec, size_t in_len, struct psa_outvec *out_vec, size_t out_len);
+psa_status_t tfm_tfm_crypto_aead_decrypt_wrapper_veneer(struct psa_invec *in_vec, size_t in_len, struct psa_outvec *out_vec, size_t out_len);
+psa_status_t tfm_tfm_crypto_aead_encrypt_wrapper_veneer(struct psa_invec *in_vec, size_t in_len, struct psa_outvec *out_vec, size_t out_len);
 
 /******** TFM_SP_PLATFORM ********/
 psa_status_t tfm_platform_sp_system_reset_veneer(struct psa_invec *in_vec, size_t in_len, struct psa_outvec *out_vec, size_t out_len);
@@ -74,6 +90,14 @@
 psa_status_t tfm_tfm_secure_client_service_sfn_run_tests_veneer(struct psa_invec *in_vec, size_t in_len, struct psa_outvec *out_vec, size_t out_len);
 #endif /* TFM_PARTITION_TEST_SECURE_SERVICES */
 
+#ifdef TFM_PSA_API
+/******** TFM_SP_IPC_SERVICE_TEST ********/
+#endif /* TFM_PSA_API */
+
+#ifdef TFM_PSA_API
+/******** TFM_SP_IPC_CLIENT_TEST ********/
+#endif /* TFM_PSA_API */
+
 #ifdef __cplusplus
 }
 #endif
diff --git a/interface/include/tfm_veneers.h.template b/interface/include/tfm_veneers.h.template
index 4a5727c..78829fa 100644
--- a/interface/include/tfm_veneers.h.template
+++ b/interface/include/tfm_veneers.h.template
@@ -20,7 +20,7 @@
 @!GENERATOR_CONDITIONAL_START!@ @@attr.conditional@@
 #ifdef @@attr.conditional@@
 @!GENERATOR_CONDITIONAL_END!@
-/******** @@manifest.tfm_partition_name@@ ********/
+/******** @@manifest.name@@ ********/
 psa_status_t tfm_@@manifest.secure_functions.tfm_symbol@@_veneer(struct psa_invec *in_vec, size_t in_len, struct psa_outvec *out_vec, size_t out_len);
 @!GENERATOR_CONDITIONAL_START!@ @@attr.conditional@@
 #endif /* @@attr.conditional@@ */
diff --git a/interface/src/tfm_psa_ns_api.c b/interface/src/tfm_psa_ns_api.c
new file mode 100644
index 0000000..159eef9
--- /dev/null
+++ b/interface/src/tfm_psa_ns_api.c
@@ -0,0 +1,75 @@
+/*
+ * Copyright (c) 2018, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
+ */
+
+#include "interface/include/psa_client.h"
+#include "tfm_ns_lock.h"
+#include "tfm_api.h"
+
+/**** API functions ****/
+
+uint32_t psa_framework_version(void)
+{
+    return tfm_ns_lock_dispatch((veneer_fn)tfm_psa_framework_version_veneer,
+                                0,
+                                0,
+                                0,
+                                0);
+}
+
+uint32_t psa_version(uint32_t sid)
+{
+    return tfm_ns_lock_dispatch((veneer_fn)tfm_psa_version_veneer,
+                                sid,
+                                0,
+                                0,
+                                0);
+}
+
+psa_handle_t psa_connect(uint32_t sid, uint32_t minor_version)
+{
+    return tfm_ns_lock_dispatch((veneer_fn)tfm_psa_connect_veneer,
+                                sid,
+                                minor_version,
+                                0,
+                                0);
+}
+
+psa_status_t psa_call(psa_handle_t handle,
+                      const psa_invec *in_vec,
+                      size_t in_len,
+                      psa_outvec *out_vec,
+                      size_t out_len)
+{
+    /* FixMe: sanity check can be added to offload some NS thread checks from
+     * TFM secure API
+     */
+
+    /* Due to v8M restrictions, TF-M NS API needs to add another layer of
+     * serialization in order for NS to pass arguments to S
+     */
+    psa_invec in_vecs, out_vecs;
+
+    in_vecs.base = in_vec;
+    in_vecs.len = in_len;
+    out_vecs.base = out_vec;
+    out_vecs.len = out_len;
+    return tfm_ns_lock_dispatch((veneer_fn)tfm_psa_call_veneer,
+                                (uint32_t)handle,
+                                (uint32_t)&in_vecs,
+                                (uint32_t)&out_vecs,
+                                0);
+}
+
+void psa_close(psa_handle_t handle)
+{
+    tfm_ns_lock_dispatch((veneer_fn)tfm_psa_close_veneer,
+                         (uint32_t)handle,
+                         0,
+                         0,
+                         0);
+}
+
diff --git a/platform/ext/target/mps2/an519/gcc/mps2_an519_s.ld b/platform/ext/target/mps2/an519/gcc/mps2_an519_s.ld
index 61bb849..5231947 100644
--- a/platform/ext/target/mps2/an519/gcc/mps2_an519_s.ld
+++ b/platform/ext/target/mps2/an519/gcc/mps2_an519_s.ld
@@ -120,6 +120,16 @@
         LONG (ADDR(.TFM_SP_SECURE_TEST_PARTITION_DATA))
         LONG (SIZEOF(.TFM_SP_SECURE_TEST_PARTITION_DATA))
 #endif /* TFM_PARTITION_TEST_SECURE_SERVICES */
+#ifdef TFM_PSA_API
+        LONG (LOADADDR(.TFM_SP_IPC_SERVICE_TEST_DATA))
+        LONG (ADDR(.TFM_SP_IPC_SERVICE_TEST_DATA))
+        LONG (SIZEOF(.TFM_SP_IPC_SERVICE_TEST_DATA))
+#endif /* TFM_PSA_API */
+#ifdef TFM_PSA_API
+        LONG (LOADADDR(.TFM_SP_IPC_CLIENT_TEST_DATA))
+        LONG (ADDR(.TFM_SP_IPC_CLIENT_TEST_DATA))
+        LONG (SIZEOF(.TFM_SP_IPC_CLIENT_TEST_DATA))
+#endif /* TFM_PSA_API */
         __copy_table_end__ = .;
     } > FLASH
 
@@ -168,6 +178,18 @@
         LONG (ADDR(.TFM_SP_SECURE_TEST_PARTITION_STACK))
         LONG (SIZEOF(.TFM_SP_SECURE_TEST_PARTITION_STACK))
 #endif /* TFM_PARTITION_TEST_SECURE_SERVICES */
+#ifdef TFM_PSA_API
+        LONG (ADDR(.TFM_SP_IPC_SERVICE_TEST_BSS))
+        LONG (SIZEOF(.TFM_SP_IPC_SERVICE_TEST_BSS))
+        LONG (ADDR(.TFM_SP_IPC_SERVICE_TEST_STACK))
+        LONG (SIZEOF(.TFM_SP_IPC_SERVICE_TEST_STACK))
+#endif /* TFM_PSA_API */
+#ifdef TFM_PSA_API
+        LONG (ADDR(.TFM_SP_IPC_CLIENT_TEST_BSS))
+        LONG (SIZEOF(.TFM_SP_IPC_CLIENT_TEST_BSS))
+        LONG (ADDR(.TFM_SP_IPC_CLIENT_TEST_STACK))
+        LONG (SIZEOF(.TFM_SP_IPC_CLIENT_TEST_STACK))
+#endif /* TFM_PSA_API */
         LONG (ADDR(.TFM_UNPRIV_SCRATCH))
         LONG (SIZEOF(.TFM_UNPRIV_SCRATCH))
         __zero_table_end__ = .;
@@ -313,6 +335,34 @@
     Image$$TFM_SP_SECURE_TEST_PARTITION$$Limit = ADDR(.TFM_SP_SECURE_TEST_PARTITION) + SIZEOF(.TFM_SP_SECURE_TEST_PARTITION);
 
 #endif /* TFM_PARTITION_TEST_SECURE_SERVICES */
+#ifdef TFM_PSA_API
+    .TFM_SP_IPC_SERVICE_TEST : ALIGN(32)
+    {
+        *ipc_service_test*:*(.text*)
+        *ipc_service_test*:*(.rodata*)
+        *(TFM_SP_IPC_SERVICE_TEST_ATTR_FN)
+        . = ALIGN(32);
+    } > FLASH
+    Image$$TFM_SP_IPC_SERVICE_TEST$$RO$$Base = ADDR(.TFM_SP_IPC_SERVICE_TEST);
+    Image$$TFM_SP_IPC_SERVICE_TEST$$RO$$Limit = ADDR(.TFM_SP_IPC_SERVICE_TEST) + SIZEOF(.TFM_SP_IPC_SERVICE_TEST);
+    Image$$TFM_SP_IPC_SERVICE_TEST$$Base = ADDR(.TFM_SP_IPC_SERVICE_TEST);
+    Image$$TFM_SP_IPC_SERVICE_TEST$$Limit = ADDR(.TFM_SP_IPC_SERVICE_TEST) + SIZEOF(.TFM_SP_IPC_SERVICE_TEST);
+
+#endif /* TFM_PSA_API */
+#ifdef TFM_PSA_API
+    .TFM_SP_IPC_CLIENT_TEST : ALIGN(32)
+    {
+        *ipc_client_test*:*(.text*)
+        *ipc_client_test*:*(.rodata*)
+        *(TFM_SP_IPC_CLIENT_TEST_ATTR_FN)
+        . = ALIGN(32);
+    } > FLASH
+    Image$$TFM_SP_IPC_CLIENT_TEST$$RO$$Base = ADDR(.TFM_SP_IPC_CLIENT_TEST);
+    Image$$TFM_SP_IPC_CLIENT_TEST$$RO$$Limit = ADDR(.TFM_SP_IPC_CLIENT_TEST) + SIZEOF(.TFM_SP_IPC_CLIENT_TEST);
+    Image$$TFM_SP_IPC_CLIENT_TEST$$Base = ADDR(.TFM_SP_IPC_CLIENT_TEST);
+    Image$$TFM_SP_IPC_CLIENT_TEST$$Limit = ADDR(.TFM_SP_IPC_CLIENT_TEST) + SIZEOF(.TFM_SP_IPC_CLIENT_TEST);
+
+#endif /* TFM_PSA_API */
 
     .ARM.extab :
     {
@@ -661,6 +711,58 @@
     Image$$TFM_SP_SECURE_TEST_PARTITION_STACK$$ZI$$Limit = ADDR(.TFM_SP_SECURE_TEST_PARTITION_STACK) + SIZEOF(.TFM_SP_SECURE_TEST_PARTITION_STACK);
 
 #endif /* TFM_PARTITION_TEST_SECURE_SERVICES */
+#ifdef TFM_PSA_API
+    .TFM_SP_IPC_SERVICE_TEST_DATA : ALIGN(32)
+    {
+        *ipc_service_test*:*(.data*)
+        . = ALIGN(32);
+    } > RAM AT> FLASH
+    Image$$TFM_SP_IPC_SERVICE_TEST_DATA$$RW$$Base = ADDR(.TFM_SP_IPC_SERVICE_TEST_DATA);
+    Image$$TFM_SP_IPC_SERVICE_TEST_DATA$$RW$$Limit = ADDR(.TFM_SP_IPC_SERVICE_TEST_DATA) + SIZEOF(.TFM_SP_IPC_SERVICE_TEST_DATA);
+
+    .TFM_SP_IPC_SERVICE_TEST_BSS : ALIGN(32)
+    {
+        *ipc_service_test*:*(.bss*)
+        *ipc_service_test*:*(COMMON)
+        . = ALIGN(32);
+    } > RAM AT> FLASH
+    Image$$TFM_SP_IPC_SERVICE_TEST_DATA$$ZI$$Base = ADDR(.TFM_SP_IPC_SERVICE_TEST_BSS);
+    Image$$TFM_SP_IPC_SERVICE_TEST_DATA$$ZI$$Limit = ADDR(.TFM_SP_IPC_SERVICE_TEST_BSS) + SIZEOF(.TFM_SP_IPC_SERVICE_TEST_BSS);
+
+    .TFM_SP_IPC_SERVICE_TEST_STACK : ALIGN(128)
+    {
+        . += 0x1000;
+    } > RAM AT> FLASH
+    Image$$TFM_SP_IPC_SERVICE_TEST_STACK$$ZI$$Base = ADDR(.TFM_SP_IPC_SERVICE_TEST_STACK);
+    Image$$TFM_SP_IPC_SERVICE_TEST_STACK$$ZI$$Limit = ADDR(.TFM_SP_IPC_SERVICE_TEST_STACK) + SIZEOF(.TFM_SP_IPC_SERVICE_TEST_STACK);
+
+#endif /* TFM_PSA_API */
+#ifdef TFM_PSA_API
+    .TFM_SP_IPC_CLIENT_TEST_DATA : ALIGN(32)
+    {
+        *ipc_client_test*:*(.data*)
+        . = ALIGN(32);
+    } > RAM AT> FLASH
+    Image$$TFM_SP_IPC_CLIENT_TEST_DATA$$RW$$Base = ADDR(.TFM_SP_IPC_CLIENT_TEST_DATA);
+    Image$$TFM_SP_IPC_CLIENT_TEST_DATA$$RW$$Limit = ADDR(.TFM_SP_IPC_CLIENT_TEST_DATA) + SIZEOF(.TFM_SP_IPC_CLIENT_TEST_DATA);
+
+    .TFM_SP_IPC_CLIENT_TEST_BSS : ALIGN(32)
+    {
+        *ipc_client_test*:*(.bss*)
+        *ipc_client_test*:*(COMMON)
+        . = ALIGN(32);
+    } > RAM AT> FLASH
+    Image$$TFM_SP_IPC_CLIENT_TEST_DATA$$ZI$$Base = ADDR(.TFM_SP_IPC_CLIENT_TEST_BSS);
+    Image$$TFM_SP_IPC_CLIENT_TEST_DATA$$ZI$$Limit = ADDR(.TFM_SP_IPC_CLIENT_TEST_BSS) + SIZEOF(.TFM_SP_IPC_CLIENT_TEST_BSS);
+
+    .TFM_SP_IPC_CLIENT_TEST_STACK : ALIGN(128)
+    {
+        . += 0x1000;
+    } > RAM AT> FLASH
+    Image$$TFM_SP_IPC_CLIENT_TEST_STACK$$ZI$$Base = ADDR(.TFM_SP_IPC_CLIENT_TEST_STACK);
+    Image$$TFM_SP_IPC_CLIENT_TEST_STACK$$ZI$$Limit = ADDR(.TFM_SP_IPC_CLIENT_TEST_STACK) + SIZEOF(.TFM_SP_IPC_CLIENT_TEST_STACK);
+
+#endif /* TFM_PSA_API */
 
     .TFM_SP_SECURE_TEST_PARTITION_DATA : ALIGN(32)
     {
@@ -720,8 +822,8 @@
         . = ALIGN(4);
 
     } > RAM AT> FLASH
-    Image$$TFM_DATA$$RW$$Base = ADDR(.TFM_DATA);
-    Image$$TFM_DATA$$RW$$Limit = ADDR(.TFM_DATA) + SIZEOF(.TFM_DATA);
+    Image$$ER_TFM_DATA$$RW$$Base = ADDR(.TFM_DATA);
+    Image$$ER_TFM_DATA$$RW$$Limit = ADDR(.TFM_DATA) + SIZEOF(.TFM_DATA);
 
     .TFM_BSS : ALIGN(4)
     {
@@ -731,8 +833,11 @@
         . = ALIGN(4);
         __bss_end__ = .;
     } > RAM AT> FLASH
-    Image$$TFM_DATA$$ZI$$Base = ADDR(.TFM_BSS);
-    Image$$TFM_DATA$$ZI$$Limit = ADDR(.TFM_BSS) + SIZEOF(.TFM_BSS);
+    Image$$ER_TFM_DATA$$ZI$$Base = ADDR(.TFM_BSS);
+    Image$$ER_TFM_DATA$$ZI$$Limit = ADDR(.TFM_BSS) + SIZEOF(.TFM_BSS);
+
+    Image$$ER_TFM_DATA$$Base = ADDR(.TFM_DATA);
+    Image$$ER_TFM_DATA$$Limit = ADDR(.TFM_DATA) + SIZEOF(.TFM_DATA) + SIZEOF(.TFM_BSS);
 
     /*
      * Place the CMSE Veneers (containing the SG instruction) after the code, in a
diff --git a/platform/ext/target/mps2/an519/gcc/mps2_an519_s.ld.template b/platform/ext/target/mps2/an519/gcc/mps2_an519_s.ld.template
index 43c9372..6a3ac44 100644
--- a/platform/ext/target/mps2/an519/gcc/mps2_an519_s.ld.template
+++ b/platform/ext/target/mps2/an519/gcc/mps2_an519_s.ld.template
@@ -94,9 +94,9 @@
 @!GENERATOR_CONDITIONAL_START!@ @@attr.conditional@@
 #ifdef @@attr.conditional@@
 @!GENERATOR_CONDITIONAL_END!@
-        LONG (LOADADDR(.@@manifest.tfm_partition_name@@_DATA))
-        LONG (ADDR(.@@manifest.tfm_partition_name@@_DATA))
-        LONG (SIZEOF(.@@manifest.tfm_partition_name@@_DATA))
+        LONG (LOADADDR(.@@manifest.name@@_DATA))
+        LONG (ADDR(.@@manifest.name@@_DATA))
+        LONG (SIZEOF(.@@manifest.name@@_DATA))
 @!GENERATOR_CONDITIONAL_START!@ @@attr.conditional@@
 #endif /* @@attr.conditional@@ */
 @!GENERATOR_CONDITIONAL_END!@
@@ -115,10 +115,10 @@
 @!GENERATOR_CONDITIONAL_START!@ @@attr.conditional@@
 #ifdef @@attr.conditional@@
 @!GENERATOR_CONDITIONAL_END!@
-        LONG (ADDR(.@@manifest.tfm_partition_name@@_BSS))
-        LONG (SIZEOF(.@@manifest.tfm_partition_name@@_BSS))
-        LONG (ADDR(.@@manifest.tfm_partition_name@@_STACK))
-        LONG (SIZEOF(.@@manifest.tfm_partition_name@@_STACK))
+        LONG (ADDR(.@@manifest.name@@_BSS))
+        LONG (SIZEOF(.@@manifest.name@@_BSS))
+        LONG (ADDR(.@@manifest.name@@_STACK))
+        LONG (SIZEOF(.@@manifest.name@@_STACK))
 @!GENERATOR_CONDITIONAL_START!@ @@attr.conditional@@
 #endif /* @@attr.conditional@@ */
 @!GENERATOR_CONDITIONAL_END!@
@@ -156,7 +156,7 @@
 @!GENERATOR_CONDITIONAL_START!@ @@attr.conditional@@
 #ifdef @@attr.conditional@@
 @!GENERATOR_CONDITIONAL_END!@
-    .@@manifest.tfm_partition_name@@ : ALIGN(32)
+    .@@manifest.name@@ : ALIGN(32)
     {
 @!GENERATOR_CONDITIONAL_START!@ @@manifest.tfm_linker_pattern.library_list@@
         @@manifest.tfm_linker_pattern.library_list@@:*(.text*)
@@ -166,13 +166,13 @@
         @@manifest.tfm_linker_pattern.object_list@@(.text*)
         @@manifest.tfm_linker_pattern.object_list@@(.rodata*)
 @!GENERATOR_CONDITIONAL_END!@
-        *(@@manifest.tfm_partition_name@@_ATTR_FN)
+        *(@@manifest.name@@_ATTR_FN)
         . = ALIGN(32);
     } > FLASH
-    Image$$@@manifest.tfm_partition_name@@$$RO$$Base = ADDR(.@@manifest.tfm_partition_name@@);
-    Image$$@@manifest.tfm_partition_name@@$$RO$$Limit = ADDR(.@@manifest.tfm_partition_name@@) + SIZEOF(.@@manifest.tfm_partition_name@@);
-    Image$$@@manifest.tfm_partition_name@@$$Base = ADDR(.@@manifest.tfm_partition_name@@);
-    Image$$@@manifest.tfm_partition_name@@$$Limit = ADDR(.@@manifest.tfm_partition_name@@) + SIZEOF(.@@manifest.tfm_partition_name@@);
+    Image$$@@manifest.name@@$$RO$$Base = ADDR(.@@manifest.name@@);
+    Image$$@@manifest.name@@$$RO$$Limit = ADDR(.@@manifest.name@@) + SIZEOF(.@@manifest.name@@);
+    Image$$@@manifest.name@@$$Base = ADDR(.@@manifest.name@@);
+    Image$$@@manifest.name@@$$Limit = ADDR(.@@manifest.name@@) + SIZEOF(.@@manifest.name@@);
 
 @!GENERATOR_CONDITIONAL_START!@ @@attr.conditional@@
 #endif /* @@attr.conditional@@ */
@@ -311,7 +311,7 @@
 @!GENERATOR_CONDITIONAL_START!@ @@attr.conditional@@
 #ifdef @@attr.conditional@@
 @!GENERATOR_CONDITIONAL_END!@
-    .@@manifest.tfm_partition_name@@_DATA : ALIGN(32)
+    .@@manifest.name@@_DATA : ALIGN(32)
     {
 @!GENERATOR_CONDITIONAL_START!@ @@manifest.tfm_linker_pattern.library_list@@
         @@manifest.tfm_linker_pattern.library_list@@:*(.data*)
@@ -321,10 +321,10 @@
 @!GENERATOR_CONDITIONAL_END!@
         . = ALIGN(32);
     } > RAM AT> FLASH
-    Image$$@@manifest.tfm_partition_name@@_DATA$$RW$$Base = ADDR(.@@manifest.tfm_partition_name@@_DATA);
-    Image$$@@manifest.tfm_partition_name@@_DATA$$RW$$Limit = ADDR(.@@manifest.tfm_partition_name@@_DATA) + SIZEOF(.@@manifest.tfm_partition_name@@_DATA);
+    Image$$@@manifest.name@@_DATA$$RW$$Base = ADDR(.@@manifest.name@@_DATA);
+    Image$$@@manifest.name@@_DATA$$RW$$Limit = ADDR(.@@manifest.name@@_DATA) + SIZEOF(.@@manifest.name@@_DATA);
 
-    .@@manifest.tfm_partition_name@@_BSS : ALIGN(32)
+    .@@manifest.name@@_BSS : ALIGN(32)
     {
 @!GENERATOR_CONDITIONAL_START!@ @@manifest.tfm_linker_pattern.library_list@@
         @@manifest.tfm_linker_pattern.library_list@@:*(.bss*)
@@ -336,15 +336,15 @@
 @!GENERATOR_CONDITIONAL_END!@
         . = ALIGN(32);
     } > RAM AT> FLASH
-    Image$$@@manifest.tfm_partition_name@@_DATA$$ZI$$Base = ADDR(.@@manifest.tfm_partition_name@@_BSS);
-    Image$$@@manifest.tfm_partition_name@@_DATA$$ZI$$Limit = ADDR(.@@manifest.tfm_partition_name@@_BSS) + SIZEOF(.@@manifest.tfm_partition_name@@_BSS);
+    Image$$@@manifest.name@@_DATA$$ZI$$Base = ADDR(.@@manifest.name@@_BSS);
+    Image$$@@manifest.name@@_DATA$$ZI$$Limit = ADDR(.@@manifest.name@@_BSS) + SIZEOF(.@@manifest.name@@_BSS);
 
-    .@@manifest.tfm_partition_name@@_STACK : ALIGN(128)
+    .@@manifest.name@@_STACK : ALIGN(128)
     {
         . += @@manifest.stack_size@@;
     } > RAM AT> FLASH
-    Image$$@@manifest.tfm_partition_name@@_STACK$$ZI$$Base = ADDR(.@@manifest.tfm_partition_name@@_STACK);
-    Image$$@@manifest.tfm_partition_name@@_STACK$$ZI$$Limit = ADDR(.@@manifest.tfm_partition_name@@_STACK) + SIZEOF(.@@manifest.tfm_partition_name@@_STACK);
+    Image$$@@manifest.name@@_STACK$$ZI$$Base = ADDR(.@@manifest.name@@_STACK);
+    Image$$@@manifest.name@@_STACK$$ZI$$Limit = ADDR(.@@manifest.name@@_STACK) + SIZEOF(.@@manifest.name@@_STACK);
 
 @!GENERATOR_CONDITIONAL_START!@ @@attr.conditional@@
 #endif /* @@attr.conditional@@ */
@@ -409,8 +409,8 @@
         . = ALIGN(4);
 
     } > RAM AT> FLASH
-    Image$$TFM_DATA$$RW$$Base = ADDR(.TFM_DATA);
-    Image$$TFM_DATA$$RW$$Limit = ADDR(.TFM_DATA) + SIZEOF(.TFM_DATA);
+    Image$$ER_TFM_DATA$$RW$$Base = ADDR(.TFM_DATA);
+    Image$$ER_TFM_DATA$$RW$$Limit = ADDR(.TFM_DATA) + SIZEOF(.TFM_DATA);
 
     .TFM_BSS : ALIGN(4)
     {
@@ -420,8 +420,11 @@
         . = ALIGN(4);
         __bss_end__ = .;
     } > RAM AT> FLASH
-    Image$$TFM_DATA$$ZI$$Base = ADDR(.TFM_BSS);
-    Image$$TFM_DATA$$ZI$$Limit = ADDR(.TFM_BSS) + SIZEOF(.TFM_BSS);
+    Image$$ER_TFM_DATA$$ZI$$Base = ADDR(.TFM_BSS);
+    Image$$ER_TFM_DATA$$ZI$$Limit = ADDR(.TFM_BSS) + SIZEOF(.TFM_BSS);
+
+    Image$$ER_TFM_DATA$$Base = ADDR(.TFM_DATA);
+    Image$$ER_TFM_DATA$$Limit = ADDR(.TFM_DATA) + SIZEOF(.TFM_DATA) + SIZEOF(.TFM_BSS);
 
     /*
      * Place the CMSE Veneers (containing the SG instruction) after the code, in a
diff --git a/platform/ext/target/mps2/an521/armclang/mps2_an521_s.sct b/platform/ext/target/mps2/an521/armclang/mps2_an521_s.sct
index c01cd10..26aa140 100644
--- a/platform/ext/target/mps2/an521/armclang/mps2_an521_s.sct
+++ b/platform/ext/target/mps2/an521/armclang/mps2_an521_s.sct
@@ -117,6 +117,15 @@
     }
 #endif /* TFM_PARTITION_TEST_SECURE_SERVICES */
 
+#ifdef TFM_PSA_API
+    TFM_SP_IPC_CLIENT_TEST +0 ALIGN 32 {
+        *ipc_client_test.* (+RO)
+    }
+    TFM_SP_IPC_SERVICE_TEST +0 ALIGN 32 {
+        *ipc_service_test.* (+RO)
+    }
+#endif /* TFM_PSA_API */
+
     /* Shared area between BL2 and runtime to exchange data */
     TFM_SHARED_DATA S_DATA_START ALIGN 32 OVERLAY EMPTY BOOT_TFM_SHARED_DATA_SIZE {
     }
@@ -214,6 +223,22 @@
     }
 #endif /* TFM_PARTITION_TEST_SECURE_SERVICES */
 
+#ifdef TFM_PSA_API
+    TFM_SP_IPC_CLIENT_TEST_DATA +0 ALIGN 32 {
+        ipc_client_test.o (+RW +ZI)
+    }
+
+    TFM_SP_IPC_CLIENT_TEST_STACK +0 ALIGN 128 EMPTY 0x1000 {
+    }
+
+    TFM_SP_IPC_SERVICE_TEST_DATA +0 ALIGN 32 {
+        ipc_service_test.o (+RW +ZI)
+    }
+
+    TFM_SP_IPC_SERVICE_TEST_STACK +0 ALIGN 128 EMPTY 0x1000 {
+    }
+#endif /* TFM_PSA_API */
+
 #endif /* TFM_LVL == 1 */
 
     /* This empty, zero long execution region is here to mark the limit address
diff --git a/platform/ext/target/mps2/an521/gcc/mps2_an521_s.ld b/platform/ext/target/mps2/an521/gcc/mps2_an521_s.ld
index ea78e05..06d2181 100644
--- a/platform/ext/target/mps2/an521/gcc/mps2_an521_s.ld
+++ b/platform/ext/target/mps2/an521/gcc/mps2_an521_s.ld
@@ -120,6 +120,16 @@
         LONG (ADDR(.TFM_SP_SECURE_TEST_PARTITION_DATA))
         LONG (SIZEOF(.TFM_SP_SECURE_TEST_PARTITION_DATA))
 #endif /* TFM_PARTITION_TEST_SECURE_SERVICES */
+#ifdef TFM_PSA_API
+        LONG (LOADADDR(.TFM_SP_IPC_SERVICE_TEST_DATA))
+        LONG (ADDR(.TFM_SP_IPC_SERVICE_TEST_DATA))
+        LONG (SIZEOF(.TFM_SP_IPC_SERVICE_TEST_DATA))
+#endif /* TFM_PSA_API */
+#ifdef TFM_PSA_API
+        LONG (LOADADDR(.TFM_SP_IPC_CLIENT_TEST_DATA))
+        LONG (ADDR(.TFM_SP_IPC_CLIENT_TEST_DATA))
+        LONG (SIZEOF(.TFM_SP_IPC_CLIENT_TEST_DATA))
+#endif /* TFM_PSA_API */
         __copy_table_end__ = .;
     } > FLASH
 
@@ -168,6 +178,18 @@
         LONG (ADDR(.TFM_SP_SECURE_TEST_PARTITION_STACK))
         LONG (SIZEOF(.TFM_SP_SECURE_TEST_PARTITION_STACK))
 #endif /* TFM_PARTITION_TEST_SECURE_SERVICES */
+#ifdef TFM_PSA_API
+        LONG (ADDR(.TFM_SP_IPC_SERVICE_TEST_BSS))
+        LONG (SIZEOF(.TFM_SP_IPC_SERVICE_TEST_BSS))
+        LONG (ADDR(.TFM_SP_IPC_SERVICE_TEST_STACK))
+        LONG (SIZEOF(.TFM_SP_IPC_SERVICE_TEST_STACK))
+#endif /* TFM_PSA_API */
+#ifdef TFM_PSA_API
+        LONG (ADDR(.TFM_SP_IPC_CLIENT_TEST_BSS))
+        LONG (SIZEOF(.TFM_SP_IPC_CLIENT_TEST_BSS))
+        LONG (ADDR(.TFM_SP_IPC_CLIENT_TEST_STACK))
+        LONG (SIZEOF(.TFM_SP_IPC_CLIENT_TEST_STACK))
+#endif /* TFM_PSA_API */
         LONG (ADDR(.TFM_UNPRIV_SCRATCH))
         LONG (SIZEOF(.TFM_UNPRIV_SCRATCH))
         __zero_table_end__ = .;
@@ -313,6 +335,34 @@
     Image$$TFM_SP_SECURE_TEST_PARTITION$$Limit = ADDR(.TFM_SP_SECURE_TEST_PARTITION) + SIZEOF(.TFM_SP_SECURE_TEST_PARTITION);
 
 #endif /* TFM_PARTITION_TEST_SECURE_SERVICES */
+#ifdef TFM_PSA_API
+    .TFM_SP_IPC_SERVICE_TEST : ALIGN(32)
+    {
+        *ipc_service_test*:*(.text*)
+        *ipc_service_test*:*(.rodata*)
+        *(TFM_SP_IPC_SERVICE_TEST_ATTR_FN)
+        . = ALIGN(32);
+    } > FLASH
+    Image$$TFM_SP_IPC_SERVICE_TEST$$RO$$Base = ADDR(.TFM_SP_IPC_SERVICE_TEST);
+    Image$$TFM_SP_IPC_SERVICE_TEST$$RO$$Limit = ADDR(.TFM_SP_IPC_SERVICE_TEST) + SIZEOF(.TFM_SP_IPC_SERVICE_TEST);
+    Image$$TFM_SP_IPC_SERVICE_TEST$$Base = ADDR(.TFM_SP_IPC_SERVICE_TEST);
+    Image$$TFM_SP_IPC_SERVICE_TEST$$Limit = ADDR(.TFM_SP_IPC_SERVICE_TEST) + SIZEOF(.TFM_SP_IPC_SERVICE_TEST);
+
+#endif /* TFM_PSA_API */
+#ifdef TFM_PSA_API
+    .TFM_SP_IPC_CLIENT_TEST : ALIGN(32)
+    {
+        *ipc_client_test*:*(.text*)
+        *ipc_client_test*:*(.rodata*)
+        *(TFM_SP_IPC_CLIENT_TEST_ATTR_FN)
+        . = ALIGN(32);
+    } > FLASH
+    Image$$TFM_SP_IPC_CLIENT_TEST$$RO$$Base = ADDR(.TFM_SP_IPC_CLIENT_TEST);
+    Image$$TFM_SP_IPC_CLIENT_TEST$$RO$$Limit = ADDR(.TFM_SP_IPC_CLIENT_TEST) + SIZEOF(.TFM_SP_IPC_CLIENT_TEST);
+    Image$$TFM_SP_IPC_CLIENT_TEST$$Base = ADDR(.TFM_SP_IPC_CLIENT_TEST);
+    Image$$TFM_SP_IPC_CLIENT_TEST$$Limit = ADDR(.TFM_SP_IPC_CLIENT_TEST) + SIZEOF(.TFM_SP_IPC_CLIENT_TEST);
+
+#endif /* TFM_PSA_API */
 
     .ARM.extab :
     {
@@ -661,6 +711,58 @@
     Image$$TFM_SP_SECURE_TEST_PARTITION_STACK$$ZI$$Limit = ADDR(.TFM_SP_SECURE_TEST_PARTITION_STACK) + SIZEOF(.TFM_SP_SECURE_TEST_PARTITION_STACK);
 
 #endif /* TFM_PARTITION_TEST_SECURE_SERVICES */
+#ifdef TFM_PSA_API
+    .TFM_SP_IPC_SERVICE_TEST_DATA : ALIGN(32)
+    {
+        *ipc_service_test*:*(.data*)
+        . = ALIGN(32);
+    } > RAM AT> FLASH
+    Image$$TFM_SP_IPC_SERVICE_TEST_DATA$$RW$$Base = ADDR(.TFM_SP_IPC_SERVICE_TEST_DATA);
+    Image$$TFM_SP_IPC_SERVICE_TEST_DATA$$RW$$Limit = ADDR(.TFM_SP_IPC_SERVICE_TEST_DATA) + SIZEOF(.TFM_SP_IPC_SERVICE_TEST_DATA);
+
+    .TFM_SP_IPC_SERVICE_TEST_BSS : ALIGN(32)
+    {
+        *ipc_service_test*:*(.bss*)
+        *ipc_service_test*:*(COMMON)
+        . = ALIGN(32);
+    } > RAM AT> FLASH
+    Image$$TFM_SP_IPC_SERVICE_TEST_DATA$$ZI$$Base = ADDR(.TFM_SP_IPC_SERVICE_TEST_BSS);
+    Image$$TFM_SP_IPC_SERVICE_TEST_DATA$$ZI$$Limit = ADDR(.TFM_SP_IPC_SERVICE_TEST_BSS) + SIZEOF(.TFM_SP_IPC_SERVICE_TEST_BSS);
+
+    .TFM_SP_IPC_SERVICE_TEST_STACK : ALIGN(128)
+    {
+        . += 0x1000;
+    } > RAM AT> FLASH
+    Image$$TFM_SP_IPC_SERVICE_TEST_STACK$$ZI$$Base = ADDR(.TFM_SP_IPC_SERVICE_TEST_STACK);
+    Image$$TFM_SP_IPC_SERVICE_TEST_STACK$$ZI$$Limit = ADDR(.TFM_SP_IPC_SERVICE_TEST_STACK) + SIZEOF(.TFM_SP_IPC_SERVICE_TEST_STACK);
+
+#endif /* TFM_PSA_API */
+#ifdef TFM_PSA_API
+    .TFM_SP_IPC_CLIENT_TEST_DATA : ALIGN(32)
+    {
+        *ipc_client_test*:*(.data*)
+        . = ALIGN(32);
+    } > RAM AT> FLASH
+    Image$$TFM_SP_IPC_CLIENT_TEST_DATA$$RW$$Base = ADDR(.TFM_SP_IPC_CLIENT_TEST_DATA);
+    Image$$TFM_SP_IPC_CLIENT_TEST_DATA$$RW$$Limit = ADDR(.TFM_SP_IPC_CLIENT_TEST_DATA) + SIZEOF(.TFM_SP_IPC_CLIENT_TEST_DATA);
+
+    .TFM_SP_IPC_CLIENT_TEST_BSS : ALIGN(32)
+    {
+        *ipc_client_test*:*(.bss*)
+        *ipc_client_test*:*(COMMON)
+        . = ALIGN(32);
+    } > RAM AT> FLASH
+    Image$$TFM_SP_IPC_CLIENT_TEST_DATA$$ZI$$Base = ADDR(.TFM_SP_IPC_CLIENT_TEST_BSS);
+    Image$$TFM_SP_IPC_CLIENT_TEST_DATA$$ZI$$Limit = ADDR(.TFM_SP_IPC_CLIENT_TEST_BSS) + SIZEOF(.TFM_SP_IPC_CLIENT_TEST_BSS);
+
+    .TFM_SP_IPC_CLIENT_TEST_STACK : ALIGN(128)
+    {
+        . += 0x1000;
+    } > RAM AT> FLASH
+    Image$$TFM_SP_IPC_CLIENT_TEST_STACK$$ZI$$Base = ADDR(.TFM_SP_IPC_CLIENT_TEST_STACK);
+    Image$$TFM_SP_IPC_CLIENT_TEST_STACK$$ZI$$Limit = ADDR(.TFM_SP_IPC_CLIENT_TEST_STACK) + SIZEOF(.TFM_SP_IPC_CLIENT_TEST_STACK);
+
+#endif /* TFM_PSA_API */
 
     .TFM_SP_SECURE_TEST_PARTITION_DATA : ALIGN(32)
     {
@@ -720,8 +822,8 @@
         . = ALIGN(4);
 
     } > RAM AT> FLASH
-    Image$$TFM_DATA$$RW$$Base = ADDR(.TFM_DATA);
-    Image$$TFM_DATA$$RW$$Limit = ADDR(.TFM_DATA) + SIZEOF(.TFM_DATA);
+    Image$$ER_TFM_DATA$$RW$$Base = ADDR(.TFM_DATA);
+    Image$$ER_TFM_DATA$$RW$$Limit = ADDR(.TFM_DATA) + SIZEOF(.TFM_DATA);
 
     .TFM_BSS : ALIGN(4)
     {
@@ -731,8 +833,11 @@
         . = ALIGN(4);
         __bss_end__ = .;
     } > RAM AT> FLASH
-    Image$$TFM_DATA$$ZI$$Base = ADDR(.TFM_BSS);
-    Image$$TFM_DATA$$ZI$$Limit = ADDR(.TFM_BSS) + SIZEOF(.TFM_BSS);
+    Image$$ER_TFM_DATA$$ZI$$Base = ADDR(.TFM_BSS);
+    Image$$ER_TFM_DATA$$ZI$$Limit = ADDR(.TFM_BSS) + SIZEOF(.TFM_BSS);
+
+    Image$$ER_TFM_DATA$$Base = ADDR(.TFM_DATA);
+    Image$$ER_TFM_DATA$$Limit = ADDR(.TFM_DATA) + SIZEOF(.TFM_DATA) + SIZEOF(.TFM_BSS);
 
     /*
      * Place the CMSE Veneers (containing the SG instruction) after the code, in a
diff --git a/platform/ext/target/mps2/an521/gcc/mps2_an521_s.ld.template b/platform/ext/target/mps2/an521/gcc/mps2_an521_s.ld.template
index 704d7a7..f1689d3 100644
--- a/platform/ext/target/mps2/an521/gcc/mps2_an521_s.ld.template
+++ b/platform/ext/target/mps2/an521/gcc/mps2_an521_s.ld.template
@@ -94,9 +94,9 @@
 @!GENERATOR_CONDITIONAL_START!@ @@attr.conditional@@
 #ifdef @@attr.conditional@@
 @!GENERATOR_CONDITIONAL_END!@
-        LONG (LOADADDR(.@@manifest.tfm_partition_name@@_DATA))
-        LONG (ADDR(.@@manifest.tfm_partition_name@@_DATA))
-        LONG (SIZEOF(.@@manifest.tfm_partition_name@@_DATA))
+        LONG (LOADADDR(.@@manifest.name@@_DATA))
+        LONG (ADDR(.@@manifest.name@@_DATA))
+        LONG (SIZEOF(.@@manifest.name@@_DATA))
 @!GENERATOR_CONDITIONAL_START!@ @@attr.conditional@@
 #endif /* @@attr.conditional@@ */
 @!GENERATOR_CONDITIONAL_END!@
@@ -115,10 +115,10 @@
 @!GENERATOR_CONDITIONAL_START!@ @@attr.conditional@@
 #ifdef @@attr.conditional@@
 @!GENERATOR_CONDITIONAL_END!@
-        LONG (ADDR(.@@manifest.tfm_partition_name@@_BSS))
-        LONG (SIZEOF(.@@manifest.tfm_partition_name@@_BSS))
-        LONG (ADDR(.@@manifest.tfm_partition_name@@_STACK))
-        LONG (SIZEOF(.@@manifest.tfm_partition_name@@_STACK))
+        LONG (ADDR(.@@manifest.name@@_BSS))
+        LONG (SIZEOF(.@@manifest.name@@_BSS))
+        LONG (ADDR(.@@manifest.name@@_STACK))
+        LONG (SIZEOF(.@@manifest.name@@_STACK))
 @!GENERATOR_CONDITIONAL_START!@ @@attr.conditional@@
 #endif /* @@attr.conditional@@ */
 @!GENERATOR_CONDITIONAL_END!@
@@ -156,7 +156,7 @@
 @!GENERATOR_CONDITIONAL_START!@ @@attr.conditional@@
 #ifdef @@attr.conditional@@
 @!GENERATOR_CONDITIONAL_END!@
-    .@@manifest.tfm_partition_name@@ : ALIGN(32)
+    .@@manifest.name@@ : ALIGN(32)
     {
 @!GENERATOR_CONDITIONAL_START!@ @@manifest.tfm_linker_pattern.library_list@@
         @@manifest.tfm_linker_pattern.library_list@@:*(.text*)
@@ -166,13 +166,13 @@
         @@manifest.tfm_linker_pattern.object_list@@(.text*)
         @@manifest.tfm_linker_pattern.object_list@@(.rodata*)
 @!GENERATOR_CONDITIONAL_END!@
-        *(@@manifest.tfm_partition_name@@_ATTR_FN)
+        *(@@manifest.name@@_ATTR_FN)
         . = ALIGN(32);
     } > FLASH
-    Image$$@@manifest.tfm_partition_name@@$$RO$$Base = ADDR(.@@manifest.tfm_partition_name@@);
-    Image$$@@manifest.tfm_partition_name@@$$RO$$Limit = ADDR(.@@manifest.tfm_partition_name@@) + SIZEOF(.@@manifest.tfm_partition_name@@);
-    Image$$@@manifest.tfm_partition_name@@$$Base = ADDR(.@@manifest.tfm_partition_name@@);
-    Image$$@@manifest.tfm_partition_name@@$$Limit = ADDR(.@@manifest.tfm_partition_name@@) + SIZEOF(.@@manifest.tfm_partition_name@@);
+    Image$$@@manifest.name@@$$RO$$Base = ADDR(.@@manifest.name@@);
+    Image$$@@manifest.name@@$$RO$$Limit = ADDR(.@@manifest.name@@) + SIZEOF(.@@manifest.name@@);
+    Image$$@@manifest.name@@$$Base = ADDR(.@@manifest.name@@);
+    Image$$@@manifest.name@@$$Limit = ADDR(.@@manifest.name@@) + SIZEOF(.@@manifest.name@@);
 
 @!GENERATOR_CONDITIONAL_START!@ @@attr.conditional@@
 #endif /* @@attr.conditional@@ */
@@ -311,7 +311,7 @@
 @!GENERATOR_CONDITIONAL_START!@ @@attr.conditional@@
 #ifdef @@attr.conditional@@
 @!GENERATOR_CONDITIONAL_END!@
-    .@@manifest.tfm_partition_name@@_DATA : ALIGN(32)
+    .@@manifest.name@@_DATA : ALIGN(32)
     {
 @!GENERATOR_CONDITIONAL_START!@ @@manifest.tfm_linker_pattern.library_list@@
         @@manifest.tfm_linker_pattern.library_list@@:*(.data*)
@@ -321,10 +321,10 @@
 @!GENERATOR_CONDITIONAL_END!@
         . = ALIGN(32);
     } > RAM AT> FLASH
-    Image$$@@manifest.tfm_partition_name@@_DATA$$RW$$Base = ADDR(.@@manifest.tfm_partition_name@@_DATA);
-    Image$$@@manifest.tfm_partition_name@@_DATA$$RW$$Limit = ADDR(.@@manifest.tfm_partition_name@@_DATA) + SIZEOF(.@@manifest.tfm_partition_name@@_DATA);
+    Image$$@@manifest.name@@_DATA$$RW$$Base = ADDR(.@@manifest.name@@_DATA);
+    Image$$@@manifest.name@@_DATA$$RW$$Limit = ADDR(.@@manifest.name@@_DATA) + SIZEOF(.@@manifest.name@@_DATA);
 
-    .@@manifest.tfm_partition_name@@_BSS : ALIGN(32)
+    .@@manifest.name@@_BSS : ALIGN(32)
     {
 @!GENERATOR_CONDITIONAL_START!@ @@manifest.tfm_linker_pattern.library_list@@
         @@manifest.tfm_linker_pattern.library_list@@:*(.bss*)
@@ -336,15 +336,15 @@
 @!GENERATOR_CONDITIONAL_END!@
         . = ALIGN(32);
     } > RAM AT> FLASH
-    Image$$@@manifest.tfm_partition_name@@_DATA$$ZI$$Base = ADDR(.@@manifest.tfm_partition_name@@_BSS);
-    Image$$@@manifest.tfm_partition_name@@_DATA$$ZI$$Limit = ADDR(.@@manifest.tfm_partition_name@@_BSS) + SIZEOF(.@@manifest.tfm_partition_name@@_BSS);
+    Image$$@@manifest.name@@_DATA$$ZI$$Base = ADDR(.@@manifest.name@@_BSS);
+    Image$$@@manifest.name@@_DATA$$ZI$$Limit = ADDR(.@@manifest.name@@_BSS) + SIZEOF(.@@manifest.name@@_BSS);
 
-    .@@manifest.tfm_partition_name@@_STACK : ALIGN(128)
+    .@@manifest.name@@_STACK : ALIGN(128)
     {
         . += @@manifest.stack_size@@;
     } > RAM AT> FLASH
-    Image$$@@manifest.tfm_partition_name@@_STACK$$ZI$$Base = ADDR(.@@manifest.tfm_partition_name@@_STACK);
-    Image$$@@manifest.tfm_partition_name@@_STACK$$ZI$$Limit = ADDR(.@@manifest.tfm_partition_name@@_STACK) + SIZEOF(.@@manifest.tfm_partition_name@@_STACK);
+    Image$$@@manifest.name@@_STACK$$ZI$$Base = ADDR(.@@manifest.name@@_STACK);
+    Image$$@@manifest.name@@_STACK$$ZI$$Limit = ADDR(.@@manifest.name@@_STACK) + SIZEOF(.@@manifest.name@@_STACK);
 
 @!GENERATOR_CONDITIONAL_START!@ @@attr.conditional@@
 #endif /* @@attr.conditional@@ */
@@ -409,8 +409,8 @@
         . = ALIGN(4);
 
     } > RAM AT> FLASH
-    Image$$TFM_DATA$$RW$$Base = ADDR(.TFM_DATA);
-    Image$$TFM_DATA$$RW$$Limit = ADDR(.TFM_DATA) + SIZEOF(.TFM_DATA);
+    Image$$ER_TFM_DATA$$RW$$Base = ADDR(.TFM_DATA);
+    Image$$ER_TFM_DATA$$RW$$Limit = ADDR(.TFM_DATA) + SIZEOF(.TFM_DATA);
 
     .TFM_BSS : ALIGN(4)
     {
@@ -420,8 +420,11 @@
         . = ALIGN(4);
         __bss_end__ = .;
     } > RAM AT> FLASH
-    Image$$TFM_DATA$$ZI$$Base = ADDR(.TFM_BSS);
-    Image$$TFM_DATA$$ZI$$Limit = ADDR(.TFM_BSS) + SIZEOF(.TFM_BSS);
+    Image$$ER_TFM_DATA$$ZI$$Base = ADDR(.TFM_BSS);
+    Image$$ER_TFM_DATA$$ZI$$Limit = ADDR(.TFM_BSS) + SIZEOF(.TFM_BSS);
+
+    Image$$ER_TFM_DATA$$Base = ADDR(.TFM_DATA);
+    Image$$ER_TFM_DATA$$Limit = ADDR(.TFM_DATA) + SIZEOF(.TFM_DATA) + SIZEOF(.TFM_BSS);
 
     /*
      * Place the CMSE Veneers (containing the SG instruction) after the code, in a
diff --git a/platform/ext/target/musca_a/Device/Source/gcc/musca_s.ld b/platform/ext/target/musca_a/Device/Source/gcc/musca_s.ld
index 61bb849..5231947 100644
--- a/platform/ext/target/musca_a/Device/Source/gcc/musca_s.ld
+++ b/platform/ext/target/musca_a/Device/Source/gcc/musca_s.ld
@@ -120,6 +120,16 @@
         LONG (ADDR(.TFM_SP_SECURE_TEST_PARTITION_DATA))
         LONG (SIZEOF(.TFM_SP_SECURE_TEST_PARTITION_DATA))
 #endif /* TFM_PARTITION_TEST_SECURE_SERVICES */
+#ifdef TFM_PSA_API
+        LONG (LOADADDR(.TFM_SP_IPC_SERVICE_TEST_DATA))
+        LONG (ADDR(.TFM_SP_IPC_SERVICE_TEST_DATA))
+        LONG (SIZEOF(.TFM_SP_IPC_SERVICE_TEST_DATA))
+#endif /* TFM_PSA_API */
+#ifdef TFM_PSA_API
+        LONG (LOADADDR(.TFM_SP_IPC_CLIENT_TEST_DATA))
+        LONG (ADDR(.TFM_SP_IPC_CLIENT_TEST_DATA))
+        LONG (SIZEOF(.TFM_SP_IPC_CLIENT_TEST_DATA))
+#endif /* TFM_PSA_API */
         __copy_table_end__ = .;
     } > FLASH
 
@@ -168,6 +178,18 @@
         LONG (ADDR(.TFM_SP_SECURE_TEST_PARTITION_STACK))
         LONG (SIZEOF(.TFM_SP_SECURE_TEST_PARTITION_STACK))
 #endif /* TFM_PARTITION_TEST_SECURE_SERVICES */
+#ifdef TFM_PSA_API
+        LONG (ADDR(.TFM_SP_IPC_SERVICE_TEST_BSS))
+        LONG (SIZEOF(.TFM_SP_IPC_SERVICE_TEST_BSS))
+        LONG (ADDR(.TFM_SP_IPC_SERVICE_TEST_STACK))
+        LONG (SIZEOF(.TFM_SP_IPC_SERVICE_TEST_STACK))
+#endif /* TFM_PSA_API */
+#ifdef TFM_PSA_API
+        LONG (ADDR(.TFM_SP_IPC_CLIENT_TEST_BSS))
+        LONG (SIZEOF(.TFM_SP_IPC_CLIENT_TEST_BSS))
+        LONG (ADDR(.TFM_SP_IPC_CLIENT_TEST_STACK))
+        LONG (SIZEOF(.TFM_SP_IPC_CLIENT_TEST_STACK))
+#endif /* TFM_PSA_API */
         LONG (ADDR(.TFM_UNPRIV_SCRATCH))
         LONG (SIZEOF(.TFM_UNPRIV_SCRATCH))
         __zero_table_end__ = .;
@@ -313,6 +335,34 @@
     Image$$TFM_SP_SECURE_TEST_PARTITION$$Limit = ADDR(.TFM_SP_SECURE_TEST_PARTITION) + SIZEOF(.TFM_SP_SECURE_TEST_PARTITION);
 
 #endif /* TFM_PARTITION_TEST_SECURE_SERVICES */
+#ifdef TFM_PSA_API
+    .TFM_SP_IPC_SERVICE_TEST : ALIGN(32)
+    {
+        *ipc_service_test*:*(.text*)
+        *ipc_service_test*:*(.rodata*)
+        *(TFM_SP_IPC_SERVICE_TEST_ATTR_FN)
+        . = ALIGN(32);
+    } > FLASH
+    Image$$TFM_SP_IPC_SERVICE_TEST$$RO$$Base = ADDR(.TFM_SP_IPC_SERVICE_TEST);
+    Image$$TFM_SP_IPC_SERVICE_TEST$$RO$$Limit = ADDR(.TFM_SP_IPC_SERVICE_TEST) + SIZEOF(.TFM_SP_IPC_SERVICE_TEST);
+    Image$$TFM_SP_IPC_SERVICE_TEST$$Base = ADDR(.TFM_SP_IPC_SERVICE_TEST);
+    Image$$TFM_SP_IPC_SERVICE_TEST$$Limit = ADDR(.TFM_SP_IPC_SERVICE_TEST) + SIZEOF(.TFM_SP_IPC_SERVICE_TEST);
+
+#endif /* TFM_PSA_API */
+#ifdef TFM_PSA_API
+    .TFM_SP_IPC_CLIENT_TEST : ALIGN(32)
+    {
+        *ipc_client_test*:*(.text*)
+        *ipc_client_test*:*(.rodata*)
+        *(TFM_SP_IPC_CLIENT_TEST_ATTR_FN)
+        . = ALIGN(32);
+    } > FLASH
+    Image$$TFM_SP_IPC_CLIENT_TEST$$RO$$Base = ADDR(.TFM_SP_IPC_CLIENT_TEST);
+    Image$$TFM_SP_IPC_CLIENT_TEST$$RO$$Limit = ADDR(.TFM_SP_IPC_CLIENT_TEST) + SIZEOF(.TFM_SP_IPC_CLIENT_TEST);
+    Image$$TFM_SP_IPC_CLIENT_TEST$$Base = ADDR(.TFM_SP_IPC_CLIENT_TEST);
+    Image$$TFM_SP_IPC_CLIENT_TEST$$Limit = ADDR(.TFM_SP_IPC_CLIENT_TEST) + SIZEOF(.TFM_SP_IPC_CLIENT_TEST);
+
+#endif /* TFM_PSA_API */
 
     .ARM.extab :
     {
@@ -661,6 +711,58 @@
     Image$$TFM_SP_SECURE_TEST_PARTITION_STACK$$ZI$$Limit = ADDR(.TFM_SP_SECURE_TEST_PARTITION_STACK) + SIZEOF(.TFM_SP_SECURE_TEST_PARTITION_STACK);
 
 #endif /* TFM_PARTITION_TEST_SECURE_SERVICES */
+#ifdef TFM_PSA_API
+    .TFM_SP_IPC_SERVICE_TEST_DATA : ALIGN(32)
+    {
+        *ipc_service_test*:*(.data*)
+        . = ALIGN(32);
+    } > RAM AT> FLASH
+    Image$$TFM_SP_IPC_SERVICE_TEST_DATA$$RW$$Base = ADDR(.TFM_SP_IPC_SERVICE_TEST_DATA);
+    Image$$TFM_SP_IPC_SERVICE_TEST_DATA$$RW$$Limit = ADDR(.TFM_SP_IPC_SERVICE_TEST_DATA) + SIZEOF(.TFM_SP_IPC_SERVICE_TEST_DATA);
+
+    .TFM_SP_IPC_SERVICE_TEST_BSS : ALIGN(32)
+    {
+        *ipc_service_test*:*(.bss*)
+        *ipc_service_test*:*(COMMON)
+        . = ALIGN(32);
+    } > RAM AT> FLASH
+    Image$$TFM_SP_IPC_SERVICE_TEST_DATA$$ZI$$Base = ADDR(.TFM_SP_IPC_SERVICE_TEST_BSS);
+    Image$$TFM_SP_IPC_SERVICE_TEST_DATA$$ZI$$Limit = ADDR(.TFM_SP_IPC_SERVICE_TEST_BSS) + SIZEOF(.TFM_SP_IPC_SERVICE_TEST_BSS);
+
+    .TFM_SP_IPC_SERVICE_TEST_STACK : ALIGN(128)
+    {
+        . += 0x1000;
+    } > RAM AT> FLASH
+    Image$$TFM_SP_IPC_SERVICE_TEST_STACK$$ZI$$Base = ADDR(.TFM_SP_IPC_SERVICE_TEST_STACK);
+    Image$$TFM_SP_IPC_SERVICE_TEST_STACK$$ZI$$Limit = ADDR(.TFM_SP_IPC_SERVICE_TEST_STACK) + SIZEOF(.TFM_SP_IPC_SERVICE_TEST_STACK);
+
+#endif /* TFM_PSA_API */
+#ifdef TFM_PSA_API
+    .TFM_SP_IPC_CLIENT_TEST_DATA : ALIGN(32)
+    {
+        *ipc_client_test*:*(.data*)
+        . = ALIGN(32);
+    } > RAM AT> FLASH
+    Image$$TFM_SP_IPC_CLIENT_TEST_DATA$$RW$$Base = ADDR(.TFM_SP_IPC_CLIENT_TEST_DATA);
+    Image$$TFM_SP_IPC_CLIENT_TEST_DATA$$RW$$Limit = ADDR(.TFM_SP_IPC_CLIENT_TEST_DATA) + SIZEOF(.TFM_SP_IPC_CLIENT_TEST_DATA);
+
+    .TFM_SP_IPC_CLIENT_TEST_BSS : ALIGN(32)
+    {
+        *ipc_client_test*:*(.bss*)
+        *ipc_client_test*:*(COMMON)
+        . = ALIGN(32);
+    } > RAM AT> FLASH
+    Image$$TFM_SP_IPC_CLIENT_TEST_DATA$$ZI$$Base = ADDR(.TFM_SP_IPC_CLIENT_TEST_BSS);
+    Image$$TFM_SP_IPC_CLIENT_TEST_DATA$$ZI$$Limit = ADDR(.TFM_SP_IPC_CLIENT_TEST_BSS) + SIZEOF(.TFM_SP_IPC_CLIENT_TEST_BSS);
+
+    .TFM_SP_IPC_CLIENT_TEST_STACK : ALIGN(128)
+    {
+        . += 0x1000;
+    } > RAM AT> FLASH
+    Image$$TFM_SP_IPC_CLIENT_TEST_STACK$$ZI$$Base = ADDR(.TFM_SP_IPC_CLIENT_TEST_STACK);
+    Image$$TFM_SP_IPC_CLIENT_TEST_STACK$$ZI$$Limit = ADDR(.TFM_SP_IPC_CLIENT_TEST_STACK) + SIZEOF(.TFM_SP_IPC_CLIENT_TEST_STACK);
+
+#endif /* TFM_PSA_API */
 
     .TFM_SP_SECURE_TEST_PARTITION_DATA : ALIGN(32)
     {
@@ -720,8 +822,8 @@
         . = ALIGN(4);
 
     } > RAM AT> FLASH
-    Image$$TFM_DATA$$RW$$Base = ADDR(.TFM_DATA);
-    Image$$TFM_DATA$$RW$$Limit = ADDR(.TFM_DATA) + SIZEOF(.TFM_DATA);
+    Image$$ER_TFM_DATA$$RW$$Base = ADDR(.TFM_DATA);
+    Image$$ER_TFM_DATA$$RW$$Limit = ADDR(.TFM_DATA) + SIZEOF(.TFM_DATA);
 
     .TFM_BSS : ALIGN(4)
     {
@@ -731,8 +833,11 @@
         . = ALIGN(4);
         __bss_end__ = .;
     } > RAM AT> FLASH
-    Image$$TFM_DATA$$ZI$$Base = ADDR(.TFM_BSS);
-    Image$$TFM_DATA$$ZI$$Limit = ADDR(.TFM_BSS) + SIZEOF(.TFM_BSS);
+    Image$$ER_TFM_DATA$$ZI$$Base = ADDR(.TFM_BSS);
+    Image$$ER_TFM_DATA$$ZI$$Limit = ADDR(.TFM_BSS) + SIZEOF(.TFM_BSS);
+
+    Image$$ER_TFM_DATA$$Base = ADDR(.TFM_DATA);
+    Image$$ER_TFM_DATA$$Limit = ADDR(.TFM_DATA) + SIZEOF(.TFM_DATA) + SIZEOF(.TFM_BSS);
 
     /*
      * Place the CMSE Veneers (containing the SG instruction) after the code, in a
diff --git a/platform/ext/target/musca_a/Device/Source/gcc/musca_s.ld.template b/platform/ext/target/musca_a/Device/Source/gcc/musca_s.ld.template
index 43c9372..6a3ac44 100644
--- a/platform/ext/target/musca_a/Device/Source/gcc/musca_s.ld.template
+++ b/platform/ext/target/musca_a/Device/Source/gcc/musca_s.ld.template
@@ -94,9 +94,9 @@
 @!GENERATOR_CONDITIONAL_START!@ @@attr.conditional@@
 #ifdef @@attr.conditional@@
 @!GENERATOR_CONDITIONAL_END!@
-        LONG (LOADADDR(.@@manifest.tfm_partition_name@@_DATA))
-        LONG (ADDR(.@@manifest.tfm_partition_name@@_DATA))
-        LONG (SIZEOF(.@@manifest.tfm_partition_name@@_DATA))
+        LONG (LOADADDR(.@@manifest.name@@_DATA))
+        LONG (ADDR(.@@manifest.name@@_DATA))
+        LONG (SIZEOF(.@@manifest.name@@_DATA))
 @!GENERATOR_CONDITIONAL_START!@ @@attr.conditional@@
 #endif /* @@attr.conditional@@ */
 @!GENERATOR_CONDITIONAL_END!@
@@ -115,10 +115,10 @@
 @!GENERATOR_CONDITIONAL_START!@ @@attr.conditional@@
 #ifdef @@attr.conditional@@
 @!GENERATOR_CONDITIONAL_END!@
-        LONG (ADDR(.@@manifest.tfm_partition_name@@_BSS))
-        LONG (SIZEOF(.@@manifest.tfm_partition_name@@_BSS))
-        LONG (ADDR(.@@manifest.tfm_partition_name@@_STACK))
-        LONG (SIZEOF(.@@manifest.tfm_partition_name@@_STACK))
+        LONG (ADDR(.@@manifest.name@@_BSS))
+        LONG (SIZEOF(.@@manifest.name@@_BSS))
+        LONG (ADDR(.@@manifest.name@@_STACK))
+        LONG (SIZEOF(.@@manifest.name@@_STACK))
 @!GENERATOR_CONDITIONAL_START!@ @@attr.conditional@@
 #endif /* @@attr.conditional@@ */
 @!GENERATOR_CONDITIONAL_END!@
@@ -156,7 +156,7 @@
 @!GENERATOR_CONDITIONAL_START!@ @@attr.conditional@@
 #ifdef @@attr.conditional@@
 @!GENERATOR_CONDITIONAL_END!@
-    .@@manifest.tfm_partition_name@@ : ALIGN(32)
+    .@@manifest.name@@ : ALIGN(32)
     {
 @!GENERATOR_CONDITIONAL_START!@ @@manifest.tfm_linker_pattern.library_list@@
         @@manifest.tfm_linker_pattern.library_list@@:*(.text*)
@@ -166,13 +166,13 @@
         @@manifest.tfm_linker_pattern.object_list@@(.text*)
         @@manifest.tfm_linker_pattern.object_list@@(.rodata*)
 @!GENERATOR_CONDITIONAL_END!@
-        *(@@manifest.tfm_partition_name@@_ATTR_FN)
+        *(@@manifest.name@@_ATTR_FN)
         . = ALIGN(32);
     } > FLASH
-    Image$$@@manifest.tfm_partition_name@@$$RO$$Base = ADDR(.@@manifest.tfm_partition_name@@);
-    Image$$@@manifest.tfm_partition_name@@$$RO$$Limit = ADDR(.@@manifest.tfm_partition_name@@) + SIZEOF(.@@manifest.tfm_partition_name@@);
-    Image$$@@manifest.tfm_partition_name@@$$Base = ADDR(.@@manifest.tfm_partition_name@@);
-    Image$$@@manifest.tfm_partition_name@@$$Limit = ADDR(.@@manifest.tfm_partition_name@@) + SIZEOF(.@@manifest.tfm_partition_name@@);
+    Image$$@@manifest.name@@$$RO$$Base = ADDR(.@@manifest.name@@);
+    Image$$@@manifest.name@@$$RO$$Limit = ADDR(.@@manifest.name@@) + SIZEOF(.@@manifest.name@@);
+    Image$$@@manifest.name@@$$Base = ADDR(.@@manifest.name@@);
+    Image$$@@manifest.name@@$$Limit = ADDR(.@@manifest.name@@) + SIZEOF(.@@manifest.name@@);
 
 @!GENERATOR_CONDITIONAL_START!@ @@attr.conditional@@
 #endif /* @@attr.conditional@@ */
@@ -311,7 +311,7 @@
 @!GENERATOR_CONDITIONAL_START!@ @@attr.conditional@@
 #ifdef @@attr.conditional@@
 @!GENERATOR_CONDITIONAL_END!@
-    .@@manifest.tfm_partition_name@@_DATA : ALIGN(32)
+    .@@manifest.name@@_DATA : ALIGN(32)
     {
 @!GENERATOR_CONDITIONAL_START!@ @@manifest.tfm_linker_pattern.library_list@@
         @@manifest.tfm_linker_pattern.library_list@@:*(.data*)
@@ -321,10 +321,10 @@
 @!GENERATOR_CONDITIONAL_END!@
         . = ALIGN(32);
     } > RAM AT> FLASH
-    Image$$@@manifest.tfm_partition_name@@_DATA$$RW$$Base = ADDR(.@@manifest.tfm_partition_name@@_DATA);
-    Image$$@@manifest.tfm_partition_name@@_DATA$$RW$$Limit = ADDR(.@@manifest.tfm_partition_name@@_DATA) + SIZEOF(.@@manifest.tfm_partition_name@@_DATA);
+    Image$$@@manifest.name@@_DATA$$RW$$Base = ADDR(.@@manifest.name@@_DATA);
+    Image$$@@manifest.name@@_DATA$$RW$$Limit = ADDR(.@@manifest.name@@_DATA) + SIZEOF(.@@manifest.name@@_DATA);
 
-    .@@manifest.tfm_partition_name@@_BSS : ALIGN(32)
+    .@@manifest.name@@_BSS : ALIGN(32)
     {
 @!GENERATOR_CONDITIONAL_START!@ @@manifest.tfm_linker_pattern.library_list@@
         @@manifest.tfm_linker_pattern.library_list@@:*(.bss*)
@@ -336,15 +336,15 @@
 @!GENERATOR_CONDITIONAL_END!@
         . = ALIGN(32);
     } > RAM AT> FLASH
-    Image$$@@manifest.tfm_partition_name@@_DATA$$ZI$$Base = ADDR(.@@manifest.tfm_partition_name@@_BSS);
-    Image$$@@manifest.tfm_partition_name@@_DATA$$ZI$$Limit = ADDR(.@@manifest.tfm_partition_name@@_BSS) + SIZEOF(.@@manifest.tfm_partition_name@@_BSS);
+    Image$$@@manifest.name@@_DATA$$ZI$$Base = ADDR(.@@manifest.name@@_BSS);
+    Image$$@@manifest.name@@_DATA$$ZI$$Limit = ADDR(.@@manifest.name@@_BSS) + SIZEOF(.@@manifest.name@@_BSS);
 
-    .@@manifest.tfm_partition_name@@_STACK : ALIGN(128)
+    .@@manifest.name@@_STACK : ALIGN(128)
     {
         . += @@manifest.stack_size@@;
     } > RAM AT> FLASH
-    Image$$@@manifest.tfm_partition_name@@_STACK$$ZI$$Base = ADDR(.@@manifest.tfm_partition_name@@_STACK);
-    Image$$@@manifest.tfm_partition_name@@_STACK$$ZI$$Limit = ADDR(.@@manifest.tfm_partition_name@@_STACK) + SIZEOF(.@@manifest.tfm_partition_name@@_STACK);
+    Image$$@@manifest.name@@_STACK$$ZI$$Base = ADDR(.@@manifest.name@@_STACK);
+    Image$$@@manifest.name@@_STACK$$ZI$$Limit = ADDR(.@@manifest.name@@_STACK) + SIZEOF(.@@manifest.name@@_STACK);
 
 @!GENERATOR_CONDITIONAL_START!@ @@attr.conditional@@
 #endif /* @@attr.conditional@@ */
@@ -409,8 +409,8 @@
         . = ALIGN(4);
 
     } > RAM AT> FLASH
-    Image$$TFM_DATA$$RW$$Base = ADDR(.TFM_DATA);
-    Image$$TFM_DATA$$RW$$Limit = ADDR(.TFM_DATA) + SIZEOF(.TFM_DATA);
+    Image$$ER_TFM_DATA$$RW$$Base = ADDR(.TFM_DATA);
+    Image$$ER_TFM_DATA$$RW$$Limit = ADDR(.TFM_DATA) + SIZEOF(.TFM_DATA);
 
     .TFM_BSS : ALIGN(4)
     {
@@ -420,8 +420,11 @@
         . = ALIGN(4);
         __bss_end__ = .;
     } > RAM AT> FLASH
-    Image$$TFM_DATA$$ZI$$Base = ADDR(.TFM_BSS);
-    Image$$TFM_DATA$$ZI$$Limit = ADDR(.TFM_BSS) + SIZEOF(.TFM_BSS);
+    Image$$ER_TFM_DATA$$ZI$$Base = ADDR(.TFM_BSS);
+    Image$$ER_TFM_DATA$$ZI$$Limit = ADDR(.TFM_BSS) + SIZEOF(.TFM_BSS);
+
+    Image$$ER_TFM_DATA$$Base = ADDR(.TFM_DATA);
+    Image$$ER_TFM_DATA$$Limit = ADDR(.TFM_DATA) + SIZEOF(.TFM_DATA) + SIZEOF(.TFM_BSS);
 
     /*
      * Place the CMSE Veneers (containing the SG instruction) after the code, in a
diff --git a/platform/ext/target/musca_b1/Device/Source/gcc/musca_s.ld b/platform/ext/target/musca_b1/Device/Source/gcc/musca_s.ld
index 13b4a15..928c952 100644
--- a/platform/ext/target/musca_b1/Device/Source/gcc/musca_s.ld
+++ b/platform/ext/target/musca_b1/Device/Source/gcc/musca_s.ld
@@ -120,6 +120,16 @@
         LONG (ADDR(.TFM_SP_SECURE_TEST_PARTITION_DATA))
         LONG (SIZEOF(.TFM_SP_SECURE_TEST_PARTITION_DATA))
 #endif /* TFM_PARTITION_TEST_SECURE_SERVICES */
+#ifdef TFM_PSA_API
+        LONG (LOADADDR(.TFM_SP_IPC_SERVICE_TEST_DATA))
+        LONG (ADDR(.TFM_SP_IPC_SERVICE_TEST_DATA))
+        LONG (SIZEOF(.TFM_SP_IPC_SERVICE_TEST_DATA))
+#endif /* TFM_PSA_API */
+#ifdef TFM_PSA_API
+        LONG (LOADADDR(.TFM_SP_IPC_CLIENT_TEST_DATA))
+        LONG (ADDR(.TFM_SP_IPC_CLIENT_TEST_DATA))
+        LONG (SIZEOF(.TFM_SP_IPC_CLIENT_TEST_DATA))
+#endif /* TFM_PSA_API */
         __copy_table_end__ = .;
     } > FLASH
 
@@ -168,6 +178,18 @@
         LONG (ADDR(.TFM_SP_SECURE_TEST_PARTITION_STACK))
         LONG (SIZEOF(.TFM_SP_SECURE_TEST_PARTITION_STACK))
 #endif /* TFM_PARTITION_TEST_SECURE_SERVICES */
+#ifdef TFM_PSA_API
+        LONG (ADDR(.TFM_SP_IPC_SERVICE_TEST_BSS))
+        LONG (SIZEOF(.TFM_SP_IPC_SERVICE_TEST_BSS))
+        LONG (ADDR(.TFM_SP_IPC_SERVICE_TEST_STACK))
+        LONG (SIZEOF(.TFM_SP_IPC_SERVICE_TEST_STACK))
+#endif /* TFM_PSA_API */
+#ifdef TFM_PSA_API
+        LONG (ADDR(.TFM_SP_IPC_CLIENT_TEST_BSS))
+        LONG (SIZEOF(.TFM_SP_IPC_CLIENT_TEST_BSS))
+        LONG (ADDR(.TFM_SP_IPC_CLIENT_TEST_STACK))
+        LONG (SIZEOF(.TFM_SP_IPC_CLIENT_TEST_STACK))
+#endif /* TFM_PSA_API */
         LONG (ADDR(.TFM_UNPRIV_SCRATCH))
         LONG (SIZEOF(.TFM_UNPRIV_SCRATCH))
         __zero_table_end__ = .;
@@ -313,6 +335,34 @@
     Image$$TFM_SP_SECURE_TEST_PARTITION$$Limit = ADDR(.TFM_SP_SECURE_TEST_PARTITION) + SIZEOF(.TFM_SP_SECURE_TEST_PARTITION);
 
 #endif /* TFM_PARTITION_TEST_SECURE_SERVICES */
+#ifdef TFM_PSA_API
+    .TFM_SP_IPC_SERVICE_TEST : ALIGN(32)
+    {
+        *ipc_service_test*:*(.text*)
+        *ipc_service_test*:*(.rodata*)
+        *(TFM_SP_IPC_SERVICE_TEST_ATTR_FN)
+        . = ALIGN(32);
+    } > FLASH
+    Image$$TFM_SP_IPC_SERVICE_TEST$$RO$$Base = ADDR(.TFM_SP_IPC_SERVICE_TEST);
+    Image$$TFM_SP_IPC_SERVICE_TEST$$RO$$Limit = ADDR(.TFM_SP_IPC_SERVICE_TEST) + SIZEOF(.TFM_SP_IPC_SERVICE_TEST);
+    Image$$TFM_SP_IPC_SERVICE_TEST$$Base = ADDR(.TFM_SP_IPC_SERVICE_TEST);
+    Image$$TFM_SP_IPC_SERVICE_TEST$$Limit = ADDR(.TFM_SP_IPC_SERVICE_TEST) + SIZEOF(.TFM_SP_IPC_SERVICE_TEST);
+
+#endif /* TFM_PSA_API */
+#ifdef TFM_PSA_API
+    .TFM_SP_IPC_CLIENT_TEST : ALIGN(32)
+    {
+        *ipc_client_test*:*(.text*)
+        *ipc_client_test*:*(.rodata*)
+        *(TFM_SP_IPC_CLIENT_TEST_ATTR_FN)
+        . = ALIGN(32);
+    } > FLASH
+    Image$$TFM_SP_IPC_CLIENT_TEST$$RO$$Base = ADDR(.TFM_SP_IPC_CLIENT_TEST);
+    Image$$TFM_SP_IPC_CLIENT_TEST$$RO$$Limit = ADDR(.TFM_SP_IPC_CLIENT_TEST) + SIZEOF(.TFM_SP_IPC_CLIENT_TEST);
+    Image$$TFM_SP_IPC_CLIENT_TEST$$Base = ADDR(.TFM_SP_IPC_CLIENT_TEST);
+    Image$$TFM_SP_IPC_CLIENT_TEST$$Limit = ADDR(.TFM_SP_IPC_CLIENT_TEST) + SIZEOF(.TFM_SP_IPC_CLIENT_TEST);
+
+#endif /* TFM_PSA_API */
 
     .ARM.extab :
     {
@@ -661,6 +711,58 @@
     Image$$TFM_SP_SECURE_TEST_PARTITION_STACK$$ZI$$Limit = ADDR(.TFM_SP_SECURE_TEST_PARTITION_STACK) + SIZEOF(.TFM_SP_SECURE_TEST_PARTITION_STACK);
 
 #endif /* TFM_PARTITION_TEST_SECURE_SERVICES */
+#ifdef TFM_PSA_API
+    .TFM_SP_IPC_SERVICE_TEST_DATA : ALIGN(32)
+    {
+        *ipc_service_test*:*(.data*)
+        . = ALIGN(32);
+    } > RAM AT> FLASH
+    Image$$TFM_SP_IPC_SERVICE_TEST_DATA$$RW$$Base = ADDR(.TFM_SP_IPC_SERVICE_TEST_DATA);
+    Image$$TFM_SP_IPC_SERVICE_TEST_DATA$$RW$$Limit = ADDR(.TFM_SP_IPC_SERVICE_TEST_DATA) + SIZEOF(.TFM_SP_IPC_SERVICE_TEST_DATA);
+
+    .TFM_SP_IPC_SERVICE_TEST_BSS : ALIGN(32)
+    {
+        *ipc_service_test*:*(.bss*)
+        *ipc_service_test*:*(COMMON)
+        . = ALIGN(32);
+    } > RAM AT> FLASH
+    Image$$TFM_SP_IPC_SERVICE_TEST_DATA$$ZI$$Base = ADDR(.TFM_SP_IPC_SERVICE_TEST_BSS);
+    Image$$TFM_SP_IPC_SERVICE_TEST_DATA$$ZI$$Limit = ADDR(.TFM_SP_IPC_SERVICE_TEST_BSS) + SIZEOF(.TFM_SP_IPC_SERVICE_TEST_BSS);
+
+    .TFM_SP_IPC_SERVICE_TEST_STACK : ALIGN(128)
+    {
+        . += 0x1000;
+    } > RAM AT> FLASH
+    Image$$TFM_SP_IPC_SERVICE_TEST_STACK$$ZI$$Base = ADDR(.TFM_SP_IPC_SERVICE_TEST_STACK);
+    Image$$TFM_SP_IPC_SERVICE_TEST_STACK$$ZI$$Limit = ADDR(.TFM_SP_IPC_SERVICE_TEST_STACK) + SIZEOF(.TFM_SP_IPC_SERVICE_TEST_STACK);
+
+#endif /* TFM_PSA_API */
+#ifdef TFM_PSA_API
+    .TFM_SP_IPC_CLIENT_TEST_DATA : ALIGN(32)
+    {
+        *ipc_client_test*:*(.data*)
+        . = ALIGN(32);
+    } > RAM AT> FLASH
+    Image$$TFM_SP_IPC_CLIENT_TEST_DATA$$RW$$Base = ADDR(.TFM_SP_IPC_CLIENT_TEST_DATA);
+    Image$$TFM_SP_IPC_CLIENT_TEST_DATA$$RW$$Limit = ADDR(.TFM_SP_IPC_CLIENT_TEST_DATA) + SIZEOF(.TFM_SP_IPC_CLIENT_TEST_DATA);
+
+    .TFM_SP_IPC_CLIENT_TEST_BSS : ALIGN(32)
+    {
+        *ipc_client_test*:*(.bss*)
+        *ipc_client_test*:*(COMMON)
+        . = ALIGN(32);
+    } > RAM AT> FLASH
+    Image$$TFM_SP_IPC_CLIENT_TEST_DATA$$ZI$$Base = ADDR(.TFM_SP_IPC_CLIENT_TEST_BSS);
+    Image$$TFM_SP_IPC_CLIENT_TEST_DATA$$ZI$$Limit = ADDR(.TFM_SP_IPC_CLIENT_TEST_BSS) + SIZEOF(.TFM_SP_IPC_CLIENT_TEST_BSS);
+
+    .TFM_SP_IPC_CLIENT_TEST_STACK : ALIGN(128)
+    {
+        . += 0x1000;
+    } > RAM AT> FLASH
+    Image$$TFM_SP_IPC_CLIENT_TEST_STACK$$ZI$$Base = ADDR(.TFM_SP_IPC_CLIENT_TEST_STACK);
+    Image$$TFM_SP_IPC_CLIENT_TEST_STACK$$ZI$$Limit = ADDR(.TFM_SP_IPC_CLIENT_TEST_STACK) + SIZEOF(.TFM_SP_IPC_CLIENT_TEST_STACK);
+
+#endif /* TFM_PSA_API */
 
     .TFM_SP_SECURE_TEST_PARTITION_DATA : ALIGN(32)
     {
@@ -734,6 +836,9 @@
     Image$$TFM_DATA$$ZI$$Base = ADDR(.TFM_BSS);
     Image$$TFM_DATA$$ZI$$Limit = ADDR(.TFM_BSS) + SIZEOF(.TFM_BSS);
 
+    Image$$ER_TFM_DATA$$Base = ADDR(.TFM_DATA);
+    Image$$ER_TFM_DATA$$Limit = ADDR(.TFM_DATA) + SIZEOF(.TFM_DATA) + SIZEOF(.TFM_BSS);
+
     /*
      * Place the CMSE Veneers (containing the SG instruction) after the code, in a
      * separate 32 bytes aligned region so that the SAU can programmed to just set
diff --git a/platform/ext/target/musca_b1/Device/Source/gcc/musca_s.ld.template b/platform/ext/target/musca_b1/Device/Source/gcc/musca_s.ld.template
index 9a30f32..ec6eaf4 100644
--- a/platform/ext/target/musca_b1/Device/Source/gcc/musca_s.ld.template
+++ b/platform/ext/target/musca_b1/Device/Source/gcc/musca_s.ld.template
@@ -94,9 +94,9 @@
 @!GENERATOR_CONDITIONAL_START!@ @@attr.conditional@@
 #ifdef @@attr.conditional@@
 @!GENERATOR_CONDITIONAL_END!@
-        LONG (LOADADDR(.@@manifest.tfm_partition_name@@_DATA))
-        LONG (ADDR(.@@manifest.tfm_partition_name@@_DATA))
-        LONG (SIZEOF(.@@manifest.tfm_partition_name@@_DATA))
+        LONG (LOADADDR(.@@manifest.name@@_DATA))
+        LONG (ADDR(.@@manifest.name@@_DATA))
+        LONG (SIZEOF(.@@manifest.name@@_DATA))
 @!GENERATOR_CONDITIONAL_START!@ @@attr.conditional@@
 #endif /* @@attr.conditional@@ */
 @!GENERATOR_CONDITIONAL_END!@
@@ -115,10 +115,10 @@
 @!GENERATOR_CONDITIONAL_START!@ @@attr.conditional@@
 #ifdef @@attr.conditional@@
 @!GENERATOR_CONDITIONAL_END!@
-        LONG (ADDR(.@@manifest.tfm_partition_name@@_BSS))
-        LONG (SIZEOF(.@@manifest.tfm_partition_name@@_BSS))
-        LONG (ADDR(.@@manifest.tfm_partition_name@@_STACK))
-        LONG (SIZEOF(.@@manifest.tfm_partition_name@@_STACK))
+        LONG (ADDR(.@@manifest.name@@_BSS))
+        LONG (SIZEOF(.@@manifest.name@@_BSS))
+        LONG (ADDR(.@@manifest.name@@_STACK))
+        LONG (SIZEOF(.@@manifest.name@@_STACK))
 @!GENERATOR_CONDITIONAL_START!@ @@attr.conditional@@
 #endif /* @@attr.conditional@@ */
 @!GENERATOR_CONDITIONAL_END!@
@@ -156,7 +156,7 @@
 @!GENERATOR_CONDITIONAL_START!@ @@attr.conditional@@
 #ifdef @@attr.conditional@@
 @!GENERATOR_CONDITIONAL_END!@
-    .@@manifest.tfm_partition_name@@ : ALIGN(32)
+    .@@manifest.name@@ : ALIGN(32)
     {
 @!GENERATOR_CONDITIONAL_START!@ @@manifest.tfm_linker_pattern.library_list@@
         @@manifest.tfm_linker_pattern.library_list@@:*(.text*)
@@ -166,13 +166,13 @@
         @@manifest.tfm_linker_pattern.object_list@@(.text*)
         @@manifest.tfm_linker_pattern.object_list@@(.rodata*)
 @!GENERATOR_CONDITIONAL_END!@
-        *(@@manifest.tfm_partition_name@@_ATTR_FN)
+        *(@@manifest.name@@_ATTR_FN)
         . = ALIGN(32);
     } > FLASH
-    Image$$@@manifest.tfm_partition_name@@$$RO$$Base = ADDR(.@@manifest.tfm_partition_name@@);
-    Image$$@@manifest.tfm_partition_name@@$$RO$$Limit = ADDR(.@@manifest.tfm_partition_name@@) + SIZEOF(.@@manifest.tfm_partition_name@@);
-    Image$$@@manifest.tfm_partition_name@@$$Base = ADDR(.@@manifest.tfm_partition_name@@);
-    Image$$@@manifest.tfm_partition_name@@$$Limit = ADDR(.@@manifest.tfm_partition_name@@) + SIZEOF(.@@manifest.tfm_partition_name@@);
+    Image$$@@manifest.name@@$$RO$$Base = ADDR(.@@manifest.name@@);
+    Image$$@@manifest.name@@$$RO$$Limit = ADDR(.@@manifest.name@@) + SIZEOF(.@@manifest.name@@);
+    Image$$@@manifest.name@@$$Base = ADDR(.@@manifest.name@@);
+    Image$$@@manifest.name@@$$Limit = ADDR(.@@manifest.name@@) + SIZEOF(.@@manifest.name@@);
 
 @!GENERATOR_CONDITIONAL_START!@ @@attr.conditional@@
 #endif /* @@attr.conditional@@ */
@@ -311,7 +311,7 @@
 @!GENERATOR_CONDITIONAL_START!@ @@attr.conditional@@
 #ifdef @@attr.conditional@@
 @!GENERATOR_CONDITIONAL_END!@
-    .@@manifest.tfm_partition_name@@_DATA : ALIGN(32)
+    .@@manifest.name@@_DATA : ALIGN(32)
     {
 @!GENERATOR_CONDITIONAL_START!@ @@manifest.tfm_linker_pattern.library_list@@
         @@manifest.tfm_linker_pattern.library_list@@:*(.data*)
@@ -321,10 +321,10 @@
 @!GENERATOR_CONDITIONAL_END!@
         . = ALIGN(32);
     } > RAM AT> FLASH
-    Image$$@@manifest.tfm_partition_name@@_DATA$$RW$$Base = ADDR(.@@manifest.tfm_partition_name@@_DATA);
-    Image$$@@manifest.tfm_partition_name@@_DATA$$RW$$Limit = ADDR(.@@manifest.tfm_partition_name@@_DATA) + SIZEOF(.@@manifest.tfm_partition_name@@_DATA);
+    Image$$@@manifest.name@@_DATA$$RW$$Base = ADDR(.@@manifest.name@@_DATA);
+    Image$$@@manifest.name@@_DATA$$RW$$Limit = ADDR(.@@manifest.name@@_DATA) + SIZEOF(.@@manifest.name@@_DATA);
 
-    .@@manifest.tfm_partition_name@@_BSS : ALIGN(32)
+    .@@manifest.name@@_BSS : ALIGN(32)
     {
 @!GENERATOR_CONDITIONAL_START!@ @@manifest.tfm_linker_pattern.library_list@@
         @@manifest.tfm_linker_pattern.library_list@@:*(.bss*)
@@ -336,15 +336,15 @@
 @!GENERATOR_CONDITIONAL_END!@
         . = ALIGN(32);
     } > RAM AT> FLASH
-    Image$$@@manifest.tfm_partition_name@@_DATA$$ZI$$Base = ADDR(.@@manifest.tfm_partition_name@@_BSS);
-    Image$$@@manifest.tfm_partition_name@@_DATA$$ZI$$Limit = ADDR(.@@manifest.tfm_partition_name@@_BSS) + SIZEOF(.@@manifest.tfm_partition_name@@_BSS);
+    Image$$@@manifest.name@@_DATA$$ZI$$Base = ADDR(.@@manifest.name@@_BSS);
+    Image$$@@manifest.name@@_DATA$$ZI$$Limit = ADDR(.@@manifest.name@@_BSS) + SIZEOF(.@@manifest.name@@_BSS);
 
-    .@@manifest.tfm_partition_name@@_STACK : ALIGN(128)
+    .@@manifest.name@@_STACK : ALIGN(128)
     {
         . += @@manifest.stack_size@@;
     } > RAM AT> FLASH
-    Image$$@@manifest.tfm_partition_name@@_STACK$$ZI$$Base = ADDR(.@@manifest.tfm_partition_name@@_STACK);
-    Image$$@@manifest.tfm_partition_name@@_STACK$$ZI$$Limit = ADDR(.@@manifest.tfm_partition_name@@_STACK) + SIZEOF(.@@manifest.tfm_partition_name@@_STACK);
+    Image$$@@manifest.name@@_STACK$$ZI$$Base = ADDR(.@@manifest.name@@_STACK);
+    Image$$@@manifest.name@@_STACK$$ZI$$Limit = ADDR(.@@manifest.name@@_STACK) + SIZEOF(.@@manifest.name@@_STACK);
 
 @!GENERATOR_CONDITIONAL_START!@ @@attr.conditional@@
 #endif /* @@attr.conditional@@ */
@@ -423,6 +423,9 @@
     Image$$TFM_DATA$$ZI$$Base = ADDR(.TFM_BSS);
     Image$$TFM_DATA$$ZI$$Limit = ADDR(.TFM_BSS) + SIZEOF(.TFM_BSS);
 
+    Image$$ER_TFM_DATA$$Base = ADDR(.TFM_DATA);
+    Image$$ER_TFM_DATA$$Limit = ADDR(.TFM_DATA) + SIZEOF(.TFM_DATA) + SIZEOF(.TFM_BSS);
+
     /*
      * Place the CMSE Veneers (containing the SG instruction) after the code, in a
      * separate 32 bytes aligned region so that the SAU can programmed to just set
diff --git a/platform/include/tfm_plat_defs.h b/platform/include/tfm_plat_defs.h
index 66747ee..f0b4297 100644
--- a/platform/include/tfm_plat_defs.h
+++ b/platform/include/tfm_plat_defs.h
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2017-2018, Arm Limited. All rights reserved.
+ * Copyright (c) 2017-2019, Arm Limited. All rights reserved.
  *
  * SPDX-License-Identifier: BSD-3-Clause
  *
@@ -30,7 +30,7 @@
  *        secure partition at linker time in TF-M Level 3.
  *
  * \param[in] TFM_PARTITION_NAME  TF-M partition name assigned in the manifest
- *                                file "tfm_partition_name" field.
+ *                                file "name" field.
  */
 #define TFM_LINK_SET_OBJECT_IN_PARTITION_SECTION(TFM_PARTITION_NAME) \
                 __attribute__((section(TFM_PARTITION_NAME"_ATTR_FN")))
diff --git a/secure_fw/CMakeLists.txt b/secure_fw/CMakeLists.txt
index ab1ced2..57aa6f0 100644
--- a/secure_fw/CMakeLists.txt
+++ b/secure_fw/CMakeLists.txt
@@ -31,8 +31,13 @@
 endif()
 
 include(${SECURE_FW_DIR}/spm/CMakeLists.inc)
-include(${SECURE_FW_DIR}/core/CMakeLists.inc)
 include(${SECURE_FW_DIR}/ns_callable/CMakeLists.inc)
+#Involve all IPC related sources in ipc's CMakeLists.inc, and switch core between IPC and Library.
+if(TFM_PSA_API)
+	include(${SECURE_FW_DIR}/core/ipc/CMakeLists.inc)
+else()
+	include(${SECURE_FW_DIR}/core/CMakeLists.inc)
+endif()
 
 set(BUILD_CMSIS_CORE On)
 set(BUILD_RETARGET On)
@@ -144,7 +149,7 @@
 	#Set macro definitions for the project.
 	embedded_set_target_compile_defines(TARGET ${PROJECT_OBJ_LIB} LANGUAGE C DEFINES __thumb2__ __ARM_FEATURE_CMSE=3 TFM_LVL=${TFM_LVL} DAUTH_CHIP_DEFAULT APPEND)
 
-	if (REGRESSION OR CORE_TEST)
+	if (REGRESSION OR CORE_TEST OR CORE_IPC)
 		if (DEFINED TFM_PARTITION_TEST_SECURE_SERVICES AND TFM_PARTITION_TEST_SECURE_SERVICES)
 			#The test service veneers in the tfm_secure_tests library may not be
 			#referenced in the secure binary so the veneer objects are explicitly loaded
@@ -202,6 +207,12 @@
 		embedded_set_target_link_defines(TARGET ${EXE_NAME} DEFINES "BL2")
 	endif()
 
+	if (NOT DEFINED TFM_PSA_API)
+		message(FATAL_ERROR "Incomplete build configuration: TFM_PSA_API is undefined. ")
+	elseif (TFM_PSA_API)
+		embedded_set_target_link_defines(TARGET ${PROJECT_NAME} DEFINES "TFM_PSA_API")
+	endif()
+
 	if(CORE_TEST)
 		set(SECURE_AXF_DIR_PREFIX "${CMAKE_BINARY_DIR}/unit_test/")
 		set_target_properties(${EXE_NAME} PROPERTIES RUNTIME_OUTPUT_DIRECTORY ${SECURE_AXF_DIR_PREFIX})
diff --git a/secure_fw/core/CMakeLists.inc b/secure_fw/core/CMakeLists.inc
index c7e4392..0b290d5 100644
--- a/secure_fw/core/CMakeLists.inc
+++ b/secure_fw/core/CMakeLists.inc
@@ -69,4 +69,3 @@
 else()
 	include(${PLATFORM_CMAKE_FILE})
 endif()
-
diff --git a/secure_fw/core/ipc/CMakeLists.inc b/secure_fw/core/ipc/CMakeLists.inc
new file mode 100644
index 0000000..59c074e
--- /dev/null
+++ b/secure_fw/core/ipc/CMakeLists.inc
@@ -0,0 +1,74 @@
+#-------------------------------------------------------------------------------
+# Copyright (c) 2018, Arm Limited. All rights reserved.
+#
+# SPDX-License-Identifier: BSD-3-Clause
+#
+#-------------------------------------------------------------------------------
+
+#Definitions to compile the "ipc" module.
+#This file assumes it will be included from a project specific cmakefile, and
+#will not create a library or executable.
+#Inputs:
+#	TFM_ROOT_DIR - directory where secure FW sourec is located.
+#
+#Outputs:
+#	Will modify include directories to make the source compile.
+#	ALL_SRC_C: C source files to be compiled will be added to this list.
+#	  This shall be added to your add_executable or add_library command.
+#	ALL_SRC_CXX: C++ source files to be compiled will be added to this list.
+#	  This shall be added to your add_executable or add_library command.
+#	ALL_SRC_ASM: assembly source files to be compiled will be added to this
+#	  list. This shall be added to your add_executable or add_library
+#	  command.
+#	Include directories will be modified by using the include_directories()
+#	  commands as needed.
+
+#Get the current directory where this file is located.
+set(SS_IPC_DIR ${CMAKE_CURRENT_LIST_DIR})
+if(NOT DEFINED TFM_ROOT_DIR)
+	message(FATAL_ERROR
+		"Please set TFM_ROOT_DIR before including this file.")
+endif()
+
+if (NOT DEFINED TFM_PSA_API)
+	message(FATAL_ERROR "Incomplete build configuration: TFM_PSA_API is undefined. ")
+elseif (TFM_PSA_API)
+	set (SS_IPC_C_SRC "${SS_IPC_DIR}/tfm_svcalls.c"
+			"${SS_IPC_DIR}/psa_service.c"
+			"${SS_IPC_DIR}/psa_client.c"
+			"${SS_IPC_DIR}/tfm_arch_v8m.c"
+			"${SS_IPC_DIR}/tfm_thread.c"
+			"${SS_IPC_DIR}/tfm_wait.c"
+			"${SS_IPC_DIR}/tfm_utils.c"
+			"${SS_IPC_DIR}/tfm_message_queue.c"
+			"${SS_IPC_DIR}/tfm_pools.c"
+			"${SS_IPC_DIR}/tfm_spm.c"
+			"${SS_IPC_DIR}/../tfm_core.c"
+			"${SS_IPC_DIR}/../tfm_secure_api.c"
+			"${SS_IPC_DIR}/../tfm_spm_services.c"
+			"${SS_IPC_DIR}/../tfm_handler.c"
+			"${SS_IPC_DIR}/../tfm_psa_api_client.c"
+			"${SS_IPC_DIR}/../tfm_nspm.c"
+			"${SS_IPC_DIR}/../tfm_boot_data.c"
+			)
+endif()
+
+#Append all our source files to global lists.
+list(APPEND ALL_SRC_C ${SS_IPC_C_SRC})
+unset(SS_IPC_C_SRC)
+
+#Setting include directories
+embedded_include_directories(PATH ${TFM_ROOT_DIR} ABSOLUTE)
+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 ABSOLUTE)
+embedded_include_directories(PATH ${TFM_ROOT_DIR}/secure_fw/core/ipc ABSOLUTE)
+embedded_include_directories(PATH ${TFM_ROOT_DIR}/secure_fw/core/ipc/include ABSOLUTE)
+
+if(NOT DEFINED PLATFORM_CMAKE_FILE)
+	message (FATAL_ERROR "Platform specific CMake is not defined. Please set PLATFORM_CMAKE_FILE.")
+elseif(NOT EXISTS ${PLATFORM_CMAKE_FILE})
+	message (FATAL_ERROR "Platform specific CMake \"${PLATFORM_CMAKE_FILE}\" file does not exist. Please fix value of PLATFORM_CMAKE_FILE.")
+else()
+	include(${PLATFORM_CMAKE_FILE})
+endif()
diff --git a/secure_fw/core/ipc/include/tfm_arch_v8m.h b/secure_fw/core/ipc/include/tfm_arch_v8m.h
new file mode 100644
index 0000000..96914c0
--- /dev/null
+++ b/secure_fw/core/ipc/include/tfm_arch_v8m.h
@@ -0,0 +1,66 @@
+/*
+ * Copyright (c) 2018-2019, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
+ */
+#ifndef __TFM_ARCH_V8M_H__
+#define __TFM_ARCH_V8M_H__
+
+#include "cmsis.h"
+
+#define XPSR_T32            0x01000000
+#define LR_UNPRIVILEGED     0xfffffffd
+
+/* This header file collects the ARCH related operations. */
+struct tfm_state_context_base {
+    uint32_t    r0;
+    uint32_t    r1;
+    uint32_t    r2;
+    uint32_t    r3;
+    uint32_t    r12;
+    uint32_t    ra_lr;
+    uint32_t    ra;
+    uint32_t    xpsr;
+};
+
+struct tfm_state_context_ext {
+    uint32_t    r4;
+    uint32_t    r5;
+    uint32_t    r6;
+    uint32_t    r7;
+    uint32_t    r8;
+    uint32_t    r9;
+    uint32_t    r10;
+    uint32_t    r11;
+    uint32_t    sp;
+    uint32_t    sp_limit;
+    uint32_t    dummy;
+    uint32_t    lr;
+};
+
+struct tfm_state_context {
+    struct tfm_state_context_ext     ctxb;
+};
+
+#define TFM_STATE_1ST_ARG(ctx)     \
+                    (((struct tfm_state_context_base *)(ctx)->ctxb.sp)->r0)
+#define TFM_STATE_2ND_ARG(ctx)     \
+                    (((struct tfm_state_context_base *)(ctx)->ctxb.sp)->r1)
+#define TFM_STATE_3RD_ARG(ctx)     \
+                    (((struct tfm_state_context_base *)(ctx)->ctxb.sp)->r2)
+#define TFM_STATE_4TH_ARG(ctx)     \
+                    (((struct tfm_state_context_base *)(ctx)->ctxb.sp)->r3)
+#define TFM_STATE_RET_VAL(ctx)     \
+                    (((struct tfm_state_context_base *)(ctx)->ctxb.sp)->r0)
+
+__STATIC_INLINE void tfm_trigger_pendsv(void)
+{
+    SCB->ICSR = SCB_ICSR_PENDSVSET_Msk;
+}
+
+void tfm_initialize_context(struct tfm_state_context *ctx,
+                            uint32_t r0, uint32_t ra,
+                            uint32_t sp, uint32_t sp_limit);
+
+#endif
diff --git a/secure_fw/core/ipc/include/tfm_internal_defines.h b/secure_fw/core/ipc/include/tfm_internal_defines.h
new file mode 100644
index 0000000..a5382c5
--- /dev/null
+++ b/secure_fw/core/ipc/include/tfm_internal_defines.h
@@ -0,0 +1,18 @@
+/*
+ * Copyright (c) 2018, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
+ */
+#ifndef __TFM_INTERNAL_DEFINES_H__
+#define __TFM_INTERNAL_DEFINES_H__
+
+/* IPC internal return status */
+#define IPC_SUCCESS                     0
+#define IPC_ERROR_BAD_PARAMETERS        (INT32_MIN)
+#define IPC_ERROR_SHORT_BUFFER          (INT32_MIN + 1)
+#define IPC_ERROR_VERSION               (INT32_MIN + 2)
+#define IPC_ERROR_MEMORY_CHECK          (INT32_MIN + 3)
+#define IPC_ERROR_GENERIC               (INT32_MIN + 0x1F)
+
+#endif
diff --git a/secure_fw/core/ipc/include/tfm_list.h b/secure_fw/core/ipc/include/tfm_list.h
new file mode 100644
index 0000000..9764503
--- /dev/null
+++ b/secure_fw/core/ipc/include/tfm_list.h
@@ -0,0 +1,98 @@
+/*
+ * Copyright (c) 2018, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
+ */
+#ifndef __TFM_LIST_H__
+#define __TFM_LIST_H__
+
+/* List structure */
+struct tfm_list_node_t {
+    struct tfm_list_node_t *prev;
+    struct tfm_list_node_t *next;
+};
+
+/**
+ * \brief Initialize list head.
+ *
+ * \param[in] head              List head need to be initialized.
+ */
+__STATIC_INLINE void tfm_list_init(struct tfm_list_node_t *head)
+{
+    head->next = head;
+    head->prev = head;
+}
+
+/**
+ * \brief Add one node to list tail.
+ *
+ * \param[in] head              List head initialized by \ref tfm_list_init.
+ * \param[in] node              List node want to be added.
+ */
+__STATIC_INLINE void
+tfm_list_add_tail(struct tfm_list_node_t *head, struct tfm_list_node_t *node)
+{
+    head->prev->next = node;
+    node->prev = head->prev;
+    head->prev = node;
+    node->next = head;
+}
+
+/**
+ * \brief Check if a list is empty.
+ *
+ * \param[in] head              List head initialized by \ref tfm_list_init.
+ *
+ * \returns                     returns 1 for empty, or 0 for not.
+ */
+__STATIC_INLINE int32_t tfm_list_is_empty(struct tfm_list_node_t *head)
+{
+    return (head->next == head);
+}
+
+/**
+ * \brief Insert one node to list head.
+ *
+ * \param[in] head              List head initialized by \ref tfm_list_init.
+ * \param[in] node              List node want to be inserted.
+ */
+__STATIC_INLINE void
+tfm_list_insert_first(struct tfm_list_node_t *head,
+                      struct tfm_list_node_t *node)
+{
+    node->next = head->next;
+    node->prev = head;
+    head->next->prev = node;
+    head->next = node;
+}
+
+/**
+ * \brief Retrieve the fist node from list.
+ *
+ * \param[in] head              List head initialized by \ref tfm_list_init.
+ *
+ *  \returns                    Returns the pointer to first list node.
+ */
+__STATIC_INLINE
+struct tfm_list_node_t *tfm_list_first_node(struct tfm_list_node_t *head)
+{
+    return head->next;
+}
+
+/**
+ * \brief Delete one node from list.
+ *
+ * \param[in] node              List node want to be deleted.
+ */
+__STATIC_INLINE void tfm_list_del_node(struct tfm_list_node_t *node)
+{
+    node->prev->next = node->next;
+    node->next->prev = node->prev;
+}
+
+/* Go through each node of a list */
+#define TFM_LIST_FOR_EACH(node, head) \
+    for (node = (head)->next; node != head; node = node->next)
+
+#endif
diff --git a/secure_fw/core/ipc/include/tfm_message_queue.h b/secure_fw/core/ipc/include/tfm_message_queue.h
new file mode 100644
index 0000000..6ecb34a
--- /dev/null
+++ b/secure_fw/core/ipc/include/tfm_message_queue.h
@@ -0,0 +1,66 @@
+/*
+ * Copyright (c) 2018-2019, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
+ */
+#ifndef __TFM_MESSAGE_QUEUE_H__
+#define __TFM_MESSAGE_QUEUE_H__
+
+#define TFM_MSG_QUEUE_MAX_MSG_NUM   128
+#define TFM_MSG_MAGIC               0x15154343
+/* Message struct to collect parameter from client */
+struct tfm_msg_body_t {
+    int32_t magic;
+    struct tfm_spm_service_t *service; /* RoT service pointer           */
+    psa_handle_t handle;            /* Connected Service handle         */
+    struct tfm_event_ctx ack_mtx;   /* Event for ack reponse            */
+    psa_msg_t msg;                  /* PSA message body                 */
+    psa_invec invec[PSA_MAX_IOVEC]; /* Put in/out vectors in msg body   */
+    psa_outvec outvec[PSA_MAX_IOVEC];
+    psa_outvec *caller_outvec;      /*
+                                     * Save caller outvec pointer for
+                                     * write length update
+                                     */
+    struct tfm_msg_body_t *next;    /* List operators                   */
+};
+
+struct tfm_msg_queue_t {
+    struct tfm_msg_body_t *head;    /* Queue head                       */
+    struct tfm_msg_body_t *tail;    /* Queue tail                       */
+    uint32_t size;                  /* Number of the queue member       */
+};
+
+/**
+ * \brief Enqueue a message into message queue.
+ *
+ * \param[in] queue             Message queue, it will be initialized
+ *                              if has not been initialized.
+ * \param[in] node              Message queue node want to be enqueue.
+ *
+ * \retval IPC_SUCCESS          Success.
+ * \retval IPC_ERROR_BAD_PARAMETERS Parameters error.
+ */
+int32_t tfm_msg_enqueue(struct tfm_msg_queue_t *queue,
+                        struct tfm_msg_body_t *node);
+
+/**
+ * \brief Dequeue a message from message queue.
+ *
+ * \param[in] queue             Message queue.
+ *
+ * \retval node pointer         Success.
+ * \retval NULL                 Queue is NULL or size is zero.
+ */
+struct tfm_msg_body_t *tfm_msg_dequeue(struct tfm_msg_queue_t *queue);
+
+/**
+ * \brief Check if a message queue is empty.
+ *
+ * \param[in] queue             Message queue.
+ *
+ * \returns                     Returns 1 for empty, or 0 for not.
+ */
+int32_t tfm_msg_queue_is_empty(struct tfm_msg_queue_t *queue);
+
+#endif
diff --git a/secure_fw/core/ipc/include/tfm_pools.h b/secure_fw/core/ipc/include/tfm_pools.h
new file mode 100644
index 0000000..1072f78
--- /dev/null
+++ b/secure_fw/core/ipc/include/tfm_pools.h
@@ -0,0 +1,85 @@
+/*
+ * Copyright (c) 2018-2019, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
+ */
+#ifndef __TFM_POOLS_H__
+#define __TFM_POOLS_H__
+
+/*
+ * Resource pool - few known size resources allocation/free is required,
+ * so pool is more applicable than heap.
+ */
+
+/*
+ * Pool Instance:
+ *  [ Pool Instance ] + N * [ Pool Chunks ]
+ */
+struct tfm_pool_chunk_t {
+    struct tfm_list_node_t list;        /* Chunk list                  */
+    void *pool;                         /* Point to the parent pool    */
+    uint8_t data[0];                    /* Data indicator              */
+};
+
+struct tfm_pool_instance_t {
+    size_t chunksz;                     /* Chunks size of pool member   */
+    struct tfm_list_node_t chunks_list; /* Chunk list head in pool      */
+    struct tfm_pool_chunk_t chunks[0];  /* Data indicator               */
+};
+
+/*
+ * This will declares a static memory pool variable with chunk memory.
+ * Parameters:
+ *  name        -   Variable name, will be used when register
+ *  chunksz     -   chunk size in bytes
+ *  num         -   Number of chunks
+ */
+#define TFM_POOL_DECLARE(name, chunksz, num)                                \
+    static uint8_t name##_pool_buf[((chunksz) +                             \
+                                   sizeof(struct tfm_pool_chunk_t)) * (num) \
+                                   + sizeof(struct tfm_pool_instance_t)]    \
+                                   __attribute__((aligned(4)));            \
+    static struct tfm_pool_instance_t *name =                               \
+                            (struct tfm_pool_instance_t *)name##_pool_buf
+
+/* Get the head size of memory pool */
+#define POOL_HEAD_SIZE (sizeof(struct tfm_pool_instance_t) +                \
+                        sizeof(struct tfm_pool_chunk_t))
+
+/* Get the whole size of memory pool */
+#define POOL_BUFFER_SIZE(name)          sizeof(name##_pool_buf)
+
+/**
+ * \brief Register a memory pool.
+ *
+ * \param[in] pool              Pointer to memory pool declared by
+ *                              \ref TFM_POOL_DECLARE
+ * \param[in] poolsz             Size of the pool buffer.
+ * \param[in] chunksz           Size of chunks.
+ * \param[in] num               Number of chunks.
+ *
+ * \retval IPC_SUCCESS          Success.
+ * \retval IPC_ERROR_BAD_PARAMETERS Parameters error.
+ */
+int32_t tfm_pool_init(struct tfm_pool_instance_t *pool, size_t poolsz,
+                      size_t chunksz, size_t num);
+
+/**
+ * \brief Allocate a memory from pool.
+ *
+ * \param[in] pool              pool pointer decleared by \ref TFM_POOL_DECLARE
+ *
+ * \retval buffer pointer       Success.
+ * \retval NULL                 Failed.
+ */
+void *tfm_pool_alloc(struct tfm_pool_instance_t *pool);
+
+/**
+ * \brief Free the allocated memory.
+ *
+ * \param[in] ptr               Buffer pointer want to free.
+ */
+void tfm_pool_free(void *ptr);
+
+#endif
diff --git a/secure_fw/core/ipc/include/tfm_spm.h b/secure_fw/core/ipc/include/tfm_spm.h
new file mode 100644
index 0000000..e9e18d0
--- /dev/null
+++ b/secure_fw/core/ipc/include/tfm_spm.h
@@ -0,0 +1,292 @@
+/*
+ * Copyright (c) 2018-2019, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
+ */
+#ifndef __TFM_SPM_H__
+#define __TFM_SPM_H__
+
+#include <stdbool.h>
+#include "tfm_list.h"
+
+#define TFM_SPM_MAX_ROT_SERV_NUM        28
+#define TFM_VERSION_POLICY_RELAXED      0
+#define TFM_VERSION_POLICY_STRICT       1
+
+#define TFM_CONN_HANDLE_MAX_NUM         32
+
+/* RoT connection handle list */
+struct tfm_conn_handle_t {
+    psa_handle_t handle;            /* Handle value                         */
+    void *rhandle;                  /* Reverse handle value                 */
+    struct tfm_list_node_t list;    /* list node                            */
+};
+
+/* Service database defined by manifest */
+struct tfm_spm_service_db_t {
+    char *name;                     /* Service name                          */
+    uint32_t partition_id;          /* Partition ID which service belong to  */
+    psa_signal_t signal;            /* Service signal                        */
+    uint32_t sid;                   /* Service identifier                    */
+    bool non_secure_client;         /* If can be called by non secure client */
+    uint32_t minor_version;         /* Minor version                         */
+    uint32_t minor_policy;          /* Minor version policy                  */
+};
+
+/* RoT Service data */
+struct tfm_spm_service_t {
+    struct tfm_spm_service_db_t *service_db; /* Service database pointer     */
+    struct tfm_spm_ipc_partition_t *partition; /*
+                                                * Point to secure partition
+                                                * data
+                                                */
+    struct tfm_list_node_t handle_list;    /* Service handle list            */
+    struct tfm_msg_queue_t msg_queue;      /* Message queue                  */
+    struct tfm_list_node_t list;           /* For list operation             */
+};
+
+/*
+ * FixMe: This structure is for IPC partition which is different with library
+ * mode partition. There needs to be an alignment for IPC partition database
+ * and library mode database.
+ */
+/* Secure Partition data */
+struct tfm_spm_ipc_partition_t {
+    int32_t index;                      /* Partition index                   */
+    int32_t id;                         /* Secure partition ID               */
+    struct tfm_event_ctx signal_event;  /* Event signal                      */
+    uint32_t signals;                   /* Service signals had been triggered*/
+    uint32_t signal_mask;        /* Service signal mask passed by psa_wait() */
+    struct tfm_list_node_t service_list;/* Service list                      */
+};
+
+/*************************** Extended SPM functions **************************/
+
+/**
+ * \brief   Get the running partition ID.
+ *
+ * \return  Returns the partition ID
+ */
+uint32_t tfm_spm_partition_get_running_partition_id_ext(void);
+
+/******************** Service handle management functions ********************/
+
+/**
+ * \brief                   Create connection handle for client connect
+ *
+ * \param[in] service       Target service context pointer
+ *
+ * \retval PSA_NULL_HANDLE  Create failed \ref PSA_NULL_HANDLE
+ * \retval >0               Service handle created, \ref psa_handle_t
+ */
+psa_handle_t tfm_spm_create_conn_handle(struct tfm_spm_service_t *service);
+
+/**
+ * \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 *************************/
+
+/**
+ * \brief                   Get current running partition context.
+ *
+ * \retval NULL             Failed
+ * \retval "Not NULL"       Return the parttion context pointer
+ *                          \ref spm_partition_t structures
+ */
+struct tfm_spm_ipc_partition_t *tfm_spm_get_running_partition(void);
+
+/**
+ * \brief                   Get the service context by signal.
+ *
+ * \param[in] partition     Partition context pointer
+ *                          \ref spm_partition_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 spm_service_t structures
+ */
+struct tfm_spm_service_t *
+tfm_spm_get_service_by_signal(struct tfm_spm_ipc_partition_t *partition,
+                              psa_signal_t signal);
+
+/**
+ * \brief                   Get the service context by service ID.
+ *
+ * \param[in] sid           RoT Service identity
+ *
+ * \retval NULL             Failed
+ * \retval "Not NULL"       Target service context pointer,
+ *                          \ref spm_service_t structures
+ */
+struct tfm_spm_service_t *tfm_spm_get_service_by_sid(uint32_t sid);
+
+/**
+ * \brief                   Get the service context by connection handle.
+ *
+ * \param[in] conn_handle   Connection handle created by
+ *                          tfm_spm_create_conn_handle()
+ *
+ * \retval NULL             Failed
+ * \retval "Not NULL"       Target service context pointer,
+ *                          \ref spm_service_t structures
+ */
+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_t structures
+ */
+struct tfm_spm_ipc_partition_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 msg_body_t structures
+ */
+struct tfm_msg_body_t *tfm_spm_get_msg_from_handle(psa_handle_t msg_handle);
+
+/**
+ * \brief                   Create a message for PSA client call.
+ *
+ * \param[in] service       Target service context pointer, which can be
+ *                          obtained by partition management functions
+ * \prarm[in] handle        Connect handle return by psa_connect(). Should
+ *                          be \ref PSA_NULL_HANDLE in psa_connect().
+ * \param[in] type          Message type, PSA_IPC_CONNECT, PSA_IPC_CALL or
+ *                          PSA_IPC_DISCONNECT
+ * \param[in] ns_caller     Whether from NS caller
+ * \param[in] invec         Array of input \ref psa_invec structures
+ * \param[in] in_len        Number of input \ref psa_invec structures
+ * \param[in] outvec        Array of output \ref psa_outvec structures
+ * \param[in] out_len       Number of output \ref psa_outvec structures
+ * \param[in] caller_outvec Array of caller output \ref psa_outvec structures
+ *
+ * \retval NULL             Failed
+ * \retval "Not NULL"       New message body pointer \ref msg_body_t structures
+ */
+struct tfm_msg_body_t *tfm_spm_create_msg(struct tfm_spm_service_t *service,
+                                          psa_handle_t handle,
+                                          uint32_t type, int32_t ns_caller,
+                                          psa_invec *invec, size_t in_len,
+                                          psa_outvec *outvec, size_t out_len,
+                                          psa_outvec *caller_outvec);
+
+/**
+ * \brief                   Free message which unused anymore
+ *
+ * \param[in] msg           Message pointer which want to free
+ *                          \ref msg_body_t structures
+ *
+ * \retval void             Success
+ * \retval "Does not return" Failed
+ */
+void tfm_spm_free_msg(struct tfm_msg_body_t *msg);
+
+/**
+ * \brief                   Send message and wake up the SP who is waiting on
+ *                          message queue, block the current thread and
+ *                          scheduler triggered
+ *
+ * \param[in] service       Target service context pointer, which can be
+ *                          obtained by partition management functions
+ * \param[in] msg           message created by spm_create_msg()
+ *                          \ref msg_body_t structures
+ *
+ * \retval IPC_SUCCESS      Success
+ * \retval IPC_ERROR_BAD_PARAMETERS Bad parameters input
+ * \retval IPC_ERROR_GENERIC Failed to enqueue message to service message queue
+ */
+int32_t tfm_spm_send_event(struct tfm_spm_service_t *service,
+                           struct tfm_msg_body_t *msg);
+
+/**
+ * \brief                   Check the client minor version according to
+ *                          version policy
+ *
+ * \param[in] service       Target service context pointer, which can be get
+ *                          by partition management functions
+ * \param[in] minor_version Client support minor version
+ *
+ * \retval IPC_SUCCESS      Success
+ * \retval IPC_ERROR_BAD_PARAMETERS Bad parameters input
+ * \retval IPC_ERROR_VERSION Check failed
+ */
+int32_t tfm_spm_check_client_version(struct tfm_spm_service_t *service,
+                                     uint32_t minor_version);
+
+/**
+ * \brief                   Check the memory reference is valid.
+ *
+ * \param[in] buffer        Pointer of memory reference
+ * \param[in] len           Length of memory reference in bytes
+ * \param[in] ns_caller     From non-secure caller
+ *
+ * \retval IPC_SUCCESS      Success
+ * \retval IPC_ERROR_BAD_PARAMETERS Bad parameters input
+ * \retval IPC_ERROR_MEMORY_CHECK Check failed
+ */
+int32_t tfm_memory_check(void *buffer, size_t len, int32_t ns_caller);
+
+/* This function should be called before schedule function */
+void tfm_spm_init(void);
+
+#endif
diff --git a/secure_fw/core/ipc/include/tfm_spm_signal_defs.h b/secure_fw/core/ipc/include/tfm_spm_signal_defs.h
new file mode 100644
index 0000000..e632354
--- /dev/null
+++ b/secure_fw/core/ipc/include/tfm_spm_signal_defs.h
@@ -0,0 +1,12 @@
+/*
+ * Copyright (c) 2018, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
+ */
+#ifndef __TFM_SPM_SIGNAL_DEFS_H__
+#define __TFM_SPM_SIGNAL_DEFS_H__
+
+#include "test/test_services/tfm_ipc_service/tfm_ipc_service_partition.h"
+
+#endif
diff --git a/secure_fw/core/ipc/include/tfm_svcalls.h b/secure_fw/core/ipc/include/tfm_svcalls.h
new file mode 100644
index 0000000..c64ce74
--- /dev/null
+++ b/secure_fw/core/ipc/include/tfm_svcalls.h
@@ -0,0 +1,105 @@
+/*
+ * Copyright (c) 2018-2019, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
+ */
+#ifndef __TFM_SVCALLS_H__
+#define __TFM_SVCALLS_H__
+
+/* 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_svcall_psa_framework_version(void);
+
+/**
+ * \brief SVC handler for \ref psa_version.
+ *
+ * \param[in] args              Include all input arguments: sid.
+ * \param[in] ns_caller         If 'non-zero', 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 minor version of the implemented RoT
+ *                              Service.
+ */
+uint32_t tfm_svcall_psa_version(uint32_t *args, int32_t ns_caller);
+
+/**
+ * \brief SVC handler for \ref psa_connect.
+ *
+ * \param[in] args              Include all input arguments:
+ *                              sid, minor_version.
+ * \param[in] ns_caller         If 'non-zero', call from non-secure client.
+ *                              Or from secure client.
+ *
+ * \retval > 0                  A handle for the connection.
+ * \retval PSA_CONNECTION_REFUSED The SPM or RoT Service has refused the
+ *                              connection.
+ * \retval PSA_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_handle_t tfm_svcall_psa_connect(uint32_t *args, int32_t 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 'non-zero', call from non-secure client.
+ *                              Or from secure client.
+ *
+ * \retval >=0                  RoT Service-specific status value.
+ * \retval <0                   RoT Service-specific error code.
+ * \retval PSA_DROP_CONNECTION  The connection has been dropped by the RoT
+ *                              Service. This indicates that either this or
+ *                              a previous message was invalid.
+ * \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_len + out_len > PSA_MAX_IOVEC.
+ * \arg                           The message is unrecognized by the RoT
+ *                                Service or incorrectly formatted.
+ */
+psa_status_t tfm_svcall_psa_call(uint32_t *args, int32_t ns_caller);
+
+/**
+ * \brief SVC handler for \ref psa_close.
+ *
+ * \param[in] args              Include all input arguments: handle.
+ * \param[in] ns_caller         If 'non-zero', 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_svcall_psa_close(uint32_t *args, int32_t ns_caller);
+
+/**
+ * \brief SVC handler for IPC functions
+ *
+ * \param[in] svc_num           SVC number
+ * \param[in] ctx               Argument context
+ *
+ * \returns                     Return values from those who has,
+ *                              or PSA_SUCCESS.
+ */
+int32_t SVC_Handler_IPC(tfm_svc_number_t svc_num, uint32_t *ctx);
+
+#endif
diff --git a/secure_fw/core/ipc/include/tfm_thread.h b/secure_fw/core/ipc/include/tfm_thread.h
new file mode 100644
index 0000000..8a6d863
--- /dev/null
+++ b/secure_fw/core/ipc/include/tfm_thread.h
@@ -0,0 +1,223 @@
+/*
+ * Copyright (c) 2018-2019, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
+ */
+#ifndef __TFM_THREAD_H__
+#define __TFM_THREAD_H__
+
+#include "tfm_arch_v8m.h"
+#include "cmsis_compiler.h"
+
+/* Status code */
+#define THRD_STAT_CREATING        0
+#define THRD_STAT_RUNNING         1
+#define THRD_STAT_BLOCK           2
+#define THRD_STAT_DETACH          3
+#define THRD_STAT_INVALID         4
+
+/* Security attribute - default as security */
+#define THRD_ATTR_SECURE_OFFSET   16
+#define THRD_ATTR_SECURE          (0)
+#define THRD_ATTR_NON_SECURE      (1 << THRD_ATTR_SECURE_OFFSET)
+
+/* Lower value has higher priority */
+#define THRD_PRIOR_MASK           0xFF
+#define THRD_PRIOR_HIGHEST        0x0
+#define THRD_PRIOR_MEDIUM         0x7F
+#define THRD_PRIOR_LOWEST         0xFF
+
+/* Error code */
+#define THRD_SUCCESS              0
+#define THRD_ERR_INVALID_PARAM    1
+
+/* Thread entry function type */
+typedef void *(*tfm_thrd_func_t)(void *);
+
+/* Thread context */
+struct tfm_thrd_ctx {
+    tfm_thrd_func_t pfn;          /* entry function      */
+    void            *param;       /* entry parameter     */
+    uint8_t         *sp_base;     /* stack bottom        */
+    uint8_t         *sp_top;      /* stack top           */
+    uint32_t        prior;        /* priority            */
+    uint32_t        status;       /* status              */
+
+    struct tfm_state_context state_ctx; /* State context */
+    struct tfm_thrd_ctx *next;    /* next thread in list */
+};
+
+/*
+ * Initialize a thread context with the necessary info.
+ *
+ * Parameters :
+ *  pth         -    pointer of caller provided thread context
+ *  pfn         -    thread entry function
+ *  param       -    thread entry function parameter
+ *  sp_base     -    stack pointer base (higher address)
+ *  sp_top      -    stack pointer top (lower address)
+ *
+ * Notes :
+ *  Thread contex rely on caller allocated memory; initialize members in
+ *  context. This function does not insert thread into schedulable list.
+ */
+void tfm_thrd_init(struct tfm_thrd_ctx *pth,
+                   tfm_thrd_func_t pfn, void *param,
+                   uint8_t *sp_base, uint8_t *sp_top);
+
+/* Set thread priority.
+ *
+ * Parameters :
+ *  pth         -     pointer of thread context
+ *  prior       -     priority value (0~255)
+ *
+ * Notes :
+ *  Set thread priority. Priority is set to THRD_PRIOR_MEDIUM in
+ *  tfm_thrd_init().
+ */
+void __STATIC_INLINE tfm_thrd_priority(struct tfm_thrd_ctx *pth,
+                                       uint32_t prior)
+{
+    pth->prior &= ~THRD_PRIOR_MASK;
+    pth->prior |= prior & THRD_PRIOR_MASK;
+}
+
+/*
+ * Set thread security attribute.
+ *
+ * Parameters :
+ *  pth         -     pointer of thread context
+ *  attr_secure -     THRD_ATTR_SECURE or THRD_ATTR_NON_SECURE
+ *
+ * Notes
+ *  Reuse prior of thread context to shift down non-secure thread priority.
+ */
+void __STATIC_INLINE tfm_thrd_secure(struct tfm_thrd_ctx *pth,
+                                     uint32_t attr_secure)
+{
+    pth->prior &= ~THRD_ATTR_NON_SECURE;
+    pth->prior |= attr_secure;
+}
+
+/*
+ * Set thread status.
+ *
+ * Parameters :
+ *  pth         -     pointer of thread context
+ *  new_status  -     new status of thread
+ *
+ * Return :
+ *  None
+ *
+ * Notes :
+ *  Thread status is not changed if invalid status value inputed.
+ */
+void tfm_thrd_set_status(struct tfm_thrd_ctx *pth, uint32_t new_status);
+
+/*
+ * Get thread status.
+ *
+ * Parameters :
+ *  pth         -     pointer of thread context
+ *
+ * Return :
+ *  Status of thread
+ */
+uint32_t __STATIC_INLINE tfm_thrd_get_status(struct tfm_thrd_ctx *pth)
+{
+    return pth->status;
+}
+
+/*
+ * Set thread state return value.
+ *
+ * Parameters :
+ *  pth         -     pointer of thread context
+ *  retval      -     return value to be set for thread state
+ *
+ * Notes :
+ *  This API is useful for blocked syscall blocking thread. Syscall
+ *  could set its return value to the caller before caller goes.
+ */
+void __STATIC_INLINE tfm_thrd_set_retval(struct tfm_thrd_ctx *pth,
+                                         uint32_t retval)
+{
+    TFM_STATE_RET_VAL(&pth->state_ctx) = retval;
+}
+
+/*
+ * Validate thread context and insert it into schedulable list.
+ *
+ * Parameters :
+ *  pth         -     pointer of thread context
+ *
+ * Return :
+ *  THRD_SUCCESS for success. Or an error is returned.
+ *
+ * Notes :
+ *  This function validates thread info. It returns error if thread info
+ *  is not correct. Thread is avaliable after successful tfm_thrd_start().
+ */
+uint32_t tfm_thrd_start(struct tfm_thrd_ctx *pth);
+
+/*
+ * Get current running thread.
+ *
+ * Return :
+ *  Current running thread context pointer.
+ */
+struct tfm_thrd_ctx *tfm_thrd_curr_thread(void);
+
+/*
+ * Get next running thread in list.
+ *
+ * Return :
+ *  Pointer of next thread to be run.
+ */
+struct tfm_thrd_ctx *tfm_thrd_next_thread(void);
+
+/*
+ * Activate a scheduling action after exception.
+ *
+ * Notes :
+ *  This function could be called multiple times before scheduling.
+ */
+void tfm_thrd_activate_schedule(void);
+
+/*
+ * Save current context into 'prev' thread and switch to 'next'.
+ *
+ * Parameters :
+ *  ctxb        -     latest caller context
+ *  prev        -     previous thread to be switched out
+ *  next        -     thread to be run
+ *
+ * Notes :
+ *  This function could be called multiple times before scheduling.
+ */
+void tfm_thrd_context_switch(struct tfm_state_context_ext *ctxb,
+                             struct tfm_thrd_ctx *prev,
+                             struct tfm_thrd_ctx *next);
+
+/*
+ * Exit current running thread.
+ *
+ * Notes :
+ *  Remove current thread out of schedulable list.
+ */
+void tfm_thrd_do_exit(void);
+
+/*
+ * PendSV specified function.
+ *
+ * Parameters :
+ *  ctxb        -    State context storage pointer
+ *
+ * Notes:
+ *  This is a staging API. Scheduler should be called in SPM finally and
+ *  this function will be obsoleted later.
+ */
+void tfm_pendsv_do_schedule(struct tfm_state_context_ext *ctxb);
+
+#endif
diff --git a/secure_fw/core/ipc/include/tfm_utils.h b/secure_fw/core/ipc/include/tfm_utils.h
new file mode 100644
index 0000000..17f94c0
--- /dev/null
+++ b/secure_fw/core/ipc/include/tfm_utils.h
@@ -0,0 +1,29 @@
+/*
+ * Copyright (c) 2018-2019, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
+ */
+#ifndef __TFM_UTILS_H__
+#define __TFM_UTILS_H__
+
+/* CPU spin here */
+void tfm_panic(void);
+
+/* Assert and spin */
+#define TFM_ASSERT(cond)                                            \
+            do {                                                    \
+                if (!(cond)) {                                      \
+                    printf("Assert:%s:%d", __FUNCTION__, __LINE__); \
+                    while (1)                                       \
+                        ;                                           \
+                }                                                   \
+            } while (0)
+
+/* Get container structure start address from member */
+#define TFM_GET_CONTAINER_PTR(ptr, type, member) \
+    (type *)((unsigned long)(ptr) - offsetof(type, member))
+
+int32_t tfm_bitcount(uint32_t n);
+
+#endif
diff --git a/secure_fw/core/ipc/include/tfm_wait.h b/secure_fw/core/ipc/include/tfm_wait.h
new file mode 100644
index 0000000..2bed0ae
--- /dev/null
+++ b/secure_fw/core/ipc/include/tfm_wait.h
@@ -0,0 +1,86 @@
+/*
+ * Copyright (c) 2018-2019, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
+ */
+#ifndef __TFM_WAIT_H__
+#define __TFM_WAIT_H__
+
+#include "cmsis_compiler.h"
+
+#define EVENT_MAGIC               0x65766e74
+#define EVENT_STAT_WAITED         0x0
+#define EVENT_STAT_SIGNALED       0x1
+
+struct tfm_event_ctx {
+    uint32_t magic;               /* 'evnt'              */
+    struct tfm_thrd_ctx *owner;   /* waiting thread      */
+    uint32_t status;              /* status              */
+    uint32_t retval;              /* return value        */
+};
+
+/*
+ * Initialize an event context.
+ *
+ * Parameters :
+ *  pevt        -    pointer of event context caller provided
+ *  stat        -    initial status (EVENT_STAT_WAITED or EVENT_STAT_SIGNALED)
+ */
+void __STATIC_INLINE tfm_event_init(struct tfm_event_ctx *pevt, uint32_t stat)
+{
+    pevt->magic = EVENT_MAGIC;
+    pevt->status = stat;
+    pevt->owner = NULL;
+    pevt->retval = 0;
+}
+
+/*
+ * Wait on an event.
+ *
+ * Parameters :
+ *  pevt        -    pointer of event context
+ *
+ * Notes :
+ *  Thread is blocked if event is not signaled.
+ */
+void tfm_event_wait(struct tfm_event_ctx *pevt);
+
+/*
+ * Signal an event.
+ *
+ * Parameters :
+ *  pevt        -    pointer of event context
+ *
+ * Notes :
+ *  Waiting thread on this event will be running.
+ */
+void tfm_event_signal(struct tfm_event_ctx *pevt);
+
+/*
+ * Peek an event status.
+ *
+ * Parameters :
+ *  pevt        -    pointer of event context
+ *
+ * Return :
+ *  Status of event.
+ *
+ * Notes :
+ *  This function is used for getting event status without blocking thread.
+ */
+uint32_t tfm_event_peek(struct tfm_event_ctx *pevt);
+
+/*
+ * Set event owner return value.
+ *
+ * Parameters :
+ *  pevt        -    pointer of event context
+ *  retval      -    return value of blocked owner thread
+ *
+ * Notes :
+ *  Thread return value is set while thread is to be running.
+ */
+void tfm_event_owner_retval(struct tfm_event_ctx *pevt, uint32_t retval);
+
+#endif
diff --git a/secure_fw/core/ipc/psa_client.c b/secure_fw/core/ipc/psa_client.c
new file mode 100644
index 0000000..f8fe605
--- /dev/null
+++ b/secure_fw/core/ipc/psa_client.c
@@ -0,0 +1,55 @@
+/*
+ * Copyright (c) 2018-2019, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
+ */
+
+#include <inttypes.h>
+#include <stdio.h>
+#include "tfm_svc.h"
+#include "psa_client.h"
+
+__attribute__((naked))
+uint32_t psa_framework_version(void)
+{
+    __ASM("SVC %0           \n"
+          "BX LR            \n"
+          : : "I" (TFM_SVC_PSA_FRAMEWORK_VERSION));
+}
+
+__attribute__((naked))
+uint32_t psa_version(uint32_t sid)
+{
+    __ASM("SVC %0           \n"
+          "BX LR            \n"
+          : : "I" (TFM_SVC_PSA_VERSION));
+}
+
+__attribute__((naked))
+psa_handle_t psa_connect(uint32_t sid, uint32_t minor_version)
+{
+    __ASM("SVC %0           \n"
+          "BX LR            \n"
+          : : "I" (TFM_SVC_PSA_CONNECT));
+}
+
+__attribute__((naked))
+psa_status_t psa_call(psa_handle_t handle,
+                      const psa_invec *in_vec,
+                      size_t in_len,
+                      psa_outvec *out_vec,
+                      size_t out_len)
+{
+    __ASM("SVC %0           \n"
+          "BX LR            \n"
+          : : "I" (TFM_SVC_PSA_CALL));
+}
+
+__attribute__((naked))
+void psa_close(psa_handle_t handle)
+{
+    __ASM("SVC %0           \n"
+          "BX LR            \n"
+          : : "I" (TFM_SVC_PSA_CLOSE));
+}
diff --git a/secure_fw/core/ipc/psa_service.c b/secure_fw/core/ipc/psa_service.c
new file mode 100644
index 0000000..4871971
--- /dev/null
+++ b/secure_fw/core/ipc/psa_service.c
@@ -0,0 +1,96 @@
+/*
+ * Copyright (c) 2018-2019, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
+ */
+
+#include <inttypes.h>
+#include <stdio.h>
+#include "tfm_svc.h"
+#include "psa_client.h"
+#include "psa_service.h"
+
+__attribute__((naked))
+psa_signal_t psa_wait(psa_signal_t signal_mask, uint32_t timeout)
+
+{
+    __ASM("SVC %0           \n"
+          "BX LR            \n"
+          : : "I" (TFM_SVC_PSA_WAIT));
+}
+
+__attribute__((naked))
+psa_status_t psa_get(psa_signal_t signal, psa_msg_t *msg)
+{
+    __ASM("SVC %0           \n"
+          "BX LR            \n"
+          : : "I" (TFM_SVC_PSA_GET));
+}
+
+__attribute__((naked))
+void psa_set_rhandle(psa_handle_t msg_handle, void *rhandle)
+{
+    __ASM("SVC %0           \n"
+          "BX LR            \n"
+          : : "I" (TFM_SVC_PSA_SET_RHANDLE));
+}
+
+__attribute__((naked))
+size_t psa_read(psa_handle_t msg_handle, uint32_t invec_idx,
+                void *buffer, size_t num_bytes)
+
+{
+    __ASM("SVC %0           \n"
+          "BX LR            \n"
+          : : "I" (TFM_SVC_PSA_READ));
+}
+
+__attribute__((naked))
+size_t psa_skip(psa_handle_t msg_handle, uint32_t invec_idx, size_t num_bytes)
+{
+    __ASM("SVC %0           \n"
+          "BX LR            \n"
+          : : "I" (TFM_SVC_PSA_SKIP));
+}
+
+__attribute__((naked))
+void psa_write(psa_handle_t msg_handle, uint32_t outvec_idx,
+               const void *buffer, size_t num_bytes)
+{
+    __ASM("SVC %0           \n"
+          "BX LR            \n"
+          : : "I" (TFM_SVC_PSA_WRITE));
+}
+
+__attribute__((naked))
+void psa_reply(psa_handle_t msg_handle, psa_status_t retval)
+{
+    __ASM("SVC %0           \n"
+          "BX LR            \n"
+          : : "I" (TFM_SVC_PSA_REPLY));
+}
+
+__attribute__((naked))
+void psa_notify(int32_t partition_id)
+{
+    __ASM("SVC %0           \n"
+          "BX LR            \n"
+          : : "I" (TFM_SVC_PSA_NOTIFY));
+}
+
+__attribute__((naked))
+void psa_clear(void)
+{
+    __ASM("SVC %0           \n"
+          "BX LR            \n"
+          : : "I" (TFM_SVC_PSA_CLEAR));
+}
+
+__attribute__((naked))
+void psa_eoi(psa_signal_t irq_signal)
+{
+    __ASM("SVC %0           \n"
+          "BX LR            \n"
+          : : "I" (TFM_SVC_PSA_EOI));
+}
diff --git a/secure_fw/core/ipc/tfm_arch_v8m.c b/secure_fw/core/ipc/tfm_arch_v8m.c
new file mode 100644
index 0000000..4c976fd
--- /dev/null
+++ b/secure_fw/core/ipc/tfm_arch_v8m.c
@@ -0,0 +1,124 @@
+/*
+ * Copyright (c) 2018-2019, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
+ */
+#include <inttypes.h>
+#include <stdio.h>
+
+#include "tfm_arch_v8m.h"
+#include "cmsis.h"
+#include "psa_client.h"
+#include "psa_service.h"
+#include "tfm_utils.h"
+#include "tfm_thread.h"
+#include "tfm_memory_utils.h"
+
+/* This file contains the ARCH code for ARM V8M */
+
+/*
+ * Thread exit zone.
+ * This function is set as the return address of thread entry and only
+ * privileged thread could return here. Un-privileged thread triggers
+ * fault if it tries to jump here and it gets exit by fault handler.
+ *
+ * The reason of putting this function here is for fault handler checking.
+ * Function address could be checked in fault handler to know it is a REAL
+ * thread exit or just an exception.
+ */
+static void exit_zone(void)
+{
+    tfm_thrd_do_exit();
+}
+
+void tfm_initialize_context(struct tfm_state_context *ctx,
+                            uint32_t r0, uint32_t ra,
+                            uint32_t sp, uint32_t sp_limit)
+{
+    /*
+     * For security consideration, set unused registers into ZERO;
+     * and only necessary registers are set here.
+     */
+    struct tfm_state_context_base *p_ctxa =
+                            (struct tfm_state_context_base *)sp;
+
+    /*
+     * Shift back SP to leave space for holding base context
+     * since thread is kicked off through exception return.
+     */
+    p_ctxa--;
+
+    /* Basic context is considerate at thread start.*/
+    tfm_memset(p_ctxa, 0, sizeof(*p_ctxa));
+    p_ctxa->r0 = r0;
+    p_ctxa->ra = ra;
+    p_ctxa->ra_lr = (uint32_t)exit_zone;
+    p_ctxa->xpsr = XPSR_T32;
+
+    tfm_memset(ctx, 0, sizeof(*ctx));
+    ctx->ctxb.sp = (uint32_t)p_ctxa;
+    ctx->ctxb.sp_limit = sp_limit;
+    ctx->ctxb.lr = LR_UNPRIVILEGED;
+}
+
+/*
+ * Stack status at PendSV entry:
+ *
+ *                                            [ R0 - R3  ]<- PSP
+ *                                            [ R12      ]
+ *                                            [ LR_of_RA ]
+ *                       MSP->[ ........ ]    [ RA       ]
+ *                            [ ........ ]    [ XPSR     ]
+ *                                            [ ........ ]
+ *                                            [ ........ ]
+ *
+ * Stack status before calling pendsv_do_schedule():
+ *
+ *                       MSP->[ R4 - R11 ]
+ *                            [ PSP      ]--->[ R0 - R3  ]
+ *                            [ PSP Limit]    [ R12      ]
+ *                            [ R2(dummy)]    [ LR_of_RA ]
+ *                            [ LR       ]    [ RA       ]
+ *                            [ ........ ]    [ XPSR     ]
+ *                            [ ........ ]    [ ........ ]
+ *                                            [ ........ ]
+ *
+ * pendsv_do_schedule() updates stacked context into current thread and
+ * replace stacked context with context of next thread.
+ *
+ * Scheduler does not support handler mode thread so take PSP/PSP_LIMIT as
+ * thread SP/SP_LIMIT. R2 holds dummy data due to stack operation is 8 bytes
+ * aligned.
+ */
+__attribute__((naked)) void PendSV_Handler(void)
+{
+    __ASM(
+        "mrs     r0, psp                    \n"
+        "mrs     r1, psplim                 \n"
+        "push    {r0, r1, r2, lr}           \n"
+        "push    {r4-r11}                   \n"
+        "mov     r0, sp                     \n"
+        "bl      tfm_pendsv_do_schedule     \n"
+        "pop     {r4-r11}                   \n"
+        "pop     {r0, r1, r2, lr}           \n"
+        "msr     psp, r0                    \n"
+        "msr     psplim, r1                 \n"
+        "bx      lr                         \n"
+    );
+}
+
+/* Reserved for future usage */
+__attribute__((naked)) void MemManage_Handler(void)
+{
+    __ASM("b    .");
+}
+
+__attribute__((naked)) void BusFault_Handler(void)
+{
+    __ASM("b    .");
+}
+__attribute__((naked)) void UsageFault_Handler(void)
+{
+    __ASM("b    .");
+}
diff --git a/secure_fw/core/ipc/tfm_message_queue.c b/secure_fw/core/ipc/tfm_message_queue.c
new file mode 100644
index 0000000..83ebf50
--- /dev/null
+++ b/secure_fw/core/ipc/tfm_message_queue.c
@@ -0,0 +1,56 @@
+/*
+ * Copyright (c) 2018, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
+ */
+#include <inttypes.h>
+#include <stdio.h>
+#include "tfm_thread.h"
+#include "tfm_wait.h"
+#include "psa_client.h"
+#include "psa_service.h"
+#include "tfm_internal_defines.h"
+#include "tfm_message_queue.h"
+
+/* Message queue process */
+int32_t tfm_msg_enqueue(struct tfm_msg_queue_t *queue,
+                        struct tfm_msg_body_t *node)
+{
+    if (!queue || !node) {
+        return IPC_ERROR_BAD_PARAMETERS;
+    }
+
+    if (queue->size == 0) {
+        queue->head = node;
+        queue->tail = node;
+    } else {
+        queue->tail->next = node;
+        queue->tail = node;
+    }
+    queue->size++;
+    return IPC_SUCCESS;
+}
+
+struct tfm_msg_body_t *tfm_msg_dequeue(struct tfm_msg_queue_t *queue)
+{
+    struct tfm_msg_body_t *pop_node;
+
+    if (!queue) {
+        return NULL;
+    }
+
+    if (queue->size == 0) {
+        return NULL;
+    }
+
+    pop_node = queue->head;
+    queue->head = queue->head->next;
+    queue->size--;
+    return pop_node;
+}
+
+int32_t tfm_msg_queue_is_empty(struct tfm_msg_queue_t *queue)
+{
+    return queue->size == 0 ? 1 : 0;
+}
diff --git a/secure_fw/core/ipc/tfm_pools.c b/secure_fw/core/ipc/tfm_pools.c
new file mode 100644
index 0000000..83342b8
--- /dev/null
+++ b/secure_fw/core/ipc/tfm_pools.c
@@ -0,0 +1,87 @@
+/*
+ * Copyright (c) 2018-2019, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
+ */
+#include <inttypes.h>
+#include <stdbool.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include "tfm_thread.h"
+#include "tfm_wait.h"
+#include "psa_client.h"
+#include "psa_service.h"
+#include "tfm_internal_defines.h"
+#include "cmsis_compiler.h"
+#include "tfm_utils.h"
+#include "tfm_list.h"
+#include "tfm_pools.h"
+#include "tfm_memory_utils.h"
+
+int32_t tfm_pool_init(struct tfm_pool_instance_t *pool, size_t poolsz,
+                      size_t chunksz, size_t num)
+{
+    struct tfm_pool_chunk_t *pchunk;
+    size_t i;
+
+    if (!pool || num == 0) {
+        return IPC_ERROR_BAD_PARAMETERS;
+    }
+
+    /* Ensure buffer is large enough */
+    if (poolsz != ((chunksz + sizeof(struct tfm_pool_chunk_t)) * num +
+        sizeof(struct tfm_pool_instance_t))) {
+        return IPC_ERROR_BAD_PARAMETERS;
+    }
+
+    /* Buffer should be BSS cleared but clear it again */
+    tfm_memset(pool, 0, poolsz);
+
+    /* Chain pool chunks */
+    tfm_list_init(&pool->chunks_list);
+
+    pchunk = (struct tfm_pool_chunk_t *)pool->chunks;
+    for (i = 0; i < num; i++) {
+        pchunk->pool = pool;
+        tfm_list_add_tail(&pool->chunks_list, &pchunk->list);
+        pchunk = (struct tfm_pool_chunk_t *)&pchunk->data[chunksz];
+    }
+
+    /* Prepare instance and insert to pool list */
+    pool->chunksz = chunksz;
+
+    return IPC_SUCCESS;
+}
+
+void *tfm_pool_alloc(struct tfm_pool_instance_t *pool)
+{
+    struct tfm_list_node_t *node;
+    struct tfm_pool_chunk_t *pchunk;
+
+    if (!pool) {
+        return NULL;
+    }
+
+    if (tfm_list_is_empty(&pool->chunks_list)) {
+        return NULL;
+    }
+
+    node = tfm_list_first_node(&pool->chunks_list);
+    pchunk = TFM_GET_CONTAINER_PTR(node, struct tfm_pool_chunk_t, list);
+
+    /* Remove node from list node, it will be added when pool free */
+    tfm_list_del_node(node);
+
+    return &pchunk->data;
+}
+
+void tfm_pool_free(void *ptr)
+{
+    struct tfm_pool_chunk_t *pchunk;
+    struct tfm_pool_instance_t *pool;
+
+    pchunk = TFM_GET_CONTAINER_PTR(ptr, struct tfm_pool_chunk_t, data);
+    pool = (struct tfm_pool_instance_t *)pchunk->pool;
+    tfm_list_add_tail(&pool->chunks_list, &pchunk->list);
+}
diff --git a/secure_fw/core/ipc/tfm_spm.c b/secure_fw/core/ipc/tfm_spm.c
new file mode 100644
index 0000000..a019a9f
--- /dev/null
+++ b/secure_fw/core/ipc/tfm_spm.c
@@ -0,0 +1,617 @@
+/*
+ * Copyright (c) 2018-2019, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
+ */
+#include <inttypes.h>
+#include <limits.h>
+#include <stdbool.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include "psa_client.h"
+#include "psa_service.h"
+#include "tfm_utils.h"
+#include "spm_api.h"
+#include "spm_db.h"
+#include "spm_db_setup.h"
+#include "tfm_internal_defines.h"
+#include "tfm_wait.h"
+#include "tfm_message_queue.h"
+#include "tfm_list.h"
+#include "tfm_pools.h"
+#include "tfm_spm.h"
+#include "tfm_spm_signal_defs.h"
+#include "tfm_thread.h"
+#include "region_defs.h"
+#include "tfm_nspm.h"
+#include "tfm_memory_utils.h"
+
+/*
+ * IPC partitions.
+ * FixMe: Need to get align with spm_partition_db_t.
+ */
+static struct tfm_spm_ipc_partition_t
+                    g_spm_ipc_partition[SPM_MAX_PARTITIONS] = {};
+
+/* Extern SPM variable */
+extern struct spm_partition_db_t g_spm_partition_db;
+
+/* Pools */
+TFM_POOL_DECLARE(conn_handle_pool, sizeof(struct tfm_conn_handle_t),
+                 TFM_CONN_HANDLE_MAX_NUM);
+TFM_POOL_DECLARE(spm_service_pool, sizeof(struct tfm_spm_service_t),
+                 TFM_SPM_MAX_ROT_SERV_NUM);
+TFM_POOL_DECLARE(msg_db_pool, sizeof(struct tfm_msg_body_t),
+                 TFM_MSG_QUEUE_MAX_MSG_NUM);
+
+static struct tfm_spm_service_db_t g_spm_service_db[] = {
+    #include "secure_fw/services/tfm_service_list.inc"
+};
+
+/********************** SPM functions for handler mode ***********************/
+
+/* Service handle management functions */
+psa_handle_t tfm_spm_create_conn_handle(struct tfm_spm_service_t *service)
+{
+    struct tfm_conn_handle_t *node;
+
+    TFM_ASSERT(service);
+
+    /* Get buffer for handle list structure from handle pool */
+    node = (struct tfm_conn_handle_t *)tfm_pool_alloc(conn_handle_pool);
+    if (!node) {
+        return PSA_NULL_HANDLE;
+    }
+
+    /* Global unique handle, use handle buffer address directly */
+    node->handle = (psa_handle_t)node;
+
+    /* Add handle node to list for next psa functions */
+    tfm_list_add_tail(&service->handle_list, &node->list);
+
+    return node->handle;
+}
+
+static struct tfm_conn_handle_t *
+tfm_spm_find_conn_handle_node(struct tfm_spm_service_t *service,
+                              psa_handle_t conn_handle)
+{
+    struct tfm_conn_handle_t *handle_node;
+    struct tfm_list_node_t *node, *head;
+
+    TFM_ASSERT(service);
+
+    head = &service->handle_list;
+    TFM_LIST_FOR_EACH(node, head) {
+        handle_node = TFM_GET_CONTAINER_PTR(node, struct tfm_conn_handle_t,
+                                            list);
+        if (handle_node->handle == conn_handle) {
+            return handle_node;
+        }
+    }
+    return NULL;
+}
+
+int32_t tfm_spm_free_conn_handle(struct tfm_spm_service_t *service,
+                                 psa_handle_t conn_handle)
+{
+    struct tfm_conn_handle_t *node;
+
+    TFM_ASSERT(service);
+
+    /* There are many handles for each RoT Service */
+    node = tfm_spm_find_conn_handle_node(service, conn_handle);
+    if (!node) {
+        tfm_panic();
+    }
+
+    /* Remove node from handle list */
+    tfm_list_del_node(&node->list);
+
+    /* Back handle buffer to pool */
+    tfm_pool_free(node);
+    return IPC_SUCCESS;
+}
+
+int32_t tfm_spm_set_rhandle(struct tfm_spm_service_t *service,
+                            psa_handle_t conn_handle,
+                            void *rhandle)
+{
+    struct tfm_conn_handle_t *node;
+
+    TFM_ASSERT(service);
+    /* Set reverse handle value only be allowed for a connected handle */
+    TFM_ASSERT(conn_handle != PSA_NULL_HANDLE);
+
+    /* There are many handles for each RoT Service */
+    node = tfm_spm_find_conn_handle_node(service, conn_handle);
+    if (!node) {
+        tfm_panic();
+    }
+
+    node->rhandle = rhandle;
+    return IPC_SUCCESS;
+}
+
+void *tfm_spm_get_rhandle(struct tfm_spm_service_t *service,
+                          psa_handle_t conn_handle)
+{
+    struct tfm_conn_handle_t *node;
+
+    TFM_ASSERT(service);
+    /* Get reverse handle value only be allowed for a connected handle */
+    TFM_ASSERT(conn_handle != PSA_NULL_HANDLE);
+
+    /* There are many handles for each RoT Service */
+    node = tfm_spm_find_conn_handle_node(service, conn_handle);
+    if (!node) {
+        tfm_panic();
+    }
+
+    return node->rhandle;
+}
+
+/* Partition management functions */
+struct tfm_spm_service_t *
+tfm_spm_get_service_by_signal(struct tfm_spm_ipc_partition_t *partition,
+                              psa_signal_t signal)
+{
+    struct tfm_list_node_t *node, *head;
+    struct tfm_spm_service_t *service;
+
+    TFM_ASSERT(partition);
+
+    if (tfm_list_is_empty(&partition->service_list)) {
+        tfm_panic();
+    }
+
+    head = &partition->service_list;
+    TFM_LIST_FOR_EACH(node, head) {
+        service = TFM_GET_CONTAINER_PTR(node, struct tfm_spm_service_t, list);
+        if (service->service_db->signal == signal) {
+            return service;
+        }
+    }
+    return NULL;
+}
+
+struct tfm_spm_service_t *tfm_spm_get_service_by_sid(uint32_t sid)
+{
+    uint32_t i;
+    struct tfm_list_node_t *node, *head;
+    struct tfm_spm_service_t *service;
+
+    for (i = 0; i < SPM_MAX_PARTITIONS; i++) {
+        /* Skip partition without IPC flag */
+        if ((tfm_spm_partition_get_flags(g_spm_ipc_partition[i].index) &
+            SPM_PART_FLAG_IPC) == 0) {
+            continue;
+        }
+
+        if (tfm_list_is_empty(&g_spm_ipc_partition[i].service_list)) {
+            continue;
+        }
+
+        head = &g_spm_ipc_partition[i].service_list;
+        TFM_LIST_FOR_EACH(node, head) {
+            service = TFM_GET_CONTAINER_PTR(node, struct tfm_spm_service_t,
+                                            list);
+            if (service->service_db->sid == sid) {
+                return service;
+            }
+        }
+    }
+    return NULL;
+}
+
+struct tfm_spm_service_t *
+    tfm_spm_get_service_by_handle(psa_handle_t conn_handle)
+{
+    uint32_t i;
+    struct tfm_conn_handle_t *handle;
+    struct tfm_list_node_t *service_node, *service_head;
+    struct tfm_list_node_t *handle_node, *handle_head;
+    struct tfm_spm_service_t *service;
+
+    for (i = 0; i < SPM_MAX_PARTITIONS; i++) {
+        /* Skip partition without IPC flag */
+        if ((tfm_spm_partition_get_flags(g_spm_ipc_partition[i].index) &
+            SPM_PART_FLAG_IPC) == 0) {
+            continue;
+        }
+
+        if (tfm_list_is_empty(&g_spm_ipc_partition[i].service_list)) {
+            continue;
+        }
+
+        service_head = &g_spm_ipc_partition[i].service_list;
+        TFM_LIST_FOR_EACH(service_node, service_head) {
+            service = TFM_GET_CONTAINER_PTR(service_node,
+                                            struct tfm_spm_service_t, list);
+            handle_head = &service->handle_list;
+            TFM_LIST_FOR_EACH(handle_node, handle_head) {
+                handle = TFM_GET_CONTAINER_PTR(handle_node,
+                                               struct tfm_conn_handle_t, list);
+                if (handle->handle == conn_handle) {
+                    return service;
+                }
+            }
+        }
+    }
+    return NULL;
+}
+
+struct tfm_spm_ipc_partition_t *
+    tfm_spm_get_partition_by_id(int32_t partition_id)
+{
+    uint32_t i;
+
+    for (i = 0; i < SPM_MAX_PARTITIONS; i++) {
+        if (g_spm_ipc_partition[i].id == partition_id) {
+            return &g_spm_ipc_partition[i];
+        }
+    }
+    return NULL;
+}
+
+struct tfm_spm_ipc_partition_t *tfm_spm_get_running_partition(void)
+{
+    uint32_t spid;
+
+    spid = tfm_spm_partition_get_running_partition_id_ext();
+
+    return tfm_spm_get_partition_by_id(spid);
+}
+
+int32_t tfm_spm_check_client_version(struct tfm_spm_service_t *service,
+                                     uint32_t minor_version)
+{
+    TFM_ASSERT(service);
+
+    switch (service->service_db->minor_policy) {
+    case TFM_VERSION_POLICY_RELAXED:
+        if (minor_version < service->service_db->minor_version) {
+            return IPC_ERROR_VERSION;
+        }
+        break;
+    case TFM_VERSION_POLICY_STRICT:
+        if (minor_version != service->service_db->minor_version) {
+            return IPC_ERROR_VERSION;
+        }
+        break;
+    default:
+        return IPC_ERROR_VERSION;
+    }
+    return IPC_SUCCESS;
+}
+
+/* Message functions */
+struct tfm_msg_body_t *tfm_spm_get_msg_from_handle(psa_handle_t msg_handle)
+{
+    /*
+     * There may be one error handle passed by the caller in two conditions:
+     *   1. Not a valid message handle.
+     *   2. Handle between different Partitions. Partition A passes one handle
+     *   belong to other Partitions and tries to access other's data.
+     * So, need do necessary checking to prevent those conditions.
+     */
+    struct tfm_msg_body_t *msg;
+    uint32_t partition_id;
+
+    msg = (struct tfm_msg_body_t *)msg_handle;
+    if (!msg) {
+        return NULL;
+    }
+
+    /*
+     * FixMe: For condition 1: using a magic number to define it's a message.
+     * It needs to be an enhancement to check the handle belong to service.
+     */
+    if (msg->magic != TFM_MSG_MAGIC) {
+        return NULL;
+    }
+
+    /* For condition 2: check if the partition ID is same */
+    partition_id = tfm_spm_partition_get_running_partition_id_ext();
+    if (partition_id != msg->service->partition->id) {
+        return NULL;
+    }
+
+    return msg;
+}
+
+struct tfm_msg_body_t *tfm_spm_create_msg(struct tfm_spm_service_t *service,
+                                          psa_handle_t handle,
+                                          uint32_t type, int32_t ns_caller,
+                                          psa_invec *invec, size_t in_len,
+                                          psa_outvec *outvec, size_t out_len,
+                                          psa_outvec *caller_outvec)
+{
+    struct tfm_msg_body_t *msg = NULL;
+    uint32_t i;
+
+    TFM_ASSERT(service);
+    TFM_ASSERT(!(invec == NULL && in_len != 0));
+    TFM_ASSERT(!(outvec == NULL && out_len != 0));
+    TFM_ASSERT(in_len <= PSA_MAX_IOVEC);
+    TFM_ASSERT(out_len <= PSA_MAX_IOVEC);
+    TFM_ASSERT(in_len + out_len <= PSA_MAX_IOVEC);
+
+    /* Get message buffer from message pool */
+    msg = (struct tfm_msg_body_t *)tfm_pool_alloc(msg_db_pool);
+    if (!msg) {
+        return NULL;
+    }
+
+    /* Clear message buffer before using it */
+    tfm_memset(msg, 0, sizeof(struct tfm_msg_body_t));
+
+    tfm_event_init(&msg->ack_mtx, EVENT_STAT_WAITED);
+    msg->magic = TFM_MSG_MAGIC;
+    msg->service = service;
+    msg->handle = handle;
+    msg->caller_outvec = caller_outvec;
+    /* Get current partition id */
+    if (ns_caller) {
+        msg->msg.client_id = tfm_nspm_get_current_client_id();
+    } else {
+        msg->msg.client_id = tfm_spm_partition_get_running_partition_id_ext();
+    }
+
+    /* Copy contents */
+    msg->msg.type = type;
+
+    for (i = 0; i < in_len; i++) {
+        msg->msg.in_size[i] = invec[i].len;
+        msg->invec[i].base = invec[i].base;
+    }
+
+    for (i = 0; i < out_len; i++) {
+        msg->msg.out_size[i] = outvec[i].len;
+        msg->outvec[i].base = outvec[i].base;
+        /* Out len is used to record the writed number, set 0 here again */
+        msg->outvec[i].len = 0;
+    }
+
+    /* Use message address as handle */
+    msg->msg.handle = (psa_handle_t)msg;
+
+    /* For connected handle, set rhandle to every message */
+    if (handle != PSA_NULL_HANDLE) {
+        msg->msg.rhandle = tfm_spm_get_rhandle(service, handle);
+    }
+
+    return msg;
+}
+
+void tfm_spm_free_msg(struct tfm_msg_body_t *msg)
+{
+    tfm_pool_free(msg);
+}
+
+int32_t tfm_spm_send_event(struct tfm_spm_service_t *service,
+                           struct tfm_msg_body_t *msg)
+{
+    TFM_ASSERT(service);
+    TFM_ASSERT(msg);
+
+    /* Enqueue message to service message queue */
+    if (tfm_msg_enqueue(&service->msg_queue, msg) != IPC_SUCCESS) {
+        return IPC_ERROR_GENERIC;
+    }
+
+    /* Messages put. Update signals */
+    service->partition->signals |= service->service_db->signal;
+
+    /* Save return value for blocked threads */
+    tfm_event_owner_retval(&service->partition->signal_event,
+                           service->partition->signals &
+                           service->partition->signal_mask);
+
+    /* Wake waiting thread up */
+    tfm_event_signal(&service->partition->signal_event);
+
+    tfm_event_wait(&msg->ack_mtx);
+
+    return IPC_SUCCESS;
+}
+
+/* SPM extend functions */
+uint32_t tfm_spm_partition_get_running_partition_id_ext(void)
+{
+    struct tfm_thrd_ctx *pth = tfm_thrd_curr_thread();
+    struct spm_partition_desc_t *partition;
+
+    partition = TFM_GET_CONTAINER_PTR(pth, struct spm_partition_desc_t,
+                                      sp_thrd);
+    return partition->static_data.partition_id;
+}
+
+static struct tfm_thrd_ctx *
+tfm_spm_partition_get_thread_info_ext(uint32_t partition_idx)
+{
+    return &g_spm_partition_db.partitions[partition_idx].sp_thrd;
+}
+
+static uint32_t tfm_spm_partition_get_stack_base_ext(uint32_t partition_idx)
+{
+    return (uint32_t)&(g_spm_partition_db.partitions[partition_idx].
+                       stack[TFM_STACK_SIZE]);
+}
+
+static uint32_t tfm_spm_partition_get_stack_limit_ext(uint32_t partition_idx)
+{
+    return (uint32_t)&g_spm_partition_db.partitions[partition_idx].stack;
+}
+
+static tfm_thrd_func_t
+        tfm_spm_partition_get_init_func_ext(uint32_t partition_idx)
+{
+    return (tfm_thrd_func_t)(g_spm_partition_db.partitions[partition_idx].
+                             static_data.partition_init);
+}
+
+static uint32_t tfm_spm_partition_get_priority_ext(uint32_t partition_idx)
+{
+    return g_spm_partition_db.partitions[partition_idx].static_data.
+                    partition_priority;
+}
+
+/* Macros to pick linker symbols and allow references to sections in all level*/
+#define REGION_DECLARE_EXT(a, b, c) extern uint32_t REGION_NAME(a, b, c)
+
+REGION_DECLARE_EXT(Image$$, ER_TFM_DATA, $$ZI$$Base);
+REGION_DECLARE_EXT(Image$$, ER_TFM_DATA, $$ZI$$Limit);
+REGION_DECLARE_EXT(Image$$, ER_TFM_DATA, $$RW$$Base);
+REGION_DECLARE_EXT(Image$$, ER_TFM_DATA, $$RW$$Limit);
+REGION_DECLARE_EXT(Image$$, TFM_SECURE_STACK, $$ZI$$Base);
+REGION_DECLARE_EXT(Image$$, TFM_SECURE_STACK, $$ZI$$Limit);
+REGION_DECLARE_EXT(Image$$, TFM_UNPRIV_SCRATCH, $$ZI$$Base);
+REGION_DECLARE_EXT(Image$$, TFM_UNPRIV_SCRATCH, $$ZI$$Limit);
+
+/*
+ * \brief                         Check the memory whether in the given range.
+ *
+ * \param[in] buffer              Pointer of memory reference
+ * \param[in] len                 Length of memory reference in bytes
+ * \param[in] base                The base address
+ * \param[in] limit               The limit address, the first byte of next
+ *                                area memory
+ *
+ * \retval IPC_SUCCESS            Success
+ * \retval IPC_ERROR_MEMORY_CHECK Check failed
+ */
+static int32_t memory_check_range(const void *buffer, size_t len,
+                                  uintptr_t base, uintptr_t limit)
+{
+    if (((uintptr_t)buffer >= base) &&
+        ((uintptr_t)((uint8_t *)buffer + len - 1) < limit)) {
+        return IPC_SUCCESS;
+    }
+    return IPC_ERROR_MEMORY_CHECK;
+}
+
+/* FixMe: This is only valid for TFM LVL 1 now */
+int32_t tfm_memory_check(void *buffer, size_t len, int32_t ns_caller)
+{
+    uintptr_t base, limit;
+
+    /* If len is zero, this indicates an empty buffer and base is ignored */
+    if (len == 0) {
+        return IPC_SUCCESS;
+    }
+
+    if (!buffer) {
+        return IPC_ERROR_BAD_PARAMETERS;
+    }
+
+    if ((uintptr_t)buffer > (UINTPTR_MAX - len)) {
+        return IPC_ERROR_MEMORY_CHECK;
+    }
+
+    if (ns_caller) {
+        base = (uintptr_t)NS_DATA_START;
+        limit = (uintptr_t)(NS_DATA_START + NS_DATA_SIZE);
+        if (memory_check_range(buffer, len, base, limit) == IPC_SUCCESS) {
+            return IPC_SUCCESS;
+        }
+    } else {
+        base = (uintptr_t)&REGION_NAME(Image$$, ER_TFM_DATA, $$RW$$Base);
+        limit = (uintptr_t)&REGION_NAME(Image$$, ER_TFM_DATA, $$RW$$Limit);
+        if (memory_check_range(buffer, len, base, limit) == IPC_SUCCESS) {
+            return IPC_SUCCESS;
+        }
+
+        base = (uintptr_t)&REGION_NAME(Image$$, ER_TFM_DATA, $$ZI$$Base);
+        limit = (uintptr_t)&REGION_NAME(Image$$, ER_TFM_DATA, $$ZI$$Limit);
+        if (memory_check_range(buffer, len, base, limit) == IPC_SUCCESS) {
+            return IPC_SUCCESS;
+        }
+
+        base = (uintptr_t)&REGION_NAME(Image$$, TFM_SECURE_STACK, $$ZI$$Base);
+        limit = (uintptr_t)&REGION_NAME(Image$$, TFM_SECURE_STACK, $$ZI$$Limit);
+        if (memory_check_range(buffer, len, base, limit) == IPC_SUCCESS) {
+            return IPC_SUCCESS;
+        }
+
+        base = (uintptr_t)&REGION_NAME(Image$$, TFM_UNPRIV_SCRATCH, $$ZI$$Base);
+        limit = (uintptr_t)&REGION_NAME(Image$$, TFM_UNPRIV_SCRATCH,
+                                        $$ZI$$Limit);
+        if (memory_check_range(buffer, len, base, limit) == IPC_SUCCESS) {
+            return IPC_SUCCESS;
+        }
+    }
+
+    return IPC_ERROR_MEMORY_CHECK;
+}
+
+/********************** SPM functions for thread mode ************************/
+
+void tfm_spm_init(void)
+{
+    uint32_t i, num;
+    struct tfm_spm_ipc_partition_t *partition;
+    struct tfm_spm_service_t *service;
+    struct tfm_thrd_ctx *pth;
+
+    tfm_pool_init(conn_handle_pool,
+                  POOL_BUFFER_SIZE(conn_handle_pool),
+                  sizeof(struct tfm_conn_handle_t),
+                  TFM_CONN_HANDLE_MAX_NUM);
+    tfm_pool_init(spm_service_pool, POOL_BUFFER_SIZE(spm_service_pool),
+                  sizeof(struct tfm_spm_service_t),
+                  TFM_SPM_MAX_ROT_SERV_NUM);
+    tfm_pool_init(msg_db_pool, POOL_BUFFER_SIZE(msg_db_pool),
+                  sizeof(struct tfm_msg_body_t),
+                  TFM_MSG_QUEUE_MAX_MSG_NUM);
+
+    /* Init partition first for it will be used when init service */
+    for (i = 0; i < SPM_MAX_PARTITIONS; i++) {
+        if ((tfm_spm_partition_get_flags(i) & SPM_PART_FLAG_IPC) == 0) {
+            continue;
+        }
+        g_spm_ipc_partition[i].index = i;
+        g_spm_ipc_partition[i].id = tfm_spm_partition_get_partition_id(i);
+        tfm_event_init(&g_spm_ipc_partition[i].signal_event, EVENT_STAT_WAITED);
+        tfm_list_init(&g_spm_ipc_partition[i].service_list);
+
+        pth = tfm_spm_partition_get_thread_info_ext(i);
+        if (!pth) {
+            tfm_panic();
+        }
+
+        tfm_thrd_init(pth,
+                      tfm_spm_partition_get_init_func_ext(i),
+                      NULL,
+                      (uint8_t *)tfm_spm_partition_get_stack_base_ext(i),
+                      (uint8_t *)tfm_spm_partition_get_stack_limit_ext(i));
+        pth->prior = tfm_spm_partition_get_priority_ext(i);
+
+        /* Kick off */
+        if (tfm_thrd_start(pth) != THRD_SUCCESS) {
+            tfm_panic();
+        }
+    }
+
+    /* Init Service */
+    num = sizeof(g_spm_service_db) / sizeof(struct tfm_spm_service_db_t);
+    for (i = 0; i < num; i++) {
+        partition =
+            tfm_spm_get_partition_by_id(g_spm_service_db[i].partition_id);
+        if (!partition) {
+            tfm_panic();
+        }
+        service = (struct tfm_spm_service_t *)tfm_pool_alloc(spm_service_pool);
+        if (!service) {
+            tfm_panic();
+        }
+        service->service_db = &g_spm_service_db[i];
+        service->partition = partition;
+        tfm_list_init(&service->handle_list);
+        tfm_list_add_tail(&partition->service_list, &service->list);
+    }
+
+    /* All thread inited.... trigger scheduler */
+    tfm_thrd_activate_schedule();
+}
diff --git a/secure_fw/core/ipc/tfm_svcalls.c b/secure_fw/core/ipc/tfm_svcalls.c
new file mode 100644
index 0000000..a566056
--- /dev/null
+++ b/secure_fw/core/ipc/tfm_svcalls.c
@@ -0,0 +1,976 @@
+/*
+ * Copyright (c) 2018-2019, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
+ */
+#include <inttypes.h>
+#include <stdbool.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include "psa_client.h"
+#include "psa_service.h"
+#include "tfm_svc.h"
+#include "tfm_svcalls.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.h"
+#include "tfm_api.h"
+#include "tfm_secure_api.h"
+#include "tfm_memory_utils.h"
+
+#define PSA_TIMEOUT_MASK        PSA_BLOCK
+
+/************************* SVC handler for PSA Client APIs *******************/
+
+uint32_t tfm_svcall_psa_framework_version(void)
+{
+    return PSA_FRAMEWORK_VERSION;
+}
+
+uint32_t tfm_svcall_psa_version(uint32_t *args, int32_t ns_caller)
+{
+    uint32_t sid;
+    struct tfm_spm_service_t *service;
+
+    TFM_ASSERT(args != NULL);
+    sid = (uint32_t)args[0];
+    /*
+     * 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 (ns_caller && !service->service_db->non_secure_client) {
+        return PSA_VERSION_NONE;
+    }
+
+    return service->service_db->minor_version;
+}
+
+psa_handle_t tfm_svcall_psa_connect(uint32_t *args, int32_t ns_caller)
+{
+    uint32_t sid;
+    uint32_t minor_version;
+    struct tfm_spm_service_t *service;
+    struct tfm_msg_body_t *msg;
+
+    TFM_ASSERT(args != NULL);
+    sid = (uint32_t)args[0];
+    minor_version = (uint32_t)args[1];
+
+    /* 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_panic();
+    }
+
+    /*
+     * It is a fatal error if the caller is not authorized to access the RoT
+     * Service.
+     */
+    if (ns_caller && !service->service_db->non_secure_client) {
+        tfm_panic();
+    }
+
+    /*
+     * 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, minor_version) != IPC_SUCCESS) {
+        tfm_panic();
+    }
+
+    /* No input or output needed for connect message */
+    msg = tfm_spm_create_msg(service, PSA_NULL_HANDLE, PSA_IPC_CONNECT,
+                             ns_caller, NULL, 0, NULL, 0, NULL);
+    if (!msg) {
+        return PSA_NULL_HANDLE;
+    }
+
+    /*
+     * Send message and wake up the SP who is waiting on message queue,
+     * and scheduler triggered
+     */
+    tfm_spm_send_event(service, msg);
+
+    return PSA_NULL_HANDLE;
+}
+
+psa_status_t tfm_svcall_psa_call(uint32_t *args, int32_t ns_caller)
+{
+    psa_handle_t handle;
+    psa_invec *inptr, invecs[PSA_MAX_IOVEC];
+    psa_outvec *outptr, outvecs[PSA_MAX_IOVEC];
+    size_t in_num, out_num;
+    struct tfm_spm_service_t *service;
+    struct tfm_msg_body_t *msg;
+    int i;
+
+    TFM_ASSERT(args != NULL);
+    handle = (psa_handle_t)args[0];
+    if (!ns_caller) {
+        inptr = (psa_invec *)args[1];
+        in_num = (size_t)args[2];
+        outptr = (psa_outvec *)args[3];
+        /*
+         * FixMe: 5th parameter is pushed at stack top before SVC; plus
+         * exception stacked contents, 5th parameter is now at 8th position
+         * in SVC handler. However, if thread mode applies FloatPoint, then
+         * FloatPoint context is pushed into stack and then 5th parameter
+         * will not be args[8].
+         * Will refine it later.
+         */
+         out_num = (size_t)args[8];
+    } else {
+        /*
+         * FixMe: From non-secure caller, vec and len are composed into a new
+         * struct parameter. Need to extract them.
+         */
+        if (tfm_memory_check((void *)args[1], sizeof(uint32_t),
+            ns_caller) != IPC_SUCCESS) {
+            tfm_panic();
+        }
+        if (tfm_memory_check((void *)args[2], sizeof(uint32_t),
+            ns_caller) != IPC_SUCCESS) {
+            tfm_panic();
+        }
+
+        inptr = (psa_invec *)((psa_invec *)args[1])->base;
+        in_num = ((psa_invec *)args[1])->len;
+        outptr = (psa_outvec *)((psa_invec *)args[2])->base;
+        out_num = ((psa_invec *)args[2])->len;
+    }
+
+    /* It is a fatal error if in_len + out_len > PSA_MAX_IOVEC. */
+    if (in_num + out_num > PSA_MAX_IOVEC) {
+        tfm_panic();
+    }
+
+    /* It is a fatal error if an invalid handle was passed. */
+    service = tfm_spm_get_service_by_handle(handle);
+    if (!service) {
+        /* FixMe: Need to implement one mechanism to resolve this failure. */
+        tfm_panic();
+    }
+
+    /* It is a fatal error if an invalid memory reference was provide. */
+    if (tfm_memory_check((void *)inptr, in_num * sizeof(psa_invec),
+        ns_caller) != IPC_SUCCESS) {
+        tfm_panic();
+    }
+    if (tfm_memory_check((void *)outptr, out_num * sizeof(psa_outvec),
+        ns_caller) != IPC_SUCCESS) {
+        tfm_panic();
+    }
+
+    tfm_memset(invecs, 0, sizeof(invecs));
+    tfm_memset(outvecs, 0, sizeof(outvecs));
+
+    /* Copy the address out to avoid TOCTOU attacks. */
+    tfm_memcpy(invecs, inptr, in_num * sizeof(psa_invec));
+    tfm_memcpy(outvecs, outptr, out_num * sizeof(psa_outvec));
+
+    /*
+     * It is a fatal error if an invalid payload memory reference
+     * was provided.
+     */
+    for (i = 0; i < in_num; i++) {
+        if (tfm_memory_check((void *)invecs[i].base, invecs[i].len,
+            ns_caller) != IPC_SUCCESS) {
+            tfm_panic();
+        }
+    }
+    for (i = 0; i < out_num; i++) {
+        if (tfm_memory_check(outvecs[i].base, outvecs[i].len,
+            ns_caller) != IPC_SUCCESS) {
+            tfm_panic();
+        }
+    }
+
+    /*
+     * FixMe: Need to check if the message is unrecognized by the RoT
+     * Service or incorrectly formatted.
+     */
+    msg = tfm_spm_create_msg(service, handle, PSA_IPC_CALL, ns_caller, invecs,
+                             in_num, outvecs, out_num, outptr);
+    if (!msg) {
+        /* FixMe: Need to implement one mechanism to resolve this failure. */
+        tfm_panic();
+    }
+
+    /*
+     * 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_panic();
+    }
+    return PSA_SUCCESS;
+}
+
+void tfm_svcall_psa_close(uint32_t *args, int32_t ns_caller)
+{
+    psa_handle_t handle;
+    struct tfm_spm_service_t *service;
+    struct tfm_msg_body_t *msg;
+
+    TFM_ASSERT(args != NULL);
+    handle = args[0];
+    /* It will have no effect if called with the NULL handle */
+    if (handle == PSA_NULL_HANDLE) {
+        return;
+    }
+
+    /*
+     * It is a fatal error if an invalid handle was provided that is not the
+     * null handle..
+     */
+    service = tfm_spm_get_service_by_handle(handle);
+    if (!service) {
+        /* FixMe: Need to implement one mechanism to resolve this failure. */
+        tfm_panic();
+    }
+
+    /* No input or output needed for close message */
+    msg = tfm_spm_create_msg(service, handle, PSA_IPC_DISCONNECT, ns_caller,
+                             NULL, 0, NULL, 0, NULL);
+    if (!msg) {
+        /* FixMe: Need to implement one mechanism to resolve this failure. */
+        return;
+    }
+
+    /*
+     * Send message and wake up the SP who is waiting on message queue,
+     * and scheduler triggered
+     */
+    tfm_spm_send_event(service, msg);
+}
+
+/*********************** SVC handler 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.
+ */
+static psa_signal_t tfm_svcall_psa_wait(uint32_t *args)
+{
+    psa_signal_t signal_mask;
+    uint32_t timeout;
+    struct tfm_spm_ipc_partition_t *partition = NULL;
+
+    TFM_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_panic();
+    }
+
+    /*
+     * Expected signals are included in signal wait mask, ignored signals
+     * should not be set and affect caller thread status. Save this mask for
+     * further checking while signals are ready to be set.
+     */
+    partition->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->signals & signal_mask) == 0)) {
+            tfm_event_wait(&partition->signal_event);
+    }
+
+    return partition->signals & signal_mask;
+}
+
+/**
+ * \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_ERR_NOMSG        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 a RoT Service.
+ * \arg                           The RoT Service signal is not currently
+ *                                asserted.
+ * \arg                           The msg pointer provided is not a valid memory
+ *                                reference.
+ */
+static psa_status_t tfm_svcall_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 tfm_spm_ipc_partition_t *partition = NULL;
+
+    TFM_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_panic();
+    }
+
+    /*
+     * It is a fatal error if the input msg pointer is not a valid memory
+     * reference.
+     */
+    if (tfm_memory_check((void *)msg, sizeof(psa_msg_t),
+        false) != IPC_SUCCESS) {
+        tfm_panic();
+    }
+
+    partition = tfm_spm_get_running_partition();
+    if (!partition) {
+        tfm_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 a RoT Service signal
+     * is returned by psa_wait().
+     */
+    if (partition->signals == 0) {
+        tfm_panic();
+    }
+
+    /*
+     * It is a fatal error if the RoT Service signal is not currently asserted.
+     */
+    if ((partition->signals & signal) == 0) {
+        tfm_panic();
+    }
+
+    /*
+     * Get Rot service by signal from partition. It is a fatal error if geting
+     * failed which mean the input signal is not correspond to a RoT service.
+     */
+    service = tfm_spm_get_service_by_signal(partition, signal);
+    if (!service) {
+        tfm_panic();
+    }
+
+    tmp_msg = tfm_msg_dequeue(&service->msg_queue);
+    if (!tmp_msg) {
+        return PSA_ERR_NOMSG;
+    }
+
+    tfm_memcpy(msg, &tmp_msg->msg, sizeof(psa_msg_t));
+
+    /*
+     * There may be mutiple 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->signals &= ~signal;
+    }
+
+    return PSA_SUCCESS;
+}
+
+/**
+ * \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.
+ */
+static void tfm_svcall_psa_set_rhandle(uint32_t *args)
+{
+    psa_handle_t msg_handle;
+    void *rhandle = NULL;
+    struct tfm_msg_body_t *msg = NULL;
+
+    TFM_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_panic();
+    }
+
+    /*
+     * Connection handle is not created while SP is processing PSA_IPC_CONNECT
+     * message. Store reverse handle temporarily and re-set it after the
+     * connection created.
+     */
+    if (msg->handle != PSA_NULL_HANDLE) {
+        tfm_spm_set_rhandle(msg->service, msg->handle, rhandle);
+    } else {
+        msg->msg.rhandle = rhandle;
+    }
+}
+
+/**
+ * \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
+ *                                \ref PSA_IPC_CALL 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.
+ */
+static size_t tfm_svcall_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;
+
+    TFM_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_panic();
+    }
+
+    /*
+     * It is a fatal error if message handle does not refer to a PSA_IPC_CALL
+     * message
+     */
+    if (msg->msg.type != PSA_IPC_CALL) {
+        tfm_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_panic();
+    }
+
+    /* There was no remaining data in this input vector */
+    if (msg->msg.in_size[invec_idx] == 0) {
+        return 0;
+    }
+
+    /*
+     * It is a fatal error if the memory reference for buffer is invalid or
+     * not writable
+     */
+    /* FixMe: write permission check to be added */
+    if (tfm_memory_check(buffer, num_bytes, false) != IPC_SUCCESS) {
+        tfm_panic();
+    }
+
+    bytes = num_bytes > msg->msg.in_size[invec_idx] ?
+                        msg->msg.in_size[invec_idx] : num_bytes;
+
+    tfm_memcpy(buffer, msg->invec[invec_idx].base, bytes);
+
+    /* There maybe some remaining data */
+    msg->invec[invec_idx].base += bytes;
+    msg->msg.in_size[invec_idx] -= bytes;
+
+    return bytes;
+}
+
+/**
+ * \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
+ *                                \ref PSA_IPC_CALL message.
+ * \arg                           invec_idx is equal to or greater than
+ *                                \ref PSA_MAX_IOVEC.
+ */
+static size_t tfm_svcall_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_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_panic();
+    }
+
+    /*
+     * It is a fatal error if message handle does not refer to a PSA_IPC_CALL
+     * message
+     */
+    if (msg->msg.type != PSA_IPC_CALL) {
+        tfm_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_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 += num_bytes;
+    msg->msg.in_size[invec_idx] -= num_bytes;
+
+    return num_bytes;
+}
+
+/**
+ * \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
+ *                                \ref PSA_IPC_CALL 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.
+ */
+static void tfm_svcall_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;
+
+    TFM_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_panic();
+    }
+
+    /*
+     * It is a fatal error if message handle does not refer to a PSA_IPC_CALL
+     * message
+     */
+    if (msg->msg.type != PSA_IPC_CALL) {
+        tfm_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_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_panic();
+    }
+
+    /* It is a fatal error if the memory reference for buffer is valid */
+    if (tfm_memory_check(buffer, num_bytes, false) != IPC_SUCCESS) {
+        tfm_panic();
+    }
+
+    tfm_memcpy(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)
+{
+    int32_t i = 0;
+
+    /*
+     * FixeMe: abstract these part into dedicated functions to avoid
+     * accessing thread context in psa layer
+     */
+    TFM_ASSERT(msg->ack_mtx.owner->status == THRD_STAT_BLOCK);
+
+    while (msg->msg.out_size[i] != 0) {
+        TFM_ASSERT(msg->caller_outvec[i].base == msg->outvec[i].base);
+        msg->caller_outvec[i].len = msg->outvec[i].len;
+        i++;
+    }
+}
+/**
+ * \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.
+ */
+static void tfm_svcall_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;
+    psa_handle_t connect_handle;
+    int32_t ret = PSA_SUCCESS;
+
+    TFM_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_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_panic();
+    }
+
+    /*
+     * Three type of message are passed in this function: CONNECT, CALL,
+     * DISCONNECT. 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 created if the
+         * input status is PSA_SUCCESS. Others return values are based on the
+         * input status.
+         */
+        if (status == PSA_SUCCESS) {
+            connect_handle = tfm_spm_create_conn_handle(service);
+            if (connect_handle == PSA_NULL_HANDLE) {
+                tfm_panic();
+            }
+            ret = connect_handle;
+
+            /* Set reverse handle after connection created if needed. */
+            if (msg->msg.rhandle) {
+                tfm_spm_set_rhandle(service, connect_handle, msg->msg.rhandle);
+            }
+        } else if (status == PSA_CONNECTION_REFUSED) {
+            ret = PSA_CONNECTION_REFUSED;
+        } else if (status == PSA_CONNECTION_BUSY) {
+            ret = PSA_CONNECTION_BUSY;
+        } else {
+            tfm_panic();
+        }
+        break;
+    case PSA_IPC_CALL:
+        /* Reply to PSA_IPC_CALL message. Return values are based on status */
+        if (status == PSA_SUCCESS) {
+            ret = PSA_SUCCESS;
+        } else if (status == PSA_DROP_CONNECTION) {
+            ret = PSA_DROP_CONNECTION;
+        } else if ((status >= (INT32_MIN + 1)) &&
+                   (status <= (INT32_MIN + 127))) {
+            tfm_panic();
+        } else if ((status >= (INT32_MIN + 128)) && (status <= -1)) {
+            ret = status;
+        } else if ((status >= 1) && (status <= INT32_MAX)) {
+            ret = status;
+        } else {
+            tfm_panic();
+        }
+
+        /*
+         * 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);
+        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:
+        tfm_panic();
+    }
+
+    /* Save return value for blocked threads */
+    tfm_event_owner_retval(&msg->ack_mtx, ret);
+
+    /* Wake waiting thread up */
+    tfm_event_signal(&msg->ack_mtx);
+
+    /* Message should not be unsed anymore */
+    tfm_spm_free_msg(msg);
+}
+
+/**
+ * \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.
+ */
+static void tfm_svcall_psa_notify(uint32_t *args)
+{
+    int32_t partition_id;
+    struct tfm_spm_ipc_partition_t *partition = NULL;
+
+    TFM_ASSERT(args != NULL);
+    partition_id = (int32_t)args[0];
+
+    /*
+     * 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_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_panic();
+    }
+
+    partition->signals |= PSA_DOORBELL;
+
+    /*
+     * 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_owner_retval(&partition->signal_event,
+                           partition->signals & partition->signal_mask);
+
+    /* Wake waiting thread up */
+    tfm_event_signal(&partition->signal_event);
+}
+
+/**
+ * \brief SVC handler for \ref psa_clear.
+ *
+ * \retval void                 Success.
+ * \retval "Does not return"    The Secure Partition's doorbell signal is not
+ *                              currently asserted.
+ */
+static void tfm_svcall_psa_clear(uint32_t *args)
+{
+    struct tfm_spm_ipc_partition_t *partition = NULL;
+
+    partition = tfm_spm_get_running_partition();
+    if (!partition) {
+        tfm_panic();
+    }
+
+    /*
+     * It is a fatal error if the Secure Partition's doorbell signal is not
+     * currently asserted.
+     */
+    if ((partition->signals & PSA_DOORBELL) == 0) {
+        tfm_panic();
+    }
+    partition->signals &= ~PSA_DOORBELL;
+}
+
+/**
+ * \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.
+ */
+static void tfm_svcall_psa_eoi(uint32_t *args)
+{
+    psa_signal_t irq_signal;
+    struct tfm_spm_ipc_partition_t *partition = NULL;
+
+    TFM_ASSERT(args != NULL);
+    irq_signal = (psa_signal_t)args[0];
+
+    partition = tfm_spm_get_running_partition();
+    if (!partition) {
+        tfm_panic();
+    }
+
+    /*
+     * FixMe: It is a fatal error if passed signal is not an interrupt signal.
+     */
+
+    /* It is a fatal error if passed signal indicates more than one signals. */
+    if (tfm_bitcount(partition->signals) != 1) {
+        tfm_panic();
+    }
+
+    /* It is a fatal error if passed signal is not currently asserted */
+    if ((partition->signals & irq_signal) == 0) {
+        tfm_panic();
+    }
+
+    partition->signals &= ~irq_signal;
+
+    /* FixMe: re-enable interrupt */
+}
+
+int32_t SVC_Handler_IPC(tfm_svc_number_t svc_num, uint32_t *ctx)
+{
+    switch (svc_num) {
+    case TFM_SVC_SCHEDULE:
+        tfm_thrd_activate_schedule();
+        break;
+    case TFM_SVC_PSA_FRAMEWORK_VERSION:
+        return tfm_svcall_psa_framework_version();
+    case TFM_SVC_PSA_VERSION:
+        return tfm_svcall_psa_version(ctx, 0);
+    case TFM_SVC_PSA_CONNECT:
+        return tfm_svcall_psa_connect(ctx, 0);
+    case TFM_SVC_PSA_CALL:
+        return tfm_svcall_psa_call(ctx, 0);
+    case TFM_SVC_PSA_CLOSE:
+        tfm_svcall_psa_close(ctx, 0);
+        break;
+    case TFM_SVC_PSA_WAIT:
+        return tfm_svcall_psa_wait(ctx);
+    case TFM_SVC_PSA_GET:
+        return tfm_svcall_psa_get(ctx);
+    case TFM_SVC_PSA_SET_RHANDLE:
+        tfm_svcall_psa_set_rhandle(ctx);
+        break;
+    case TFM_SVC_PSA_READ:
+        return tfm_svcall_psa_read(ctx);
+    case TFM_SVC_PSA_SKIP:
+        return tfm_svcall_psa_skip(ctx);
+    case TFM_SVC_PSA_WRITE:
+        tfm_svcall_psa_write(ctx);
+        break;
+    case TFM_SVC_PSA_REPLY:
+        tfm_svcall_psa_reply(ctx);
+        break;
+    case TFM_SVC_PSA_NOTIFY:
+        tfm_svcall_psa_notify(ctx);
+        break;
+    case TFM_SVC_PSA_CLEAR:
+        tfm_svcall_psa_clear(ctx);
+        break;
+    case TFM_SVC_PSA_EOI:
+        tfm_svcall_psa_eoi(ctx);
+        break;
+    default:
+        break;
+    }
+    return PSA_SUCCESS;
+}
diff --git a/secure_fw/core/ipc/tfm_thread.c b/secure_fw/core/ipc/tfm_thread.c
new file mode 100644
index 0000000..cd01259
--- /dev/null
+++ b/secure_fw/core/ipc/tfm_thread.c
@@ -0,0 +1,198 @@
+/*
+ * Copyright (c) 2018-2019, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
+ */
+#include <inttypes.h>
+#include <stdio.h>
+#include "tfm_arch_v8m.h"
+#include "tfm_thread.h"
+#include "tfm_utils.h"
+#include "tfm_memory_utils.h"
+
+/* Force ZERO in case ZI(bss) clear is missing */
+static struct tfm_thrd_ctx *p_thrd_head = NULL;
+static struct tfm_thrd_ctx *p_runn_head = NULL;
+static struct tfm_thrd_ctx *p_curr_thrd = NULL;
+
+/* Define Macro to fetch global to support future expansion (PERCPU e.g.) */
+#define LIST_HEAD   p_thrd_head
+#define RUNN_HEAD   p_runn_head
+#define CURR_THRD   p_curr_thrd
+
+static struct tfm_thrd_ctx *find_next_running_thread(struct tfm_thrd_ctx *pth)
+{
+    while (pth && pth->status != THRD_STAT_RUNNING) {
+        pth = pth->next;
+    }
+
+    return pth;
+}
+
+/* To get next running thread for scheduler */
+struct tfm_thrd_ctx *tfm_thrd_next_thread(void)
+{
+    /*
+     * First RUNNING thread has highest priority since threads are sorted with
+     * priority.
+     */
+    return find_next_running_thread(RUNN_HEAD);
+}
+
+/* To get current thread for caller */
+struct tfm_thrd_ctx *tfm_thrd_curr_thread()
+{
+    return CURR_THRD;
+}
+
+/* Insert a new thread into list by descending priority (Highest at head) */
+static void insert_by_prior(struct tfm_thrd_ctx **head,
+                            struct tfm_thrd_ctx *node)
+{
+    if (*head == NULL || (node->prior <= (*head)->prior)) {
+        node->next = *head;
+        *head = node;
+    } else {
+        struct tfm_thrd_ctx *iter = *head;
+
+        while (iter->next && (node->prior > iter->next->prior)) {
+            iter = iter->next;
+        }
+        node->next = iter->next;
+        iter->next = node;
+    }
+}
+
+/*
+ * Set first running thread as head to reduce enumerate
+ * depth while searching for a first running thread.
+ */
+static void update_running_head(struct tfm_thrd_ctx **runn,
+                                struct tfm_thrd_ctx *node)
+{
+    if ((node->status == THRD_STAT_RUNNING) &&
+        (*runn == NULL || (node->prior < (*runn)->prior))) {
+        *runn = node;
+    } else {
+        *runn = find_next_running_thread(LIST_HEAD);
+    }
+}
+
+/* Set context members only. No validation here */
+void tfm_thrd_init(struct tfm_thrd_ctx *pth,
+                   tfm_thrd_func_t pfn, void *param,
+                   uint8_t *sp_base, uint8_t *sp_top)
+{
+    pth->prior = THRD_PRIOR_MEDIUM;
+    pth->status = THRD_STAT_CREATING;
+    pth->pfn = pfn;
+    pth->param = param;
+    pth->sp_base = sp_base;
+    pth->sp_top = sp_top;
+}
+
+uint32_t tfm_thrd_start(struct tfm_thrd_ctx *pth)
+{
+    /* Validate parameters before really start */
+    if ((pth->status != THRD_STAT_CREATING) ||
+        (pth->pfn == NULL)                  ||
+        (pth->sp_base == NULL)              ||
+        (pth->sp_top == NULL)) {
+        return THRD_ERR_INVALID_PARAM;
+    }
+
+    /* Thread management runs in handler mode; set context for thread mode. */
+    tfm_initialize_context(&pth->state_ctx,
+                           (uint32_t)pth->param, (uint32_t)pth->pfn,
+                           (uint32_t)pth->sp_base, (uint32_t)pth->sp_top);
+
+    /* Insert a new thread with priority */
+    insert_by_prior(&LIST_HEAD, pth);
+
+    /* Mark it as RUNNING after insertion */
+    tfm_thrd_set_status(pth, THRD_STAT_RUNNING);
+
+    return THRD_SUCCESS;
+}
+
+void tfm_thrd_set_status(struct tfm_thrd_ctx *pth, uint32_t new_status)
+{
+    TFM_ASSERT(pth != NULL && new_status < THRD_STAT_INVALID);
+
+    pth->status = new_status;
+    update_running_head(&RUNN_HEAD, pth);
+}
+
+/*
+ * TEMP WORKAROUND: The caller function who called thread module init needs to
+ * be returned. The caller is not a thread. Create a dummy IDLE thread to
+ * collect caller context; and schedule back to the caller with this context
+ * after all other real threads blocked.
+ *
+ * This WORKAROUND needs to be removed after IPC NSPM takes place.
+ */
+#define DUMMY_IDLE_TAG       0xDEEDDEED
+static uint8_t idle_stack[32] __attribute__((aligned(8)));
+static struct tfm_thrd_ctx idle_thread;
+static struct tfm_thrd_ctx *init_idle_thread(struct tfm_thrd_ctx *pth)
+{
+    /*
+     * IDLE thread is a thread with the lowest priority.
+     * It gets scheduled after all other higher priority threads get blocked.
+     * The entry of IDLE thread is a dummy and has no mean.
+     */
+    tfm_thrd_init(pth, (tfm_thrd_func_t)DUMMY_IDLE_TAG, NULL,
+                  (uint8_t *)&idle_stack[32], (uint8_t *)idle_stack);
+    tfm_thrd_priority(pth, THRD_PRIOR_LOWEST);
+    tfm_thrd_start(pth);
+    return pth;
+}
+
+/* Scheduling won't happen immediately but after the exception returns */
+void tfm_thrd_activate_schedule(void)
+{
+    /*
+     * The current thread can be NULL only when initializing. Create the IDLE
+     * thread and set it as the current thread to collect caller context.
+     */
+    if (CURR_THRD == NULL) {
+        CURR_THRD = init_idle_thread(&idle_thread);
+    }
+
+    tfm_trigger_pendsv();
+}
+
+/* Remove current thread out of the schedulable list */
+void tfm_thrd_do_exit(void)
+{
+    CURR_THRD->status = THRD_STAT_DETACH;
+    tfm_trigger_pendsv();
+}
+
+void tfm_thrd_context_switch(struct tfm_state_context_ext *ctxb,
+                             struct tfm_thrd_ctx *prev,
+                             struct tfm_thrd_ctx *next)
+{
+    /* Update latest context into the current thread context */
+    tfm_memcpy(&prev->state_ctx.ctxb, ctxb, sizeof(*ctxb));
+    /* Update background context with next thread's context */
+    tfm_memcpy(ctxb, &next->state_ctx.ctxb, sizeof(next->state_ctx.ctxb));
+    /* Set current thread indicator with next thread */
+    CURR_THRD = next;
+}
+
+/*
+ * This function is a reference implementation for PendSV handler in
+ * isolation level 1. More jobs (sandboxing e.g.) need to be done while
+ * scheduling in other isolation levels.
+ */
+void tfm_pendsv_do_schedule(struct tfm_state_context_ext *ctxb)
+{
+    struct tfm_thrd_ctx *pth = tfm_thrd_next_thread();
+
+    /* Swith context if another thread ready to run */
+    if (pth && pth != CURR_THRD) {
+        tfm_thrd_context_switch(ctxb, CURR_THRD, pth);
+    }
+}
diff --git a/secure_fw/core/ipc/tfm_utils.c b/secure_fw/core/ipc/tfm_utils.c
new file mode 100644
index 0000000..1586633
--- /dev/null
+++ b/secure_fw/core/ipc/tfm_utils.c
@@ -0,0 +1,32 @@
+/*
+ * Copyright (c) 2018-2019, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
+ */
+#include <inttypes.h>
+#include <stdio.h>
+#include "tfm_utils.h"
+
+void tfm_panic(void)
+{
+    while (1)
+        ;
+}
+
+int32_t tfm_bitcount(uint32_t n)
+{
+    int32_t count = 0;
+    uint8_t tmp;
+
+    while (n) {
+        tmp = n & 0xFF;
+        while (tmp) {
+            count += tmp & 0x1;
+            tmp >>= 1;
+        }
+        n >>= 8;
+    }
+
+    return count;
+}
diff --git a/secure_fw/core/ipc/tfm_wait.c b/secure_fw/core/ipc/tfm_wait.c
new file mode 100644
index 0000000..814ec89
--- /dev/null
+++ b/secure_fw/core/ipc/tfm_wait.c
@@ -0,0 +1,62 @@
+/*
+ * Copyright (c) 2018-2019, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
+ */
+#include <inttypes.h>
+#include <stdio.h>
+#include "tfm_arch_v8m.h"
+#include "tfm_thread.h"
+#include "tfm_utils.h"
+#include "tfm_wait.h"
+
+void tfm_event_wait(struct tfm_event_ctx *pevt)
+{
+    struct tfm_thrd_ctx *curr_thrd = tfm_thrd_curr_thread();
+
+    TFM_ASSERT(pevt && pevt->magic == EVENT_MAGIC);
+
+    if (pevt->status == EVENT_STAT_WAITED) {
+        pevt->owner = curr_thrd;
+        pevt->retval = TFM_STATE_1ST_ARG(&pevt->owner->state_ctx);
+        tfm_thrd_set_status(pevt->owner, THRD_STAT_BLOCK);
+        tfm_thrd_activate_schedule();
+    }
+
+    pevt->status = EVENT_STAT_WAITED;
+}
+
+/* Peek the status to see if caller would block. */
+uint32_t tfm_event_peek(struct tfm_event_ctx *pevt)
+{
+    TFM_ASSERT(pevt && pevt->magic == EVENT_MAGIC);
+
+    return pevt->status;
+}
+
+void tfm_event_signal(struct tfm_event_ctx *pevt)
+{
+    TFM_ASSERT(pevt && pevt->magic == EVENT_MAGIC);
+
+    pevt->status = EVENT_STAT_SIGNALED;
+
+    /*
+     * Wake the blocked owner up and keep the status as EVENT_STAT_WAITED
+     * if there is an owner. Or the second event wait caller will return
+     * without block since status is EVENT_STAT_SIGNALED.
+     */
+    if (pevt->owner && pevt->owner->status == THRD_STAT_BLOCK) {
+        tfm_thrd_set_status(pevt->owner, THRD_STAT_RUNNING);
+        tfm_thrd_set_retval(pevt->owner, pevt->retval);
+        pevt->status = EVENT_STAT_WAITED;
+        tfm_thrd_activate_schedule();
+    }
+}
+
+void tfm_event_owner_retval(struct tfm_event_ctx *pmtx, uint32_t retval)
+{
+    TFM_ASSERT(pmtx && pmtx->magic == EVENT_MAGIC);
+
+    pmtx->retval = retval;
+}
diff --git a/secure_fw/core/tfm_core.c b/secure_fw/core/tfm_core.c
index 81eeccd..7cf6508 100644
--- a/secure_fw/core/tfm_core.c
+++ b/secure_fw/core/tfm_core.c
@@ -15,6 +15,14 @@
 #include "secure_utilities.h"
 #include "secure_fw/spm/spm_api.h"
 #include "secure_fw/include/tfm_spm_services_api.h"
+#ifdef TFM_PSA_API
+#include "psa_client.h"
+#include "psa_service.h"
+#include "tfm_thread.h"
+#include "tfm_wait.h"
+#include "tfm_message_queue.h"
+#include "tfm_spm.h"
+#endif
 
 /*
  * Avoids the semihosting issue
@@ -165,6 +173,10 @@
          */
     }
 
+#ifdef TFM_PSA_API
+    tfm_spm_init();
+#endif
+
 #ifdef TFM_CORE_DEBUG
     /* Jumps to non-secure code */
     LOG_MSG("Jumping to non-secure code...");
diff --git a/secure_fw/core/tfm_handler.c b/secure_fw/core/tfm_handler.c
index ee59ea1..15965bf 100644
--- a/secure_fw/core/tfm_handler.c
+++ b/secure_fw/core/tfm_handler.c
@@ -17,11 +17,18 @@
 #include "tfm_api.h"
 #include "tfm_internal.h"
 #include "tfm_memory_utils.h"
+#ifdef TFM_PSA_API
+#include <stdbool.h>
+#include "tfm_svcalls.h"
+#endif
 
 /* This SVC handler is called when a secure partition requests access to a
  * buffer area
  */
 extern int32_t tfm_core_set_buffer_area_handler(const uint32_t args[]);
+#ifdef TFM_PSA_API
+extern void tfm_psa_ipc_request_handler(const uint32_t svc_args[]);
+#endif
 
 struct tfm_fault_context_s {
     uint32_t R0;
@@ -172,12 +179,36 @@
     case TFM_SVC_SET_SHARE_AREA:
         tfm_core_set_buffer_area_handler(svc_args);
         break;
+#ifdef TFM_PSA_API
+    case TFM_SVC_IPC_REQUEST:
+        tfm_psa_ipc_request_handler(svc_args);
+        break;
+#endif
     case TFM_SVC_PRINT:
         printf("\e[1;34m[Sec Thread] %s\e[0m\r\n", (char *)svc_args[0]);
         break;
     case TFM_SVC_GET_BOOT_DATA:
         tfm_core_get_boot_data_handler(svc_args);
         break;
+#ifdef TFM_PSA_API
+    case TFM_SVC_PSA_FRAMEWORK_VERSION:
+    case TFM_SVC_PSA_VERSION:
+    case TFM_SVC_PSA_CONNECT:
+    case TFM_SVC_PSA_CALL:
+    case TFM_SVC_PSA_CLOSE:
+    case TFM_SVC_PSA_WAIT:
+    case TFM_SVC_PSA_GET:
+    case TFM_SVC_PSA_SET_RHANDLE:
+    case TFM_SVC_PSA_READ:
+    case TFM_SVC_PSA_SKIP:
+    case TFM_SVC_PSA_WRITE:
+    case TFM_SVC_PSA_REPLY:
+    case TFM_SVC_PSA_NOTIFY:
+    case TFM_SVC_PSA_CLEAR:
+    case TFM_SVC_PSA_EOI:
+        svc_args[0] = SVC_Handler_IPC(svc_number, svc_args);
+        break;
+#endif
     default:
         LOG_MSG("Unknown SVC number requested!");
         break;
diff --git a/secure_fw/core/tfm_psa_api_client.c b/secure_fw/core/tfm_psa_api_client.c
new file mode 100644
index 0000000..4b35c58
--- /dev/null
+++ b/secure_fw/core/tfm_psa_api_client.c
@@ -0,0 +1,133 @@
+/*
+ * Copyright (c) 2018, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
+ */
+
+#include <stdbool.h>
+#include <stdio.h>
+#include "psa_client.h"
+#include "psa_service.h"
+#include "secure_utilities.h"
+#include "tfm_secure_api.h"
+#include "tfm_api.h"
+#include "tfm_svcalls.h"
+
+/* FixMe: check if this is really needed */
+extern int32_t tfm_secure_lock;
+
+__attribute__ ((always_inline)) __STATIC_INLINE
+int32_t tfm_psa_veneer_sanity_check(struct tfm_sfn_req_s *desc_ptr)
+{
+    if (desc_ptr->ns_caller) {
+        if (tfm_secure_lock != 0) {
+            /* Secure domain is already locked!
+             * FixMe: Decide if this is a fault or permitted in case of PSA
+             * API usage
+             */
+            return TFM_ERROR_SECURE_DOMAIN_LOCKED;
+        }
+    } else {
+        /* Secure partition should not call a different secure partition
+         * using TFM PSA veneers
+         */
+        return TFM_ERROR_INVALID_EXC_MODE;
+    }
+    return TFM_SUCCESS;
+}
+
+/* Veneer implementation */
+
+#define TFM_CORE_NS_IPC_REQUEST_VENEER(fn, a, b, c, d) \
+            return tfm_core_ns_ipc_request(fn, (int32_t)a, (int32_t)b, \
+                (int32_t)c, (int32_t)d)
+
+__attribute__ ((always_inline)) __STATIC_INLINE
+int32_t tfm_core_ns_ipc_request(void *fn, int32_t arg1, int32_t arg2,
+                                int32_t arg3, int32_t arg4)
+{
+    int32_t args[4] = {arg1, arg2, arg3, arg4};
+    struct tfm_sfn_req_s desc, *desc_ptr = &desc;
+    int32_t res;
+
+    desc.sfn = fn;
+    desc.args = args;
+    desc.ns_caller = cmse_nonsecure_caller();
+
+    if (__get_active_exc_num() != EXC_NUM_THREAD_MODE)
+    {
+        /* FIXME: Proper error handling to be implemented */
+        return TFM_ERROR_INVALID_EXC_MODE;
+    } else {
+        __ASM("MOV r0, %1\n"
+              "SVC %2\n"
+              "MOV %0, r0\n"
+              : "=r" (res)
+              : "r" (desc_ptr), "I" (TFM_SVC_IPC_REQUEST)
+              : "r0");
+        return res;
+    }
+}
+
+/* FixMe: these functions need to have different attributes compared to those
+ * legacy veneers which may be called by secure partitions.
+ * They won't call legacy SFN but instead will be handlers for TF-M
+ */
+
+__tfm_secure_gateway_attributes__
+uint32_t tfm_psa_framework_version_veneer(void)
+{
+    TFM_CORE_NS_IPC_REQUEST_VENEER(tfm_svcall_psa_framework_version, 0, 0,
+                                   0, 0);
+}
+
+__tfm_secure_gateway_attributes__
+uint32_t tfm_psa_version_veneer(uint32_t sid)
+{
+    TFM_CORE_NS_IPC_REQUEST_VENEER(tfm_svcall_psa_version, sid, 0, 0, 0);
+}
+
+__tfm_secure_gateway_attributes__
+psa_handle_t tfm_psa_connect_veneer(uint32_t sid, uint32_t minor_version)
+{
+    TFM_CORE_NS_IPC_REQUEST_VENEER(tfm_svcall_psa_connect, sid,
+                                   minor_version, 0, 0);
+}
+
+__tfm_secure_gateway_attributes__
+psa_status_t tfm_psa_call_veneer(psa_handle_t handle,
+                                 const psa_invec *in_vecs,
+                                 const psa_invec *out_vecs)
+{
+    TFM_CORE_NS_IPC_REQUEST_VENEER(tfm_svcall_psa_call, handle, in_vecs,
+                                   out_vecs, 0);
+}
+
+__tfm_secure_gateway_attributes__
+psa_status_t tfm_psa_close_veneer(psa_handle_t handle)
+{
+    TFM_CORE_NS_IPC_REQUEST_VENEER(tfm_svcall_psa_close, handle, 0, 0, 0);
+}
+
+void tfm_psa_ipc_request_handler(uint32_t svc_ctx[])
+{
+    uint32_t *r0_ptr = svc_ctx;
+
+    /* The only argument to the SVC call is stored in the stacked r0 */
+    struct tfm_sfn_req_s *desc_ptr = (struct tfm_sfn_req_s *) *r0_ptr;
+
+    if(tfm_psa_veneer_sanity_check(desc_ptr) != TFM_SUCCESS) {
+        /* FixMe: consider error handling - this may be critical error */
+        *r0_ptr = TFM_ERROR_INVALID_PARAMETER;
+        return;
+    }
+
+    /* Store SVC return value in stacked r0 */
+    *r0_ptr = desc_ptr->sfn((int32_t)desc_ptr->args,
+                            desc_ptr->ns_caller,
+                            0,
+                            0);
+
+    return;
+}
diff --git a/secure_fw/core/tfm_secure_api.c b/secure_fw/core/tfm_secure_api.c
index 14f82ef..8bcbec1 100644
--- a/secure_fw/core/tfm_secure_api.c
+++ b/secure_fw/core/tfm_secure_api.c
@@ -40,7 +40,7 @@
 /* This is the "Big Lock" on the secure side, to guarantee single entry
  * to SPE
  */
-static int32_t tfm_secure_lock;
+int32_t tfm_secure_lock;
 static int32_t tfm_secure_api_initializing = 1;
 
 static int32_t is_iovec_api_call(void)
@@ -367,12 +367,13 @@
     caller_flags = tfm_spm_partition_get_flags(caller_partition_idx);
 
     /* Check partition state consistency */
-    if (((caller_flags&SPM_PART_FLAG_SECURE) != 0) != (!desc_ptr->ns_caller)) {
+    if (((caller_flags & SPM_PART_FLAG_APP_ROT) != 0)
+        != (!desc_ptr->ns_caller)) {
         /* Partition state inconsistency detected */
         return TFM_SECURE_LOCK_FAILED;
     }
 
-    if((caller_flags & SPM_PART_FLAG_SECURE) == 0) {
+    if((caller_flags & SPM_PART_FLAG_APP_ROT) == 0) {
         /* Disable NS exception handling while secure service is running.
          * FixMe:
          * This restriction is applied to limit the number of possible attack
@@ -396,7 +397,7 @@
         /* Make thread mode unprivileged while untrusted partition init is
          * executed
          */
-        if ((partition_flags & SPM_PART_FLAG_TRUSTED) == 0) {
+        if ((partition_flags & SPM_PART_FLAG_PSA_ROT) == 0) {
             CONTROL_Type ctrl;
 
             ctrl.w = __get_CONTROL();
@@ -436,7 +437,7 @@
                                                caller_partition_idx);
     tfm_spm_partition_store_context(caller_partition_idx, psp, excReturn);
 
-    if ((caller_flags&SPM_PART_FLAG_SECURE)) {
+    if ((caller_flags & SPM_PART_FLAG_APP_ROT)) {
         tfm_spm_partition_set_caller_client_id(partition_idx,
                                                caller_partition_id);
     } else {
@@ -562,7 +563,7 @@
 
     tfm_secure_lock--;
 
-    if((return_partition_flags & SPM_PART_FLAG_SECURE) == 0) {
+    if((return_partition_flags & SPM_PART_FLAG_APP_ROT) == 0) {
         /* Re-enable NS exceptions when secure service returns to NS client.
          * FixMe:
          * To be removed when pre-emption and context management issues have
@@ -578,7 +579,7 @@
         /* Restore privilege for thread mode during TF-M init. This is only
          * have to be done if the partition is not trusted.
          */
-        if ((current_partition_flags & SPM_PART_FLAG_TRUSTED) == 0) {
+        if ((current_partition_flags & SPM_PART_FLAG_PSA_ROT) == 0) {
             CONTROL_Type ctrl;
 
             ctrl.w = __get_CONTROL();
@@ -596,7 +597,7 @@
             ERROR_MSG("Failed to configure sandbox for partition!");
             tfm_secure_api_error_handler();
         }
-        if (return_partition_flags&SPM_PART_FLAG_SECURE) {
+        if (return_partition_flags & SPM_PART_FLAG_APP_ROT) {
             /* Restore share status */
             tfm_spm_partition_set_share(
                 return_partition_idx,
@@ -607,7 +608,7 @@
 #endif
 
 #if TFM_LVL == 1
-    if (!(return_partition_flags & SPM_PART_FLAG_SECURE) ||
+    if (!(return_partition_flags & SPM_PART_FLAG_APP_ROT) ||
         (tfm_secure_api_initializing)) {
         /* In TFM level 1 context restore is only done when
          * returning to NS or after initialization
@@ -832,7 +833,7 @@
     uint32_t caller_partition_flags =
             tfm_spm_partition_get_flags(curr_part_data->caller_partition_idx);
 
-    if (!(running_partition_flags&SPM_PART_FLAG_SECURE))  {
+    if (!(running_partition_flags & SPM_PART_FLAG_APP_ROT))  {
         /* This handler shouldn't be called from outside partition context.
          * Partitions are only allowed to run while S domain is locked.
          */
@@ -841,7 +842,7 @@
     }
 
     /* Store return value in r0 */
-    if (caller_partition_flags&SPM_PART_FLAG_SECURE) {
+    if (caller_partition_flags & SPM_PART_FLAG_APP_ROT) {
         res = TFM_SUCCESS;
     }
     svc_args[0] = res;
@@ -915,7 +916,7 @@
             tfm_spm_partition_get_runtime_data(running_partition_idx);
     int res = 0;
 
-    if (!(running_partition_flags&SPM_PART_FLAG_SECURE))  {
+    if (!(running_partition_flags & SPM_PART_FLAG_APP_ROT))  {
         /* This handler shouldn't be called from outside partition context.
          * Partitions are only allowed to run while S domain is locked.
          */
@@ -959,7 +960,7 @@
     int32_t flags = 0;
     void *rangeptr;
 
-    if (!(running_partition_flags&SPM_PART_FLAG_SECURE) || (size == 0)) {
+    if (!(running_partition_flags & SPM_PART_FLAG_APP_ROT) || (size == 0)) {
         /* This handler should only be called from a secure partition. */
         svc_args[0] = TFM_ERROR_INVALID_PARAMETER;
         return;
@@ -1132,7 +1133,7 @@
      /* tfm_core_set_buffer_area() returns int32_t */
     int32_t *res_ptr = (int32_t *)&args[0];
 
-    if (!(running_partition_flags&SPM_PART_FLAG_SECURE)) {
+    if (!(running_partition_flags & SPM_PART_FLAG_APP_ROT)) {
         /* This handler should only be called from a secure partition. */
         *res_ptr = TFM_ERROR_INVALID_PARAMETER;
         return;
@@ -1140,7 +1141,7 @@
 
     switch (args[0]) {
     case TFM_BUFFER_SHARE_DEFAULT:
-        share = (!(caller_partition_flags&SPM_PART_FLAG_SECURE)) ?
+        share = (!(caller_partition_flags & SPM_PART_FLAG_APP_ROT)) ?
             (TFM_BUFFER_SHARE_NS_CODE) : (TFM_BUFFER_SHARE_SCRATCH);
         break;
     case TFM_BUFFER_SHARE_SCRATCH:
diff --git a/secure_fw/core/tfm_svc.h b/secure_fw/core/tfm_svc.h
index 60c9ac8..44ad9ff 100644
--- a/secure_fw/core/tfm_svc.h
+++ b/secure_fw/core/tfm_svc.h
@@ -20,6 +20,27 @@
     TFM_SVC_SPM_REQUEST,
     TFM_SVC_PRINT,
     TFM_SVC_GET_BOOT_DATA,
+#ifdef TFM_PSA_API
+    TFM_SVC_IPC_REQUEST,
+    TFM_SVC_SCHEDULE,
+    /* PSA Client SVC */
+    TFM_SVC_PSA_FRAMEWORK_VERSION,
+    TFM_SVC_PSA_VERSION,
+    TFM_SVC_PSA_CONNECT,
+    TFM_SVC_PSA_CALL,
+    TFM_SVC_PSA_CLOSE,
+    /* PSA Service SVC */
+    TFM_SVC_PSA_WAIT,
+    TFM_SVC_PSA_GET,
+    TFM_SVC_PSA_SET_RHANDLE,
+    TFM_SVC_PSA_READ,
+    TFM_SVC_PSA_SKIP,
+    TFM_SVC_PSA_WRITE,
+    TFM_SVC_PSA_REPLY,
+    TFM_SVC_PSA_NOTIFY,
+    TFM_SVC_PSA_CLEAR,
+    TFM_SVC_PSA_EOI,
+#endif
 } tfm_svc_number_t;
 
 #define SVC(code) __ASM("svc %0" : : "I" (code))
diff --git a/secure_fw/ns_callable/tfm_veneers.c b/secure_fw/ns_callable/tfm_veneers.c
index ed69b94..9e9063f 100644
--- a/secure_fw/ns_callable/tfm_veneers.c
+++ b/secure_fw/ns_callable/tfm_veneers.c
@@ -30,6 +30,14 @@
 psa_status_t tfm_crypto_destroy_key(struct psa_invec *, size_t, struct psa_outvec *, size_t);
 psa_status_t tfm_crypto_get_key_information(struct psa_invec *, size_t, struct psa_outvec *, size_t);
 psa_status_t tfm_crypto_export_key(struct psa_invec *, size_t, struct psa_outvec *, size_t);
+psa_status_t tfm_crypto_key_policy_init(struct psa_invec *, size_t, struct psa_outvec *, size_t);
+psa_status_t tfm_crypto_key_policy_set_usage(struct psa_invec *, size_t, struct psa_outvec *, size_t);
+psa_status_t tfm_crypto_key_policy_get_usage(struct psa_invec *, size_t, struct psa_outvec *, size_t);
+psa_status_t tfm_crypto_key_policy_get_algorithm(struct psa_invec *, size_t, struct psa_outvec *, size_t);
+psa_status_t tfm_crypto_set_key_policy(struct psa_invec *, size_t, struct psa_outvec *, size_t);
+psa_status_t tfm_crypto_get_key_policy(struct psa_invec *, size_t, struct psa_outvec *, size_t);
+psa_status_t tfm_crypto_get_key_lifetime(struct psa_invec *, size_t, struct psa_outvec *, size_t);
+psa_status_t tfm_crypto_set_key_lifetime(struct psa_invec *, size_t, struct psa_outvec *, size_t);
 psa_status_t tfm_crypto_cipher_set_iv(struct psa_invec *, size_t, struct psa_outvec *, size_t);
 psa_status_t tfm_crypto_cipher_encrypt_setup(struct psa_invec *, size_t, struct psa_outvec *, size_t);
 psa_status_t tfm_crypto_cipher_decrypt_setup(struct psa_invec *, size_t, struct psa_outvec *, size_t);
@@ -41,6 +49,14 @@
 psa_status_t tfm_crypto_hash_finish(struct psa_invec *, size_t, struct psa_outvec *, size_t);
 psa_status_t tfm_crypto_hash_verify(struct psa_invec *, size_t, struct psa_outvec *, size_t);
 psa_status_t tfm_crypto_hash_abort(struct psa_invec *, size_t, struct psa_outvec *, size_t);
+psa_status_t tfm_crypto_mac_sign_setup(struct psa_invec *, size_t, struct psa_outvec *, size_t);
+psa_status_t tfm_crypto_mac_verify_setup(struct psa_invec *, size_t, struct psa_outvec *, size_t);
+psa_status_t tfm_crypto_mac_update(struct psa_invec *, size_t, struct psa_outvec *, size_t);
+psa_status_t tfm_crypto_mac_sign_finish(struct psa_invec *, size_t, struct psa_outvec *, size_t);
+psa_status_t tfm_crypto_mac_verify_finish(struct psa_invec *, size_t, struct psa_outvec *, size_t);
+psa_status_t tfm_crypto_mac_abort(struct psa_invec *, size_t, struct psa_outvec *, size_t);
+psa_status_t tfm_crypto_aead_decrypt_wrapper(struct psa_invec *, size_t, struct psa_outvec *, size_t);
+psa_status_t tfm_crypto_aead_encrypt_wrapper(struct psa_invec *, size_t, struct psa_outvec *, size_t);
 
 /******** TFM_SP_PLATFORM ********/
 psa_status_t platform_sp_system_reset(struct psa_invec *, size_t, struct psa_outvec *, size_t);
@@ -69,6 +85,14 @@
 psa_status_t tfm_secure_client_service_sfn_run_tests(struct psa_invec *, size_t, struct psa_outvec *, size_t);
 #endif /* TFM_PARTITION_TEST_SECURE_SERVICES */
 
+#ifdef TFM_PSA_API
+/******** TFM_SP_IPC_SERVICE_TEST ********/
+#endif /* TFM_PSA_API */
+
+#ifdef TFM_PSA_API
+/******** TFM_SP_IPC_CLIENT_TEST ********/
+#endif /* TFM_PSA_API */
+
 
 #define TFM_VENEER_FUNCTION(partition_name, sfn_name) \
     __tfm_secure_gateway_attributes__ \
@@ -101,6 +125,14 @@
 TFM_VENEER_FUNCTION(TFM_SP_CRYPTO, tfm_crypto_destroy_key)
 TFM_VENEER_FUNCTION(TFM_SP_CRYPTO, tfm_crypto_get_key_information)
 TFM_VENEER_FUNCTION(TFM_SP_CRYPTO, tfm_crypto_export_key)
+TFM_VENEER_FUNCTION(TFM_SP_CRYPTO, tfm_crypto_key_policy_init)
+TFM_VENEER_FUNCTION(TFM_SP_CRYPTO, tfm_crypto_key_policy_set_usage)
+TFM_VENEER_FUNCTION(TFM_SP_CRYPTO, tfm_crypto_key_policy_get_usage)
+TFM_VENEER_FUNCTION(TFM_SP_CRYPTO, tfm_crypto_key_policy_get_algorithm)
+TFM_VENEER_FUNCTION(TFM_SP_CRYPTO, tfm_crypto_set_key_policy)
+TFM_VENEER_FUNCTION(TFM_SP_CRYPTO, tfm_crypto_get_key_policy)
+TFM_VENEER_FUNCTION(TFM_SP_CRYPTO, tfm_crypto_get_key_lifetime)
+TFM_VENEER_FUNCTION(TFM_SP_CRYPTO, tfm_crypto_set_key_lifetime)
 TFM_VENEER_FUNCTION(TFM_SP_CRYPTO, tfm_crypto_cipher_set_iv)
 TFM_VENEER_FUNCTION(TFM_SP_CRYPTO, tfm_crypto_cipher_encrypt_setup)
 TFM_VENEER_FUNCTION(TFM_SP_CRYPTO, tfm_crypto_cipher_decrypt_setup)
@@ -112,6 +144,14 @@
 TFM_VENEER_FUNCTION(TFM_SP_CRYPTO, tfm_crypto_hash_finish)
 TFM_VENEER_FUNCTION(TFM_SP_CRYPTO, tfm_crypto_hash_verify)
 TFM_VENEER_FUNCTION(TFM_SP_CRYPTO, tfm_crypto_hash_abort)
+TFM_VENEER_FUNCTION(TFM_SP_CRYPTO, tfm_crypto_mac_sign_setup)
+TFM_VENEER_FUNCTION(TFM_SP_CRYPTO, tfm_crypto_mac_verify_setup)
+TFM_VENEER_FUNCTION(TFM_SP_CRYPTO, tfm_crypto_mac_update)
+TFM_VENEER_FUNCTION(TFM_SP_CRYPTO, tfm_crypto_mac_sign_finish)
+TFM_VENEER_FUNCTION(TFM_SP_CRYPTO, tfm_crypto_mac_verify_finish)
+TFM_VENEER_FUNCTION(TFM_SP_CRYPTO, tfm_crypto_mac_abort)
+TFM_VENEER_FUNCTION(TFM_SP_CRYPTO, tfm_crypto_aead_decrypt_wrapper)
+TFM_VENEER_FUNCTION(TFM_SP_CRYPTO, tfm_crypto_aead_encrypt_wrapper)
 
 /******** TFM_SP_PLATFORM ********/
 TFM_VENEER_FUNCTION(TFM_SP_PLATFORM, platform_sp_system_reset)
@@ -140,3 +180,11 @@
 TFM_VENEER_FUNCTION(TFM_SP_SECURE_TEST_PARTITION, tfm_secure_client_service_sfn_run_tests)
 #endif /* TFM_PARTITION_TEST_SECURE_SERVICES */
 
+#ifdef TFM_PSA_API
+/******** TFM_SP_IPC_SERVICE_TEST ********/
+#endif /* TFM_PSA_API */
+
+#ifdef TFM_PSA_API
+/******** TFM_SP_IPC_CLIENT_TEST ********/
+#endif /* TFM_PSA_API */
+
diff --git a/secure_fw/ns_callable/tfm_veneers.c.template b/secure_fw/ns_callable/tfm_veneers.c.template
index 0386d05..d57dc18 100644
--- a/secure_fw/ns_callable/tfm_veneers.c.template
+++ b/secure_fw/ns_callable/tfm_veneers.c.template
@@ -15,7 +15,7 @@
 @!GENERATOR_CONDITIONAL_START!@ @@attr.conditional@@
 #ifdef @@attr.conditional@@
 @!GENERATOR_CONDITIONAL_END!@
-/******** @@manifest.tfm_partition_name@@ ********/
+/******** @@manifest.name@@ ********/
 psa_status_t @@manifest.secure_functions.tfm_symbol@@(struct psa_invec *, size_t, struct psa_outvec *, size_t);
 @!GENERATOR_CONDITIONAL_START!@ @@attr.conditional@@
 #endif /* @@attr.conditional@@ */
@@ -39,8 +39,8 @@
 @!GENERATOR_CONDITIONAL_START!@ @@attr.conditional@@
 #ifdef @@attr.conditional@@
 @!GENERATOR_CONDITIONAL_END!@
-/******** @@manifest.tfm_partition_name@@ ********/
-TFM_VENEER_FUNCTION(@@manifest.tfm_partition_name@@, @@manifest.secure_functions.tfm_symbol@@)
+/******** @@manifest.name@@ ********/
+TFM_VENEER_FUNCTION(@@manifest.name@@, @@manifest.secure_functions.tfm_symbol@@)
 @!GENERATOR_CONDITIONAL_START!@ @@attr.conditional@@
 #endif /* @@attr.conditional@@ */
 @!GENERATOR_CONDITIONAL_END!@
diff --git a/secure_fw/services/audit_logging/manifest.yaml b/secure_fw/services/audit_logging/manifest.yaml
index 694b822..371ce2d 100644
--- a/secure_fw/services/audit_logging/manifest.yaml
+++ b/secure_fw/services/audit_logging/manifest.yaml
@@ -1,18 +1,16 @@
 #-------------------------------------------------------------------------------
-# Copyright (c) 2018, Arm Limited. All rights reserved.
+# Copyright (c) 2018-2019, Arm Limited. All rights reserved.
 #
 # SPDX-License-Identifier: BSD-3-Clause
 #
 #-------------------------------------------------------------------------------
 
 {
-  "name": "AUDIT_LOG",
-  "type": "TRUSTED",
-  "tfm_partition_name": "TFM_SP_AUDIT_LOG",
-  "tfm_trusted": true,
+  "name": "TFM_SP_AUDIT_LOG",
+  "type": "PSA-ROT",
   "priority": "NORMAL",
   "id": "0x00000101",
-  "entry_point": "main",
+  "entry_point": "audit_core_init",
   "stack_size": "0x1000",
   "heap_size": "0x0400",
   "mmio_regions" : [
@@ -22,7 +20,6 @@
       "conditional": "AUDIT_UART_REDIRECTION"
     }
   ],
-  "tfm_init_symbol": "audit_core_init",
   "secure_functions": [
     {
       "sfid": "TFM_AUDIT_RETRIEVE_RECORD_SFID",
diff --git a/secure_fw/services/crypto/manifest.yaml b/secure_fw/services/crypto/manifest.yaml
index e1030a3..fecd540 100644
--- a/secure_fw/services/crypto/manifest.yaml
+++ b/secure_fw/services/crypto/manifest.yaml
@@ -6,16 +6,13 @@
 #-------------------------------------------------------------------------------
 
 {
-  "name": "CRYPTO",
-  "type": "TRUSTED",
-  "tfm_partition_name": "TFM_SP_CRYPTO",
-  "tfm_trusted": true,
+  "name": "TFM_SP_CRYPTO",
+  "type": "PSA-ROT",
   "priority": "NORMAL",
   "id": "0x00000102",
-  "entry_point": "main",
+  "entry_point": "tfm_crypto_init",
   "stack_size": "0x2000",
   "heap_size": "0x0400",
-  "tfm_init_symbol": "tfm_crypto_init",
   "secure_functions": [
     {
       "sfid": "TFM_CRYPTO_IMPORT_KEY_SFID",
diff --git a/secure_fw/services/initial_attestation/manifest.yaml b/secure_fw/services/initial_attestation/manifest.yaml
index 2c83291..e57eee0 100644
--- a/secure_fw/services/initial_attestation/manifest.yaml
+++ b/secure_fw/services/initial_attestation/manifest.yaml
@@ -6,13 +6,11 @@
 #-------------------------------------------------------------------------------
 
 {
-  "name": "INITIAL_ATTESTATION",
-  "type": "TRUSTED",
-  "tfm_partition_name": "TFM_SP_INITIAL_ATTESTATION",
-  "tfm_trusted": true,
+  "name": "TFM_SP_INITIAL_ATTESTATION",
+  "type": "PSA-ROT",
   "priority": "NORMAL",
   "id": "0x00000103",
-  "entry_point": "main",
+  "entry_point": "attest_init",
   "stack_size": "0x0400",
   "heap_size": "0x0400",
   "tfm_init_symbol": "attest_init",
diff --git a/secure_fw/services/platform/manifest.yaml b/secure_fw/services/platform/manifest.yaml
index 8688ed6..e66b54e 100644
--- a/secure_fw/services/platform/manifest.yaml
+++ b/secure_fw/services/platform/manifest.yaml
@@ -1,21 +1,18 @@
 #-------------------------------------------------------------------------------
-# Copyright (c) 2018, Arm Limited. All rights reserved.
+# Copyright (c) 2018-2019, Arm Limited. All rights reserved.
 #
 # SPDX-License-Identifier: BSD-3-Clause
 #
 #-------------------------------------------------------------------------------
 
 {
-  "name": "SP_PLATFORM",
-  "type": "TRUSTED",
-  "tfm_partition_name": "TFM_SP_PLATFORM",
-  "tfm_trusted": true,
+  "name": "TFM_SP_PLATFORM",
+  "type": "PSA-ROT",
   "priority": "NORMAL",
   "id": "0x00000102",
-  "entry_point": "main",
+  "entry_point": "platform_sp_init",
   "stack_size": "0x0400",
   "heap_size": "0x0400",
-  "tfm_init_symbol": "platform_sp_init",
   "secure_functions": [
     {
       "sfid": "TFM_SP_PLATFORM_SYSTEM_RESET_SFID",
diff --git a/secure_fw/services/secure_storage/manifest.yaml b/secure_fw/services/secure_storage/manifest.yaml
index f6f63c1..86e2bc7 100644
--- a/secure_fw/services/secure_storage/manifest.yaml
+++ b/secure_fw/services/secure_storage/manifest.yaml
@@ -6,16 +6,13 @@
 #-------------------------------------------------------------------------------
 
 {
-  "name": "SST",
-  "type": "TRUSTED",
-  "tfm_partition_name": "TFM_SP_STORAGE",
-  "tfm_trusted": true,
+  "name": "TFM_SP_STORAGE",
+  "type": "PSA-ROT",
   "priority": "NORMAL",
   "id": "0x00000100",
-  "entry_point": "main",
+  "entry_point": "tfm_sst_init",
   "stack_size": "0x2000",
   "heap_size": "0x0400",
-  "tfm_init_symbol": "tfm_sst_init",
   "secure_functions": [
     {
       "sfid": "TFM_SST_SET_SFID",
diff --git a/secure_fw/services/tfm_partition_defs.inc b/secure_fw/services/tfm_partition_defs.inc
index 2fe3ac6..ab0cb28 100644
--- a/secure_fw/services/tfm_partition_defs.inc
+++ b/secure_fw/services/tfm_partition_defs.inc
@@ -32,6 +32,14 @@
 #define TFM_SP_SECURE_TEST_PARTITION_ID (TFM_SP_BASE + 7)
 #endif /* TFM_PARTITION_TEST_SECURE_SERVICES */
 
-#define TFM_MAX_USER_PARTITIONS (8)
+#ifdef TFM_PSA_API
+#define TFM_SP_IPC_SERVICE_TEST_ID (TFM_SP_BASE + 8)
+#endif /* TFM_PSA_API */
+
+#ifdef TFM_PSA_API
+#define TFM_SP_IPC_CLIENT_TEST_ID (TFM_SP_BASE + 9)
+#endif /* TFM_PSA_API */
+
+#define TFM_MAX_USER_PARTITIONS (10)
 
 #endif /* __TFM_PARTITION_DEFS_INC__ */
diff --git a/secure_fw/services/tfm_partition_defs.inc.template b/secure_fw/services/tfm_partition_defs.inc.template
index ad05eeb..12eeefc 100644
--- a/secure_fw/services/tfm_partition_defs.inc.template
+++ b/secure_fw/services/tfm_partition_defs.inc.template
@@ -14,7 +14,7 @@
 @!GENERATOR_CONDITIONAL_START!@ @@attr.conditional@@

 #ifdef @@attr.conditional@@

 @!GENERATOR_CONDITIONAL_END!@

-#define @@manifest.tfm_partition_name@@_ID (TFM_SP_BASE + @!GENERATOR_ITERATION_COUNTER!@)

+#define @@manifest.name@@_ID (TFM_SP_BASE + @!GENERATOR_ITERATION_COUNTER!@)

 @!GENERATOR_CONDITIONAL_START!@ @@attr.conditional@@

 #endif /* @@attr.conditional@@ */

 @!GENERATOR_CONDITIONAL_END!@

diff --git a/secure_fw/services/tfm_partition_list.inc b/secure_fw/services/tfm_partition_list.inc
index 7d3aadc..12213a6 100644
--- a/secure_fw/services/tfm_partition_list.inc
+++ b/secure_fw/services/tfm_partition_list.inc
@@ -11,46 +11,70 @@
 #define __TFM_PARTITION_LIST_INC__
 
 /******** TFM_SP_STORAGE ********/
-PARTITION_DECLARE(TFM_SP_STORAGE, SPM_PART_FLAG_SECURE | SPM_PART_FLAG_TRUSTED);
+PARTITION_DECLARE(TFM_SP_STORAGE, 0
+    , "PSA-ROT", 0x00000100, NORMAL);
 PARTITION_ADD_INIT_FUNC(TFM_SP_STORAGE, tfm_sst_init);
 
 /******** TFM_SP_AUDIT_LOG ********/
-PARTITION_DECLARE(TFM_SP_AUDIT_LOG, SPM_PART_FLAG_SECURE | SPM_PART_FLAG_TRUSTED);
+PARTITION_DECLARE(TFM_SP_AUDIT_LOG, 0
+    , "PSA-ROT", 0x00000101, NORMAL);
 PARTITION_ADD_INIT_FUNC(TFM_SP_AUDIT_LOG, audit_core_init);
 #ifdef AUDIT_UART_REDIRECTION
 PARTITION_ADD_PERIPHERAL(TFM_SP_AUDIT_LOG, TFM_PERIPHERAL_UART1);
 #endif /* AUDIT_UART_REDIRECTION */
 
 /******** TFM_SP_CRYPTO ********/
-PARTITION_DECLARE(TFM_SP_CRYPTO, SPM_PART_FLAG_SECURE | SPM_PART_FLAG_TRUSTED);
+PARTITION_DECLARE(TFM_SP_CRYPTO, 0
+    , "PSA-ROT", 0x00000102, NORMAL);
 PARTITION_ADD_INIT_FUNC(TFM_SP_CRYPTO, tfm_crypto_init);
 
 /******** TFM_SP_PLATFORM ********/
-PARTITION_DECLARE(TFM_SP_PLATFORM, SPM_PART_FLAG_SECURE | SPM_PART_FLAG_TRUSTED);
+PARTITION_DECLARE(TFM_SP_PLATFORM, 0
+    , "PSA-ROT", 0x00000102, NORMAL);
 PARTITION_ADD_INIT_FUNC(TFM_SP_PLATFORM, platform_sp_init);
 
 /******** TFM_SP_INITIAL_ATTESTATION ********/
-PARTITION_DECLARE(TFM_SP_INITIAL_ATTESTATION, SPM_PART_FLAG_SECURE | SPM_PART_FLAG_TRUSTED);
+PARTITION_DECLARE(TFM_SP_INITIAL_ATTESTATION, 0
+    , "PSA-ROT", 0x00000103, NORMAL);
 PARTITION_ADD_INIT_FUNC(TFM_SP_INITIAL_ATTESTATION, attest_init);
 
 #ifdef TFM_PARTITION_TEST_CORE
 /******** TFM_SP_CORE_TEST ********/
-PARTITION_DECLARE(TFM_SP_CORE_TEST, SPM_PART_FLAG_SECURE);
+PARTITION_DECLARE(TFM_SP_CORE_TEST, 0
+    , "APPLICATION-ROT", 0x00000002, NORMAL);
 PARTITION_ADD_INIT_FUNC(TFM_SP_CORE_TEST, core_test_init);
 PARTITION_ADD_PERIPHERAL(TFM_SP_CORE_TEST, TFM_PERIPHERAL_FPGA_IO);
 #endif /* TFM_PARTITION_TEST_CORE */
 
 #ifdef TFM_PARTITION_TEST_CORE
 /******** TFM_SP_CORE_TEST_2 ********/
-PARTITION_DECLARE(TFM_SP_CORE_TEST_2, SPM_PART_FLAG_SECURE);
+PARTITION_DECLARE(TFM_SP_CORE_TEST_2, 0
+    , "APPLICATION-ROT", 0x00000003, NORMAL);
 PARTITION_ADD_INIT_FUNC(TFM_SP_CORE_TEST_2, core_test_2_init);
 #endif /* TFM_PARTITION_TEST_CORE */
 
 #ifdef TFM_PARTITION_TEST_SECURE_SERVICES
 /******** TFM_SP_SECURE_TEST_PARTITION ********/
-PARTITION_DECLARE(TFM_SP_SECURE_TEST_PARTITION, SPM_PART_FLAG_SECURE | SPM_PART_FLAG_TRUSTED);
+PARTITION_DECLARE(TFM_SP_SECURE_TEST_PARTITION, 0
+    , "PSA-ROT", 0x00000005, NORMAL);
 PARTITION_ADD_INIT_FUNC(TFM_SP_SECURE_TEST_PARTITION, tfm_secure_client_service_init);
 PARTITION_ADD_PERIPHERAL(TFM_SP_SECURE_TEST_PARTITION, TFM_PERIPHERAL_STD_UART);
 #endif /* TFM_PARTITION_TEST_SECURE_SERVICES */
 
+#ifdef TFM_PSA_API
+/******** TFM_SP_IPC_SERVICE_TEST ********/
+PARTITION_DECLARE(TFM_SP_IPC_SERVICE_TEST, 0
+    | SPM_PART_FLAG_IPC
+    , "APPLICATION-ROT", 0x00000007, HIGH);
+PARTITION_ADD_INIT_FUNC(TFM_SP_IPC_SERVICE_TEST, ipc_service_test_main);
+#endif /* TFM_PSA_API */
+
+#ifdef TFM_PSA_API
+/******** TFM_SP_IPC_CLIENT_TEST ********/
+PARTITION_DECLARE(TFM_SP_IPC_CLIENT_TEST, 0
+    | SPM_PART_FLAG_IPC
+    , "APPLICATION-ROT", 0x00000006, NORMAL);
+PARTITION_ADD_INIT_FUNC(TFM_SP_IPC_CLIENT_TEST, ipc_client_init);
+#endif /* TFM_PSA_API */
+
 #endif /* __TFM_PARTITION_LIST_INC__ */
diff --git a/secure_fw/services/tfm_partition_list.inc.template b/secure_fw/services/tfm_partition_list.inc.template
index 3c5812b..5ab855e 100644
--- a/secure_fw/services/tfm_partition_list.inc.template
+++ b/secure_fw/services/tfm_partition_list.inc.template
@@ -14,18 +14,18 @@
 @!GENERATOR_CONDITIONAL_START!@ @@attr.conditional@@

 #ifdef @@attr.conditional@@

 @!GENERATOR_CONDITIONAL_END!@

-/******** @@manifest.tfm_partition_name@@ ********/

-@!GENERATOR_CONDITIONAL_START!@ @@manifest.tfm_trusted@@

-PARTITION_DECLARE(@@manifest.tfm_partition_name@@, SPM_PART_FLAG_SECURE | SPM_PART_FLAG_TRUSTED);

-@!GENERATOR_CONDITIONAL_ELSE!@

-PARTITION_DECLARE(@@manifest.tfm_partition_name@@, SPM_PART_FLAG_SECURE);

+/******** @@manifest.name@@ ********/

+PARTITION_DECLARE(@@manifest.name@@, 0

+@!GENERATOR_CONDITIONAL_START!@ @@manifest.tfm_partition_ipc@@

+    | SPM_PART_FLAG_IPC

 @!GENERATOR_CONDITIONAL_END!@

-PARTITION_ADD_INIT_FUNC(@@manifest.tfm_partition_name@@, @@manifest.tfm_init_symbol@@);

+    , "@@manifest.type@@", @@manifest.id@@, @@manifest.priority@@);

+PARTITION_ADD_INIT_FUNC(@@manifest.name@@, @@manifest.entry_point@@);

 @!GENERATOR_CONDITIONAL_START!@ @@manifest.mmio_regions.conditional@@

 #ifdef @@manifest.mmio_regions.conditional@@

 @!GENERATOR_CONDITIONAL_END!@

 @!GENERATOR_CONDITIONAL_START!@ @@manifest.mmio_regions.name@@

-PARTITION_ADD_PERIPHERAL(@@manifest.tfm_partition_name@@, @@manifest.mmio_regions.name@@);

+PARTITION_ADD_PERIPHERAL(@@manifest.name@@, @@manifest.mmio_regions.name@@);

 @!GENERATOR_CONDITIONAL_END!@

 @!GENERATOR_CONDITIONAL_START!@ @@manifest.mmio_regions.conditional@@

 #endif /* @@manifest.mmio_regions.conditional@@ */

diff --git a/secure_fw/services/tfm_service_list.inc b/secure_fw/services/tfm_service_list.inc
new file mode 100644
index 0000000..e953f2d
--- /dev/null
+++ b/secure_fw/services/tfm_service_list.inc
@@ -0,0 +1,44 @@
+/*
+ * Copyright (c) 2018-2019, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
+ */
+
+/*********** WARNING: This is an auto-generated file. Do not edit! ***********/
+
+#ifndef __TFM_SERVICE_LIST_INC__
+#define __TFM_SERVICE_LIST_INC__
+
+/******** TFM_SP_STORAGE ********/
+
+/******** TFM_SP_AUDIT_LOG ********/
+
+/******** TFM_SP_CRYPTO ********/
+
+/******** TFM_SP_PLATFORM ********/
+
+/******** TFM_SP_INITIAL_ATTESTATION ********/
+
+#ifdef TFM_PARTITION_TEST_CORE
+/******** TFM_SP_CORE_TEST ********/
+#endif /* TFM_PARTITION_TEST_CORE */
+
+#ifdef TFM_PARTITION_TEST_CORE
+/******** TFM_SP_CORE_TEST_2 ********/
+#endif /* TFM_PARTITION_TEST_CORE */
+
+#ifdef TFM_PARTITION_TEST_SECURE_SERVICES
+/******** TFM_SP_SECURE_TEST_PARTITION ********/
+#endif /* TFM_PARTITION_TEST_SECURE_SERVICES */
+
+#ifdef TFM_PSA_API
+/******** TFM_SP_IPC_SERVICE_TEST ********/
+{"IPC_SID_BASIC", TFM_SP_IPC_SERVICE_TEST_ID, IPC_BASIC_SIGNAL, 0x00001000, true, 1, TFM_VERSION_POLICY_STRICT},
+#endif /* TFM_PSA_API */
+
+#ifdef TFM_PSA_API
+/******** TFM_SP_IPC_CLIENT_TEST ********/
+#endif /* TFM_PSA_API */
+
+#endif /* __TFM_SERVICE_LIST_INC__ */
diff --git a/secure_fw/services/tfm_service_list.inc.template b/secure_fw/services/tfm_service_list.inc.template
new file mode 100644
index 0000000..f247fec
--- /dev/null
+++ b/secure_fw/services/tfm_service_list.inc.template
@@ -0,0 +1,26 @@
+/*
+ * Copyright (c) 2018-2019, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
+ */
+
+@!GENERATOR_DONOTEDIT_WARNING!@
+
+#ifndef __TFM_SERVICE_LIST_INC__
+#define __TFM_SERVICE_LIST_INC__
+
+@!GENERATOR_BLOCK_START!@
+@!GENERATOR_CONDITIONAL_START!@ @@attr.conditional@@
+#ifdef @@attr.conditional@@
+@!GENERATOR_CONDITIONAL_END!@
+/******** @@manifest.name@@ ********/
+@!GENERATOR_CONDITIONAL_START!@ @@manifest.services@@
+{"@@manifest.services.name@@", @@manifest.name@@_ID, @@manifest.services.signal@@, @@manifest.services.sid@@, @@manifest.services.non_secure_clients@@, @@manifest.services.minor_version@@, TFM_VERSION_POLICY_@@manifest.services.minor_policy@@},
+@!GENERATOR_CONDITIONAL_END!@
+@!GENERATOR_CONDITIONAL_START!@ @@attr.conditional@@
+#endif /* @@attr.conditional@@ */
+@!GENERATOR_CONDITIONAL_END!@
+
+@!GENERATOR_BLOCK_END!@
+#endif /* __TFM_SERVICE_LIST_INC__ */
diff --git a/secure_fw/services/tfm_sfid_list.inc b/secure_fw/services/tfm_sfid_list.inc
deleted file mode 100644
index 8f833bf..0000000
--- a/secure_fw/services/tfm_sfid_list.inc
+++ /dev/null
@@ -1,87 +0,0 @@
-/*
- * Copyright (c) 2018-2019, Arm Limited. All rights reserved.
- *
- * SPDX-License-Identifier: BSD-3-Clause
- *
- */
-
-/*********** WARNING: This is an auto-generated file. Do not edit! ***********/
-
-#ifndef __TFM_SFID_LIST_INC__
-#define __TFM_SFID_LIST_INC__
-
-    /******** TFM_SP_STORAGE ********/
-    {tfm_sst_set, TFM_SST_SET_SFID},
-    {tfm_sst_get, TFM_SST_GET_SFID},
-    {tfm_sst_get_info, TFM_SST_GET_INFO_SFID},
-    {tfm_sst_remove, TFM_SST_REMOVE_SFID},
-    {tfm_sst_get_support, TFM_SST_GET_SUPPORT_SFID},
-
-    /******** TFM_SP_AUDIT_LOG ********/
-    {audit_core_retrieve_record, TFM_AUDIT_RETRIEVE_RECORD_SFID},
-    {audit_core_add_record, TFM_AUDIT_ADD_RECORD_SFID},
-    {audit_core_get_info, TFM_AUDIT_GET_INFO_SFID},
-    {audit_core_get_record_info, TFM_AUDIT_GET_RECORD_INFO_SFID},
-    {audit_core_delete_record, TFM_AUDIT_DELETE_RECORD_SFID},
-
-    /******** TFM_SP_CRYPTO ********/
-    {tfm_crypto_import_key, TFM_CRYPTO_IMPORT_KEY_SFID},
-    {tfm_crypto_destroy_key, TFM_CRYPTO_DESTROY_KEY_SFID},
-    {tfm_crypto_get_key_information, TFM_CRYPTO_GET_KEY_INFORMATION_SFID},
-    {tfm_crypto_export_key, TFM_CRYPTO_EXPORT_KEY_SFID},
-    {tfm_crypto_key_policy_init, TFM_CRYPTO_KEY_POLICY_INIT_SFID},
-    {tfm_crypto_key_policy_set_usage, TFM_CRYPTO_KEY_POLICY_SET_USAGE_SFID},
-    {tfm_crypto_key_policy_get_usage, TFM_CRYPTO_KEY_POLICY_GET_USAGE_SFID},
-    {tfm_crypto_key_policy_get_algorithm, TFM_CRYPTO_KEY_POLICY_GET_ALGORITHM_SFID},
-    {tfm_crypto_set_key_policy, TFM_CRYPTO_SET_KEY_POLICY_SFID},
-    {tfm_crypto_get_key_policy, TFM_CRYPTO_GET_KEY_POLICY_SFID},
-    {tfm_crypto_get_key_lifetime, TFM_CRYPTO_GET_KEY_LIFETIME_SFID},
-    {tfm_crypto_set_key_lifetime, TFM_CRYPTO_SET_KEY_LIFETIME_SFID},
-    {tfm_crypto_cipher_set_iv, TFM_CRYPTO_CIPHER_SET_IV_SFID},
-    {tfm_crypto_cipher_encrypt_setup, TFM_CRYPTO_CIPHER_ENCRYPT_SETUP_SFID},
-    {tfm_crypto_cipher_decrypt_setup, TFM_CRYPTO_CIPHER_DECRYPT_SETUP_SFID},
-    {tfm_crypto_cipher_update_wrapper, TFM_CRYPTO_CIPHER_UPDATE_SFID},
-    {tfm_crypto_cipher_abort, TFM_CRYPTO_CIPHER_ABORT_SFID},
-    {tfm_crypto_cipher_finish, TFM_CRYPTO_CIPHER_FINISH_SFID},
-    {tfm_crypto_hash_setup, TFM_CRYPTO_HASH_SETUP_SFID},
-    {tfm_crypto_hash_update, TFM_CRYPTO_HASH_UPDATE_SFID},
-    {tfm_crypto_hash_finish, TFM_CRYPTO_HASH_FINISH_SFID},
-    {tfm_crypto_hash_verify, TFM_CRYPTO_HASH_VERIFY_SFID},
-    {tfm_crypto_hash_abort, TFM_CRYPTO_HASH_ABORT_SFID},
-    {tfm_crypto_mac_sign_setup, TFM_CRYPTO_MAC_SIGN_SETUP_SFID},
-    {tfm_crypto_mac_verify_setup, TFM_CRYPTO_MAC_VERIFY_SETUP_SFID},
-    {tfm_crypto_mac_update, TFM_CRYPTO_MAC_UPDATE_SFID},
-    {tfm_crypto_mac_sign_finish, TFM_CRYPTO_MAC_SIGN_FINISH_SFID},
-    {tfm_crypto_mac_verify_finish, TFM_CRYPTO_MAC_VERIFY_FINISH_SFID},
-    {tfm_crypto_mac_abort, TFM_CRYPTO_MAC_ABORT_SFID},
-    {tfm_crypto_aead_decrypt_wrapper, TFM_CRYPTO_AEAD_DECRYPT_SFID},
-    {tfm_crypto_aead_encrypt_wrapper, TFM_CRYPTO_AEAD_ENCRYPT_SFID},
-
-    /******** TFM_SP_PLATFORM ********/
-    {platform_sp_system_reset, TFM_SP_PLATFORM_SYSTEM_RESET_SFID},
-
-    /******** TFM_SP_INITIAL_ATTESTATION ********/
-    {initial_attest_get_token, TFM_ATTEST_GET_TOKEN_SFID},
-    {initial_attest_get_token_size, TFM_ATTEST_GET_TOKEN_SIZE_SFID},
-
-#ifdef TFM_PARTITION_TEST_CORE
-    /******** TFM_SP_CORE_TEST ********/
-    {spm_core_test_sfn, TFM_CORE_TEST_SFN_SFID},
-    {spm_core_test_sfn_init_success, TFM_CORE_TEST_SFN_INIT_SUCCESS_SFID},
-    {spm_core_test_sfn_direct_recursion, TFM_CORE_TEST_SFN_DIRECT_RECURSION_SFID},
-#endif /* TFM_PARTITION_TEST_CORE */
-
-#ifdef TFM_PARTITION_TEST_CORE
-    /******** TFM_SP_CORE_TEST_2 ********/
-    {spm_core_test_2_slave_service, TFM_CORE_TEST_2_SFN_SLAVE_SERVICE_SFID},
-    {spm_core_test_2_sfn_invert, TFM_CORE_TEST_2_SFN_INVERT_SFID},
-    {spm_core_test_2_check_caller_client_id, TFM_CORE_TEST_2_SFN_CHECK_CALLER_CLIENT_ID_SFID},
-    {spm_core_test_2_get_every_second_byte, TFM_CORE_TEST_2_SFN_GET_EVERY_SECOND_BYTE},
-#endif /* TFM_PARTITION_TEST_CORE */
-
-#ifdef TFM_PARTITION_TEST_SECURE_SERVICES
-    /******** TFM_SP_SECURE_TEST_PARTITION ********/
-    {tfm_secure_client_service_sfn_run_tests, TFM_SECURE_CLIENT_SFN_RUN_TESTS_SFID},
-#endif /* TFM_PARTITION_TEST_SECURE_SERVICES */
-
-#endif /* __TFM_SFID_LIST_INC__ */
diff --git a/secure_fw/services/tfm_sfid_list.inc.template b/secure_fw/services/tfm_sfid_list.inc.template
deleted file mode 100644
index 7f9bb92..0000000
--- a/secure_fw/services/tfm_sfid_list.inc.template
+++ /dev/null
@@ -1,24 +0,0 @@
-/*

- * Copyright (c) 2018-2019, Arm Limited. All rights reserved.

- *

- * SPDX-License-Identifier: BSD-3-Clause

- *

- */

-

-@!GENERATOR_DONOTEDIT_WARNING!@

-

-#ifndef __TFM_SFID_LIST_INC__

-#define __TFM_SFID_LIST_INC__

-

-@!GENERATOR_BLOCK_START!@

-@!GENERATOR_CONDITIONAL_START!@ @@attr.conditional@@

-#ifdef @@attr.conditional@@

-@!GENERATOR_CONDITIONAL_END!@

-    /******** @@manifest.tfm_partition_name@@ ********/

-    {@@manifest.secure_functions.tfm_symbol@@, @@manifest.secure_functions.sfid@@},

-@!GENERATOR_CONDITIONAL_START!@ @@attr.conditional@@

-#endif /* @@attr.conditional@@ */

-@!GENERATOR_CONDITIONAL_END!@

-

-@!GENERATOR_BLOCK_END!@

-#endif /* __TFM_SFID_LIST_INC__ */

diff --git a/secure_fw/spm/spm_api.c b/secure_fw/spm/spm_api.c
index efc4306..ff4eb11 100644
--- a/secure_fw/spm/spm_api.c
+++ b/secure_fw/spm/spm_api.c
@@ -118,7 +118,7 @@
             g_spm_partition_db.partition_count]);
     part_ptr->static_data.partition_id = TFM_SP_CORE_ID;
     part_ptr->static_data.partition_flags =
-                    SPM_PART_FLAG_SECURE | SPM_PART_FLAG_TRUSTED;
+                    SPM_PART_FLAG_APP_ROT | SPM_PART_FLAG_PSA_ROT;
     part_ptr->runtime_data.partition_state = SPM_PARTITION_STATE_UNINIT;
     ++g_spm_partition_db.partition_count;
 
@@ -142,6 +142,11 @@
     for (idx = 0; idx < g_spm_partition_db.partition_count; ++idx) {
         part = &g_spm_partition_db.partitions[idx];
         tfm_spm_hal_configure_default_isolation(part->platform_data);
+#ifdef TFM_PSA_API
+        if (part->static_data.partition_flags & SPM_PART_FLAG_IPC) {
+            continue;
+        }
+#endif
         if (part->static_data.partition_init == NULL) {
             tfm_spm_partition_set_state(idx, SPM_PARTITION_STATE_IDLE);
             tfm_spm_partition_set_caller_partition_idx(idx,
diff --git a/secure_fw/spm/spm_api.h b/secure_fw/spm/spm_api.h
index 0fa4c86..89d4564 100644
--- a/secure_fw/spm/spm_api.h
+++ b/secure_fw/spm/spm_api.h
@@ -33,8 +33,9 @@
 };
 
 enum spm_part_flag_mask_t {
-    SPM_PART_FLAG_SECURE  = 0x01,
-    SPM_PART_FLAG_TRUSTED = 0x02,
+    SPM_PART_FLAG_APP_ROT = 0x01,
+    SPM_PART_FLAG_PSA_ROT = 0x02,
+    SPM_PART_FLAG_IPC     = 0x04
 };
 
 /**
diff --git a/secure_fw/spm/spm_db.h b/secure_fw/spm/spm_db.h
index 512ede1..6b28f94 100644
--- a/secure_fw/spm/spm_db.h
+++ b/secure_fw/spm/spm_db.h
@@ -8,8 +8,37 @@
 #ifndef __SPM_DB_H__
 #define __SPM_DB_H__
 
+
+#ifdef TFM_PSA_API
+#include "tfm_thread.h"
+#endif
+
+struct spm_partition_desc_t;
+struct spm_partition_db_t;
+
 typedef psa_status_t(*sp_init_function)(void);
 
+#define TFM_PARTITION_TYPE_APP   "APPLICATION-ROT"
+#define TFM_PARTITION_TYPE_PSA   "PSA-ROT"
+
+#define TFM_STACK_SIZE  1024
+
+#ifdef TFM_PSA_API
+enum tfm_partition_priority {
+    TFM_PRIORITY_LOW = THRD_PRIOR_LOWEST,
+    TFM_PRIORITY_NORMAL = THRD_PRIOR_MEDIUM,
+    TFM_PRIORITY_HIGH = THRD_PRIOR_HIGHEST,
+};
+#else
+enum tfm_partition_priority {
+    TFM_PRIORITY_LOW = 0xFF,
+    TFM_PRIORITY_NORMAL = 0x7F,
+    TFM_PRIORITY_HIGH = 0,
+};
+#endif
+
+#define TFM_PRIORITY(LEVEL)      TFM_PRIORITY_##LEVEL
+
 /**
  * Holds the fields of the partition DB used by the SPM code. The values of
  * these fields are calculated at compile time, and set during initialisation
@@ -18,6 +47,7 @@
 struct spm_partition_static_data_t {
     uint32_t partition_id;
     uint32_t partition_flags;
+    uint32_t partition_priority;
     sp_init_function partition_init;
 };
 
@@ -32,6 +62,15 @@
 #if TFM_LVL != 1
     struct tfm_spm_partition_memory_data_t memory_data;
 #endif
+#ifdef TFM_PSA_API
+    struct tfm_thrd_ctx sp_thrd;
+    /*
+     * FixMe: Hard code stack is not aligned with the definition in the
+     * manifest. It will use the partition stacks in the linker scripts/sct
+     * files include Level 1 to 3.
+     */
+    uint8_t stack[TFM_STACK_SIZE] __attribute__((aligned(8)));
+#endif
 };
 
 /* Macros to pick linker symbols and allow to form the partition data base */
diff --git a/secure_fw/spm/spm_db_setup.h b/secure_fw/spm/spm_db_setup.h
index f4102cf1..d79fed9 100644
--- a/secure_fw/spm/spm_db_setup.h
+++ b/secure_fw/spm/spm_db_setup.h
@@ -31,10 +31,11 @@
     struct spm_partition_desc_t partitions[SPM_MAX_PARTITIONS];
 };
 
-#define PARTITION_INIT_STATIC_DATA(data, partition, flags) \
-    do {                                                   \
-        data.partition_id    = partition##_ID;             \
-        data.partition_flags = flags;                      \
+#define PARTITION_INIT_STATIC_DATA(data, partition, flags, id, priority)      \
+    do {                                                                      \
+        data.partition_id    = partition##_ID;                                \
+        data.partition_flags = flags;                                         \
+        data.partition_priority = TFM_PRIORITY(priority);                     \
     } while (0)
 
 #if TFM_LVL == 1
@@ -75,7 +76,7 @@
     } while (0)
 #endif
 
-#define PARTITION_DECLARE(partition, flags)                                  \
+#define PARTITION_DECLARE(partition, flag, type, id, priority)               \
     do {                                                                     \
         REGION_DECLARE(Image$$, partition, $$Base);                          \
         REGION_DECLARE(Image$$, partition, $$Limit);                         \
@@ -87,13 +88,24 @@
         REGION_DECLARE(Image$$, partition, _DATA$$ZI$$Limit);                \
         REGION_DECLARE(Image$$, partition, _STACK$$ZI$$Base);                \
         REGION_DECLARE(Image$$, partition, _STACK$$ZI$$Limit);               \
+        int32_t flags = flag;                                                \
+        if (tfm_memcmp(type, TFM_PARTITION_TYPE_APP,                         \
+            strlen(TFM_PARTITION_TYPE_APP)) == 0) {                          \
+            flags |= SPM_PART_FLAG_APP_ROT;                                  \
+        } else if (tfm_memcmp(type, TFM_PARTITION_TYPE_PSA,                  \
+                   strlen(TFM_PARTITION_TYPE_PSA)) == 0) {                   \
+            flags |= SPM_PART_FLAG_PSA_ROT | SPM_PART_FLAG_APP_ROT;          \
+        } else {                                                             \
+            return SPM_ERR_INVALID_CONFIG;                                   \
+        }                                                                    \
         struct spm_partition_desc_t *part_ptr;                               \
         if (g_spm_partition_db.partition_count >= SPM_MAX_PARTITIONS) {      \
             return SPM_ERR_INVALID_CONFIG;                                   \
         }                                                                    \
         part_ptr = &(g_spm_partition_db.partitions[                          \
             g_spm_partition_db.partition_count]);                            \
-        PARTITION_INIT_STATIC_DATA(part_ptr->static_data, partition, flags); \
+        PARTITION_INIT_STATIC_DATA(part_ptr->static_data, partition, flags,  \
+                                   id, priority);                            \
         PARTITION_INIT_RUNTIME_DATA(part_ptr->runtime_data, partition);      \
         PARTITION_INIT_MEMORY_DATA(part_ptr->memory_data, partition);        \
         ++g_spm_partition_db.partition_count;                                \
diff --git a/test/CMakeLists.inc b/test/CMakeLists.inc
index cb36a19..ffc662c 100644
--- a/test/CMakeLists.inc
+++ b/test/CMakeLists.inc
@@ -35,3 +35,4 @@
 include(${CMAKE_CURRENT_LIST_DIR}/suites/attestation/CMakeLists.inc)
 include(${CMAKE_CURRENT_LIST_DIR}/suites/qcbor/CMakeLists.inc)
 include(${CMAKE_CURRENT_LIST_DIR}/test_services/CMakeLists.inc)
+include(${CMAKE_CURRENT_LIST_DIR}/suites/ipc/CMakeLists.inc)
diff --git a/test/framework/non_secure_suites.c b/test/framework/non_secure_suites.c
index b458224..7c442c7 100644
--- a/test/framework/non_secure_suites.c
+++ b/test/framework/non_secure_suites.c
@@ -17,6 +17,7 @@
 #include "test/suites/qcbor/non_secure/qcbor_ns_tests.h"
 #include "test/suites/invert/non_secure/invert_ns_tests.h"
 #include "test/suites/core/non_secure/core_ns_tests.h"
+#include "test/suites/ipc/non_secure/ipc_ns_tests.h"
 
 static struct test_suite_t test_suites[] = {
 #if TFM_LVL == 3
@@ -69,6 +70,11 @@
     /* Non-secure interactive test cases */
     {&register_testsuite_ns_core_interactive, 0, 0, 0},
 #endif
+
+#ifdef CORE_TEST_IPC
+    /* Non-secure IPC test cases */
+    {&register_testsuite_ns_ipc_interface, 0, 0, 0},
+#endif
 };
 
 void start_integ_test(void)
diff --git a/test/framework/secure_suites.c b/test/framework/secure_suites.c
index 0f7bb64..4caf4ae 100644
--- a/test/framework/secure_suites.c
+++ b/test/framework/secure_suites.c
@@ -15,6 +15,7 @@
 #include "test/suites/attestation/secure/attestation_s_tests.h"
 #include "test/suites/invert/secure/invert_s_tests.h"
 #include "test/suites/crypto/secure/crypto_s_tests.h"
+#include "test/suites/ipc/secure/ipc_s_tests.h"
 
 static struct test_suite_t test_suites[] = {
 #if TFM_LVL == 3
@@ -48,6 +49,11 @@
     /* Note: since this is sample code, only run if test services are enabled */
     {&register_testsuite_s_invert_interface, 0, 0, 0},
 #endif /* TFM_PARTITION_TEST_CORE*/
+
+#ifdef CORE_TEST_IPC
+    /* Secure IPC test cases */
+    {&register_testsuite_s_ipc_interface, 0, 0, 0},
+#endif
 #endif /* SERVICES_TEST_S */
 #endif /* TFM_LVL == 3 */
 };
diff --git a/test/suites/ipc/CMakeLists.inc b/test/suites/ipc/CMakeLists.inc
new file mode 100644
index 0000000..c88de5b
--- /dev/null
+++ b/test/suites/ipc/CMakeLists.inc
@@ -0,0 +1,36 @@
+#-------------------------------------------------------------------------------
+# Copyright (c) 2018, Arm Limited. All rights reserved.
+#
+# SPDX-License-Identifier: BSD-3-Clause
+#
+#-------------------------------------------------------------------------------
+
+#Definitions to compile the "ipc test" module.
+#This file assumes it will be included from a project specific cmakefile, and
+#will not create a library or executable.
+#Inputs:
+#	TFM_ROOT_DIR - root directory of the TF-M repo.
+#
+#Outputs:
+#	Will modify include directories to make the source compile.
+#	ALL_SRC_C: C source files to be compiled will be added to this list. This shall be added to your add_executable or add_library command.
+#	ALL_SRC_CXX: C++ source files to be compiled will be added to this list. This shall be added to your add_executable or add_library command.
+#	ALL_SRC_ASM: assembly source files to be compiled will be added to this list. This shall be added to your add_executable or add_library command.
+#	Include directories will be modified by using the include_directories() commands as needed.
+
+#Get the current directory where this file is located.
+set(IPC_TEST_DIR ${CMAKE_CURRENT_LIST_DIR})
+if(NOT DEFINED TFM_ROOT_DIR)
+	message(FATAL_ERROR "Please set TFM_ROOT_DIR before including this file.")
+endif()
+
+if (NOT DEFINED CORE_TEST_IPC)
+	message(FATAL_ERROR "Incomplete build configuration: CORE_TEST_IPC is undefined. ")
+elseif(CORE_TEST_IPC)
+	list(APPEND ALL_SRC_C_S "${IPC_TEST_DIR}/secure/ipc_s_interface_testsuite.c")
+	list(APPEND ALL_SRC_C_NS "${IPC_TEST_DIR}/non_secure/ipc_ns_interface_testsuite.c")
+
+	#Setting include directories
+	embedded_include_directories(PATH ${TFM_ROOT_DIR} ABSOLUTE)
+	embedded_include_directories(PATH ${TFM_ROOT_DIR}/interface/include ABSOLUTE)
+endif()
diff --git a/test/suites/ipc/non_secure/ipc_ns_interface_testsuite.c b/test/suites/ipc/non_secure/ipc_ns_interface_testsuite.c
new file mode 100644
index 0000000..ad86b95
--- /dev/null
+++ b/test/suites/ipc/non_secure/ipc_ns_interface_testsuite.c
@@ -0,0 +1,133 @@
+/*
+ * Copyright (c) 2018-2019, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
+ */
+
+#include <stdio.h>
+#include "ipc_ns_tests.h"
+#include "psa_client.h"
+#include "test/framework/test_framework_helpers.h"
+
+#define IPC_TEST_SERVICE1_SID        (0x1000)
+#define IPC_TEST_SERVICE1_MIN_VER    (0x0001)
+
+/* List of tests */
+static void tfm_ipc_test_1001(struct test_result_t *ret);
+static void tfm_ipc_test_1002(struct test_result_t *ret);
+static void tfm_ipc_test_1003(struct test_result_t *ret);
+static void tfm_ipc_test_1004(struct test_result_t *ret);
+
+static struct test_t ipc_veneers_tests[] = {
+    {&tfm_ipc_test_1001, "TFM_IPC_TEST_1001",
+     "Get PSA framework version", {0} },
+    {&tfm_ipc_test_1002, "TFM_IPC_TEST_1002",
+     "Get minor version of a RoT Service", {0} },
+    {&tfm_ipc_test_1003, "TFM_IPC_TEST_1003",
+     "Connect to a RoT Service", {0} },
+    {&tfm_ipc_test_1004, "TFM_IPC_TEST_1004",
+     "Call a RoT Service", {0} }
+};
+
+void register_testsuite_ns_ipc_interface(struct test_suite_t *p_test_suite)
+{
+    uint32_t list_size;
+
+    list_size = (sizeof(ipc_veneers_tests) / sizeof(ipc_veneers_tests[0]));
+
+    set_testsuite("IPC non-secure interface test (TFM_IPC_TEST_1XXX)",
+                  ipc_veneers_tests, list_size, p_test_suite);
+}
+
+/**
+ * \brief Retrieve the version of the PSA Framework API.
+ *
+ * \note This is a functional test only and doesn't
+ *       mean to test all possible combinations of
+ *       input parameters and return values.
+ */
+static void tfm_ipc_test_1001(struct test_result_t *ret)
+{
+    uint32_t version;
+
+    version = psa_framework_version();
+    if (version == PSA_FRAMEWORK_VERSION) {
+        TEST_LOG("The version of the PSA Framework API is %d.\r\n", version);
+    } else {
+        TEST_FAIL("The version of the PSA Framework API is not valid!\r\n");
+        return;
+    }
+}
+
+/**
+ * \brief Retrieve the minor version of a RoT Service.
+ */
+static void tfm_ipc_test_1002(struct test_result_t *ret)
+{
+    uint32_t version;
+
+    version = psa_version(IPC_TEST_SERVICE1_SID);
+    if (version == PSA_VERSION_NONE) {
+        TEST_FAIL("RoT Service is not implemented or caller is not authorized" \
+                  "to access it!\r\n");
+        return;
+    } else {
+        /* Valid version number */
+        TEST_LOG("The minor version is %d.\r\n", version);
+    }
+    ret->val = TEST_PASSED;
+}
+
+/**
+ * \brief Connect to a RoT Service by its SID.
+ */
+static void tfm_ipc_test_1003(struct test_result_t *ret)
+{
+    psa_handle_t handle;
+
+    handle = psa_connect(IPC_TEST_SERVICE1_SID, IPC_TEST_SERVICE1_MIN_VER);
+    if (handle > 0) {
+        TEST_LOG("Connect success!\r\n");
+    } else {
+        TEST_FAIL("The RoT Service has refused the connection!\r\n");
+        return;
+    }
+    psa_close(handle);
+    ret->val = TEST_PASSED;
+}
+
+/**
+ * \brief Call a RoT Service.
+ */
+static void tfm_ipc_test_1004(struct test_result_t *ret)
+{
+    char str1[] = "str1";
+    char str2[] = "str2";
+    char str3[128], str4[128];
+    struct psa_invec invecs[2] = {{str1, sizeof(str1)/sizeof(char)},
+                                  {str2, sizeof(str2)/sizeof(char)}};
+    struct psa_outvec outvecs[2] = {{str3, sizeof(str3)/sizeof(char)},
+                                    {str4, sizeof(str4)/sizeof(char)}};
+    psa_handle_t handle;
+    psa_status_t status;
+    uint32_t min_version;
+
+    min_version = psa_version(IPC_TEST_SERVICE1_SID);
+    TEST_LOG("TFM service support minor version is %d.\r\n", min_version);
+    handle = psa_connect(IPC_TEST_SERVICE1_SID, IPC_TEST_SERVICE1_MIN_VER);
+    status = psa_call(handle, invecs, 2, outvecs, 2);
+    if (status >= 0) {
+        TEST_LOG("psa_call is successful!\r\n");
+    } else if (status == PSA_DROP_CONNECTION) {
+        TEST_FAIL("The connection has been dropped by the RoT Service!\r\n");
+        return;
+    } else {
+        TEST_FAIL("psa_call is failed!\r\n");
+        return;
+    }
+    TEST_LOG("outvec1 is: %s\r\n", outvecs[0].base);
+    TEST_LOG("outvec2 is: %s\r\n", outvecs[1].base);
+    psa_close(handle);
+    ret->val = TEST_PASSED;
+}
diff --git a/test/suites/ipc/non_secure/ipc_ns_tests.h b/test/suites/ipc/non_secure/ipc_ns_tests.h
new file mode 100644
index 0000000..12f3bb6
--- /dev/null
+++ b/test/suites/ipc/non_secure/ipc_ns_tests.h
@@ -0,0 +1,28 @@
+/*
+ * Copyright (c) 2018, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
+ */
+
+#ifndef __IPC_NS_TESTS_H__
+#define __IPC_NS_TESTS_H__
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include "test/framework/test_framework.h"
+
+/**
+ * \brief Register testsuite for ipc non-secure interface.
+ *
+ * \param[in] p_test_suite The test suite to be executed.
+ */
+void register_testsuite_ns_ipc_interface(struct test_suite_t *p_test_suite);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __IPC_NS_TESTS_H__ */
diff --git a/test/suites/ipc/secure/ipc_s_interface_testsuite.c b/test/suites/ipc/secure/ipc_s_interface_testsuite.c
new file mode 100644
index 0000000..62258b8
--- /dev/null
+++ b/test/suites/ipc/secure/ipc_s_interface_testsuite.c
@@ -0,0 +1,39 @@
+/*
+ * Copyright (c) 2018, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
+ */
+
+#include "ipc_s_tests.h"
+#include "psa_client.h"
+#include "test/framework/test_framework_helpers.h"
+
+/* List of tests */
+static void tfm_ipc_test_1001(struct test_result_t *ret);
+
+static struct test_t ipc_veneers_tests[] = {
+    {&tfm_ipc_test_1001, "TFM_IPC_TEST_1001", "Secure functional", {0} },
+};
+
+void register_testsuite_s_ipc_interface(struct test_suite_t *p_test_suite)
+{
+    uint32_t list_size;
+
+    list_size = (sizeof(ipc_veneers_tests) / sizeof(ipc_veneers_tests[0]));
+
+    set_testsuite("IPC secure interface test (TFM_IPC_TEST_1XXX)",
+                  ipc_veneers_tests, list_size, p_test_suite);
+}
+
+/**
+ * \brief Functional test of the Secure interface
+ *
+ * \note This is a functional test only and doesn't
+ *       mean to test all possible combinations of
+ *       input parameters and return values.
+ */
+static void tfm_ipc_test_1001(struct test_result_t *ret)
+{
+    ret->val = TEST_PASSED;
+}
diff --git a/test/suites/ipc/secure/ipc_s_tests.h b/test/suites/ipc/secure/ipc_s_tests.h
new file mode 100644
index 0000000..3b6a755
--- /dev/null
+++ b/test/suites/ipc/secure/ipc_s_tests.h
@@ -0,0 +1,28 @@
+/*
+ * Copyright (c) 2018, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
+ */
+
+#ifndef __IPC_S_TESTS_H__
+#define __IPC_S_TESTS_H__
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include "test/framework/test_framework.h"
+
+/**
+ * \brief Register testsuite for ipc secure interface.
+ *
+ * \param[in] p_test_suite The test suite to be executed.
+ */
+void register_testsuite_s_ipc_interface(struct test_suite_t *p_test_suite);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __IPC_S_TESTS_H__ */
diff --git a/test/test_services/CMakeLists.inc b/test/test_services/CMakeLists.inc
index 7006095..b91ae2c 100644
--- a/test/test_services/CMakeLists.inc
+++ b/test/test_services/CMakeLists.inc
@@ -48,6 +48,14 @@
 	list(APPEND ALL_SRC_C_NS "${CORE_TEST_DIR}/tfm_secure_client_service/tfm_secure_client_service_api.c")
 endif()
 
+if (NOT DEFINED CORE_TEST_IPC)
+	message(FATAL_ERROR "Incomplete build configuration: CORE_TEST_IPC is undefined. ")
+elseif (CORE_TEST_IPC)
+	list(APPEND ALL_SRC_C_S "${CORE_TEST_DIR}/tfm_ipc_service/tfm_ipc_service_test.c"
+		"${CORE_TEST_DIR}/tfm_ipc_client/tfm_ipc_client_test.c"
+		)
+endif()
+
 embedded_include_directories(PATH ${TFM_ROOT_DIR} ABSOLUTE)
 embedded_include_directories(PATH ${TFM_ROOT_DIR}/interface/include ABSOLUTE)
 
diff --git a/test/test_services/tfm_core_test/manifest.yaml b/test/test_services/tfm_core_test/manifest.yaml
index 076b650..58abfe1 100644
--- a/test/test_services/tfm_core_test/manifest.yaml
+++ b/test/test_services/tfm_core_test/manifest.yaml
@@ -1,17 +1,16 @@
 #-------------------------------------------------------------------------------
-# Copyright (c) 2018, Arm Limited. All rights reserved.
+# Copyright (c) 2018-2019, Arm Limited. All rights reserved.
 #
 # SPDX-License-Identifier: BSD-3-Clause
 #
 #-------------------------------------------------------------------------------
 
 {
-  "name": "TFM_CORE_TEST",
-  "tfm_partition_name": "TFM_SP_CORE_TEST",
-  "type": "SECURE",
+  "name": "TFM_SP_CORE_TEST",
+  "type": "APPLICATION-ROT",
   "priority": "NORMAL",
   "id": "0x00000002",
-  "entry_point": "main",
+  "entry_point": "core_test_init",
   "stack_size": "0x0400",
   "heap_size": "0x0400",
   "mmio_regions": [
@@ -20,7 +19,6 @@
       "permission": "READ-WRITE"
     }
   ],
-  "tfm_init_symbol": "core_test_init",
   "secure_functions": [
     {
       "sfid": "TFM_CORE_TEST_SFN_SFID",
diff --git a/test/test_services/tfm_core_test_2/manifest.yaml b/test/test_services/tfm_core_test_2/manifest.yaml
index b5b4fce..d95209f 100644
--- a/test/test_services/tfm_core_test_2/manifest.yaml
+++ b/test/test_services/tfm_core_test_2/manifest.yaml
@@ -1,20 +1,18 @@
 #-------------------------------------------------------------------------------
-# Copyright (c) 2018, Arm Limited. All rights reserved.
+# Copyright (c) 2018-2019, Arm Limited. All rights reserved.
 #
 # SPDX-License-Identifier: BSD-3-Clause
 #
 #-------------------------------------------------------------------------------
 
 {
-  "name": "TFM_CORE_TEST_2",
-  "tfm_partition_name": "TFM_SP_CORE_TEST_2",
-  "type": "SECURE",
+  "name": "TFM_SP_CORE_TEST_2",
+  "type": "APPLICATION-ROT",
   "priority": "NORMAL",
   "id": "0x00000003",
-  "entry_point": "main",
+  "entry_point": "core_test_2_init",
   "stack_size": "0x0400",
   "heap_size": "0x0400",
-  "tfm_init_symbol": "core_test_2_init",
   "secure_functions": [
     {
       "sfid": "TFM_CORE_TEST_2_SFN_SLAVE_SERVICE_SFID",
diff --git a/test/test_services/tfm_ipc_client/tfm_ipc_client_partition.yaml b/test/test_services/tfm_ipc_client/tfm_ipc_client_partition.yaml
new file mode 100644
index 0000000..781caa0
--- /dev/null
+++ b/test/test_services/tfm_ipc_client/tfm_ipc_client_partition.yaml
@@ -0,0 +1,27 @@
+#-------------------------------------------------------------------------------
+# Copyright (c) 2018-2019, Arm Limited. All rights reserved.
+#
+# SPDX-License-Identifier: BSD-3-Clause
+#
+#-------------------------------------------------------------------------------
+
+{
+  "name": "TFM_SP_IPC_CLIENT_TEST",
+  "type": "APPLICATION-ROT",
+  "priority": "NORMAL",
+  "id": "0x00000006",
+  "entry_point": "ipc_client_init",
+  "stack_size": "0x1000",
+  "heap_size": "0",
+  "secure_functions": [
+  ],
+  "tfm_partition_ipc": true,
+  "source_files": [
+    "ipc_client_test.c",
+  ],
+  "tfm_linker_pattern": {
+    "library_list": [
+      "*ipc_client_test*"
+    ]
+  }
+}
diff --git a/test/test_services/tfm_ipc_client/tfm_ipc_client_test.c b/test/test_services/tfm_ipc_client/tfm_ipc_client_test.c
new file mode 100644
index 0000000..f343a04
--- /dev/null
+++ b/test/test_services/tfm_ipc_client/tfm_ipc_client_test.c
@@ -0,0 +1,47 @@
+/*
+ * Copyright (c) 2018-2019, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
+ */
+
+#include <stdio.h>
+#include "psa_client.h"
+#include "secure_utilities.h"
+
+/* These SID should be same with service manifest.*/
+#define IPC_TEST_SERVICE1_SID        (0x1000)
+#define IPC_TEST_SERVICE1_MIN_VER    (0x0001)
+
+int ipc_client_init(void)
+{
+    psa_handle_t handle;
+    psa_status_t status;
+    char str1[] = "123";
+    char str2[] = "456";
+    char str3[64], str4[64];
+    struct psa_invec invecs[2] = {{str1, sizeof(str1)/sizeof(char)},
+                                  {str2, sizeof(str2)/sizeof(char)}};
+    struct psa_outvec outvecs[2] = {{str3, sizeof(str3)/sizeof(char)},
+                                    {str4, sizeof(str4)/sizeof(char)}};
+
+
+    LOG_MSG("hello! this is ipc client test sp!");
+
+    handle = psa_connect(IPC_TEST_SERVICE1_SID, IPC_TEST_SERVICE1_MIN_VER);
+    if (handle > 0) {
+        LOG_MSG("Connect success!");
+    } else {
+        LOG_MSG("The RoT Service has refused the connection!");
+    }
+
+    status = psa_call(handle, invecs, 2, outvecs, 2);
+    if (status >= 0) {
+        LOG_MSG("Call success!");
+    } else {
+        LOG_MSG("Call failed!");
+    }
+
+    psa_close(handle);
+    return 0;
+}
diff --git a/test/test_services/tfm_ipc_service/tfm_ipc_service_partition.h b/test/test_services/tfm_ipc_service/tfm_ipc_service_partition.h
new file mode 100644
index 0000000..759ccfa
--- /dev/null
+++ b/test/test_services/tfm_ipc_service/tfm_ipc_service_partition.h
@@ -0,0 +1,16 @@
+/*
+ * Copyright (c) 2018, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
+ */
+
+#ifndef __TFM_IPC_SERVICE_PARTITION_H__
+#define __TFM_IPC_SERVICE_PARTITION_H__
+
+/* FixMe: hardcode it for the tool cannot support now */
+#ifdef TFM_PSA_API
+#define IPC_BASIC_SIGNAL (1 << (0 + 4))
+#endif /* TFM_PSA_API */
+
+#endif /* __TFM_IPC_SERVICE_PARTITION_H__ */
diff --git a/test/test_services/tfm_ipc_service/tfm_ipc_service_partition.yaml b/test/test_services/tfm_ipc_service/tfm_ipc_service_partition.yaml
new file mode 100644
index 0000000..e9fcf32
--- /dev/null
+++ b/test/test_services/tfm_ipc_service/tfm_ipc_service_partition.yaml
@@ -0,0 +1,36 @@
+#-------------------------------------------------------------------------------
+# Copyright (c) 2018-2019, Arm Limited. All rights reserved.
+#
+# SPDX-License-Identifier: BSD-3-Clause
+#
+#-------------------------------------------------------------------------------
+
+{
+  "name": "TFM_SP_IPC_SERVICE_TEST",
+  "type": "APPLICATION-ROT",
+  "priority": "HIGH",
+  "id": "0x00000007",
+  "entry_point": "ipc_service_test_main",
+  "stack_size": "0x1000",
+  "heap_size": "0",
+  "secure_functions": [
+  ],
+  "tfm_partition_ipc": true,
+  "services" : [{
+    "name": "IPC_SID_BASIC",
+    "sid": "0x00001000",
+    "signal": "IPC_BASIC_SIGNAL",
+    "non_secure_clients": "true",
+    "minor_version": 1,
+    "minor_policy": "STRICT"
+   }
+  ],
+  "source_files": [
+    "./ipc_service_test.c",
+  ],
+  "tfm_linker_pattern": {
+    "library_list": [
+      "*ipc_service_test*"
+    ]
+  }
+}
diff --git a/test/test_services/tfm_ipc_service/tfm_ipc_service_test.c b/test/test_services/tfm_ipc_service/tfm_ipc_service_test.c
new file mode 100644
index 0000000..e8f25a8
--- /dev/null
+++ b/test/test_services/tfm_ipc_service/tfm_ipc_service_test.c
@@ -0,0 +1,75 @@
+/*
+ * Copyright (c) 2018-2019, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
+ */
+
+#include <assert.h>
+#include <stdio.h>
+#include "psa_client.h"
+#include "psa_service.h"
+#include "secure_fw/core/secure_utilities.h"
+#include "secure_fw/core/tfm_secure_api.h"
+#include "tfm_api.h"
+#include "tfm_ipc_service_partition.h"
+
+#define IPC_SERVICE_BUFFER_LEN 64
+
+static int inuse = 0;
+
+static psa_status_t ipc_service_call(psa_msg_t *msg)
+{
+    int i;
+    uint8_t rec_buf[IPC_SERVICE_BUFFER_LEN];
+    uint8_t send_buf[IPC_SERVICE_BUFFER_LEN] = "It is just for IPC call test.";
+
+    for (i = 0; i < PSA_MAX_IOVEC; i++) {
+        if (msg->in_size[i] != 0) {
+            psa_read(msg->handle, i, rec_buf, IPC_SERVICE_BUFFER_LEN);
+        }
+        if (msg->out_size[i] != 0) {
+            psa_write(msg->handle, i, send_buf, IPC_SERVICE_BUFFER_LEN);
+        }
+    }
+    return PSA_SUCCESS;
+}
+
+/* Test thread */
+void ipc_service_test_main(void *param)
+{
+    uint32_t signals = 0;
+    psa_msg_t msg;
+    psa_status_t r;
+
+    while (1) {
+        signals = psa_wait(PSA_WAIT_ANY, PSA_BLOCK);
+        if (signals & IPC_BASIC_SIGNAL) {
+            psa_get(IPC_BASIC_SIGNAL, &msg);
+            switch (msg.type) {
+            case PSA_IPC_CONNECT:
+                if (inuse) {
+                    r = PSA_CONNECTION_REFUSED;
+                } else {
+                    inuse = 1;
+                    r = PSA_SUCCESS;
+                }
+                psa_reply(msg.handle, r);
+                break;
+            case PSA_IPC_CALL:
+                psa_reply(msg.handle, ipc_service_call(&msg));
+                break;
+            case PSA_IPC_DISCONNECT:
+                assert (inuse == 1);
+                inuse = 0;
+                psa_reply(msg.handle, PSA_SUCCESS);
+                break;
+            default:
+                /* cannot get here? [broken SPM]. TODO*/
+                break;
+            }
+        }
+    }
+
+    return;
+}
diff --git a/test/test_services/tfm_secure_client_service/manifest.yaml b/test/test_services/tfm_secure_client_service/manifest.yaml
index 9ab5b62..79728ee 100644
--- a/test/test_services/tfm_secure_client_service/manifest.yaml
+++ b/test/test_services/tfm_secure_client_service/manifest.yaml
@@ -1,18 +1,16 @@
 #-------------------------------------------------------------------------------
-# Copyright (c) 2018, Arm Limited. All rights reserved.
+# Copyright (c) 2018-2019, Arm Limited. All rights reserved.
 #
 # SPDX-License-Identifier: BSD-3-Clause
 #
 #-------------------------------------------------------------------------------
 
 {
-  "name": "TFM_SECURE_CLIENT",
-  "tfm_partition_name": "TFM_SP_SECURE_TEST_PARTITION",
-  "type": "TRUSTED",
-  "tfm_trusted": true,
+  "name": "TFM_SP_SECURE_TEST_PARTITION",
+  "type": "PSA-ROT",
   "priority": "NORMAL",
   "id": "0x00000005",
-  "entry_point": "main",
+  "entry_point": "tfm_secure_client_service_init",
   "stack_size": "0x1000",
   "heap_size": "0x0400",
   "mmio_regions": [
@@ -21,7 +19,6 @@
       "permission": "READ-WRITE"
     }
   ],
-  "tfm_init_symbol": "tfm_secure_client_service_init",
   "secure_functions": [
     {
       "sfid": "TFM_SECURE_CLIENT_SFN_RUN_TESTS_SFID",
diff --git a/tools/tfm_generated_file_list.yaml b/tools/tfm_generated_file_list.yaml
index 2669953..23cc0a2 100644
--- a/tools/tfm_generated_file_list.yaml
+++ b/tools/tfm_generated_file_list.yaml
@@ -1,5 +1,5 @@
 #-------------------------------------------------------------------------------
-# Copyright (c) 2018, Arm Limited. All rights reserved.
+# Copyright (c) 2018-2019, Arm Limited. All rights reserved.
 #
 # SPDX-License-Identifier: BSD-3-Clause
 #
@@ -22,9 +22,9 @@
         "output": "secure_fw/services/tfm_partition_list.inc"
     },
     {
-        "name": "Secure Function list",
-        "short_name": "tfm_sfid_list",
-        "output": "secure_fw/services/tfm_sfid_list.inc"
+        "name": "Secure Service list",
+        "short_name": "tfm_service_list",
+        "output": "secure_fw/services/tfm_service_list.inc"
     },
     {
         "name": "AN521 secure ld file",
diff --git a/tools/tfm_manifest_list.yaml b/tools/tfm_manifest_list.yaml
index 15486d5..bbcdffd 100644
--- a/tools/tfm_manifest_list.yaml
+++ b/tools/tfm_manifest_list.yaml
@@ -77,6 +77,24 @@
       "conditional": "TFM_PARTITION_TEST_SECURE_SERVICES",

       "version_major": 0,

       "version_minor": 1

+    },

+    {

+      "name": "TFM IPC Service Test",

+      "short_name": "TFM_IPC_Service",

+      "manifest": "test/test_services/tfm_ipc_service/tfm_ipc_service_partition.yaml",

+      "tfm_extensions": true,

+      "conditional": "TFM_PSA_API",

+      "version_major": 0,

+      "version_minor": 1

+    },

+    {

+      "name": "TFM IPC Client Service",

+      "short_name": "TFM_IPC_Client",

+      "manifest": "test/test_services/tfm_ipc_client/tfm_ipc_client_partition.yaml",

+      "tfm_extensions": true,

+      "conditional": "TFM_PSA_API",

+      "version_major": 0,

+      "version_minor": 1

     }

   ]

 }