* Copyright 2018, JΓ©rΓ΄me Duval, jerome.duval@gmail.com.
* Copyright 2012, Alex Smith, alex@alex-smith.me.uk.
* Distributed under the terms of the MIT License.
*/
#include "x86_syscalls.h"
#include <KernelExport.h>
#ifdef _COMPAT_MODE
# include <commpage_compat.h>
#endif
#include <cpu.h>
#ifdef _COMPAT_MODE
# include <elf.h>
#endif
#include <smp.h>
extern "C" void x86_64_syscall_entry(void);
#ifdef _COMPAT_MODE
extern "C" {
void x86_64_syscall32_entry(void);
void x86_64_sysenter32_entry(void);
}
void (*gX86SetSyscallStack)(addr_t stackTop) = NULL;
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
static void
init_syscall_registers(void* dummy, int cpuNum)
{
x86_write_msr(IA32_MSR_EFER, x86_read_msr(IA32_MSR_EFER)
| IA32_MSR_EFER_SYSCALL);
x86_write_msr(IA32_MSR_FMASK, X86_EFLAGS_INTERRUPT | X86_EFLAGS_DIRECTION
| X86_EFLAGS_ALIGNMENT_CHECK);
x86_write_msr(IA32_MSR_LSTAR, (addr_t)x86_64_syscall_entry);
#ifdef _COMPAT_MODE
x86_write_msr(IA32_MSR_CSTAR, (addr_t)x86_64_syscall32_entry);
#endif
x86_write_msr(IA32_MSR_STAR, ((uint64)(USER32_CODE_SELECTOR) << 48)
| ((uint64)(KERNEL_CODE_SELECTOR) << 32));
}
void
x86_initialize_syscall(void)
{
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)
{
call_all_cpus_sync(&init_intel_syscall_registers, NULL);
void* syscallCode = (void *)&x86_user_syscall_sysenter;
void* syscallCodeEnd = &x86_user_syscall_sysenter_end;
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