Fork us on GitHub Follow us on Facebook Follow us on Twitter

Changeset 1a5eca4 in mainline


Ignore:
Timestamp:
2016-04-27T19:36:56Z (6 years ago)
Author:
Jakub Jermar <jakub@…>
Branches:
lfn, master
Children:
af9dd1e
Parents:
d6f9fff
Message:

amd64: Make TLS settable from uspace

The TLS document[1] mandates that %fs[0] is the thread pointer on amd64.
That is good as it allows userspace-only TLS management for fibrils:
fibril_save/restore() simply manipulate the thread pointer in %fs:0 and
don't need to ask the kernel to modify %fs's base. The kernel treats
%fs: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 %fs 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 %fs:0 as the thread pointer
  • Make GCC generate code that always goes through %gs:0 to access TLS
  • Introduce kseg: a per-CPU area accessible from GS_KERNEL that holds the kernel stack, kernel FS base and a scratch space for syscall and int handlers to use

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

Files:
5 added
13 edited

Legend:

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

    rd6f9fff r1a5eca4  
    5757        arch/$(KARCH)/src/debug/stacktrace_asm.S \
    5858        arch/$(KARCH)/src/pm.c \
     59        arch/$(KARCH)/src/vreg.c \
     60        arch/$(KARCH)/src/kseg.c \
    5961        arch/$(KARCH)/src/context.S \
    6062        arch/$(KARCH)/src/ddi/ddi.c \
     
    9092ARCH_AUTOGENS_AG = \
    9193        arch/$(KARCH)/include/arch/istate_struct.ag \
    92         arch/$(KARCH)/include/arch/context_struct.ag
     94        arch/$(KARCH)/include/arch/context_struct.ag \
     95        arch/$(KARCH)/include/arch/kseg_struct.ag
  • kernel/arch/amd64/include/arch/asm.h

    rd6f9fff r1a5eca4  
    206206        } else
    207207                *port = val;
    208 }
    209 
    210 /** Swap Hidden part of GS register with visible one */
    211 NO_TRACE static inline void swapgs(void)
    212 {
    213         asm volatile (
    214                 "swapgs"
    215         );
    216208}
    217209
  • kernel/arch/amd64/include/arch/context_struct.ag

    rd6f9fff r1a5eca4  
    7575                        type : uint64_t
    7676                },
     77                {
     78                        name : tp,
     79                        type : uint64_t
     80                },
    7781
    7882                {
  • kernel/arch/amd64/include/arch/cpu.h

    rd6f9fff r1a5eca4  
    5656
    5757/* MSR registers */
    58 #define AMD_MSR_STAR    0xc0000081
    59 #define AMD_MSR_LSTAR   0xc0000082
    60 #define AMD_MSR_SFMASK  0xc0000084
    61 #define AMD_MSR_FS      0xc0000100
    62 #define AMD_MSR_GS      0xc0000101
     58#define AMD_MSR_STAR            0xc0000081
     59#define AMD_MSR_LSTAR           0xc0000082
     60#define AMD_MSR_SFMASK          0xc0000084
     61#define AMD_MSR_FS              0xc0000100
     62#define AMD_MSR_GS              0xc0000101
     63#define AMD_MSR_GS_KERNEL       0xc0000102
    6364
    6465#ifndef __ASM__
  • kernel/arch/amd64/include/arch/proc/thread.h

    rd6f9fff r1a5eca4  
    3636#define KERN_amd64_THREAD_H_
    3737
    38 /* CAUTION: keep these in sync with low level assembly code in syscall_entry */
    39 #define SYSCALL_USTACK_RSP  0
    40 #define SYSCALL_KSTACK_RSP  1
     38#include <typedefs.h>
    4139
    4240typedef struct {
    43         sysarg_t tls;
    44         /** User and kernel RSP for syscalls. */
    45         uint64_t syscall_rsp[2];
     41        uint64_t kstack_rsp;
    4642} thread_arch_t;
    4743
  • kernel/arch/amd64/src/amd64.c

    rd6f9fff r1a5eca4  
    5656#include <genarch/multiboot/multiboot.h>
    5757#include <genarch/multiboot/multiboot2.h>
     58#include <arch/pm.h>
     59#include <arch/vreg.h>
     60#include <arch/kseg.h>
    5861
    5962#ifdef CONFIG_SMP
     
    139142void arch_post_mm_init(void)
    140143{
     144        vreg_init();
     145        kseg_init();
     146
    141147        if (config.cpu_active == 1) {
    142148                /* Initialize IRQ routing */
     
    272278sysarg_t sys_tls_set(uintptr_t addr)
    273279{
    274         THREAD->arch.tls = addr;
    275         write_msr(AMD_MSR_FS, addr);
    276        
    277280        return EOK;
    278281}
  • kernel/arch/amd64/src/asm.S

    rd6f9fff r1a5eca4  
    3131#include <arch/mm/page.h>
    3232#include <arch/istate_struct.h>
     33#include <arch/kseg_struct.h>
     34#include <arch/cpu.h>
    3335
    3436.text
     
    178180                subq $(ISTATE_SOFT_SIZE + 8), %rsp
    179181        .endif
    180        
     182
    181183        /*
    182184         * Save the general purpose registers.
     
    199201
    200202        /*
     203         * Is this trap from the kernel?
     204         */
     205        cmpq $(GDT_SELECTOR(KTEXT_DES)), ISTATE_OFFSET_CS(%rsp)
     206        jz 0f
     207
     208        /*
     209         * Switch to kernel FS base.
     210         */
     211        swapgs
     212        movl $AMD_MSR_FS, %ecx
     213        movl %gs:KSEG_OFFSET_FSBASE, %eax
     214        movl %gs:KSEG_OFFSET_FSBASE+4, %edx
     215        wrmsr
     216        swapgs
     217
     218        /*
    201219         * Imitate a regular stack frame linkage.
    202220         * Stop stack traces here if we came from userspace.
    203221         */
    204         xorl %edx, %edx
    205         cmpq $(GDT_SELECTOR(KTEXT_DES)), ISTATE_OFFSET_CS(%rsp)
     2220:      movl $0x0, %edx
    206223        cmovnzq %rdx, %rbp
    207224
     
    272289        swapgs
    273290       
    274         /*
    275          * %gs:0 Scratch space for this thread's user RSP
    276          * %gs:8 Address to be used as this thread's kernel RSP
    277          */
    278        
    279         movq %rsp, %gs:0  /* save this thread's user RSP */
    280         movq %gs:8, %rsp  /* set this thread's kernel RSP */
    281        
     291        movq %rsp, %gs:KSEG_OFFSET_USTACK_RSP  /* save this thread's user RSP */
     292        movq %gs:KSEG_OFFSET_KSTACK_RSP, %rsp  /* set this thread's kernel RSP */
     293
    282294        /*
    283295         * Note that the space needed for the imitated istate structure has been
     
    308320
    309321        /*
     322         * Switch to kernel FS base.
     323         */
     324        movl $AMD_MSR_FS, %ecx
     325        movl %gs:KSEG_OFFSET_FSBASE, %eax
     326        movl %gs:KSEG_OFFSET_FSBASE+4, %edx
     327        wrmsr
     328        movq ISTATE_OFFSET_RDX(%rsp), %rdx      /* restore 3rd argument */
     329
     330        /*
    310331         * Save the return address and the userspace stack on locations that
    311332         * would normally be taken by them.
    312333         */
    313         movq %gs:0, %rax
     334        movq %gs:KSEG_OFFSET_USTACK_RSP, %rax
    314335        movq %rax, ISTATE_OFFSET_RSP(%rsp)
    315336        movq %rcx, ISTATE_OFFSET_RIP(%rsp)
     
    325346        swapgs
    326347        sti
    327        
     348
    328349        /* Copy the 4th argument where it is expected  */
    329350        movq %r10, %rcx
  • kernel/arch/amd64/src/context.S

    rd6f9fff r1a5eca4  
    2929#include <abi/asmtool.h>
    3030#include <arch/context_struct.h>
     31#include <arch/vreg.h>
    3132
    3233.text
     
    5051        movq %r14, CONTEXT_OFFSET_R14(%rdi)
    5152        movq %r15, CONTEXT_OFFSET_R15(%rdi)
     53
     54        movq vreg_ptr, %rsi
     55        movq %fs:VREG_TP(%rsi), %rsi
     56        movq %rsi, CONTEXT_OFFSET_TP(%rdi)
    5257       
    5358        xorl %eax, %eax       # context_save returns 1
     
    7277        movq CONTEXT_OFFSET_SP(%rdi), %rsp   # ctx->sp -> %rsp
    7378       
    74         movq CONTEXT_OFFSET_PC(%rdi), %rdx
    75        
     79        movq CONTEXT_OFFSET_PC(%rdi), %rdx
    7680        movq %rdx, (%rsp)
     81
     82        movq CONTEXT_OFFSET_TP(%rdi), %rcx
     83        movq vreg_ptr, %rsi
     84        movq %rcx, %fs:VREG_TP(%rsi)
    7785       
    7886        xorl %eax, %eax       # context_restore returns 0
  • kernel/arch/amd64/src/proc/scheduler.c

    rd6f9fff r1a5eca4  
    4242#include <arch/pm.h>
    4343#include <arch/ddi/ddi.h>
     44#include <arch/kseg_struct.h>
    4445
    4546/** Perform amd64 specific tasks needed before the new task is run.
     
    5556void before_thread_runs_arch(void)
    5657{
    57         CPU->arch.tss->rsp0 =
    58             (uintptr_t) &THREAD->kstack[STACK_SIZE];
    59        
    60         /*
    61          * Syscall support.
    62          */
    63         swapgs();
    64         write_msr(AMD_MSR_GS, (uintptr_t) THREAD->arch.syscall_rsp);
    65         swapgs();
    66        
    67         /* TLS support - set FS to thread local storage */
    68         write_msr(AMD_MSR_FS, THREAD->arch.tls);
     58        CPU->arch.tss->rsp0 = (uintptr_t) &THREAD->kstack[STACK_SIZE];
     59
     60        kseg_t *kseg = (kseg_t *) read_msr(AMD_MSR_GS_KERNEL); 
     61        kseg->kstack_rsp = THREAD->arch.kstack_rsp;
    6962}
    7063
  • kernel/arch/amd64/src/proc/thread.c

    rd6f9fff r1a5eca4  
    3535#include <proc/thread.h>
    3636#include <arch/interrupt.h>
     37#include <arch/kseg_struct.h>
    3738
    3839/** Perform amd64 specific thread initialization.
     
    4344void thread_create_arch(thread_t *thread)
    4445{
    45         thread->arch.tls = 0;
    46         thread->arch.syscall_rsp[SYSCALL_USTACK_RSP] = 0;
    47        
    4846        /*
    4947         * Kernel RSP can be precalculated at thread creation time.
    5048         */
    51         thread->arch.syscall_rsp[SYSCALL_KSTACK_RSP] =
     49        thread->arch.kstack_rsp =
    5250            (uintptr_t) &thread->kstack[PAGE_SIZE - sizeof(istate_t)];
    5351}
  • uspace/lib/c/arch/amd64/Makefile.common

    rd6f9fff r1a5eca4  
    2727#
    2828
    29 GCC_CFLAGS += -fno-omit-frame-pointer
     29GCC_CFLAGS += -mno-tls-direct-seg-refs -fno-omit-frame-pointer
    3030CLANG_CFLAGS += -fno-omit-frame-pointer
    3131
  • uspace/lib/c/arch/amd64/include/libarch/tls.h

    rd6f9fff r1a5eca4  
    4747static inline void __tcb_set(tcb_t *tcb)
    4848{
    49         __SYSCALL1(SYS_TLS_SET, (sysarg_t) tcb);
     49        asm volatile ("movq %0, %%fs:0" :: "r" (tcb));
    5050}
    5151
    52 static inline tcb_t * __tcb_get(void)
     52static inline tcb_t *__tcb_get(void)
    5353{
    54         void * retval;
     54        void *retval;
    5555
    56         asm ("movq %%fs:0, %0" : "=r"(retval));
     56        asm volatile ("movq %%fs:0, %0" : "=r" (retval));
    5757        return retval;
    5858}
  • uspace/lib/c/arch/amd64/src/fibril.S

    rd6f9fff r1a5eca4  
    5151        movq %r15, CONTEXT_OFFSET_R15(%rdi)
    5252       
    53         # save TLS
    5453        movq %fs:0, %rax
    5554        movq %rax, CONTEXT_OFFSET_TLS(%rdi)
     
    7978        movq %rdx,(%rsp)
    8079       
    81         # Set thread local storage
    82         movq CONTEXT_OFFSET_TLS(%rdi), %rdi  # Set arg1 to TLS addr
    83         movl $1, %eax                        # SYS_TLS_SET
    84         syscall
     80        movq CONTEXT_OFFSET_TLS(%rdi), %rdi
     81        movq %rdi, %fs:0
    8582       
    8683        xorl %eax, %eax                      # context_restore returns 0
Note: See TracChangeset for help on using the changeset viewer.