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 = (void *)&_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 = (void *)&_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