Skip to content

Commit fc18243

Browse files
dcpleungnashif
authored andcommitted
kernel: userspace: reserve stack space to store local data
This enables reserving little space on the top of stack to store data local to thread when CONFIG_USERSPACE. The first customer of this is errno. Note that ARC, due to how it lays out the user stack and privilege stack, sets the pointer itself rather than relying on the common way. Fixes: zephyrproject-rtos#9067 Signed-off-by: Daniel Leung <[email protected]>
1 parent a5f7e33 commit fc18243

File tree

5 files changed

+54
-10
lines changed

5 files changed

+54
-10
lines changed

arch/arc/core/thread.c

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -71,6 +71,7 @@ void _new_thread(struct k_thread *thread, k_thread_stack_t *stack,
7171
_ASSERT_VALID_PRIO(priority, pEntry);
7272

7373
char *stackEnd;
74+
char *stackAdjEnd;
7475
struct init_stack_frame *pInitCtx;
7576

7677
#if CONFIG_USERSPACE
@@ -101,8 +102,18 @@ void _new_thread(struct k_thread *thread, k_thread_stack_t *stack,
101102
#endif
102103
_new_thread_init(thread, pStackMem, stackSize, priority, options);
103104

105+
stackAdjEnd = stackEnd;
106+
107+
#ifdef CONFIG_THREAD_USERSPACE_LOCAL_DATA
108+
/* reserve stack space for the userspace local data struct */
109+
stackAdjEnd = (char *)STACK_ROUND_DOWN(stackEnd
110+
- sizeof(*thread->userspace_local_data));
111+
thread->userspace_local_data =
112+
(struct _thread_userspace_local_data *)stackAdjEnd;
113+
#endif
114+
104115
/* carve the thread entry struct from the "base" of the stack */
105-
pInitCtx = (struct init_stack_frame *)(STACK_ROUND_DOWN(stackEnd) -
116+
pInitCtx = (struct init_stack_frame *)(STACK_ROUND_DOWN(stackAdjEnd) -
106117
sizeof(struct init_stack_frame));
107118
#if CONFIG_USERSPACE
108119
if (options & K_USER) {

include/kernel.h

Lines changed: 11 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -503,6 +503,12 @@ struct _mem_domain_info {
503503

504504
#endif /* CONFIG_USERSPACE */
505505

506+
#ifdef CONFIG_THREAD_USERSPACE_LOCAL_DATA
507+
struct _thread_userspace_local_data {
508+
int errno_var;
509+
};
510+
#endif
511+
506512
/**
507513
* @ingroup thread_apis
508514
* Thread Structure
@@ -538,14 +544,12 @@ struct k_thread {
538544
void *custom_data;
539545
#endif
540546

547+
#ifdef CONFIG_THREAD_USERSPACE_LOCAL_DATA
548+
struct _thread_userspace_local_data *userspace_local_data;
549+
#endif
550+
541551
#ifdef CONFIG_ERRNO
542-
#ifdef CONFIG_USERSPACE
543-
/* Set to the lowest area in the thread stack since this needs to
544-
* be directly read/writable by user mode. Not ideal, but best we
545-
* can do until we have thread-local storage
546-
*/
547-
int *errno_location;
548-
#else
552+
#ifndef CONFIG_USERSPACE
549553
/** per-thread errno variable */
550554
int errno_var;
551555
#endif

kernel/Kconfig

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -164,9 +164,19 @@ config THREAD_CUSTOM_DATA
164164
This option allows each thread to store 32 bits of custom data,
165165
which can be accessed using the k_thread_custom_data_xxx() APIs.
166166

167+
config THREAD_USERSPACE_LOCAL_DATA
168+
bool
169+
depends on USERSPACE
170+
171+
config THREAD_USERSPACE_LOCAL_DATA_ARCH_DEFER_SETUP
172+
bool
173+
depends on THREAD_USERSPACE_LOCAL_DATA
174+
default y if ARCH="arc"
175+
167176
config ERRNO
168177
bool "Enable errno support"
169178
default y
179+
select THREAD_USERSPACE_LOCAL_DATA if USERSPACE
170180
help
171181
Enable per-thread errno in the kernel. Application and library code must
172182
include errno.h provided by the C library (libc) to use the errno

kernel/errno.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@ int *_impl_z_errno(void)
2929
/* Initialized to the lowest address in the stack so the thread can
3030
* directly read/write it
3131
*/
32-
return _current->errno_location;
32+
return &_current->userspace_local_data->errno_var;
3333
}
3434

3535
Z_SYSCALL_HANDLER0_SIMPLE(z_errno);

kernel/thread.c

Lines changed: 20 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -294,8 +294,28 @@ void _setup_new_thread(struct k_thread *new_thread,
294294
{
295295
stack_size = adjust_stack_size(stack_size);
296296

297+
#ifdef CONFIG_THREAD_USERSPACE_LOCAL_DATA
298+
#ifndef CONFIG_THREAD_USERSPACE_LOCAL_DATA_ARCH_DEFER_SETUP
299+
/* reserve space on top of stack for local data */
300+
stack_size = STACK_ROUND_DOWN(stack_size
301+
- sizeof(*new_thread->userspace_local_data));
302+
#endif
303+
#endif
304+
297305
_new_thread(new_thread, stack, stack_size, entry, p1, p2, p3,
298306
prio, options);
307+
308+
#ifdef CONFIG_THREAD_USERSPACE_LOCAL_DATA
309+
#ifndef CONFIG_THREAD_USERSPACE_LOCAL_DATA_ARCH_DEFER_SETUP
310+
/* don't set again if the arch's own code in _new_thread() has
311+
* already set the pointer.
312+
*/
313+
new_thread->userspace_local_data =
314+
(struct _thread_userspace_local_data *)
315+
(K_THREAD_STACK_BUFFER(stack) + stack_size);
316+
#endif
317+
#endif
318+
299319
#ifdef CONFIG_THREAD_MONITOR
300320
new_thread->entry.pEntry = entry;
301321
new_thread->entry.parameter1 = p1;
@@ -312,7 +332,6 @@ void _setup_new_thread(struct k_thread *new_thread,
312332
_k_object_init(new_thread);
313333
_k_object_init(stack);
314334
new_thread->stack_obj = stack;
315-
new_thread->errno_location = (int *)K_THREAD_STACK_BUFFER(stack);
316335

317336
/* Any given thread has access to itself */
318337
k_object_access_grant(new_thread, new_thread);

0 commit comments

Comments
 (0)