[PATCH] i386: Support thread-local storage (TLS)

Sebastian Huber sebastian.huber at embedded-brains.de
Fri Jun 9 13:43:11 UTC 2017


Close #2468.
---
 c/src/lib/libbsp/i386/pc386/include/tblsizes.h |  3 ++-
 c/src/lib/libbsp/i386/pc386/startup/ldsegs.S   | 10 +++++++---
 c/src/lib/libbsp/i386/shared/irq/idt.c         |  3 ++-
 cpukit/score/cpu/i386/cpu.c                    |  6 ++++++
 cpukit/score/cpu/i386/cpu_asm.S                | 10 ++++++++++
 cpukit/score/cpu/i386/rtems/score/cpu.h        |  4 +++-
 cpukit/score/include/rtems/score/tls.h         | 23 +++++++++++++++++++----
 7 files changed, 49 insertions(+), 10 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..a9e12d9c75 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>
@@ -42,6 +43,7 @@ I386_ASSERT_OFFSET(ebp, EBP);
 I386_ASSERT_OFFSET(ebx, EBX);
 I386_ASSERT_OFFSET(esi, ESI);
 I386_ASSERT_OFFSET(edi, EDI);
+I386_ASSERT_OFFSET(gs, GS);
 
 #ifdef RTEMS_SMP
   I386_ASSERT_OFFSET(is_executing, IS_EXECUTING);
@@ -168,6 +170,10 @@ void _CPU_Context_Initialize(
   *((proc_ptr *)(_stack)) = (_entry_point);
   the_context->ebp     = (void *) 0;
   the_context->esp     = (void *) _stack;
+
+  if ( tls_area != NULL ) {
+    the_context->gs = _TLS_TCB_after_TLS_block_initialize( tls_area );
+  }
 }
 
 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..f4eb38b8bd 100644
--- a/cpukit/score/cpu/i386/cpu_asm.S
+++ b/cpukit/score/cpu/i386/cpu_asm.S
@@ -32,6 +32,7 @@
 .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,      I386_CONTEXT_CONTROL_GS_OFFSET
 
         BEGIN_CODE
 
@@ -83,6 +84,15 @@ 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(eax), ecx
+        movw      cx, _Global_descriptor_table + 26
+        movl      ecx, edx
+        shrl      $16, edx
+        movb      dl, _Global_descriptor_table + 28
+        shrl      $24, ecx
+        movb      cl, _Global_descriptor_table + 31
+        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..4aea2e1669 100644
--- a/cpukit/score/cpu/i386/rtems/score/cpu.h
+++ b/cpukit/score/cpu/i386/rtems/score/cpu.h
@@ -122,9 +122,10 @@ 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_OFFSET 24
 
 #ifdef RTEMS_SMP
-  #define I386_CONTEXT_CONTROL_IS_EXECUTING_OFFSET 24
+  #define I386_CONTEXT_CONTROL_IS_EXECUTING_OFFSET 28
 #endif
 
 /* structures */
@@ -142,6 +143,7 @@ typedef struct {
   uint32_t    ebx;      /* extended bx register                      */
   uint32_t    esi;      /* extended source index register            */
   uint32_t    edi;      /* extended destination index flags register */
+  void       *gs;       /* thread pointer                            */
 #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 );
 }
-- 
2.12.3



More information about the devel mailing list