aboutsummaryrefslogtreecommitdiff
path: root/test
diff options
context:
space:
mode:
authorDavid Hu <david.hu@arm.com>2019-10-21 17:46:49 +0800
committerDavid Hu <david.hu@arm.com>2020-02-20 09:10:30 +0800
commit74098b24feaf83680889a5d2c172142ee2283761 (patch)
tree153b7ccaf5df5c6f00c096b231df8b7b90fa285f /test
parent8b2d6ab08c2635fe5b07d11a8bebab6b8fad0d7c (diff)
downloadtrusted-firmware-m-74098b24feaf83680889a5d2c172142ee2283761.tar.gz
Test: Light test for multi-core multiple outstanding NS PSA Client calls
Create multiple threads in NS test to send PSA client call to lightweight SPE secure services simultaneously. Each child thread in NS test loops several rounds of psa_connect(), psa_call() and psa_close(), which are sent to multi-core test specific secure services. Add two multi-core topology specific lightweight test secure services to handle the PSA client calls from NS child threads. Each just returns the number of PSA client calls. Change-Id: Id235a3a32ef126d35903fb7ec1ee70120bfbb040 Signed-off-by: David Hu <david.hu@arm.com>
Diffstat (limited to 'test')
-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
4 files changed, 298 insertions, 12 deletions
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"