diff --git a/arch/xtensa/core/CMakeLists.txt b/arch/xtensa/core/CMakeLists.txt index 5fc828758ed..f8e62262610 100644 --- a/arch/xtensa/core/CMakeLists.txt +++ b/arch/xtensa/core/CMakeLists.txt @@ -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) diff --git a/arch/xtensa/core/tls.c b/arch/xtensa/core/tls.c new file mode 100644 index 00000000000..9f22cafad31 --- /dev/null +++ b/arch/xtensa/core/tls.c @@ -0,0 +1,47 @@ +/* + * Copyright (c) 2020 Intel Corporation + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include +#include +#include +#include +#include + +#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)); +} diff --git a/arch/xtensa/core/xtensa-asm2-util.S b/arch/xtensa/core/xtensa-asm2-util.S index 995861e2fa8..c6278dd5050 100644 --- a/arch/xtensa/core/xtensa-asm2-util.S +++ b/arch/xtensa/core/xtensa-asm2-util.S @@ -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 diff --git a/arch/xtensa/core/xtensa-asm2.c b/arch/xtensa/core/xtensa-asm2.c index 05b6b6c30e1..4045cb90c23 100644 --- a/arch/xtensa/core/xtensa-asm2.c +++ b/arch/xtensa/core/xtensa-asm2.c @@ -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); } diff --git a/arch/xtensa/include/xtensa-asm2-context.h b/arch/xtensa/include/xtensa-asm2-context.h index 620e256a916..1f21c03774a 100644 --- a/arch/xtensa/include/xtensa-asm2-context.h +++ b/arch/xtensa/include/xtensa-asm2-context.h @@ -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_ */ diff --git a/arch/xtensa/include/xtensa-asm2-s.h b/arch/xtensa/include/xtensa-asm2-s.h index 9f85e7d0cae..f7848814eac 100644 --- a/arch/xtensa/include/xtensa-asm2-s.h +++ b/arch/xtensa/include/xtensa-asm2-s.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 /* diff --git a/arch/xtensa/include/xtensa-asm2.h b/arch/xtensa/include/xtensa-asm2.h index a51f9f85243..6b4d928a3de 100644 --- a/arch/xtensa/include/xtensa-asm2.h +++ b/arch/xtensa/include/xtensa-asm2.h @@ -6,6 +6,7 @@ #ifndef ZEPHYR_ARCH_XTENSA_INCLUDE_XTENSA_ASM2_H_ #define ZEPHYR_ARCH_XTENSA_INCLUDE_XTENSA_ASM2_H_ +#include #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); diff --git a/tests/arch/xtensa_asm2/src/main.c b/tests/arch/xtensa_asm2/src/main.c index d30fcb68ce4..1df3ec1dc3f 100644 --- a/tests/arch/xtensa_asm2/src/main.c +++ b/tests/arch/xtensa_asm2/src/main.c @@ -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);