vfs: check userland buffers before reading them.
[haiku.git] / src / system / kernel / arch / x86 / 32 / syscalls.cpp
blob7fcee05a3cc7525ce4319036351b9684d9079bb0
1 /*
2 * Copyright 2008-2010, Ingo Weinhold, ingo_weinhold@gmx.de.
3 * Copyright 2007, Travis Geiselbrecht. All rights reserved.
4 * Distributed under the terms of the MIT License.
5 */
8 #include "x86_syscalls.h"
10 #include <string.h>
12 #include <KernelExport.h>
14 #include <commpage.h>
15 #include <cpu.h>
16 #include <elf.h>
17 #include <smp.h>
20 // user syscall assembly stubs
21 extern "C" void x86_user_syscall_int(void);
22 extern unsigned int x86_user_syscall_int_end;
23 extern "C" void x86_user_syscall_sysenter(void);
24 extern unsigned int x86_user_syscall_sysenter_end;
26 // sysenter handler
27 extern "C" void x86_sysenter();
30 void (*gX86SetSyscallStack)(addr_t stackTop) = NULL;
33 extern int memcpy_end;
34 extern int memset_end;
37 static bool
38 all_cpus_have_feature(enum x86_feature_type type, int feature)
40 int i;
41 int cpuCount = smp_get_num_cpus();
43 for (i = 0; i < cpuCount; i++) {
44 if (!(gCPU[i].arch.feature[type] & feature))
45 return false;
48 return true;
52 static void
53 set_intel_syscall_stack(addr_t stackTop)
55 x86_write_msr(IA32_MSR_SYSENTER_ESP, stackTop);
59 static void
60 init_intel_syscall_registers(void* dummy, int cpuNum)
62 x86_write_msr(IA32_MSR_SYSENTER_CS, KERNEL_CODE_SELECTOR);
63 x86_write_msr(IA32_MSR_SYSENTER_ESP, 0);
64 x86_write_msr(IA32_MSR_SYSENTER_EIP, (addr_t)x86_sysenter);
66 gX86SetSyscallStack = &set_intel_syscall_stack;
70 #if 0
71 static void
72 init_amd_syscall_registers(void* dummy, int cpuNum)
74 // TODO: ...
76 #endif
79 // #pragma mark -
82 void
83 x86_initialize_syscall(void)
85 void* syscallCode = (void *)&x86_user_syscall_int;
86 void* syscallCodeEnd = &x86_user_syscall_int_end;
88 // check syscall
89 if (all_cpus_have_feature(FEATURE_COMMON, IA32_FEATURE_SEP)
90 && !(gCPU[0].arch.family == 6 && gCPU[0].arch.model < 3
91 && gCPU[0].arch.stepping < 3)) {
92 // Intel sysenter/sysexit
93 dprintf("initialize_commpage_syscall(): sysenter/sysexit supported\n");
95 // the code to be used in userland
96 syscallCode = (void *)&x86_user_syscall_sysenter;
97 syscallCodeEnd = &x86_user_syscall_sysenter_end;
99 // tell all CPUs to init their sysenter/sysexit related registers
100 call_all_cpus_sync(&init_intel_syscall_registers, NULL);
101 } else if (all_cpus_have_feature(FEATURE_EXT_AMD,
102 IA32_FEATURE_AMD_EXT_SYSCALL)) {
103 // AMD syscall/sysret
104 dprintf("initialize_commpage_syscall(): syscall/sysret supported "
105 "-- not yet by Haiku, though");
106 } else {
107 // no special syscall support
108 dprintf("initialize_commpage_syscall(): no special syscall support\n");
111 // fill in the table entry
112 size_t len = (size_t)((addr_t)syscallCodeEnd - (addr_t)syscallCode);
113 addr_t position = fill_commpage_entry(COMMPAGE_ENTRY_X86_SYSCALL,
114 syscallCode, len);
116 // put the optimized functions into the commpage
117 size_t memcpyLen = (addr_t)&memcpy_end - (addr_t)memcpy;
118 addr_t memcpyPosition = fill_commpage_entry(COMMPAGE_ENTRY_X86_MEMCPY,
119 (const void*)memcpy, memcpyLen);
120 size_t memsetLen = (addr_t)&memset_end - (addr_t)memset;
121 addr_t memsetPosition = fill_commpage_entry(COMMPAGE_ENTRY_X86_MEMSET,
122 (const void*)memset, memsetLen);
124 // add syscall to the commpage image
125 image_id image = get_commpage_image();
126 elf_add_memory_image_symbol(image, "commpage_memcpy", memcpyPosition,
127 memcpyLen, B_SYMBOL_TYPE_TEXT);
128 elf_add_memory_image_symbol(image, "commpage_memset", memsetPosition,
129 memsetLen, B_SYMBOL_TYPE_TEXT);
130 elf_add_memory_image_symbol(image, "commpage_syscall", position, len,
131 B_SYMBOL_TYPE_TEXT);