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