xref: /haiku/src/system/kernel/arch/x86/32/syscalls.cpp (revision e81b792e8f5d72c21de8ab3fc508cb9728722918)
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