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/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 */