Changeset 1a5eca4 in mainline for kernel/arch/amd64/src


Ignore:
Timestamp:
2016-04-27T19:36:56Z (9 years ago)
Author:
Jakub Jermar <jakub@…>
Branches:
lfn, master, serial, ticket/834-toolchain-update, topic/msim-upgrade, topic/simplify-dev-export
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

Location:
kernel/arch/amd64/src
Files:
2 added
5 edited

Legend:

Unmodified
Added
Removed
  • 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}
Note: See TracChangeset for help on using the changeset viewer.