Back to home page

LXR

 
 

    


File indexing completed on 2025-05-11 08:24:13

0001 /* SPDX-License-Identifier: BSD-2-Clause */
0002 
0003 /**
0004  * @file
0005  *
0006  * @ingroup RTEMSScoreTLS
0007  *
0008  * @brief This header file provides the interfaces of the
0009  *   @ref RTEMSScoreTLS.
0010  */
0011 
0012 /*
0013  * Copyright (C) 2014, 2023 embedded brains GmbH & Co. KG
0014  *
0015  * Redistribution and use in source and binary forms, with or without
0016  * modification, are permitted provided that the following conditions
0017  * are met:
0018  * 1. Redistributions of source code must retain the above copyright
0019  *    notice, this list of conditions and the following disclaimer.
0020  * 2. Redistributions in binary form must reproduce the above copyright
0021  *    notice, this list of conditions and the following disclaimer in the
0022  *    documentation and/or other materials provided with the distribution.
0023  *
0024  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
0025  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
0026  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
0027  * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
0028  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
0029  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
0030  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
0031  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
0032  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
0033  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
0034  * POSSIBILITY OF SUCH DAMAGE.
0035  */
0036 
0037 #ifndef _RTEMS_SCORE_TLS_H
0038 #define _RTEMS_SCORE_TLS_H
0039 
0040 #include <rtems/score/cpuimpl.h>
0041 
0042 #include <string.h>
0043 
0044 #ifdef __cplusplus
0045 extern "C" {
0046 #endif /* __cplusplus */
0047 
0048 /**
0049  * @defgroup RTEMSScoreTLS Thread-Local Storage (TLS)
0050  *
0051  * @ingroup RTEMSScore
0052  *
0053  * @brief This group contains the implementation to support thread-local
0054  *   storage (TLS).
0055  *
0056  * Variants I and II are according to Ulrich Drepper, "ELF Handling For
0057  * Thread-Local Storage".
0058  *
0059  * @{
0060  */
0061 
0062 /**
0063  * @brief Represents the TLS configuration.
0064  */
0065 typedef struct {
0066   /**
0067    * @brief This member is initialized to _TLS_Data_begin.
0068    */
0069   const char *data_begin;
0070 
0071   /**
0072    * @brief This member is initialized to _TLS_Data_size.
0073    */
0074   const char *data_size;
0075 
0076   /**
0077    * @brief This member is initialized to _TLS_BSS_begin.
0078    */
0079   const char *bss_begin;
0080 
0081   /**
0082    * @brief This member is initialized to _TLS_BSS_size.
0083    */
0084   const char *bss_size;
0085 
0086   /**
0087    * @brief This member is initialized to _TLS_Size.
0088    */
0089   const char *size;
0090 
0091   /**
0092    * @brief This member is initialized to _TLS_Alignment.
0093    */
0094   const char *alignment;
0095 } TLS_Configuration;
0096 
0097 /**
0098  * @brief Provides the TLS configuration.
0099  *
0100  * Directly using symbols with an arbitrary absolute address such as
0101  * _TLS_Alignment may not work with all code models (for example the AArch64
0102  * tiny and small code models).  Store the addresses in a read-only object.
0103  * Using the volatile qualifier ensures that the compiler actually loads the
0104  * address from the object.
0105  */
0106 extern const volatile TLS_Configuration _TLS_Configuration;
0107 
0108 typedef struct {
0109   /*
0110    * FIXME: Not sure if the generation number type is correct for all
0111    * architectures.
0112   */
0113   uint32_t generation_number;
0114 
0115   void *tls_blocks[1];
0116 } TLS_Dynamic_thread_vector;
0117 
0118 typedef struct TLS_Thread_control_block {
0119 #if defined(__i386__) || defined(__x86_64__)
0120   struct TLS_Thread_control_block *tcb;
0121 #else /* !(__i386__ || __x86_64__) */
0122   TLS_Dynamic_thread_vector *dtv;
0123 /*
0124  * GCC under AArch64/LP64 expects a 16 byte TCB at the beginning of the TLS
0125  * data segment and indexes into it accordingly for TLS variable addresses.
0126  */
0127 #if CPU_SIZEOF_POINTER == 4 || defined(AARCH64_MULTILIB_ARCH_V8)
0128   uintptr_t reserved;
0129 #endif
0130 #endif /* __i386__ || __x86_64__ */
0131 } TLS_Thread_control_block;
0132 
0133 typedef struct {
0134   uintptr_t module;
0135   uintptr_t offset;
0136 } TLS_Index;
0137 
0138 /**
0139  * @brief Gets the size of the thread control block area in bytes.
0140  *
0141  * @param config is the TLS configuration.
0142  *
0143  * @return Returns the size of the thread control block area in bytes.
0144  */
0145 static inline uintptr_t _TLS_Get_thread_control_block_area_size(
0146   const volatile TLS_Configuration *config
0147 )
0148 {
0149 #if CPU_THREAD_LOCAL_STORAGE_VARIANT == 11
0150   uintptr_t alignment;
0151 
0152   alignment = (uintptr_t) config->alignment;
0153 
0154   return RTEMS_ALIGN_UP( sizeof( TLS_Thread_control_block ), alignment );
0155 #else
0156   (void) config;
0157   return sizeof( TLS_Thread_control_block );
0158 #endif
0159 }
0160 
0161 /**
0162  * @brief Gets the allocation size of the thread-local storage area in bytes.
0163  *
0164  * @return Returns the allocation size of the thread-local storage area in
0165  *   bytes.
0166  */
0167 uintptr_t _TLS_Get_allocation_size( void );
0168 
0169 /**
0170  * @brief Initializes the thread-local storage data.
0171  *
0172  * @param config is the TLS configuration.
0173  *
0174  * @param[out] tls_data is the thread-local storage data to initialize.
0175  */
0176 static inline void _TLS_Copy_and_clear(
0177   const volatile TLS_Configuration *config,
0178   void                             *tls_data
0179 )
0180 {
0181   tls_data =
0182     memcpy( tls_data, config->data_begin, (uintptr_t) config->data_size );
0183 
0184   memset(
0185     (char *) tls_data +
0186       (uintptr_t) config->bss_begin - (uintptr_t) config->data_begin,
0187     0,
0188     (uintptr_t) config->bss_size
0189   );
0190 }
0191 
0192 /**
0193  * @brief Initializes the thread control block and the dynamic thread vector.
0194  *
0195  * @param tls_data is the thread-local storage data address.
0196  *
0197  * @param[out] tcb is the thread control block to initialize.
0198  *
0199  * @param[out] dtv is the dynamic thread vector to initialize.
0200  */
0201 static inline void _TLS_Initialize_TCB_and_DTV(
0202   void                      *tls_data,
0203   TLS_Thread_control_block  *tcb,
0204   TLS_Dynamic_thread_vector *dtv
0205 )
0206 {
0207 #if defined(__i386__) || defined(__x86_64__)
0208   (void) dtv;
0209   tcb->tcb = tcb;
0210 #else
0211   tcb->dtv = dtv;
0212   dtv->generation_number = 1;
0213   dtv->tls_blocks[0] = tls_data;
0214 #endif
0215 }
0216 
0217 /**
0218  * @brief Initializes the thread-local storage area.
0219  *
0220  * @param tls_area[out] is the thread-local storage area to initialize.
0221  *
0222  * @return Where the architectures uses Variant I and the TLS offsets emitted
0223  *   by the linker neglect the TCB, returns the address of the thread-local
0224  *   storage data.  Otherwise, returns the address of the thread control block.
0225  */
0226 static inline void *_TLS_Initialize_area( void *tls_area )
0227 {
0228   const volatile TLS_Configuration *config;
0229   uintptr_t                         alignment;
0230   void                             *tls_data;
0231   TLS_Thread_control_block         *tcb;
0232   TLS_Dynamic_thread_vector        *dtv;
0233   void                             *return_value;
0234 #if CPU_THREAD_LOCAL_STORAGE_VARIANT == 11
0235   uintptr_t                         tcb_size;
0236 #endif
0237 #if CPU_THREAD_LOCAL_STORAGE_VARIANT == 20
0238   uintptr_t                         size;
0239   uintptr_t                         alignment_2;
0240 #endif
0241 
0242   config = &_TLS_Configuration;
0243   alignment = (uintptr_t) config->alignment;
0244 
0245 #if defined(__i386__) || defined(__x86_64__)
0246   dtv = NULL;
0247 #else
0248   dtv = (TLS_Dynamic_thread_vector *) tls_area;
0249   tls_area = (char *) tls_area + sizeof( *dtv );
0250 #endif
0251 
0252 #if CPU_THREAD_LOCAL_STORAGE_VARIANT == 10
0253   tls_data = (void *)
0254     RTEMS_ALIGN_UP( (uintptr_t) tls_area + sizeof( *tcb ), alignment );
0255   tcb = (TLS_Thread_control_block *) ((char *) tls_data - sizeof( *tcb ));
0256   return_value = tls_data;
0257 #elif CPU_THREAD_LOCAL_STORAGE_VARIANT == 11
0258   tcb_size = RTEMS_ALIGN_UP( sizeof( *tcb ), alignment );
0259   tls_data = (void *)
0260     RTEMS_ALIGN_UP( (uintptr_t) tls_area + tcb_size, alignment );
0261   tcb = (TLS_Thread_control_block *) ((char *) tls_data - tcb_size);
0262   return_value = tcb;
0263 #elif CPU_THREAD_LOCAL_STORAGE_VARIANT == 20
0264   alignment_2 = RTEMS_ALIGN_UP( alignment, CPU_SIZEOF_POINTER );
0265   tls_area = (void *) RTEMS_ALIGN_UP( (uintptr_t) tls_area, alignment_2 );
0266   size = (uintptr_t) config->size;
0267   tcb = (TLS_Thread_control_block *)
0268     ((char *) tls_area + RTEMS_ALIGN_UP( size, alignment_2 ));
0269   tls_data = (char *) tcb - RTEMS_ALIGN_UP( size, alignment );
0270   return_value = tcb;
0271 #else
0272 #error "unexpected CPU_THREAD_LOCAL_STORAGE_VARIANT value"
0273 #endif
0274 
0275   _TLS_Initialize_TCB_and_DTV( tls_data, tcb, dtv );
0276   _TLS_Copy_and_clear( config, tls_data );
0277 
0278   return return_value;
0279 }
0280 
0281 /** @} */
0282 
0283 #ifdef __cplusplus
0284 }
0285 #endif /* __cplusplus */
0286 
0287 #endif /* _RTEMS_SCORE_TLS_H */