diff options
Diffstat (limited to 'cpukit/include/rtems/score/tls.h')
-rw-r--r-- | cpukit/include/rtems/score/tls.h | 315 |
1 files changed, 152 insertions, 163 deletions
diff --git a/cpukit/include/rtems/score/tls.h b/cpukit/include/rtems/score/tls.h index 7725a003ca..8716c5230c 100644 --- a/cpukit/include/rtems/score/tls.h +++ b/cpukit/include/rtems/score/tls.h @@ -1,3 +1,5 @@ +/* SPDX-License-Identifier: BSD-2-Clause */ + /** * @file * @@ -8,23 +10,34 @@ */ /* - * Copyright (c) 2014 embedded brains GmbH. All rights reserved. + * Copyright (C) 2014, 2023 embedded brains GmbH & Co. KG * - * embedded brains GmbH - * Dornierstr. 4 - * 82178 Puchheim - * Germany - * <rtems@embedded-brains.de> + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. * - * The license and distribution terms for this file may be - * found in the file LICENSE in this distribution or at - * http://www.rtems.org/license/LICENSE. + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. */ #ifndef _RTEMS_SCORE_TLS_H #define _RTEMS_SCORE_TLS_H -#include <rtems/score/cpu.h> +#include <rtems/score/cpuimpl.h> #include <string.h> @@ -46,31 +59,51 @@ extern "C" { * @{ */ -extern char _TLS_Data_begin[]; - -extern char _TLS_Data_end[]; +/** + * @brief Represents the TLS configuration. + */ +typedef struct { + /** + * @brief This member is initialized to _TLS_Data_begin. + */ + const char *data_begin; -extern char _TLS_Data_size[]; + /** + * @brief This member is initialized to _TLS_Data_size. + */ + const char *data_size; -extern char _TLS_BSS_begin[]; + /** + * @brief This member is initialized to _TLS_BSS_begin. + */ + const char *bss_begin; -extern char _TLS_BSS_end[]; + /** + * @brief This member is initialized to _TLS_BSS_size. + */ + const char *bss_size; -extern char _TLS_BSS_size[]; + /** + * @brief This member is initialized to _TLS_Size. + */ + const char *size; -extern char _TLS_Size[]; + /** + * @brief This member is initialized to _TLS_Alignment. + */ + const char *alignment; +} TLS_Configuration; /** - * @brief The TLS section alignment. + * @brief Provides the TLS configuration. * - * This symbol is provided by the linker command file as the maximum alignment - * of the .tdata and .tbss sections. The linker ensures that the first TLS - * output section is aligned to the maximum alignment of all TLS output - * sections, see function _bfd_elf_tls_setup() in bfd/elflink.c of the GNU - * Binutils sources. The linker command file must take into account the case - * that the .tdata section is empty and the .tbss section is non-empty. + * Directly using symbols with an arbitrary absolute address such as + * _TLS_Alignment may not work with all code models (for example the AArch64 + * tiny and small code models). Store the addresses in a read-only object. + * Using the volatile qualifier ensures that the compiler actually loads the + * address from the object. */ -extern char _TLS_Alignment[]; +extern const volatile TLS_Configuration _TLS_Configuration; typedef struct { /* @@ -103,101 +136,71 @@ typedef struct { } TLS_Index; /** - * @brief Gets the TLS size. - * - * @return The TLS size. - */ -static inline uintptr_t _TLS_Get_size( void ) -{ - uintptr_t size; - - /* - * We must be careful with using _TLS_Size here since this could lead GCC to - * assume that this symbol is not 0 and the tests for 0 will be optimized - * away. - */ - size = (uintptr_t) _TLS_Size; - RTEMS_OBFUSCATE_VARIABLE( size ); - return size; -} - -/** - * @brief Returns the value aligned up to the stack alignment. - * - * @param val The value to align. - * - * @return The value aligned to the stack alignment. - */ -static inline uintptr_t _TLS_Align_up( uintptr_t val ) -{ - uintptr_t alignment = CPU_STACK_ALIGNMENT; - - return RTEMS_ALIGN_UP( val, alignment ); -} - -/** - * @brief Returns the size of the thread control block area size for this - * alignment, or the minimum size if alignment is too small. + * @brief Gets the size of the thread control block area in bytes. * - * @param alignment The alignment for the operation. + * @param config is the TLS configuration. * - * @return The size of the thread control block area. + * @return Returns the size of the thread control block area in bytes. */ static inline uintptr_t _TLS_Get_thread_control_block_area_size( - uintptr_t alignment + const volatile TLS_Configuration *config ) { - return alignment <= sizeof(TLS_Thread_control_block) ? - sizeof(TLS_Thread_control_block) : alignment; +#if CPU_THREAD_LOCAL_STORAGE_VARIANT == 11 + uintptr_t alignment; + + alignment = (uintptr_t) config->alignment; + + return RTEMS_ALIGN_UP( sizeof( TLS_Thread_control_block ), alignment ); +#else + (void) config; + return sizeof( TLS_Thread_control_block ); +#endif } /** - * @brief Return the TLS area allocation size. + * @brief Gets the allocation size of the thread-local storage area in bytes. * - * @return The TLS area allocation size. + * @return Returns the allocation size of the thread-local storage area in + * bytes. */ uintptr_t _TLS_Get_allocation_size( void ); /** - * @brief Copies TLS size bytes from the address tls_area and returns a pointer - * to the start of the area after clearing it. + * @brief Initializes the thread-local storage data. * - * @param tls_area The starting address of the area to clear. + * @param config is the TLS configuration. * - * @return The pointer to the beginning of the cleared section. + * @param[out] tls_data is the thread-local storage data to initialize. */ -static inline void *_TLS_Copy_and_clear( void *tls_area ) +static inline void _TLS_Copy_and_clear( + const volatile TLS_Configuration *config, + void *tls_data +) { - tls_area = memcpy( - tls_area, - _TLS_Data_begin, - (size_t) ((uintptr_t)_TLS_Data_size) - ); - + tls_data = + memcpy( tls_data, config->data_begin, (uintptr_t) config->data_size ); memset( - (char *) tls_area + (size_t)((intptr_t) _TLS_BSS_begin) - - (size_t)((intptr_t) _TLS_Data_begin), + (char *) tls_data + + (uintptr_t) config->bss_begin - (uintptr_t) config->data_begin, 0, - ((size_t) (intptr_t)_TLS_BSS_size) + (uintptr_t) config->bss_size ); - - return tls_area; } /** - * @brief Initializes the dynamic thread vector. + * @brief Initializes the thread control block and the dynamic thread vector. * - * @param tls_block The tls block for @a dtv. - * @param tcb The thread control block for @a dtv. - * @param[out] dtv The dynamic thread vector to initialize. + * @param tls_data is the thread-local storage data address. * - * @return Pointer to an area that was copied and cleared from tls_block - * onwards (@see _TLS_Copy_and_clear). + * @param[out] tcb is the thread control block to initialize. + * + * @param[out] dtv is the dynamic thread vector to initialize. */ -static inline void *_TLS_Initialize( - void *tls_block, - TLS_Thread_control_block *tcb, +static inline void _TLS_Initialize_TCB_and_DTV( + void *tls_data, + TLS_Thread_control_block *tcb, TLS_Dynamic_thread_vector *dtv ) { @@ -207,86 +210,72 @@ static inline void *_TLS_Initialize( #else tcb->dtv = dtv; dtv->generation_number = 1; - dtv->tls_blocks[0] = tls_block; + dtv->tls_blocks[0] = tls_data; #endif - - return _TLS_Copy_and_clear( tls_block ); } /** - * @brief Initializes a dynamic thread vector beginning at the given starting - * address. + * @brief Initializes the thread-local storage area. * - * Use Variant I, TLS offsets emitted by linker takes the TCB into account. + * @param tls_area[out] is the thread-local storage area to initialize. * - * @param tls_area The tls area for the initialization. - * - * @return Pointer to an area that was copied and cleared from tls_block - * onwards (@see _TLS_Copy_and_clear). + * @return Where the architectures uses Variant I and the TLS offsets emitted + * by the linker neglect the TCB, returns the address of the thread-local + * storage data. Otherwise, returns the address of the thread control block. */ -static inline void *_TLS_TCB_at_area_begin_initialize( void *tls_area ) +static inline void *_TLS_Initialize_area( void *tls_area ) { - void *tls_block = (char *) tls_area - + _TLS_Get_thread_control_block_area_size( (uintptr_t) _TLS_Alignment ); - TLS_Thread_control_block *tcb = tls_area; - uintptr_t aligned_size = _TLS_Align_up( (uintptr_t) _TLS_Size ); - TLS_Dynamic_thread_vector *dtv = (TLS_Dynamic_thread_vector *) - ((char *) tls_block + aligned_size); - - return _TLS_Initialize( tls_block, tcb, dtv ); -} + const volatile TLS_Configuration *config; + uintptr_t alignment; + void *tls_data; + TLS_Thread_control_block *tcb; + TLS_Dynamic_thread_vector *dtv; + void *return_value; +#if CPU_THREAD_LOCAL_STORAGE_VARIANT == 11 + uintptr_t tcb_size; +#endif +#if CPU_THREAD_LOCAL_STORAGE_VARIANT == 20 + uintptr_t size; + uintptr_t alignment_2; +#endif -/** - * @brief Initializes a dynamic thread vector with the area before a given - * starting address as thread control block. - * - * Use Variant I, TLS offsets emitted by linker neglects the TCB. - * - * @param tls_area The tls area for the initialization. - * - * @return Pointer to an area that was copied and cleared from tls_block - * onwards (@see _TLS_Copy_and_clear). - */ -static inline void *_TLS_TCB_before_TLS_block_initialize( void *tls_area ) -{ - void *tls_block = (char *) tls_area - + _TLS_Get_thread_control_block_area_size( (uintptr_t) _TLS_Alignment ); - TLS_Thread_control_block *tcb = (TLS_Thread_control_block *) - ((char *) tls_block - sizeof(*tcb)); - uintptr_t aligned_size = _TLS_Align_up( (uintptr_t) _TLS_Size ); - TLS_Dynamic_thread_vector *dtv = (TLS_Dynamic_thread_vector *) - ((char *) tls_block + aligned_size); - - return _TLS_Initialize( tls_block, tcb, dtv ); -} + config = &_TLS_Configuration; + alignment = (uintptr_t) config->alignment; -/** - * @brief Initializes a dynamic thread vector with the area after a given - * starting address as thread control block. - * - * Use Variant II - * - * @param tls_area The tls area for the initialization. - * - * @return Pointer to an area that was copied and cleared from tls_block - * onwards (@see _TLS_Copy_and_clear). - */ -static inline void *_TLS_TCB_after_TLS_block_initialize( void *tls_area ) -{ - uintptr_t size = (uintptr_t) _TLS_Size; - uintptr_t tls_align = (uintptr_t) _TLS_Alignment; - uintptr_t tls_mask = tls_align - 1; - uintptr_t heap_align = _TLS_Align_up( tls_align ); - uintptr_t heap_mask = heap_align - 1; - TLS_Thread_control_block *tcb = (TLS_Thread_control_block *) - ((char *) tls_area + ((size + heap_mask) & ~heap_mask)); - void *tls_block = (char *) tcb - ((size + tls_mask) & ~tls_mask); - TLS_Dynamic_thread_vector *dtv = (TLS_Dynamic_thread_vector *) - ((char *) tcb + sizeof(*tcb)); - - _TLS_Initialize( tls_block, tcb, dtv ); - - return tcb; +#ifdef __i386__ + dtv = NULL; +#else + dtv = (TLS_Dynamic_thread_vector *) tls_area; + tls_area = (char *) tls_area + sizeof( *dtv ); +#endif + +#if CPU_THREAD_LOCAL_STORAGE_VARIANT == 10 + tls_data = (void *) + RTEMS_ALIGN_UP( (uintptr_t) tls_area + sizeof( *tcb ), alignment ); + tcb = (TLS_Thread_control_block *) ((char *) tls_data - sizeof( *tcb )); + return_value = tls_data; +#elif CPU_THREAD_LOCAL_STORAGE_VARIANT == 11 + tcb_size = RTEMS_ALIGN_UP( sizeof( *tcb ), alignment ); + tls_data = (void *) + RTEMS_ALIGN_UP( (uintptr_t) tls_area + tcb_size, alignment ); + tcb = (TLS_Thread_control_block *) ((char *) tls_data - tcb_size); + return_value = tcb; +#elif CPU_THREAD_LOCAL_STORAGE_VARIANT == 20 + alignment_2 = RTEMS_ALIGN_UP( alignment, CPU_SIZEOF_POINTER ); + tls_area = (void *) RTEMS_ALIGN_UP( (uintptr_t) tls_area, alignment_2 ); + size = (uintptr_t) config->size; + tcb = (TLS_Thread_control_block *) + ((char *) tls_area + RTEMS_ALIGN_UP( size, alignment_2 )); + tls_data = (char *) tcb - RTEMS_ALIGN_UP( size, alignment ); + return_value = tcb; +#else +#error "unexpected CPU_THREAD_LOCAL_STORAGE_VARIANT value" +#endif + + _TLS_Initialize_TCB_and_DTV( tls_data, tcb, dtv ); + _TLS_Copy_and_clear( config, tls_data ); + + return return_value; } /** @} */ |