1// Copyright 2016 The Fuchsia Authors 2// Copyright (c) 2009 Corey Tabaka 3// Copyright (c) 2014 Travis Geiselbrecht 4// Copyright (c) 2015 Intel Corporation 5// 6// Use of this source code is governed by a MIT-style 7// license that can be found in the LICENSE file or at 8// https://opensource.org/licenses/MIT 9 10#include <arch/x86.h> 11#include <arch/x86/descriptor.h> 12#include <arch/x86/feature.h> 13#include <arch/x86/mp.h> 14#include <arch/x86/registers.h> 15#include <arch/x86/x86intrin.h> 16#include <assert.h> 17#include <debug.h> 18#include <kernel/spinlock.h> 19#include <kernel/thread.h> 20#include <stdlib.h> 21#include <string.h> 22#include <sys/types.h> 23 24void arch_thread_initialize(thread_t* t, vaddr_t entry_point) { 25 // create a default stack frame on the stack 26 vaddr_t stack_top = t->stack.top; 27 28 // make sure the top of the stack is 16 byte aligned for ABI compliance 29 stack_top = ROUNDDOWN(stack_top, 16); 30 t->stack.top = stack_top; 31 32 // make sure we start the frame 8 byte unaligned (relative to the 16 byte alignment) because 33 // of the way the context switch will pop the return address off the stack. After the first 34 // context switch, this leaves the stack unaligned relative to how a called function expects it. 35 stack_top -= 8; 36 struct x86_64_context_switch_frame* frame = (struct x86_64_context_switch_frame*)(stack_top); 37 38 // Record a zero return address so that backtraces will stop here. 39 // Otherwise if heap debugging is on, and say there is 99..99 here, 40 // then the debugger could try to continue the backtrace from there. 41 memset((void*)stack_top, 0, 8); 42 43 // move down a frame size and zero it out 44 frame--; 45 memset(frame, 0, sizeof(*frame)); 46 47 frame->rip = entry_point; 48 49 // initialize the saved extended register state 50 vaddr_t buf = ROUNDUP(((vaddr_t)t->arch.extended_register_buffer), 64); 51 __UNUSED size_t overhead = buf - (vaddr_t)t->arch.extended_register_buffer; 52 DEBUG_ASSERT(sizeof(t->arch.extended_register_buffer) - overhead >= 53 x86_extended_register_size()); 54 t->arch.extended_register_state = (vaddr_t*)buf; 55 x86_extended_register_init_state(t->arch.extended_register_state); 56 57 // set the stack pointer 58 t->arch.sp = (vaddr_t)frame; 59#if __has_feature(safe_stack) 60 t->arch.unsafe_sp = 61 ROUNDDOWN(t->stack.unsafe_base + t->stack.size, 16); 62#endif 63 64 // initialize the fs, gs and kernel bases to 0. 65 t->arch.fs_base = 0; 66 t->arch.gs_base = 0; 67} 68 69void arch_thread_construct_first(thread_t* t) { 70} 71 72void arch_dump_thread(thread_t* t) { 73 if (t->state != THREAD_RUNNING) { 74 dprintf(INFO, "\tarch: "); 75 dprintf(INFO, "sp %#" PRIxPTR "\n", t->arch.sp); 76 } 77} 78 79void* arch_thread_get_blocked_fp(struct thread* t) { 80 if (!WITH_FRAME_POINTERS) 81 return nullptr; 82 83 struct x86_64_context_switch_frame* frame = (struct x86_64_context_switch_frame*)t->arch.sp; 84 85 return (void*)frame->rbp; 86} 87 88__NO_SAFESTACK __attribute__((target("fsgsbase"))) void arch_context_switch(thread_t* oldthread, thread_t* newthread) { 89 x86_extended_register_context_switch(oldthread, newthread); 90 91 //printf("cs 0x%llx\n", kstack_top); 92 93 /* set the tss SP0 value to point at the top of our stack */ 94 x86_set_tss_sp(newthread->stack.top); 95 96 /* Save the user fs_base register value. The new rdfsbase instruction 97 * is much faster than reading the MSR, so use the former in 98 * preference. */ 99 if (likely(g_x86_feature_fsgsbase)) { 100 oldthread->arch.fs_base = _readfsbase_u64(); 101 } else { 102 oldthread->arch.fs_base = read_msr(X86_MSR_IA32_FS_BASE); 103 } 104 105 /* The segment selector registers can't be preserved across context 106 * switches in all cases, because some values get clobbered when 107 * returning from interrupts. If an interrupt occurs when a userland 108 * process has set %fs = 1 (for example), the IRET instruction used for 109 * returning from the interrupt will reset %fs to 0. 110 * 111 * To prevent the segment selector register values from leaking between 112 * processes, we reset these registers across context switches. */ 113 set_ds(0); 114 set_es(0); 115 set_fs(0); 116 if (get_gs() != 0) { 117 /* Assigning to %gs clobbers gs_base, so we must restore gs_base 118 * afterwards. */ 119 DEBUG_ASSERT(arch_ints_disabled()); 120 uintptr_t gs_base = (uintptr_t)x86_get_percpu(); 121 set_gs(0); 122 write_msr(X86_MSR_IA32_GS_BASE, gs_base); 123 } 124 125 /* Restore fs_base and save+restore user gs_base. Note that the user 126 * and kernel gs_base values have been swapped -- the user value is 127 * currently in KERNEL_GS_BASE. */ 128 if (likely(g_x86_feature_fsgsbase)) { 129 /* There is no variant of the {rd,wr}gsbase instructions for 130 * accessing KERNEL_GS_BASE, so we wrap those in two swapgs 131 * instructions to get the same effect. This is a little 132 * convoluted, but still faster than using the KERNEL_GS_BASE 133 * MSRs. */ 134 __asm__ __volatile__( 135 "swapgs\n" 136 "rdgsbase %[old_value]\n" 137 "wrgsbase %[new_value]\n" 138 "swapgs\n" 139 : [old_value] "=&r"(oldthread->arch.gs_base) 140 : [new_value] "r"(newthread->arch.gs_base)); 141 142 _writefsbase_u64(newthread->arch.fs_base); 143 } else { 144 oldthread->arch.gs_base = read_msr(X86_MSR_IA32_KERNEL_GS_BASE); 145 write_msr(X86_MSR_IA32_FS_BASE, newthread->arch.fs_base); 146 write_msr(X86_MSR_IA32_KERNEL_GS_BASE, newthread->arch.gs_base); 147 } 148 149#if __has_feature(safe_stack) 150 oldthread->arch.unsafe_sp = x86_read_gs_offset64(ZX_TLS_UNSAFE_SP_OFFSET); 151 x86_write_gs_offset64(ZX_TLS_UNSAFE_SP_OFFSET, newthread->arch.unsafe_sp); 152#endif 153 154 x86_64_context_switch(&oldthread->arch.sp, newthread->arch.sp); 155} 156