* 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
This commit is contained in:
@@ -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
|
||||
|
||||
@@ -7,99 +7,7 @@
|
||||
|
||||
#include <commpage.h>
|
||||
|
||||
#include <string.h>
|
||||
|
||||
#include <KernelExport.h>
|
||||
|
||||
#include <cpu.h>
|
||||
#include <elf.h>
|
||||
#include <smp.h>
|
||||
|
||||
|
||||
// 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;
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -26,6 +26,7 @@
|
||||
#include <vm/VMAddressSpace.h>
|
||||
|
||||
#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;
|
||||
|
||||
@@ -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 <string.h>
|
||||
|
||||
#include <KernelExport.h>
|
||||
|
||||
#include <commpage.h>
|
||||
#include <cpu.h>
|
||||
#include <elf.h>
|
||||
#include <smp.h>
|
||||
|
||||
|
||||
// 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;
|
||||
}
|
||||
@@ -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 <SupportDefs.h>
|
||||
|
||||
|
||||
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
|
||||
Reference in New Issue
Block a user