From f8a909dad15ad117133f4f94ad3e43b588a4fc1d Mon Sep 17 00:00:00 2001 From: Daniel Leung Date: Fri, 2 Oct 2020 14:55:34 -0700 Subject: [PATCH] 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 --- arch/xtensa/core/CMakeLists.txt | 1 + arch/xtensa/core/tls.c | 47 +++++++++++++++++++++++ arch/xtensa/core/xtensa-asm2-util.S | 4 ++ arch/xtensa/core/xtensa-asm2.c | 9 ++++- arch/xtensa/include/xtensa-asm2-context.h | 23 ++++++++++- arch/xtensa/include/xtensa-asm2-s.h | 4 ++ arch/xtensa/include/xtensa-asm2.h | 3 +- tests/arch/xtensa_asm2/src/main.c | 3 +- 8 files changed, 88 insertions(+), 6 deletions(-) create mode 100644 arch/xtensa/core/tls.c 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);