From 2cf60f9070b06681ff0c4cf04d3ffbda2ca7805f Mon Sep 17 00:00:00 2001 From: Ingo Weinhold Date: Wed, 24 Feb 2010 19:50:20 +0000 Subject: [PATCH] * Moved the syscall stuff from arch_commpage.cpp to x86_syscalls.{cpp,h}. * On context switches we do now set the IA32_MSR_SYSENTER_ESP. This saves us setting esp at the beginning of x86_sysenter(). More importantly when entering it in single-step mode, this no longer causes a double fault (cf. #3487). We still don't handle the resulting debug exception correctly, so that we still get a (continuable) panic(). git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@35609 a95241bf-73f2-0310-859d-f6bbb57e9c96 --- src/system/kernel/arch/x86/Jamfile | 1 + src/system/kernel/arch/x86/arch_commpage.cpp | 96 +-------------- src/system/kernel/arch/x86/arch_interrupts.S | 3 +- src/system/kernel/arch/x86/arch_thread.cpp | 3 + src/system/kernel/arch/x86/x86_syscalls.cpp | 118 +++++++++++++++++++ src/system/kernel/arch/x86/x86_syscalls.h | 26 ++++ 6 files changed, 151 insertions(+), 96 deletions(-) create mode 100644 src/system/kernel/arch/x86/x86_syscalls.cpp create mode 100644 src/system/kernel/arch/x86/x86_syscalls.h diff --git a/src/system/kernel/arch/x86/Jamfile b/src/system/kernel/arch/x86/Jamfile index 635f88a2f4..9d6f08664a 100644 --- a/src/system/kernel/arch/x86/Jamfile +++ b/src/system/kernel/arch/x86/Jamfile @@ -36,6 +36,7 @@ KernelMergeObject kernel_arch_x86.o : vm86.cpp x86_physical_page_mapper.cpp x86_physical_page_mapper_large_memory.cpp + x86_syscalls.cpp x86_apic.cpp x86_hpet.cpp diff --git a/src/system/kernel/arch/x86/arch_commpage.cpp b/src/system/kernel/arch/x86/arch_commpage.cpp index 8b08e81388..581b0788d4 100644 --- a/src/system/kernel/arch/x86/arch_commpage.cpp +++ b/src/system/kernel/arch/x86/arch_commpage.cpp @@ -7,99 +7,7 @@ #include -#include - -#include - -#include -#include -#include - - -// user syscall assembly stubs -extern "C" void _user_syscall_int(void); -extern unsigned int _user_syscall_int_end; -extern "C" void _user_syscall_sysenter(void); -extern unsigned int _user_syscall_sysenter_end; - -// sysenter handler -extern "C" void x86_sysenter(); - - -static bool -all_cpus_have_feature(enum x86_feature_type type, int feature) -{ - int i; - int cpuCount = smp_get_num_cpus(); - - for (i = 0; i < cpuCount; i++) { - if (!(gCPU[i].arch.feature[type] & feature)) - return false; - } - - return true; -} - - -static void -init_intel_syscall_registers(void* dummy, int cpuNum) -{ - x86_write_msr(IA32_MSR_SYSENTER_CS, KERNEL_CODE_SEG); - x86_write_msr(IA32_MSR_SYSENTER_ESP, 0); - x86_write_msr(IA32_MSR_SYSENTER_EIP, (addr_t)x86_sysenter); -} - - -#if 0 -static void -init_amd_syscall_registers(void* dummy, int cpuNum) -{ - // TODO: ... -} -#endif - - -static status_t -initialize_commpage_syscall(void) -{ - void* syscallCode = (void *)&_user_syscall_int; - void* syscallCodeEnd = &_user_syscall_int_end; - - // check syscall - if (all_cpus_have_feature(FEATURE_COMMON, IA32_FEATURE_SEP) - && !(gCPU[0].arch.family == 6 && gCPU[0].arch.model < 3 - && gCPU[0].arch.stepping < 3)) { - // Intel sysenter/sysexit - dprintf("initialize_commpage_syscall(): sysenter/sysexit supported\n"); - - // the code to be used in userland - syscallCode = (void *)&_user_syscall_sysenter; - syscallCodeEnd = &_user_syscall_sysenter_end; - - // tell all CPUs to init their sysenter/sysexit related registers - call_all_cpus_sync(&init_intel_syscall_registers, NULL); - } else if (all_cpus_have_feature(FEATURE_EXT_AMD, - IA32_FEATURE_AMD_EXT_SYSCALL)) { - // AMD syscall/sysret - dprintf("initialize_commpage_syscall(): syscall/sysret supported " - "-- not yet by Haiku, though"); - } else { - // no special syscall support - dprintf("initialize_commpage_syscall(): no special syscall support\n"); - } - - // fill in the table entry - size_t len = (size_t)((addr_t)syscallCodeEnd - (addr_t)syscallCode); - fill_commpage_entry(COMMPAGE_ENTRY_X86_SYSCALL, syscallCode, len); - - // add syscall to the commpage image - image_id image = get_commpage_image(); - elf_add_memory_image_symbol(image, "commpage_syscall", - ((addr_t*)USER_COMMPAGE_ADDR)[COMMPAGE_ENTRY_X86_SYSCALL], len, - B_SYMBOL_TYPE_TEXT); - - return B_OK; -} +#include "x86_syscalls.h" status_t @@ -113,7 +21,7 @@ status_t arch_commpage_init_post_cpus(void) { // select the optimum syscall mechanism and patch the commpage - initialize_commpage_syscall(); + x86_initialize_commpage_syscall(); return B_OK; } diff --git a/src/system/kernel/arch/x86/arch_interrupts.S b/src/system/kernel/arch/x86/arch_interrupts.S index c1144ef04c..9e4e083bfa 100644 --- a/src/system/kernel/arch/x86/arch_interrupts.S +++ b/src/system/kernel/arch/x86/arch_interrupts.S @@ -555,9 +555,8 @@ FUNCTION_END(handle_syscall) ecx - user esp */ FUNCTION(x86_sysenter): - // switch the stack + // get the thread movl %dr3, %edx - movl THREAD_kernel_stack_top(%edx), %esp // push the iframe pushl $USER_DATA_SEG // user_ss diff --git a/src/system/kernel/arch/x86/arch_thread.cpp b/src/system/kernel/arch/x86/arch_thread.cpp index 6831f7bcaf..738cd34fa3 100644 --- a/src/system/kernel/arch/x86/arch_thread.cpp +++ b/src/system/kernel/arch/x86/arch_thread.cpp @@ -26,6 +26,7 @@ #include #include "x86_paging.h" +#include "x86_syscalls.h" #include "X86VMTranslationMap.h" @@ -357,6 +358,7 @@ void arch_thread_context_switch(struct thread *from, struct thread *to) { i386_set_tss_and_kstack(to->kernel_stack_top); + x86_set_syscall_stack(to->kernel_stack_top); // set TLS GDT entry to the current thread - since this action is // dependent on the current CPU, we have to do it here @@ -451,6 +453,7 @@ arch_thread_enter_userspace(struct thread *t, addr_t entry, void *args1, // set the CPU dependent GDT entry for TLS set_tls_context(t); + x86_set_syscall_stack(t->kernel_stack_top); x86_enter_userspace(entry, stackTop); return B_OK; diff --git a/src/system/kernel/arch/x86/x86_syscalls.cpp b/src/system/kernel/arch/x86/x86_syscalls.cpp new file mode 100644 index 0000000000..d0ba8d0473 --- /dev/null +++ b/src/system/kernel/arch/x86/x86_syscalls.cpp @@ -0,0 +1,118 @@ +/* + * Copyright 2008-2010, Ingo Weinhold, ingo_weinhold@gmx.de. + * Copyright 2007, Travis Geiselbrecht. All rights reserved. + * Distributed under the terms of the MIT License. + */ + + +#include "x86_syscalls.h" + +#include + +#include + +#include +#include +#include +#include + + +// user syscall assembly stubs +extern "C" void _user_syscall_int(void); +extern unsigned int _user_syscall_int_end; +extern "C" void _user_syscall_sysenter(void); +extern unsigned int _user_syscall_sysenter_end; + +// sysenter handler +extern "C" void x86_sysenter(); + + +void (*gX86SetSyscallStack)(addr_t stackTop) = NULL; + + +static bool +all_cpus_have_feature(enum x86_feature_type type, int feature) +{ + int i; + int cpuCount = smp_get_num_cpus(); + + for (i = 0; i < cpuCount; i++) { + if (!(gCPU[i].arch.feature[type] & feature)) + return false; + } + + return true; +} + + +static void +set_intel_syscall_stack(addr_t stackTop) +{ + x86_write_msr(IA32_MSR_SYSENTER_ESP, stackTop); +} + + +static void +init_intel_syscall_registers(void* dummy, int cpuNum) +{ + x86_write_msr(IA32_MSR_SYSENTER_CS, KERNEL_CODE_SEG); + x86_write_msr(IA32_MSR_SYSENTER_ESP, 0); + x86_write_msr(IA32_MSR_SYSENTER_EIP, (addr_t)x86_sysenter); + + gX86SetSyscallStack = &set_intel_syscall_stack; +} + + +#if 0 +static void +init_amd_syscall_registers(void* dummy, int cpuNum) +{ + // TODO: ... +} +#endif + + +// #pragma mark - + + +status_t +x86_initialize_commpage_syscall(void) +{ + void* syscallCode = (void *)&_user_syscall_int; + void* syscallCodeEnd = &_user_syscall_int_end; + + // check syscall + if (all_cpus_have_feature(FEATURE_COMMON, IA32_FEATURE_SEP) + && !(gCPU[0].arch.family == 6 && gCPU[0].arch.model < 3 + && gCPU[0].arch.stepping < 3)) { + // Intel sysenter/sysexit + dprintf("initialize_commpage_syscall(): sysenter/sysexit supported\n"); + + // the code to be used in userland + syscallCode = (void *)&_user_syscall_sysenter; + syscallCodeEnd = &_user_syscall_sysenter_end; + + // tell all CPUs to init their sysenter/sysexit related registers + call_all_cpus_sync(&init_intel_syscall_registers, NULL); + } else if (all_cpus_have_feature(FEATURE_EXT_AMD, + IA32_FEATURE_AMD_EXT_SYSCALL)) { + // AMD syscall/sysret + dprintf("initialize_commpage_syscall(): syscall/sysret supported " + "-- not yet by Haiku, though"); + } else { + // no special syscall support + dprintf("initialize_commpage_syscall(): no special syscall support\n"); + } + + // fill in the table entry + size_t len = (size_t)((addr_t)syscallCodeEnd - (addr_t)syscallCode); + fill_commpage_entry(COMMPAGE_ENTRY_X86_SYSCALL, syscallCode, len); + + // add syscall to the commpage image + image_id image = get_commpage_image(); + elf_add_memory_image_symbol(image, "commpage_syscall", + ((addr_t*)USER_COMMPAGE_ADDR)[COMMPAGE_ENTRY_X86_SYSCALL], len, + B_SYMBOL_TYPE_TEXT); + + return B_OK; +} diff --git a/src/system/kernel/arch/x86/x86_syscalls.h b/src/system/kernel/arch/x86/x86_syscalls.h new file mode 100644 index 0000000000..f6434ac694 --- /dev/null +++ b/src/system/kernel/arch/x86/x86_syscalls.h @@ -0,0 +1,26 @@ +/* + * Copyright 2010, Ingo Weinhold, ingo_weinhold@gmx.de. + * Distributed under the terms of the MIT License. + */ +#ifndef _KERNEL_ARCH_X86_SYSCALLS_H +#define _KERNEL_ARCH_X86_SYSCALLS_H + + +#include + + +extern void (*gX86SetSyscallStack)(addr_t stackTop); + + +status_t x86_initialize_commpage_syscall(); + + +static inline void +x86_set_syscall_stack(addr_t stackTop) +{ + if (gX86SetSyscallStack != NULL) + gX86SetSyscallStack(stackTop); +} + + +#endif // _KERNEL_ARCH_X86_SYSCALLS_H