summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorSebastian Huber <sebastian.huber@embedded-brains.de>2014-01-28 12:10:08 +0100
committerSebastian Huber <sebastian.huber@embedded-brains.de>2014-02-04 10:06:35 +0100
commit022851aba54d32831feaff13deb3d9943e130eee (patch)
treec1d6a8404dae393bd147790f6a9cf09c2f327b5a
parentbsps: Thread-local storage (TLS) for linkcmds (diff)
downloadrtems-022851aba54d32831feaff13deb3d9943e130eee.tar.bz2
Add thread-local storage (TLS) support
Tested and implemented on ARM, m68k, PowerPC and SPARC. Other architectures need more work.
-rw-r--r--c/src/lib/libcpu/powerpc/new-exceptions/cpu.c16
-rw-r--r--cpukit/score/Makefile.am1
-rw-r--r--cpukit/score/cpu/arm/Makefile.am2
-rw-r--r--cpukit/score/cpu/arm/__aeabi_read_tp.c44
-rw-r--r--cpukit/score/cpu/arm/__tls_get_addr.c35
-rw-r--r--cpukit/score/cpu/arm/armv7m-context-initialize.c8
-rw-r--r--cpukit/score/cpu/arm/cpu.c20
-rw-r--r--cpukit/score/cpu/arm/cpu_asm.S10
-rw-r--r--cpukit/score/cpu/arm/rtems/score/arm.h5
-rw-r--r--cpukit/score/cpu/arm/rtems/score/cpu.h10
-rw-r--r--cpukit/score/cpu/avr/rtems/score/cpu.h3
-rw-r--r--cpukit/score/cpu/bfin/cpu.c3
-rw-r--r--cpukit/score/cpu/bfin/rtems/score/cpu.h4
-rw-r--r--cpukit/score/cpu/h8300/rtems/score/cpu.h2
-rw-r--r--cpukit/score/cpu/i386/rtems/score/cpu.h2
-rw-r--r--cpukit/score/cpu/lm32/rtems/score/cpu.h2
-rw-r--r--cpukit/score/cpu/m32c/context_init.c3
-rw-r--r--cpukit/score/cpu/m32c/rtems/score/cpu.h4
-rw-r--r--cpukit/score/cpu/m32r/context_init.c3
-rw-r--r--cpukit/score/cpu/m32r/rtems/score/cpu.h4
-rw-r--r--cpukit/score/cpu/m68k/Makefile.am1
-rw-r--r--cpukit/score/cpu/m68k/__m68k_read_tp.c36
-rw-r--r--cpukit/score/cpu/m68k/cpu.c27
-rw-r--r--cpukit/score/cpu/m68k/rtems/score/cpu.h33
-rw-r--r--cpukit/score/cpu/mips/cpu.c3
-rw-r--r--cpukit/score/cpu/mips/rtems/score/cpu.h3
-rw-r--r--cpukit/score/cpu/moxie/rtems/score/cpu.h2
-rw-r--r--cpukit/score/cpu/nios2/nios2-context-initialize.c3
-rw-r--r--cpukit/score/cpu/nios2/rtems/score/cpu.h4
-rw-r--r--cpukit/score/cpu/no_cpu/rtems/score/cpu.h3
-rw-r--r--cpukit/score/cpu/powerpc/rtems/score/cpu.h3
-rw-r--r--cpukit/score/cpu/sh/cpu.c3
-rw-r--r--cpukit/score/cpu/sh/rtems/score/cpu.h3
-rw-r--r--cpukit/score/cpu/sparc/cpu.c10
-rw-r--r--cpukit/score/cpu/sparc/rtems/score/cpu.h4
-rw-r--r--cpukit/score/cpu/sparc64/cpu.c10
-rw-r--r--cpukit/score/cpu/sparc64/rtems/score/cpu.h3
-rw-r--r--cpukit/score/cpu/v850/cpu.c3
-rw-r--r--cpukit/score/cpu/v850/rtems/score/cpu.h4
-rw-r--r--cpukit/score/include/rtems/score/context.h7
-rw-r--r--cpukit/score/include/rtems/score/thread.h2
-rw-r--r--cpukit/score/include/rtems/score/tls.h187
-rw-r--r--cpukit/score/preinstall.am4
-rw-r--r--cpukit/score/src/threadclose.c2
-rw-r--r--cpukit/score/src/threadinitialize.c18
-rw-r--r--cpukit/score/src/threadloadenv.c3
-rw-r--r--cpukit/score/src/wkspace.c30
-rw-r--r--doc/cpu_supplement/Makefile.am46
-rw-r--r--doc/cpu_supplement/arm.t4
-rw-r--r--doc/cpu_supplement/avr.t4
-rw-r--r--doc/cpu_supplement/bfin.t4
-rw-r--r--doc/cpu_supplement/cpu_supplement.texi10
-rw-r--r--doc/cpu_supplement/general.t27
-rw-r--r--doc/cpu_supplement/h8300.t7
-rw-r--r--doc/cpu_supplement/i386.t4
-rw-r--r--doc/cpu_supplement/lm32.t4
-rw-r--r--doc/cpu_supplement/m32c.t7
-rw-r--r--doc/cpu_supplement/m32r.t7
-rw-r--r--doc/cpu_supplement/m68k.t4
-rw-r--r--doc/cpu_supplement/microblaze.t7
-rw-r--r--doc/cpu_supplement/mips.t4
-rw-r--r--doc/cpu_supplement/nios2.t7
-rw-r--r--doc/cpu_supplement/powerpc.t4
-rw-r--r--doc/cpu_supplement/sh.t4
-rw-r--r--doc/cpu_supplement/sparc.t3
-rw-r--r--doc/cpu_supplement/sparc64.t3
-rw-r--r--doc/cpu_supplement/v850.t4
-rw-r--r--testsuites/sptests/Makefile.am4
-rw-r--r--testsuites/sptests/configure.ac7
-rw-r--r--testsuites/sptests/sptls01/Makefile.am19
-rw-r--r--testsuites/sptests/sptls01/init.c98
-rw-r--r--testsuites/sptests/sptls01/sptls01.doc11
-rw-r--r--testsuites/sptests/sptls01/sptls01.scn5
-rw-r--r--testsuites/sptests/sptls02/Makefile.am20
-rw-r--r--testsuites/sptests/sptls02/init.cc256
-rw-r--r--testsuites/sptests/sptls02/sptls02.doc12
-rw-r--r--testsuites/sptests/sptls02/sptls02.scn4
77 files changed, 1132 insertions, 60 deletions
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 <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 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
+ * <rtems@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/__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
+ * <rtems@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>
+
+#include <assert.h>
+
+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 <rtems/score/armv7m.h>
#include <rtems/score/thread.h>
+#include <rtems/score/tls.h>
#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 <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 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
+ * <rtems@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 3776345769..589d099f9d 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 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 <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 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 <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 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
+ * <rtems@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/cpu.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;
+
+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 <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_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 <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/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
+ * <rtems@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);
+ 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 <rtems/confdefs.h>
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
+ * <rtems@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 <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()
+{
+ 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<long>(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 <rtems/confdefs.h>
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 ***