* 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
|
vm86.cpp
|
||||||
x86_physical_page_mapper.cpp
|
x86_physical_page_mapper.cpp
|
||||||
x86_physical_page_mapper_large_memory.cpp
|
x86_physical_page_mapper_large_memory.cpp
|
||||||
|
x86_syscalls.cpp
|
||||||
|
|
||||||
x86_apic.cpp
|
x86_apic.cpp
|
||||||
x86_hpet.cpp
|
x86_hpet.cpp
|
||||||
|
|||||||
@@ -7,99 +7,7 @@
|
|||||||
|
|
||||||
#include <commpage.h>
|
#include <commpage.h>
|
||||||
|
|
||||||
#include <string.h>
|
#include "x86_syscalls.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;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
status_t
|
status_t
|
||||||
@@ -113,7 +21,7 @@ status_t
|
|||||||
arch_commpage_init_post_cpus(void)
|
arch_commpage_init_post_cpus(void)
|
||||||
{
|
{
|
||||||
// select the optimum syscall mechanism and patch the commpage
|
// select the optimum syscall mechanism and patch the commpage
|
||||||
initialize_commpage_syscall();
|
x86_initialize_commpage_syscall();
|
||||||
|
|
||||||
return B_OK;
|
return B_OK;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -555,9 +555,8 @@ FUNCTION_END(handle_syscall)
|
|||||||
ecx - user esp
|
ecx - user esp
|
||||||
*/
|
*/
|
||||||
FUNCTION(x86_sysenter):
|
FUNCTION(x86_sysenter):
|
||||||
// switch the stack
|
// get the thread
|
||||||
movl %dr3, %edx
|
movl %dr3, %edx
|
||||||
movl THREAD_kernel_stack_top(%edx), %esp
|
|
||||||
|
|
||||||
// push the iframe
|
// push the iframe
|
||||||
pushl $USER_DATA_SEG // user_ss
|
pushl $USER_DATA_SEG // user_ss
|
||||||
|
|||||||
@@ -26,6 +26,7 @@
|
|||||||
#include <vm/VMAddressSpace.h>
|
#include <vm/VMAddressSpace.h>
|
||||||
|
|
||||||
#include "x86_paging.h"
|
#include "x86_paging.h"
|
||||||
|
#include "x86_syscalls.h"
|
||||||
#include "X86VMTranslationMap.h"
|
#include "X86VMTranslationMap.h"
|
||||||
|
|
||||||
|
|
||||||
@@ -357,6 +358,7 @@ void
|
|||||||
arch_thread_context_switch(struct thread *from, struct thread *to)
|
arch_thread_context_switch(struct thread *from, struct thread *to)
|
||||||
{
|
{
|
||||||
i386_set_tss_and_kstack(to->kernel_stack_top);
|
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
|
// set TLS GDT entry to the current thread - since this action is
|
||||||
// dependent on the current CPU, we have to do it here
|
// 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 the CPU dependent GDT entry for TLS
|
||||||
set_tls_context(t);
|
set_tls_context(t);
|
||||||
|
|
||||||
|
x86_set_syscall_stack(t->kernel_stack_top);
|
||||||
x86_enter_userspace(entry, stackTop);
|
x86_enter_userspace(entry, stackTop);
|
||||||
|
|
||||||
return B_OK;
|
return B_OK;
|
||||||
|
|||||||
@@ -0,0 +1,118 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2008-2010, Ingo Weinhold, [email protected].
|
||||||
|
* 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, [email protected].
|
||||||
|
* 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