xref: /haiku/src/system/kernel/arch/x86/32/syscalls.cpp (revision 25a7b01d15612846f332751841da3579db313082)
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  */
6 
7 
8 #include "x86_syscalls.h"
9 
10 #include <string.h>
11 
12 #include <KernelExport.h>
13 
14 #include <commpage.h>
15 #include <cpu.h>
16 #include <elf.h>
17 #include <smp.h>
18 
19 
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;
25 
26 // sysenter handler
27 extern "C" void x86_sysenter();
28 
29 
30 void (*gX86SetSyscallStack)(addr_t stackTop) = NULL;
31 
32 
33 static bool
34 all_cpus_have_feature(enum x86_feature_type type, int feature)
35 {
36 	int i;
37 	int cpuCount = smp_get_num_cpus();
38 
39 	for (i = 0; i < cpuCount; i++) {
40 		if (!(gCPU[i].arch.feature[type] & feature))
41 			return false;
42 	}
43 
44 	return true;
45 }
46 
47 
48 static void
49 set_intel_syscall_stack(addr_t stackTop)
50 {
51 	x86_write_msr(IA32_MSR_SYSENTER_ESP, stackTop);
52 }
53 
54 
55 static void
56 init_intel_syscall_registers(void* dummy, int cpuNum)
57 {
58 	x86_write_msr(IA32_MSR_SYSENTER_CS, KERNEL_CODE_SEG);
59 	x86_write_msr(IA32_MSR_SYSENTER_ESP, 0);
60 	x86_write_msr(IA32_MSR_SYSENTER_EIP, (addr_t)x86_sysenter);
61 
62 	gX86SetSyscallStack = &set_intel_syscall_stack;
63 }
64 
65 
66 #if 0
67 static void
68 init_amd_syscall_registers(void* dummy, int cpuNum)
69 {
70 	// TODO: ...
71 }
72 #endif
73 
74 
75 // #pragma mark -
76 
77 
78 void
79 x86_initialize_syscall(void)
80 {
81 	void* syscallCode = (void *)&x86_user_syscall_int;
82 	void* syscallCodeEnd = &x86_user_syscall_int_end;
83 
84 	// check syscall
85 	if (all_cpus_have_feature(FEATURE_COMMON, IA32_FEATURE_SEP)
86 		&& !(gCPU[0].arch.family == 6 && gCPU[0].arch.model < 3
87 			&& gCPU[0].arch.stepping < 3)) {
88 		// Intel sysenter/sysexit
89 		dprintf("initialize_commpage_syscall(): sysenter/sysexit supported\n");
90 
91 		// the code to be used in userland
92 		syscallCode = (void *)&x86_user_syscall_sysenter;
93 		syscallCodeEnd = &x86_user_syscall_sysenter_end;
94 
95 		// tell all CPUs to init their sysenter/sysexit related registers
96 		call_all_cpus_sync(&init_intel_syscall_registers, NULL);
97 	} else if (all_cpus_have_feature(FEATURE_EXT_AMD,
98 			IA32_FEATURE_AMD_EXT_SYSCALL)) {
99 		// AMD syscall/sysret
100 		dprintf("initialize_commpage_syscall(): syscall/sysret supported "
101 			"-- not yet by Haiku, though");
102 	} else {
103 		// no special syscall support
104 		dprintf("initialize_commpage_syscall(): no special syscall support\n");
105 	}
106 
107 	// fill in the table entry
108 	size_t len = (size_t)((addr_t)syscallCodeEnd - (addr_t)syscallCode);
109 	addr_t position = fill_commpage_entry(COMMPAGE_ENTRY_X86_SYSCALL,
110 		syscallCode, len);
111 
112 	// add syscall to the commpage image
113 	image_id image = get_commpage_image();
114 	elf_add_memory_image_symbol(image, "commpage_syscall", position, len,
115 		B_SYMBOL_TYPE_TEXT);
116 }
117