diff --git a/arch/arc/core/thread.c b/arch/arc/core/thread.c index 59f28181f63..bf7e31851ce 100644 --- a/arch/arc/core/thread.c +++ b/arch/arc/core/thread.c @@ -71,6 +71,7 @@ void _new_thread(struct k_thread *thread, k_thread_stack_t *stack, _ASSERT_VALID_PRIO(priority, pEntry); char *stackEnd; + char *stackAdjEnd; struct init_stack_frame *pInitCtx; #if CONFIG_USERSPACE @@ -101,8 +102,18 @@ void _new_thread(struct k_thread *thread, k_thread_stack_t *stack, #endif _new_thread_init(thread, pStackMem, stackSize, priority, options); + stackAdjEnd = stackEnd; + +#ifdef CONFIG_THREAD_USERSPACE_LOCAL_DATA + /* reserve stack space for the userspace local data struct */ + stackAdjEnd = (char *)STACK_ROUND_DOWN(stackEnd + - sizeof(*thread->userspace_local_data)); + thread->userspace_local_data = + (struct _thread_userspace_local_data *)stackAdjEnd; +#endif + /* carve the thread entry struct from the "base" of the stack */ - pInitCtx = (struct init_stack_frame *)(STACK_ROUND_DOWN(stackEnd) - + pInitCtx = (struct init_stack_frame *)(STACK_ROUND_DOWN(stackAdjEnd) - sizeof(struct init_stack_frame)); #if CONFIG_USERSPACE if (options & K_USER) { diff --git a/include/kernel.h b/include/kernel.h index 25c82aee51b..da8ed7243aa 100644 --- a/include/kernel.h +++ b/include/kernel.h @@ -503,6 +503,12 @@ struct _mem_domain_info { #endif /* CONFIG_USERSPACE */ +#ifdef CONFIG_THREAD_USERSPACE_LOCAL_DATA +struct _thread_userspace_local_data { + int errno_var; +}; +#endif + /** * @ingroup thread_apis * Thread Structure @@ -538,14 +544,12 @@ struct k_thread { void *custom_data; #endif +#ifdef CONFIG_THREAD_USERSPACE_LOCAL_DATA + struct _thread_userspace_local_data *userspace_local_data; +#endif + #ifdef CONFIG_ERRNO -#ifdef CONFIG_USERSPACE - /* Set to the lowest area in the thread stack since this needs to - * be directly read/writable by user mode. Not ideal, but best we - * can do until we have thread-local storage - */ - int *errno_location; -#else +#ifndef CONFIG_USERSPACE /** per-thread errno variable */ int errno_var; #endif diff --git a/kernel/Kconfig b/kernel/Kconfig index 498339adb25..ffc41a6ddc4 100644 --- a/kernel/Kconfig +++ b/kernel/Kconfig @@ -164,9 +164,19 @@ config THREAD_CUSTOM_DATA This option allows each thread to store 32 bits of custom data, which can be accessed using the k_thread_custom_data_xxx() APIs. +config THREAD_USERSPACE_LOCAL_DATA + bool + depends on USERSPACE + +config THREAD_USERSPACE_LOCAL_DATA_ARCH_DEFER_SETUP + bool + depends on THREAD_USERSPACE_LOCAL_DATA + default y if ARCH="arc" + config ERRNO bool "Enable errno support" default y + select THREAD_USERSPACE_LOCAL_DATA if USERSPACE help Enable per-thread errno in the kernel. Application and library code must include errno.h provided by the C library (libc) to use the errno diff --git a/kernel/errno.c b/kernel/errno.c index 43268ff8f54..070ec0ae35f 100644 --- a/kernel/errno.c +++ b/kernel/errno.c @@ -29,7 +29,7 @@ int *_impl_z_errno(void) /* Initialized to the lowest address in the stack so the thread can * directly read/write it */ - return _current->errno_location; + return &_current->userspace_local_data->errno_var; } Z_SYSCALL_HANDLER0_SIMPLE(z_errno); diff --git a/kernel/thread.c b/kernel/thread.c index 4e7c1ec30ba..78a8296f7ea 100644 --- a/kernel/thread.c +++ b/kernel/thread.c @@ -294,8 +294,28 @@ void _setup_new_thread(struct k_thread *new_thread, { stack_size = adjust_stack_size(stack_size); +#ifdef CONFIG_THREAD_USERSPACE_LOCAL_DATA +#ifndef CONFIG_THREAD_USERSPACE_LOCAL_DATA_ARCH_DEFER_SETUP + /* reserve space on top of stack for local data */ + stack_size = STACK_ROUND_DOWN(stack_size + - sizeof(*new_thread->userspace_local_data)); +#endif +#endif + _new_thread(new_thread, stack, stack_size, entry, p1, p2, p3, prio, options); + +#ifdef CONFIG_THREAD_USERSPACE_LOCAL_DATA +#ifndef CONFIG_THREAD_USERSPACE_LOCAL_DATA_ARCH_DEFER_SETUP + /* don't set again if the arch's own code in _new_thread() has + * already set the pointer. + */ + new_thread->userspace_local_data = + (struct _thread_userspace_local_data *) + (K_THREAD_STACK_BUFFER(stack) + stack_size); +#endif +#endif + #ifdef CONFIG_THREAD_MONITOR new_thread->entry.pEntry = entry; new_thread->entry.parameter1 = p1; @@ -312,7 +332,6 @@ void _setup_new_thread(struct k_thread *new_thread, _k_object_init(new_thread); _k_object_init(stack); new_thread->stack_obj = stack; - new_thread->errno_location = (int *)K_THREAD_STACK_BUFFER(stack); /* Any given thread has access to itself */ k_object_access_grant(new_thread, new_thread);