diff options
Diffstat (limited to 'cpukit/score/src/tlsallocsize.c')
-rw-r--r-- | cpukit/score/src/tlsallocsize.c | 83 |
1 files changed, 66 insertions, 17 deletions
diff --git a/cpukit/score/src/tlsallocsize.c b/cpukit/score/src/tlsallocsize.c index d761f3b6cf..fa28391b83 100644 --- a/cpukit/score/src/tlsallocsize.c +++ b/cpukit/score/src/tlsallocsize.c @@ -10,7 +10,7 @@ */ /* - * Copyright (C) 2014, 2020 embedded brains GmbH (http://www.embedded-brains.de) + * 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 @@ -42,14 +42,47 @@ #include <rtems/score/interr.h> #include <rtems/score/thread.h> +extern char _TLS_Data_begin[]; + +extern char _TLS_Data_size[]; + +extern char _TLS_BSS_begin[]; + +extern char _TLS_BSS_size[]; + +extern char _TLS_Size[]; + +/** + * @brief The TLS section alignment. + * + * 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. + */ +extern char _TLS_Alignment[]; + +const volatile TLS_Configuration _TLS_Configuration = { + .data_begin = _TLS_Data_begin, + .data_size = _TLS_Data_size, + .bss_begin = _TLS_BSS_begin, + .bss_size = _TLS_BSS_size, + .size = _TLS_Size, + .alignment = _TLS_Alignment +}; + static uintptr_t _TLS_Allocation_size; uintptr_t _TLS_Get_allocation_size( void ) { - uintptr_t size; - uintptr_t allocation_size; + const volatile TLS_Configuration *config; + uintptr_t size; + uintptr_t allocation_size; - size = _TLS_Get_size(); + config = &_TLS_Configuration; + size = (uintptr_t) config->size; if ( size == 0 ) { return 0; @@ -58,29 +91,45 @@ uintptr_t _TLS_Get_allocation_size( void ) allocation_size = _TLS_Allocation_size; if ( allocation_size == 0 ) { - uintptr_t alignment; - - alignment = _TLS_Align_up( (uintptr_t) _TLS_Alignment ); - - allocation_size = size; - allocation_size += _TLS_Get_thread_control_block_area_size( alignment ); -#ifndef __i386__ - allocation_size += sizeof( TLS_Dynamic_thread_vector ); -#endif + uintptr_t tls_align; + uintptr_t stack_align; /* * The TLS area is allocated in the thread storage area. Each allocation * shall meet the stack alignment requirement. */ - allocation_size = _TLS_Align_up( allocation_size ); + stack_align = CPU_STACK_ALIGNMENT; + tls_align = RTEMS_ALIGN_UP( (uintptr_t) config->alignment, stack_align ); + +#ifndef __i386__ + /* Reserve space for the dynamic thread vector */ + allocation_size += + RTEMS_ALIGN_UP( sizeof( TLS_Dynamic_thread_vector ), stack_align ); +#endif + + /* Reserve space for the thread control block */ + allocation_size += +#if CPU_THREAD_LOCAL_STORAGE_VARIANT == 11 + RTEMS_ALIGN_UP( sizeof( TLS_Thread_control_block ), tls_align ); +#else + RTEMS_ALIGN_UP( sizeof( TLS_Thread_control_block ), stack_align ); +#endif + + /* Reserve space for the thread-local storage data */ + allocation_size += +#if CPU_THREAD_LOCAL_STORAGE_VARIANT == 20 + RTEMS_ALIGN_UP( size, tls_align ); +#else + RTEMS_ALIGN_UP( size, stack_align ); +#endif /* * The stack allocator does not support aligned allocations. Allocate * enough to do the alignment manually. */ - if ( alignment > CPU_STACK_ALIGNMENT ) { - _Assert( alignment % CPU_STACK_ALIGNMENT == 0 ); - allocation_size += alignment - CPU_STACK_ALIGNMENT; + if ( tls_align > stack_align ) { + _Assert( tls_align % stack_align == 0 ); + allocation_size += tls_align - stack_align; } if ( _Thread_Maximum_TLS_size != 0 ) { |