xtensa: add support for thread local storage
Adds the necessary bits to initialize TLS in the stack area and sets up CPU registers during context switch. Note that this does not enable TLS for all Xtensa SoC. This is because Xtensa SoCs are highly configurable so that each SoC can be considered a whole architecture. So TLS needs to be enabled on the SoC level, instead of at the arch level. Signed-off-by: Daniel Leung <daniel.leung@intel.com>
This commit is contained in:
parent
8a79ce1428
commit
f8a909dad1
8 changed files with 88 additions and 6 deletions
|
@ -16,5 +16,6 @@ zephyr_library_sources(
|
|||
zephyr_library_sources_ifndef(CONFIG_ATOMIC_OPERATIONS_C atomic.S)
|
||||
zephyr_library_sources_ifdef(CONFIG_XTENSA_USE_CORE_CRT1 crt1.S)
|
||||
zephyr_library_sources_ifdef(CONFIG_IRQ_OFFLOAD irq_offload.c)
|
||||
zephyr_library_sources_ifdef(CONFIG_THREAD_LOCAL_STORAGE tls.c)
|
||||
|
||||
add_subdirectory(startup)
|
||||
|
|
47
arch/xtensa/core/tls.c
Normal file
47
arch/xtensa/core/tls.c
Normal file
|
@ -0,0 +1,47 @@
|
|||
/*
|
||||
* Copyright (c) 2020 Intel Corporation
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#include <kernel.h>
|
||||
#include <kernel_structs.h>
|
||||
#include <kernel_internal.h>
|
||||
#include <kernel_tls.h>
|
||||
#include <app_memory/app_memdomain.h>
|
||||
#include <sys/util.h>
|
||||
|
||||
#if XCHAL_HAVE_THREADPTR == 0
|
||||
#error SoC does not support THREADPTR for thread local storage.
|
||||
#endif
|
||||
|
||||
size_t arch_tls_stack_setup(struct k_thread *new_thread, char *stack_ptr)
|
||||
{
|
||||
/*
|
||||
* TLS area has some data fields following by
|
||||
* thread data and bss. These fields are supposed to be
|
||||
* used by toolchain and OS TLS code to aid in locating
|
||||
* the TLS data/bss. Zephyr currently has no use for
|
||||
* this so we can simply skip these. However, since GCC
|
||||
* is generating code assuming these fields are there,
|
||||
* we simply skip them when setting the TLS pointer.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Since we are populating things backwards,
|
||||
* setup the TLS data/bss area first.
|
||||
*/
|
||||
stack_ptr -= z_tls_data_size();
|
||||
z_tls_copy(stack_ptr);
|
||||
|
||||
/* Skip two pointers due to toolchain */
|
||||
stack_ptr -= sizeof(uintptr_t) * 2;
|
||||
|
||||
/*
|
||||
* Set thread TLS pointer which is used in
|
||||
* context switch to point to TLS area.
|
||||
*/
|
||||
new_thread->tls = POINTER_TO_UINT(stack_ptr);
|
||||
|
||||
return (z_tls_data_size() + (sizeof(uintptr_t) * 2));
|
||||
}
|
|
@ -167,6 +167,10 @@ _restore_context:
|
|||
#if XCHAL_HAVE_S32C1I
|
||||
l32i a0, a1, BSA_SCOMPARE1_OFF
|
||||
wsr.SCOMPARE1 a0
|
||||
#endif
|
||||
#if XCHAL_HAVE_THREADPTR && defined(CONFIG_THREAD_LOCAL_STORAGE)
|
||||
l32i a0, a1, BSA_THREADPTR_OFF
|
||||
wur.THREADPTR a0
|
||||
#endif
|
||||
rsync
|
||||
|
||||
|
|
|
@ -15,7 +15,7 @@
|
|||
|
||||
LOG_MODULE_DECLARE(os);
|
||||
|
||||
void *xtensa_init_stack(int *stack_top,
|
||||
void *xtensa_init_stack(struct k_thread *thread, int *stack_top,
|
||||
void (*entry)(void *, void *, void *),
|
||||
void *arg1, void *arg2, void *arg3)
|
||||
{
|
||||
|
@ -34,6 +34,10 @@ void *xtensa_init_stack(int *stack_top,
|
|||
bsa[BSA_PC_OFF/4] = z_thread_entry;
|
||||
bsa[BSA_PS_OFF/4] = (void *)(PS_WOE | PS_UM | PS_CALLINC(1));
|
||||
|
||||
#if XCHAL_HAVE_THREADPTR && defined(CONFIG_THREAD_LOCAL_STORAGE)
|
||||
bsa[BSA_THREADPTR_OFF/4] = UINT_TO_POINTER(thread->tls);
|
||||
#endif
|
||||
|
||||
/* Arguments to z_thread_entry(). Remember these start at A6,
|
||||
* which will be rotated into A2 by the ENTRY instruction that
|
||||
* begins the C function. And A4-A7 and A8-A11 are optional
|
||||
|
@ -65,7 +69,8 @@ void arch_new_thread(struct k_thread *thread, k_thread_stack_t *stack,
|
|||
char *stack_ptr, k_thread_entry_t entry,
|
||||
void *p1, void *p2, void *p3)
|
||||
{
|
||||
thread->switch_handle = xtensa_init_stack((int *)stack_ptr, entry,
|
||||
thread->switch_handle = xtensa_init_stack(thread,
|
||||
(int *)stack_ptr, entry,
|
||||
p1, p2, p3);
|
||||
}
|
||||
|
||||
|
|
|
@ -78,10 +78,17 @@
|
|||
#define BASE_SAVE_AREA_SIZE_SCOMPARE 0
|
||||
#endif
|
||||
|
||||
#if XCHAL_HAVE_THREADPTR && defined(CONFIG_THREAD_LOCAL_STORAGE)
|
||||
#define BASE_SAVE_AREA_SIZE_THREADPTR 4
|
||||
#else
|
||||
#define BASE_SAVE_AREA_SIZE_THREADPTR 0
|
||||
#endif
|
||||
|
||||
#define BASE_SAVE_AREA_SIZE \
|
||||
(BASE_SAVE_AREA_SIZE_COMMON + \
|
||||
BASE_SAVE_AREA_SIZE_LOOPS + \
|
||||
BASE_SAVE_AREA_SIZE_SCOMPARE)
|
||||
BASE_SAVE_AREA_SIZE_SCOMPARE + \
|
||||
BASE_SAVE_AREA_SIZE_THREADPTR)
|
||||
|
||||
#define BSA_A3_OFF (BASE_SAVE_AREA_SIZE - 20)
|
||||
#define BSA_A2_OFF (BASE_SAVE_AREA_SIZE - 24)
|
||||
|
@ -94,9 +101,21 @@
|
|||
#define BSA_LEND_OFF (BASE_SAVE_AREA_SIZE - 52)
|
||||
#define BSA_LCOUNT_OFF (BASE_SAVE_AREA_SIZE - 56)
|
||||
|
||||
#if XCHAL_HAVE_S32C1I
|
||||
#define BSA_SCOMPARE1_OFF \
|
||||
(BASE_SAVE_AREA_SIZE - \
|
||||
(BASE_SAVE_AREA_SIZE_COMMON + \
|
||||
BASE_SAVE_AREA_SIZE_LOOPS + 4))
|
||||
BASE_SAVE_AREA_SIZE_LOOPS + \
|
||||
BASE_SAVE_AREA_SIZE_SCOMPARE))
|
||||
#endif
|
||||
|
||||
#if XCHAL_HAVE_THREADPTR && defined(CONFIG_THREAD_LOCAL_STORAGE)
|
||||
#define BSA_THREADPTR_OFF \
|
||||
(BASE_SAVE_AREA_SIZE - \
|
||||
(BASE_SAVE_AREA_SIZE_COMMON + \
|
||||
BASE_SAVE_AREA_SIZE_LOOPS + \
|
||||
BASE_SAVE_AREA_SIZE_SCOMPARE + \
|
||||
BASE_SAVE_AREA_SIZE_THREADPTR))
|
||||
#endif
|
||||
|
||||
#endif /* ZEPHYR_ARCH_XTENSA_INCLUDE_XTENSA_ASM2_CONTEXT_H_ */
|
||||
|
|
|
@ -114,6 +114,10 @@
|
|||
rsr.SCOMPARE1 a0
|
||||
s32i a0, a1, BSA_SCOMPARE1_OFF
|
||||
#endif
|
||||
#if XCHAL_HAVE_THREADPTR && defined(CONFIG_THREAD_LOCAL_STORAGE)
|
||||
rur.THREADPTR a0
|
||||
s32i a0, a1, BSA_THREADPTR_OFF
|
||||
#endif
|
||||
.endm
|
||||
|
||||
/*
|
||||
|
|
|
@ -6,6 +6,7 @@
|
|||
#ifndef ZEPHYR_ARCH_XTENSA_INCLUDE_XTENSA_ASM2_H_
|
||||
#define ZEPHYR_ARCH_XTENSA_INCLUDE_XTENSA_ASM2_H_
|
||||
|
||||
#include <kernel_structs.h>
|
||||
#include "xtensa-asm2-context.h"
|
||||
|
||||
/**
|
||||
|
@ -16,7 +17,7 @@
|
|||
* INTLEVEL set to zero (i.e. it's a user thread, we don't start with
|
||||
* anything masked, so don't assume that!).
|
||||
*/
|
||||
void *xtensa_init_stack(int *stack_top,
|
||||
void *xtensa_init_stack(struct k_thread *thread, int *stack_top,
|
||||
void (*entry)(void *, void *, void *),
|
||||
void *arg1, void *arg2, void *arg3);
|
||||
|
||||
|
|
|
@ -260,7 +260,8 @@ int test_switch(void)
|
|||
|
||||
(void)memset(stack2, 0, sizeof(stack2));
|
||||
|
||||
int *sp = xtensa_init_stack(&stack2[ARRAY_SIZE(stack2)],
|
||||
int *sp = xtensa_init_stack(k_current_get(),
|
||||
&stack2[ARRAY_SIZE(stack2)],
|
||||
(void *)test_switch_bounce,
|
||||
0, 0, 0);
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue