Skip to content

Commit 83ccc8e

Browse files
laurenmurphyx64carlescufi
authored andcommitted
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 <lauren.murphy@intel.com>
1 parent 83d879b commit 83ccc8e

File tree

4 files changed

+123
-10
lines changed

4 files changed

+123
-10
lines changed

tests/subsys/llext/simple/CMakeLists.txt

+1-1
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ target_include_directories(app PRIVATE
1717

1818
if(NOT LOADER_BUILD_ONLY)
1919
# generate extension targets foreach extension given by name
20-
foreach(ext_name hello_world logging relative_jump object syscalls)
20+
foreach(ext_name hello_world logging relative_jump object syscalls threads_kernel_objects)
2121
set(ext_src ${PROJECT_SOURCE_DIR}/src/${ext_name}_ext.c)
2222
set(ext_bin ${ZEPHYR_BINARY_DIR}/${ext_name}.llext)
2323
set(ext_inc ${ZEPHYR_BINARY_DIR}/include/generated/${ext_name}.inc)

tests/subsys/llext/simple/src/test_llext_simple.c

+60-9
Original file line numberDiff line numberDiff line change
@@ -7,11 +7,13 @@
77
#include <zephyr/ztest.h>
88
#include <zephyr/kernel.h>
99
#include <zephyr/llext/llext.h>
10+
#include <zephyr/llext/symbol.h>
1011
#include <zephyr/llext/buf_loader.h>
1112
#include <zephyr/logging/log.h>
1213
#include <zephyr/sys/libc-hooks.h>
13-
1414
#include "syscalls_ext.h"
15+
#include "threads_kernel_objects_ext.h"
16+
1517

1618
LOG_MODULE_REGISTER(test_llext_simple);
1719

@@ -28,8 +30,9 @@ struct llext_test {
2830
size_t buf_len;
2931

3032
LLEXT_CONST uint8_t *buf;
31-
};
3233

34+
void (*perm_setup)(struct k_thread *llext_thread);
35+
};
3336

3437

3538
K_THREAD_STACK_DEFINE(llext_stack, 1024);
@@ -45,6 +48,9 @@ void llext_entry(void *arg0, void *arg1, void *arg2)
4548
}
4649
#endif /* CONFIG_USERSPACE */
4750

