1370ab57dSAlex Smith /*
2370ab57dSAlex Smith * Copyright 2008-2010, Ingo Weinhold, ingo_weinhold@gmx.de.
3370ab57dSAlex Smith * Copyright 2007, Travis Geiselbrecht. All rights reserved.
4370ab57dSAlex Smith * Distributed under the terms of the MIT License.
5370ab57dSAlex Smith */
6370ab57dSAlex Smith
7370ab57dSAlex Smith
8370ab57dSAlex Smith #include "x86_syscalls.h"
9370ab57dSAlex Smith
10370ab57dSAlex Smith #include <string.h>
11370ab57dSAlex Smith
12370ab57dSAlex Smith #include <KernelExport.h>
13370ab57dSAlex Smith
14370ab57dSAlex Smith #include <commpage.h>
15370ab57dSAlex Smith #include <cpu.h>
16370ab57dSAlex Smith #include <elf.h>
17370ab57dSAlex Smith #include <smp.h>
18370ab57dSAlex Smith
19370ab57dSAlex Smith
20370ab57dSAlex Smith // user syscall assembly stubs
2102dd3236SAlex Smith extern "C" void x86_user_syscall_int(void);
2202dd3236SAlex Smith extern unsigned int x86_user_syscall_int_end;
2302dd3236SAlex Smith extern "C" void x86_user_syscall_sysenter(void);
2402dd3236SAlex Smith extern unsigned int x86_user_syscall_sysenter_end;
25370ab57dSAlex Smith
26370ab57dSAlex Smith // sysenter handler
27370ab57dSAlex Smith extern "C" void x86_sysenter();
28370ab57dSAlex Smith
29370ab57dSAlex Smith
30370ab57dSAlex Smith void (*gX86SetSyscallStack)(addr_t stackTop) = NULL;
31370ab57dSAlex Smith
32370ab57dSAlex Smith
33*f2f91078SPaweł Dziepak extern int memcpy_end;
34*f2f91078SPaweł Dziepak extern int memset_end;
35*f2f91078SPaweł Dziepak
36*f2f91078SPaweł Dziepak
37370ab57dSAlex Smith static bool
all_cpus_have_feature(enum x86_feature_type type,int feature)38370ab57dSAlex Smith all_cpus_have_feature(enum x86_feature_type type, int feature)
39370ab57dSAlex Smith {
40370ab57dSAlex Smith int i;
41370ab57dSAlex Smith int cpuCount = smp_get_num_cpus();
42370ab57dSAlex Smith
43370ab57dSAlex Smith for (i = 0; i < cpuCount; i++) {
44370ab57dSAlex Smith if (!(gCPU[i].arch.feature[type] & feature))
45370ab57dSAlex Smith return false;
46370ab57dSAlex Smith }
47370ab57dSAlex Smith
48370ab57dSAlex Smith return true;
49370ab57dSAlex Smith }
50370ab57dSAlex Smith
51370ab57dSAlex Smith
52370ab57dSAlex Smith static void
set_intel_syscall_stack(addr_t stackTop)53370ab57dSAlex Smith set_intel_syscall_stack(addr_t stackTop)
54370ab57dSAlex Smith {
55370ab57dSAlex Smith x86_write_msr(IA32_MSR_SYSENTER_ESP, stackTop);
56370ab57dSAlex Smith }
57370ab57dSAlex Smith
58370ab57dSAlex Smith
59370ab57dSAlex Smith static void
init_intel_syscall_registers(void * dummy,int cpuNum)60370ab57dSAlex Smith init_intel_syscall_registers(void* dummy, int cpuNum)
61370ab57dSAlex Smith {
62611376feSPawel Dziepak x86_write_msr(IA32_MSR_SYSENTER_CS, KERNEL_CODE_SELECTOR);
63370ab57dSAlex Smith x86_write_msr(IA32_MSR_SYSENTER_ESP, 0);
64370ab57dSAlex Smith x86_write_msr(IA32_MSR_SYSENTER_EIP, (addr_t)x86_sysenter);
65370ab57dSAlex Smith
66370ab57dSAlex Smith gX86SetSyscallStack = &set_intel_syscall_stack;
67370ab57dSAlex Smith }
68370ab57dSAlex Smith
69370ab57dSAlex Smith
70370ab57dSAlex Smith #if 0
71370ab57dSAlex Smith static void
72370ab57dSAlex Smith init_amd_syscall_registers(void* dummy, int cpuNum)
73370ab57dSAlex Smith {
74370ab57dSAlex Smith // TODO: ...
75370ab57dSAlex Smith }
76370ab57dSAlex Smith #endif
77370ab57dSAlex Smith
78370ab57dSAlex Smith
79370ab57dSAlex Smith // #pragma mark -
80370ab57dSAlex Smith
81370ab57dSAlex Smith
82370ab57dSAlex Smith void
x86_initialize_syscall(void)83370ab57dSAlex Smith x86_initialize_syscall(void)
84370ab57dSAlex Smith {
8502dd3236SAlex Smith void* syscallCode = (void *)&x86_user_syscall_int;
8602dd3236SAlex Smith void* syscallCodeEnd = &x86_user_syscall_int_end;
87370ab57dSAlex Smith
88370ab57dSAlex Smith // check syscall
89370ab57dSAlex Smith if (all_cpus_have_feature(FEATURE_COMMON, IA32_FEATURE_SEP)
90370ab57dSAlex Smith && !(gCPU[0].arch.family == 6 && gCPU[0].arch.model < 3
91370ab57dSAlex Smith && gCPU[0].arch.stepping < 3)) {
92370ab57dSAlex Smith // Intel sysenter/sysexit
93370ab57dSAlex Smith dprintf("initialize_commpage_syscall(): sysenter/sysexit supported\n");
94370ab57dSAlex Smith
95370ab57dSAlex Smith // the code to be used in userland
9602dd3236SAlex Smith syscallCode = (void *)&x86_user_syscall_sysenter;
9702dd3236SAlex Smith syscallCodeEnd = &x86_user_syscall_sysenter_end;
98370ab57dSAlex Smith
99370ab57dSAlex Smith // tell all CPUs to init their sysenter/sysexit related registers
100370ab57dSAlex Smith call_all_cpus_sync(&init_intel_syscall_registers, NULL);
101370ab57dSAlex Smith } else if (all_cpus_have_feature(FEATURE_EXT_AMD,
102370ab57dSAlex Smith IA32_FEATURE_AMD_EXT_SYSCALL)) {
103370ab57dSAlex Smith // AMD syscall/sysret
104370ab57dSAlex Smith dprintf("initialize_commpage_syscall(): syscall/sysret supported "
105370ab57dSAlex Smith "-- not yet by Haiku, though");
106370ab57dSAlex Smith } else {
107370ab57dSAlex Smith // no special syscall support
108370ab57dSAlex Smith dprintf("initialize_commpage_syscall(): no special syscall support\n");
109370ab57dSAlex Smith }
110370ab57dSAlex Smith
111370ab57dSAlex Smith // fill in the table entry
112370ab57dSAlex Smith size_t len = (size_t)((addr_t)syscallCodeEnd - (addr_t)syscallCode);
113e85e399fSPawel Dziepak addr_t position = fill_commpage_entry(COMMPAGE_ENTRY_X86_SYSCALL,
114e85e399fSPawel Dziepak syscallCode, len);
115370ab57dSAlex Smith
116*f2f91078SPaweł Dziepak // put the optimized functions into the commpage
117*f2f91078SPaweł Dziepak size_t memcpyLen = (addr_t)&memcpy_end - (addr_t)memcpy;
118*f2f91078SPaweł Dziepak addr_t memcpyPosition = fill_commpage_entry(COMMPAGE_ENTRY_X86_MEMCPY,
119*f2f91078SPaweł Dziepak (const void*)memcpy, memcpyLen);
120*f2f91078SPaweł Dziepak size_t memsetLen = (addr_t)&memset_end - (addr_t)memset;
121*f2f91078SPaweł Dziepak addr_t memsetPosition = fill_commpage_entry(COMMPAGE_ENTRY_X86_MEMSET,
122*f2f91078SPaweł Dziepak (const void*)memset, memsetLen);
123*f2f91078SPaweł Dziepak
124370ab57dSAlex Smith // add syscall to the commpage image
125370ab57dSAlex Smith image_id image = get_commpage_image();
126*f2f91078SPaweł Dziepak elf_add_memory_image_symbol(image, "commpage_memcpy", memcpyPosition,
127*f2f91078SPaweł Dziepak memcpyLen, B_SYMBOL_TYPE_TEXT);
128*f2f91078SPaweł Dziepak elf_add_memory_image_symbol(image, "commpage_memset", memsetPosition,
129*f2f91078SPaweł Dziepak memsetLen, B_SYMBOL_TYPE_TEXT);
130e85e399fSPawel Dziepak elf_add_memory_image_symbol(image, "commpage_syscall", position, len,
131370ab57dSAlex Smith B_SYMBOL_TYPE_TEXT);
132370ab57dSAlex Smith }
133