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: #9067 Signed-off-by: Daniel Leung <daniel.leung@intel.com>
This commit is contained in:
parent
a5f7e3345b
commit
fc182430c0
5 changed files with 54 additions and 10 deletions
|
@ -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) {
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue