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