51+
52+
/* syscalls test */
53+
4854
int z_impl_ext_syscall_ok(int a)
4955
{
5056
return a + 1;
@@ -58,6 +64,33 @@ static inline int z_vrfy_ext_syscall_ok(int a)
5864
#include <syscalls/ext_syscall_ok_mrsh.c>
5965
#endif /* CONFIG_USERSPACE */
6066

67+
68+
/* threads kernel objects test */
69+
70+
/* For these to be accessible from user space, they must be top-level globals
71+
* in the Zephyr image. Also, macros that add objects to special linker sections,
72+
* such as K_THREAD_STACK_DEFINE, do not work properly from extensions code.
73+
*/
74+
K_SEM_DEFINE(my_sem, 1, 1);
75+
EXPORT_SYMBOL(my_sem);
76+
struct k_thread my_thread;
77+
EXPORT_SYMBOL(my_thread);
78+
K_THREAD_STACK_DEFINE(my_thread_stack, MY_THREAD_STACK_SIZE);
79+
EXPORT_SYMBOL(my_thread_stack);
80+
81+
#ifdef CONFIG_USERSPACE
82+
/* Allow the user space test thread to access global objects */
83+
static void threads_objects_perm_setup(struct k_thread *llext_thread)
84+
{
85+
k_object_access_grant(&my_sem, llext_thread);
86+
k_object_access_grant(&my_thread, llext_thread);
87+
k_object_access_grant(&my_thread_stack, llext_thread);
88+
}
89+
#else
90+
/* No need to set up permissions for supervisor mode */
91+
#define threads_objects_perm_setup NULL
92+
#endif /* CONFIG_USERSPACE */
93+
6194
void load_call_unload(struct llext_test *test_case)
6295
{
6396
struct llext_buf_loader buf_loader =
@@ -108,6 +141,14 @@ void load_call_unload(struct llext_test *test_case)
108141

109142
k_mem_domain_add_thread(&domain, &llext_thread);
110143

144+
/* Even in supervisor mode, initialize permissions on objects used in
145+
* the test by this thread, so that user mode descendant threads can
146+
* inherit these permissions.
147+
*/
148+
if (test_case->perm_setup) {
149+
test_case->perm_setup(&llext_thread);
150+
}
151+
111152
k_thread_start(&llext_thread);
112153
k_thread_join(&llext_thread, K_FOREVER);
113154

@@ -123,11 +164,14 @@ void load_call_unload(struct llext_test *test_case)
123164

124165
k_mem_domain_add_thread(&domain, &llext_thread);
125166

167+
if (test_case->perm_setup) {
168+
test_case->perm_setup(&llext_thread);
169+
}
170+
126171
k_thread_start(&llext_thread);
127172
k_thread_join(&llext_thread, K_FOREVER);
128173
}
129174

130-
131175
#else /* CONFIG_USERSPACE */
132176
zassert_ok(llext_call_fn(ext, "test_entry"),
133177
"test_entry call should succeed");
@@ -143,43 +187,50 @@ void load_call_unload(struct llext_test *test_case)
143187
* unloading each extension which may itself excercise various APIs provided by
144188
* Zephyr.
145189
*/
146-
#define LLEXT_LOAD_UNLOAD(_name, _userspace) \
190+
#define LLEXT_LOAD_UNLOAD(_name, _userspace, _perm_setup) \
147191
ZTEST(llext, test_load_unload_##_name) \
148192
{ \
149193
struct llext_test test_case = { \
150194
.name = STRINGIFY(_name), \
151195
.try_userspace = _userspace, \
152196
.buf_len = ARRAY_SIZE(_name ## _ext), \
153197
.buf = _name ## _ext, \
198+
.perm_setup = _perm_setup, \
154199
}; \
155200
load_call_unload(&test_case); \
156201
}
157202
static LLEXT_CONST uint8_t hello_world_ext[] __aligned(4) = {
158203
#include "hello_world.inc"
159204
};
160-
LLEXT_LOAD_UNLOAD(hello_world, false)
205+
LLEXT_LOAD_UNLOAD(hello_world, false, NULL)
161206

162207
static LLEXT_CONST uint8_t logging_ext[] __aligned(4) = {
163208
#include "logging.inc"
164209
};
165-
LLEXT_LOAD_UNLOAD(logging, true)
210+
LLEXT_LOAD_UNLOAD(logging, true, NULL)
166211

167212
static LLEXT_CONST uint8_t relative_jump_ext[] __aligned(4) = {
168213
#include "relative_jump.inc"
169214
};
170-
LLEXT_LOAD_UNLOAD(relative_jump, true)
215+
LLEXT_LOAD_UNLOAD(relative_jump, true, NULL)
171216

172217
static LLEXT_CONST uint8_t object_ext[] __aligned(4) = {
173218
#include "object.inc"
174219
};
175-
LLEXT_LOAD_UNLOAD(object, true)
220+
LLEXT_LOAD_UNLOAD(object, true, NULL)
176221

177222
static LLEXT_CONST uint8_t syscalls_ext[] __aligned(4) = {
178223
#include "syscalls.inc"
179224
};
180-
LLEXT_LOAD_UNLOAD(syscalls, true)
225+
LLEXT_LOAD_UNLOAD(syscalls, true, NULL)
226+
227+
static LLEXT_CONST uint8_t threads_kernel_objects_ext[] __aligned(4) = {
228+
#include "threads_kernel_objects.inc"
229+
};
230+
LLEXT_LOAD_UNLOAD(threads_kernel_objects, true, threads_objects_perm_setup)
181231
#endif /* ! LOADER_BUILD_ONLY */
182232

233+
183234
/*
184235
* Ensure that EXPORT_SYMBOL does indeed provide a symbol and a valid address
185236
* to it.
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
/*
2+
* Copyright (c) 2023 Intel Corporation.
3+
*
4+
* SPDX-License-Identifier: Apache-2.0
5+
*/
6+
7+
/*
8+
* This code demonstrates the use of threads and requires object
9+
* relocation support.
10+
*/
11+
12+
#include <stdint.h>
13+
#include <zephyr/llext/symbol.h>
14+
#include <zephyr/kernel.h>
15+
#include "threads_kernel_objects_ext.h"
16+
17+
void test_thread(void *arg0, void *arg1, void *arg2)
18+
{
19+
printk("Take semaphore from test thread\n");
20+
k_sem_take(&my_sem, K_FOREVER);
21+
}
22+
23+
void test_entry(void)
24+
{
25+
printk("Give semaphore from main thread\n");
26+
k_sem_give(&my_sem);
27+
28+
printk("Creating thread\n");
29+
k_tid_t tid = k_thread_create(&my_thread, (k_thread_stack_t *) &my_thread_stack,
30+
MY_THREAD_STACK_SIZE, &test_thread, NULL, NULL, NULL,
31+
MY_THREAD_PRIO, MY_THREAD_OPTIONS, K_FOREVER);
32+
33+
printk("Starting thread\n");
34+
k_thread_start(tid);
35+
36+
printk("Joining thread\n");
37+
k_thread_join(&my_thread, K_FOREVER);
38+
printk("Test thread joined\n");
39+
}
40+
LL_EXTENSION_SYMBOL(test_entry);
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
/*
2+
* Copyright (c) 2024 Intel Corporation.
3+
*
4+
* SPDX-License-Identifier: Apache-2.0
5+
*/
6+
7+
#include <zephyr/llext/symbol.h>
8+
#include <zephyr/kernel.h>
9+
10+
extern struct k_thread my_thread;
11+
#define MY_THREAD_STACK_SIZE 1024
12+
extern struct z_thread_stack_element my_thread_stack[];
13+
14+
extern struct k_sem my_sem;
15+
16+
#ifdef CONFIG_USERSPACE
17+
#define MY_THREAD_PRIO 1
18+
#define MY_THREAD_OPTIONS (K_USER | K_INHERIT_PERMS)
19+
#else
20+
#define MY_THREAD_PRIO 0
21+
#define MY_THREAD_OPTIONS 0
22+
#endif

0 commit comments

Comments
 (0)