diff --git a/arch/Kconfig b/arch/Kconfig index eda8983e83e..673e5da2a53 100644 --- a/arch/Kconfig +++ b/arch/Kconfig @@ -21,6 +21,7 @@ config ARC select ARCH_IS_SET select HAS_DTS imply XIP + select ARCH_HAS_THREAD_LOCAL_STORAGE help ARC architecture diff --git a/arch/arc/CMakeLists.txt b/arch/arc/CMakeLists.txt index 8697bbe1659..8135d072f10 100644 --- a/arch/arc/CMakeLists.txt +++ b/arch/arc/CMakeLists.txt @@ -12,4 +12,8 @@ zephyr_cc_option(-fno-delete-null-pointer-checks) zephyr_cc_option_ifdef(CONFIG_ARC_USE_UNALIGNED_MEM_ACCESS -munaligned-access) +# Instruct compiler to use register R26 as thread pointer +# for thread local storage. +zephyr_cc_option_ifdef(CONFIG_THREAD_LOCAL_STORAGE -mtp-regno=26) + add_subdirectory(core) diff --git a/arch/arc/core/CMakeLists.txt b/arch/arc/core/CMakeLists.txt index 1651dfec11b..5518976f144 100644 --- a/arch/arc/core/CMakeLists.txt +++ b/arch/arc/core/CMakeLists.txt @@ -32,6 +32,8 @@ zephyr_library_sources_ifdef(CONFIG_USERSPACE userspace.S) zephyr_library_sources_ifdef(CONFIG_ARC_CONNECT arc_connect.c) zephyr_library_sources_ifdef(CONFIG_ARC_CONNECT arc_smp.c) +zephyr_library_sources_ifdef(CONFIG_THREAD_LOCAL_STORAGE tls.c) + add_subdirectory_ifdef(CONFIG_ARC_CORE_MPU mpu) add_subdirectory_ifdef(CONFIG_ARC_SECURE_FIRMWARE secureshield) diff --git a/arch/arc/core/thread.c b/arch/arc/core/thread.c index 7a7cdd194fa..5598607b962 100644 --- a/arch/arc/core/thread.c +++ b/arch/arc/core/thread.c @@ -108,6 +108,25 @@ static struct init_stack_frame *get_iframe(struct k_thread *thread, return Z_STACK_PTR_TO_FRAME(struct init_stack_frame, stack_ptr); } +/* + * Pre-populate values in the registers inside _callee_saved_stack struct + * so these registers have pre-defined values when new thread begins + * execution. For example, setting up the thread pointer for thread local + * storage here so the thread starts with thread pointer already set up. + */ +static inline void arch_setup_callee_saved_regs(struct k_thread *thread, + uintptr_t stack_ptr) +{ + _callee_saved_stack_t *regs = UINT_TO_POINTER(stack_ptr); + + ARG_UNUSED(regs); + +#ifdef CONFIG_THREAD_LOCAL_STORAGE + /* R26 is used for thread pointer */ + regs->r26 = thread->tls; +#endif +} + /* * The initial context is a basic stack frame that contains arguments for * z_thread_entry() return address, that points at z_thread_entry() @@ -164,6 +183,9 @@ void arch_new_thread(struct k_thread *thread, k_thread_stack_t *stack, thread->arch.relinquish_cause = _CAUSE_COOP; thread->callee_saved.sp = (uint32_t)iframe - ___callee_saved_stack_t_SIZEOF; + + arch_setup_callee_saved_regs(thread, thread->callee_saved.sp); + /* initial values in all other regs/k_thread entries are irrelevant */ } diff --git a/arch/arc/core/tls.c b/arch/arc/core/tls.c new file mode 100644 index 00000000000..4f2a9ed97a6 --- /dev/null +++ b/arch/arc/core/tls.c @@ -0,0 +1,42 @@ +/* + * Copyright (c) 2020 Intel Corporation + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include +#include +#include +#include + +size_t arch_tls_stack_setup(struct k_thread *new_thread, char *stack_ptr) +{ + /* + * TLS area for ARC 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/include/arch/arc/v2/linker.ld b/include/arch/arc/v2/linker.ld index 4b5ee28b27f..bbc16c6f05f 100644 --- a/include/arch/arc/v2/linker.ld +++ b/include/arch/arc/v2/linker.ld @@ -98,6 +98,7 @@ SECTIONS { _image_rodata_start = .; #include +#include SECTION_PROLOGUE(_RODATA_SECTION_NAME,,) { KEEP(*(.openocd_dbg)) @@ -220,5 +221,11 @@ SECTIONS { KEEP(*(.gnu.attributes)) } - /DISCARD/ : { *(.note.GNU-stack) } + /DISCARD/ : { + *(.note.GNU-stack) + *(.got.plt) + *(.igot.plt) + *(.got) + *(.igot) + } }