/* * Copyright (c) 2018 Intel Corporation * * SPDX-License-Identifier: Apache-2.0 */ #include #include #include #define STACKSIZE (256 + CONFIG_TEST_EXTRA_STACKSIZE) #if defined(CONFIG_USERSPACE) && defined(CONFIG_DYNAMIC_OBJECTS) static K_THREAD_STACK_DEFINE(dyn_thread_stack, STACKSIZE); static K_SEM_DEFINE(start_sem, 0, 1); static K_SEM_DEFINE(end_sem, 0, 1); static void dyn_thread_entry(void *p1, void *p2, void *p3) { k_sem_take(&start_sem, K_FOREVER); k_sem_give(&end_sem); } static void prep(void) { k_thread_access_grant(k_current_get(), dyn_thread_stack, &start_sem, &end_sem, NULL); } static void create_dynamic_thread(void) { struct k_thread *dyn_thread; k_tid_t tid; dyn_thread = k_object_alloc(K_OBJ_THREAD); zassert_not_null(dyn_thread, "Cannot allocate thread k_object!"); tid = k_thread_create(dyn_thread, dyn_thread_stack, STACKSIZE, dyn_thread_entry, NULL, NULL, NULL, K_PRIO_PREEMPT(0), K_USER, 0); k_object_access_grant(&start_sem, tid); k_object_access_grant(&end_sem, tid); k_sem_give(&start_sem); zassert_true(k_sem_take(&end_sem, K_SECONDS(1)) == 0, "k_sem_take(end_sem) failed"); k_thread_abort(tid); k_object_release(dyn_thread); } static void permission_test(void) { struct k_thread *dyn_thread; k_tid_t tid; dyn_thread = k_object_alloc(K_OBJ_THREAD); zassert_not_null(dyn_thread, "Cannot allocate thread k_object!"); tid = k_thread_create(dyn_thread, dyn_thread_stack, STACKSIZE, dyn_thread_entry, NULL, NULL, NULL, K_PRIO_PREEMPT(0), K_USER, 0); k_object_access_grant(&start_sem, tid); /* * Notice dyn_thread will not have permission to access * end_sem, which will cause kernel oops. */ k_sem_give(&start_sem); /* * If dyn_thread has permission to access end_sem, * k_sem_take() would be able to take the semaphore. */ zassert_true(k_sem_take(&end_sem, K_SECONDS(1)) != 0, "Semaphore end_sem has incorrect permission"); k_thread_abort(tid); k_object_release(dyn_thread); } /** * @ingroup kernel_thread_tests * @brief Test object permission on dynamic user thread when index is reused * * @details This creates one dynamic thread with permissions to both * semaphores so there is no fault. Then a new thread is created and will be * re-using the thread index in first pass. Except the second thread does * not have permission to one of the semaphore. If permissions are cleared * correctly when thread is destroyed, the second should raise kernel oops. */ static void test_dyn_thread_perms(void) { permission_test(); TC_PRINT("===== must have access denied on k_sem %p\n", &end_sem); } #else /* (CONFIG_USERSPACE && CONFIG_DYNAMIC_OBJECTS) */ static void prep(void) { } static void create_dynamic_thread(void) { TC_PRINT("Test skipped. Userspace and dynamic objects required.\n"); ztest_test_skip(); } static void test_dyn_thread_perms(void) { TC_PRINT("Test skipped. Userspace and dynamic objects required.\n"); ztest_test_skip(); } #endif /* !(CONFIG_USERSPACE && CONFIG_DYNAMIC_OBJECTS) */ /** * @ingroup kernel_thread_tests * @brief Test creation of dynamic user thread under kernel thread * * @details This is a simple test to create a user thread * dynamically via k_object_alloc() under a kernel thread. */ static void test_kernel_create_dyn_user_thread(void) { create_dynamic_thread(); } /** * @ingroup kernel_thread_tests * @brief Test creation of dynamic user thread under user thread * * @details This is a simple test to create a user thread * dynamically via k_object_alloc() under a user thread. */ static void test_user_create_dyn_user_thread(void) { create_dynamic_thread(); } /* test case main entry */ void test_main(void) { k_thread_system_pool_assign(k_current_get()); prep(); ztest_test_suite(thread_dynamic, ztest_unit_test(test_kernel_create_dyn_user_thread), ztest_user_unit_test(test_user_create_dyn_user_thread), ztest_unit_test(test_dyn_thread_perms) ); ztest_run_test_suite(thread_dynamic); }