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