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