From 7b0c74ffb085656d67554102857224223ee03f88 Mon Sep 17 00:00:00 2001 From: Sebastian Huber Date: Fri, 9 Jun 2017 15:42:36 +0200 Subject: i386: Support thread-local storage (TLS) Update #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 | 25 +++++++++++++++++++++++++ cpukit/score/cpu/i386/cpu_asm.S | 8 ++++++++ cpukit/score/cpu/i386/rtems/score/cpu.h | 17 ++++++++++------- cpukit/score/include/rtems/score/tls.h | 23 +++++++++++++++++++---- 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 #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 #include +#include /* * 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 #include #include +#include #include #include @@ -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 ); } -- cgit v1.2.3