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