Test/App: Add the original test and app codes from tf-m

The version of the tf-m is:
ac9ccf207e153726b8dc1f5569f702f56d94297f

Change-Id: I445ada360540da55bbe74b3e7aa8d622e8fda501
Signed-off-by: Kevin Peng <kevin.peng@arm.com>
diff --git a/test/test_services/CMakeLists.inc b/test/test_services/CMakeLists.inc
new file mode 100644
index 0000000..f4f0482
--- /dev/null
+++ b/test/test_services/CMakeLists.inc
@@ -0,0 +1,101 @@
+#-------------------------------------------------------------------------------
+# Copyright (c) 2017-2020, Arm Limited. All rights reserved.
+#
+# SPDX-License-Identifier: BSD-3-Clause
+#
+#-------------------------------------------------------------------------------
+
+#Definitions to compile the "secure services" 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 repository.
+#
+#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(CORE_TEST_DIR ${CMAKE_CURRENT_LIST_DIR})
+
+#Check input variables
+if (NOT DEFINED TFM_ROOT_DIR)
+	message(FATAL_ERROR "Please set TFM_ROOT_DIR before including this file.")
+endif()
+
+if (NOT DEFINED ENABLE_CORE_TESTS)
+	message(FATAL_ERROR "Incomplete build configuration: ENABLE_CORE_TESTS is undefined. ")
+elseif(ENABLE_CORE_TESTS)
+	list(APPEND ALL_SRC_C_S "${CORE_TEST_DIR}/tfm_core_test/tfm_ss_core_test.c")
+endif()
+
+if (NOT DEFINED ENABLE_CORE_TESTS_2)
+	message(FATAL_ERROR "Incomplete build configuration: ENABLE_CORE_TESTS_2 is undefined. ")
+elseif(ENABLE_CORE_TESTS_2)
+	list(APPEND ALL_SRC_C_S "${CORE_TEST_DIR}/tfm_core_test_2/tfm_ss_core_test_2.c")
+endif()
+
+if (NOT DEFINED ENABLE_IRQ_TEST_SERVICES)
+	message(FATAL_ERROR "Incomplete build configuration: ENABLE_IRQ_TEST_SERVICES is undefined. ")
+elseif(ENABLE_IRQ_TEST_SERVICES)
+	list(APPEND ALL_SRC_C_S
+		"${CORE_TEST_DIR}/tfm_irq_test_service_1/tfm_irq_test_service_1.c")
+endif()
+
+if (NOT DEFINED TFM_PARTITION_TEST_SECURE_SERVICES)
+	message(FATAL_ERROR "Incomplete build configuration: TFM_PARTITION_TEST_SECURE_SERVICES is undefined. ")
+elseif (TFM_PARTITION_TEST_SECURE_SERVICES)
+	list(APPEND ALL_SRC_C_S "${CORE_TEST_DIR}/tfm_secure_client_service/tfm_secure_client_service.c"
+		"${CORE_TEST_DIR}/tfm_secure_client_2/tfm_secure_client_2.c"
+		"${CORE_TEST_DIR}/tfm_secure_client_2/tfm_secure_client_2_api.c")
+
+	list(APPEND ALL_SRC_C_NS "${CORE_TEST_DIR}/tfm_secure_client_service/tfm_secure_client_service_api.c")
+endif()
+
+if (NOT DEFINED TFM_PARTITION_TEST_CORE_IPC)
+	message(FATAL_ERROR "Incomplete build configuration: TFM_PARTITION_TEST_CORE_IPC is undefined. ")
+elseif (TFM_PARTITION_TEST_CORE_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()
+
+if (NOT DEFINED TFM_PARTITION_TEST_PS)
+	message(FATAL_ERROR "Incomplete build configuration: TFM_PARTITION_TEST_PS is undefined.")
+elseif (TFM_PARTITION_TEST_PS)
+	list(APPEND ALL_SRC_C_S "${CORE_TEST_DIR}/tfm_ps_test_service/tfm_ps_test_service.c"
+		"${CORE_TEST_DIR}/tfm_ps_test_service/tfm_ps_test_service_api.c")
+endif()
+
+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}/platform/include ABSOLUTE)
+embedded_include_directories(PATH ${TFM_ROOT_DIR}/secure_fw/include ABSOLUTE)
+
+set(BUILD_CMSIS_CORE Off)
+set(BUILD_RETARGET Off)
+set(BUILD_NATIVE_DRIVERS Off)
+set(BUILD_STARTUP Off)
+set(BUILD_TARGET_CFG Off)
+set(BUILD_TARGET_HARDWARE_KEYS Off)
+set(BUILD_TARGET_NV_COUNTERS Off)
+set(BUILD_CMSIS_DRIVERS Off)
+set(BUILD_UART_STDOUT Off)
+set(BUILD_FLASH Off)
+if (CORE_TEST_POSITIVE OR CORE_TEST_INTERACTIVE)
+	set(BUILD_PLAT_TEST On)
+	set(BUILD_TIME On)
+else()
+	set(BUILD_PLAT_TEST Off)
+	set(BUILD_TIME Off)
+endif()
+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/test/test_services/tfm_core_test/core_test_defs.h b/test/test_services/tfm_core_test/core_test_defs.h
new file mode 100644
index 0000000..819d2a8
--- /dev/null
+++ b/test/test_services/tfm_core_test/core_test_defs.h
@@ -0,0 +1,82 @@
+/*
+ * Copyright (c) 2017-2020, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
+ */
+
+#ifndef __CORE_TEST_DEFS_H__
+#define __CORE_TEST_DEFS_H__
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include <inttypes.h>
+#include <limits.h>
+#include "tfm_api.h"
+
+/* These definitions are used in symbols, only digits are permitted */
+#define CORE_TEST_ID_NS_THREAD            1001
+#define CORE_TEST_ID_CHECK_INIT           1003
+#define CORE_TEST_ID_RECURSION            1004
+#define CORE_TEST_ID_BUFFER_CHECK         1007
+#define CORE_TEST_ID_SS_TO_SS             1008
+#define CORE_TEST_ID_SS_TO_SS_BUFFER      1010
+#define CORE_TEST_ID_PERIPHERAL_ACCESS    1012
+#define CORE_TEST_ID_GET_CALLER_CLIENT_ID 1013
+#define CORE_TEST_ID_SPM_REQUEST          1014
+#define CORE_TEST_ID_IOVEC_SANITIZATION   1015
+#define CORE_TEST_ID_OUTVEC_WRITE         1016
+#define CORE_TEST_ID_SECURE_IRQ           1017
+#define CORE_TEST_ID_BLOCK                2001
+
+enum irq_test_scenario_t {
+    IRQ_TEST_SCENARIO_NONE,
+    IRQ_TEST_SCENARIO_1,
+    IRQ_TEST_SCENARIO_2,
+    IRQ_TEST_SCENARIO_3,
+    IRQ_TEST_SCENARIO_4,
+    IRQ_TEST_SCENARIO_5,
+};
+
+struct irq_test_execution_data_t {
+    volatile int32_t timer0_triggered;
+    volatile int32_t timer1_triggered;
+};
+
+/* Use lower 16 bits in return value for error code, upper 16 for line number
+ * in test service
+ */
+#define CORE_TEST_RETURN_ERROR(x) return (((__LINE__) << 16) | x)
+#define CORE_TEST_ERROR_GET_EXTRA(x) (x >> 16)
+#define CORE_TEST_ERROR_GET_CODE(x) (x & 0xFFFF)
+
+enum core_test_errno_t {
+    CORE_TEST_ERRNO_TEST_NOT_SUPPORTED         = -13,
+    CORE_TEST_ERRNO_SP_NOT_INITED              = -12,
+    CORE_TEST_ERRNO_UNEXPECTED_CORE_BEHAVIOUR  = -11,
+    CORE_TEST_ERRNO_SP_RECURSION_NOT_REJECTED  = -10,
+    CORE_TEST_ERRNO_INVALID_BUFFER             = -9,
+    CORE_TEST_ERRNO_SLAVE_SP_CALL_FAILURE      = -8,
+    CORE_TEST_ERRNO_SLAVE_SP_BUFFER_FAILURE    = -7,
+    CORE_TEST_ERRNO_FIRST_CALL_FAILED          = -6,
+    CORE_TEST_ERRNO_SECOND_CALL_FAILED         = -5,
+    CORE_TEST_ERRNO_PERIPHERAL_ACCESS_FAILED   = -4,
+    CORE_TEST_ERRNO_TEST_FAULT                 = -3,
+    CORE_TEST_ERRNO_INVALID_TEST_ID            = -2,
+    CORE_TEST_ERRNO_INVALID_PARAMETER          = -1,
+
+    CORE_TEST_ERRNO_SUCCESS                    =  0,
+
+    CORE_TEST_ERRNO_SUCCESS_2                  =  1,
+
+    /* Following entry is only to ensure the error code of int size */
+    CORE_TEST_ERRNO_FORCE_INT_SIZE = INT_MAX
+};
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __CORE_TEST_DEFS_H__ */
diff --git a/test/test_services/tfm_core_test/psa_manifest/tfm_test_core.h b/test/test_services/tfm_core_test/psa_manifest/tfm_test_core.h
new file mode 100644
index 0000000..e133c46
--- /dev/null
+++ b/test/test_services/tfm_core_test/psa_manifest/tfm_test_core.h
@@ -0,0 +1,32 @@
+/*
+ * Copyright (c) 2019-2020, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
+ */
+
+/*********** WARNING: This is an auto-generated file. Do not edit! ***********/
+
+#ifndef __PSA_MANIFEST_TFM_TEST_CORE_H__
+#define __PSA_MANIFEST_TFM_TEST_CORE_H__
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#define SPM_CORE_TEST_INIT_SUCCESS_SIGNAL                       (1U << (0 + 4))
+#define SPM_CORE_TEST_DIRECT_RECURSION_SIGNAL                   (1U << (1 + 4))
+#define SPM_CORE_TEST_SS_TO_SS_SIGNAL                           (1U << (2 + 4))
+#define SPM_CORE_TEST_SS_TO_SS_BUFFER_SIGNAL                    (1U << (3 + 4))
+#define SPM_CORE_TEST_OUTVEC_WRITE_SIGNAL                       (1U << (4 + 4))
+#define SPM_CORE_TEST_PERIPHERAL_ACCESS_SIGNAL                  (1U << (5 + 4))
+#define SPM_CORE_TEST_GET_CALLER_CLIENT_ID_SIGNAL               (1U << (6 + 4))
+#define SPM_CORE_TEST_SPM_REQUEST_SIGNAL                        (1U << (7 + 4))
+#define SPM_CORE_TEST_BLOCK_SIGNAL                              (1U << (8 + 4))
+#define SPM_CORE_TEST_NS_THREAD_SIGNAL                          (1U << (9 + 4))
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __PSA_MANIFEST_TFM_TEST_CORE_H__ */
diff --git a/test/test_services/tfm_core_test/tfm_ss_core_test.c b/test/test_services/tfm_core_test/tfm_ss_core_test.c
new file mode 100644
index 0000000..7390fc3
--- /dev/null
+++ b/test/test_services/tfm_core_test/tfm_ss_core_test.c
@@ -0,0 +1,593 @@
+/*
+ * Copyright (c) 2017-2020, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
+ */
+
+#include <stddef.h>
+#include "tfm_ss_core_test.h"
+#include "tfm_api.h"
+#include "test/test_services/tfm_core_test/core_test_defs.h"
+#include "test/framework/test_framework.h"
+#include "tfm_veneers.h"
+#include "tfm_secure_api.h"
+#include "secure_fw/include/tfm/tfm_spm_services.h"
+#include "psa/service.h"
+#include "tfm_plat_test.h"
+#include "psa_manifest/pid.h"
+#include "psa_manifest/tfm_test_core.h"
+#ifdef TFM_PSA_API
+#include "psa_manifest/sid.h"
+#endif
+
+static int32_t partition_init_done;
+
+#define INVALID_NS_CLIENT_ID  0x49abcdef
+#define EXPECTED_NS_CLIENT_ID (-1)
+
+#define IRQ_TEST_TOOL_CODE_LOCATION(name)
+
+#ifndef TFM_PSA_API
+/* Don't initialise caller_partition_id_zi and expect it to be linked in the
+ * zero-initialised data area
+ */
+static int32_t caller_client_id_zi;
+
+/* Initialise caller_partition_id_rw and expect it to be linked in the
+ * read-write data area
+ */
+static int32_t caller_client_id_rw = INVALID_NS_CLIENT_ID;
+
+static int32_t* invalid_addresses [] = {(int32_t*)0x0, (int32_t*)0xFFF12000};
+
+#else /* !defined(TFM_PSA_API) */
+
+static psa_status_t psa_test_common(uint32_t sid, uint32_t version,
+                                    const psa_invec *in_vecs, size_t in_len,
+                                    psa_outvec *out_vecs, size_t out_len)
+{
+    psa_handle_t handle;
+    psa_status_t status;
+
+    handle = psa_connect(sid, version);
+    if (handle <= 0) {
+        return CORE_TEST_ERRNO_INVALID_PARAMETER;
+    }
+
+    status = psa_call(handle, PSA_IPC_CALL, in_vecs, in_len, out_vecs, out_len);
+    if (status < 0) {
+        status = CORE_TEST_ERRNO_UNEXPECTED_CORE_BEHAVIOUR;
+    }
+
+    psa_close(handle);
+    return status;
+}
+#endif /* !defined(TFM_PSA_API) */
+
+psa_status_t spm_core_test_sfn_init_success(
+                                     struct psa_invec *in_vec, size_t in_len,
+                                     struct psa_outvec *out_vec, size_t out_len)
+{
+    if ((in_len != 0) || (out_len != 0)) {
+        return CORE_TEST_ERRNO_INVALID_PARAMETER;
+    }
+
+    if (partition_init_done) {
+        return CORE_TEST_ERRNO_SUCCESS;
+    } else {
+        return CORE_TEST_ERRNO_SP_NOT_INITED;
+    }
+}
+
+#ifndef TFM_PSA_API
+psa_status_t spm_core_test_sfn_direct_recursion(
+                                     struct psa_invec *in_vec, size_t in_len,
+                                     struct psa_outvec *out_vec, size_t out_len)
+{
+    uint32_t depth;
+    struct psa_invec new_vec = {NULL, sizeof(uint32_t)};
+
+    if ((in_len != 1) || (out_len != 0) ||
+        (in_vec[0].len != sizeof(uint32_t))) {
+            return CORE_TEST_ERRNO_INVALID_PARAMETER;
+    }
+
+    depth = *((uint32_t *)in_vec[0].base);
+
+    if (depth != 0) {
+        /* Protect against scenario where TF-M core fails to block recursion */
+        return CORE_TEST_ERRNO_SP_RECURSION_NOT_REJECTED;
+    }
+    /* Call to the same service again, should be rejected */
+    depth += 1;
+    new_vec.base = &depth;
+    int32_t ret = tfm_spm_core_test_sfn_direct_recursion_veneer(&new_vec,
+                                                                1, NULL, 0);
+
+    if (ret == CORE_TEST_ERRNO_SUCCESS) {
+        /* This is an unexpected return value */
+        return CORE_TEST_ERRNO_UNEXPECTED_CORE_BEHAVIOUR;
+    } else if (ret == CORE_TEST_ERRNO_SP_RECURSION_NOT_REJECTED) {
+        /* This means that service was started in recursion */
+        return CORE_TEST_ERRNO_SP_RECURSION_NOT_REJECTED;
+    } else {
+        return CORE_TEST_ERRNO_SUCCESS;
+    }
+}
+#endif /* !defined(TFM_PSA_API) */
+
+static psa_status_t test_peripheral_access(void)
+{
+#ifdef TFM_ENABLE_PERIPH_ACCESS_TEST
+    uint32_t leds;
+    uint32_t invleds;
+    uint32_t userled_mask;
+
+    leds = tfm_plat_test_get_led_status();
+    tfm_plat_test_set_led_status(~leds);
+    invleds = tfm_plat_test_get_led_status();
+    userled_mask = tfm_plat_test_get_userled_mask();
+
+    if ((invleds & userled_mask) != (~leds & userled_mask)) {
+        /* Code failed to invert value in peripheral reg */
+        return CORE_TEST_ERRNO_PERIPHERAL_ACCESS_FAILED;
+    }
+
+    return CORE_TEST_ERRNO_SUCCESS;
+#else
+    return CORE_TEST_ERRNO_TEST_NOT_SUPPORTED;
+#endif
+}
+
+#define SS_BUFFER_LEN 16
+
+static psa_status_t test_ss_to_ss_buffer(uint32_t *in_ptr, uint32_t *out_ptr,
+                                         int32_t len)
+{
+    int32_t i;
+    /* Service internal buffer */
+    uint32_t ss_buffer[SS_BUFFER_LEN] = {0};
+    uint32_t slave_buffer [len];
+    int32_t result;
+    int32_t *result_ptr = &result;
+    int32_t res;
+    psa_invec in_vec[] = { {slave_buffer, len*sizeof(uint32_t)} };
+    psa_outvec outvec[] = { {slave_buffer, len*sizeof(uint32_t)},
+                            {result_ptr, sizeof(int32_t)} };
+
+    if (len > SS_BUFFER_LEN) {
+        return CORE_TEST_ERRNO_TEST_FAULT;
+    }
+
+    for (i = 0; i < len; i++) {
+        ss_buffer[i] = in_ptr[i];
+    }
+
+    for (i = 0; i < len; i++) {
+        slave_buffer[i] = ss_buffer[i];
+    }
+
+    /* Call internal service with buffer handling */
+
+#ifdef TFM_PSA_API
+    res = psa_test_common(SPM_CORE_TEST_2_INVERT_SID,
+                          SPM_CORE_TEST_2_INVERT_VERSION,
+                          in_vec, 1, outvec, 2);
+#else /* defined(TFM_PSA_API) */
+    res = tfm_spm_core_test_2_sfn_invert_veneer(in_vec, 1, outvec, 2);
+#endif /* defined(TFM_PSA_API) */
+
+    if (res != CORE_TEST_ERRNO_SUCCESS) {
+        return CORE_TEST_ERRNO_SLAVE_SP_CALL_FAILURE;
+    }
+
+    for (i = 0; i < len; i++) {
+        if (slave_buffer[i] != ~ss_buffer[i]) {
+            return CORE_TEST_ERRNO_SLAVE_SP_BUFFER_FAILURE;
+        }
+        ss_buffer[i] = slave_buffer[i];
+    }
+
+    for (i = 0; i < len; i++) {
+        out_ptr[i] = ss_buffer[i];
+    }
+
+    return CORE_TEST_ERRNO_SUCCESS;
+}
+
+static psa_status_t test_outvec_write(void)
+{
+    int32_t err;
+    int i;
+    uint8_t data_buf [36]; /* (6 + 12) * 2 = 36 plus some alignment */
+    uint8_t *data_buf_ptr = data_buf;
+    psa_invec in_vec [2];
+    psa_outvec out_vec [2];
+    uint8_t *in_buf_0;
+    uint8_t *in_buf_1;
+    uint8_t *out_buf_0;
+    uint8_t *out_buf_1;
+
+    in_buf_0 = data_buf_ptr;
+    for (i = 0; i < 5; ++i, ++data_buf_ptr)
+    {
+        *data_buf_ptr = i;
+    }
+    in_vec[0].base = in_buf_0;
+    in_vec[0].len = data_buf_ptr - in_buf_0;
+
+    in_buf_1 = data_buf_ptr;
+    *(data_buf_ptr++) = 1;
+    *(data_buf_ptr++) = 1;
+    for (i = 2; i < 11; ++i, ++data_buf_ptr)
+    {
+        *data_buf_ptr = *(data_buf_ptr-1) + *(data_buf_ptr-2);
+    }
+    in_vec[1].base = in_buf_1;
+    in_vec[1].len = data_buf_ptr - in_buf_1;
+
+    out_buf_0 = data_buf_ptr;
+    data_buf_ptr += in_vec[0].len;
+    out_vec[0].base = out_buf_0;
+    out_vec[0].len = data_buf_ptr - out_buf_0;
+
+    out_buf_1 = data_buf_ptr;
+    data_buf_ptr += in_vec[1].len;
+    out_vec[1].base = out_buf_1;
+    out_vec[1].len = data_buf_ptr - out_buf_1;
+
+#ifdef TFM_PSA_API
+    err = psa_test_common(SPM_CORE_TEST_2_GET_EVERY_SECOND_BYTE_SID,
+                          SPM_CORE_TEST_2_GET_EVERY_SECOND_BYTE_VERSION,
+                          in_vec, 2, out_vec, 2);
+#else /* defined(TFM_PSA_API) */
+    err = tfm_spm_core_test_2_get_every_second_byte_veneer(in_vec, 2,
+                                                           out_vec, 2);
+#endif /* defined(TFM_PSA_API) */
+
+    if (err != CORE_TEST_ERRNO_SUCCESS) {
+        return CORE_TEST_ERRNO_TEST_FAULT;
+    }
+
+    if (out_vec[0].len != in_vec[0].len/2 ||
+        out_vec[1].len != in_vec[1].len/2) {
+        return CORE_TEST_ERRNO_TEST_FAULT;
+    }
+    for (i = 1; i < sizeof(in_buf_0); i += 2) {
+        if (((uint8_t *)out_vec[0].base)[i/2] != in_buf_0[i]) {
+            return CORE_TEST_ERRNO_TEST_FAULT;
+        }
+    }
+    for (i = 1; i < sizeof(in_buf_1); i += 2) {
+        if (((uint8_t *)out_vec[1].base)[i/2] != in_buf_1[i]) {
+            return CORE_TEST_ERRNO_TEST_FAULT;
+        }
+    }
+
+    return CORE_TEST_ERRNO_SUCCESS;
+}
+
+static psa_status_t test_ss_to_ss(void)
+{
+    int32_t ret;
+    /* Call to a different service, should be successful */
+    IRQ_TEST_TOOL_CODE_LOCATION(example_secure_service_start);
+#ifdef TFM_PSA_API
+    ret = psa_test_common(SPM_CORE_TEST_2_SLAVE_SERVICE_SID,
+                          SPM_CORE_TEST_2_SLAVE_SERVICE_VERSION,
+                          NULL, 0, NULL, 0);
+#else /* defined(TFM_PSA_API) */
+    ret = tfm_spm_core_test_2_slave_service_veneer(NULL, 0, NULL, 0);
+#endif /* defined(TFM_PSA_API) */
+    IRQ_TEST_TOOL_CODE_LOCATION(example_secure_service_end);
+    if (ret == CORE_TEST_ERRNO_SUCCESS_2) {
+        return CORE_TEST_ERRNO_SUCCESS;
+    } else {
+        return CORE_TEST_ERRNO_SLAVE_SP_CALL_FAILURE;
+    }
+}
+
+#ifndef TFM_PSA_API
+static psa_status_t test_get_caller_client_id(void)
+{
+    /* Call to a special service that checks the caller service ID */
+    size_t i;
+    int32_t ret;
+    int32_t caller_client_id_stack = INVALID_NS_CLIENT_ID;
+
+    caller_client_id_zi = INVALID_NS_CLIENT_ID;
+
+    ret = tfm_spm_core_test_2_check_caller_client_id_veneer(NULL, 0, NULL, 0);
+    if (ret != CORE_TEST_ERRNO_SUCCESS) {
+        return CORE_TEST_ERRNO_SLAVE_SP_CALL_FAILURE;
+    }
+
+    /* test with invalid output pointers */
+    for (i = 0; i < sizeof(invalid_addresses)/sizeof(invalid_addresses[0]); ++i)
+    {
+        ret = tfm_core_get_caller_client_id(invalid_addresses[i]);
+        if (ret != TFM_ERROR_INVALID_PARAMETER) {
+            return CORE_TEST_ERRNO_TEST_FAULT;
+        }
+    }
+
+    /* test with valid output pointers */
+    ret = tfm_core_get_caller_client_id(&caller_client_id_zi);
+    if (ret != TFM_SUCCESS || caller_client_id_zi != EXPECTED_NS_CLIENT_ID) {
+        return CORE_TEST_ERRNO_TEST_FAULT;
+    }
+
+    ret = tfm_core_get_caller_client_id(&caller_client_id_rw);
+    if (ret != TFM_SUCCESS || caller_client_id_rw != EXPECTED_NS_CLIENT_ID) {
+        return CORE_TEST_ERRNO_TEST_FAULT;
+    }
+
+    ret = tfm_core_get_caller_client_id(&caller_client_id_stack);
+    if (ret != TFM_SUCCESS ||
+            caller_client_id_stack != EXPECTED_NS_CLIENT_ID) {
+        return CORE_TEST_ERRNO_TEST_FAULT;
+    }
+
+    return CORE_TEST_ERRNO_SUCCESS;
+}
+
+static psa_status_t test_spm_request(void)
+{
+    /* Request a reset vote, should be successful */
+    int32_t ret = tfm_spm_request_reset_vote();
+
+    if (ret != TFM_SUCCESS) {
+        return CORE_TEST_ERRNO_SLAVE_SP_CALL_FAILURE;
+    }
+
+    return CORE_TEST_ERRNO_SUCCESS;
+}
+#endif /* !defined(TFM_PSA_API) */
+
+#ifdef CORE_TEST_INTERACTIVE
+static void wait_button_event(void)
+{
+    tfm_plat_test_wait_user_button_pressed();
+    /*
+     * The follow wait is required to skip multiple continues in one go due to
+     * the fast execution of the code and time used by the user to
+     * release button.
+     */
+
+    tfm_plat_test_wait_user_button_released();
+}
+
+psa_status_t test_wait_button(void)
+{
+    TEST_LOG("Inside the service, press button to continue...");
+    wait_button_event();
+    TEST_LOG("Leaving the service");
+    return CORE_TEST_ERRNO_SUCCESS;
+}
+#endif /* defined(CORE_TEST_INTERACTIVE) */
+
+static psa_status_t test_block(void)
+{
+#ifdef CORE_TEST_INTERACTIVE
+    /* Only block if interactive test is turned on */
+    return test_wait_button();
+#else /* defined(CORE_TEST_INTERACTIVE) */
+    /* This test should not be run if interactive tests are disabled */
+    return CORE_TEST_ERRNO_TEST_FAULT;
+#endif /* defined(CORE_TEST_INTERACTIVE) */
+}
+
+#ifndef TFM_PSA_API
+psa_status_t spm_core_test_sfn(struct psa_invec *in_vec, size_t in_len,
+                          struct psa_outvec *out_vec, size_t out_len)
+{
+    uint32_t tc;
+    int32_t arg1;
+    int32_t arg2;
+    int32_t arg3;
+
+    if ((in_len < 1) || (in_vec[0].len != sizeof(uint32_t))) {
+        return CORE_TEST_ERRNO_INVALID_PARAMETER;
+    }
+    tc = *((uint32_t *)in_vec[0].base);
+
+    switch (tc) {
+    case CORE_TEST_ID_SS_TO_SS:
+        return test_ss_to_ss();
+    case CORE_TEST_ID_SS_TO_SS_BUFFER:
+        if ((in_len != 3) || (out_len != 1) ||
+        (in_vec[2].len != sizeof(int32_t))) {
+            return CORE_TEST_ERRNO_INVALID_PARAMETER;
+        }
+        arg3 = *((int32_t *)in_vec[2].base);
+        if ((in_vec[1].len < arg3*sizeof(int32_t)) ||
+            (out_vec[0].len < arg3*sizeof(int32_t))) {
+            return CORE_TEST_ERRNO_INVALID_PARAMETER;
+        }
+        arg1 = (int32_t)in_vec[1].base;
+        arg2 = (int32_t)out_vec[0].base;
+        return test_ss_to_ss_buffer((uint32_t *)arg1, (uint32_t *)arg2, arg3);
+    case CORE_TEST_ID_OUTVEC_WRITE:
+        return test_outvec_write();
+    case CORE_TEST_ID_PERIPHERAL_ACCESS:
+        return test_peripheral_access();
+    case CORE_TEST_ID_GET_CALLER_CLIENT_ID:
+        return test_get_caller_client_id();
+    case CORE_TEST_ID_SPM_REQUEST:
+        return test_spm_request();
+    case CORE_TEST_ID_BLOCK:
+        return test_block();
+    case CORE_TEST_ID_NS_THREAD:
+        /* dummy service call is enough */
+        return CORE_TEST_ERRNO_SUCCESS;
+    default:
+        return CORE_TEST_ERRNO_INVALID_TEST_ID;
+    }
+}
+
+#else /* !defined(TFM_PSA_API) */
+
+#define SS_TO_SS_BUFFER_SIZE (16*4)
+
+typedef psa_status_t (*core_test_func_t)(psa_msg_t *msg);
+
+static psa_status_t tfm_core_test_sfn_wrap_init_success(psa_msg_t *msg)
+{
+    return spm_core_test_sfn_init_success(NULL, 0, NULL, 0);
+}
+
+static psa_status_t tfm_core_test_sfn_wrap_direct_recursion(psa_msg_t *msg)
+{
+    return CORE_TEST_ERRNO_TEST_FAULT;
+}
+
+static psa_status_t tfm_core_test_sfn_wrap_ss_to_ss(psa_msg_t *msg)
+{
+    return test_ss_to_ss();
+}
+
+static psa_status_t tfm_core_test_sfn_wrap_ss_to_ss_buffer(psa_msg_t *msg)
+{
+    size_t num;
+    uint32_t inbuf[SS_TO_SS_BUFFER_SIZE/sizeof(uint32_t)] = {0};
+    uint32_t outbuf[SS_TO_SS_BUFFER_SIZE/sizeof(uint32_t)] = {0};
+    uint32_t len;
+    psa_status_t res;
+
+    if ((msg->in_size[0] > SS_TO_SS_BUFFER_SIZE) ||
+        (msg->in_size[1] != sizeof(int32_t)) ||
+        (msg->out_size[0] > SS_TO_SS_BUFFER_SIZE)) {
+        return CORE_TEST_ERRNO_INVALID_PARAMETER;
+    }
+
+    num = psa_read(msg->handle, 0, inbuf, msg->in_size[0]);
+    if (num != msg->in_size[0]) {
+        return CORE_TEST_ERRNO_INVALID_PARAMETER;
+    }
+
+    num = psa_read(msg->handle, 1, &len, sizeof(int32_t));
+    if (num != sizeof(int32_t)) {
+        return CORE_TEST_ERRNO_INVALID_PARAMETER;
+    }
+
+    if (len > SS_TO_SS_BUFFER_SIZE) {
+        return CORE_TEST_ERRNO_INVALID_PARAMETER;
+    }
+
+    res = test_ss_to_ss_buffer(inbuf, outbuf, len);
+    if (res < 0) {
+        return res;
+    }
+
+    psa_write(msg->handle, 0, outbuf, len * sizeof(uint32_t));
+
+    return res;
+}
+
+static psa_status_t tfm_core_test_sfn_wrap_outvec_write(psa_msg_t *msg)
+{
+    return test_outvec_write();
+}
+
+static psa_status_t tfm_core_test_sfn_wrap_peripheral_access(psa_msg_t *msg)
+{
+    return test_peripheral_access();
+}
+
+static psa_status_t tfm_core_test_sfn_wrap_get_caller_client_id(psa_msg_t *msg)
+{
+    return CORE_TEST_ERRNO_TEST_NOT_SUPPORTED;
+}
+
+static psa_status_t tfm_core_test_sfn_wrap_spm_request(psa_msg_t *msg)
+{
+    return CORE_TEST_ERRNO_TEST_NOT_SUPPORTED;
+}
+
+static psa_status_t tfm_core_test_sfn_wrap_block(psa_msg_t *msg)
+{
+    return test_block();
+}
+
+static psa_status_t tfm_core_test_sfn_wrap_ns_thread(psa_msg_t *msg)
+{
+    return CORE_TEST_ERRNO_SUCCESS;
+}
+
+static void core_test_signal_handle(psa_signal_t signal, core_test_func_t pfn)
+{
+    psa_msg_t msg;
+    psa_status_t status;
+
+    status = psa_get(signal, &msg);
+    if (status) {
+        return;
+    }
+
+    switch (msg.type) {
+    case PSA_IPC_CONNECT:
+        psa_reply(msg.handle, PSA_SUCCESS);
+        break;
+    case PSA_IPC_CALL:
+        status = pfn(&msg);
+        psa_reply(msg.handle, status);
+        break;
+    case PSA_IPC_DISCONNECT:
+        psa_reply(msg.handle, PSA_SUCCESS);
+        break;
+    default:
+        break;
+    }
+}
+#endif /* !defined(TFM_PSA_API) */
+
+psa_status_t core_test_init(void)
+{
+#ifdef TFM_PSA_API
+    psa_signal_t signals = 0;
+#endif /* defined(TFM_PSA_API) */
+
+    partition_init_done = 1;
+
+#ifdef TFM_PSA_API
+    while (1) {
+        signals = psa_wait(PSA_WAIT_ANY, PSA_BLOCK);
+        if (signals & SPM_CORE_TEST_INIT_SUCCESS_SIGNAL) {
+            core_test_signal_handle(SPM_CORE_TEST_INIT_SUCCESS_SIGNAL,
+                                    tfm_core_test_sfn_wrap_init_success);
+        } else if (signals & SPM_CORE_TEST_DIRECT_RECURSION_SIGNAL) {
+            core_test_signal_handle(SPM_CORE_TEST_DIRECT_RECURSION_SIGNAL,
+                                    tfm_core_test_sfn_wrap_direct_recursion);
+        } else if (signals & SPM_CORE_TEST_SS_TO_SS_SIGNAL) {
+            core_test_signal_handle(SPM_CORE_TEST_SS_TO_SS_SIGNAL,
+                                    tfm_core_test_sfn_wrap_ss_to_ss);
+        } else if (signals & SPM_CORE_TEST_SS_TO_SS_BUFFER_SIGNAL) {
+            core_test_signal_handle(SPM_CORE_TEST_SS_TO_SS_BUFFER_SIGNAL,
+                                    tfm_core_test_sfn_wrap_ss_to_ss_buffer);
+        } else if (signals & SPM_CORE_TEST_OUTVEC_WRITE_SIGNAL) {
+            core_test_signal_handle(SPM_CORE_TEST_OUTVEC_WRITE_SIGNAL,
+                                    tfm_core_test_sfn_wrap_outvec_write);
+        } else if (signals & SPM_CORE_TEST_PERIPHERAL_ACCESS_SIGNAL) {
+            core_test_signal_handle(SPM_CORE_TEST_PERIPHERAL_ACCESS_SIGNAL,
+                                    tfm_core_test_sfn_wrap_peripheral_access);
+        } else if (signals & SPM_CORE_TEST_GET_CALLER_CLIENT_ID_SIGNAL) {
+            core_test_signal_handle(SPM_CORE_TEST_GET_CALLER_CLIENT_ID_SIGNAL,
+                                   tfm_core_test_sfn_wrap_get_caller_client_id);
+        } else if (signals & SPM_CORE_TEST_SPM_REQUEST_SIGNAL) {
+            core_test_signal_handle(SPM_CORE_TEST_SPM_REQUEST_SIGNAL,
+                                    tfm_core_test_sfn_wrap_spm_request);
+        } else if (signals & SPM_CORE_TEST_BLOCK_SIGNAL) {
+            core_test_signal_handle(SPM_CORE_TEST_BLOCK_SIGNAL,
+                                    tfm_core_test_sfn_wrap_block);
+        } else if (signals & SPM_CORE_TEST_NS_THREAD_SIGNAL) {
+            core_test_signal_handle(SPM_CORE_TEST_NS_THREAD_SIGNAL,
+                                    tfm_core_test_sfn_wrap_ns_thread);
+        } else {
+            ; /* do nothing */
+        }
+    }
+#else
+    return CORE_TEST_ERRNO_SUCCESS;
+#endif /* defined(TFM_PSA_API) */
+}
diff --git a/test/test_services/tfm_core_test/tfm_ss_core_test.h b/test/test_services/tfm_core_test/tfm_ss_core_test.h
new file mode 100644
index 0000000..eb9598f
--- /dev/null
+++ b/test/test_services/tfm_core_test/tfm_ss_core_test.h
@@ -0,0 +1,90 @@
+/*
+ * Copyright (c) 2017-2019, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
+ */
+
+#ifndef __TFM_SS_CORE_TEST_H__
+#define __TFM_SS_CORE_TEST_H__
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include <inttypes.h>
+#include <limits.h>
+#include "tfm_api.h"
+
+/**
+ * \brief Tests whether the initialisation of the service was successful.
+ *
+ * \param[in] in_vec    Array of psa_invec objects
+ * \param[in] in_len    Number psa_invec objects in in_vec
+ * \param[in] out_vec   Array of psa_outvec objects
+ * \param[in] out_len   Number psa_outvec objects in out_vec
+ *
+ * \param[in] in_vec    Array of psa_invec objects
+ * \param[in] in_len    Number psa_invec objects in in_vec
+ * \param[in] out_vec   Array of psa_outvec objects
+ * \param[in] out_len   Number psa_outvec objects in out_vec
+ *
+ * The function expects 0 in_vec objects.
+ * The function expects 0 out_vec objects.
+ *
+ * \return Returns \ref CORE_TEST_ERRNO_SUCCESS on success, and
+ *                 \ref CORE_TEST_ERRNO_SP_NOT_INITED on failure.
+ */
+psa_status_t spm_core_test_sfn_init_success(
+                                    struct psa_invec *in_vec, size_t in_len,
+                                    struct psa_outvec *out_vec, size_t out_len);
+
+/**
+ * \brief Tests what happens when a service calls itself directly.
+ *
+ * \param[in] in_vec    Array of psa_invec objects
+ * \param[in] in_len    Number psa_invec objects in in_vec
+ * \param[in] out_vec   Array of psa_outvec objects
+ * \param[in] out_len   Number psa_outvec objects in out_vec
+ *
+ * The function expects 1 in_vec object:
+ * in_vec[0].base: A buffer containing a pointer to an uint32_t value
+ *                 containing the current depth of the call (the value of the
+ *                 depth is 0 when first called).
+ * in_vec[0].len:  The size of a pointer in bytes.
+
+ * The function expects 0 out_vec objects.
+ *
+ * \return Returns \ref CORE_TEST_ERRNO_SUCCESS.
+ */
+psa_status_t spm_core_test_sfn_direct_recursion(
+                                    struct psa_invec *in_vec, size_t in_len,
+                                    struct psa_outvec *out_vec, size_t out_len);
+
+/**
+ * \brief Entry point for multiple test cases to be executed on the secure side.
+ *
+ * \param[in] in_vec    Array of psa_invec objects
+ * \param[in] in_len    Number psa_invec objects in in_vec
+ * \param[in] out_vec   Array of psa_outvec objects
+ * \param[in] out_len   Number psa_outvec objects in out_vec
+ *
+ * The function expects at least 1 in_vec object:
+ *
+ * in_vec[0].base: A buffer containing a pointer to an uint32_t value
+ *                 containing the testcase id to be executed.
+ * in_vec[0].len:  The size of a pointer in bytes.
+ *
+ * The number of expected additional in_vecs and out_vecs is dependent on the id
+ * of the test case. For details see the function implementation.
+ *
+ * \return Can return various error codes.
+ */
+psa_status_t spm_core_test_sfn(struct psa_invec *in_vec, size_t in_len,
+                          struct psa_outvec *out_vec, size_t out_len);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __TFM_SS_CORE_TEST_H__ */
diff --git a/test/test_services/tfm_core_test/tfm_test_core.yaml b/test/test_services/tfm_core_test/tfm_test_core.yaml
new file mode 100644
index 0000000..a7e6a81
--- /dev/null
+++ b/test/test_services/tfm_core_test/tfm_test_core.yaml
@@ -0,0 +1,121 @@
+#-------------------------------------------------------------------------------
+# Copyright (c) 2018-2020, Arm Limited. All rights reserved.
+#
+# SPDX-License-Identifier: BSD-3-Clause
+#
+#-------------------------------------------------------------------------------
+
+{
+  "psa_framework_version": 1.0,
+  "name": "TFM_SP_CORE_TEST",
+  "type": "PSA-ROT",
+  "priority": "NORMAL",
+  "entry_point": "core_test_init",
+  "stack_size": "0x0380",
+  "mmio_regions": [
+    {
+      "name": "TFM_PERIPHERAL_FPGA_IO",
+      "permission": "READ-WRITE"
+    }
+  ],
+  "secure_functions": [
+    {
+      "name": "TFM_CORE_TEST_SFN",
+      "signal": "SPM_CORE_TEST_SFN",
+      "non_secure_clients": true,
+      "version": 1,
+      "version_policy": "STRICT"
+    },
+    {
+      "name": "TFM_CORE_TEST_SFN_INIT_SUCCESS",
+      "signal": "SPM_CORE_TEST_SFN_INIT_SUCCESS",
+      "non_secure_clients": true,
+      "version": 1,
+      "version_policy": "STRICT"
+    },
+    {
+      "name": "TFM_CORE_TEST_SFN_DIRECT_RECURSION",
+      "signal": "SPM_CORE_TEST_SFN_DIRECT_RECURSION",
+      "non_secure_clients": true,
+      "version": 1,
+      "version_policy": "STRICT"
+    }
+  ],
+  "services": [
+    {
+      "name": "SPM_CORE_TEST_INIT_SUCCESS",
+      "sid": "0x0000F020",
+      "non_secure_clients": true,
+      "version": 1,
+      "version_policy": "STRICT"
+    },
+    {
+      "name": "SPM_CORE_TEST_DIRECT_RECURSION",
+      "sid": "0x0000F021",
+      "non_secure_clients": true,
+      "version": 1,
+      "version_policy": "STRICT"
+    },
+    {
+      "name": "SPM_CORE_TEST_SS_TO_SS",
+      "sid": "0x0000F024",
+      "non_secure_clients": true,
+      "version": 1,
+      "version_policy": "STRICT"
+    },
+    {
+      "name": "SPM_CORE_TEST_SS_TO_SS_BUFFER",
+      "sid": "0x0000F025",
+      "non_secure_clients": true,
+      "version": 1,
+      "version_policy": "STRICT"
+    },
+    {
+      "name": "SPM_CORE_TEST_OUTVEC_WRITE",
+      "sid": "0x0000F026",
+      "non_secure_clients": true,
+      "version": 1,
+      "version_policy": "STRICT"
+    },
+    {
+      "name": "SPM_CORE_TEST_PERIPHERAL_ACCESS",
+      "sid": "0x0000F027",
+      "non_secure_clients": true,
+      "version": 1,
+      "version_policy": "STRICT"
+    },
+    {
+      "name": "SPM_CORE_TEST_GET_CALLER_CLIENT_ID",
+      "sid": "0x0000F028",
+      "non_secure_clients": true,
+      "version": 1,
+      "version_policy": "STRICT"
+    },
+    {
+      "name": "SPM_CORE_TEST_SPM_REQUEST",
+      "sid": "0x0000F029",
+      "non_secure_clients": true,
+      "version": 1,
+      "version_policy": "STRICT"
+    },
+    {
+      "name": "SPM_CORE_TEST_BLOCK",
+      "sid": "0x0000F02A",
+      "non_secure_clients": true,
+      "version": 1,
+      "version_policy": "STRICT"
+    },
+    {
+      "name": "SPM_CORE_TEST_NS_THREAD",
+      "sid": "0x0000F02B",
+      "non_secure_clients": true,
+      "version": 1,
+      "version_policy": "STRICT"
+    }
+  ],
+  "dependencies": [
+    "SPM_CORE_TEST_2_INVERT",
+    "SPM_CORE_TEST_2_GET_EVERY_SECOND_BYTE",
+    "SPM_CORE_TEST_2_SLAVE_SERVICE"
+  ]
+}
diff --git a/test/test_services/tfm_core_test_2/psa_manifest/tfm_test_core_2.h b/test/test_services/tfm_core_test_2/psa_manifest/tfm_test_core_2.h
new file mode 100644
index 0000000..c636835
--- /dev/null
+++ b/test/test_services/tfm_core_test_2/psa_manifest/tfm_test_core_2.h
@@ -0,0 +1,28 @@
+/*
+ * Copyright (c) 2019-2020, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
+ */
+
+/*********** WARNING: This is an auto-generated file. Do not edit! ***********/
+
+#ifndef __PSA_MANIFEST_TFM_TEST_CORE_2_H__
+#define __PSA_MANIFEST_TFM_TEST_CORE_2_H__
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#define SPM_CORE_TEST_2_SLAVE_SERVICE_SIGNAL                    (1U << (0 + 4))
+#define SPM_CORE_TEST_2_CHECK_CALLER_CLIENT_ID_SIGNAL           (1U << (1 + 4))
+#define SPM_CORE_TEST_2_GET_EVERY_SECOND_BYTE_SIGNAL            (1U << (2 + 4))
+#define SPM_CORE_TEST_2_INVERT_SIGNAL                           (1U << (3 + 4))
+#define SPM_CORE_TEST_2_PREPARE_TEST_SCENARIO_SIGNAL            (1U << (4 + 4))
+#define SPM_CORE_TEST_2_EXECUTE_TEST_SCENARIO_SIGNAL            (1U << (5 + 4))
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __PSA_MANIFEST_TFM_TEST_CORE_2_H__ */
diff --git a/test/test_services/tfm_core_test_2/tfm_ss_core_test_2.c b/test/test_services/tfm_core_test_2/tfm_ss_core_test_2.c
new file mode 100644
index 0000000..e9d8c95
--- /dev/null
+++ b/test/test_services/tfm_core_test_2/tfm_ss_core_test_2.c
@@ -0,0 +1,478 @@
+/*
+ * Copyright (c) 2017-2020, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
+ */
+
+#include <stddef.h>
+#include "test/test_services/tfm_core_test/core_test_defs.h"
+#include "tfm_ss_core_test_2.h"
+#include "tfm_api.h"
+#include "tfm_secure_api.h"
+#include "psa/service.h"
+#include "psa_manifest/pid.h"
+#include "psa_manifest/tfm_test_core_2.h"
+
+#define INVALID_NS_CLIENT_ID  0x49abcdef
+#define INVERT_BUFFER_SIZE    (16*4)
+
+#ifndef TFM_PSA_API
+/* Don't initialise caller_partition_id_zi and expect it to be linked in the
+ * zero-initialised data area
+ */
+static int32_t caller_client_id_zi;
+
+/* Initialise caller_partition_id_rw and expect it to be linked in the
+ * read-write data area
+ */
+static int32_t caller_client_id_rw = INVALID_NS_CLIENT_ID;
+
+static int32_t* invalid_addresses [] = {(int32_t*)0x0, (int32_t*)0xFFF12000};
+#endif /* !defined(TFM_PSA_API) */
+
+/* structures for secure IRQ testing */
+static struct irq_test_execution_data_t *current_execution_data;
+
+psa_status_t spm_core_test_2_slave_service(struct psa_invec *in_vec,
+                                           size_t in_len,
+                                           struct psa_outvec *out_vec,
+                                           size_t out_len)
+{
+    /* This function doesn't do any sanity check on the input parameters, nor
+     * makes any expectation of them, always returns successfully, with a
+     * non-zero return value.
+     * This is to test the parameter sanitization mechanisms implemented in SPM,
+     * and the handling of non-zero success codes.
+     */
+
+    return CORE_TEST_ERRNO_SUCCESS_2;
+}
+
+#ifndef TFM_PSA_API
+psa_status_t spm_core_test_2_check_caller_client_id(struct psa_invec *in_vec,
+                                                    size_t in_len,
+                                                    struct psa_outvec *out_vec,
+                                                    size_t out_len)
+{
+    size_t i;
+    int32_t caller_client_id_stack = INVALID_NS_CLIENT_ID;
+    int32_t ret;
+
+    caller_client_id_zi = INVALID_NS_CLIENT_ID;
+
+    /* test with invalid output pointers */
+    for (i = 0; i < sizeof(invalid_addresses)/sizeof(invalid_addresses[0]); ++i)
+    {
+        ret = tfm_core_get_caller_client_id(invalid_addresses[i]);
+        if (ret != TFM_ERROR_INVALID_PARAMETER) {
+            return CORE_TEST_ERRNO_TEST_FAULT;
+        }
+    }
+
+    /* test with valid output pointers */
+    ret = tfm_core_get_caller_client_id(&caller_client_id_zi);
+    if (ret != TFM_SUCCESS || caller_client_id_zi != TFM_SP_CORE_TEST) {
+        return CORE_TEST_ERRNO_TEST_FAULT;
+    }
+
+    ret = tfm_core_get_caller_client_id(&caller_client_id_rw);
+    if (ret != TFM_SUCCESS || caller_client_id_rw != TFM_SP_CORE_TEST) {
+        return CORE_TEST_ERRNO_TEST_FAULT;
+    }
+
+    ret = tfm_core_get_caller_client_id(&caller_client_id_stack);
+    if (ret != TFM_SUCCESS ||
+            caller_client_id_stack != TFM_SP_CORE_TEST) {
+        return CORE_TEST_ERRNO_TEST_FAULT;
+    }
+
+    return CORE_TEST_ERRNO_SUCCESS;
+}
+#endif /* !defined(TFM_PSA_API) */
+
+psa_status_t spm_core_test_2_get_every_second_byte_internal(
+                                                           const uint8_t *inbuf,
+                                                           uint8_t *outbuf,
+                                                           size_t in_size,
+                                                           size_t *out_size)
+{
+    int j;
+
+    if (in_size/2 > *out_size) {
+        return CORE_TEST_ERRNO_INVALID_PARAMETER;
+    }
+    for (j = 1; j < in_size; j += 2) {
+        outbuf[j/2] = inbuf[j];
+    }
+    *out_size = in_size/2;
+
+    return CORE_TEST_ERRNO_SUCCESS;
+}
+
+psa_status_t spm_core_test_2_get_every_second_byte(
+                                     struct psa_invec *in_vec, size_t in_len,
+                                     struct psa_outvec *out_vec, size_t out_len)
+{
+    int i;
+    psa_status_t res;
+
+    if (in_len != out_len) {
+        return CORE_TEST_ERRNO_INVALID_PARAMETER;
+    }
+    for (i = 0; i < in_len; ++i) {
+        res = spm_core_test_2_get_every_second_byte_internal(
+                              in_vec[i].base, out_vec[i].base,
+                              in_vec[i].len, &out_vec[i].len);
+        if (res < 0) {
+            return res;
+        }
+    }
+    return CORE_TEST_ERRNO_SUCCESS;
+}
+
+/* Invert function */
+#define SFN_INVERT_MAX_LEN 128
+static psa_status_t spm_core_test_2_sfn_invert_internal(uint32_t *in_ptr,
+                                                        uint32_t *out_ptr,
+                                                        int32_t *res_ptr,
+                                                        int32_t len)
+{
+    int32_t i;
+    static uint32_t invert_buffer[SFN_INVERT_MAX_LEN];
+
+    *res_ptr = -1;
+
+    if (len > SFN_INVERT_MAX_LEN) {
+        return CORE_TEST_ERRNO_INVALID_BUFFER;
+    }
+
+    for (i = 0; i < len; i++) {
+        invert_buffer[i] = in_ptr[i];
+    }
+    for (i = 0; i < len; i++) {
+        invert_buffer[i] = ~invert_buffer[i];
+    }
+    for (i = 0; i < len; i++) {
+        out_ptr[i] = invert_buffer[i];
+    }
+
+    *res_ptr = 0;
+    return CORE_TEST_ERRNO_SUCCESS;
+}
+
+psa_status_t spm_core_test_2_sfn_invert(
+                                     struct psa_invec *in_vec, size_t in_len,
+                                     struct psa_outvec *out_vec, size_t out_len)
+{
+    int32_t len;
+    uint32_t *in_ptr;
+    uint32_t *out_ptr;
+    int32_t *res_ptr;
+
+    if ((in_len != 1) || (out_len != 2)) {
+        return CORE_TEST_ERRNO_INVALID_PARAMETER;
+    }
+
+    if ((out_vec[0].len < in_vec[0].len) || (in_vec[0].len%4 != 0) ||
+        (out_vec[1].len < sizeof(int32_t))) {
+        return CORE_TEST_ERRNO_INVALID_PARAMETER;
+    }
+
+    len = in_vec[0].len / 4;
+
+    in_ptr = (uint32_t *)in_vec[0].base;
+    out_ptr = (uint32_t *)out_vec[0].base;
+    res_ptr = (int32_t *)out_vec[1].base;
+
+    return spm_core_test_2_sfn_invert_internal(in_ptr, out_ptr, res_ptr, len);
+}
+
+static psa_status_t spm_core_test_2_prepare_test_scenario_internal(
+                               enum irq_test_scenario_t irq_test_scenario,
+                               struct irq_test_execution_data_t *execution_data)
+{
+    current_execution_data = execution_data;
+
+    switch (irq_test_scenario) {
+    case IRQ_TEST_SCENARIO_NONE:
+        return CORE_TEST_ERRNO_INVALID_PARAMETER;
+    case IRQ_TEST_SCENARIO_1:
+    case IRQ_TEST_SCENARIO_2:
+    case IRQ_TEST_SCENARIO_3:
+    case IRQ_TEST_SCENARIO_4:
+    case IRQ_TEST_SCENARIO_5:
+        /* No action is necessary*/
+        break;
+    default:
+        return CORE_TEST_ERRNO_INVALID_PARAMETER;
+    }
+
+    return CORE_TEST_ERRNO_SUCCESS;
+}
+
+psa_status_t spm_core_test_2_prepare_test_scenario(
+                             struct psa_invec *in_vec, size_t in_len,
+                             struct psa_outvec *out_vec, size_t out_size)
+{
+    if ((in_len != 2) ||
+        (in_vec[0].len != sizeof(uint32_t)) ||
+        (in_vec[1].len != sizeof(struct irq_test_execution_data_t *))) {
+        return CORE_TEST_ERRNO_INVALID_PARAMETER;
+    }
+
+    enum irq_test_scenario_t irq_test_scenario =
+            (enum irq_test_scenario_t) *(uint32_t *)in_vec[0].base;
+
+    struct irq_test_execution_data_t *execution_data =
+            *(struct irq_test_execution_data_t **)in_vec[1].base;
+
+    return spm_core_test_2_prepare_test_scenario_internal(irq_test_scenario,
+                                                          execution_data);
+}
+
+static psa_status_t spm_core_test_2_execute_test_scenario_internal(
+                                     enum irq_test_scenario_t irq_test_scenario)
+{
+    switch (irq_test_scenario) {
+    case IRQ_TEST_SCENARIO_NONE:
+        return CORE_TEST_ERRNO_INVALID_PARAMETER;
+    case IRQ_TEST_SCENARIO_1:
+        /* No action is necessary*/
+        break;
+    case IRQ_TEST_SCENARIO_2:
+        if (current_execution_data->timer0_triggered) {
+            return CORE_TEST_ERRNO_TEST_FAULT;
+        }
+        while (!current_execution_data->timer0_triggered) {
+            ;
+        }
+        break;
+    case IRQ_TEST_SCENARIO_3:
+    case IRQ_TEST_SCENARIO_4:
+        /* No action is necessary*/
+        break;
+    case IRQ_TEST_SCENARIO_5:
+        if (current_execution_data->timer1_triggered) {
+            return CORE_TEST_ERRNO_TEST_FAULT;
+        }
+        while (!current_execution_data->timer1_triggered) {
+            ;
+        }
+        break;
+    default:
+        return CORE_TEST_ERRNO_INVALID_PARAMETER;
+    }
+
+    return CORE_TEST_ERRNO_SUCCESS;
+}
+
+psa_status_t spm_core_test_2_execute_test_scenario(
+                                    struct psa_invec *in_vec, size_t in_len,
+                                    struct psa_outvec *out_vec, size_t out_size)
+{
+    enum irq_test_scenario_t irq_test_scenario =
+            (enum irq_test_scenario_t) *(uint32_t *)in_vec[0].base;
+
+    return spm_core_test_2_execute_test_scenario_internal(irq_test_scenario);
+}
+
+
+#ifdef TFM_PSA_API
+
+typedef psa_status_t (*core_test_2_func_t)(psa_msg_t *msg);
+
+static void core_test_2_signal_handle(psa_signal_t signal,
+                                      core_test_2_func_t pfn)
+{
+    psa_msg_t msg;
+    psa_status_t status;
+
+    status = psa_get(signal, &msg);
+    if (status) {
+        return;
+    }
+
+    switch (msg.type) {
+    case PSA_IPC_CONNECT:
+        psa_reply(msg.handle, PSA_SUCCESS);
+        break;
+    case PSA_IPC_CALL:
+        status = pfn(&msg);
+        psa_reply(msg.handle, status);
+        break;
+    case PSA_IPC_DISCONNECT:
+        psa_reply(msg.handle, PSA_SUCCESS);
+        break;
+    default:
+        break;
+    }
+}
+
+psa_status_t spm_core_test_2_wrap_slave_service(psa_msg_t *msg)
+{
+    return spm_core_test_2_slave_service(NULL, 0, NULL, 0);
+}
+
+psa_status_t spm_core_test_2_wrap_check_caller_client_id(psa_msg_t *msg)
+{
+    return CORE_TEST_ERRNO_TEST_NOT_SUPPORTED;
+}
+
+psa_status_t spm_core_test_2_wrap_get_every_second_byte(psa_msg_t *msg)
+{
+    uint32_t inbuf[INVERT_BUFFER_SIZE/sizeof(uint32_t)] = {0};
+    uint32_t outbuf[INVERT_BUFFER_SIZE/sizeof(uint32_t)] = {0};
+
+    int i;
+    size_t num;
+    size_t out_len;
+    psa_status_t res;
+
+    for (i = 0; i < PSA_MAX_IOVEC; ++i) {
+        if (msg->in_size[i] > INVERT_BUFFER_SIZE) {
+            return CORE_TEST_ERRNO_INVALID_PARAMETER;
+        }
+
+        if (msg->in_size[i] == 0) {
+            continue;
+        }
+
+        num = psa_read(msg->handle, i, inbuf, msg->in_size[i]);
+        if (num != msg->in_size[i]) {
+            return CORE_TEST_ERRNO_INVALID_PARAMETER;
+        }
+
+        out_len = msg->out_size[i];
+
+        res = spm_core_test_2_get_every_second_byte_internal((uint8_t *)inbuf,
+                (uint8_t *)outbuf, msg->in_size[i], &out_len);
+        if (res < 0) {
+            return res;
+        }
+
+        psa_write(msg->handle, i, outbuf, out_len);
+    }
+    return CORE_TEST_ERRNO_SUCCESS;
+}
+
+psa_status_t spm_core_test_2_wrap_sfn_invert(psa_msg_t *msg)
+{
+    uint32_t inbuf[INVERT_BUFFER_SIZE/sizeof(uint32_t)] = {0};
+    uint32_t outbuf[INVERT_BUFFER_SIZE/sizeof(uint32_t)] = {0};
+    size_t num;
+    int32_t res_ptr;
+    psa_status_t ret;
+
+    if ((msg->out_size[0] < msg->in_size[0]) ||
+        (msg->in_size[0] > INVERT_BUFFER_SIZE) ||
+        (msg->in_size[0]%4 != 0) ||
+        (msg->out_size[1] < sizeof(int32_t))) {
+        return CORE_TEST_ERRNO_INVALID_PARAMETER;
+    }
+
+    num = psa_read(msg->handle, 0, inbuf, msg->in_size[0]);
+    if (num != msg->in_size[0]) {
+        return CORE_TEST_ERRNO_INVALID_PARAMETER;
+    }
+
+    ret = spm_core_test_2_sfn_invert_internal(inbuf, outbuf,
+                                              &res_ptr, msg->in_size[0] / 4);
+    if (ret < 0) {
+        return ret;
+    }
+
+    psa_write(msg->handle, 0, outbuf, msg->in_size[0]);
+    psa_write(msg->handle, 1, &res_ptr, sizeof(int32_t));
+
+    return ret;
+}
+
+psa_status_t spm_core_test_2_wrap_prepare_test_scenario(psa_msg_t *msg)
+{
+    uint32_t irq_test_scenario;
+    struct irq_test_execution_data_t *execution_data;
+    size_t num;
+
+    if ((msg->in_size[0] != sizeof(uint32_t)) ||
+        (msg->in_size[1] != sizeof(struct irq_test_execution_data_t*)))  {
+        return CORE_TEST_ERRNO_INVALID_PARAMETER;
+    }
+
+    num = psa_read(msg->handle, 0, &irq_test_scenario, sizeof(irq_test_scenario));
+    if (num != msg->in_size[0]) {
+        return CORE_TEST_ERRNO_INVALID_PARAMETER;
+    }
+
+    num = psa_read(msg->handle, 1, &execution_data, sizeof(
+                                            struct irq_test_execution_data_t*));
+    if (num != msg->in_size[1]) {
+        return CORE_TEST_ERRNO_INVALID_PARAMETER;
+    }
+
+    return spm_core_test_2_prepare_test_scenario_internal((enum irq_test_scenario_t)
+                                                          irq_test_scenario,
+                                                          execution_data);
+}
+
+psa_status_t spm_core_test_2_wrap_execute_test_scenario(psa_msg_t *msg)
+{
+    uint32_t irq_test_scenario;
+    size_t num;
+
+    if (msg->in_size[0] != sizeof(uint32_t))  {
+        return CORE_TEST_ERRNO_INVALID_PARAMETER;
+    }
+
+    num = psa_read(msg->handle, 0, &irq_test_scenario, sizeof(irq_test_scenario));
+    if (num != msg->in_size[0]) {
+        return CORE_TEST_ERRNO_INVALID_PARAMETER;
+    }
+
+    return spm_core_test_2_execute_test_scenario_internal((enum irq_test_scenario_t)
+                                                          irq_test_scenario);
+}
+
+#endif /* defined(TFM_PSA_API) */
+
+/* FIXME: Add a testcase to test that a failed init makes the secure partition
+ * closed, and none of its functions can be called.
+ * A new test service for this purpose is to be added.
+ */
+psa_status_t core_test_2_init(void)
+{
+#ifdef TFM_PSA_API
+    psa_signal_t signals = 0;
+
+    while (1) {
+        signals = psa_wait(PSA_WAIT_ANY, PSA_BLOCK);
+        if (signals & SPM_CORE_TEST_2_SLAVE_SERVICE_SIGNAL) {
+            core_test_2_signal_handle(SPM_CORE_TEST_2_SLAVE_SERVICE_SIGNAL,
+                                      spm_core_test_2_wrap_slave_service);
+        } else if (signals & SPM_CORE_TEST_2_CHECK_CALLER_CLIENT_ID_SIGNAL) {
+            core_test_2_signal_handle(
+                                  SPM_CORE_TEST_2_CHECK_CALLER_CLIENT_ID_SIGNAL,
+                                  spm_core_test_2_wrap_check_caller_client_id);
+        } else if (signals & SPM_CORE_TEST_2_GET_EVERY_SECOND_BYTE_SIGNAL) {
+            core_test_2_signal_handle(
+                                   SPM_CORE_TEST_2_GET_EVERY_SECOND_BYTE_SIGNAL,
+                                   spm_core_test_2_wrap_get_every_second_byte);
+        } else if (signals & SPM_CORE_TEST_2_INVERT_SIGNAL) {
+            core_test_2_signal_handle(SPM_CORE_TEST_2_INVERT_SIGNAL,
+                                      spm_core_test_2_wrap_sfn_invert);
+        } else if (signals & SPM_CORE_TEST_2_PREPARE_TEST_SCENARIO_SIGNAL) {
+            core_test_2_signal_handle(
+                                   SPM_CORE_TEST_2_PREPARE_TEST_SCENARIO_SIGNAL,
+                                   spm_core_test_2_wrap_prepare_test_scenario);
+        } else if (signals & SPM_CORE_TEST_2_EXECUTE_TEST_SCENARIO_SIGNAL) {
+            core_test_2_signal_handle(
+                                   SPM_CORE_TEST_2_EXECUTE_TEST_SCENARIO_SIGNAL,
+                                   spm_core_test_2_wrap_execute_test_scenario);
+        } else {
+            ; /* do nothing */
+        }
+    }
+#else
+    return CORE_TEST_ERRNO_SUCCESS;
+#endif /* defined(TFM_PSA_API) */
+}
diff --git a/test/test_services/tfm_core_test_2/tfm_ss_core_test_2.h b/test/test_services/tfm_core_test_2/tfm_ss_core_test_2.h
new file mode 100644
index 0000000..44b12df
--- /dev/null
+++ b/test/test_services/tfm_core_test_2/tfm_ss_core_test_2.h
@@ -0,0 +1,85 @@
+/*
+ * Copyright (c) 2017-2019, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
+ */
+
+#ifndef __TFM_SS_CORE_TEST_2_H__
+#define __TFM_SS_CORE_TEST_2_H__
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include <inttypes.h>
+#include <limits.h>
+
+#include "tfm_api.h"
+
+/**
+ * \brief A minimal test service to be called from another service.
+ *
+ * \param[in] in_vec    Array of psa_invec objects
+ * \param[in] in_len    Number psa_invec objects in in_vec
+ * \param[in] out_vec   Array of psa_outvec objects
+ * \param[in] out_len   Number psa_outvec objects in out_vec
+ *
+ * The function expects 0 in_vec objects.
+ * The function expects 0 out_vec objects.
+ *
+ * \return Returns \ref TFM_SUCCESS.
+ */
+psa_status_t spm_core_test_2_slave_service(
+                                    struct psa_invec *in_vec, size_t in_len,
+                                    struct psa_outvec *out_vec, size_t out_len);
+
+
+/**
+ * \brief Bitwise inverts the buffer received as input.
+ *
+ * \param[in] in_vec    Array of psa_invec objects
+ * \param[in] in_len    Number psa_invec objects in in_vec
+ * \param[in] out_vec   Array of psa_outvec objects
+ * \param[in] out_len   Number psa_outvec objects in out_vec
+ *
+ * The function expects 2 in_vec objects:
+ * in_vec[0].base: A pointer to the buffer containing the data to be inverted
+ * in_vec[0].len:  The length of the buffer
+ * in_vec[1].base: A pointer to an int32_t object
+ * in_vec[1].len:  The size of int32_t object
+ *
+ * The function expects 1 out_vec object:
+ * out_vec[0].base: A pointer to the buffer to put the result to
+ * out_vec[0].len:  The length of the buffer
+ *
+ * \return Returns \ref TFM_SUCCESS on success, TFM_PARTITION_BUSY otherwise.
+ */
+psa_status_t spm_core_test_2_sfn_invert(struct psa_invec *in_vec, size_t in_len,
+                                   struct psa_outvec *out_vec, size_t out_len);
+
+/**
+ * \brief A minimal test secure function to be called from another partition.
+ *
+ * Checks the functionality of querying the client ID of the caller service.
+ *
+ * \param[in] in_vec    Array of psa_invec objects
+ * \param[in] in_len    Number psa_invec objects in in_vec
+ * \param[in] out_vec   Array of psa_outvec objects
+ * \param[in] out_len   Number psa_outvec objects in out_vec
+ *
+ * The function expects 0 in_vec objects.
+ * The function expects 0 out_vec objects.
+ *
+ * \return Returns \ref TFM_SUCCESS on success, \ref CORE_TEST_ERRNO_TEST_FAULT
+ *         othervise.
+ */
+    psa_status_t spm_core_test_2_check_caller_client_id(
+            struct psa_invec *in_vec, size_t in_len, struct psa_outvec *out_vec,
+            size_t out_len);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __TFM_SS_CORE_TEST_2_H__ */
diff --git a/test/test_services/tfm_core_test_2/tfm_test_core_2.yaml b/test/test_services/tfm_core_test_2/tfm_test_core_2.yaml
new file mode 100644
index 0000000..8b5d43c
--- /dev/null
+++ b/test/test_services/tfm_core_test_2/tfm_test_core_2.yaml
@@ -0,0 +1,103 @@
+#-------------------------------------------------------------------------------
+# Copyright (c) 2018-2020, Arm Limited. All rights reserved.
+#
+# SPDX-License-Identifier: BSD-3-Clause
+#
+#-------------------------------------------------------------------------------
+
+{
+  "psa_framework_version": 1.0,
+  "name": "TFM_SP_CORE_TEST_2",
+  "type": "APPLICATION-ROT",
+  "priority": "NORMAL",
+  "entry_point": "core_test_2_init",
+  "stack_size": "0x0280",
+  "secure_functions": [
+    {
+      "name": "TFM_CORE_TEST_2_SFN_SLAVE_SERVICE",
+      "signal": "SPM_CORE_TEST_2_SLAVE_SERVICE",
+      "non_secure_clients": false,
+      "version": 1,
+      "version_policy": "STRICT"
+    },
+    {
+      "name": "TFM_CORE_TEST_2_SFN_INVERT",
+      "signal": "SPM_CORE_TEST_2_SFN_INVERT",
+      "non_secure_clients": true,
+      "version": 1,
+      "version_policy": "STRICT"
+    },
+    {
+      "name": "TFM_CORE_TEST_2_SFN_CHECK_CALLER_CLIENT_ID",
+      "signal": "SPM_CORE_TEST_2_CHECK_CALLER_CLIENT_ID",
+      "non_secure_clients": true,
+      "version": 1,
+      "version_policy": "STRICT"
+    },
+    {
+      "name": "TFM_CORE_TEST_2_SFN_GET_EVERY_SECOND_BYTE",
+      "signal": "SPM_CORE_TEST_2_GET_EVERY_SECOND_BYTE",
+      "non_secure_clients": true,
+      "version": 1,
+      "version_policy": "STRICT"
+    },
+    {
+      "name": "TFM_CORE_TEST_2_SFN_PREPARE_TEST_SCENARIO",
+      "signal": "SPM_CORE_TEST_2_PREPARE_TEST_SCENARIO",
+      "non_secure_clients": true,
+      "version": 1,
+      "version_policy": "STRICT"
+    },
+    {
+      "name": "TFM_CORE_TEST_2_SFN_EXECUTE_TEST_SCENARIO",
+      "signal": "SPM_CORE_TEST_2_EXECUTE_TEST_SCENARIO",
+      "non_secure_clients": true,
+      "version": 1,
+      "version_policy": "STRICT"
+    }
+  ],
+  "services": [
+    {
+      "name": "SPM_CORE_TEST_2_SLAVE_SERVICE",
+      "sid": "0x0000F040",
+      "non_secure_clients": true,
+      "version": 1,
+      "version_policy": "STRICT"
+    },
+    {
+      "name": "SPM_CORE_TEST_2_CHECK_CALLER_CLIENT_ID",
+      "sid": "0x0000F041",
+      "non_secure_clients": true,
+      "version": 1,
+      "version_policy": "STRICT"
+    },
+    {
+      "name": "SPM_CORE_TEST_2_GET_EVERY_SECOND_BYTE",
+      "sid": "0x0000F042",
+      "non_secure_clients": true,
+      "version": 1,
+      "version_policy": "STRICT"
+    },
+    {
+      "name": "SPM_CORE_TEST_2_INVERT",
+      "sid": "0x0000F043",
+      "non_secure_clients": true,
+      "version": 1,
+      "version_policy": "STRICT"
+    },
+    {
+    "name": "SPM_CORE_TEST_2_PREPARE_TEST_SCENARIO",
+    "sid": "0x0000F044",
+    "non_secure_clients": true,
+    "version": 1,
+    "version_policy": "STRICT"
+    },
+    {
+    "name": "SPM_CORE_TEST_2_EXECUTE_TEST_SCENARIO",
+    "sid": "0x0000F045",
+    "non_secure_clients": true,
+    "version": 1,
+    "version_policy": "STRICT"
+    },
+  ]
+}
diff --git a/test/test_services/tfm_ipc_client/psa_manifest/tfm_ipc_client_partition.h b/test/test_services/tfm_ipc_client/psa_manifest/tfm_ipc_client_partition.h
new file mode 100644
index 0000000..d6d7513
--- /dev/null
+++ b/test/test_services/tfm_ipc_client/psa_manifest/tfm_ipc_client_partition.h
@@ -0,0 +1,27 @@
+/*
+ * Copyright (c) 2019-2020, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
+ */
+
+/*********** WARNING: This is an auto-generated file. Do not edit! ***********/
+
+#ifndef __PSA_MANIFEST_TFM_IPC_CLIENT_PARTITION_H__
+#define __PSA_MANIFEST_TFM_IPC_CLIENT_PARTITION_H__
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#define IPC_CLIENT_TEST_BASIC_SIGNAL                            (1U << (0 + 4))
+#define IPC_CLIENT_TEST_PSA_ACCESS_APP_MEM_SIGNAL               (1U << (1 + 4))
+#define IPC_CLIENT_TEST_PSA_ACCESS_APP_READ_ONLY_MEM_SIGNAL     (1U << (2 + 4))
+#define IPC_CLIENT_TEST_APP_ACCESS_PSA_MEM_SIGNAL               (1U << (3 + 4))
+#define IPC_CLIENT_TEST_MEM_CHECK_SIGNAL                        (1U << (4 + 4))
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __PSA_MANIFEST_TFM_IPC_CLIENT_PARTITION_H__ */
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..e66139e
--- /dev/null
+++ b/test/test_services/tfm_ipc_client/tfm_ipc_client_partition.yaml
@@ -0,0 +1,60 @@
+#-------------------------------------------------------------------------------
+# Copyright (c) 2018-2020, Arm Limited. All rights reserved.
+#
+# SPDX-License-Identifier: BSD-3-Clause
+#
+#-------------------------------------------------------------------------------
+
+{
+  "psa_framework_version": 1.0,
+  "name": "TFM_SP_IPC_CLIENT_TEST",
+  "type": "APPLICATION-ROT",
+  "priority": "NORMAL",
+  "entry_point": "ipc_client_test_main",
+  "stack_size": "0x0300",
+  "secure_functions": [
+  ],
+  "services" : [
+    {
+      "name": "IPC_CLIENT_TEST_BASIC",
+      "sid": "0x0000F060",
+      "non_secure_clients": true,
+      "version": 1,
+      "version_policy": "STRICT"
+    },
+    {
+      "name": "IPC_CLIENT_TEST_PSA_ACCESS_APP_MEM",
+      "sid": "0x0000F061",
+      "non_secure_clients": true,
+      "version": 1,
+      "version_policy": "STRICT"
+    },
+    {
+      "name": "IPC_CLIENT_TEST_PSA_ACCESS_APP_READ_ONLY_MEM",
+      "sid": "0x0000F062",
+      "non_secure_clients": true,
+      "version": 1,
+      "version_policy": "STRICT"
+    },
+    {
+      "name": "IPC_CLIENT_TEST_APP_ACCESS_PSA_MEM",
+      "sid": "0x0000F063",
+      "non_secure_clients": true,
+      "version": 1,
+      "version_policy": "STRICT"
+    },
+    {
+      "name": "IPC_CLIENT_TEST_MEM_CHECK",
+      "sid": "0x0000F064",
+      "non_secure_clients": true,
+      "version": 1,
+      "version_policy": "STRICT"
+    }
+  ],
+  "dependencies": [
+    "IPC_SERVICE_TEST_PSA_ACCESS_APP_READ_ONLY_MEM",
+    "IPC_SERVICE_TEST_PSA_ACCESS_APP_MEM",
+    "IPC_SERVICE_TEST_BASIC",
+    "IPC_SERVICE_TEST_APP_ACCESS_PSA_MEM"
+  ]
+}
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..40c5560
--- /dev/null
+++ b/test/test_services/tfm_ipc_client/tfm_ipc_client_test.c
@@ -0,0 +1,263 @@
+/*
+ * Copyright (c) 2018-2020, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
+ */
+
+#include <stdio.h>
+#include <assert.h>
+#include "psa/client.h"
+#include "psa/service.h"
+#include "psa_manifest/tfm_ipc_client_partition.h"
+#include "utilities.h"
+#include "psa_manifest/sid.h"
+
+/* Define the return status */
+#define IPC_SP_TEST_SUCCESS     (1)
+#define IPC_SP_TEST_FAILED      (-1)
+
+/*
+ * The bit corresponding to service signal indicates whether
+ * the service is in use.
+ */
+uint32_t service_in_use = 0;
+
+/*
+ * Create a global const data, so that it is stored in code
+ * section which is read only.
+ */
+char const client_data_read_only = 'A';
+
+/*
+ * Fixme: Temporarily implement abort as infinite loop,
+ * will replace it later.
+ */
+static void tfm_abort(void)
+{
+    while (1)
+        ;
+}
+
+#ifdef TFM_IPC_ISOLATION_2_TEST_READ_ONLY_MEM
+static int ipc_isolation_2_psa_access_app_readonly_memory(void)
+{
+    psa_handle_t handle;
+    psa_status_t status;
+    char const *client_data_p = &client_data_read_only;
+    struct psa_invec invecs[1] = {{&client_data_p, sizeof(client_data_p)}};
+
+    handle = psa_connect(IPC_SERVICE_TEST_PSA_ACCESS_APP_READ_ONLY_MEM_SID,
+                         IPC_SERVICE_TEST_PSA_ACCESS_APP_READ_ONLY_MEM_VERSION);
+
+    if (handle <= 0) {
+        return IPC_SP_TEST_FAILED;
+    }
+
+    status = psa_call(handle, PSA_IPC_CALL, invecs, 1, NULL, 0);
+
+    /* The system should panic before here. */
+    psa_close(handle);
+    return IPC_SP_TEST_FAILED;
+}
+#endif
+
+static int ipc_isolation_2_psa_access_app_memory(void)
+{
+    psa_handle_t handle;
+    psa_status_t status;
+    int32_t result = IPC_SP_TEST_FAILED;
+    char client_data = 'A';
+    char *client_data_p = &client_data;
+    struct psa_invec invecs[1] = {{&client_data_p, sizeof(client_data_p)}};
+
+    handle = psa_connect(IPC_SERVICE_TEST_PSA_ACCESS_APP_MEM_SID,
+                         IPC_SERVICE_TEST_PSA_ACCESS_APP_MEM_VERSION);
+
+    if (handle <= 0) {
+        return result;
+    }
+
+    status = psa_call(handle, PSA_IPC_CALL, invecs, 1, NULL, 0);
+
+    if ((client_data == 'B') && (status >= 0)) {
+        result = IPC_SP_TEST_SUCCESS;
+    }
+
+    psa_close(handle);
+    return result;
+}
+
+static int ipc_client_base_test(void)
+{
+    psa_handle_t handle;
+    psa_status_t status;
+    int32_t result = IPC_SP_TEST_FAILED;
+    char str1[] = "123";
+    char str2[] = "456";
+    char str3[32], str4[32];
+    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)}};
+
+    handle = psa_connect(IPC_SERVICE_TEST_BASIC_SID,
+                         IPC_SERVICE_TEST_BASIC_VERSION);
+    if (handle <= 0) {
+        return result;
+    }
+
+    status = psa_call(handle, PSA_IPC_CALL, invecs, 2, outvecs, 2);
+    if (status >= 0) {
+        result = IPC_SP_TEST_SUCCESS;
+    }
+
+    psa_close(handle);
+    return result;
+}
+
+#ifdef TFM_IPC_ISOLATION_2_APP_ACCESS_PSA_MEM
+static int ipc_client_app_access_psa_mem_test(void)
+{
+    psa_handle_t handle;
+    psa_status_t status;
+    uint8_t *outvec_data[1] = {0};
+    struct psa_outvec outvecs[1] = {{outvec_data, sizeof(outvec_data[0])}};
+
+    handle = psa_connect(IPC_SERVICE_TEST_APP_ACCESS_PSA_MEM_SID,
+                         IPC_SERVICE_TEST_APP_ACCESS_PSA_MEM_VERSION);
+
+    if (handle <= 0) {
+        return IPC_SP_TEST_FAILED;
+    }
+
+    status = psa_call(handle, PSA_IPC_CALL, NULL, 0, outvecs, 1);
+    if (status >= 0) {
+        /*
+         * outvecs should contain the pointer pointed to ipc service parition
+         * memory. Read the pointed memory should cause panic.
+         */
+        uint8_t *psa_data_p = outvec_data[0];
+        if (psa_data_p) {
+            (*psa_data_p)++;
+        }
+    }
+
+    /* The system should panic before here. */
+    psa_close(handle);
+    return IPC_SP_TEST_FAILED;
+}
+#endif
+
+#ifdef TFM_IPC_ISOLATION_2_MEM_CHECK
+static int ipc_client_mem_check_test(void)
+{
+    psa_handle_t handle;
+    psa_status_t status;
+    uint8_t *outvec_data[1] = {0};
+    struct psa_outvec outvecs[1] = {{outvec_data, sizeof(outvec_data[0])}};
+    struct psa_invec invecs[1] = {{NULL, 0}};
+
+    handle = psa_connect(IPC_SERVICE_TEST_APP_ACCESS_PSA_MEM_SID,
+                         IPC_SERVICE_TEST_APP_ACCESS_PSA_MEM_VERSION);
+
+    if (handle <= 0) {
+        return IPC_SP_TEST_FAILED;
+    }
+
+    status = psa_call(handle, PSA_IPC_CALL, NULL, 0, outvecs, 1);
+    if (status >= 0) {
+        /*
+         * outvecs should contain the pointer pointed to ipc service parition
+         * memory. In psa_call, it checks whether the target partition has the
+         * access right to the invecs indicated memory. If no, the system will
+         * panic.
+         */
+        uint8_t *psa_data_p = outvec_data[0];
+        if (psa_data_p) {
+            invecs[0].base = psa_data_p;
+            invecs[0].len = sizeof(psa_data_p);
+            psa_call(handle, PSA_IPC_CALL, invecs, 1, NULL, 0);
+        }
+    }
+
+    /* The system should panic before here. */
+    psa_close(handle);
+    return IPC_SP_TEST_FAILED;
+}
+#endif
+
+static void ipc_client_handle_ser_req(psa_msg_t msg, uint32_t signals,
+                                      int (*fn)(void))
+{
+    psa_status_t r;
+    int32_t ret;
+
+    switch (msg.type) {
+    case PSA_IPC_CONNECT:
+        if (service_in_use & signals) {
+            r = PSA_ERROR_CONNECTION_REFUSED;
+        } else {
+            service_in_use |= signals;
+            r = PSA_SUCCESS;
+        }
+        psa_reply(msg.handle, r);
+        break;
+    case PSA_IPC_CALL:
+        ret = (*fn)();
+        if (msg.out_size[0] != 0) {
+            psa_write(msg.handle, 0, &ret, sizeof(ret));
+        }
+        psa_reply(msg.handle, PSA_SUCCESS);
+        break;
+    case PSA_IPC_DISCONNECT:
+        assert((service_in_use & signals) != 0);
+        service_in_use &= ~(signals);
+        psa_reply(msg.handle, PSA_SUCCESS);
+        break;
+    default:
+        /* cannot get here? [broken SPM]. TODO*/
+        tfm_abort();
+        break;
+    }
+}
+
+void ipc_client_test_main(void)
+{
+    psa_msg_t msg;
+    uint32_t signals = 0;
+
+    while (1) {
+        signals = psa_wait(PSA_WAIT_ANY, PSA_BLOCK);
+        psa_get(signals, &msg);
+        if ((signals & IPC_CLIENT_TEST_BASIC_SIGNAL)) {
+            ipc_client_handle_ser_req(msg, IPC_CLIENT_TEST_BASIC_SIGNAL,
+                                      &ipc_client_base_test);
+        } else if (signals & IPC_CLIENT_TEST_PSA_ACCESS_APP_MEM_SIGNAL) {
+            ipc_client_handle_ser_req(msg,
+                                     IPC_CLIENT_TEST_PSA_ACCESS_APP_MEM_SIGNAL,
+                                     &ipc_isolation_2_psa_access_app_memory);
+#ifdef TFM_IPC_ISOLATION_2_TEST_READ_ONLY_MEM
+        } else if (signals &
+                    IPC_CLIENT_TEST_PSA_ACCESS_APP_READ_ONLY_MEM_SIGNAL) {
+            ipc_client_handle_ser_req(msg,
+                           IPC_CLIENT_TEST_PSA_ACCESS_APP_READ_ONLY_MEM_SIGNAL,
+                           &ipc_isolation_2_psa_access_app_readonly_memory);
+#endif
+#ifdef TFM_IPC_ISOLATION_2_APP_ACCESS_PSA_MEM
+        } else if (signals & IPC_CLIENT_TEST_APP_ACCESS_PSA_MEM_SIGNAL) {
+            ipc_client_handle_ser_req(msg,
+                                     IPC_CLIENT_TEST_APP_ACCESS_PSA_MEM_SIGNAL,
+                                     &ipc_client_app_access_psa_mem_test);
+#endif
+#ifdef TFM_IPC_ISOLATION_2_MEM_CHECK
+        } else if (signals & IPC_CLIENT_TEST_MEM_CHECK_SIGNAL) {
+            ipc_client_handle_ser_req(msg, IPC_CLIENT_TEST_MEM_CHECK_SIGNAL,
+                                      &ipc_client_mem_check_test);
+#endif
+        } else {
+            /* Should not go here. */
+            tfm_abort();
+        }
+    }
+}
diff --git a/test/test_services/tfm_ipc_service/psa_manifest/tfm_ipc_service_partition.h b/test/test_services/tfm_ipc_service/psa_manifest/tfm_ipc_service_partition.h
new file mode 100644
index 0000000..47427a0
--- /dev/null
+++ b/test/test_services/tfm_ipc_service/psa_manifest/tfm_ipc_service_partition.h
@@ -0,0 +1,27 @@
+/*
+ * Copyright (c) 2019-2020, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
+ */
+
+/*********** WARNING: This is an auto-generated file. Do not edit! ***********/
+
+#ifndef __PSA_MANIFEST_TFM_IPC_SERVICE_PARTITION_H__
+#define __PSA_MANIFEST_TFM_IPC_SERVICE_PARTITION_H__
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#define IPC_SERVICE_TEST_BASIC_SIGNAL                           (1U << (0 + 4))
+#define IPC_SERVICE_TEST_PSA_ACCESS_APP_MEM_SIGNAL              (1U << (1 + 4))
+#define IPC_SERVICE_TEST_PSA_ACCESS_APP_READ_ONLY_MEM_SIGNAL    (1U << (2 + 4))
+#define IPC_SERVICE_TEST_APP_ACCESS_PSA_MEM_SIGNAL              (1U << (3 + 4))
+#define IPC_SERVICE_TEST_CLIENT_PROGRAMMER_ERROR_SIGNAL         (1U << (4 + 4))
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __PSA_MANIFEST_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..d06bddb
--- /dev/null
+++ b/test/test_services/tfm_ipc_service/tfm_ipc_service_partition.yaml
@@ -0,0 +1,54 @@
+#-------------------------------------------------------------------------------
+# Copyright (c) 2018-2020, Arm Limited. All rights reserved.
+#
+# SPDX-License-Identifier: BSD-3-Clause
+#
+#-------------------------------------------------------------------------------
+
+{
+  "psa_framework_version": 1.0,
+  "name": "TFM_SP_IPC_SERVICE_TEST",
+  "type": "PSA-ROT",
+  "priority": "HIGH",
+  "entry_point": "ipc_service_test_main",
+  "stack_size": "0x0220",
+  "secure_functions": [
+  ],
+  "services" : [
+    {
+      "name": "IPC_SERVICE_TEST_BASIC",
+      "sid": "0x0000F080",
+      "non_secure_clients": true,
+      "version": 1,
+      "version_policy": "STRICT"
+    },
+    {
+      "name": "IPC_SERVICE_TEST_PSA_ACCESS_APP_MEM",
+      "sid": "0x0000F081",
+      "non_secure_clients": true,
+      "version": 1,
+      "version_policy": "STRICT"
+    },
+    {
+      "name": "IPC_SERVICE_TEST_PSA_ACCESS_APP_READ_ONLY_MEM",
+      "sid": "0x0000F082",
+      "non_secure_clients": true,
+      "version": 1,
+      "version_policy": "STRICT"
+    },
+    {
+      "name": "IPC_SERVICE_TEST_APP_ACCESS_PSA_MEM",
+      "sid": "0x0000F083",
+      "non_secure_clients": true,
+      "version": 1,
+      "version_policy": "STRICT"
+    },
+    {
+      "name": "IPC_SERVICE_TEST_CLIENT_PROGRAMMER_ERROR",
+      "sid": "0x0000F084",
+      "non_secure_clients": true,
+      "version": 1,
+      "version_policy": "STRICT"
+    }
+  ]
+}
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..ad7d1f2
--- /dev/null
+++ b/test/test_services/tfm_ipc_service/tfm_ipc_service_test.c
@@ -0,0 +1,291 @@
+/*
+ * Copyright (c) 2018-2020, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
+ */
+
+#include <assert.h>
+#include <stdio.h>
+#include <stdbool.h>
+#include "psa/client.h"
+#include "psa/service.h"
+#include "tfm_secure_api.h"
+#include "tfm_api.h"
+#include "psa_manifest/tfm_ipc_service_partition.h"
+
+#define IPC_SERVICE_BUFFER_LEN                          32
+
+/* Define the whether the service is inuse flag. */
+static uint32_t service_in_use = 0;
+
+/* Define the global variable for the IPC_APP_ACCESS_PSA_MEM_SID service. */
+uint8_t ipc_servic_data;
+uint8_t *ipc_service_data_p = &ipc_servic_data;
+
+/*
+ * Fixme: Temporarily implement abort as infinite loop,
+ * will replace it later.
+ */
+static void tfm_abort(void)
+{
+    while (1)
+        ;
+}
+
+static void ipc_service_basic(void)
+{
+    psa_msg_t msg;
+    psa_status_t r;
+    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.";
+
+    psa_get(IPC_SERVICE_TEST_BASIC_SIGNAL, &msg);
+    switch (msg.type) {
+    case PSA_IPC_CONNECT:
+        if (service_in_use & IPC_SERVICE_TEST_BASIC_SIGNAL) {
+            r = PSA_ERROR_CONNECTION_REFUSED;
+        } else {
+            service_in_use |= IPC_SERVICE_TEST_BASIC_SIGNAL;
+            r = PSA_SUCCESS;
+        }
+        psa_reply(msg.handle, r);
+        break;
+    case PSA_IPC_CALL:
+        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);
+            }
+        }
+        psa_reply(msg.handle, PSA_SUCCESS);
+        break;
+    case PSA_IPC_DISCONNECT:
+        assert((service_in_use & IPC_SERVICE_TEST_BASIC_SIGNAL) != 0);
+        service_in_use &= ~IPC_SERVICE_TEST_BASIC_SIGNAL;
+        psa_reply(msg.handle, PSA_SUCCESS);
+        break;
+    default:
+        /* cannot get here? [broken SPM]. TODO*/
+        tfm_abort();
+        break;
+    }
+}
+
+static void ipc_service_psa_access_app_mem(void)
+{
+    psa_msg_t msg;
+    psa_status_t r;
+    char rec_data;
+    uint32_t rec_buf;
+
+    psa_get(IPC_SERVICE_TEST_PSA_ACCESS_APP_MEM_SIGNAL, &msg);
+    switch (msg.type) {
+    case PSA_IPC_CONNECT:
+        if (service_in_use & IPC_SERVICE_TEST_PSA_ACCESS_APP_MEM_SIGNAL) {
+            r = PSA_ERROR_CONNECTION_REFUSED;
+        } else {
+            service_in_use |= IPC_SERVICE_TEST_PSA_ACCESS_APP_MEM_SIGNAL;
+            r = PSA_SUCCESS;
+        }
+        psa_reply(msg.handle, r);
+        break;
+    case PSA_IPC_CALL:
+        /*
+         * rec_buf is a pointer pointed to a char type memory in client stack.
+         */
+        if (msg.in_size[0] != 0) {
+            psa_read(msg.handle, 0, &rec_buf, 4);
+            rec_data = *(char *)rec_buf;
+
+            /* rec_data is assigned to 'A' by the client side. */
+            if (rec_data != 'A') {
+                psa_reply(msg.handle, -1);
+                break;
+            }
+
+            /* Change the char type client stack memory to 'B'. */
+            *((char *)rec_buf) = 'B';
+        }
+        psa_reply(msg.handle, PSA_SUCCESS);
+        break;
+    case PSA_IPC_DISCONNECT:
+        assert((service_in_use & IPC_SERVICE_TEST_PSA_ACCESS_APP_MEM_SIGNAL)
+               != 0);
+        service_in_use &= ~IPC_SERVICE_TEST_PSA_ACCESS_APP_MEM_SIGNAL;
+        psa_reply(msg.handle, PSA_SUCCESS);
+        break;
+    default:
+        /* cannot get here? [broken SPM]. TODO*/
+        tfm_abort();
+        break;
+    }
+}
+
+#ifdef TFM_IPC_ISOLATION_2_TEST_READ_ONLY_MEM
+static void ipc_service_psa_access_app_readonly_mem(void)
+{
+    psa_msg_t msg;
+    psa_status_t r;
+    char rec_data;
+    uint32_t rec_buf;
+
+    psa_get(IPC_SERVICE_TEST_PSA_ACCESS_APP_READ_ONLY_MEM_SIGNAL, &msg);
+    switch (msg.type) {
+    case PSA_IPC_CONNECT:
+        if (service_in_use &
+            IPC_SERVICE_TEST_PSA_ACCESS_APP_READ_ONLY_MEM_SIGNAL) {
+            r = PSA_ERROR_CONNECTION_REFUSED;
+        } else {
+            service_in_use |=
+                          IPC_SERVICE_TEST_PSA_ACCESS_APP_READ_ONLY_MEM_SIGNAL;
+            r = PSA_SUCCESS;
+        }
+        psa_reply(msg.handle, r);
+        break;
+    case PSA_IPC_CALL:
+         /*
+          * rec_buf is a pointer pointed to a char type memory in client
+          * code section. Write the memory will cause MemManage fault.
+          */
+        if (msg.in_size[0] != 0) {
+            psa_read(msg.handle, 0, &rec_buf, 4);
+            rec_data = *(char *)rec_buf;
+
+            /* rec_data is assigned to 'A' by the client side. */
+            if (rec_data != 'A') {
+                psa_reply(msg.handle, -1);
+                break;
+            }
+
+            /* Write the char type read only memory. */
+            *((char *)rec_buf) = 'B';
+        }
+
+        psa_reply(msg.handle, PSA_SUCCESS);
+        break;
+    case PSA_IPC_DISCONNECT:
+        assert((service_in_use &
+                IPC_SERVICE_TEST_PSA_ACCESS_APP_READ_ONLY_MEM_SIGNAL) != 0);
+        service_in_use &=
+                         ~IPC_SERVICE_TEST_PSA_ACCESS_APP_READ_ONLY_MEM_SIGNAL;
+        psa_reply(msg.handle, PSA_SUCCESS);
+        break;
+    default:
+        /* cannot get here? [broken SPM]. TODO*/
+        tfm_abort();
+        break;
+    }
+}
+#endif
+
+#if defined TFM_IPC_ISOLATION_2_MEM_CHECK \
+    || defined TFM_IPC_ISOLATION_2_APP_ACCESS_PSA_MEM
+static void ipc_service_app_access_psa_mem(void)
+{
+    psa_msg_t msg;
+    psa_status_t r;
+
+    psa_get(IPC_SERVICE_TEST_APP_ACCESS_PSA_MEM_SIGNAL, &msg);
+    switch (msg.type) {
+    case PSA_IPC_CONNECT:
+        if (service_in_use & IPC_SERVICE_TEST_APP_ACCESS_PSA_MEM_SIGNAL) {
+            r = PSA_ERROR_CONNECTION_REFUSED;
+        } else {
+            service_in_use |= IPC_SERVICE_TEST_APP_ACCESS_PSA_MEM_SIGNAL;
+            r = PSA_SUCCESS;
+        }
+
+        psa_reply(msg.handle, r);
+        break;
+    case PSA_IPC_CALL:
+        if (msg.out_size[0] != 0) {
+
+            /*
+             * Write a pointer to outvec. The pointer points to uint8_t
+             * memory in ipc servive partition.
+             */
+            psa_write(msg.handle, 0, &ipc_service_data_p,
+                      sizeof(ipc_service_data_p));
+        }
+
+        psa_reply(msg.handle, PSA_SUCCESS);
+        break;
+    case PSA_IPC_DISCONNECT:
+        assert((service_in_use & IPC_SERVICE_TEST_APP_ACCESS_PSA_MEM_SIGNAL)
+               != 0);
+        service_in_use &= ~IPC_SERVICE_TEST_APP_ACCESS_PSA_MEM_SIGNAL;
+        psa_reply(msg.handle, PSA_SUCCESS);
+        break;
+    default:
+        /* cannot get here? [broken SPM]. TODO*/
+        tfm_abort();
+        break;
+    }
+}
+#endif
+
+static void ipc_service_programmer_error(void)
+{
+    psa_msg_t msg;
+    psa_status_t r;
+
+    psa_get(IPC_SERVICE_TEST_CLIENT_PROGRAMMER_ERROR_SIGNAL, &msg);
+    switch (msg.type) {
+    case PSA_IPC_CONNECT:
+        if (service_in_use & IPC_SERVICE_TEST_CLIENT_PROGRAMMER_ERROR_SIGNAL) {
+            r = PSA_ERROR_CONNECTION_REFUSED;
+        } else {
+            service_in_use |= IPC_SERVICE_TEST_CLIENT_PROGRAMMER_ERROR_SIGNAL;
+            r = PSA_SUCCESS;
+        }
+        psa_reply(msg.handle, r);
+        break;
+    case PSA_IPC_CALL:
+        psa_reply(msg.handle, PSA_ERROR_PROGRAMMER_ERROR);
+        break;
+    case PSA_IPC_DISCONNECT:
+        assert((service_in_use
+                & IPC_SERVICE_TEST_CLIENT_PROGRAMMER_ERROR_SIGNAL) != 0);
+        service_in_use &= ~IPC_SERVICE_TEST_CLIENT_PROGRAMMER_ERROR_SIGNAL;
+        psa_reply(msg.handle, PSA_SUCCESS);
+        break;
+    default:
+        /* cannot get here? [broken SPM]. TODO*/
+        tfm_abort();
+        break;
+    }
+}
+
+/* Test thread */
+void ipc_service_test_main(void *param)
+{
+    uint32_t signals = 0;
+
+    while (1) {
+        signals = psa_wait(PSA_WAIT_ANY, PSA_BLOCK);
+        if (signals & IPC_SERVICE_TEST_BASIC_SIGNAL) {
+            ipc_service_basic();
+        } else if (signals & IPC_SERVICE_TEST_PSA_ACCESS_APP_MEM_SIGNAL) {
+            ipc_service_psa_access_app_mem();
+#ifdef TFM_IPC_ISOLATION_2_TEST_READ_ONLY_MEM
+        } else if (signals
+                   & IPC_SERVICE_TEST_PSA_ACCESS_APP_READ_ONLY_MEM_SIGNAL) {
+            ipc_service_psa_access_app_readonly_mem();
+#endif
+#if defined TFM_IPC_ISOLATION_2_MEM_CHECK \
+    || defined TFM_IPC_ISOLATION_2_APP_ACCESS_PSA_MEM
+        } else if (signals & IPC_SERVICE_TEST_APP_ACCESS_PSA_MEM_SIGNAL) {
+            ipc_service_app_access_psa_mem();
+#endif
+        } else if (signals & IPC_SERVICE_TEST_CLIENT_PROGRAMMER_ERROR_SIGNAL) {
+            ipc_service_programmer_error();
+        } else {
+            /* Should not come here */
+            tfm_abort();
+        }
+    }
+}
diff --git a/test/test_services/tfm_irq_test_service_1/psa_manifest/tfm_irq_test_service_1.h b/test/test_services/tfm_irq_test_service_1/psa_manifest/tfm_irq_test_service_1.h
new file mode 100644
index 0000000..18ef22a
--- /dev/null
+++ b/test/test_services/tfm_irq_test_service_1/psa_manifest/tfm_irq_test_service_1.h
@@ -0,0 +1,26 @@
+/*
+ * Copyright (c) 2019-2020, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
+ */
+
+/*********** WARNING: This is an auto-generated file. Do not edit! ***********/
+
+#ifndef __PSA_MANIFEST_TFM_IRQ_TEST_SERVICE_1_H__
+#define __PSA_MANIFEST_TFM_IRQ_TEST_SERVICE_1_H__
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#define SPM_CORE_IRQ_TEST_1_PREPARE_TEST_SCENARIO_SIGNAL        (1U << (0 + 4))
+#define SPM_CORE_IRQ_TEST_1_EXECUTE_TEST_SCENARIO_SIGNAL        (1U << (1 + 4))
+
+#define SPM_CORE_IRQ_TEST_1_SIGNAL_TIMER_0_IRQ                  (1U << (27 + 4))
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __PSA_MANIFEST_TFM_IRQ_TEST_SERVICE_1_H__ */
diff --git a/test/test_services/tfm_irq_test_service_1/tfm_irq_test_service_1.c b/test/test_services/tfm_irq_test_service_1/tfm_irq_test_service_1.c
new file mode 100644
index 0000000..559a3ec
--- /dev/null
+++ b/test/test_services/tfm_irq_test_service_1/tfm_irq_test_service_1.c
@@ -0,0 +1,409 @@
+/*
+ * Copyright (c) 2019-2020, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
+ */
+
+#include <stddef.h>
+#include "tfm_api.h"
+#include "tfm_veneers.h"
+#include "tfm_secure_api.h"
+#include "tfm/tfm_spm_services.h"
+#include "test/test_services/tfm_core_test/core_test_defs.h"
+#include "psa/service.h"
+#include "psa_manifest/pid.h"
+#include "psa_manifest/tfm_irq_test_service_1.h"
+#include "tfm_plat_test.h"
+
+#define IRQ_TEST_TOOL_CODE_LOCATION(name)
+
+static enum irq_test_scenario_t current_scenario = IRQ_TEST_SCENARIO_NONE;
+static struct irq_test_execution_data_t *current_execution_data;
+
+#ifdef TFM_PSA_API
+static psa_handle_t execute_msg_handle = -1;
+#endif
+
+/**
+ * \brief unrecoverable error during test execution.
+ *
+ * Called from places, where error code would be very difficult, or impossible
+ * to return.
+ */
+static void halt_test_execution(void)
+{
+    while (1) {
+        ; /* Test fail */
+    }
+}
+
+/**
+ * \brief Stop the timer, and disable and clear interrupts
+ */
+static void stop_timer(void)
+{
+    IRQ_TEST_TOOL_CODE_LOCATION(stop_secure_timer);
+    tfm_plat_test_secure_timer_stop();
+}
+
+int32_t spm_irq_test_1_prepare_test_scenario_internal(
+                               enum irq_test_scenario_t irq_test_scenario,
+                               struct irq_test_execution_data_t *execution_data)
+{
+    current_scenario = irq_test_scenario;
+    current_execution_data = execution_data;
+
+    current_execution_data->timer0_triggered = 0;
+
+    switch (irq_test_scenario) {
+    case IRQ_TEST_SCENARIO_NONE:
+        break; /* uninitialised scenario */
+    case IRQ_TEST_SCENARIO_1:
+    case IRQ_TEST_SCENARIO_2:
+    case IRQ_TEST_SCENARIO_3:
+    case IRQ_TEST_SCENARIO_4:
+        tfm_plat_test_secure_timer_start();
+        break;
+    case IRQ_TEST_SCENARIO_5:
+        /* Do nothing */
+        break;
+    default:
+        return CORE_TEST_ERRNO_INVALID_PARAMETER;
+    }
+
+    return CORE_TEST_ERRNO_SUCCESS;
+}
+
+int32_t spm_irq_test_1_execute_test_scenario(
+                                     struct psa_invec *in_vec, size_t in_len,
+                                     struct psa_outvec *out_vec, size_t out_len)
+{
+    enum irq_test_scenario_t irq_test_scenario =
+            (enum irq_test_scenario_t) *(uint32_t *)in_vec[0].base;
+    psa_signal_t signals = 0;
+
+    if (irq_test_scenario != current_scenario) {
+        return CORE_TEST_ERRNO_INVALID_PARAMETER;
+    }
+
+    switch (irq_test_scenario) {
+    case IRQ_TEST_SCENARIO_NONE:
+        return CORE_TEST_ERRNO_INVALID_PARAMETER;
+    case IRQ_TEST_SCENARIO_1:
+    case IRQ_TEST_SCENARIO_2:
+        /* nothing to do*/
+        break;
+    case IRQ_TEST_SCENARIO_3:
+        if (current_execution_data->timer0_triggered) {
+            return CORE_TEST_ERRNO_TEST_FAULT;
+        }
+        while (!current_execution_data->timer0_triggered) {
+            /* Wait for the timer to be triggered */
+            ;
+        }
+        break;
+    case IRQ_TEST_SCENARIO_4:
+        if (current_execution_data->timer0_triggered) {
+            return CORE_TEST_ERRNO_TEST_FAULT;
+        }
+        while ((signals & SPM_CORE_IRQ_TEST_1_SIGNAL_TIMER_0_IRQ) == 0) {
+            signals = psa_wait(SPM_CORE_IRQ_TEST_1_SIGNAL_TIMER_0_IRQ,
+                               PSA_BLOCK);
+        }
+        if (!current_execution_data->timer0_triggered) {
+            return CORE_TEST_ERRNO_TEST_FAULT;
+        }
+        psa_eoi(SPM_CORE_IRQ_TEST_1_SIGNAL_TIMER_0_IRQ);
+        break;
+    case IRQ_TEST_SCENARIO_5:
+        /* nothing to do*/
+        break;
+    default:
+        return CORE_TEST_ERRNO_INVALID_PARAMETER;
+    }
+
+    return CORE_TEST_ERRNO_SUCCESS;
+}
+
+uint32_t spm_irq_test_1_prepare_test_scenario(
+                                     struct psa_invec *in_vec, size_t in_len,
+                                     struct psa_outvec *out_vec, size_t out_len)
+{
+    enum irq_test_scenario_t irq_test_scenario;
+    struct irq_test_execution_data_t *execution_data;
+
+    if ((in_len != 2) || (out_len != 0)) {
+        return CORE_TEST_ERRNO_INVALID_PARAMETER;
+    }
+
+    if ((in_vec[0].len != sizeof(uint32_t)) ||
+        (in_vec[1].len != sizeof(struct irq_test_execution_data_t *))) {
+        return CORE_TEST_ERRNO_INVALID_PARAMETER;
+    }
+
+    irq_test_scenario =
+            (enum irq_test_scenario_t) *(uint32_t *)in_vec[0].base;
+
+    execution_data =
+            *(struct irq_test_execution_data_t **)in_vec[1].base;
+
+    return spm_irq_test_1_prepare_test_scenario_internal(irq_test_scenario,
+                                                         execution_data);
+}
+
+#ifndef TFM_PSA_API
+
+void SPM_CORE_IRQ_TEST_1_SIGNAL_TIMER_0_IRQ_isr(void)
+{
+    stop_timer();
+
+    if ((current_execution_data == NULL) ||
+        (current_execution_data->timer0_triggered != 0)) {
+            halt_test_execution();
+    }
+
+    current_execution_data->timer0_triggered = 1;
+
+    switch (current_scenario) {
+    case IRQ_TEST_SCENARIO_NONE:
+        psa_eoi(SPM_CORE_IRQ_TEST_1_SIGNAL_TIMER_0_IRQ);
+        break;
+    case IRQ_TEST_SCENARIO_1:
+    case IRQ_TEST_SCENARIO_2:
+    case IRQ_TEST_SCENARIO_3:
+        psa_eoi(SPM_CORE_IRQ_TEST_1_SIGNAL_TIMER_0_IRQ);
+        break;
+    case IRQ_TEST_SCENARIO_4:
+        /* nothing to do*/
+        break;
+    case IRQ_TEST_SCENARIO_5:
+        halt_test_execution();
+        /* No secure interrups are used in this scenario */
+        break;
+    default:
+        halt_test_execution();
+        break;
+    }
+
+    __asm("DSB");
+}
+
+#else /* TFM_PSA_API */
+
+typedef psa_status_t (*irq_test_1_func_t)(psa_msg_t *msg);
+
+static void spm_irq_test_1_signal_handle(psa_signal_t signal,
+                                         irq_test_1_func_t pfn)
+{
+    psa_msg_t msg;
+    psa_status_t status;
+
+    status = psa_get(signal, &msg);
+    if (status) {
+        return;
+    }
+
+    switch (msg.type) {
+    case PSA_IPC_CONNECT:
+        psa_reply(msg.handle, PSA_SUCCESS);
+        break;
+    case PSA_IPC_CALL:
+        status = pfn(&msg);
+        psa_reply(msg.handle, status);
+        break;
+    case PSA_IPC_DISCONNECT:
+        psa_reply(msg.handle, PSA_SUCCESS);
+        break;
+    default:
+        break;
+    }
+}
+
+void TIMER_0_isr_ipc(void)
+{
+    current_execution_data->timer0_triggered = 1;
+
+    stop_timer();
+
+    switch (current_scenario) {
+    case IRQ_TEST_SCENARIO_NONE:
+        psa_eoi(SPM_CORE_IRQ_TEST_1_SIGNAL_TIMER_0_IRQ);
+        break;
+    case IRQ_TEST_SCENARIO_1:
+    case IRQ_TEST_SCENARIO_2:
+        psa_eoi(SPM_CORE_IRQ_TEST_1_SIGNAL_TIMER_0_IRQ);
+        break;
+    case IRQ_TEST_SCENARIO_3:
+        /* execute_msg_handle have to be valid at this point */
+        if (execute_msg_handle <= 0) {
+            halt_test_execution();
+        }
+        /* reply to the execute message, to unblock NS side */
+        psa_reply(execute_msg_handle, CORE_TEST_ERRNO_SUCCESS);
+        execute_msg_handle = -1;
+        psa_eoi(SPM_CORE_IRQ_TEST_1_SIGNAL_TIMER_0_IRQ);
+        break;
+    case IRQ_TEST_SCENARIO_4:
+        /* This case should never be executed as in this scenario the 'execute
+         * function does the psa wait, and calls psa_eoi immediately'. So when
+         * execution gets to the psa_wait in the main loop, the IRQ signal is
+         * unset.
+         */
+        halt_test_execution();
+        break;
+    case IRQ_TEST_SCENARIO_5:
+        /* No secure interrups are used in this scenario */
+        halt_test_execution();
+        break;
+    default:
+        halt_test_execution();
+        break;
+    }
+}
+
+static psa_status_t spm_irq_test_1_wrap_prepare_test_scenario(psa_msg_t *msg)
+{
+    uint32_t irq_test_scenario;
+    struct irq_test_execution_data_t *execution_data;
+    size_t num;
+
+    if ((msg->in_size[0] != sizeof(uint32_t)) ||
+        (msg->in_size[1] != sizeof(struct irq_test_execution_data_t *))) {
+        return CORE_TEST_ERRNO_INVALID_PARAMETER;
+    }
+
+
+    num = psa_read(msg->handle, 0, &irq_test_scenario, sizeof(uint32_t));
+    if (num != msg->in_size[0]) {
+        return CORE_TEST_ERRNO_INVALID_PARAMETER;
+    }
+
+    num = psa_read(msg->handle, 1, &execution_data,
+                   sizeof(struct irq_test_execution_data_t *));
+    if (num != msg->in_size[1]) {
+        return CORE_TEST_ERRNO_INVALID_PARAMETER;
+    }
+
+    return spm_irq_test_1_prepare_test_scenario_internal((enum irq_test_scenario_t)
+                                                         irq_test_scenario,
+                                                         execution_data);
+}
+
+static void spm_irq_test_1_execute_test_scenario_ipc_call(psa_msg_t *msg)
+{
+    size_t num;
+    uint32_t irq_test_scenario;
+    psa_signal_t signals = 0;
+
+    num = psa_read(msg->handle, 0, &irq_test_scenario, sizeof(uint32_t));
+    if ((num != msg->in_size[0]) ||
+        (irq_test_scenario != current_scenario)) {
+        psa_reply(msg->handle, CORE_TEST_ERRNO_INVALID_PARAMETER);
+        return;
+    }
+
+    switch (irq_test_scenario) {
+    case IRQ_TEST_SCENARIO_NONE:
+        psa_reply(msg->handle, CORE_TEST_ERRNO_INVALID_PARAMETER);
+        return;
+    case IRQ_TEST_SCENARIO_1:
+    case IRQ_TEST_SCENARIO_2:
+    case IRQ_TEST_SCENARIO_5:
+        /* nothing to do, return success */
+        psa_reply(msg->handle, CORE_TEST_ERRNO_SUCCESS);
+        return;
+    case IRQ_TEST_SCENARIO_3:
+        if (current_execution_data->timer0_triggered) {
+            psa_reply(msg->handle, CORE_TEST_ERRNO_TEST_FAULT);
+            return;
+        }
+        /* We need the ISR to be able to run. So we do a wait to let
+         * it run and set timer0_triggered. This message will be replied
+         * from the ISR, so the NS side remains blocked for now. To be able
+         * to reply, we also save the handle of the message.
+         */
+        if (execute_msg_handle > 0) {
+            /* execute_msg_handle should be uninitialised at this point */
+            psa_reply(msg->handle, CORE_TEST_ERRNO_TEST_FAULT);
+            return;
+        }
+        execute_msg_handle = msg->handle;
+        while (!(signals & SPM_CORE_IRQ_TEST_1_SIGNAL_TIMER_0_IRQ)) {
+           signals = psa_wait(SPM_CORE_IRQ_TEST_1_SIGNAL_TIMER_0_IRQ,
+                              PSA_BLOCK);
+        }
+        return;
+    case IRQ_TEST_SCENARIO_4:
+        while (!(signals & SPM_CORE_IRQ_TEST_1_SIGNAL_TIMER_0_IRQ)) {
+            signals = psa_wait(SPM_CORE_IRQ_TEST_1_SIGNAL_TIMER_0_IRQ,
+                              PSA_BLOCK);
+        }
+        /* There is no need to call the ISR in this scenario, so we can
+         * clear the IRQ signal
+         */
+        stop_timer();
+        psa_eoi(SPM_CORE_IRQ_TEST_1_SIGNAL_TIMER_0_IRQ);
+        psa_reply(msg->handle, CORE_TEST_ERRNO_SUCCESS);
+        break;
+    default:
+        psa_reply(msg->handle, CORE_TEST_ERRNO_INVALID_PARAMETER);
+        return;
+    }
+}
+
+static void spm_irq_test_1_execute_test_scenario_ipc(psa_signal_t signal)
+{
+    psa_msg_t msg;
+    psa_status_t status;
+
+    status = psa_get(signal, &msg);
+    if (status) {
+        return;
+    }
+
+    if (signal != SPM_CORE_IRQ_TEST_1_EXECUTE_TEST_SCENARIO_SIGNAL) {
+        psa_reply(msg.handle, CORE_TEST_ERRNO_INVALID_PARAMETER);
+    }
+
+    switch (msg.type) {
+    case PSA_IPC_CONNECT:
+        psa_reply(msg.handle, PSA_SUCCESS);
+        break;
+    case PSA_IPC_CALL:
+        spm_irq_test_1_execute_test_scenario_ipc_call(&msg);
+    break;
+    case PSA_IPC_DISCONNECT:
+        psa_reply(msg.handle, PSA_SUCCESS);
+        break;
+    default:
+        break;
+    }
+}
+#endif /* TFM_PSA_API */
+
+int32_t tfm_irq_test_1_init(void)
+{
+    tfm_enable_irq(SPM_CORE_IRQ_TEST_1_SIGNAL_TIMER_0_IRQ);
+#ifdef TFM_PSA_API
+    psa_signal_t signals = 0;
+
+    while (1) {
+        signals = psa_wait(PSA_WAIT_ANY, PSA_BLOCK);
+        if (signals & SPM_CORE_IRQ_TEST_1_SIGNAL_TIMER_0_IRQ) {
+            TIMER_0_isr_ipc();
+        } else if (signals & SPM_CORE_IRQ_TEST_1_PREPARE_TEST_SCENARIO_SIGNAL) {
+            spm_irq_test_1_signal_handle(
+                               SPM_CORE_IRQ_TEST_1_PREPARE_TEST_SCENARIO_SIGNAL,
+                               spm_irq_test_1_wrap_prepare_test_scenario);
+        } else if (signals & SPM_CORE_IRQ_TEST_1_EXECUTE_TEST_SCENARIO_SIGNAL) {
+            spm_irq_test_1_execute_test_scenario_ipc(
+                              SPM_CORE_IRQ_TEST_1_EXECUTE_TEST_SCENARIO_SIGNAL);
+        } else {
+            ; /* do nothing */
+        }
+    }
+#else
+    return TFM_SUCCESS;
+#endif /* TFM_PSA_API */
+}
diff --git a/test/test_services/tfm_irq_test_service_1/tfm_irq_test_service_1.yaml b/test/test_services/tfm_irq_test_service_1/tfm_irq_test_service_1.yaml
new file mode 100644
index 0000000..1825666
--- /dev/null
+++ b/test/test_services/tfm_irq_test_service_1/tfm_irq_test_service_1.yaml
@@ -0,0 +1,60 @@
+#-------------------------------------------------------------------------------
+# Copyright (c) 2019-2020, Arm Limited. All rights reserved.
+#
+# SPDX-License-Identifier: BSD-3-Clause
+#
+#-------------------------------------------------------------------------------
+
+{
+  "psa_framework_version": 1.0,
+  "name": "TFM_IRQ_TEST_1",
+  "type": "APPLICATION-ROT",
+  "priority": "NORMAL",
+  "entry_point": "tfm_irq_test_1_init",
+  "stack_size": "0x0400",
+  "mmio_regions": [
+    {
+      "name": "TFM_PERIPHERAL_TIMER0",
+      "permission": "READ-WRITE"
+    }
+  ],
+  "secure_functions": [
+    {
+      "name": "SPM_IRQ_TEST_1_PREPARE_TEST_SCENARIO",
+      "signal": "SPM_IRQ_TEST_1_PREPARE_TEST_SCENARIO",
+      "non_secure_clients": true,
+      "version": 1,
+      "version_policy": "STRICT"
+    },
+    {
+      "name": "SPM_IRQ_TEST_1_EXECUTE_TEST_SCENARIO",
+      "signal": "SPM_IRQ_TEST_1_EXECUTE_TEST_SCENARIO",
+      "non_secure_clients": true,
+      "version": 1,
+      "version_policy": "STRICT"
+    }
+  ],
+  "irqs": [
+    {
+      "source": "TFM_TIMER0_IRQ",
+      "signal": "SPM_CORE_IRQ_TEST_1_SIGNAL_TIMER_0_IRQ",
+      "tfm_irq_priority": 64,
+    }
+  ],
+  "services": [
+    {
+      "name": "SPM_CORE_IRQ_TEST_1_PREPARE_TEST_SCENARIO",
+      "sid": "0x0000F0A0",
+      "non_secure_clients": true,
+      "version": 1,
+      "version_policy": "STRICT"
+    },
+    {
+      "name": "SPM_CORE_IRQ_TEST_1_EXECUTE_TEST_SCENARIO",
+      "sid": "0x0000F0A1",
+      "non_secure_clients": true,
+      "version": 1,
+      "version_policy": "STRICT"
+    },
+  ]
+}
diff --git a/test/test_services/tfm_multi_core_test/psa_manifest/tfm_multi_core_test.h b/test/test_services/tfm_multi_core_test/psa_manifest/tfm_multi_core_test.h
new file mode 100644
index 0000000..ad7ccb5
--- /dev/null
+++ b/test/test_services/tfm_multi_core_test/psa_manifest/tfm_multi_core_test.h
@@ -0,0 +1,24 @@
+/*
+ * Copyright (c) 2019-2020, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
+ */
+
+/*********** WARNING: This is an auto-generated file. Do not edit! ***********/
+
+#ifndef __PSA_MANIFEST_TFM_MULTI_CORE_TEST_H__
+#define __PSA_MANIFEST_TFM_MULTI_CORE_TEST_H__
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#define MULTI_CORE_MULTI_CLIENT_CALL_TEST_0_SIGNAL              (1U << (0 + 4))
+#define MULTI_CORE_MULTI_CLIENT_CALL_TEST_1_SIGNAL              (1U << (1 + 4))
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __PSA_MANIFEST_TFM_MULTI_CORE_TEST_H__ */
diff --git a/test/test_services/tfm_multi_core_test/tfm_multi_core_test.c b/test/test_services/tfm_multi_core_test/tfm_multi_core_test.c
new file mode 100644
index 0000000..fe2238e
--- /dev/null
+++ b/test/test_services/tfm_multi_core_test/tfm_multi_core_test.c
@@ -0,0 +1,74 @@
+/*
+ * Copyright (c) 2019, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
+ */
+
+#include "psa/client.h"
+#include "psa/service.h"
+#include "psa_manifest/tfm_multi_core_test.h"
+
+static uint32_t nr_psa_call;
+
+/*
+ * Fixme: Temporarily implement abort as infinite loop,
+ * will replace it later.
+ */
+static void tfm_abort(void)
+{
+    while (1)
+        ;
+}
+
+static void multi_core_multi_client_call_test(uint32_t signal)
+{
+    psa_msg_t msg;
+    psa_status_t status;
+
+    status = psa_get(signal, &msg);
+    if (status != PSA_SUCCESS) {
+        return;
+    }
+
+    switch(msg.type) {
+    case PSA_IPC_CONNECT:
+        psa_reply(msg.handle, PSA_SUCCESS);
+        break;
+    case PSA_IPC_CALL:
+        nr_psa_call++;
+        /* Write current number of calls to outvec. */
+        psa_write(msg.handle, 0, &nr_psa_call, sizeof(nr_psa_call));
+        psa_reply(msg.handle, PSA_SUCCESS);
+        break;
+    case PSA_IPC_DISCONNECT:
+        psa_reply(msg.handle, PSA_SUCCESS);
+        break;
+    default:
+        /* Unsupported operations */
+        tfm_abort();
+    }
+}
+
+/* Test thread */
+void multi_core_test_main(void *param)
+{
+    uint32_t signals = 0;
+
+    (void)param;
+
+    while (1) {
+        signals = psa_wait(PSA_WAIT_ANY, PSA_BLOCK);
+
+        if (signals & MULTI_CORE_MULTI_CLIENT_CALL_TEST_0_SIGNAL) {
+            multi_core_multi_client_call_test(
+                                    MULTI_CORE_MULTI_CLIENT_CALL_TEST_0_SIGNAL);
+        } else if (signals & MULTI_CORE_MULTI_CLIENT_CALL_TEST_1_SIGNAL) {
+            multi_core_multi_client_call_test(
+                                    MULTI_CORE_MULTI_CLIENT_CALL_TEST_1_SIGNAL);
+        } else {
+            /* Should not come here */
+            tfm_abort();
+        }
+    }
+}
diff --git a/test/test_services/tfm_multi_core_test/tfm_multi_core_test.yaml b/test/test_services/tfm_multi_core_test/tfm_multi_core_test.yaml
new file mode 100644
index 0000000..0b910bc
--- /dev/null
+++ b/test/test_services/tfm_multi_core_test/tfm_multi_core_test.yaml
@@ -0,0 +1,36 @@
+#-------------------------------------------------------------------------------
+# Copyright (c) 2019, Arm Limited. All rights reserved.
+#
+# SPDX-License-Identifier: BSD-3-Clause
+#
+#-------------------------------------------------------------------------------
+
+{
+  "psa_framework_version": 1.0,
+  "name": "TFM_SP_MULTI_CORE_TEST",
+  "type": "APPLICATION-ROT",
+  "priority": "NORMAL",
+  "id": "0x00000007",
+  "entry_point": "multi_core_test_main",
+  "stack_size": "0x0100",
+  "secure_functions": [
+  ],
+  "services" : [
+    {
+      "name": "MULTI_CORE_MULTI_CLIENT_CALL_TEST_0",
+      "sid": "0x0000F100",
+      "signal": "MULTI_CORE_MULTI_CLIENT_CALL_TEST_0_SIGNAL",
+      "non_secure_clients": true,
+      "minor_version": 1,
+      "minor_policy": "STRICT"
+    },
+    {
+      "name": "MULTI_CORE_MULTI_CLIENT_CALL_TEST_1",
+      "sid": "0x0000F101",
+      "signal": "MULTI_CORE_MULTI_CLIENT_CALL_TEST_1_SIGNAL",
+      "non_secure_clients": true,
+      "minor_version": 1,
+      "minor_policy": "STRICT"
+    }
+  ]
+}
diff --git a/test/test_services/tfm_ps_test_service/psa_manifest/tfm_ps_test_service.h b/test/test_services/tfm_ps_test_service/psa_manifest/tfm_ps_test_service.h
new file mode 100644
index 0000000..e748ddf
--- /dev/null
+++ b/test/test_services/tfm_ps_test_service/psa_manifest/tfm_ps_test_service.h
@@ -0,0 +1,23 @@
+/*
+ * Copyright (c) 2019-2020, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
+ */
+
+/*********** WARNING: This is an auto-generated file. Do not edit! ***********/
+
+#ifndef __PSA_MANIFEST_TFM_PS_TEST_SERVICE_H__
+#define __PSA_MANIFEST_TFM_PS_TEST_SERVICE_H__
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#define TFM_PS_TEST_PREPARE_SIGNAL                              (1U << (0 + 4))
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __PSA_MANIFEST_TFM_PS_TEST_SERVICE_H__ */
diff --git a/test/test_services/tfm_ps_test_service/tfm_ps_test_service.c b/test/test_services/tfm_ps_test_service/tfm_ps_test_service.c
new file mode 100644
index 0000000..2e30796
--- /dev/null
+++ b/test/test_services/tfm_ps_test_service/tfm_ps_test_service.c
@@ -0,0 +1,49 @@
+/*
+ * Copyright (c) 2019-2020, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
+ */
+
+#ifdef TFM_PSA_API
+#include "psa/service.h"
+#include "psa_manifest/tfm_ps_test_service.h"
+#else
+#include "psa/client.h"
+#endif
+
+#include "secure_fw/partitions/protected_storage/ps_object_system.h"
+
+psa_status_t tfm_ps_test_prepare(psa_invec *in_vec, size_t in_len,
+                                 psa_outvec *out_vec, size_t out_len)
+{
+    (void)in_vec;
+    (void)in_len;
+    (void)out_vec;
+    (void)out_len;
+
+    return ps_system_prepare();
+}
+
+psa_status_t tfm_ps_test_init(void)
+{
+#ifdef TFM_PSA_API
+    psa_msg_t msg;
+
+    while (1) {
+        (void)psa_wait(TFM_PS_TEST_PREPARE_SIGNAL, PSA_BLOCK);
+        (void)psa_get(TFM_PS_TEST_PREPARE_SIGNAL, &msg);
+        switch (msg.type) {
+        case PSA_IPC_CONNECT:
+        case PSA_IPC_DISCONNECT:
+            psa_reply(msg.handle, PSA_SUCCESS);
+            break;
+        case PSA_IPC_CALL:
+            psa_reply(msg.handle, ps_system_prepare());
+            break;
+        }
+    }
+#else
+    return PSA_SUCCESS;
+#endif
+}
diff --git a/test/test_services/tfm_ps_test_service/tfm_ps_test_service.yaml b/test/test_services/tfm_ps_test_service/tfm_ps_test_service.yaml
new file mode 100644
index 0000000..eddc3ed
--- /dev/null
+++ b/test/test_services/tfm_ps_test_service/tfm_ps_test_service.yaml
@@ -0,0 +1,38 @@
+#-------------------------------------------------------------------------------
+# Copyright (c) 2019-2020, Arm Limited. All rights reserved.
+#
+# SPDX-License-Identifier: BSD-3-Clause
+#
+#-------------------------------------------------------------------------------
+
+{
+  "psa_framework_version": 1.0,
+  "name": "TFM_SP_PS_TEST",
+  "type": "PSA-ROT",
+  "priority": "NORMAL",
+  "entry_point": "tfm_ps_test_init",
+  "stack_size": "0x500",
+  "secure_functions": [
+    {
+      "name": "TFM_PS_TEST_PREPARE",
+      "signal": "TFM_PS_TEST_PREPARE",
+      "non_secure_clients": false,
+      "version": 1,
+      "version_policy": "STRICT"
+    },
+  ],
+  "services": [
+    {
+      "name": "TFM_PS_TEST_PREPARE",
+      "sid": "0x0000F0C0",
+      "non_secure_clients": false,
+      "version": 1,
+      "version_policy": "STRICT"
+    }
+  ],
+  "dependencies": [
+    "TFM_CRYPTO",
+    "TFM_ITS_GET",
+    "TFM_ITS_REMOVE"
+  ]
+}
diff --git a/test/test_services/tfm_ps_test_service/tfm_ps_test_service_api.c b/test/test_services/tfm_ps_test_service/tfm_ps_test_service_api.c
new file mode 100644
index 0000000..1377e93
--- /dev/null
+++ b/test/test_services/tfm_ps_test_service/tfm_ps_test_service_api.c
@@ -0,0 +1,37 @@
+/*
+ * Copyright (c) 2019-2020, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
+ */
+
+#include "tfm_ps_test_service_api.h"
+
+#ifdef TFM_PSA_API
+#include "psa/client.h"
+#include "psa_manifest/sid.h"
+#else
+#include "tfm_veneers.h"
+#endif
+
+__attribute__((section("SFN")))
+psa_status_t tfm_ps_test_system_prepare(void)
+{
+#ifdef TFM_PSA_API
+    psa_handle_t handle;
+    psa_status_t status;
+
+    handle = psa_connect(TFM_PS_TEST_PREPARE_SID,
+                         TFM_PS_TEST_PREPARE_VERSION);
+    if (!PSA_HANDLE_IS_VALID(handle)) {
+        return PSA_ERROR_GENERIC_ERROR;
+    }
+
+    status = psa_call(handle, PSA_IPC_CALL, NULL, 0, NULL, 0);
+    psa_close(handle);
+
+    return status;
+#else
+    return tfm_tfm_ps_test_prepare_veneer(NULL, 0, NULL, 0);
+#endif
+}
diff --git a/test/test_services/tfm_ps_test_service/tfm_ps_test_service_api.h b/test/test_services/tfm_ps_test_service/tfm_ps_test_service_api.h
new file mode 100644
index 0000000..50aaa69
--- /dev/null
+++ b/test/test_services/tfm_ps_test_service/tfm_ps_test_service_api.h
@@ -0,0 +1,28 @@
+/*
+ * Copyright (c) 2019-2020, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
+ */
+
+#ifndef __TFM_PS_TEST_SERVICE_API_H__
+#define __TFM_PS_TEST_SERVICE_API_H__
+
+#include "psa/error.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * \brief Requests the PS Test Service to call ps_system_prepare().
+ *
+ * \return Returns error code as specified in \ref psa_status_t
+ */
+psa_status_t tfm_ps_test_system_prepare(void);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __TFM_PS_TEST_SERVICE_API_H__ */
diff --git a/test/test_services/tfm_secure_client_2/psa_manifest/tfm_secure_client_2.h b/test/test_services/tfm_secure_client_2/psa_manifest/tfm_secure_client_2.h
new file mode 100644
index 0000000..a8fdf47
--- /dev/null
+++ b/test/test_services/tfm_secure_client_2/psa_manifest/tfm_secure_client_2.h
@@ -0,0 +1,23 @@
+/*
+ * Copyright (c) 2019-2020, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
+ */
+
+/*********** WARNING: This is an auto-generated file. Do not edit! ***********/
+
+#ifndef __PSA_MANIFEST_TFM_SECURE_CLIENT_2_H__
+#define __PSA_MANIFEST_TFM_SECURE_CLIENT_2_H__
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#define TFM_SECURE_CLIENT_2_SIGNAL                              (1U << (0 + 4))
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __PSA_MANIFEST_TFM_SECURE_CLIENT_2_H__ */
diff --git a/test/test_services/tfm_secure_client_2/tfm_secure_client_2.c b/test/test_services/tfm_secure_client_2/tfm_secure_client_2.c
new file mode 100644
index 0000000..153caac
--- /dev/null
+++ b/test/test_services/tfm_secure_client_2/tfm_secure_client_2.c
@@ -0,0 +1,145 @@
+/*
+ * Copyright (c) 2019-2020, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
+ */
+
+#include "tfm_secure_client_2_api.h"
+#include "psa/internal_trusted_storage.h"
+#include "psa/crypto.h"
+
+#ifdef TFM_PSA_API
+#include "psa/service.h"
+#include "psa_manifest/tfm_secure_client_2.h"
+#else
+#include "psa/client.h"
+#endif
+
+#ifdef ENABLE_CRYPTO_SERVICE_TESTS
+/**
+ * \brief Tests calling psa_destroy_key() with the supplied key handle.
+ *
+ * \param[in] arg      Pointer to key handle
+ * \param[in] arg_len  Length of arg in bytes
+ *
+ * \return Returns test result as specified in \ref psa_status_t
+ */
+static psa_status_t secure_client_2_test_crypto_access_ctrl(const void *arg,
+                                                            size_t arg_len)
+{
+    psa_key_handle_t key_handle;
+
+    if (arg_len != sizeof(key_handle)) {
+        return PSA_ERROR_PROGRAMMER_ERROR;
+    }
+
+    key_handle = *((psa_key_handle_t *)arg);
+
+    /* Attempt to destroy the key handle */
+    return psa_destroy_key(key_handle);
+}
+#endif /* ENABLE_CRYPTO_SERVICE_TESTS */
+
+#ifdef ENABLE_INTERNAL_TRUSTED_STORAGE_SERVICE_TESTS
+/**
+ * \brief Tests calling psa_its_get() with the supplied uid.
+ *
+ * \param[in] arg      Pointer to uid
+ * \param[in] arg_len  Length of arg in bytes
+ *
+ * \return Returns test result as specified in \ref psa_status_t
+ */
+static psa_status_t secure_client_2_test_its_access_ctrl(const void *arg,
+                                                         size_t arg_len)
+{
+    psa_storage_uid_t uid;
+    size_t p_data_length;
+    uint8_t data[1];
+
+    if (arg_len != sizeof(uid)) {
+        return PSA_ERROR_PROGRAMMER_ERROR;
+    }
+
+    uid = *((psa_storage_uid_t *)arg);
+
+    /* Attempt to get one byte from the UID and return the resulting status */
+    return psa_its_get(uid, 0, sizeof(data), data, &p_data_length);
+}
+#endif /* ENABLE_INTERNAL_TRUSTED_STORAGE_SERVICE_TESTS */
+
+/**
+ * \brief Calls the test function with the supplied ID and returns the result
+ *        from the test function.
+ *
+ * \param[in] id       The ID of the test function
+ * \param[in] arg      Pointer to argument to pass to test function
+ * \param[in] arg_len  Length of argument in bytes
+ *
+ * \return Returns test result as specified in \ref psa_status_t
+ */
+static psa_status_t secure_client_2_dispatch(int32_t id, const void *arg,
+                                             size_t arg_len)
+{
+    switch (id) {
+#ifdef ENABLE_INTERNAL_TRUSTED_STORAGE_SERVICE_TESTS
+    case TFM_SECURE_CLIENT_2_ID_ITS_ACCESS_CTRL:
+        return secure_client_2_test_its_access_ctrl(arg, arg_len);
+#endif
+#ifdef ENABLE_CRYPTO_SERVICE_TESTS
+    case TFM_SECURE_CLIENT_2_ID_CRYPTO_ACCESS_CTRL:
+        return secure_client_2_test_crypto_access_ctrl(arg, arg_len);
+#endif
+    default:
+        return PSA_ERROR_PROGRAMMER_ERROR;
+    }
+}
+
+#ifdef TFM_PSA_API
+#define SECURE_CLIENT_2_MAX_ARG_LEN 8U
+
+void tfm_secure_client_2_init(void)
+{
+    psa_msg_t msg;
+    size_t len;
+    char arg[SECURE_CLIENT_2_MAX_ARG_LEN] __attribute__((__aligned__(8)));
+
+    while (1) {
+        (void)psa_wait(TFM_SECURE_CLIENT_2_SIGNAL, PSA_BLOCK);
+        if (psa_get(TFM_SECURE_CLIENT_2_SIGNAL, &msg) != PSA_SUCCESS) {
+            continue;
+        }
+        switch (msg.type) {
+        case PSA_IPC_CONNECT:
+        case PSA_IPC_DISCONNECT:
+            psa_reply(msg.handle, PSA_SUCCESS);
+            break;
+        default:
+            len = psa_read(msg.handle, 0, arg, SECURE_CLIENT_2_MAX_ARG_LEN);
+            psa_reply(msg.handle, secure_client_2_dispatch(msg.type, arg, len));
+            break;
+        }
+    }
+}
+#else /* TFM_PSA_API */
+psa_status_t tfm_secure_client_2_init(void)
+{
+    return PSA_SUCCESS;
+}
+
+psa_status_t tfm_secure_client_2_call(psa_invec *in_vec, size_t in_len,
+                                      psa_outvec *out_vec, size_t out_len)
+{
+    int32_t id;
+
+    (void)out_vec;
+
+    if (in_len != 2 || out_len != 0 || in_vec[0].len != sizeof(id)) {
+        return PSA_ERROR_PROGRAMMER_ERROR;
+    }
+
+    id = *((int32_t *)in_vec[0].base);
+
+    return secure_client_2_dispatch(id, in_vec[1].base, in_vec[1].len);
+}
+#endif /* TFM_PSA_API */
diff --git a/test/test_services/tfm_secure_client_2/tfm_secure_client_2.yaml b/test/test_services/tfm_secure_client_2/tfm_secure_client_2.yaml
new file mode 100644
index 0000000..3399933
--- /dev/null
+++ b/test/test_services/tfm_secure_client_2/tfm_secure_client_2.yaml
@@ -0,0 +1,37 @@
+#-------------------------------------------------------------------------------
+# Copyright (c) 2019-2020, Arm Limited. All rights reserved.
+#
+# SPDX-License-Identifier: BSD-3-Clause
+#
+#-------------------------------------------------------------------------------
+
+{
+  "psa_framework_version": 1.0,
+  "name": "TFM_SP_SECURE_CLIENT_2",
+  "type": "APPLICATION-ROT",
+  "priority": "NORMAL",
+  "entry_point": "tfm_secure_client_2_init",
+  "stack_size": "0x300",
+  "secure_functions": [
+    {
+      "name": "TFM_SECURE_CLIENT_2_CALL",
+      "signal": "TFM_SECURE_CLIENT_2_CALL",
+      "non_secure_clients": false,
+      "version": 1,
+      "version_policy": "STRICT"
+    },
+  ],
+  "services": [
+    {
+      "name": "TFM_SECURE_CLIENT_2",
+      "sid": "0x0000F0E0",
+      "non_secure_clients": false,
+      "version": 1,
+      "version_policy": "STRICT"
+    }
+  ],
+  "dependencies": [
+    "TFM_ITS_GET",
+    "TFM_CRYPTO"
+  ]
+}
diff --git a/test/test_services/tfm_secure_client_2/tfm_secure_client_2_api.c b/test/test_services/tfm_secure_client_2/tfm_secure_client_2_api.c
new file mode 100644
index 0000000..b5beb9a
--- /dev/null
+++ b/test/test_services/tfm_secure_client_2/tfm_secure_client_2_api.c
@@ -0,0 +1,47 @@
+/*
+ * Copyright (c) 2019, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
+ */
+
+#include "tfm_secure_client_2_api.h"
+#include "psa/client.h"
+
+#ifdef TFM_PSA_API
+#include "psa_manifest/sid.h"
+#else
+#include "tfm_veneers.h"
+#endif
+
+__attribute__((section("SFN")))
+psa_status_t tfm_secure_client_2_call_test(int32_t id, const void *arg,
+                                           size_t arg_len)
+{
+#ifdef TFM_PSA_API
+    psa_handle_t handle;
+    psa_status_t status;
+    psa_invec in_vec[] = {
+        { .base = arg, .len = arg_len },
+    };
+
+    handle = psa_connect(TFM_SECURE_CLIENT_2_SID, TFM_SECURE_CLIENT_2_VERSION);
+    if (!PSA_HANDLE_IS_VALID(handle)) {
+        return PSA_ERROR_GENERIC_ERROR;
+    }
+
+    /* Pass the ID through the type parameter of psa_call() */
+    status = psa_call(handle, id, in_vec, 1, NULL, 0);
+    psa_close(handle);
+
+    return status;
+#else
+    /* Pack the ID in the invec */
+    psa_invec in_vec[] = {
+        { .base = &id, .len = sizeof(id) },
+        { .base = arg, .len = arg_len },
+    };
+
+    return tfm_tfm_secure_client_2_call_veneer(in_vec, 2, NULL, 0);
+#endif
+}
diff --git a/test/test_services/tfm_secure_client_2/tfm_secure_client_2_api.h b/test/test_services/tfm_secure_client_2/tfm_secure_client_2_api.h
new file mode 100644
index 0000000..a6018c5
--- /dev/null
+++ b/test/test_services/tfm_secure_client_2/tfm_secure_client_2_api.h
@@ -0,0 +1,41 @@
+/*
+ * Copyright (c) 2019-2020, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
+ */
+
+#ifndef __TFM_SECURE_CLIENT_2_API_H__
+#define __TFM_SECURE_CLIENT_2_API_H__
+
+#include <stddef.h>
+#include <stdint.h>
+
+#include "psa/error.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#define TFM_SECURE_CLIENT_2_ID_ITS_ACCESS_CTRL    1001
+#define TFM_SECURE_CLIENT_2_ID_CRYPTO_ACCESS_CTRL 2001
+
+/**
+ * \brief Calls the test function with the supplied ID within the execution
+ *        context of the Secure Client 2 partition and returns the resulting
+ *        status.
+ *
+ * \param[in] id       The ID of the test function
+ * \param[in] arg      Pointer to argument to pass to test function
+ * \param[in] arg_len  Length of argument in bytes
+ *
+ * \return Returns error code as specified in \ref psa_status_t
+ */
+psa_status_t tfm_secure_client_2_call_test(int32_t id, const void *arg,
+                                           size_t arg_len);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __TFM_SECURE_CLIENT_2_API_H__ */
diff --git a/test/test_services/tfm_secure_client_service/psa_manifest/tfm_test_client_service.h b/test/test_services/tfm_secure_client_service/psa_manifest/tfm_test_client_service.h
new file mode 100644
index 0000000..2e03069
--- /dev/null
+++ b/test/test_services/tfm_secure_client_service/psa_manifest/tfm_test_client_service.h
@@ -0,0 +1,23 @@
+/*
+ * Copyright (c) 2019-2020, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
+ */
+
+/*********** WARNING: This is an auto-generated file. Do not edit! ***********/
+
+#ifndef __PSA_MANIFEST_TFM_TEST_CLIENT_SERVICE_H__
+#define __PSA_MANIFEST_TFM_TEST_CLIENT_SERVICE_H__
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#define TFM_SECURE_CLIENT_SFN_RUN_TESTS_SIGNAL                  (1U << (0 + 4))
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __PSA_MANIFEST_TFM_TEST_CLIENT_SERVICE_H__ */
diff --git a/test/test_services/tfm_secure_client_service/tfm_secure_client_service.c b/test/test_services/tfm_secure_client_service/tfm_secure_client_service.c
new file mode 100644
index 0000000..62a8b5d
--- /dev/null
+++ b/test/test_services/tfm_secure_client_service/tfm_secure_client_service.c
@@ -0,0 +1,54 @@
+/*
+ * Copyright (c) 2018-2020, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
+ */
+
+#include "tfm_secure_client_service.h"
+#include "test/framework/test_framework_integ_test.h"
+#ifdef TFM_PSA_API
+#include "psa/client.h"
+#include "psa/service.h"
+#include "psa_manifest/tfm_test_client_service.h"
+#endif
+
+/**
+ * \brief Service initialisation function. No special initialisation is
+ *        required.
+ *
+ * \return Returns 0 on success
+ */
+int32_t tfm_secure_client_service_init(void)
+{
+#ifdef TFM_PSA_API
+    psa_msg_t msg;
+
+    while (1) {
+        psa_wait(TFM_SECURE_CLIENT_SFN_RUN_TESTS_SIGNAL, PSA_BLOCK);
+        psa_get(TFM_SECURE_CLIENT_SFN_RUN_TESTS_SIGNAL, &msg);
+        switch (msg.type) {
+        case PSA_IPC_CONNECT:
+            psa_reply(msg.handle, PSA_SUCCESS);
+            break;
+        case PSA_IPC_CALL:
+            psa_reply(msg.handle, tfm_secure_client_service_sfn_run_tests());
+            break;
+        case PSA_IPC_DISCONNECT:
+            psa_reply(msg.handle, PSA_SUCCESS);
+            break;
+        default:
+            /* cannot get here? [broken SPM]. TODO*/
+            break;
+        }
+    }
+#else
+    return 0;
+#endif
+}
+
+int32_t tfm_secure_client_service_sfn_run_tests(void)
+{
+    start_integ_test();
+    return 0;
+}
diff --git a/test/test_services/tfm_secure_client_service/tfm_secure_client_service.h b/test/test_services/tfm_secure_client_service/tfm_secure_client_service.h
new file mode 100644
index 0000000..baa650a
--- /dev/null
+++ b/test/test_services/tfm_secure_client_service/tfm_secure_client_service.h
@@ -0,0 +1,28 @@
+/*
+ * Copyright (c) 2018-2019, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
+ */
+
+#ifndef __TFM_SECURE_CLIENT_SERVICE_H__
+#define __TFM_SECURE_CLIENT_SERVICE_H__
+
+#include <stdint.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * \brief Runs the secure integration tests.
+ *
+ * \return Returns 0 on success.
+ */
+int32_t tfm_secure_client_service_sfn_run_tests(void);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __TFM_SECURE_CLIENT_SERVICE_H__ */
diff --git a/test/test_services/tfm_secure_client_service/tfm_secure_client_service_api.c b/test/test_services/tfm_secure_client_service/tfm_secure_client_service_api.c
new file mode 100644
index 0000000..3a80446
--- /dev/null
+++ b/test/test_services/tfm_secure_client_service/tfm_secure_client_service_api.c
@@ -0,0 +1,40 @@
+/*
+ * Copyright (c) 2018-2019, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
+ */
+
+#include "tfm_secure_client_service_api.h"
+#ifdef TFM_PSA_API
+#include "psa/client.h"
+#include "tfm_api.h"
+#include "psa_manifest/sid.h"
+#else /* TFM_PSA_API */
+#include "tfm_veneers.h"
+#endif /* TFM_PSA_API */
+
+int32_t tfm_secure_client_run_tests(void)
+{
+#ifdef TFM_PSA_API
+    psa_handle_t handle;
+    psa_status_t status;
+
+    handle = psa_connect(TFM_SECURE_CLIENT_SFN_RUN_TESTS_SID,
+                         TFM_SECURE_CLIENT_SFN_RUN_TESTS_VERSION);
+    if (handle <= 0) {
+        return TFM_ERROR_GENERIC;
+    }
+
+    status = psa_call(handle, PSA_IPC_CALL, NULL, 0, NULL, 0);
+    psa_close(handle);
+
+    if (status != PSA_SUCCESS) {
+        return TFM_ERROR_GENERIC;
+    }
+#else
+    tfm_tfm_secure_client_service_sfn_run_tests_veneer(NULL, 0, NULL, 0);
+#endif
+
+    return 0;
+}
diff --git a/test/test_services/tfm_secure_client_service/tfm_secure_client_service_api.h b/test/test_services/tfm_secure_client_service/tfm_secure_client_service_api.h
new file mode 100644
index 0000000..35e9004
--- /dev/null
+++ b/test/test_services/tfm_secure_client_service/tfm_secure_client_service_api.h
@@ -0,0 +1,28 @@
+/*
+ * Copyright (c) 2018, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
+ */
+
+#ifndef __TFM_SECURE_CLIENT_SERVICE_API_H__
+#define __TFM_SECURE_CLIENT_SERVICE_API_H__
+
+#include <stdint.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * \brief Runs the secure integration tests.
+ *
+ * \return Returns 0 on success
+ */
+int32_t tfm_secure_client_run_tests(void);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __TFM_SECURE_CLIENT_SERVICE_API_H__ */
diff --git a/test/test_services/tfm_secure_client_service/tfm_test_client_service.yaml b/test/test_services/tfm_secure_client_service/tfm_test_client_service.yaml
new file mode 100644
index 0000000..7931f16
--- /dev/null
+++ b/test/test_services/tfm_secure_client_service/tfm_test_client_service.yaml
@@ -0,0 +1,58 @@
+#-------------------------------------------------------------------------------
+# Copyright (c) 2018-2020, Arm Limited. All rights reserved.
+#
+# SPDX-License-Identifier: BSD-3-Clause
+#
+#-------------------------------------------------------------------------------
+
+{
+  "psa_framework_version": 1.0,
+  "name": "TFM_SP_SECURE_TEST_PARTITION",
+  "type": "PSA-ROT",
+  "priority": "NORMAL",
+  "entry_point": "tfm_secure_client_service_init",
+  "stack_size": "0x0D00",
+  "mmio_regions": [
+    {
+      "name": "TFM_PERIPHERAL_STD_UART",
+      "permission": "READ-WRITE"
+    }
+  ],
+  "secure_functions": [
+    {
+      "name": "TFM_SECURE_CLIENT_SFN_RUN_TESTS",
+      "signal": "TFM_SECURE_CLIENT_SERVICE_SFN_RUN_TESTS",
+      "non_secure_clients": true,
+      "version": 1,
+      "version_policy": "STRICT"
+    },
+  ],
+  "services": [
+    {
+      "name": "TFM_SECURE_CLIENT_SFN_RUN_TESTS",
+      "sid": "0x0000F000",
+      "non_secure_clients": true,
+      "version": 1,
+      "version_policy": "STRICT"
+    }
+  ],
+  "dependencies": [
+    "TFM_SECURE_CLIENT_2",
+    "TFM_CRYPTO",
+    "TFM_PS_SET",
+    "TFM_PS_GET",
+    "TFM_PS_GET_INFO",
+    "TFM_PS_REMOVE",
+    "TFM_PS_GET_SUPPORT",
+    "TFM_ITS_SET",
+    "TFM_ITS_GET",
+    "TFM_ITS_GET_INFO",
+    "TFM_ITS_REMOVE",
+    "TFM_ATTEST_GET_TOKEN",
+    "TFM_ATTEST_GET_TOKEN_SIZE",
+    "TFM_ATTEST_GET_PUBLIC_KEY",
+    "TFM_PS_TEST_PREPARE",
+    "TFM_SP_PLATFORM_SYSTEM_RESET",
+    "TFM_SP_PLATFORM_IOCTL"
+  ]
+}