xref: /haiku/src/system/kernel/arch/x86/64/syscalls.cpp (revision 37fedaf8494b34aad811abcc49e79aa32943f880)
1 /*
2  * Copyright 2012, Alex Smith, alex@alex-smith.me.uk.
3  * Distributed under the terms of the MIT License.
4  */
5 
6 
7 #include "x86_syscalls.h"
8 
9 #include <KernelExport.h>
10 
11 #include <cpu.h>
12 #include <smp.h>
13 
14 
15 // SYSCALL handler (in interrupts.S).
16 extern "C" void x86_64_syscall_entry(void);
17 
18 
19 static void
20 init_syscall_registers(void* dummy, int cpuNum)
21 {
22 	// Enable SYSCALL (EFER.SCE = 1).
23 	x86_write_msr(IA32_MSR_EFER, x86_read_msr(IA32_MSR_EFER)
24 		| IA32_MSR_EFER_SYSCALL);
25 
26 	// Flags to clear upon entry. Want interrupts disabled and the direction
27 	// flag cleared.
28 	x86_write_msr(IA32_MSR_FMASK, X86_EFLAGS_INTERRUPT | X86_EFLAGS_DIRECTION);
29 
30 	// Entry point address.
31 	x86_write_msr(IA32_MSR_LSTAR, (addr_t)x86_64_syscall_entry);
32 
33 	// Segments that will be set upon entry and return. This is very strange
34 	// and requires a specific ordering of segments in the GDT. Upon entry:
35 	//  - CS is set to IA32_STAR[47:32]
36 	//  - SS is set to IA32_STAR[47:32] + 8
37 	// Upon return:
38 	//  - CS is set to IA32_STAR[63:48] + 16
39 	//  - SS is set to IA32_STAR[63:48] + 8
40 	// From this we get:
41 	//  - Entry CS  = KERNEL_CODE_SELECTOR
42 	//  - Entry SS  = KERNEL_CODE_SELECTOR + 8  = KERNEL_DATA_SELECTOR
43 	//  - Return CS = KERNEL_DATA_SELECTOR + 16 = USER_CODE_SELECTOR
44 	//  - Return SS = KERNEL_DATA_SELECTOR + 8  = USER_DATA_SLECTORG
45 	x86_write_msr(IA32_MSR_STAR, ((uint64)(KERNEL_DATA_SELECTOR | 3) << 48)
46 		| ((uint64)KERNEL_CODE_SELECTOR << 32));
47 }
48 
49 
50 // #pragma mark -
51 
52 
53 void
54 x86_initialize_syscall(void)
55 {
56 	// SYSCALL/SYSRET are always available on x86_64 so we just use them, no
57 	// need to use the commpage. Tell all CPUs to initialize the SYSCALL MSRs.
58 	call_all_cpus_sync(&init_syscall_registers, NULL);
59 }
60