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