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