App: Example NS app
Contains an example implementation for NS application using Trusted
Firmware M interface.
This app is also used for triggering the test suites.
Change-Id: Ie294ab683014a70112d4aa78e415882ab0e872fa
Signed-off-by: Abhishek Pandit <abhishek.pandit@arm.com>
diff --git a/app/ext/tz_context.c b/app/ext/tz_context.c
new file mode 100644
index 0000000..26e8081
--- /dev/null
+++ b/app/ext/tz_context.c
@@ -0,0 +1,70 @@
+/*
+ * Copyright (c) 2015-2016 ARM Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ *
+ * Licensed under the Apache License, Version 2.0 (the License); you may
+ * not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an AS IS BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ * ----------------------------------------------------------------------------
+ *
+ * $Date: 15. October 2016
+ * $Revision: 1.1.0
+ *
+ * Project: TrustZone for ARMv8-M
+ * Title: Context Management for ARMv8-M TrustZone - Stub implementation,
+ * TFM will take charge of the stack memory management in S mode
+ *
+ *---------------------------------------------------------------------------*/
+
+#include "tz_context.h"
+
+
+/// Initialize secure context memory system
+/// \return execution status (1: success, 0: error)
+uint32_t TZ_InitContextSystem_S (void) {
+ return 1U; // Success
+}
+
+
+/// Allocate context memory for calling secure software modules in TrustZone
+/// \param[in] module identifies software modules called from non-secure mode
+/// \return value != 0 id TrustZone memory slot identifier
+/// \return value 0 no memory available or internal error
+TZ_MemoryId_t TZ_AllocModuleContext_S (TZ_ModuleId_t module) {
+ uint32_t slot = 0;
+ return (slot + 1U);
+}
+
+
+/// Free context memory that was previously allocated with \ref TZ_AllocModuleContext_S
+/// \param[in] id TrustZone memory slot identifier
+/// \return execution status (1: success, 0: error)
+uint32_t TZ_FreeModuleContext_S (TZ_MemoryId_t id) {
+ return 1U; // Success
+}
+
+
+/// Load secure context (called on RTOS thread context switch)
+/// \param[in] id TrustZone memory slot identifier
+/// \return execution status (1: success, 0: error)
+uint32_t TZ_LoadContext_S (TZ_MemoryId_t id) {
+ return 1U; // Success
+}
+
+
+/// Store secure context (called on RTOS thread context switch)
+/// \param[in] id TrustZone memory slot identifier
+/// \return execution status (1: success, 0: error)
+uint32_t TZ_StoreContext_S (TZ_MemoryId_t id) {
+ return 1U; // Success
+}
diff --git a/app/ext/tz_context.h b/app/ext/tz_context.h
new file mode 100644
index 0000000..cd6d8ab
--- /dev/null
+++ b/app/ext/tz_context.h
@@ -0,0 +1,69 @@
+/*
+ * Copyright (c) 2015-2016 ARM Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ *
+ * Licensed under the Apache License, Version 2.0 (the License); you may
+ * not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an AS IS BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ * ----------------------------------------------------------------------------
+ *
+ * $Date: 21. September 2016
+ * $Revision: V1.0
+ *
+ * Project: TrustZone for ARMv8-M
+ * Title: Context Management for ARMv8-M TrustZone
+ *
+ * Version 1.0
+ * Initial Release
+ *---------------------------------------------------------------------------*/
+
+#ifndef TZ_CONTEXT_H
+#define TZ_CONTEXT_H
+
+#include <stdint.h>
+
+#ifndef TZ_MODULEID_T
+#define TZ_MODULEID_T
+/// \details Data type that identifies secure software modules called by a process.
+typedef uint32_t TZ_ModuleId_t;
+#endif
+
+/// \details TZ Memory ID identifies an allocated memory slot.
+typedef uint32_t TZ_MemoryId_t;
+
+/// Initialize secure context memory system
+/// \return execution status (1: success, 0: error)
+uint32_t TZ_InitContextSystem_S (void);
+
+/// Allocate context memory for calling secure software modules in TrustZone
+/// \param[in] module identifies software modules called from non-secure mode
+/// \return value != 0 id TrustZone memory slot identifier
+/// \return value 0 no memory available or internal error
+TZ_MemoryId_t TZ_AllocModuleContext_S (TZ_ModuleId_t module);
+
+/// Free context memory that was previously allocated with \ref TZ_AllocModuleContext_S
+/// \param[in] id TrustZone memory slot identifier
+/// \return execution status (1: success, 0: error)
+uint32_t TZ_FreeModuleContext_S (TZ_MemoryId_t id);
+
+/// Load secure context (called on RTOS thread context switch)
+/// \param[in] id TrustZone memory slot identifier
+/// \return execution status (1: success, 0: error)
+uint32_t TZ_LoadContext_S (TZ_MemoryId_t id);
+
+/// Store secure context (called on RTOS thread context switch)
+/// \param[in] id TrustZone memory slot identifier
+/// \return execution status (1: success, 0: error)
+uint32_t TZ_StoreContext_S (TZ_MemoryId_t id);
+
+#endif // TZ_CONTEXT_H
diff --git a/app/main_ns.c b/app/main_ns.c
new file mode 100644
index 0000000..a0d64d5
--- /dev/null
+++ b/app/main_ns.c
@@ -0,0 +1,122 @@
+/*
+ * Copyright (c) 2017, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
+ */
+
+#include <stdio.h>
+#include <string.h>
+#include <stdbool.h>
+
+#include "cmsis.h"
+#include "tfm_api.h"
+#include "cmsis_os2.h"
+#include "tfm_integ_test.h"
+#include "tfm_ns_svc.h"
+#include "tfm_sst_svc_handler.h"
+#include "tfm_ns_lock.h"
+#ifdef CORE_TEST_SERVICES
+#include "test/suites/core/non_secure/svc_core_test_ns.h"
+#endif
+#ifdef TEST_FRAMEWORK_NS
+#include "test/framework/integ_test.h"
+#endif
+
+#include "Driver_USART.h"
+
+/* For UART the CMSIS driver is used */
+extern ARM_DRIVER_USART Driver_USART0;
+
+/**
+ * \brief Modified table template for user defined SVC functions
+ *
+ * \details RTX has a weak definition of osRtxUserSVC, which
+ * is overridden here
+ */
+extern void * const osRtxUserSVC[1+USER_SVC_COUNT];
+ void * const osRtxUserSVC[1+USER_SVC_COUNT] = {
+ (void *)USER_SVC_COUNT,
+
+/* SERVICES_TEST_NS */
+ (void *)tfm_sst_svc_get_handle,
+ (void *)tfm_sst_svc_create,
+ (void *)tfm_sst_svc_get_attributes,
+ (void *)tfm_sst_svc_read,
+ (void *)tfm_sst_svc_write,
+ (void *)tfm_sst_svc_delete,
+
+#if defined(CORE_TEST_INTERACTIVE)
+ (void *)svc_secure_decrement_ns_lock_1,
+ (void *)svc_secure_decrement_ns_lock_2,
+#endif /* CORE_TEST_INTERACTIVE */
+
+#if defined(CORE_TEST_SERVICES)
+ (void *)svc_tfm_core_test,
+ (void *)svc_tfm_core_test_multiple_calls,
+#endif /* CORE_TEST_SERVICES */
+
+//(void *)user_function1,
+// ...
+};
+
+/* Struct FILE is implemented in stdio.h. Used to redirect printf to UART0 */
+FILE __stdout;
+/* Redirects armclang printf to UART */
+int fputc(int ch, FILE *f) {
+ /* Send byte to UART0 */
+ (void)Driver_USART0.Send((const unsigned char *)&ch, 1);
+ /* Return character written */
+ return ch;
+}
+/* redirects gcc printf to uart */
+int _write(int fd, char * str, int len)
+{
+ (void)Driver_USART0.Send(str, len);
+
+ return len;
+}
+
+/**
+ * \brief List of RTOS thread attributes
+ */
+#ifdef TEST_FRAMEWORK_NS
+static const osThreadAttr_t tserv_test = {
+ .name = "test_app",
+ .stack_size = 1024U
+};
+#endif
+
+/**
+ * \brief Static globals to hold RTOS related quantities,
+ * main thread
+ */
+static osStatus_t status;
+static osThreadId_t thread_id;
+
+/**
+ * \brief main() function
+ */
+__attribute__((noreturn))
+int main(void)
+{
+ (void)Driver_USART0.Initialize(NULL); /* Use UART0 as stdout */
+ Driver_USART0.Control(ARM_USART_MODE_ASYNCHRONOUS, 115200);
+
+ status = osKernelInitialize();
+
+ /* Initialize the TFM NS lock */
+ tfm_ns_lock_init();
+
+#ifdef TEST_FRAMEWORK_NS
+ thread_id = osThreadNew(test_app, NULL, &tserv_test);
+#else
+ UNUSED_VARIABLE(thread_id);
+#endif
+
+ status = osKernelStart();
+
+ /* Reached only in case of error */
+ for (;;) {
+ }
+}
diff --git a/app/os_wrapper_rtx.c b/app/os_wrapper_rtx.c
new file mode 100644
index 0000000..7d8d6d1
--- /dev/null
+++ b/app/os_wrapper_rtx.c
@@ -0,0 +1,121 @@
+/*
+ * Copyright (c) 2017, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
+ */
+
+#include "test/suites/sst/non_secure/os_wrapper.h"
+
+#include <string.h>
+#include "cmsis.h"
+#include "cmsis_os2.h"
+
+/* This is an example OS abstraction layer rtx RTOS for non-secure test
+ * environment */
+
+uint32_t os_wrapper_new_thread(const char* name, uint32_t stack_size,
+ os_wrapper_thread_func func, uint32_t priority)
+{
+ osThreadAttr_t task_attribs = {.tz_module = 1};
+ osThreadId_t thread_id;
+
+ task_attribs.stack_size = stack_size;
+ task_attribs.name = name;
+ task_attribs.priority = priority;
+
+ thread_id = osThreadNew(func, NULL, &task_attribs);
+ if (thread_id == NULL) {
+ return OS_WRAPPER_ERROR;
+ }
+
+ return (uint32_t)thread_id;
+}
+
+
+uint32_t os_wrapper_semaphore_create(uint32_t max_count, uint32_t initial_count,
+ const char* name)
+{
+ osSemaphoreAttr_t sema_attrib = {0};
+ osSemaphoreId_t semaphore;
+
+ sema_attrib.name = name;
+
+ semaphore = osSemaphoreNew(max_count, initial_count, &sema_attrib);
+ if (semaphore == NULL) {
+ return OS_WRAPPER_ERROR;
+ }
+
+ return (uint32_t)semaphore;
+}
+
+uint32_t os_wrapper_semaphore_acquire(uint32_t semaphore_id, uint32_t timeout)
+{
+ osStatus_t status;
+
+ status = osSemaphoreAcquire((osSemaphoreId_t)semaphore_id, timeout);
+ if (status != osOK) {
+ return OS_WRAPPER_ERROR;
+ }
+
+ return 0;
+}
+
+uint32_t os_wrapper_semaphore_release(uint32_t sema)
+{
+ osStatus_t status;
+
+ status = osSemaphoreRelease((osSemaphoreId_t)sema);
+ if (status != osOK) {
+ return OS_WRAPPER_ERROR;
+ }
+
+ return 0;
+}
+
+uint32_t os_wrapper_semaphore_delete(uint32_t sema)
+{
+ osStatus_t status;
+
+ status = osSemaphoreDelete((osSemaphoreId_t)sema);
+ if (status != osOK) {
+ return OS_WRAPPER_ERROR;
+ }
+
+ return 0;
+}
+
+uint32_t os_wrapper_get_thread_id(void)
+{
+ osThreadId_t thread_id;
+
+ thread_id = osThreadGetId();
+ if(thread_id == NULL) {
+ return OS_WRAPPER_ERROR;
+ }
+
+ return (uint32_t)thread_id;
+}
+
+uint32_t os_wrapper_get_thread_priority(uint32_t id)
+{
+ osPriority_t prio;
+
+ prio = osThreadGetPriority((osThreadId_t)id);
+ if (prio == osPriorityError) {
+ return OS_WRAPPER_ERROR;
+ }
+
+ return prio;
+}
+
+uint32_t os_wrapper_delete_thread(uint32_t id)
+{
+ /* Make sure the thread has ended at this point*/
+ (void)osThreadJoin((osThreadId_t) id);
+
+ /* RTX handles thread deletion automatically. So, any
+ * action is required in this function to delete the thread. */
+
+ return 0;
+}
diff --git a/app/tfm_integ_test.c b/app/tfm_integ_test.c
new file mode 100644
index 0000000..dfa73c1
--- /dev/null
+++ b/app/tfm_integ_test.c
@@ -0,0 +1,341 @@
+/*
+ * Copyright (c) 2017, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
+ */
+
+#include <stdio.h>
+#include <stdint.h>
+#include <string.h>
+#include <stdbool.h>
+
+#include "cmsis.h"
+#include "tfm_api.h"
+#include "cmsis_os2.h"
+
+#include "tfm_integ_test.h"
+#include "test/framework/integ_test.h"
+
+#ifdef CORE_TEST_INTERACTIVE
+#include "test/test_services/tfm_core_test/core_test_defs.h"
+#include "test/test_services/tfm_core_test/tfm_ss_core_test_veneers.h"
+#include "tfm_ns_svc.h"
+
+#define TRY_SFN(fn, ...) \
+ do { \
+ enum tfm_status_e res = (enum tfm_status_e) fn(__VA_ARGS__); \
+ switch(res) { \
+ case TFM_SUCCESS: \
+ LOG_MSG("Secure call to " #fn "(" #__VA_ARGS__") successful!!"); \
+ break; \
+ case TFM_SERVICE_PENDED: \
+ LOG_MSG("Secure call to " #fn "(" #__VA_ARGS__") pended!!"); \
+ break; \
+ case TFM_ERROR_SERVICE_ALREADY_PENDED: \
+ LOG_MSG("Secure call to " #fn "(" #__VA_ARGS__") failed, already pended!!"); \
+ break; \
+ case TFM_ERROR_SECURE_DOMAIN_LOCKED: \
+ LOG_MSG("Secure call to " #fn "(" #__VA_ARGS__") failed, S domain locked!!"); \
+ break; \
+ case TFM_ERROR_NS_THREAD_MODE_CALL: \
+ LOG_MSG("Secure call to " #fn "(" #__VA_ARGS__") failed, NS thread mode!!"); \
+ break; \
+ default: \
+ LOG_MSG("Secure call to " #fn "(" #__VA_ARGS__") failed, generic!!"); \
+ } \
+ } while(0)
+/**
+ * \brief SVC_SECURE_DECREMENT_NS_LOCK_1
+ *
+ */
+void svc_secure_decrement_ns_lock_1(void)
+{
+ TRY_SFN(tfm_core_test_sfn, CORE_TEST_ID_BLOCK, 0x1, 0x1, 0x1);
+}
+
+/**
+ * \brief SVC_SECURE_DECREMENT_NS_LOCK_2
+ *
+ */
+void svc_secure_decrement_ns_lock_2(void)
+{
+ TRY_SFN(tfm_core_test_sfn, CORE_TEST_ID_BLOCK, 0x2, 0x2, 0x2);
+}
+/**
+ * \brief Test definition for the RTX - TFM integration tests
+ * scenarios
+ */
+enum test_type {
+ TEST_TYPE_1 = 1, /*!< Sequential test: single task using the NS lock to access TFM */
+ TEST_TYPE_2, /*!< Priority test: high priority tries to preempt TFM, gets delayed */
+ TEST_TYPE_3, /*!< Priority inversion: classical scenario with high priority task
+ waiting on lower priority task undefinitely if NS lock is configured
+ without priority inheritance */
+ TEST_TYPE_4, /*!< non-NS lock: like sequential, but doesn't use any NS lock mechanism */
+ TEST_TYPE_5 /*!< non-NS lock, core locked: high priority tries to overcome the NS lock
+ but finds TFM core locked by lower priority task and fails */
+};
+
+static const osThreadAttr_t tattr_seq = {
+ .name = "seq_task",
+ .stack_size = 1024U,
+ .attr_bits = osThreadJoinable,
+ .tz_module = 1,
+};
+static const osThreadAttr_t tattr_mid = {
+ .name = "mid_task",
+ .stack_size = 512U,
+ .attr_bits = osThreadJoinable,
+ .tz_module = 0,
+ .priority = osPriorityAboveNormal
+};
+static const osThreadAttr_t tattr_pri = {
+ .name = "pri_task",
+ .stack_size = 1024U,
+ .attr_bits = osThreadJoinable,
+ .tz_module = 1,
+ .priority = osPriorityHigh
+};
+
+/**
+ * \brief Mutex id, NS lock
+ */
+static osMutexId_t mutex_id;
+
+/**
+ * \brief Mutex properties, NS lock
+ */
+static const osMutexAttr_t mattr_ns_lock = {
+ .name = "ns_lock",
+ //.attr_bits = osMutexPrioInherit
+};
+
+/**
+ * \brief SVC dispatcher
+ */
+__attribute__((always_inline)) __STATIC_INLINE void svc_dispatch(enum tfm_svc_num svc_num)
+{
+ switch (svc_num) {
+ case SVC_SECURE_DECREMENT_NS_LOCK_1:
+ SVC(SVC_SECURE_DECREMENT_NS_LOCK_1);
+ break;
+ case SVC_SECURE_DECREMENT_NS_LOCK_2:
+ SVC(SVC_SECURE_DECREMENT_NS_LOCK_2);
+ break;
+ default:
+ break;
+ }
+}
+
+/**
+ * \brief tfm_service_request
+ *
+ * \details This function is used to request a TFM
+ * service in handler mode, using SVC.
+ * Optionally uses the NS lock
+ */
+static void tfm_service_request(enum tfm_svc_num svc_num, bool use_ns_lock)
+{
+ osStatus_t result;
+
+ char buffer[80];
+
+#define LOG_MSG_THREAD(MSG_THREAD) \
+ do { \
+ sprintf(buffer,"%s [%s]", MSG_THREAD, osThreadGetName(osThreadGetId())); \
+ LOG_MSG(buffer); \
+ } \
+ while(0)
+
+ LOG_MSG_THREAD("Trying to acquire the TFM core from NS");
+
+ if (use_ns_lock) {
+ result = osMutexAcquire(mutex_id,0);
+ if (result == osOK) {
+ LOG_MSG_THREAD("NS Lock: acquired");
+ svc_dispatch(svc_num);
+ LOG_MSG_THREAD("NS Lock: releasing...");
+ osMutexRelease(mutex_id);
+ }
+ else {
+ LOG_MSG_THREAD("Failed to acquire the NS lock");
+
+ osMutexAcquire(mutex_id,osWaitForever);
+ LOG_MSG_THREAD("NS Lock: acquired");
+ svc_dispatch(svc_num);
+ LOG_MSG_THREAD("NS Lock: releasing...");
+ osMutexRelease(mutex_id);
+ }
+ }
+ else {
+ svc_dispatch(svc_num);
+ }
+}
+
+/**
+ * \brief Non-blocking test thread
+ *
+ */
+__attribute__((noreturn))
+static void mid_task(void *argument)
+{
+ osThreadId_t thread_id_pri;
+ osThreadState_t thread_pri_state;
+ uint32_t idx;
+
+ thread_id_pri = *((osThreadId_t *)argument);
+
+ /* go to sleep */
+ osDelay(100U);
+
+ thread_pri_state = osThreadGetState(thread_id_pri);
+
+ if (thread_pri_state == osThreadBlocked) {
+ LOG_MSG("Running [mid_task] while [pri_task] is blocked");
+ }
+ else if (thread_pri_state == osThreadTerminated) {
+ LOG_MSG("Running [mid_task] while [pri_task] is terminated");
+ }
+ else {
+ LOG_MSG("Running [mid_task]");
+ }
+
+ /* Do non TFM related, non blocking, operations */
+ for (idx=0; idx<0x3ffffff; idx++) {
+ }
+
+ LOG_MSG("Exiting [mid_task]");
+
+ osThreadExit();
+}
+
+/**
+ * \brief Priority test thread
+ *
+ */
+__attribute__((noreturn))
+static void pri_task(void *argument)
+{
+ /* go to sleep */
+ osDelay(100U);
+
+ /* After wake up, try to get hold of the NS lock */
+ tfm_service_request(SVC_SECURE_DECREMENT_NS_LOCK_2, *((bool *)argument));
+
+ osThreadExit();
+}
+
+/**
+ * \brief Sequential test thread
+ *
+ */
+__attribute__((noreturn))
+static void seq_task(void *argument)
+{
+ osThreadId_t thread_id, thread_id_mid;
+ bool use_ns_lock, use_ns_lock_pri;
+ enum test_type test_type;
+
+ test_type = *((enum test_type *)argument);
+
+ if (test_type == TEST_TYPE_1) {
+ LOG_MSG("Scenario 1 - Sequential");
+ use_ns_lock = true;
+ }
+ else if (test_type == TEST_TYPE_2) {
+ LOG_MSG("Scenario 2 - Priority");
+ use_ns_lock = true;
+ use_ns_lock_pri = true;
+ thread_id = osThreadNew(pri_task, &use_ns_lock_pri, &tattr_pri);
+ }
+ else if (test_type == TEST_TYPE_3) {
+ LOG_MSG("Scenario 3 - Priority inversion");
+ use_ns_lock = true;
+ use_ns_lock_pri = true;
+ thread_id = osThreadNew(pri_task, &use_ns_lock_pri, &tattr_pri);
+ thread_id_mid = osThreadNew(mid_task, &thread_id, &tattr_mid);
+ }
+ else if (test_type == TEST_TYPE_4) {
+ LOG_MSG("Scenario 4 - non-NS lock");
+ use_ns_lock = false;
+ }
+ else if (test_type == TEST_TYPE_5) {
+ LOG_MSG("Scenario 5 - non-NS lock, core locked");
+ use_ns_lock = true;
+ use_ns_lock_pri = false;
+ thread_id = osThreadNew(pri_task, &use_ns_lock_pri, &tattr_pri);
+ }
+ else {
+ LOG_MSG("Scenario not supported");
+ osThreadExit();
+ }
+
+ /* Try to acquire the NS lock */
+ tfm_service_request(SVC_SECURE_DECREMENT_NS_LOCK_1, use_ns_lock);
+
+ if (test_type == TEST_TYPE_1) {
+ LOG_MSG("Scenario 1 - test finished\n");
+ }
+ else if (test_type == TEST_TYPE_2) {
+ osThreadJoin(thread_id);
+ LOG_MSG("Scenario 2 - test finished\n");
+ }
+ else if (test_type == TEST_TYPE_3) {
+ osThreadJoin(thread_id);
+ osThreadJoin(thread_id_mid);
+ LOG_MSG("Scenario 3 - test finished\n");
+ }
+ else if (test_type == TEST_TYPE_4) {
+ LOG_MSG("Scenario 4 - test finished\n");
+ }
+ else if (test_type == TEST_TYPE_5) {
+ osThreadJoin(thread_id);
+ LOG_MSG("Scenario 5 - test finished\n");
+ }
+
+ osThreadExit();
+}
+
+/**
+ * \brief Execute the interactive tets cases
+ *
+ */
+void execute_ns_interactive_tests(void)
+{
+ uint8_t idx;
+
+ osThreadId_t thread_id;
+
+ /* Test type list */
+ enum test_type test_type[] = {TEST_TYPE_1, TEST_TYPE_2, TEST_TYPE_3, TEST_TYPE_4, TEST_TYPE_5};
+
+ /* Create the NS lock -- shared among testing scenarios */
+ mutex_id = osMutexNew(&mattr_ns_lock);
+
+ /* Loop in the test list */
+ for (idx=0; idx<sizeof(test_type); idx++) {
+ /* Spawn the main thread */
+ thread_id = osThreadNew(seq_task, &test_type[idx], &tattr_seq);
+
+ /* Wait for it to finish before moving to the next scenario */
+ osThreadJoin(thread_id);
+ }
+}
+#endif /* CORE_TEST_INTERACTIVE */
+
+#ifdef TEST_FRAMEWORK_NS
+/**
+ * \brief Services test thread
+ *
+ */
+__attribute__((noreturn))
+void test_app(void *argument)
+{
+ UNUSED_VARIABLE(argument);
+ start_integ_test();
+ /* End of test */
+ for (;;) {
+ }
+}
+#endif /* TEST_FRAMEWORK_NS */
diff --git a/app/tfm_integ_test.h b/app/tfm_integ_test.h
new file mode 100644
index 0000000..5be104b
--- /dev/null
+++ b/app/tfm_integ_test.h
@@ -0,0 +1,73 @@
+/*
+ * Copyright (c) 2017, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
+ */
+
+#include <stdio.h>
+#include <cmsis_compiler.h>
+
+#ifndef __TFM_INTEG_TEST_H__
+#define __TFM_INTEG_TEST_H__
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* Avoids the semihosting issue */
+#if defined (__ARMCC_VERSION) && (__ARMCC_VERSION >= 6010050)
+__asm(" .global __ARM_use_no_argv\n");
+#endif
+
+/**
+ * \brief Simple macro to mark UNUSED variables
+ *
+ */
+#define UNUSED_VARIABLE(X) ((void)(X))
+
+/**
+ * \brief Declarations for User defined SVC functions
+ * used in CORE_TEST_INTERACTIVE or
+ * CORE_TEST_POSITIVE
+ *
+ */
+void svc_secure_decrement_ns_lock_1(void);
+void svc_secure_decrement_ns_lock_2(void);
+
+#ifdef TEST_FRAMEWORK_NS
+/**
+ * \brief Main test application for the RTX-TFM core
+ * integration tests
+ *
+ */
+void test_app(void *argument);
+#endif /* TEST_FRAMEWORK_NS */
+
+/**
+ * \brief Execute the interactive test cases (button push)
+ *
+ */
+void execute_ns_interactive_tests(void);
+
+/**
+ * \brief Logging function
+ *
+ */
+__attribute__((always_inline)) __STATIC_INLINE void LOG_MSG(const char *MSG)
+{
+#ifndef LOG_MSG_HANDLER_MODE_PRINTF_ENABLED
+ /* if IPSR is non-zero, exception is active. NOT banked S/NS */
+ if (!__get_IPSR()) {
+ printf("\t\e[1;32m[Non-Sec] %s\e[0m\r\n", MSG);
+ }
+#else
+ printf("\t\e[1;32m[Non-Sec] %s\e[0m\r\n", MSG);
+#endif
+}
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __TFM_INTEG_TEST_H__ */