Skip to content

Commit

Permalink
llext: add threads and kernel object test case
Browse files Browse the repository at this point in the history
Tests threads and kernel objects with userspace. Includes cleanups
suggested by Luca Burelli.

Signed-off-by: Lauren Murphy <[email protected]>
  • Loading branch information
laurenmurphyx64 authored and carlescufi committed Apr 5, 2024
1 parent 83d879b commit 83ccc8e
Show file tree
Hide file tree
Showing 4 changed files with 123 additions and 10 deletions.
2 changes: 1 addition & 1 deletion tests/subsys/llext/simple/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down
69 changes: 60 additions & 9 deletions tests/subsys/llext/simple/src/test_llext_simple.c
Original file line number Diff line number Diff line change
Expand Up @@ -7,11 +7,13 @@
#include <zephyr/ztest.h>
#include <zephyr/kernel.h>
#include <zephyr/llext/llext.h>
#include <zephyr/llext/symbol.h>
#include <zephyr/llext/buf_loader.h>
#include <zephyr/logging/log.h>
#include <zephyr/sys/libc-hooks.h>

#include "syscalls_ext.h"
#include "threads_kernel_objects_ext.h"


LOG_MODULE_REGISTER(test_llext_simple);

Expand All @@ -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);
Expand All @@ -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;
Expand All @@ -58,6 +64,33 @@ static inline int z_vrfy_ext_syscall_ok(int a)
#include <syscalls/ext_syscall_ok_mrsh.c>
#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 =
Expand Down Expand Up @@ -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);

Expand All @@ -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");
Expand All @@ -143,43 +187,50 @@ 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 = { \
.name = STRINGIFY(_name), \
.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.
Expand Down
40 changes: 40 additions & 0 deletions tests/subsys/llext/simple/src/threads_kernel_objects_ext.c
Original file line number Diff line number Diff line change
@@ -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 <stdint.h>
#include <zephyr/llext/symbol.h>
#include <zephyr/kernel.h>
#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);
22 changes: 22 additions & 0 deletions tests/subsys/llext/simple/src/threads_kernel_objects_ext.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
/*
* Copyright (c) 2024 Intel Corporation.
*
* SPDX-License-Identifier: Apache-2.0
*/

#include <zephyr/llext/symbol.h>
#include <zephyr/kernel.h>

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

0 comments on commit 83ccc8e

Please sign in to comment.