Changeset d6f9fff in mainline


Ignore:
Timestamp:
2016-04-27T12:39:14Z (8 years ago)
Author:
Jakub Jermar <jakub@…>
Branches:
lfn, master, serial, ticket/834-toolchain-update, topic/msim-upgrade, topic/simplify-dev-export
Children:
1a5eca4
Parents:
8a36bc1e
Message:

ia32: Make TLS settable from uspace

The TLS document[1] mandates that %gs[0] is the thread pointer on ia32.
That is good as it allows userspace-only TLS management for fibrils:
fibril_save/restore() simply manipulate the thread pointer in %gs:0 and
don't need to ask the kernel to modify %gs's base. The kernel treats
%gs:0 as another preserved register and preserves it across context
switches. GCC gets in the way a little bit because it by default assumes
that TLS is accessible from negative %gs offsets (which would
necessitate a kernel-assisted solution). Fortunately, there is a GCC
option to suppress this assumption.

  • Introduce the concept of virtual registers, with VREG_TP (thread pointer) being the first of them
  • Preserve VREG_TP in context_save/restore()
  • Stop using sys_tls_set() in favour of using %gs:0 as the thread pointer
  • Make GCC generate code that always goes through %gs:0 to access TLS

[1] Drepper, U.: ELF Handling For Thread-Local Storage

Files:
2 added
15 edited

Legend:

