summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorSebastian Huber <sebastian.huber@embedded-brains.de>2017-06-09 15:42:36 +0200
committerSebastian Huber <sebastian.huber@embedded-brains.de>2017-06-12 08:01:58 +0200
commit7b0c74ffb085656d67554102857224223ee03f88 (patch)
treed2cf69f695da218e67c6c5cb7d26f82c3fc967be
parenti386: Move _CPU_Context_Initialize() (diff)
downloadrtems-7b0c74ffb085656d67554102857224223ee03f88.tar.bz2
i386: Support thread-local storage (TLS)
Update #2468.
-rw-r--r--c/src/lib/libbsp/i386/pc386/include/tblsizes.h3
-rw-r--r--c/src/lib/libbsp/i386/pc386/startup/ldsegs.S10
-rw-r--r--c/src/lib/libbsp/i386/shared/irq/idt.c3
-rw-r--r--cpukit/score/cpu/i386/cpu.c25
-rw-r--r--cpukit/score/cpu/i386/cpu_asm.S8
-rw-r--r--cpukit/score/cpu/i386/rtems/score/cpu.h17
-rw-r--r--cpukit/score/include/rtems/score/tls.h23
7 files changed, 73 insertions, 16 deletions
diff --git a/c/src/lib/libbsp/i386/pc386/include/tblsizes.h b/c/src/lib/libbsp/i386/pc386/include/tblsizes.h
index bd4e9896bf..cea8619c8f 100644
--- a/c/src/lib/libbsp/i386/pc386/include/tblsizes.h
+++ b/c/src/lib/libbsp/i386/pc386/include/tblsizes.h
@@ -20,4 +20,5 @@
#include <bspopts.h>
#define IDT_SIZE (256)
-#define GDT_SIZE (3 + NUM_APP_DRV_GDT_DESCRIPTORS)
+#define NUM_SYSTEM_GDT_DESCRIPTORS 4
+#define GDT_SIZE (NUM_SYSTEM_GDT_DESCRIPTORS + NUM_APP_DRV_GDT_DESCRIPTORS)
diff --git a/c/src/lib/libbsp/i386/pc386/startup/ldsegs.S b/c/src/lib/libbsp/i386/pc386/startup/ldsegs.S
index ea41874a1b..626d5a02d4 100644
--- a/c/src/lib/libbsp/i386/pc386/startup/ldsegs.S
+++ b/c/src/lib/libbsp/i386/pc386/startup/ldsegs.S
@@ -171,8 +171,8 @@ next_step:
/*---------------------------------------------------------------------------+
| GDT itself
+--------------------------------------------------------------------------*/
-#if GDT_SIZE < 3
-#error "GDT_SIZE must be at least 3"
+#if GDT_SIZE < NUM_SYSTEM_GDT_DESCRIPTORS
+#error "GDT_SIZE must be at least NUM_SYSTEM_GDT_DESCRIPTORS"
#endif
BEGIN_DATA
@@ -193,8 +193,12 @@ SYM (_Global_descriptor_table):
.word 0xffff, 0
.byte 0, 0x92, 0xcf, 0
+ /* gs segment */
+ .word 0xffff, 0
+ .byte 0, 0x92, 0xcf, 0
+
/* allocated space for user segments */
- .rept (GDT_SIZE - 3)
+ .rept (GDT_SIZE - NUM_SYSTEM_GDT_DESCRIPTORS)
.word 0,0,0,0
.endr
diff --git a/c/src/lib/libbsp/i386/shared/irq/idt.c b/c/src/lib/libbsp/i386/shared/irq/idt.c
index ac79a97004..d3adbc4f05 100644
--- a/c/src/lib/libbsp/i386/shared/irq/idt.c
+++ b/c/src/lib/libbsp/i386/shared/irq/idt.c
@@ -18,6 +18,7 @@
#include <rtems/score/cpu.h>
#include <bsp/irq.h>
+#include <bsp/tblsizes.h>
/*
* This locking is not enough if IDT is changed at runtime
@@ -331,7 +332,7 @@ uint16_t i386_next_empty_gdt_entry ()
uint16_t gdt_limit;
segment_descriptors* gdt_entry_tbl;
/* initial amount of filled descriptors */
- static uint16_t segment_selector_index = 2;
+ static uint16_t segment_selector_index = NUM_SYSTEM_GDT_DESCRIPTORS - 1;
segment_selector_index += 1;
i386_get_info_from_GDTR (&gdt_entry_tbl, &gdt_limit);
diff --git a/cpukit/score/cpu/i386/cpu.c b/cpukit/score/cpu/i386/cpu.c
index 804afb1647..c9434f7c86 100644
--- a/cpukit/score/cpu/i386/cpu.c
+++ b/cpukit/score/cpu/i386/cpu.c
@@ -24,6 +24,7 @@
#include <rtems/score/types.h>
#include <rtems/score/isr.h>
#include <rtems/score/idtr.h>
+#include <rtems/score/tls.h>
#include <rtems/bspIo.h>
#include <rtems/score/percpu.h>
@@ -43,6 +44,12 @@ I386_ASSERT_OFFSET(ebx, EBX);
I386_ASSERT_OFFSET(esi, ESI);
I386_ASSERT_OFFSET(edi, EDI);
+RTEMS_STATIC_ASSERT(
+ offsetof(Context_Control, gs)
+ == I386_CONTEXT_CONTROL_GS_0_OFFSET,
+ Context_Control_gs_0
+);
+
#ifdef RTEMS_SMP
I386_ASSERT_OFFSET(is_executing, IS_EXECUTING);
#endif
@@ -153,6 +160,7 @@ void _CPU_Context_Initialize(
)
{
uint32_t _stack;
+ uint32_t tcb;
(void) is_fp; /* avoid warning for being unused */
@@ -168,6 +176,23 @@ void _CPU_Context_Initialize(
*((proc_ptr *)(_stack)) = (_entry_point);
the_context->ebp = (void *) 0;
the_context->esp = (void *) _stack;
+
+ if ( tls_area != NULL ) {
+ tcb = (uint32_t) _TLS_TCB_after_TLS_block_initialize( tls_area );
+ } else {
+ tcb = 0;
+ }
+
+ the_context->gs.limit_15_0 = 0xffff;
+ the_context->gs.base_address_15_0 = (tcb >> 0) & 0xffff;
+ the_context->gs.type = 0x2;
+ the_context->gs.descriptor_type = 0x1;
+ the_context->gs.limit_19_16 = 0xf;
+ the_context->gs.present = 0x1;
+ the_context->gs.operation_size = 0x1;
+ the_context->gs.granularity = 0x1;
+ the_context->gs.base_address_23_16 = (tcb >> 16) & 0xff;
+ the_context->gs.base_address_31_24 = (tcb >> 24) & 0xff;
}
uint32_t _CPU_ISR_Get_level( void )
diff --git a/cpukit/score/cpu/i386/cpu_asm.S b/cpukit/score/cpu/i386/cpu_asm.S
index 45079a65b8..6b609ab4ce 100644
--- a/cpukit/score/cpu/i386/cpu_asm.S
+++ b/cpukit/score/cpu/i386/cpu_asm.S
@@ -32,6 +32,8 @@
.set REG_EBX, I386_CONTEXT_CONTROL_EBX_OFFSET
.set REG_ESI, I386_CONTEXT_CONTROL_ESI_OFFSET
.set REG_EDI, I386_CONTEXT_CONTROL_EDI_OFFSET
+.set REG_GS_0, I386_CONTEXT_CONTROL_GS_0_OFFSET
+.set REG_GS_1, I386_CONTEXT_CONTROL_GS_1_OFFSET
BEGIN_CODE
@@ -83,6 +85,12 @@ restore:
movl REG_EBX(eax),ebx /* restore ebx */
movl REG_ESI(eax),esi /* restore source register */
movl REG_EDI(eax),edi /* restore destination register */
+ movl REG_GS_0(eax), ecx /* restore gs segment */
+ movl REG_GS_1(eax), edx
+ movl ecx, _Global_descriptor_table + 24
+ movl edx, _Global_descriptor_table + 28
+ movl $24, ecx
+ mov ecx, gs
ret
/*
diff --git a/cpukit/score/cpu/i386/rtems/score/cpu.h b/cpukit/score/cpu/i386/rtems/score/cpu.h
index 64f049ed0b..f78149c24b 100644
--- a/cpukit/score/cpu/i386/rtems/score/cpu.h
+++ b/cpukit/score/cpu/i386/rtems/score/cpu.h
@@ -122,9 +122,11 @@ extern "C" {
#define I386_CONTEXT_CONTROL_EBX_OFFSET 12
#define I386_CONTEXT_CONTROL_ESI_OFFSET 16
#define I386_CONTEXT_CONTROL_EDI_OFFSET 20
+#define I386_CONTEXT_CONTROL_GS_0_OFFSET 24
+#define I386_CONTEXT_CONTROL_GS_1_OFFSET 28
#ifdef RTEMS_SMP
- #define I386_CONTEXT_CONTROL_IS_EXECUTING_OFFSET 24
+ #define I386_CONTEXT_CONTROL_IS_EXECUTING_OFFSET 32
#endif
/* structures */
@@ -136,12 +138,13 @@ extern "C" {
*/
typedef struct {
- uint32_t eflags; /* extended flags register */
- void *esp; /* extended stack pointer register */
- void *ebp; /* extended base pointer register */
- uint32_t ebx; /* extended bx register */
- uint32_t esi; /* extended source index register */
- uint32_t edi; /* extended destination index flags register */
+ uint32_t eflags; /* extended flags register */
+ void *esp; /* extended stack pointer register */
+ void *ebp; /* extended base pointer register */
+ uint32_t ebx; /* extended bx register */
+ uint32_t esi; /* extended source index register */
+ uint32_t edi; /* extended destination index flags register */
+ segment_descriptors gs; /* gs segment descriptor */
#ifdef RTEMS_SMP
volatile bool is_executing;
#endif
diff --git a/cpukit/score/include/rtems/score/tls.h b/cpukit/score/include/rtems/score/tls.h
index 51398a0a35..644e54e6f7 100644
--- a/cpukit/score/include/rtems/score/tls.h
+++ b/cpukit/score/include/rtems/score/tls.h
@@ -70,9 +70,13 @@ typedef struct {
void *tls_blocks[1];
} TLS_Dynamic_thread_vector;
-typedef struct {
+typedef struct TLS_Thread_control_block {
+#ifdef __i386__
+ struct TLS_Thread_control_block *tcb;
+#else
TLS_Dynamic_thread_vector *dtv;
uintptr_t reserved;
+#endif
} TLS_Thread_control_block;
typedef struct {
@@ -109,10 +113,16 @@ static inline uintptr_t _TLS_Get_allocation_size(
uintptr_t alignment
)
{
- uintptr_t aligned_size = _TLS_Heap_align_up( size );
+ uintptr_t allocation_size = 0;
+
+ allocation_size += _TLS_Heap_align_up( size );
+ allocation_size += _TLS_Get_thread_control_block_area_size( alignment );
+
+#ifndef __i386__
+ allocation_size += sizeof(TLS_Dynamic_thread_vector);
+#endif
- return _TLS_Get_thread_control_block_area_size( alignment )
- + aligned_size + sizeof(TLS_Dynamic_thread_vector);
+ return allocation_size;
}
static inline void *_TLS_Copy_and_clear( void *tls_area )
@@ -140,9 +150,14 @@ static inline void *_TLS_Initialize(
TLS_Dynamic_thread_vector *dtv
)
{
+#ifdef __i386__
+ (void) dtv;
+ tcb->tcb = tcb;
+#else
tcb->dtv = dtv;
dtv->generation_number = 1;
dtv->tls_blocks[0] = tls_block;
+#endif
return _TLS_Copy_and_clear( tls_block );
}