From 83ccc8e29b2d4f2252226d5484afb2da15b18688 Mon Sep 17 00:00:00 2001 From: Lauren Murphy Date: Mon, 11 Mar 2024 13:20:41 -0700 Subject: [PATCH] llext: add threads and kernel object test case Tests threads and kernel objects with userspace. Includes cleanups suggested by Luca Burelli. Signed-off-by: Lauren Murphy --- tests/subsys/llext/simple/CMakeLists.txt | 2 +- .../llext/simple/src/test_llext_simple.c | 69 ++++++++++++++++--- .../simple/src/threads_kernel_objects_ext.c | 40 +++++++++++ .../simple/src/threads_kernel_objects_ext.h | 22 ++++++ 4 files changed, 123 insertions(+), 10 deletions(-) create mode 100644 tests/subsys/llext/simple/src/threads_kernel_objects_ext.c create mode 100644 tests/subsys/llext/simple/src/threads_kernel_objects_ext.h diff --git a/tests/subsys/llext/simple/CMakeLists.txt b/tests/subsys/llext/simple/CMakeLists.txt index e2618136b0..f134a78c1f 100644 --- a/tests/subsys/llext/simple/CMakeLists.txt +++ b/tests/subsys/llext/simple/CMakeLists.txt @@ -17,7 +17,7 @@ target_include_directories(app PRIVATE if(NOT LOADER_BUILD_ONLY) # generate extension targets foreach extension given by name -foreach(ext_name hello_world logging relative_jump object syscalls) +foreach(ext_name hello_world logging relative_jump object syscalls threads_kernel_objects) set(ext_src ${PROJECT_SOURCE_DIR}/src/${ext_name}_ext.c) set(ext_bin ${ZEPHYR_BINARY_DIR}/${ext_name}.llext) set(ext_inc ${ZEPHYR_BINARY_DIR}/include/generated/${ext_name}.inc) diff --git a/tests/subsys/llext/simple/src/test_llext_simple.c b/tests/subsys/llext/simple/src/test_llext_simple.c index 33f4b694ba..90fadb68f1 100644 --- a/tests/subsys/llext/simple/src/test_llext_simple.c +++ b/tests/subsys/llext/simple/src/test_llext_simple.c @@ -7,11 +7,13 @@ #include #include #include +#include #include #include #include - #include "syscalls_ext.h" +#include "threads_kernel_objects_ext.h" + LOG_MODULE_REGISTER(test_llext_simple); @@ -28,8 +30,9 @@ struct llext_test { size_t buf_len; LLEXT_CONST uint8_t *buf; -}; + void (*perm_setup)(struct k_thread *llext_thread); +}; K_THREAD_STACK_DEFINE(llext_stack, 1024); @@ -45,6 +48,9 @@ void llext_entry(void *arg0, void *arg1, void *arg2) } #endif /* CONFIG_USERSPACE */ + +/* syscalls test */ + int z_impl_ext_syscall_ok(int a) { return a + 1; @@ -58,6 +64,33 @@ static inline int z_vrfy_ext_syscall_ok(int a) #include #endif /* CONFIG_USERSPACE */ + +/* threads kernel objects test */ + +/* For these to be accessible from user space, they must be top-level globals + * in the Zephyr image. Also, macros that add objects to special linker sections, + * such as K_THREAD_STACK_DEFINE, do not work properly from extensions code. + */ +K_SEM_DEFINE(my_sem, 1, 1); +EXPORT_SYMBOL(my_sem); +struct k_thread my_thread; +EXPORT_SYMBOL(my_thread); +K_THREAD_STACK_DEFINE(my_thread_stack, MY_THREAD_STACK_SIZE); +EXPORT_SYMBOL(my_thread_stack); + +#ifdef CONFIG_USERSPACE +/* Allow the user space test thread to access global objects */ +static void threads_objects_perm_setup(struct k_thread *llext_thread) +{ + k_object_access_grant(&my_sem, llext_thread); + k_object_access_grant(&my_thread, llext_thread); + k_object_access_grant(&my_thread_stack, llext_thread); +} +#else +/* No need to set up permissions for supervisor mode */ +#define threads_objects_perm_setup NULL +#endif /* CONFIG_USERSPACE */ + void load_call_unload(struct llext_test *test_case) { struct llext_buf_loader buf_loader = @@ -108,6 +141,14 @@ void load_call_unload(struct llext_test *test_case) k_mem_domain_add_thread(&domain, &llext_thread); + /* Even in supervisor mode, initialize permissions on objects used in + * the test by this thread, so that user mode descendant threads can + * inherit these permissions. + */ + if (test_case->perm_setup) { + test_case->perm_setup(&llext_thread); + } + k_thread_start(&llext_thread); k_thread_join(&llext_thread, K_FOREVER); @@ -123,11 +164,14 @@ void load_call_unload(struct llext_test *test_case) k_mem_domain_add_thread(&domain, &llext_thread); + if (test_case->perm_setup) { + test_case->perm_setup(&llext_thread); + } + k_thread_start(&llext_thread); k_thread_join(&llext_thread, K_FOREVER); } - #else /* CONFIG_USERSPACE */ zassert_ok(llext_call_fn(ext, "test_entry"), "test_entry call should succeed"); @@ -143,7 +187,7 @@ void load_call_unload(struct llext_test *test_case) * unloading each extension which may itself excercise various APIs provided by * Zephyr. */ -#define LLEXT_LOAD_UNLOAD(_name, _userspace) \ +#define LLEXT_LOAD_UNLOAD(_name, _userspace, _perm_setup) \ ZTEST(llext, test_load_unload_##_name) \ { \ struct llext_test test_case = { \ @@ -151,35 +195,42 @@ void load_call_unload(struct llext_test *test_case) .try_userspace = _userspace, \ .buf_len = ARRAY_SIZE(_name ## _ext), \ .buf = _name ## _ext, \ + .perm_setup = _perm_setup, \ }; \ load_call_unload(&test_case); \ } static LLEXT_CONST uint8_t hello_world_ext[] __aligned(4) = { #include "hello_world.inc" }; -LLEXT_LOAD_UNLOAD(hello_world, false) +LLEXT_LOAD_UNLOAD(hello_world, false, NULL) static LLEXT_CONST uint8_t logging_ext[] __aligned(4) = { #include "logging.inc" }; -LLEXT_LOAD_UNLOAD(logging, true) +LLEXT_LOAD_UNLOAD(logging, true, NULL) static LLEXT_CONST uint8_t relative_jump_ext[] __aligned(4) = { #include "relative_jump.inc" }; -LLEXT_LOAD_UNLOAD(relative_jump, true) +LLEXT_LOAD_UNLOAD(relative_jump, true, NULL) static LLEXT_CONST uint8_t object_ext[] __aligned(4) = { #include "object.inc" }; -LLEXT_LOAD_UNLOAD(object, true) +LLEXT_LOAD_UNLOAD(object, true, NULL) static LLEXT_CONST uint8_t syscalls_ext[] __aligned(4) = { #include "syscalls.inc" }; -LLEXT_LOAD_UNLOAD(syscalls, true) +LLEXT_LOAD_UNLOAD(syscalls, true, NULL) + +static LLEXT_CONST uint8_t threads_kernel_objects_ext[] __aligned(4) = { + #include "threads_kernel_objects.inc" +}; +LLEXT_LOAD_UNLOAD(threads_kernel_objects, true, threads_objects_perm_setup) #endif /* ! LOADER_BUILD_ONLY */ + /* * Ensure that EXPORT_SYMBOL does indeed provide a symbol and a valid address * to it. diff --git a/tests/subsys/llext/simple/src/threads_kernel_objects_ext.c b/tests/subsys/llext/simple/src/threads_kernel_objects_ext.c new file mode 100644 index 0000000000..21ca839efc --- /dev/null +++ b/tests/subsys/llext/simple/src/threads_kernel_objects_ext.c @@ -0,0 +1,40 @@ +/* + * Copyright (c) 2023 Intel Corporation. + * + * SPDX-License-Identifier: Apache-2.0 + */ + +/* + * This code demonstrates the use of threads and requires object + * relocation support. + */ + +#include +#include +#include +#include "threads_kernel_objects_ext.h" + +void test_thread(void *arg0, void *arg1, void *arg2) +{ + printk("Take semaphore from test thread\n"); + k_sem_take(&my_sem, K_FOREVER); +} + +void test_entry(void) +{ + printk("Give semaphore from main thread\n"); + k_sem_give(&my_sem); + + printk("Creating thread\n"); + k_tid_t tid = k_thread_create(&my_thread, (k_thread_stack_t *) &my_thread_stack, + MY_THREAD_STACK_SIZE, &test_thread, NULL, NULL, NULL, + MY_THREAD_PRIO, MY_THREAD_OPTIONS, K_FOREVER); + + printk("Starting thread\n"); + k_thread_start(tid); + + printk("Joining thread\n"); + k_thread_join(&my_thread, K_FOREVER); + printk("Test thread joined\n"); +} +LL_EXTENSION_SYMBOL(test_entry); diff --git a/tests/subsys/llext/simple/src/threads_kernel_objects_ext.h b/tests/subsys/llext/simple/src/threads_kernel_objects_ext.h new file mode 100644 index 0000000000..d14c7cc9e9 --- /dev/null +++ b/tests/subsys/llext/simple/src/threads_kernel_objects_ext.h @@ -0,0 +1,22 @@ +/* + * Copyright (c) 2024 Intel Corporation. + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include + +extern struct k_thread my_thread; +#define MY_THREAD_STACK_SIZE 1024 +extern struct z_thread_stack_element my_thread_stack[]; + +extern struct k_sem my_sem; + +#ifdef CONFIG_USERSPACE +#define MY_THREAD_PRIO 1 +#define MY_THREAD_OPTIONS (K_USER | K_INHERIT_PERMS) +#else +#define MY_THREAD_PRIO 0 +#define MY_THREAD_OPTIONS 0 +#endif