aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--interface/include/psa_manifest/sid.h6
-rw-r--r--secure_fw/services/tfm_service_list.inc20
-rw-r--r--test/suites/multi_core/non_secure/multi_core_ns_interface_testsuite.c237
-rw-r--r--test/test_services/tfm_multi_core_test/psa_manifest/tfm_multi_core_test.h3
-rw-r--r--test/test_services/tfm_multi_core_test/tfm_multi_core_test.c58
-rw-r--r--test/test_services/tfm_multi_core_test/tfm_multi_core_test.yaml12
6 files changed, 320 insertions, 16 deletions
diff --git a/interface/include/psa_manifest/sid.h b/interface/include/psa_manifest/sid.h
index 4b66a3e9b1..6ee681b833 100644
--- a/interface/include/psa_manifest/sid.h
+++ b/interface/include/psa_manifest/sid.h
@@ -137,8 +137,10 @@ extern "C" {
#define TFM_SECURE_CLIENT_2_VERSION (1U)
/******** TFM_SP_MULTI_CORE_TEST ********/
-#define MULTI_CORE_TEST_DUMMY_SID (0x0000F100U)
-#define MULTI_CORE_TEST_DUMMY_VERSION (1U)
+#define MULTI_CORE_MULTI_CLIENT_CALL_TEST_0_SID (0x0000F100U)
+#define MULTI_CORE_MULTI_CLIENT_CALL_TEST_0_VERSION (1U)
+#define MULTI_CORE_MULTI_CLIENT_CALL_TEST_1_SID (0x0000F101U)
+#define MULTI_CORE_MULTI_CLIENT_CALL_TEST_1_VERSION (1U)
#ifdef __cplusplus
}
diff --git a/secure_fw/services/tfm_service_list.inc b/secure_fw/services/tfm_service_list.inc
index e3bc1a3e84..539dada747 100644
--- a/secure_fw/services/tfm_service_list.inc
+++ b/secure_fw/services/tfm_service_list.inc
@@ -515,14 +515,23 @@ const struct tfm_spm_service_db_t service_db[] =
#ifdef TFM_MULTI_CORE_TEST
/******** TFM_SP_MULTI_CORE_TEST ********/
{
- .name = "MULTI_CORE_TEST_DUMMY",
+ .name = "MULTI_CORE_MULTI_CLIENT_CALL_TEST_0",
.partition_id = TFM_SP_MULTI_CORE_TEST,
- .signal = MULTI_CORE_TEST_DUMMY_SIGNAL,
+ .signal = MULTI_CORE_MULTI_CLIENT_CALL_TEST_0_SIGNAL,
.sid = 0x0000F100,
.non_secure_client = true,
.version = 1,
.version_policy = TFM_VERSION_POLICY_STRICT
},
+ {
+ .name = "MULTI_CORE_MULTI_CLIENT_CALL_TEST_1",
+ .partition_id = TFM_SP_MULTI_CORE_TEST,
+ .signal = MULTI_CORE_MULTI_CLIENT_CALL_TEST_1_SIGNAL,
+ .sid = 0x0000F101,
+ .non_secure_client = true,
+ .version = 1,
+ .version_policy = TFM_VERSION_POLICY_STRICT
+ },
#endif /* TFM_MULTI_CORE_TEST */
};
@@ -929,6 +938,13 @@ struct tfm_spm_service_t service[] =
.msg_queue = {0},
.list = {0},
},
+ {
+ .service_db = NULL,
+ .partition = NULL,
+ .handle_list = {0},
+ .msg_queue = {0},
+ .list = {0},
+ },
#endif /* TFM_MULTI_CORE_TEST */
};
diff --git a/test/suites/multi_core/non_secure/multi_core_ns_interface_testsuite.c b/test/suites/multi_core/non_secure/multi_core_ns_interface_testsuite.c
index 38929c83e8..14ab0d4c69 100644
--- a/test/suites/multi_core/non_secure/multi_core_ns_interface_testsuite.c
+++ b/test/suites/multi_core/non_secure/multi_core_ns_interface_testsuite.c
@@ -5,16 +5,62 @@
*
*/
+#include <stdbool.h>
+#include <stdint.h>
+#include "os_wrapper/mutex.h"
+#include "os_wrapper/thread.h"
#include "psa/client.h"
#include "psa_manifest/sid.h"
#include "test/framework/test_framework_helpers.h"
+#include "tfm_ns_mailbox.h"
+
+/* Max number of child threads for multiple outstanding PSA client call test */
+#define NR_MULTI_CALL_CHILD (NUM_MAILBOX_QUEUE_SLOT * 2)
+
+/* The event flag to sync up between parent thread and child threads */
+#define TEST_CHILD_EVENT_FLAG(x) (uint32_t)(0x1UL << (x))
+
+/* Max number of test rounds */
+#define MAX_NR_LIGHT_TEST_ROUND 0x200
+
+/* Default stack size for child thread */
+#define MULTI_CALL_LIGHT_TEST_STACK_SIZE 0x200
+
+/* Structure passed to test threads */
+struct test_params {
+ void *parent_handle; /* The thread handle of parent thread */
+ uint32_t child_idx; /* The index of current child thread */
+ uint32_t nr_rounds; /* The number of test rounds */
+ void *mutex_handle; /* Mutex to protect is_complete flag */
+ enum test_status_t ret; /* The test result */
+ bool is_complete; /* Whether current test thread completes */
+ bool is_parent; /* Whether executed in parent thread */
+};
+
+/* Multiple outstanding PSA client call test secure service SID and version */
+struct multi_call_service_info {
+ uint32_t sid;
+ uint32_t version;
+};
+
+/*
+ * If not enough secure services are defined for multiple outstanding PSA
+ * client call test, the definitions below will trigger compiling error.
+ */
+const static struct multi_call_service_info multi_call_service_list[] = {
+ {MULTI_CORE_MULTI_CLIENT_CALL_TEST_0_SID,
+ MULTI_CORE_MULTI_CLIENT_CALL_TEST_0_VERSION},
+ {MULTI_CORE_MULTI_CLIENT_CALL_TEST_1_SID,
+ MULTI_CORE_MULTI_CLIENT_CALL_TEST_1_VERSION}
+};
/* List of tests */
-static void tfm_multi_core_dummy_test(struct test_result_t *ret);
+static void multi_client_call_light_test(struct test_result_t *ret);
static struct test_t multi_core_tests[] = {
- {&tfm_multi_core_dummy_test, "TFM_MULTI_CORE_TEST_DUMMY_TEST",
- "A dummy test in multi-core test service", {0}},
+ {&multi_client_call_light_test,
+ "MULTI_CLIENT_CALL_LIGHT_TEST",
+ "Multiple outstanding NS PSA client calls lightweight test", {0}},
};
void register_testsuite_multi_core_ns_interface(
@@ -28,12 +74,187 @@ void register_testsuite_multi_core_ns_interface(
multi_core_tests, list_size, p_test_suite);
}
-/**
- * \brief A dummy test case. It will be replaced by actual test cases.
- */
-static void tfm_multi_core_dummy_test(struct test_result_t *ret)
+static void wait_child_thread_completion(struct test_params *params_array,
+ uint8_t child_idx)
+{
+ bool is_complete;
+ uint8_t i;
+ void *mutex = params_array[0].mutex_handle;
+
+ for (i = 0; i < child_idx; i++) {
+ while (1) {
+ os_wrapper_mutex_acquire(mutex, OS_WRAPPER_WAIT_FOREVER);
+ is_complete = params_array[i].is_complete;
+ os_wrapper_mutex_release(mutex);
+
+ if (is_complete) {
+ break;
+ }
+ }
+ }
+}
+
+static void multi_client_call_test(struct test_result_t *ret,
+ os_wrapper_thread_func test_runner,
+ int32_t stack_size,
+ int32_t nr_rounds)
{
- TEST_LOG("A fake test and of course it succeeds\r\n");
+ uint8_t i, nr_child;
+ void *current_thread_handle;
+ uint32_t current_thread_priority, err;
+ void *mutex_handle;
+ void *child_ids[NR_MULTI_CALL_CHILD];
+ struct test_params parent_params, params[NR_MULTI_CALL_CHILD];
+
+ current_thread_handle = os_wrapper_thread_get_handle();
+ if (!current_thread_handle) {
+ TEST_FAIL("Failed to get current thread ID\r\n");
+ return;
+ }
+
+ err = os_wrapper_thread_get_priority(current_thread_handle,
+ &current_thread_priority);
+ if (err == OS_WRAPPER_ERROR) {
+ TEST_FAIL("Failed to get current thread priority\r\n");
+ return;
+ }
+
+ /*
+ * Create a mutex to protect the synchronization between child test thread
+ * about the completion status.
+ * The best way is to use os_wrapper_thread_wait/set_flag(). However, due to
+ * the implementation of the wait event functions in some RTOS, if the
+ * child test threads already exit before the main thread starts to wait for
+ * event (main thread itself has to perform test too), the main thread
+ * cannot receive the event flags.
+ * As a result, use a flag and a mutex to make sure the main thread can
+ * capture the completion event of child threads.
+ */
+ mutex_handle = os_wrapper_mutex_create();
+ if (!mutex_handle) {
+ TEST_FAIL("Failed to create a mutex\r\n");
+ return;
+ }
+
+ /* Create test threads one by one */
+ for (i = 0; i < NR_MULTI_CALL_CHILD; i++) {
+ params[i].parent_handle = current_thread_handle;
+ params[i].child_idx = i;
+ params[i].nr_rounds = nr_rounds;
+ params[i].mutex_handle = mutex_handle;
+ params[i].is_complete = false;
+ params[i].is_parent = false;
+
+ child_ids[i] = os_wrapper_thread_new(NULL,
+ stack_size,
+ test_runner,
+ &params[i],
+ current_thread_priority);
+ if (!child_ids[i]) {
+ break;
+ }
+ }
+
+ nr_child = i;
+ TEST_LOG("Totally %d threads for test start\r\n", nr_child + 1);
+ TEST_LOG("Each thread run 0x%x rounds tests\r\n", nr_rounds);
+
+ /*
+ * Activate test threads one by one.
+ * Try to make test threads to run together.
+ */
+ for (i = 0; i < nr_child; i++) {
+ os_wrapper_thread_set_flag(child_ids[i], TEST_CHILD_EVENT_FLAG(i));
+ }
+
+ /* Use current thread to execute a test instance */
+ parent_params.child_idx = nr_child;
+ parent_params.nr_rounds = nr_rounds;
+ parent_params.is_parent = true;
+ test_runner(&parent_params);
+
+ /* Wait for all the test threads completes */
+ wait_child_thread_completion(params, nr_child);
+
+ os_wrapper_mutex_delete(mutex_handle);
+
+ if (parent_params.ret != TEST_PASSED) {
+ ret->val = TEST_FAILED;
+ return;
+ }
+
+ /* Check the test result of each child thread */
+ for (i = 0; i < nr_child; i++) {
+ if (params[i].ret != TEST_PASSED) {
+ ret->val = TEST_FAILED;
+ return;
+ }
+ }
ret->val = TEST_PASSED;
}
+
+static inline enum test_status_t multi_client_call_light_loop(uint8_t child_idx,
+ uint32_t nr_rounds)
+{
+ psa_handle_t handle;
+ psa_status_t status;
+ uint32_t i, nr_calls, nr_service, sid, version;
+ struct psa_outvec outvec = {&nr_calls, sizeof(nr_calls)};
+
+ nr_service = sizeof(multi_call_service_list) /
+ sizeof(multi_call_service_list[0]);
+ /* Determine the secure service ID and version */
+ sid = multi_call_service_list[child_idx % nr_service].sid;
+ version = multi_call_service_list[child_idx % nr_service].version;
+
+ for (i = 0; i < nr_rounds; i++) {
+ handle = psa_connect(sid, version);
+ if (handle <= 0) {
+ TEST_LOG("Fail to connect test service!\r\n");
+ return TEST_FAILED;
+ }
+
+ status = psa_call(handle, PSA_IPC_CALL, NULL, 0, &outvec, 1);
+ if (status < 0) {
+ TEST_LOG("Fail to call test service\r\n");
+ return TEST_FAILED;
+ }
+
+ psa_close(handle);
+ }
+
+ return TEST_PASSED;
+}
+
+static void multi_client_call_light_runner(void *argument)
+{
+ struct test_params *params = (struct test_params *)argument;
+
+ if (!params->is_parent) {
+ /* Wait for the signal to kick-off the test */
+ os_wrapper_thread_wait_flag(TEST_CHILD_EVENT_FLAG(params->child_idx),
+ OS_WRAPPER_WAIT_FOREVER);
+ }
+
+ params->ret = multi_client_call_light_loop(params->child_idx,
+ params->nr_rounds);
+
+ if (!params->is_parent) {
+ /* Mark this child thread has completed */
+ os_wrapper_mutex_acquire(params->mutex_handle, OS_WRAPPER_WAIT_FOREVER);
+ params->is_complete = true;
+ os_wrapper_mutex_release(params->mutex_handle);
+ }
+}
+
+/**
+ * \brief Lightweight test case to verify multiple outstanding PSA client calls
+ * feature.
+ */
+static void multi_client_call_light_test(struct test_result_t *ret)
+{
+ multi_client_call_test(ret, multi_client_call_light_runner,
+ MULTI_CALL_LIGHT_TEST_STACK_SIZE,
+ MAX_NR_LIGHT_TEST_ROUND);
+}
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
index a4b9cb24db..1692715f42 100644
--- 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
@@ -14,7 +14,8 @@
extern "C" {
#endif
-#define MULTI_CORE_TEST_DUMMY_SIGNAL (1U << (0 + 4))
+#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
}
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
index 9d371fcb9e..fe2238ee2f 100644
--- 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
@@ -9,10 +9,66 @@
#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;
- /* Do nothing */
+ 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
index 3d2df093bd..43142f4afa 100644
--- 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
@@ -17,9 +17,17 @@
],
"services" : [
{
- "name": "MULTI_CORE_TEST_DUMMY",
+ "name": "MULTI_CORE_MULTI_CLIENT_CALL_TEST_0",
"sid": "0x0000F100",
- "signal": "MULTI_CORE_TEST_DUMMY_SIGNAL",
+ "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"