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"
+ ]
+}