Tested and implemented on ARM, m68k, PowerPC and SPARC. Other architectures need more work. --- c/src/lib/libcpu/powerpc/new-exceptions/cpu.c | 16 +- cpukit/score/Makefile.am | 1 + cpukit/score/cpu/arm/Makefile.am | 1 + cpukit/score/cpu/arm/__aeabi_read_tp.c | 44 ++++ cpukit/score/cpu/arm/armv7m-context-initialize.c | 3 +- cpukit/score/cpu/arm/cpu.c | 20 ++- cpukit/score/cpu/arm/cpu_asm.S | 10 + cpukit/score/cpu/arm/rtems/score/arm.h | 5 + cpukit/score/cpu/arm/rtems/score/cpu.h | 10 +- cpukit/score/cpu/avr/rtems/score/cpu.h | 3 +- cpukit/score/cpu/bfin/cpu.c | 3 +- cpukit/score/cpu/bfin/rtems/score/cpu.h | 4 +- cpukit/score/cpu/h8300/rtems/score/cpu.h | 2 +- cpukit/score/cpu/i386/rtems/score/cpu.h | 2 +- cpukit/score/cpu/lm32/rtems/score/cpu.h | 2 +- cpukit/score/cpu/m32c/context_init.c | 3 +- cpukit/score/cpu/m32c/rtems/score/cpu.h | 4 +- cpukit/score/cpu/m32r/context_init.c | 3 +- cpukit/score/cpu/m32r/rtems/score/cpu.h | 4 +- cpukit/score/cpu/m68k/Makefile.am | 1 + cpukit/score/cpu/m68k/__m68k_read_tp.c | 36 +++ cpukit/score/cpu/m68k/cpu.c | 27 +++ cpukit/score/cpu/m68k/rtems/score/cpu.h | 33 +-- cpukit/score/cpu/mips/cpu.c | 3 +- cpukit/score/cpu/mips/rtems/score/cpu.h | 3 +- cpukit/score/cpu/moxie/rtems/score/cpu.h | 2 +- cpukit/score/cpu/nios2/nios2-context-initialize.c | 3 +- cpukit/score/cpu/nios2/rtems/score/cpu.h | 4 +- cpukit/score/cpu/no_cpu/rtems/score/cpu.h | 3 +- cpukit/score/cpu/powerpc/rtems/score/cpu.h | 3 +- cpukit/score/cpu/sh/cpu.c | 3 +- cpukit/score/cpu/sh/rtems/score/cpu.h | 3 +- cpukit/score/cpu/sparc/cpu.c | 10 +- cpukit/score/cpu/sparc/rtems/score/cpu.h | 4 +- cpukit/score/cpu/sparc64/cpu.c | 10 +- cpukit/score/cpu/sparc64/rtems/score/cpu.h | 3 +- cpukit/score/cpu/v850/cpu.c | 3 +- cpukit/score/cpu/v850/rtems/score/cpu.h | 4 +- cpukit/score/include/rtems/score/context.h | 7 +- cpukit/score/include/rtems/score/thread.h | 2 + cpukit/score/include/rtems/score/tls.h | 169 ++++++++++++++ cpukit/score/preinstall.am | 4 + cpukit/score/src/threadclose.c | 2 + cpukit/score/src/threadinitialize.c | 18 ++ cpukit/score/src/threadloadenv.c | 3 +- cpukit/score/src/wkspace.c | 30 +++ testsuites/sptests/Makefile.am | 4 + testsuites/sptests/configure.ac | 7 + testsuites/sptests/sptls01/Makefile.am | 19 ++ testsuites/sptests/sptls01/init.c | 98 ++++++++ testsuites/sptests/sptls01/sptls01.doc | 11 + testsuites/sptests/sptls01/sptls01.scn | 5 + testsuites/sptests/sptls02/Makefile.am | 20 ++ testsuites/sptests/sptls02/init.cc | 257 +++++++++++++++++++++ testsuites/sptests/sptls02/sptls02.doc | 12 + testsuites/sptests/sptls02/sptls02.scn | 4 + 56 files changed, 912 insertions(+), 58 deletions(-) create mode 100644 cpukit/score/cpu/arm/__aeabi_read_tp.c create mode 100644 cpukit/score/cpu/m68k/__m68k_read_tp.c create mode 100644 cpukit/score/include/rtems/score/tls.h create mode 100644 testsuites/sptests/sptls01/Makefile.am create mode 100644 testsuites/sptests/sptls01/init.c create mode 100644 testsuites/sptests/sptls01/sptls01.doc create mode 100644 testsuites/sptests/sptls01/sptls01.scn create mode 100644 testsuites/sptests/sptls02/Makefile.am create mode 100644 testsuites/sptests/sptls02/init.cc create mode 100644 testsuites/sptests/sptls02/sptls02.doc create mode 100644 testsuites/sptests/sptls02/sptls02.scn
diff --git a/c/src/lib/libcpu/powerpc/new-exceptions/cpu.c b/c/src/lib/libcpu/powerpc/new-exceptions/cpu.c index d6a883a..a339f70 100644 --- a/c/src/lib/libcpu/powerpc/new-exceptions/cpu.c +++ b/c/src/lib/libcpu/powerpc/new-exceptions/cpu.c @@ -34,6 +34,7 @@ #include <rtems/score/thread.h> #include <rtems/score/interr.h> #include <rtems/score/cpu.h> +#include <rtems/score/tls.h> #include <rtems/powerpc/powerpc.h> /* _CPU_Initialize @@ -62,13 +63,13 @@ void _CPU_Context_Initialize( uint32_t size, uint32_t new_level, void *entry_point, - bool is_fp + bool is_fp, + void *tls_area ) { ppc_context *the_ppc_context; uint32_t msr_value; uint32_t sp; - register uint32_t gpr2 __asm__("2"); sp = (uint32_t)stack_base + size - PPC_MINIMUM_STACK_FRAME_SIZE; @@ -128,9 +129,18 @@ void _CPU_Context_Initialize( the_ppc_context->gpr1 = sp; the_ppc_context->msr = msr_value; the_ppc_context->lr = (uint32_t) entry_point; - the_ppc_context->gpr2 = gpr2; #ifdef __ALTIVEC__ _CPU_Context_initialize_altivec( the_ppc_context ); #endif + + if ( tls_area != NULL ) { + void *tls_block = _TLS_TCB_before_tls_block_initialize( tls_area ); + + the_ppc_context->gpr2 = (uint32_t) tls_block + 0x7000; + } else { + register uint32_t gpr2 __asm__("2"); + + the_ppc_context->gpr2 = gpr2; + } } diff --git a/cpukit/score/Makefile.am b/cpukit/score/Makefile.am index 4b22129..871d44e 100644 --- a/cpukit/score/Makefile.am +++ b/cpukit/score/Makefile.am @@ -74,6 +74,7 @@ include_rtems_score_HEADERS += include/rtems/score/threadsync.h include_rtems_score_HEADERS += include/rtems/score/timespec.h include_rtems_score_HEADERS += include/rtems/score/timestamp.h include_rtems_score_HEADERS += include/rtems/score/timestamp64.h +include_rtems_score_HEADERS += include/rtems/score/tls.h include_rtems_score_HEADERS += include/rtems/score/tod.h include_rtems_score_HEADERS += include/rtems/score/todimpl.h include_rtems_score_HEADERS += include/rtems/score/userext.h diff --git a/cpukit/score/cpu/arm/Makefile.am b/cpukit/score/cpu/arm/Makefile.am index edd7248..9fc0781 100644 --- a/cpukit/score/cpu/arm/Makefile.am +++ b/cpukit/score/cpu/arm/Makefile.am @@ -15,6 +15,7 @@ include_rtems_score_HEADERS += rtems/score/cpusmplock.h noinst_LIBRARIES = libscorecpu.a libscorecpu_a_CPPFLAGS = $(AM_CPPFLAGS) libscorecpu_a_SOURCES = +libscorecpu_a_SOURCES += __aeabi_read_tp.c libscorecpu_a_SOURCES += cpu.c libscorecpu_a_SOURCES += cpu_asm.S libscorecpu_a_SOURCES += arm-context-validate.S diff --git a/cpukit/score/cpu/arm/__aeabi_read_tp.c b/cpukit/score/cpu/arm/__aeabi_read_tp.c new file mode 100644 index 0000000..afdfd99 --- /dev/null +++ b/cpukit/score/cpu/arm/__aeabi_read_tp.c @@ -0,0 +1,44 @@ +/* + * Copyright (c) 2014 embedded brains GmbH. All rights reserved. + * + * embedded brains GmbH + * Obere Lagerstr. 30 + * 82178 Puchheim + * Germany + * <rt...@embedded-brains.de> + * + * The license and distribution terms for this file may be + * found in the file LICENSE in this distribution or at + * http://www.rtems.com/license/LICENSE. + */ + +#ifdef HAVE_CONFIG_H + #include "config.h" +#endif + +#include <rtems/score/thread.h> +#include <rtems/score/percpu.h> + +#ifndef RTEMS_SMP + +void __attribute__((naked)) __aeabi_read_tp(void); + +void __attribute__((naked)) __aeabi_read_tp(void) +{ + __asm__ volatile ( + "ldr r0, =_Per_CPU_Information\n" + "ldr r0, [r0, %[executingoff]]\n" +#if defined(__thumb__) && !defined(__thumb2__) + "add r0, %[tlsareaoff]\n" + "ldr r0, [r0]\n" +#else + "ldr r0, [r0, %[tlsareaoff]]\n" +#endif + "bx lr\n" + : + : [executingoff] "I" (offsetof(Per_CPU_Control, executing)), + [tlsareaoff] "I" (offsetof(Thread_Control, Start.tls_area)) + ); +} + +#endif /* RTEMS_SMP */ diff --git a/cpukit/score/cpu/arm/armv7m-context-initialize.c b/cpukit/score/cpu/arm/armv7m-context-initialize.c index 892df4d..8d91c67 100644 --- a/cpukit/score/cpu/arm/armv7m-context-initialize.c +++ b/cpukit/score/cpu/arm/armv7m-context-initialize.c @@ -35,7 +35,8 @@ void _CPU_Context_Initialize( size_t stack_area_size, uint32_t new_level, void (*entry_point)( void ), - bool is_fp + bool is_fp, + void *tls_area_begin ) { char *stack_area_end = (char *) stack_area_begin + stack_area_size; diff --git a/cpukit/score/cpu/arm/cpu.c b/cpukit/score/cpu/arm/cpu.c index 1c1fe5d..c3f071d 100644 --- a/cpukit/score/cpu/arm/cpu.c +++ b/cpukit/score/cpu/arm/cpu.c @@ -32,6 +32,7 @@ #include <rtems/score/isr.h> #include <rtems/score/wkspace.h> #include <rtems/score/thread.h> +#include <rtems/score/tls.h> #include <rtems/score/cpu.h> #ifdef ARM_MULTILIB_VFP_D32 @@ -41,6 +42,14 @@ ); #endif +#ifdef ARM_MULTILIB_HAS_THREAD_ID_REGISTER + RTEMS_STATIC_ASSERT( + offsetof( Context_Control, thread_id ) + == ARM_CONTEXT_CONTROL_THREAD_ID_OFFSET, + ARM_CONTEXT_CONTROL_THREAD_ID_OFFSET + ); +#endif + RTEMS_STATIC_ASSERT( sizeof( CPU_Exception_frame ) == ARM_EXCEPTION_FRAME_SIZE, ARM_EXCEPTION_FRAME_SIZE @@ -71,13 +80,22 @@ void _CPU_Context_Initialize( size_t stack_area_size, uint32_t new_level, void (*entry_point)( void ), - bool is_fp + bool is_fp, + void *tls_area ) { the_context->register_sp = (uint32_t) stack_area_begin + stack_area_size; the_context->register_lr = (uint32_t) entry_point; the_context->register_cpsr = ( ( new_level != 0 ) ? ARM_PSR_I : 0 ) | arm_cpu_mode; + +#ifdef ARM_MULTILIB_HAS_THREAD_ID_REGISTER + the_context->thread_id = (uint32_t) tls_area; +#endif + + if ( tls_area != NULL ) { + _TLS_TCB_at_area_begin_initialize( tls_area ); + } } /* Preprocessor magic for stringification of x */ diff --git a/cpukit/score/cpu/arm/cpu_asm.S b/cpukit/score/cpu/arm/cpu_asm.S index 7fb4062..1771ddd 100644 --- a/cpukit/score/cpu/arm/cpu_asm.S +++ b/cpukit/score/cpu/arm/cpu_asm.S @@ -62,12 +62,22 @@ DEFINE_FUNCTION_ARM(_CPU_Context_switch) vstm r3, {d8-d15} #endif +#ifdef ARM_MULTILIB_HAS_THREAD_ID_REGISTER + mrc p15, 0, r3, c13, c0, 3 + str r3, [r0, #ARM_CONTEXT_CONTROL_THREAD_ID_OFFSET] +#endif + /* Start restoring context */ _restore: #ifdef ARM_MULTILIB_HAS_LOAD_STORE_EXCLUSIVE clrex #endif +#ifdef ARM_MULTILIB_HAS_THREAD_ID_REGISTER + ldr r3, [r1, #ARM_CONTEXT_CONTROL_THREAD_ID_OFFSET] + mcr p15, 0, r3, c13, c0, 3 +#endif + #ifdef ARM_MULTILIB_VFP_D32 add r3, r1, #ARM_CONTEXT_CONTROL_D8_OFFSET vldm r3, {d8-d15} diff --git a/cpukit/score/cpu/arm/rtems/score/arm.h b/cpukit/score/cpu/arm/rtems/score/arm.h index 608f753..3e428f9 100644 --- a/cpukit/score/cpu/arm/rtems/score/arm.h +++ b/cpukit/score/cpu/arm/rtems/score/arm.h @@ -44,6 +44,11 @@ extern "C" { #define ARM_MULTILIB_HAS_LOAD_STORE_EXCLUSIVE #endif +#if defined(__ARM_ARCH_7A__) \ + || defined(__ARM_ARCH_7R__) + #define ARM_MULTILIB_HAS_THREAD_ID_REGISTER +#endif + #if defined(__ARM_NEON__) #define ARM_MULTILIB_VFP_D32 #elif !defined(__SOFTFP__) diff --git a/cpukit/score/cpu/arm/rtems/score/cpu.h b/cpukit/score/cpu/arm/rtems/score/cpu.h index 2d9b5d5..216f39f 100644 --- a/cpukit/score/cpu/arm/rtems/score/cpu.h +++ b/cpukit/score/cpu/arm/rtems/score/cpu.h @@ -212,6 +212,10 @@ /** @} */ +#ifdef ARM_MULTILIB_HAS_THREAD_ID_REGISTER + #define ARM_CONTEXT_CONTROL_THREAD_ID_OFFSET 44 +#endif + #ifdef ARM_MULTILIB_VFP_D32 #define ARM_CONTEXT_CONTROL_D8_OFFSET 48 #endif @@ -267,6 +271,9 @@ typedef struct { #else void *register_sp; #endif +#ifdef ARM_MULTILIB_HAS_THREAD_ID_REGISTER + uint32_t thread_id; +#endif #ifdef ARM_MULTILIB_VFP_D32 uint64_t register_d8; uint64_t register_d9; @@ -400,7 +407,8 @@ void _CPU_Context_Initialize( size_t stack_area_size, uint32_t new_level, void (*entry_point)( void ), - bool is_fp + bool is_fp, + void *tls_area ); #define _CPU_Context_Get_SP( _context ) \ diff --git a/cpukit/score/cpu/avr/rtems/score/cpu.h b/cpukit/score/cpu/avr/rtems/score/cpu.h index b67b241..f82b763 100644 --- a/cpukit/score/cpu/avr/rtems/score/cpu.h +++ b/cpukit/score/cpu/avr/rtems/score/cpu.h @@ -963,7 +963,8 @@ void _CPU_Context_Initialize( uint32_t size, uint32_t new_level, void *entry_point, - bool is_fp + bool is_fp, + void *tls_area ); /* diff --git a/cpukit/score/cpu/bfin/cpu.c b/cpukit/score/cpu/bfin/cpu.c index 05b9243..268848e 100644 --- a/cpukit/score/cpu/bfin/cpu.c +++ b/cpukit/score/cpu/bfin/cpu.c @@ -186,7 +186,8 @@ void _CPU_Context_Initialize( uint32_t size, uint32_t new_level, void *entry_point, - bool is_fp + bool is_fp, + void *tls_area ) { uint32_t stack_high; /* highest "stack aligned" address */ diff --git a/cpukit/score/cpu/bfin/rtems/score/cpu.h b/cpukit/score/cpu/bfin/rtems/score/cpu.h index 1af3f81..a8c60a5 100644 --- a/cpukit/score/cpu/bfin/rtems/score/cpu.h +++ b/cpukit/score/cpu/bfin/rtems/score/cpu.h @@ -817,6 +817,7 @@ uint32_t _CPU_ISR_Get_level( void ); * point thread. This is typically only used on CPUs where the * FPU may be easily disabled by software such as on the SPARC * where the PSR contains an enable FPU bit. + * @param[in] tls_area is the thread-local storage (TLS) area * * Port Specific Information: * @@ -828,7 +829,8 @@ void _CPU_Context_Initialize( uint32_t size, uint32_t new_level, void *entry_point, - bool is_fp + bool is_fp, + void *tls_area ); /** diff --git a/cpukit/score/cpu/h8300/rtems/score/cpu.h b/cpukit/score/cpu/h8300/rtems/score/cpu.h index f75f2e5..66774d4 100644 --- a/cpukit/score/cpu/h8300/rtems/score/cpu.h +++ b/cpukit/score/cpu/h8300/rtems/score/cpu.h @@ -756,7 +756,7 @@ uint32_t _CPU_ISR_Get_level( void ); #define CPU_CCR_INTERRUPTS_OFF 0x00 #define _CPU_Context_Initialize( _the_context, _stack_base, _size, \ - _isr, _entry_point, _is_fp ) \ + _isr, _entry_point, _is_fp, _tls_area ) \ /* Locate Me */ \ do { \ uintptr_t _stack; \ diff --git a/cpukit/score/cpu/i386/rtems/score/cpu.h b/cpukit/score/cpu/i386/rtems/score/cpu.h index 43422ed..dd06059 100644 --- a/cpukit/score/cpu/i386/rtems/score/cpu.h +++ b/cpukit/score/cpu/i386/rtems/score/cpu.h @@ -443,7 +443,7 @@ uint32_t _CPU_ISR_Get_level( void ); #define _CPU_Context_Initialize( _the_context, _stack_base, _size, \ - _isr, _entry_point, _is_fp ) \ + _isr, _entry_point, _is_fp, _tls_area ) \ do { \ uint32_t _stack; \ \ diff --git a/cpukit/score/cpu/lm32/rtems/score/cpu.h b/cpukit/score/cpu/lm32/rtems/score/cpu.h index 95553ef..4699c1a 100644 --- a/cpukit/score/cpu/lm32/rtems/score/cpu.h +++ b/cpukit/score/cpu/lm32/rtems/score/cpu.h @@ -823,7 +823,7 @@ uint32_t _CPU_ISR_Get_level( void ); extern char _gp[]; #define _CPU_Context_Initialize( _the_context, _stack_base, _size, \ - _isr, _entry_point, _is_fp ) \ + _isr, _entry_point, _is_fp, _tls_area ) \ do { \ uint32_t _stack = (uint32_t)(_stack_base) + (_size) - 4; \ (_the_context)->gp = (uint32_t)_gp; \ diff --git a/cpukit/score/cpu/m32c/context_init.c b/cpukit/score/cpu/m32c/context_init.c index d7c1c5d..b2edcf8 100644 --- a/cpukit/score/cpu/m32c/context_init.c +++ b/cpukit/score/cpu/m32c/context_init.c @@ -50,7 +50,8 @@ void _CPU_Context_Initialize( size_t size, uint32_t new_level, void *entry_point, - bool is_fp + bool is_fp, + void *tls_area ) { void *stackEnd = stack_base; diff --git a/cpukit/score/cpu/m32c/rtems/score/cpu.h b/cpukit/score/cpu/m32c/rtems/score/cpu.h index 5841885..681fb4b 100644 --- a/cpukit/score/cpu/m32c/rtems/score/cpu.h +++ b/cpukit/score/cpu/m32c/rtems/score/cpu.h @@ -809,6 +809,7 @@ uint32_t _CPU_ISR_Get_level( void ); * point thread. This is typically only used on CPUs where the * FPU may be easily disabled by software such as on the SPARC * where the PSR contains an enable FPU bit. + * @param[in] tls_area is the thread-local storage (TLS) area * * Port Specific Information: * @@ -820,7 +821,8 @@ void _CPU_Context_Initialize( size_t size, uint32_t new_level, void *entry_point, - bool is_fp + bool is_fp, + void *tls_area ); /** diff --git a/cpukit/score/cpu/m32r/context_init.c b/cpukit/score/cpu/m32r/context_init.c index bdfd758..d8ecc53 100644 --- a/cpukit/score/cpu/m32r/context_init.c +++ b/cpukit/score/cpu/m32r/context_init.c @@ -33,7 +33,8 @@ void _CPU_Context_Initialize( uint32_t size, uint32_t new_level, void *entry_point, - bool is_fp + bool is_fp, + void *tls_area ) { void *stackEnd = stack_base; diff --git a/cpukit/score/cpu/m32r/rtems/score/cpu.h b/cpukit/score/cpu/m32r/rtems/score/cpu.h index 0fea7bd..95a897a 100644 --- a/cpukit/score/cpu/m32r/rtems/score/cpu.h +++ b/cpukit/score/cpu/m32r/rtems/score/cpu.h @@ -828,6 +828,7 @@ uint32_t _CPU_ISR_Get_level( void ); * point thread. This is typically only used on CPUs where the * FPU may be easily disabled by software such as on the SPARC * where the PSR contains an enable FPU bit. + * @param[in] tls_area is the thread-local storage (TLS) area * * Port Specific Information: * @@ -839,7 +840,8 @@ void _CPU_Context_Initialize( size_t size, uint32_t new_level, void *entry_point, - bool is_fp + bool is_fp, + void *tls_area ); /** diff --git a/cpukit/score/cpu/m68k/Makefile.am b/cpukit/score/cpu/m68k/Makefile.am index 863a071..9d8d333 100644 --- a/cpukit/score/cpu/m68k/Makefile.am +++ b/cpukit/score/cpu/m68k/Makefile.am @@ -20,6 +20,7 @@ include_rtems_score_HEADERS += rtems/score/cpuatomic.h libscorecpu_a_SOURCES = cpu.c cpu_asm.S libscorecpu_a_SOURCES += m68k-exception-frame-print.c +libscorecpu_a_SOURCES += __m68k_read_tp.c include $(srcdir)/preinstall.am include $(top_srcdir)/automake/local.am diff --git a/cpukit/score/cpu/m68k/__m68k_read_tp.c b/cpukit/score/cpu/m68k/__m68k_read_tp.c new file mode 100644 index 0000000..3e024a8 --- /dev/null +++ b/cpukit/score/cpu/m68k/__m68k_read_tp.c @@ -0,0 +1,36 @@ +/* + * Copyright (c) 2014 embedded brains GmbH. All rights reserved. + * + * embedded brains GmbH + * Obere Lagerstr. 30 + * 82178 Puchheim + * Germany + * <rt...@embedded-brains.de> + * + * The license and distribution terms for this file may be + * found in the file LICENSE in this distribution or at + * http://www.rtems.com/license/LICENSE. + */ + +#ifdef HAVE_CONFIG_H + #include "config.h" +#endif + +#include <rtems/score/thread.h> +#include <rtems/score/tls.h> + +void __m68k_read_tp(void); + +void __m68k_read_tp(void) +{ + const Thread_Control *executing = _Thread_Get_executing(); + void *tp = (char *) executing->Start.tls_area + + _TLS_Get_thread_control_block_area_size((uintptr_t) _TLS_Alignment) + + 0x7000; + + __asm__ volatile ( + "move.l %0, %%a0" + : + : "d" (tp) + ); +} diff --git a/cpukit/score/cpu/m68k/cpu.c b/cpukit/score/cpu/m68k/cpu.c index 3776345..589d099 100644 --- a/cpukit/score/cpu/m68k/cpu.c +++ b/cpukit/score/cpu/m68k/cpu.c @@ -19,6 +19,7 @@ #include <rtems/system.h> #include <rtems/score/isr.h> +#include <rtems/score/tls.h> #if defined( __mcoldfire__ ) && ( M68K_HAS_FPU == 1 ) uint32_t _CPU_cacr_shadow; @@ -181,3 +182,29 @@ void _CPU_Context_restore_fp (Context_Control_fp **fp_context_ptr) _fpCCR = *fp; } #endif + +void _CPU_Context_Initialize( + Context_Control *the_context, + void *stack_area_begin, + size_t stack_area_size, + uint32_t new_level, + void (*entry_point)( void ), + bool is_fp, + void *tls_area +) +{ + uint32_t stack; + + the_context->sr = 0x3000 | (new_level << 8); + stack = (uint32_t)stack_area_begin + stack_area_size - 4; + the_context->a7_msp = (void *)stack; + *(void **)stack = (void *)entry_point; + +#if (defined(__mcoldfire__) && ( M68K_HAS_FPU == 1 )) + the_context->fpu_dis = is_fp ? 0x00 : 0x10; +#endif + + if ( tls_area != NULL ) { + _TLS_TCB_before_tls_block_initialize( tls_area ); + } +} diff --git a/cpukit/score/cpu/m68k/rtems/score/cpu.h b/cpukit/score/cpu/m68k/rtems/score/cpu.h index ccec3a6..9981f53 100644 --- a/cpukit/score/cpu/m68k/rtems/score/cpu.h +++ b/cpukit/score/cpu/m68k/rtems/score/cpu.h @@ -448,30 +448,15 @@ uint32_t _CPU_ISR_Get_level( void ); * + initialize an FP context area */ -#if (defined(__mcoldfire__) && ( M68K_HAS_FPU == 1 )) -#define _CPU_Context_Initialize( _the_context, _stack_base, _size, \ - _isr, _entry_point, _is_fp ) \ - do { \ - uint32_t _stack; \ - \ - (_the_context)->sr = 0x3000 | ((_isr) << 8); \ - _stack = (uint32_t)(_stack_base) + (_size) - 4; \ - (_the_context)->a7_msp = (void *)_stack; \ - *(void **)_stack = (void *)(_entry_point); \ - (_the_context)->fpu_dis = (_is_fp == TRUE) ? 0x00 : 0x10; \ - } while ( 0 ) -#else -#define _CPU_Context_Initialize( _the_context, _stack_base, _size, \ - _isr, _entry_point, _is_fp ) \ - do { \ - uint32_t _stack; \ - \ - (_the_context)->sr = 0x3000 | ((_isr) << 8); \ - _stack = (uint32_t)(_stack_base) + (_size) - 4; \ - (_the_context)->a7_msp = (void *)_stack; \ - *(void **)_stack = (void *)(_entry_point); \ - } while ( 0 ) -#endif +void _CPU_Context_Initialize( + Context_Control *the_context, + void *stack_area_begin, + size_t stack_area_size, + uint32_t new_level, + void (*entry_point)( void ), + bool is_fp, + void *tls_area +); /* end of Context handler macros */ diff --git a/cpukit/score/cpu/mips/cpu.c b/cpukit/score/cpu/mips/cpu.c index 5f7abeb..3be5df3 100644 --- a/cpukit/score/cpu/mips/cpu.c +++ b/cpukit/score/cpu/mips/cpu.c @@ -173,7 +173,8 @@ void _CPU_Context_Initialize( uint32_t size, uint32_t new_level, void *entry_point, - bool is_fp + bool is_fp, + void *tls_area ) { uintptr_t stack_tmp; diff --git a/cpukit/score/cpu/mips/rtems/score/cpu.h b/cpukit/score/cpu/mips/rtems/score/cpu.h index 1d1449c..6299961 100644 --- a/cpukit/score/cpu/mips/rtems/score/cpu.h +++ b/cpukit/score/cpu/mips/rtems/score/cpu.h @@ -858,7 +858,8 @@ void _CPU_Context_Initialize( uint32_t size, uint32_t new_level, void *entry_point, - bool is_fp + bool is_fp, + void *tls_area ); diff --git a/cpukit/score/cpu/moxie/rtems/score/cpu.h b/cpukit/score/cpu/moxie/rtems/score/cpu.h index 309110a..36a956c 100644 --- a/cpukit/score/cpu/moxie/rtems/score/cpu.h +++ b/cpukit/score/cpu/moxie/rtems/score/cpu.h @@ -651,7 +651,7 @@ uint32_t _CPU_ISR_Get_level( void ); #define CPU_CCR_INTERRUPTS_OFF 0x00 #define _CPU_Context_Initialize( _the_context, _stack_base, _size, \ - _isr, _entry_point, _is_fp ) \ + _isr, _entry_point, _is_fp, _tls_area ) \ /* Locate Me */ \ do { \ uintptr_t _stack; \ diff --git a/cpukit/score/cpu/nios2/nios2-context-initialize.c b/cpukit/score/cpu/nios2/nios2-context-initialize.c index e74e04f..6b884d0 100644 --- a/cpukit/score/cpu/nios2/nios2-context-initialize.c +++ b/cpukit/score/cpu/nios2/nios2-context-initialize.c @@ -27,7 +27,8 @@ void _CPU_Context_Initialize( size_t stack_area_size, uint32_t new_level, void (*entry_point)( void ), - bool is_fp + bool is_fp, + void *tls_area ) { const Nios2_MPU_Configuration *mpu_config = _Nios2_MPU_Get_configuration(); diff --git a/cpukit/score/cpu/nios2/rtems/score/cpu.h b/cpukit/score/cpu/nios2/rtems/score/cpu.h index e0dfd9f..bdd8f57 100644 --- a/cpukit/score/cpu/nios2/rtems/score/cpu.h +++ b/cpukit/score/cpu/nios2/rtems/score/cpu.h @@ -295,6 +295,7 @@ uint32_t _CPU_ISR_Get_level( void ); * @param[in] new_level is the interrupt level for the task * @param[in] entry_point is the task's entry point * @param[in] is_fp is set to @c true if the task is a floating point task + * @param[in] tls_area is the thread-local storage (TLS) area */ void _CPU_Context_Initialize( Context_Control *context, @@ -302,7 +303,8 @@ void _CPU_Context_Initialize( size_t stack_area_size, uint32_t new_level, void (*entry_point)( void ), - bool is_fp + bool is_fp, + void *tls_area ); #define _CPU_Context_Restart_self( _the_context ) \ diff --git a/cpukit/score/cpu/no_cpu/rtems/score/cpu.h b/cpukit/score/cpu/no_cpu/rtems/score/cpu.h index f1f02ed..783da76 100644 --- a/cpukit/score/cpu/no_cpu/rtems/score/cpu.h +++ b/cpukit/score/cpu/no_cpu/rtems/score/cpu.h @@ -932,13 +932,14 @@ uint32_t _CPU_ISR_Get_level( void ); * point thread. This is typically only used on CPUs where the * FPU may be easily disabled by software such as on the SPARC * where the PSR contains an enable FPU bit. + * @param[in] _tls_area The thread-local storage (TLS) area. * * Port Specific Information: * * XXX document implementation including references if appropriate */ #define _CPU_Context_Initialize( _the_context, _stack_base, _size, \ - _isr, _entry_point, _is_fp ) \ + _isr, _entry_point, _is_fp, _tls_area ) \ { \ } diff --git a/cpukit/score/cpu/powerpc/rtems/score/cpu.h b/cpukit/score/cpu/powerpc/rtems/score/cpu.h index 6263d34..8eb2327 100644 --- a/cpukit/score/cpu/powerpc/rtems/score/cpu.h +++ b/cpukit/score/cpu/powerpc/rtems/score/cpu.h @@ -797,7 +797,8 @@ void _CPU_Context_Initialize( uint32_t size, uint32_t new_level, void *entry_point, - bool is_fp + bool is_fp, + void *tls_area ); /* diff --git a/cpukit/score/cpu/sh/cpu.c b/cpukit/score/cpu/sh/cpu.c index 57d6ffc..be3fedd 100644 --- a/cpukit/score/cpu/sh/cpu.c +++ b/cpukit/score/cpu/sh/cpu.c @@ -211,7 +211,8 @@ void _CPU_Context_Initialize( uint32_t _size, uint32_t _isr, void (*_entry_point)(void), - int _is_fp ) + int _is_fp, + void *_tls_base) { _the_context->r15 = (uint32_t *) ((uint32_t) (_stack_base) + (_size) ); #if defined(__sh1__) || defined(__sh2__) || defined(__SH2E__) diff --git a/cpukit/score/cpu/sh/rtems/score/cpu.h b/cpukit/score/cpu/sh/rtems/score/cpu.h index 41d9638..ff9ad55 100644 --- a/cpukit/score/cpu/sh/rtems/score/cpu.h +++ b/cpukit/score/cpu/sh/rtems/score/cpu.h @@ -603,7 +603,8 @@ SCORE_EXTERN void _CPU_Context_Initialize( uint32_t _size, uint32_t _isr, void (*_entry_point)(void), - int _is_fp ); + int _is_fp, + void *_tls_area ); /* * This routine is responsible for somehow restarting the currently diff --git a/cpukit/score/cpu/sparc/cpu.c b/cpukit/score/cpu/sparc/cpu.c index 1865a21..11e31f9 100644 --- a/cpukit/score/cpu/sparc/cpu.c +++ b/cpukit/score/cpu/sparc/cpu.c @@ -20,6 +20,7 @@ #include <rtems/system.h> #include <rtems/score/isr.h> #include <rtems/score/percpu.h> +#include <rtems/score/tls.h> #include <rtems/rtems/cache.h> RTEMS_STATIC_ASSERT( @@ -232,7 +233,8 @@ void _CPU_Context_Initialize( uint32_t size, uint32_t new_level, void *entry_point, - bool is_fp + bool is_fp, + void *tls_area ) { uint32_t stack_high; /* highest "stack aligned" address */ @@ -285,4 +287,10 @@ void _CPU_Context_Initialize( * thread can have an _ISR_Dispatch stack frame on its stack. */ the_context->isr_dispatch_disable = 0; + + if ( tls_area != NULL ) { + void *tcb = _TLS_TCB_after_tls_block_initialize( tls_area ); + + the_context->g7 = (uintptr_t) tcb; + } } diff --git a/cpukit/score/cpu/sparc/rtems/score/cpu.h b/cpukit/score/cpu/sparc/rtems/score/cpu.h index 690ddcf..ae89311 100644 --- a/cpukit/score/cpu/sparc/rtems/score/cpu.h +++ b/cpukit/score/cpu/sparc/rtems/score/cpu.h @@ -1019,6 +1019,7 @@ uint32_t _CPU_ISR_Get_level( void ); * @param[in] new_level is the interrupt level for the task * @param[in] entry_point is the task's entry point * @param[in] is_fp is set to TRUE if the task is a floating point task + * @param[in] tls_area is the thread-local storage (TLS) area * * NOTE: Implemented as a subroutine for the SPARC port. */ @@ -1028,7 +1029,8 @@ void _CPU_Context_Initialize( uint32_t size, uint32_t new_level, void *entry_point, - bool is_fp + bool is_fp, + void *tls_area ); /** diff --git a/cpukit/score/cpu/sparc64/cpu.c b/cpukit/score/cpu/sparc64/cpu.c index 94f9340..d7c2f47 100644 --- a/cpukit/score/cpu/sparc64/cpu.c +++ b/cpukit/score/cpu/sparc64/cpu.c @@ -20,6 +20,7 @@ #include <rtems/system.h> #include <rtems/asm.h> #include <rtems/score/isr.h> +#include <rtems/score/tls.h> #include <rtems/rtems/cache.h> /* @@ -65,7 +66,8 @@ void _CPU_Context_Initialize( uint32_t size, uint32_t new_level, void *entry_point, - bool is_fp + bool is_fp, + void *tls_area ) { uint64_t stack_high; /* highest "stack aligned" address */ @@ -99,4 +101,10 @@ void _CPU_Context_Initialize( * thread can have an _ISR_Dispatch stack frame on its stack. */ the_context->isr_dispatch_disable = 0; + + if ( tls_area != NULL ) { + void *tcb = _TLS_TCB_after_tls_block_initialize( tls_area ); + + the_context->g7 = (uintptr_t) tcb; + } } diff --git a/cpukit/score/cpu/sparc64/rtems/score/cpu.h b/cpukit/score/cpu/sparc64/rtems/score/cpu.h index 8d3e273..22ec97d 100644 --- a/cpukit/score/cpu/sparc64/rtems/score/cpu.h +++ b/cpukit/score/cpu/sparc64/rtems/score/cpu.h @@ -838,7 +838,8 @@ void _CPU_Context_Initialize( uint32_t size, uint32_t new_level, void *entry_point, - bool is_fp + bool is_fp, + void *tls_area ); /* diff --git a/cpukit/score/cpu/v850/cpu.c b/cpukit/score/cpu/v850/cpu.c index 50065b6..d4022f3 100644 --- a/cpukit/score/cpu/v850/cpu.c +++ b/cpukit/score/cpu/v850/cpu.c @@ -61,7 +61,8 @@ void _CPU_Context_Initialize( uint32_t size, uint32_t new_level, void *entry_point, - bool is_fp + bool is_fp, + void *tls_area ) { uint32_t stack_high; /* highest "stack aligned" address */ diff --git a/cpukit/score/cpu/v850/rtems/score/cpu.h b/cpukit/score/cpu/v850/rtems/score/cpu.h index 3e110b5..f41bde0 100644 --- a/cpukit/score/cpu/v850/rtems/score/cpu.h +++ b/cpukit/score/cpu/v850/rtems/score/cpu.h @@ -790,6 +790,7 @@ uint32_t _CPU_ISR_Get_level( void ); * point thread. This is typically only used on CPUs where the * FPU may be easily disabled by software such as on the SPARC * where the PSR contains an enable FPU bit. + * @param[in] tls_area is the thread-local storage (TLS) area * * Port Specific Information: * @@ -801,7 +802,8 @@ void _CPU_Context_Initialize( uint32_t size, uint32_t new_level, void *entry_point, - bool is_fp + bool is_fp, + void *tls_area ); /** diff --git a/cpukit/score/include/rtems/score/context.h b/cpukit/score/include/rtems/score/context.h index 02bcf15..ffffe9b 100644 --- a/cpukit/score/include/rtems/score/context.h +++ b/cpukit/score/include/rtems/score/context.h @@ -60,9 +60,12 @@ extern "C" { * @param[in] _entry is this thread's entry point * @param[in] _is_fp is set to true if this thread has floating point * enabled + * @param[in] _tls_area The thread-local storage (TLS) area begin. */ -#define _Context_Initialize(_the_context, _stack, _size, _isr, _entry, _is_fp) \ - _CPU_Context_Initialize( _the_context, _stack, _size, _isr, _entry, _is_fp ) +#define _Context_Initialize( _the_context, _stack, _size, _isr, _entry, \ + _is_fp, _tls_area ) \ + _CPU_Context_Initialize( _the_context, _stack, _size, _isr, _entry, \ + _is_fp, _tls_area ) /** * This macro is invoked from _Thread_Handler to do whatever CPU diff --git a/cpukit/score/include/rtems/score/thread.h b/cpukit/score/include/rtems/score/thread.h index edb2f67..3b09007 100644 --- a/cpukit/score/include/rtems/score/thread.h +++ b/cpukit/score/include/rtems/score/thread.h @@ -229,6 +229,8 @@ typedef struct { #endif /** This field is the initial stack area address. */ void *stack; + /** The thread-local storage (TLS) area */ + void *tls_area; } Thread_Start_information; /** diff --git a/cpukit/score/include/rtems/score/tls.h b/cpukit/score/include/rtems/score/tls.h new file mode 100644 index 0000000..858a65c --- /dev/null +++ b/cpukit/score/include/rtems/score/tls.h @@ -0,0 +1,169 @@ +/** + * @file + * + * @ingroup ScoreTLS + * + * @brief Thread-Local Storage (TLS) + */ + +/* + * Copyright (c) 2014 embedded brains GmbH. All rights reserved. + * + * embedded brains GmbH + * Dornierstr. 4 + * 82178 Puchheim + * Germany + * <rt...@embedded-brains.de> + * + * The license and distribution terms for this file may be + * found in the file LICENSE in this distribution or at + * http://www.rtems.com/license/LICENSE. + */ + +#ifndef _RTEMS_SCORE_TLS_H +#define _RTEMS_SCORE_TLS_H + +#include <rtems/score/basedefs.h> + +#include <string.h> + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + +/** + * @defgroup ScoreTLS Thread-Local Storage (TLS) + * + * @ingroup Score + * + * @brief Thread-local storage (TLS) support. + * + * Variants I and II are according to Ulrich Drepper, "ELF Handling For + * Thread-Local Storage". + * + * @{ + */ + +extern char _TLS_Data_begin[]; + +extern char _TLS_Data_end[]; + +extern char _TLS_Data_size[]; + +extern char _TLS_BSS_begin[]; + +extern char _TLS_BSS_end[]; + +extern char _TLS_BSS_size[]; + +extern char _TLS_Size[]; + +extern char _TLS_Alignment[]; + +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_Dynamic_thread_vector *dtv; + uintptr_t reserved; +} TLS_Thread_control_block; + +static inline uintptr_t _TLS_Get_thread_control_block_area_size( + uintptr_t alignment +) +{ + return alignment <= sizeof(TLS_Thread_control_block) ? + sizeof(TLS_Thread_control_block) : alignment; +} + +static inline uintptr_t _TLS_Get_allocation_size( + uintptr_t size, + uintptr_t alignment +) +{ + return _TLS_Get_thread_control_block_area_size(alignment) + + size + sizeof(TLS_Dynamic_thread_vector); +} + +static inline void *_TLS_Copy_and_clear(void *tls_area) +{ + tls_area = memcpy(tls_area, _TLS_Data_begin, (size_t) _TLS_Data_size); + + memset( + (char *) tls_area + (size_t) _TLS_BSS_begin - (size_t) _TLS_Data_begin, + 0, + (size_t) _TLS_BSS_size + ); + + return tls_area; +} + +static inline void *_TLS_Initialize( + void *tls_block, + TLS_Thread_control_block *tcb, + TLS_Dynamic_thread_vector *dtv +) +{ + tcb->dtv = dtv; + dtv->generation_number = 1; + dtv->tls_blocks[0] = tls_block; + + return _TLS_Copy_and_clear(tls_block); +} + +/* Use Variant I, TLS offsets emitted by linker takes the TCB into account */ +static inline void *_TLS_TCB_at_area_begin_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_area; + TLS_Dynamic_thread_vector *dtv = (TLS_Dynamic_thread_vector *) + ((char *) tls_block + (uintptr_t) _TLS_Size); + + return _TLS_Initialize( tls_block, tcb, dtv ); +} + +/* Use Variant I, TLS offsets emitted by linker neglects the TCB */ +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)); + TLS_Dynamic_thread_vector *dtv = (TLS_Dynamic_thread_vector *) + ((char *) tls_block + (uintptr_t) _TLS_Size); + + return _TLS_Initialize( tls_block, tcb, dtv ); +} + +/* Use Variant II */ +static inline void *_TLS_TCB_after_tls_block_initialize(void *tls_area) +{ + void *tls_block = (char *) tls_area; + uintptr_t tls_size = (uintptr_t) _TLS_Size; + uintptr_t tls_align = (uintptr_t) _TLS_Alignment; + uintptr_t tls_mask = tls_align - 1; + TLS_Thread_control_block *tcb = (TLS_Thread_control_block *) + ((char *) tls_block + ((tls_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 __cplusplus +} +#endif /* __cplusplus */ + +#endif /* _RTEMS_SCORE_TLS_H */ diff --git a/cpukit/score/preinstall.am b/cpukit/score/preinstall.am index 79a18b5..f43fc9d 100644 --- a/cpukit/score/preinstall.am +++ b/cpukit/score/preinstall.am @@ -279,6 +279,10 @@ $(PROJECT_INCLUDE)/rtems/score/timestamp64.h: include/rtems/score/timestamp64.h $(INSTALL_DATA) $< $(PROJECT_INCLUDE)/rtems/score/timestamp64.h PREINSTALL_FILES += $(PROJECT_INCLUDE)/rtems/score/timestamp64.h +$(PROJECT_INCLUDE)/rtems/score/tls.h: include/rtems/score/tls.h $(PROJECT_INCLUDE)/rtems/score/$(dirstamp) + $(INSTALL_DATA) $< $(PROJECT_INCLUDE)/rtems/score/tls.h +PREINSTALL_FILES += $(PROJECT_INCLUDE)/rtems/score/tls.h + $(PROJECT_INCLUDE)/rtems/score/tod.h: include/rtems/score/tod.h $(PROJECT_INCLUDE)/rtems/score/$(dirstamp) $(INSTALL_DATA) $< $(PROJECT_INCLUDE)/rtems/score/tod.h PREINSTALL_FILES += $(PROJECT_INCLUDE)/rtems/score/tod.h diff --git a/cpukit/score/src/threadclose.c b/cpukit/score/src/threadclose.c index df70f50..82c4ab4 100644 --- a/cpukit/score/src/threadclose.c +++ b/cpukit/score/src/threadclose.c @@ -96,4 +96,6 @@ void _Thread_Close( _Workspace_Free( the_thread->extensions ); the_thread->extensions = NULL; + + _Workspace_Free( the_thread->Start.tls_area ); } diff --git a/cpukit/score/src/threadinitialize.c b/cpukit/score/src/threadinitialize.c index 34198ca..6345ae7 100644 --- a/cpukit/score/src/threadinitialize.c +++ b/cpukit/score/src/threadinitialize.c @@ -20,6 +20,7 @@ #include <rtems/score/threadimpl.h> #include <rtems/score/schedulerimpl.h> #include <rtems/score/stackimpl.h> +#include <rtems/score/tls.h> #include <rtems/score/userextimpl.h> #include <rtems/score/watchdogimpl.h> #include <rtems/score/wkspace.h> @@ -48,6 +49,7 @@ bool _Thread_Initialize( void *extensions_area; bool extension_status; int i; + uintptr_t tls_size = (uintptr_t) _TLS_Size; #if defined( RTEMS_SMP ) if ( rtems_configuration_is_smp_enabled() && !is_preemptible ) { @@ -70,6 +72,7 @@ bool _Thread_Initialize( extensions_area = NULL; the_thread->libc_reent = NULL; + the_thread->Start.tls_area = NULL; #if ( CPU_HARDWARE_FP == TRUE ) || ( CPU_SOFTWARE_FP == TRUE ) fp_area = NULL; @@ -105,6 +108,19 @@ bool _Thread_Initialize( actual_stack_size ); + /* Thread-local storage (TLS) area allocation */ + if ( tls_size > 0 ) { + uintptr_t tls_alignment = (uintptr_t) _TLS_Alignment; + uintptr_t tls_alloc = _TLS_Get_allocation_size( tls_size, tls_alignment ); + + the_thread->Start.tls_area = + _Workspace_Allocate_aligned( tls_alloc, tls_alignment ); + + if ( the_thread->Start.tls_area == NULL ) { + goto failed; + } + } + /* * Allocate the floating point area for this thread */ @@ -223,6 +239,8 @@ bool _Thread_Initialize( return true; failed: + _Workspace_Free( the_thread->Start.tls_area ); + _Workspace_Free( the_thread->libc_reent ); for ( i=0 ; i <= THREAD_API_LAST ; i++ ) diff --git a/cpukit/score/src/threadloadenv.c b/cpukit/score/src/threadloadenv.c index eb3cc63..49821b0 100644 --- a/cpukit/score/src/threadloadenv.c +++ b/cpukit/score/src/threadloadenv.c @@ -58,7 +58,8 @@ void _Thread_Load_environment( the_thread->Start.Initial_stack.size, isr_level, _Thread_Handler, - is_fp + is_fp, + the_thread->Start.tls_area ); } diff --git a/cpukit/score/src/wkspace.c b/cpukit/score/src/wkspace.c index 6580686..f437b88 100644 --- a/cpukit/score/src/wkspace.c +++ b/cpukit/score/src/wkspace.c @@ -21,6 +21,8 @@ #include <rtems/score/wkspace.h> #include <rtems/score/heapimpl.h> #include <rtems/score/interr.h> +#include <rtems/score/threadimpl.h> +#include <rtems/score/tls.h> #include <rtems/config.h> #include <string.h> /* for memset */ @@ -30,6 +32,25 @@ #include <rtems/bspIo.h> #endif +static uint32_t _Get_maximum_thread_count(void) +{ + uint32_t thread_count = 0; + + thread_count += _Thread_Get_maximum_internal_threads(); + + thread_count += rtems_resource_maximum_per_allocation( + Configuration_RTEMS_API.maximum_tasks + ); + +#if defined(RTEMS_POSIX_API) + thread_count += rtems_resource_maximum_per_allocation( + Configuration_POSIX_API.maximum_threads + ); +#endif + + return thread_count; +} + void _Workspace_Handler_initialization( Heap_Area *areas, size_t area_count, @@ -42,8 +63,17 @@ void _Workspace_Handler_initialization( bool unified = rtems_configuration_get_unified_work_area(); uintptr_t page_size = CPU_HEAP_ALIGNMENT; uintptr_t overhead = _Heap_Area_overhead( page_size ); + uintptr_t tls_size = (uintptr_t) _TLS_Size; size_t i; + if ( tls_size > 0 ) { + uintptr_t tls_alignment = (uintptr_t) _TLS_Alignment; + uintptr_t tls_alloc = _TLS_Get_allocation_size( tls_size, tls_alignment ); + + remaining += _Get_maximum_thread_count() + * _Heap_Size_with_overhead( page_size, tls_alloc, tls_alignment ); + } + for (i = 0; i < area_count; ++i) { Heap_Area *area = &areas [i]; diff --git a/testsuites/sptests/Makefile.am b/testsuites/sptests/Makefile.am index 7eab621..1eacf5c 100644 --- a/testsuites/sptests/Makefile.am +++ b/testsuites/sptests/Makefile.am @@ -30,6 +30,10 @@ SUBDIRS = \ spsimplesched03 spnsext01 spedfsched01 spedfsched02 spedfsched03 \ spcbssched01 spcbssched02 spcbssched03 spqreslib sptimespec01 \ spregion_err01 sppartition_err01 +if HAS_CPLUSPLUS +SUBDIRS += sptls02 +endif +SUBDIRS += sptls01 SUBDIRS += spintrcritical20 SUBDIRS += spintrcritical19 SUBDIRS += spcontext01 diff --git a/testsuites/sptests/configure.ac b/testsuites/sptests/configure.ac index 6b14543..623e784 100644 --- a/testsuites/sptests/configure.ac +++ b/testsuites/sptests/configure.ac @@ -11,16 +11,21 @@ RTEMS_CANONICAL_TARGET_CPU AM_INIT_AUTOMAKE([no-define foreign 1.12.2]) AM_MAINTAINER_MODE +RTEMS_ENABLE_CXX RTEMS_ENV_RTEMSBSP RTEMS_CHECK_RTEMS_TEST_NO_PAUSE RTEMS_PROJECT_ROOT RTEMS_PROG_CC_FOR_TARGET +RTEMS_PROG_CXX_FOR_TARGET RTEMS_CANONICALIZE_TOOLS RTEMS_CHECK_CUSTOM_BSP(RTEMS_BSP) +RTEMS_CHECK_CXX(RTEMS_BSP) + +AM_CONDITIONAL([HAS_CPLUSPLUS],[test $HAS_CPLUSPLUS = "yes"]) # FIXME: We should get rid of this. It's a cludge. AC_CHECK_SIZEOF([time_t]) @@ -31,6 +36,8 @@ AM_CONDITIONAL(HAS_CPUSET,test x"${ac_cv_header_sys_cpuset_h}" = x"yes") # Explicitly list all Makefiles here AC_CONFIG_FILES([Makefile +sptls02/Makefile +sptls01/Makefile spintrcritical20/Makefile spintrcritical19/Makefile spcontext01/Makefile diff --git a/testsuites/sptests/sptls01/Makefile.am b/testsuites/sptests/sptls01/Makefile.am new file mode 100644 index 0000000..5512b8a --- /dev/null +++ b/testsuites/sptests/sptls01/Makefile.am @@ -0,0 +1,19 @@ +rtems_tests_PROGRAMS = sptls01 +sptls01_SOURCES = init.c + +dist_rtems_tests_DATA = sptls01.scn sptls01.doc + +include $(RTEMS_ROOT)/make/custom/@RTEMS_BSP@.cfg +include $(top_srcdir)/../automake/compile.am +include $(top_srcdir)/../automake/leaf.am + +AM_CPPFLAGS += -I$(top_srcdir)/../support/include + +LINK_OBJS = $(sptls01_OBJECTS) +LINK_LIBS = $(sptls01_LDLIBS) + +sptls01$(EXEEXT): $(sptls01_OBJECTS) $(sptls01_DEPENDENCIES) + @rm -f sptls01$(EXEEXT) + $(make-exe) + +include $(top_srcdir)/../automake/local.am diff --git a/testsuites/sptests/sptls01/init.c b/testsuites/sptests/sptls01/init.c new file mode 100644 index 0000000..57a3434 --- /dev/null +++ b/testsuites/sptests/sptls01/init.c @@ -0,0 +1,98 @@ +/* + * Copyright (c) 2014 embedded brains GmbH. All rights reserved. + * + * embedded brains GmbH + * Dornierstr. 4 + * 82178 Puchheim + * Germany + * <rt...@embedded-brains.de> + * + * The license and distribution terms for this file may be + * found in the file LICENSE in this distribution or at + * http://www.rtems.com/license/LICENSE. + */ + +#ifdef HAVE_CONFIG_H + #include "config.h" +#endif + +#include <stdio.h> + +#include "tmacros.h" + +static rtems_id master_task; + +static __thread volatile char tls_item = 123; + +static void check_tls_item(int expected) +{ + printf("TLS item = %i\n", tls_item); + rtems_test_assert(tls_item == expected); +} + +static void task(rtems_task_argument arg) +{ + rtems_status_code sc; + + check_tls_item(123); + + sc = rtems_event_transient_send(master_task); + assert(sc == RTEMS_SUCCESSFUL); + + sc = rtems_task_suspend(RTEMS_SELF); + assert(sc == RTEMS_SUCCESSFUL); +} + +static void test(void) +{ + rtems_id id; + rtems_status_code sc; + + master_task = rtems_task_self(); + + check_tls_item(123); + tls_item = 5; + + sc = rtems_task_create( + rtems_build_name('T', 'A', 'S', 'K'), + RTEMS_MINIMUM_PRIORITY, + RTEMS_MINIMUM_STACK_SIZE, + RTEMS_DEFAULT_MODES, + RTEMS_DEFAULT_ATTRIBUTES, + &id + ); + assert(sc == RTEMS_SUCCESSFUL); + + sc = rtems_task_start(id, task, 0); + assert(sc == RTEMS_SUCCESSFUL); + + sc = rtems_event_transient_receive(RTEMS_WAIT, RTEMS_NO_TIMEOUT); + assert(sc == RTEMS_SUCCESSFUL); + + sc = rtems_task_delete(id); + assert(sc == RTEMS_SUCCESSFUL); + + check_tls_item(5); +} + +static void Init(rtems_task_argument arg) +{ + puts("\n\n*** TEST SPTLS 1 ***"); + + test(); + + puts("*** END OF TEST SPTLS 1 ***"); + + rtems_test_exit(0); +} + +#define CONFIGURE_APPLICATION_NEEDS_CLOCK_DRIVER +#define CONFIGURE_APPLICATION_NEEDS_CONSOLE_DRIVER + +#define CONFIGURE_MAXIMUM_TASKS 2 + +#define CONFIGURE_RTEMS_INIT_TASKS_TABLE + +#define CONFIGURE_INIT + +#include <rtems/confdefs.h> diff --git a/testsuites/sptests/sptls01/sptls01.doc b/testsuites/sptests/sptls01/sptls01.doc new file mode 100644 index 0000000..a6cc38b --- /dev/null +++ b/testsuites/sptests/sptls01/sptls01.doc @@ -0,0 +1,11 @@ +This file describes the directives and concepts tested by this test set. + +test set name: sptls01 + +directives: + + - None + +concepts: + + - Ensure that thread-local storage (TLS) works minimum alignment requirements. diff --git a/testsuites/sptests/sptls01/sptls01.scn b/testsuites/sptests/sptls01/sptls01.scn new file mode 100644 index 0000000..eaeb11e --- /dev/null +++ b/testsuites/sptests/sptls01/sptls01.scn @@ -0,0 +1,5 @@ +*** TEST SPTLS 1 *** +TLS item = 123 +TLS item = 123 +TLS item = 5 +*** END OF TEST SPTLS 1 *** diff --git a/testsuites/sptests/sptls02/Makefile.am b/testsuites/sptests/sptls02/Makefile.am new file mode 100644 index 0000000..d577b5b --- /dev/null +++ b/testsuites/sptests/sptls02/Makefile.am @@ -0,0 +1,20 @@ +rtems_tests_PROGRAMS = sptls02 +sptls02_SOURCES = init.cc + +dist_rtems_tests_DATA = sptls02.scn sptls02.doc + +include $(RTEMS_ROOT)/make/custom/@RTEMS_BSP@.cfg +include $(top_srcdir)/../automake/compile.am +include $(top_srcdir)/../automake/leaf.am + +AM_CPPFLAGS += -I$(top_srcdir)/../support/include +AM_CXXFLAGS += -std=c++11 -ftls-model=local-exec + +LINK_OBJS = $(sptls02_OBJECTS) +LINK_LIBS = $(sptls02_LDLIBS) + +sptls02$(EXEEXT): $(sptls02_OBJECTS) $(sptls02_DEPENDENCIES) + @rm -f sptls02$(EXEEXT) + $(make-cxx-exe) + +include $(top_srcdir)/../automake/local.am diff --git a/testsuites/sptests/sptls02/init.cc b/testsuites/sptests/sptls02/init.cc new file mode 100644 index 0000000..b1b2e8a --- /dev/null +++ b/testsuites/sptests/sptls02/init.cc @@ -0,0 +1,257 @@ +/* + * Copyright (c) 2014 embedded brains GmbH. All rights reserved. + * + * embedded brains GmbH + * Dornierstr. 4 + * 82178 Puchheim + * Germany + * <rt...@embedded-brains.de> + * + * The license and distribution terms for this file may be + * found in the file LICENSE in this distribution or at + * http://www.rtems.com/license/LICENSE. + */ + +#ifdef HAVE_CONFIG_H + #include "config.h" +#endif + +#include <stdio.h> +#include <stdlib.h> +#include <assert.h> + +#include <rtems.h> +#include <rtems/libcsupport.h> + +#include "tmacros.h" + +static thread_local long i123 = 123; + +alignas(256) static thread_local long a256 = 256; + +static thread_local long i0; + +alignas(512) static thread_local long a512; + +static void clobber() +{ + i123 = 0xdead0001; + a256 = 0xdead0002; + i0 = 0xdead0003; + a512 = 0xdead0004; +} + +static long f456(bool clobber) +{ + static thread_local long fi456 = 456; + + if (clobber) { + fi456 = 0xdead0003; + } + + return fi456; +} + +static long f0(bool clobber) +{ + static thread_local long fi0; + + if (clobber) { + fi0 = 0xdead0004; + } + + return fi0; +} + +class C { + public: + static long c789() + { + return ci789; + } + + static long c0() + { + return ci0; + } + + static void clobber() + { + ci789 = 0xdead0005; + ci0 = 0xdead0006; + } + + private: + static thread_local long ci789; + + static thread_local long ci0; +}; + +thread_local long C::ci789 = 789; + +thread_local long C::ci0; + +class A { + public: + A(long i) + : ii(i), c(gc) + { + ++gc; + } + + ~A() + { + --gc; + } + + long i() const + { + return ii; + } + + void clobber() + { + ii = ~ii; + c = ~c; + } + + long counter() const + { + return c; + } + + static long globalCounter() + { + return gc; + } + + private: + static long gc; + + long ii; + + long c; +}; + +long A::gc; + +static volatile long mc; + +static thread_local A a1(mc + 1); +static thread_local A a2(mc + 2); +static thread_local A a3(mc + 3); + +static void checkTLSValues() +{ + assert(i123 == 123); + assert(a256 == 256); + assert((a256 & 255) == 0); + assert(i0 == 0); + assert(a512 == 0); + assert((a512 & 511) == 0); + assert(f456(false) == 456); + assert(f0(false) == 0); + assert(C::c789() == 789); + assert(C::c0() == 0); + assert(a1.i() == 1); + assert(a2.i() == 2); + assert(a3.i() == 3); +} + +static rtems_id masterTask; + +static void task(rtems_task_argument arg) +{ + checkTLSValues(); + + const long gc = static_cast<long>(arg); + + assert(A::globalCounter() == gc + 3); + + assert(a1.counter() == gc + 0); + assert(a2.counter() == gc + 1); + assert(a3.counter() == gc + 2); + + clobber(); + f456(true); + f0(true); + C::clobber(); + a1.clobber(); + a2.clobber(); + a3.clobber(); + + rtems_status_code sc = rtems_event_transient_send(masterTask); + assert(sc == RTEMS_SUCCESSFUL); + + sc = rtems_task_suspend(RTEMS_SELF); + assert(sc == RTEMS_SUCCESSFUL); +} + +static void testTask() +{ + checkTLSValues(); + + rtems_id id; + rtems_status_code sc = rtems_task_create( + rtems_build_name('T', 'A', 'S', 'K'), + RTEMS_MINIMUM_PRIORITY, + RTEMS_MINIMUM_STACK_SIZE, + RTEMS_DEFAULT_MODES, + RTEMS_DEFAULT_ATTRIBUTES, + &id + ); + assert(sc == RTEMS_SUCCESSFUL); + + const long gc = A::globalCounter(); + + sc = rtems_task_start(id, task, gc); + assert(sc == RTEMS_SUCCESSFUL); + + sc = rtems_event_transient_receive(RTEMS_WAIT, RTEMS_NO_TIMEOUT); + assert(sc == RTEMS_SUCCESSFUL); + + sc = rtems_task_delete(id); + assert(sc == RTEMS_SUCCESSFUL); + + assert(A::globalCounter() == gc); + + checkTLSValues(); +} + +extern "C" void Init(rtems_task_argument arg) +{ + puts("*** TEST SPTLS 2 ***"); + + printf("A::globalCounter() = %li\n", A::globalCounter()); + + checkTLSValues(); + + printf("A::globalCounter() = %li\n", A::globalCounter()); + + masterTask = rtems_task_self(); + + testTask(); + + rtems_resource_snapshot snapshot; + rtems_resource_snapshot_take(&snapshot); + + testTask(); + + assert(rtems_resource_snapshot_check(&snapshot)); + + puts("*** END OF TEST SPTLS 2 ***"); + + exit(0); +} + +#define CONFIGURE_APPLICATION_NEEDS_CLOCK_DRIVER +#define CONFIGURE_APPLICATION_NEEDS_CONSOLE_DRIVER + +#define CONFIGURE_MAXIMUM_TASKS 2 +#define CONFIGURE_MAXIMUM_SEMAPHORES 2 + +#define CONFIGURE_RTEMS_INIT_TASKS_TABLE + +#define CONFIGURE_INIT + +#include <rtems/confdefs.h> diff --git a/testsuites/sptests/sptls02/sptls02.doc b/testsuites/sptests/sptls02/sptls02.doc new file mode 100644 index 0000000..4417004 --- /dev/null +++ b/testsuites/sptests/sptls02/sptls02.doc @@ -0,0 +1,12 @@ +This file describes the directives and concepts tested by this test set. + +test set name: sptls02 + +directives: + + - None + +concepts: + + - Ensure that thread-local storage (TLS) works alignment requirements. + - Ensure that thread-local storage (TLS) works objects. diff --git a/testsuites/sptests/sptls02/sptls02.scn b/testsuites/sptests/sptls02/sptls02.scn new file mode 100644 index 0000000..e4c92f5 --- /dev/null +++ b/testsuites/sptests/sptls02/sptls02.scn @@ -0,0 +1,4 @@ +*** TEST SPTLS 2 *** +A::globalCounter() = 0 +A::globalCounter() = 3 +*** END OF TEST SPTLS 2 *** -- 1.7.7 _______________________________________________ rtems-devel mailing list rtems-devel@rtems.org http://www.rtems.org/mailman/listinfo/rtems-devel