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