summaryrefslogblamecommitdiffstats
path: root/cpukit/include/rtems/score/tls.h
blob: 8716c5230c2fd5e0069f5e24886510a5c09cd31e (plain) (tree)
1
2
3
4
5
6
7
8
9

                                           


        
                         
  

                                                         


   
                                                         
  



















                                                                              




                          
                                







                        
                                                     
  
                      
  

                                                                        






                                                                       







                                                          
 



                                                         
 



                                                         
 



                                                        
 



                                                    
 




                                                         
 
   
                                         
  




                                                                            
   
                                                           










                                                                     


                                         
                     
                                 




                                                                           
                     
      
                     






                           
   
                                                                  
  

                                          
                                                                      
   


                                                                
 

                                          
 
                                            
 

                                                                         
                

                                            

 
   
                                                                             
  

                                                                          
   
                                           
 
   
                                                    
  

                                          
                                                                       
   



                                            
 

                                                                          
 
         
                       
                                                                     
      
                                
    

 
   


                                                                             
  
                                                             
  
                                                              
   


                                               


                                



                 

                             
                                
      

 
   
                                                    
  
                                                                       
  


                                                                               
   
                                                          
 





                                                 
                                          
                                             

                                          

                                                
      
 

                                            
 




















                                                                          
                                  








                                                              
                                          

                      








                               
/* SPDX-License-Identifier: BSD-2-Clause */

/**
 * @file
 *
 * @ingroup RTEMSScoreTLS
 *
 * @brief This header file provides the interfaces of the
 *   @ref RTEMSScoreTLS.
 */

/*
 * Copyright (C) 2014, 2023 embedded brains GmbH & Co. KG
 *
 * 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.
 *
 * 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/cpuimpl.h>

#include <string.h>

#ifdef __cplusplus
extern "C" {
#endif /* __cplusplus */

/**
 * @defgroup RTEMSScoreTLS Thread-Local Storage (TLS)
 *
 * @ingroup RTEMSScore
 *
 * @brief This group contains the implementation to support thread-local
 *   storage (TLS).
 *
 * Variants I and II are according to Ulrich Drepper, "ELF Handling For
 * Thread-Local Storage".
 *
 * @{
 */

/**
 * @brief Represents the TLS configuration.
 */
typedef struct {
  /**
   * @brief This member is initialized to _TLS_Data_begin.
   */
  const char *data_begin;

  /**
   * @brief This member is initialized to _TLS_Data_size.
   */
  const char *data_size;

  /**
   * @brief This member is initialized to _TLS_BSS_begin.
   */
  const char *bss_begin;

  /**
   * @brief This member is initialized to _TLS_BSS_size.
   */
  const char *bss_size;

  /**
   * @brief This member is initialized to _TLS_Size.
   */
  const char *size;

  /**
   * @brief This member is initialized to _TLS_Alignment.
   */
  const char *alignment;
} TLS_Configuration;

/**
 * @brief Provides the TLS configuration.
 *
 * 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 const volatile TLS_Configuration _TLS_Configuration;

typedef struct {
  /*
   * FIXME: Not sure if the generation number type is correct for all
   * architectures.
  */
  uint32_t generation_number;

  void *tls_blocks[1];
} TLS_Dynamic_thread_vector;

typedef struct TLS_Thread_control_block {
#ifdef __i386__
  struct TLS_Thread_control_block *tcb;
#else /* !__i386__ */
  TLS_Dynamic_thread_vector *dtv;
/*
 * GCC under AArch64/LP64 expects a 16 byte TCB at the beginning of the TLS
 * data segment and indexes into it accordingly for TLS variable addresses.
 */
#if CPU_SIZEOF_POINTER == 4 || defined(AARCH64_MULTILIB_ARCH_V8)
  uintptr_t reserved;
#endif
#endif /* __i386__ */
} TLS_Thread_control_block;

typedef struct {
  uintptr_t module;
  uintptr_t offset;
} TLS_Index;

/**
 * @brief Gets the size of the thread control block area in bytes.
 *
 * @param config is the TLS configuration.
 *
 * @return Returns the size of the thread control block area in bytes.
 */
static inline uintptr_t _TLS_Get_thread_control_block_area_size(
  const volatile TLS_Configuration *config
)
{
#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 Gets the allocation size of the thread-local storage area in bytes.
 *
 * @return Returns the allocation size of the thread-local storage area in
 *   bytes.
 */
uintptr_t _TLS_Get_allocation_size( void );

/**
 * @brief Initializes the thread-local storage data.
 *
 * @param config is the TLS configuration.
 *
 * @param[out] tls_data is the thread-local storage data to initialize.
 */
static inline void _TLS_Copy_and_clear(
  const volatile TLS_Configuration *config,
  void                             *tls_data
)
{
  tls_data =
    memcpy( tls_data, config->data_begin, (uintptr_t) config->data_size );

  memset(
    (char *) tls_data +
      (uintptr_t) config->bss_begin - (uintptr_t) config->data_begin,
    0,
    (uintptr_t) config->bss_size
  );
}

/**
 * @brief Initializes the thread control block and the dynamic thread vector.
 *
 * @param tls_data is the thread-local storage data address.
 *
 * @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_TCB_and_DTV(
  void                      *tls_data,
  TLS_Thread_control_block  *tcb,
  TLS_Dynamic_thread_vector *dtv
)
{
#ifdef __i386__
  (void) dtv;
  tcb->tcb = tcb;
#else
  tcb->dtv = dtv;
  dtv->generation_number = 1;
  dtv->tls_blocks[0] = tls_data;
#endif
}

/**
 * @brief Initializes the thread-local storage area.
 *
 * @param tls_area[out] is the thread-local storage area to initialize.
 *
 * @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_Initialize_area( void *tls_area )
{
  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

  config = &_TLS_Configuration;
  alignment = (uintptr_t) config->alignment;

#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;
}

/** @} */

#ifdef __cplusplus
}
#endif /* __cplusplus */

#endif /* _RTEMS_SCORE_TLS_H */