From bdd7dae89c36aa55ab8eeaff6b442d0c4406664b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=A9r=C3=B4me=20Duval?= Date: Tue, 15 May 2018 18:59:13 +0200 Subject: [PATCH] kernel/x86_64: add a compatibility syscalls table. * install syscall handlers in compatibility mode. * copy the syscall entry in the compatibility commpage, ATM only for Intel SYSENTER. * copy the thread exit handler in the compatibility commpage. Change-Id: Ic350799938815194377d8a4560cb106fe7366cc6 --- src/system/kernel/arch/x86/64/syscalls.cpp | 90 +++++++++++++++++++ .../kernel/arch/x86/syscalls_compat.cpp | 73 +++++++++++++++ src/system/kernel/arch/x86/x86_syscalls.h | 23 ++--- 3 files changed, 170 insertions(+), 16 deletions(-) create mode 100644 src/system/kernel/arch/x86/syscalls_compat.cpp diff --git a/src/system/kernel/arch/x86/64/syscalls.cpp b/src/system/kernel/arch/x86/64/syscalls.cpp index 907dd4989d..f71e7ad7f5 100644 --- a/src/system/kernel/arch/x86/64/syscalls.cpp +++ b/src/system/kernel/arch/x86/64/syscalls.cpp @@ -9,7 +9,13 @@ #include +#ifdef _COMPAT_MODE +# include +#endif #include +#ifdef _COMPAT_MODE +# include +#endif #include @@ -17,6 +23,30 @@ extern "C" void x86_64_syscall_entry(void); +#ifdef _COMPAT_MODE + +// SYSCALL/SYSENTER handlers (in entry_compat.S). +extern "C" { + void x86_64_syscall32_entry(void); + void x86_64_sysenter32_entry(void); +} + + +void (*gX86SetSyscallStack)(addr_t stackTop) = NULL; + + +// user syscall assembly stubs +extern "C" void x86_user_syscall_sysenter(void); +extern unsigned int x86_user_syscall_sysenter_end; +extern "C" void x86_user_syscall_syscall(void); +extern unsigned int x86_user_syscall_syscall_end; + +extern "C" void x86_sysenter32_userspace_thread_exit(void); +extern unsigned int x86_sysenter32_userspace_thread_exit_end; + +#endif // _COMPAT_MODE + + static void init_syscall_registers(void* dummy, int cpuNum) { @@ -32,6 +62,11 @@ init_syscall_registers(void* dummy, int cpuNum) // Entry point address. x86_write_msr(IA32_MSR_LSTAR, (addr_t)x86_64_syscall_entry); +#ifdef _COMPAT_MODE + // Syscall compat entry point address. + x86_write_msr(IA32_MSR_CSTAR, (addr_t)x86_64_syscall32_entry); +#endif + // Segments that will be set upon entry and return. This is very strange // and requires a specific ordering of segments in the GDT. Upon entry: // - CS is set to IA32_STAR[47:32] @@ -59,3 +94,58 @@ x86_initialize_syscall(void) // need to use the commpage. Tell all CPUs to initialize the SYSCALL MSRs. call_all_cpus_sync(&init_syscall_registers, NULL); } + + +#ifdef _COMPAT_MODE + +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_SELECTOR); + x86_write_msr(IA32_MSR_SYSENTER_ESP, 0); + x86_write_msr(IA32_MSR_SYSENTER_EIP, (addr_t)x86_64_sysenter32_entry); + + gX86SetSyscallStack = &set_intel_syscall_stack; +} + + +void +x86_compat_initialize_syscall(void) +{ + // for 32-bit syscalls, fill the commpage with the right mechanism + call_all_cpus_sync(&init_intel_syscall_registers, NULL); + + void* syscallCode = (void *)&x86_user_syscall_sysenter; + void* syscallCodeEnd = &x86_user_syscall_sysenter_end; + + // TODO check AMD for sysenter + + // fill in the table entry + size_t len = (size_t)((addr_t)syscallCodeEnd - (addr_t)syscallCode); + addr_t position = fill_commpage_compat_entry(COMMPAGE_ENTRY_X86_SYSCALL, + syscallCode, len); + + image_id image = get_commpage_compat_image(); + elf_add_memory_image_symbol(image, "commpage_compat_syscall", position, + len, B_SYMBOL_TYPE_TEXT); + + void* threadExitCode = (void *)&x86_sysenter32_userspace_thread_exit; + void* threadExitCodeEnd = &x86_sysenter32_userspace_thread_exit_end; + + len = (size_t)((addr_t)threadExitCodeEnd - (addr_t)threadExitCode); + position = fill_commpage_compat_entry(COMMPAGE_ENTRY_X86_THREAD_EXIT, + threadExitCode, len); + + elf_add_memory_image_symbol(image, "commpage_compat_thread_exit", + position, len, B_SYMBOL_TYPE_TEXT); +} + +#endif // _COMPAT_MODE + diff --git a/src/system/kernel/arch/x86/syscalls_compat.cpp b/src/system/kernel/arch/x86/syscalls_compat.cpp new file mode 100644 index 0000000000..f4d751a5d7 --- /dev/null +++ b/src/system/kernel/arch/x86/syscalls_compat.cpp @@ -0,0 +1,73 @@ +/* + * Copyright 2018, Jérôme Duval, jerome.duval@gmail.com. + * Copyright 2008, Ingo Weinhold, ingo_weinhold@gmx.de. + * Copyright 2004-2010, Haiku Inc. All rights reserved. + * Distributed under the terms of the MIT License. + */ + + +/*! Big case statement for dispatching syscalls, as well as the generic + syscall interface. +*/ + + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + + +status_t _user_generic_syscall(const char* userSubsystem, uint32 function, + void* buffer, size_t bufferSize); +int _user_is_computer_on(void); + + +#include "syscall_numbers.h" + +#define kSyscallCount kSyscallCompatCount +#define kSyscallInfos kSyscallCompatInfos +#define kExtendedSyscallInfos kExtendedSyscallCompatInfos + +extern const int kSyscallCount; +extern const syscall_info kSyscallInfos[]; +extern const extended_syscall_info kExtendedSyscallInfos[]; + +/* + * kSyscallCount and kSyscallInfos here + */ +// generated by gensyscalls +#include "syscall_table.h" diff --git a/src/system/kernel/arch/x86/x86_syscalls.h b/src/system/kernel/arch/x86/x86_syscalls.h index 85ae6d7878..049aacd6ce 100644 --- a/src/system/kernel/arch/x86/x86_syscalls.h +++ b/src/system/kernel/arch/x86/x86_syscalls.h @@ -1,4 +1,5 @@ /* + * Copyright 2018, Jérôme Duval, jerome.duval@gmail.com. * Copyright 2010, Ingo Weinhold, ingo_weinhold@gmx.de. * Distributed under the terms of the MIT License. */ @@ -10,20 +11,9 @@ void x86_initialize_syscall(); - - -#ifdef __x86_64__ - - -static inline void -x86_set_syscall_stack(addr_t stackTop) -{ - // Nothing to do here, the thread's stack pointer is always accessible - // via the GS segment. -} - - -#else +#if defined(__x86_64__) && defined(_COMPAT_MODE) +void x86_compat_initialize_syscall(); +#endif extern void (*gX86SetSyscallStack)(addr_t stackTop); @@ -32,11 +22,12 @@ extern void (*gX86SetSyscallStack)(addr_t stackTop); static inline void x86_set_syscall_stack(addr_t stackTop) { +#if !defined(__x86_64__) || defined(_COMPAT_MODE) + // TODO on x86_64, only necessary for 32-bit threads if (gX86SetSyscallStack != NULL) gX86SetSyscallStack(stackTop); +#endif } -#endif // __x86_64__ - #endif // _KERNEL_ARCH_X86_SYSCALLS_H