xref: /haiku/src/system/kernel/arch/x86/32/syscalls.cpp (revision 02dd3236d21fd322310a1f791bab69d7bc031434)
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
21*02dd3236SAlex Smith extern "C" void x86_user_syscall_int(void);
22*02dd3236SAlex Smith extern unsigned int x86_user_syscall_int_end;
23*02dd3236SAlex Smith extern "C" void x86_user_syscall_sysenter(void);
24*02dd3236SAlex 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 
33370ab57dSAlex Smith static bool
34370ab57dSAlex Smith all_cpus_have_feature(enum x86_feature_type type, int feature)
35370ab57dSAlex Smith {
36370ab57dSAlex Smith 	int i;
37370ab57dSAlex Smith 	int cpuCount = smp_get_num_cpus();
38370ab57dSAlex Smith 
39370ab57dSAlex Smith 	for (i = 0; i < cpuCount; i++) {
40370ab57dSAlex Smith 		if (!(gCPU[i].arch.feature[type] & feature))
41370ab57dSAlex Smith 			return false;
42370ab57dSAlex Smith 	}
43370ab57dSAlex Smith 
44370ab57dSAlex Smith 	return true;
45370ab57dSAlex Smith }
46370ab57dSAlex Smith 
47370ab57dSAlex Smith 
48370ab57dSAlex Smith static void
49370ab57dSAlex Smith set_intel_syscall_stack(addr_t stackTop)
50370ab57dSAlex Smith {
51370ab57dSAlex Smith 	x86_write_msr(IA32_MSR_SYSENTER_ESP, stackTop);
52370ab57dSAlex Smith }
53370ab57dSAlex Smith 
54370ab57dSAlex Smith 
55370ab57dSAlex Smith static void
56370ab57dSAlex Smith init_intel_syscall_registers(void* dummy, int cpuNum)
57370ab57dSAlex Smith {
58370ab57dSAlex Smith 	x86_write_msr(IA32_MSR_SYSENTER_CS, KERNEL_CODE_SEG);
59370ab57dSAlex Smith 	x86_write_msr(IA32_MSR_SYSENTER_ESP, 0);
60370ab57dSAlex Smith 	x86_write_msr(IA32_MSR_SYSENTER_EIP, (addr_t)x86_sysenter);
61370ab57dSAlex Smith 
62370ab57dSAlex Smith 	gX86SetSyscallStack = &set_intel_syscall_stack;
63370ab57dSAlex Smith }
64370ab57dSAlex Smith 
65370ab57dSAlex Smith 
66370ab57dSAlex Smith #if 0
67370ab57dSAlex Smith static void
68370ab57dSAlex Smith init_amd_syscall_registers(void* dummy, int cpuNum)
69370ab57dSAlex Smith {
70370ab57dSAlex Smith 	// TODO: ...
71370ab57dSAlex Smith }
72370ab57dSAlex Smith #endif
73370ab57dSAlex Smith 
74370ab57dSAlex Smith 
75370ab57dSAlex Smith // #pragma mark -
76370ab57dSAlex Smith 
77370ab57dSAlex Smith 
78370ab57dSAlex Smith void
79370ab57dSAlex Smith x86_initialize_syscall(void)
80370ab57dSAlex Smith {
81*02dd3236SAlex Smith 	void* syscallCode = (void *)&x86_user_syscall_int;
82*02dd3236SAlex Smith 	void* syscallCodeEnd = &x86_user_syscall_int_end;
83370ab57dSAlex Smith 
84370ab57dSAlex Smith 	// check syscall
85370ab57dSAlex Smith 	if (all_cpus_have_feature(FEATURE_COMMON, IA32_FEATURE_SEP)
86370ab57dSAlex Smith 		&& !(gCPU[0].arch.family == 6 && gCPU[0].arch.model < 3
87370ab57dSAlex Smith 			&& gCPU[0].arch.stepping < 3)) {
88370ab57dSAlex Smith 		// Intel sysenter/sysexit
89370ab57dSAlex Smith 		dprintf("initialize_commpage_syscall(): sysenter/sysexit supported\n");
90370ab57dSAlex Smith 
91370ab57dSAlex Smith 		// the code to be used in userland
92*02dd3236SAlex Smith 		syscallCode = (void *)&x86_user_syscall_sysenter;
93*02dd3236SAlex Smith 		syscallCodeEnd = &x86_user_syscall_sysenter_end;
94370ab57dSAlex Smith 
95370ab57dSAlex Smith 		// tell all CPUs to init their sysenter/sysexit related registers
96370ab57dSAlex Smith 		call_all_cpus_sync(&init_intel_syscall_registers, NULL);
97370ab57dSAlex Smith 	} else if (all_cpus_have_feature(FEATURE_EXT_AMD,
98370ab57dSAlex Smith 			IA32_FEATURE_AMD_EXT_SYSCALL)) {
99370ab57dSAlex Smith 		// AMD syscall/sysret
100370ab57dSAlex Smith 		dprintf("initialize_commpage_syscall(): syscall/sysret supported "
101370ab57dSAlex Smith 			"-- not yet by Haiku, though");
102370ab57dSAlex Smith 	} else {
103370ab57dSAlex Smith 		// no special syscall support
104370ab57dSAlex Smith 		dprintf("initialize_commpage_syscall(): no special syscall support\n");
105370ab57dSAlex Smith 	}
106370ab57dSAlex Smith 
107370ab57dSAlex Smith 	// fill in the table entry
108370ab57dSAlex Smith 	size_t len = (size_t)((addr_t)syscallCodeEnd - (addr_t)syscallCode);
109370ab57dSAlex Smith 	fill_commpage_entry(COMMPAGE_ENTRY_X86_SYSCALL, syscallCode, len);
110370ab57dSAlex Smith 
111370ab57dSAlex Smith 	// add syscall to the commpage image
112370ab57dSAlex Smith 	image_id image = get_commpage_image();
113370ab57dSAlex Smith 	elf_add_memory_image_symbol(image, "commpage_syscall",
114370ab57dSAlex Smith 		((addr_t*)USER_COMMPAGE_ADDR)[COMMPAGE_ENTRY_X86_SYSCALL], len,
115370ab57dSAlex Smith 		B_SYMBOL_TYPE_TEXT);
116370ab57dSAlex Smith }
117