From 022851aba54d32831feaff13deb3d9943e130eee Mon Sep 17 00:00:00 2001 From: Sebastian Huber Date: Tue, 28 Jan 2014 12:10:08 +0100 Subject: Add thread-local storage (TLS) support 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 | 2 + cpukit/score/cpu/arm/__aeabi_read_tp.c | 44 ++++ cpukit/score/cpu/arm/__tls_get_addr.c | 35 +++ cpukit/score/cpu/arm/armv7m-context-initialize.c | 8 +- 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 | 187 ++++++++++++++++ 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 +++ doc/cpu_supplement/Makefile.am | 46 +++- doc/cpu_supplement/arm.t | 4 + doc/cpu_supplement/avr.t | 4 + doc/cpu_supplement/bfin.t | 4 + doc/cpu_supplement/cpu_supplement.texi | 10 + doc/cpu_supplement/general.t | 27 +++ doc/cpu_supplement/h8300.t | 7 + doc/cpu_supplement/i386.t | 4 + doc/cpu_supplement/lm32.t | 4 + doc/cpu_supplement/m32c.t | 7 + doc/cpu_supplement/m32r.t | 7 + doc/cpu_supplement/m68k.t | 4 + doc/cpu_supplement/microblaze.t | 7 + doc/cpu_supplement/mips.t | 4 + doc/cpu_supplement/nios2.t | 7 + doc/cpu_supplement/powerpc.t | 4 + doc/cpu_supplement/sh.t | 4 + doc/cpu_supplement/sparc.t | 3 + doc/cpu_supplement/sparc64.t | 3 + doc/cpu_supplement/v850.t | 4 + 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 | 256 ++++++++++++++++++++++ testsuites/sptests/sptls02/sptls02.doc | 12 + testsuites/sptests/sptls02/sptls02.scn | 4 + 77 files changed, 1132 insertions(+), 60 deletions(-) create mode 100644 cpukit/score/cpu/arm/__aeabi_read_tp.c create mode 100644 cpukit/score/cpu/arm/__tls_get_addr.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 doc/cpu_supplement/h8300.t create mode 100644 doc/cpu_supplement/m32c.t create mode 100644 doc/cpu_supplement/m32r.t create mode 100644 doc/cpu_supplement/microblaze.t create mode 100644 doc/cpu_supplement/nios2.t 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 d6a883a6ad..a339f704a4 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 #include #include +#include #include /* _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 4b221294d2..871d44ea39 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 edd72480bd..fe97e03e29 100644 --- a/cpukit/score/cpu/arm/Makefile.am +++ b/cpukit/score/cpu/arm/Makefile.am @@ -15,6 +15,8 @@ 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 += __tls_get_addr.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 0000000000..afdfd99d8b --- /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 + * + * + * 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 +#include + +#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/__tls_get_addr.c b/cpukit/score/cpu/arm/__tls_get_addr.c new file mode 100644 index 0000000000..cd046518e1 --- /dev/null +++ b/cpukit/score/cpu/arm/__tls_get_addr.c @@ -0,0 +1,35 @@ +/* + * Copyright (c) 2014 embedded brains GmbH. All rights reserved. + * + * embedded brains GmbH + * Obere Lagerstr. 30 + * 82178 Puchheim + * Germany + * + * + * 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 +#include + +#include + +void *__tls_get_addr(const TLS_Index *ti); + +void *__tls_get_addr(const TLS_Index *ti) +{ + const Thread_Control *executing = _Thread_Get_executing(); + void *tls_block = (char *) executing->Start.tls_area + + _TLS_Get_thread_control_block_area_size( (uintptr_t) _TLS_Alignment ); + + assert(ti->module == 1); + + return (char *) tls_block + ti->offset; +} diff --git a/cpukit/score/cpu/arm/armv7m-context-initialize.c b/cpukit/score/cpu/arm/armv7m-context-initialize.c index 892df4d8c8..13aa0a9b19 100644 --- a/cpukit/score/cpu/arm/armv7m-context-initialize.c +++ b/cpukit/score/cpu/arm/armv7m-context-initialize.c @@ -26,6 +26,7 @@ #include #include +#include #ifdef ARM_MULTILIB_ARCH_V7M @@ -35,7 +36,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 ) { char *stack_area_end = (char *) stack_area_begin + stack_area_size; @@ -44,6 +46,10 @@ void _CPU_Context_Initialize( context->register_lr = entry_point; context->register_sp = stack_area_end; + + if ( tls_area != NULL ) { + _TLS_TCB_at_area_begin_initialize( tls_area ); + } } #endif /* ARM_MULTILIB_ARCH_V7M */ diff --git a/cpukit/score/cpu/arm/cpu.c b/cpukit/score/cpu/arm/cpu.c index 1c1fe5d3de..c3f071df55 100644 --- a/cpukit/score/cpu/arm/cpu.c +++ b/cpukit/score/cpu/arm/cpu.c @@ -32,6 +32,7 @@ #include #include #include +#include #include #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 7fb4062d50..1771ddd661 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 608f753d11..3e428f9201 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 2d9b5d50b6..216f39f862 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 b67b2416a5..f82b7637d3 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 05b9243513..268848e02b 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 1af3f81f81..a8c60a5c44 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 f75f2e5825..66774d4039 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 43422ed9d7..dd06059853 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 95553efa48..4699c1a226 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 d7c1c5dd92..b2edcf8a21 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 5841885c8e..681fb4bcd0 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 bdfd758d91..d8ecc5309d 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 0fea7bdc4b..95a897a1e2 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 863a071499..9d8d333dab 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 0000000000..3e024a84b3 --- /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 + * + * + * 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 +#include + +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 3776345769..589d099f9d 100644 --- a/cpukit/score/cpu/m68k/cpu.c +++ b/cpukit/score/cpu/m68k/cpu.c @@ -19,6 +19,7 @@ #include #include +#include #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 ccec3a6a64..9981f5393d 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 5f7abeb368..3be5df361a 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 1d1449ce6f..629996117a 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 309110a399..36a956cdc8 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 e74e04f356..6b884d0085 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 e0dfd9fd36..bdd8f57e96 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 f1f02edaf0..783da76dee 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 6263d34fb7..8eb2327b93 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 57d6ffc6db..be3fedd04d 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 41d96384de..ff9ad55ae4 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 1865a21ee8..11e31f9d10 100644 --- a/cpukit/score/cpu/sparc/cpu.c +++ b/cpukit/score/cpu/sparc/cpu.c @@ -20,6 +20,7 @@ #include #include #include +#include #include 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 690ddcf90c..ae893112f3 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 94f9340614..d7c2f47904 100644 --- a/cpukit/score/cpu/sparc64/cpu.c +++ b/cpukit/score/cpu/sparc64/cpu.c @@ -20,6 +20,7 @@ #include #include #include +#include #include /* @@ -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 8d3e27318b..22ec97d17a 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 50065b6623..d4022f36a0 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 3e110b5776..f41bde0953 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 02bcf156dd..ffffe9bb51 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 33b5244ac7..bf500fe6f5 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 0000000000..89954d9e48 --- /dev/null +++ b/cpukit/score/include/rtems/score/tls.h @@ -0,0 +1,187 @@ +/** + * @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 + * + * + * 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 + +#include + +#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; + +typedef struct { + uintptr_t module; + uintptr_t offset; +} TLS_Index; + +static inline uintptr_t _TLS_Heap_align_up( uintptr_t val ) +{ + uintptr_t msk = CPU_HEAP_ALIGNMENT - 1; + + return (val + msk) & ~msk; +} + +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 +) +{ + uintptr_t aligned_size = _TLS_Heap_align_up( size ); + + return _TLS_Get_thread_control_block_area_size( alignment ) + + aligned_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; + uintptr_t aligned_size = _TLS_Heap_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 ); +} + +/* 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)); + uintptr_t aligned_size = _TLS_Heap_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 ); +} + +/* Use Variant II */ +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_Heap_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 __cplusplus +} +#endif /* __cplusplus */ + +#endif /* _RTEMS_SCORE_TLS_H */ diff --git a/cpukit/score/preinstall.am b/cpukit/score/preinstall.am index 79a18b5dd1..f43fc9d733 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 df70f508ad..82c4ab4a39 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 34198caa80..bc2600afcb 100644 --- a/cpukit/score/src/threadinitialize.c +++ b/cpukit/score/src/threadinitialize.c @@ -20,6 +20,7 @@ #include #include #include +#include #include #include #include @@ -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_align = _TLS_Heap_align_up( (uintptr_t) _TLS_Alignment ); + uintptr_t tls_alloc = _TLS_Get_allocation_size( tls_size, tls_align ); + + the_thread->Start.tls_area = + _Workspace_Allocate_aligned( tls_alloc, tls_align ); + + 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 eb3cc63ca7..49821b0697 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 65806863c2..f437b885c0 100644 --- a/cpukit/score/src/wkspace.c +++ b/cpukit/score/src/wkspace.c @@ -21,6 +21,8 @@ #include #include #include +#include +#include #include #include /* for memset */ @@ -30,6 +32,25 @@ #include #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/doc/cpu_supplement/Makefile.am b/doc/cpu_supplement/Makefile.am index 8d117cfcd0..3083922174 100644 --- a/doc/cpu_supplement/Makefile.am +++ b/doc/cpu_supplement/Makefile.am @@ -10,8 +10,25 @@ include $(top_srcdir)/main.am REPLACE2 = $(PERL) $(top_srcdir)/tools/word-replace2 -GENERATED_FILES = general.texi arm.texi avr.texi bfin.texi i386.texi lm32.texi \ - m68k.texi mips.texi powerpc.texi sh.texi sparc.texi sparc64.texi v850.texi +GENERATED_FILES = +GENERATED_FILES += general.texi +GENERATED_FILES += arm.texi +GENERATED_FILES += avr.texi +GENERATED_FILES += bfin.texi +GENERATED_FILES += h8300.texi +GENERATED_FILES += i386.texi +GENERATED_FILES += lm32.texi +GENERATED_FILES += m32c.texi +GENERATED_FILES += m32r.texi +GENERATED_FILES += m68k.texi +GENERATED_FILES += microblaze.texi +GENERATED_FILES += mips.texi +GENERATED_FILES += powerpc.texi +GENERATED_FILES += nios2.texi +GENERATED_FILES += sh.texi +GENERATED_FILES += sparc.texi +GENERATED_FILES += sparc64.texi +GENERATED_FILES += v850.texi COMMON_FILES += $(top_srcdir)/common/cpright.texi @@ -44,11 +61,26 @@ bfin.texi: bfin.t -u "Top" \ -n "" < $< > $@ +h8300.texi: h8300.t + $(BMENU2) -p "" \ + -u "Top" \ + -n "" < $< > $@ + i386.texi: i386.t $(BMENU2) -p "" \ -u "Top" \ -n "" < $< > $@ +m32c.texi: m32c.t + $(BMENU2) -p "" \ + -u "Top" \ + -n "" < $< > $@ + +m32r.texi: m32r.t + $(BMENU2) -p "" \ + -u "Top" \ + -n "" < $< > $@ + lm32.texi: lm32.t $(BMENU2) -p "" \ -u "Top" \ @@ -59,6 +91,11 @@ m68k.texi: m68k.t -u "Top" \ -n "" < $< > $@ +microblaze.texi: microblaze.t + $(BMENU2) -p "" \ + -u "Top" \ + -n "" < $< > $@ + mips.texi: mips.t $(BMENU2) -p "" \ -u "Top" \ @@ -69,6 +106,11 @@ powerpc.texi: powerpc.t -u "Top" \ -n "" < $< > $@ +nios2.texi: nios2.t + $(BMENU2) -p "" \ + -u "Top" \ + -n "" < $< > $@ + sh.texi: sh.t $(BMENU2) -p "" \ -u "Top" \ diff --git a/doc/cpu_supplement/arm.t b/doc/cpu_supplement/arm.t index 98f9ad1ce7..790830d653 100644 --- a/doc/cpu_supplement/arm.t +++ b/doc/cpu_supplement/arm.t @@ -97,3 +97,7 @@ following actions: @item places the error code in @code{r0}, and @item executes an infinite loop to simulate a halt processor instruction. @end itemize + +@section Thread-Local Storage + +Thread-local storage is supported. diff --git a/doc/cpu_supplement/avr.t b/doc/cpu_supplement/avr.t index 6bbb68c5d3..233e0525f6 100644 --- a/doc/cpu_supplement/avr.t +++ b/doc/cpu_supplement/avr.t @@ -117,6 +117,10 @@ actions: simulate a halt processor instruction. @end itemize +@section Thread-Local Storage + +Thread-local storage is not supported due to a broken tool chain. + @section Board Support Packages diff --git a/doc/cpu_supplement/bfin.t b/doc/cpu_supplement/bfin.t index db1713ec02..320061aa87 100644 --- a/doc/cpu_supplement/bfin.t +++ b/doc/cpu_supplement/bfin.t @@ -130,6 +130,10 @@ actions: simulate a halt processor instruction. @end itemize +@section Thread-Local Storage + +Thread-local storage is not implemented. + @section Board Support Packages diff --git a/doc/cpu_supplement/cpu_supplement.texi b/doc/cpu_supplement/cpu_supplement.texi index 7195da94b2..1087538f4e 100644 --- a/doc/cpu_supplement/cpu_supplement.texi +++ b/doc/cpu_supplement/cpu_supplement.texi @@ -65,10 +65,15 @@ * ARM Specific Information:: * Atmel AVR Specific Information:: * Blackfin Specific Information:: +* Renesas H8/300 Specific Information:: * Intel/AMD x86 Specific Information:: * Lattice Mico32 Specific Information:: +* Renesas M32C Specific Information:: +* Renesas M32R Specific Information:: * M68xxx and Coldfire Specific Information:: +* Xilinx MicroBlaze Specific Information:: * MIPS Specific Information:: +* Altera Nios II Specific Information:: * PowerPC Specific Information:: * SuperH Specific Information:: * SPARC Specific Information:: @@ -83,10 +88,15 @@ @include arm.texi @include avr.texi @include bfin.texi +@include h8300.texi @include i386.texi @include lm32.texi +@include m32c.texi +@include m32r.texi @include m68k.texi +@include microblaze.texi @include mips.texi +@include nios2.texi @include powerpc.texi @include sh.texi @include sparc.texi diff --git a/doc/cpu_supplement/general.t b/doc/cpu_supplement/general.t index 3a36843b59..cf28eefd63 100644 --- a/doc/cpu_supplement/general.t +++ b/doc/cpu_supplement/general.t @@ -314,6 +314,33 @@ interrupts and halts the processor. In each of the architecture specific chapters, this describes the precise operations of the default CPU specific fatal error handler. +@section Thread-Local Storage + +In order to support thread-local storage (TLS) the CPU port must implement the +facilities mandated by the application binary interface (ABI) of the CPU +architecture. The CPU port must initialize the TLS area in the +@code{_CPU_Context_Initialize} function. + +The board support package (BSP) must provide the following sections and symbols +in its linker command file: + +@example +.tdata : @{ + _TLS_Data_begin = .; + *(.tdata .tdata.* .gnu.linkonce.td.*) + _TLS_Data_end = .; +@} +.tbss : @{ + _TLS_BSS_begin = .; + *(.tbss .tbss.* .gnu.linkonce.tb.*) *(.tcommon) + _TLS_BSS_end = .; +@} +_TLS_Data_size = _TLS_Data_end - _TLS_Data_begin; +_TLS_BSS_size = _TLS_BSS_end - _TLS_BSS_begin; +_TLS_Size = _TLS_BSS_end - _TLS_Data_begin; +_TLS_Alignment = ALIGNOF (.tdata); +@end example + @c @c @c diff --git a/doc/cpu_supplement/h8300.t b/doc/cpu_supplement/h8300.t new file mode 100644 index 0000000000..8120a31e30 --- /dev/null +++ b/doc/cpu_supplement/h8300.t @@ -0,0 +1,7 @@ +@c Copyright (c) 2014 embedded brains GmbH. All rights reserved. + +@chapter Renesas H8/300 Specific Information + +@section Thread-Local Storage + +Thread-local storage is not implemented. diff --git a/doc/cpu_supplement/i386.t b/doc/cpu_supplement/i386.t index 365c175556..716cf9bc11 100644 --- a/doc/cpu_supplement/i386.t +++ b/doc/cpu_supplement/i386.t @@ -266,6 +266,10 @@ The default fatal error handler for this architecture disables processor interrupts, places the error code in EAX, and executes a HLT instruction to halt the processor. +@section Thread-Local Storage + +Thread-local storage is not implemented. + @c @c @c diff --git a/doc/cpu_supplement/lm32.t b/doc/cpu_supplement/lm32.t index 4ac525d60c..a81e0b57ba 100644 --- a/doc/cpu_supplement/lm32.t +++ b/doc/cpu_supplement/lm32.t @@ -163,6 +163,10 @@ interrupts and halts the processor. In each of the architecture specific chapters, this describes the precise operations of the default CPU specific fatal error handler. +@section Thread-Local Storage + +Thread-local storage is not implemented. + @c @c @c diff --git a/doc/cpu_supplement/m32c.t b/doc/cpu_supplement/m32c.t new file mode 100644 index 0000000000..ce738fe0a7 --- /dev/null +++ b/doc/cpu_supplement/m32c.t @@ -0,0 +1,7 @@ +@c Copyright (c) 2014 embedded brains GmbH. All rights reserved. + +@chapter Renesas M32C Specific Information + +@section Thread-Local Storage + +Thread-local storage is not implemented. diff --git a/doc/cpu_supplement/m32r.t b/doc/cpu_supplement/m32r.t new file mode 100644 index 0000000000..f70c185f27 --- /dev/null +++ b/doc/cpu_supplement/m32r.t @@ -0,0 +1,7 @@ +@c Copyright (c) 2014 embedded brains GmbH. All rights reserved. + +@chapter Renesas M32R Specific Information + +@section Thread-Local Storage + +Thread-local storage is not implemented. diff --git a/doc/cpu_supplement/m68k.t b/doc/cpu_supplement/m68k.t index a4b888634a..a3ddc88db3 100644 --- a/doc/cpu_supplement/m68k.t +++ b/doc/cpu_supplement/m68k.t @@ -357,6 +357,10 @@ The default fatal error handler for this architecture disables processor interrupts to level 7, places the error code in D0, and executes a @code{stop} instruction to simulate a halt processor instruction. +@section Thread-Local Storage + +Thread-local storage is supported. + @c @c @c diff --git a/doc/cpu_supplement/microblaze.t b/doc/cpu_supplement/microblaze.t new file mode 100644 index 0000000000..b641d4314f --- /dev/null +++ b/doc/cpu_supplement/microblaze.t @@ -0,0 +1,7 @@ +@c Copyright (c) 2014 embedded brains GmbH. All rights reserved. + +@chapter Xilinx MicroBlaze Specific Information + +@section Thread-Local Storage + +Thread-local storage is not implemented. diff --git a/doc/cpu_supplement/mips.t b/doc/cpu_supplement/mips.t index 816c43aa0d..7d6fcb3527 100644 --- a/doc/cpu_supplement/mips.t +++ b/doc/cpu_supplement/mips.t @@ -122,6 +122,10 @@ The default fatal error handler for this target architecture disables processor interrupts, places the error code in @b{XXX}, and executes a @code{XXX} instruction to simulate a halt processor instruction. +@section Thread-Local Storage + +Thread-local storage is not implemented. + @c @c @c diff --git a/doc/cpu_supplement/nios2.t b/doc/cpu_supplement/nios2.t new file mode 100644 index 0000000000..9013f15790 --- /dev/null +++ b/doc/cpu_supplement/nios2.t @@ -0,0 +1,7 @@ +@c Copyright (c) 2014 embedded brains GmbH. All rights reserved. + +@chapter Altera Nios II Specific Information + +@section Thread-Local Storage + +Thread-local storage is not implemented. diff --git a/doc/cpu_supplement/powerpc.t b/doc/cpu_supplement/powerpc.t index 7c8b2beecf..95a6315f15 100644 --- a/doc/cpu_supplement/powerpc.t +++ b/doc/cpu_supplement/powerpc.t @@ -623,6 +623,10 @@ If the Program Exception returns, then the following actions are performed: @end itemize +@section Thread-Local Storage + +Thread-local storage is supported. + @c @c @c diff --git a/doc/cpu_supplement/sh.t b/doc/cpu_supplement/sh.t index 65b8ffa93b..763c31e96d 100644 --- a/doc/cpu_supplement/sh.t +++ b/doc/cpu_supplement/sh.t @@ -139,6 +139,10 @@ The default fatal error handler for this architecture disables processor interrupts, places the error code in @b{XXX}, and executes a @code{XXX} instruction to simulate a halt processor instruction. +@section Thread-Local Storage + +Thread-local storage is not implemented. + @c @c @c diff --git a/doc/cpu_supplement/sparc.t b/doc/cpu_supplement/sparc.t index 32f4321de6..616f79f5c2 100644 --- a/doc/cpu_supplement/sparc.t +++ b/doc/cpu_supplement/sparc.t @@ -917,6 +917,9 @@ default fatal error handler disables processor interrupts to level 15, places the error code in g1, and goes into an infinite loop to simulate a halt processor instruction. +@section Thread-Local Storage + +Thread-local storage is supported. @c @c COPYRIGHT (c) 1988-2002. diff --git a/doc/cpu_supplement/sparc64.t b/doc/cpu_supplement/sparc64.t index 047a9f5a6c..f93000893a 100644 --- a/doc/cpu_supplement/sparc64.t +++ b/doc/cpu_supplement/sparc64.t @@ -773,6 +773,9 @@ default fatal error handler disables processor interrupts to level 15, places the error code in g1, and goes into an infinite loop to simulate a halt processor instruction. +@section Thread-Local Storage + +Thread-local storage is supported. @c @c COPYRIGHT (c) 1988-2002. diff --git a/doc/cpu_supplement/v850.t b/doc/cpu_supplement/v850.t index 072e10e4e0..e8ef05ee10 100644 --- a/doc/cpu_supplement/v850.t +++ b/doc/cpu_supplement/v850.t @@ -102,3 +102,7 @@ following actions: @item places the error code in @code{r10}, and @item executes a halt processor instruction. @end itemize + +@section Thread-Local Storage + +Thread-local storage is not implemented. diff --git a/testsuites/sptests/Makefile.am b/testsuites/sptests/Makefile.am index 7eab621dc5..1eacf5ceb3 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 6b14543e9e..623e784fd5 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 0000000000..5512b8aa3d --- /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 0000000000..76bd671dff --- /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 + * + * + * 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 + +#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); + rtems_test_assert(sc == RTEMS_SUCCESSFUL); + + sc = rtems_task_suspend(RTEMS_SELF); + rtems_test_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 + ); + rtems_test_assert(sc == RTEMS_SUCCESSFUL); + + sc = rtems_task_start(id, task, 0); + rtems_test_assert(sc == RTEMS_SUCCESSFUL); + + sc = rtems_event_transient_receive(RTEMS_WAIT, RTEMS_NO_TIMEOUT); + rtems_test_assert(sc == RTEMS_SUCCESSFUL); + + sc = rtems_task_delete(id); + rtems_test_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 diff --git a/testsuites/sptests/sptls01/sptls01.doc b/testsuites/sptests/sptls01/sptls01.doc new file mode 100644 index 0000000000..a6cc38b81c --- /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 0000000000..eaeb11e21f --- /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 0000000000..d577b5b2c8 --- /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 0000000000..d70419009a --- /dev/null +++ b/testsuites/sptests/sptls02/init.cc @@ -0,0 +1,256 @@ +/* + * Copyright (c) 2014 embedded brains GmbH. All rights reserved. + * + * embedded brains GmbH + * Dornierstr. 4 + * 82178 Puchheim + * Germany + * + * + * 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 +#include + +#include +#include + +#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() +{ + rtems_test_assert(i123 == 123); + rtems_test_assert(a256 == 256); + rtems_test_assert((a256 & 255) == 0); + rtems_test_assert(i0 == 0); + rtems_test_assert(a512 == 0); + rtems_test_assert((a512 & 511) == 0); + rtems_test_assert(f456(false) == 456); + rtems_test_assert(f0(false) == 0); + rtems_test_assert(C::c789() == 789); + rtems_test_assert(C::c0() == 0); + rtems_test_assert(a1.i() == 1); + rtems_test_assert(a2.i() == 2); + rtems_test_assert(a3.i() == 3); +} + +static rtems_id masterTask; + +static void task(rtems_task_argument arg) +{ + checkTLSValues(); + + const long gc = static_cast(arg); + + rtems_test_assert(A::globalCounter() == gc + 3); + + rtems_test_assert(a1.counter() == gc + 0); + rtems_test_assert(a2.counter() == gc + 1); + rtems_test_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); + rtems_test_assert(sc == RTEMS_SUCCESSFUL); + + sc = rtems_task_suspend(RTEMS_SELF); + rtems_test_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 + ); + rtems_test_assert(sc == RTEMS_SUCCESSFUL); + + const long gc = A::globalCounter(); + + sc = rtems_task_start(id, task, gc); + rtems_test_assert(sc == RTEMS_SUCCESSFUL); + + sc = rtems_event_transient_receive(RTEMS_WAIT, RTEMS_NO_TIMEOUT); + rtems_test_assert(sc == RTEMS_SUCCESSFUL); + + sc = rtems_task_delete(id); + rtems_test_assert(sc == RTEMS_SUCCESSFUL); + + rtems_test_assert(A::globalCounter() == gc); + + checkTLSValues(); +} + +extern "C" void Init(rtems_task_argument arg) +{ + puts("\n\n*** 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(); + + rtems_test_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 3 + +#define CONFIGURE_RTEMS_INIT_TASKS_TABLE + +#define CONFIGURE_INIT + +#include diff --git a/testsuites/sptests/sptls02/sptls02.doc b/testsuites/sptests/sptls02/sptls02.doc new file mode 100644 index 0000000000..7c19462166 --- /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 thread-local storage (TLS) alignment requirements. + - Ensure thread-local storage (TLS) object construction and destruction. diff --git a/testsuites/sptests/sptls02/sptls02.scn b/testsuites/sptests/sptls02/sptls02.scn new file mode 100644 index 0000000000..e4c92f5f36 --- /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 *** -- cgit v1.2.3