Unmodified
Added
Removed
  • kernel/arch/ia32/Makefile.inc

    r8a36bc1e rd6f9fff  
    8989        arch/$(KARCH)/src/smp/ipi.c \
    9090        arch/$(KARCH)/src/ia32.c \
     91        arch/$(KARCH)/src/vreg.c \
    9192        arch/$(KARCH)/src/interrupt.c \
    9293        arch/$(KARCH)/src/pm.c \
  • kernel/arch/ia32/include/arch/asm.h

    r8a36bc1e rd6f9fff  
    439439        asm volatile (
    440440                "ltr %[sel]"
     441                :: [sel] "r" (sel)
     442        );
     443}
     444
     445/** Load GS from descriptor table.
     446 *
     447 * @param sel Selector specifying descriptor of the GS segment.
     448 *
     449 */
     450NO_TRACE static inline void gs_load(uint16_t sel)
     451{
     452        asm volatile (
     453                "mov %[sel], %%gs"
    441454                :: [sel] "r" (sel)
    442455        );
  • kernel/arch/ia32/include/arch/context_struct.ag

    r8a36bc1e rd6f9fff  
    6666                },
    6767                {
     68                        name : tp,
     69                        type : uint32_t
     70                },
     71
     72                {
    6873                        name : ipl,
    6974                        type : ipl_t
  • kernel/arch/ia32/include/arch/pm.h

    r8a36bc1e rd6f9fff  
    4545#define UDATA_DES  4
    4646#define TSS_DES    5
    47 #define TLS_DES    6  /* Pointer to Thread-Local-Storage data */
     47#define VREG_DES   6  /* Virtual registers */
    4848
    4949#ifdef CONFIG_FB
     
    169169
    170170extern void tss_initialize(tss_t *t);
    171 extern void set_tls_desc(uintptr_t tls);
    172171
    173172#endif /* __ASM__ */
  • kernel/arch/ia32/include/arch/proc/thread.h

    r8a36bc1e rd6f9fff  
    3939
    4040typedef struct {
    41         sysarg_t tls;
    4241} thread_arch_t;
    4342
  • kernel/arch/ia32/src/asm.S

    r8a36bc1e rd6f9fff  
    183183
    184184        /*
    185          * Save TLS.
    186          */
    187         movl %gs, %edx
    188         movl %edx, ISTATE_OFFSET_GS(%esp)
    189 
    190         /*
    191185         * Switch to kernel selectors.
    192186         */
    193         movw $(GDT_SELECTOR(KDATA_DES)), %ax
    194         movw %ax, %ds
    195         movw %ax, %es
     187        movl $(GDT_SELECTOR(KDATA_DES)), %eax
     188        movl %eax, %ds
     189        movl %eax, %es
     190        movl $(GDT_SELECTOR(VREG_DES)), %eax
     191        movl %eax, %gs
    196192       
    197193        /*
     
    213209       
    214210        /*
    215          * Restore TLS.
    216          */
    217         movl ISTATE_OFFSET_GS(%esp), %edx
    218         movl %edx, %gs
    219        
    220         /*
    221211         * Prepare return address and userspace stack for SYSEXIT.
    222212         */
     
    252242
    253243        /*
    254          * Save the selector registers.
     244         * Save the segment registers.
    255245         */
    256246        movl %gs, %ecx
     
    272262        movl %eax, %ds
    273263        movl %eax, %es
     264        movl $(GDT_SELECTOR(VREG_DES)), %eax
     265        movl %eax, %gs
    274266               
    275267        movl $0, ISTATE_OFFSET_EBP_FRAME(%esp)
     
    284276                       
    285277        /*
    286          * Restore the selector registers.
     278         * Restore the segment registers.
    287279         */
    288280        movl ISTATE_OFFSET_GS(%esp), %ecx
     
    354346       
    355347        /*
    356          * Save the selector registers.
     348         * Save the segment registers.
    357349         */
    358350        movl %gs, %ecx
     
    374366        movl %eax, %ds
    375367        movl %eax, %es
     368        movl $(GDT_SELECTOR(VREG_DES)), %eax
     369        movl %eax, %gs
    376370       
    377371        /*
  • kernel/arch/ia32/src/context.S

    r8a36bc1e rd6f9fff  
    2929#include <abi/asmtool.h>
    3030#include <arch/context_struct.h>
     31#include <arch/vreg.h>
    3132
    3233.text
     
    4849        movl %edi, CONTEXT_OFFSET_EDI(%edx)     # %edi -> ctx->edi
    4950        movl %ebp, CONTEXT_OFFSET_EBP(%edx)     # %ebp -> ctx->ebp
     51
     52        mov vreg_ptr, %ecx
     53        movl %gs:VREG_TP(%ecx), %ecx
     54        movl %ecx, CONTEXT_OFFSET_TP(%edx)
    5055
    5156        xorl %eax, %eax         # context_save returns 1
     
    7277
    7378        movl %edx, 0(%esp)      # put saved pc on stack
     79
     80        mov vreg_ptr, %ecx
     81        movl CONTEXT_OFFSET_TP(%eax), %edx
     82        movl %edx, %gs:VREG_TP(%ecx)
     83
    7484        xorl %eax, %eax         # context_restore returns 0
    7585        ret
    76 FUNCTION_END(context_restore_arch)
  • kernel/arch/ia32/src/ia32.c

    r8a36bc1e rd6f9fff  
    5757#include <genarch/multiboot/multiboot.h>
    5858#include <genarch/multiboot/multiboot2.h>
     59#include <arch/pm.h>
     60#include <arch/vreg.h>
    5961
    6062#ifdef CONFIG_SMP
     
    9698void arch_post_mm_init(void)
    9799{
     100        vreg_init();
     101
    98102        if (config.cpu_active == 1) {
    99103                /* Initialize IRQ routing */
     
    122126                zone_merge_all();
    123127        }
     128
    124129}
    125130
     
    223228sysarg_t sys_tls_set(uintptr_t addr)
    224229{
    225         THREAD->arch.tls = addr;
    226         set_tls_desc(addr);
    227        
    228230        return EOK;
    229231}
  • kernel/arch/ia32/src/pm.c

    r8a36bc1e rd6f9fff  
    4141#include <panic.h>
    4242#include <arch/mm/page.h>
     43#include <mm/km.h>
     44#include <mm/frame.h>
    4345#include <mm/slab.h>
    4446#include <memstr.h>
     
    5153
    5254/*
    53  * We have no use for segmentation so we set up flat mode. In this
    54  * mode, we use, for each privilege level, two segments spanning the
     55 * We don't have much use for segmentation so we set up flat mode.
     56 * In this mode, we use, for each privilege level, two segments spanning the
    5557 * whole memory. One is for code and one is for data.
    5658 *
    57  * One is for GS register which holds pointer to the TLS thread
    58  * structure in it's base.
     59 * One special segment apart of that is for the GS register which holds
     60 * a pointer to the VREG page in its base.
    5961 */
    6062descriptor_t gdt[GDT_ITEMS] = {
     
    7173        /* TSS descriptor - set up will be completed later */
    7274        { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
    73         /* TLS descriptor */
    74         { 0xffff, 0, 0, AR_PRESENT | AR_DATA | AR_WRITABLE | DPL_USER, 0xf, 0, 0, 1, 1, 0 },
     75        /* VREG descriptor - segment used for virtual registers, will be reinitialized later */
     76        { 0xffff, 0 , 0, AR_PRESENT | AR_DATA | AR_WRITABLE | DPL_USER, 0xf, 0, 0, 1, 1, 0 },
    7577        /* VESA Init descriptor */
    7678#ifdef CONFIG_FB
     
    8284static idescriptor_t idt[IDT_ITEMS];
    8385
    84 static tss_t tss;
     86static tss_t tss0;
    8587
    8688tss_t *tss_p = NULL;
     
    9597{
    9698        d->base_0_15 = base & 0xffff;
    97         d->base_16_23 = ((base) >> 16) & 0xff;
    98         d->base_24_31 = ((base) >> 24) & 0xff;
     99        d->base_16_23 = (base >> 16) & 0xff;
     100        d->base_24_31 = (base >> 24) & 0xff;
    99101}
    100102
     
    265267                 * the heap hasn't been initialized so far.
    266268                 */
    267                 tss_p = &tss;
    268         }
    269         else {
     269                tss_p = &tss0;
     270        } else {
    270271                tss_p = (tss_t *) malloc(sizeof(tss_t), FRAME_ATOMIC);
    271272                if (!tss_p)
     
    292293}
    293294
    294 void set_tls_desc(uintptr_t tls)
    295 {
    296         ptr_16_32_t cpugdtr;
    297         descriptor_t *gdt_p;
    298 
    299         gdtr_store(&cpugdtr);
    300         gdt_p = (descriptor_t *) cpugdtr.base;
    301         gdt_setbase(&gdt_p[TLS_DES], tls);
    302         /* Reload gdt register to update GS in CPU */
    303         gdtr_load(&cpugdtr);
    304 }
    305 
    306295/** @}
    307296 */
  • kernel/arch/ia32/src/proc/scheduler.c

    r8a36bc1e rd6f9fff  
    7070        CPU->arch.tss->esp0 = kstk;
    7171        CPU->arch.tss->ss0 = GDT_SELECTOR(KDATA_DES);
    72        
    73         /* Set up TLS in GS register */
    74         set_tls_desc(THREAD->arch.tls);
    7572}
    7673
  • kernel/arch/ia32/src/proc/thread.c

    r8a36bc1e rd6f9fff  
    4141void thread_create_arch(thread_t *t)
    4242{
    43         t->arch.tls = 0;
    4443}
    4544
  • kernel/arch/ia32/src/userspace.c

    r8a36bc1e rd6f9fff  
    5959                "popfl\n"
    6060               
    61                 /* Set up GS register (TLS) */
    62                 "movl %[tls_des], %%gs\n"
     61                /* Set up GS register (virtual register segment) */
     62                "movl %[vreg_des], %%gs\n"
    6363               
    6464                "pushl %[udata_des]\n"
     
    8181                  [entry] "r" (kernel_uarg->uspace_entry),
    8282                  [uarg] "r" (kernel_uarg->uspace_uarg),
    83                   [tls_des] "r" (GDT_SELECTOR(TLS_DES))
     83                  [vreg_des] "r" (GDT_SELECTOR(VREG_DES))
    8484                : "eax");
    8585       
  • uspace/lib/c/arch/ia32/Makefile.common

    r8a36bc1e rd6f9fff  
    2828
    2929ifeq ($(PROCESSOR),i486)
    30         GCC_CFLAGS += -march=i486 -fno-omit-frame-pointer
     30        GCC_CFLAGS += -march=i486 -mno-tls-direct-seg-refs -fno-omit-frame-pointer
    3131else
    32         GCC_CFLAGS += -march=pentium -fno-omit-frame-pointer
     32        GCC_CFLAGS += -march=pentium -mno-tls-direct-seg-refs -fno-omit-frame-pointer
    3333endif
    3434
  • uspace/lib/c/arch/ia32/include/libarch/tls.h

    r8a36bc1e rd6f9fff  
    4747static inline void __tcb_set(tcb_t *tcb)
    4848{
    49         __SYSCALL1(SYS_TLS_SET, (sysarg_t) tcb);
     49        asm volatile ("movl %0, %%gs:0" :: "r" (tcb));
    5050}
    5151
     
    5454        void *retval;
    5555       
    56         asm (
    57                 "movl %%gs:0, %0"
    58                 : "=r" (retval)
    59         );
     56        asm volatile ("movl %%gs:0, %0" : "=r" (retval));
    6057       
    6158        return retval;
  • uspace/lib/c/arch/ia32/src/fibril.S

    r8a36bc1e rd6f9fff  
    7777       
    7878        # set thread local storage
    79         pushl %edx
    8079        movl CONTEXT_OFFSET_TLS(%eax), %edx     # Set arg1 to TLS addr
    81         movl $1, %eax                           # Syscall SYS_TLS_SET
    82         int $0x30
    83         popl %edx
     80        movl %edx, %gs:0
    8481       
    8582        xorl %eax, %eax         # context_restore returns 0
Note: See TracChangeset for help on using the changeset viewer.