1 /* $NetBSD: pthread_md.h,v 1.15 2008/06/23 10:39:38 ad Exp $ */ 2 3 /*- 4 * Copyright (c) 2001, 2007, 2008 The NetBSD Foundation, Inc. 5 * All rights reserved. 6 * 7 * This code is derived from software contributed to The NetBSD Foundation 8 * by Nathan J. Williams, and by Andrew Doran. 9 * 10 * Redistribution and use in source and binary forms, with or without 11 * modification, are permitted provided that the following conditions 12 * are met: 13 * 1. Redistributions of source code must retain the above copyright 14 * notice, this list of conditions and the following disclaimer. 15 * 2. Redistributions in binary form must reproduce the above copyright 16 * notice, this list of conditions and the following disclaimer in the 17 * documentation and/or other materials provided with the distribution. 18 * 19 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 20 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 21 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 22 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 23 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 24 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 25 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 26 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 27 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 28 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 29 * POSSIBILITY OF SUCH DAMAGE. 30 */ 31 32 #ifndef _LIB_PTHREAD_I386_MD_H 33 #define _LIB_PTHREAD_I386_MD_H 34 35 #include <sys/ucontext.h> 36 #include <ucontext.h> 37 38 extern int (*_md_getcontext_u)(ucontext_t *); 39 extern int (*_md_setcontext_u)(const ucontext_t *); 40 extern int (*_md_swapcontext_u)(ucontext_t *, const ucontext_t *); 41 42 #define _getcontext_u(uc) (*_md_getcontext_u)((uc)) 43 #define _setcontext_u(uc) (*_md_setcontext_u)((uc)) 44 #define _swapcontext_u(ouc, nuc) (*_md_swapcontext_u)((ouc), (nuc)) 45 46 int _getcontext_u_s87(ucontext_t *); 47 int _setcontext_u_s87(const ucontext_t *); 48 int _swapcontext_u_s87(ucontext_t *, const ucontext_t *); 49 int _getcontext_u_xmm(ucontext_t *); 50 int _setcontext_u_xmm(const ucontext_t *); 51 int _swapcontext_u_xmm(ucontext_t *, const ucontext_t *); 52 53 void pthread__i386_init(void); 54 55 #define PTHREAD_MD_INIT pthread__i386_init(); 56 57 static inline long 58 pthread__sp(void) 59 { 60 long ret; 61 __asm("movl %%esp, %0" : "=g" (ret)); 62 63 return ret; 64 } 65 66 #define pthread__uc_sp(ucp) ((ucp)->uc_mcontext.__gregs[_REG_UESP]) 67 #define pthread__uc_pc(ucp) ((ucp)->uc_mcontext.__gregs[_REG_EIP]) 68 69 /* 70 * Set initial, sane values for registers whose values aren't just 71 * "don't care". 72 * 73 * We use the current context instead of a guessed one because we cannot 74 * assume how the GDT entries are ordered: what is true on i386 is not 75 * true anymore on amd64. 76 */ 77 #define _INITCONTEXT_U_MD(ucp) \ 78 do { \ 79 ucontext_t ucur; \ 80 (void)getcontext(&ucur); \ 81 (ucp)->uc_mcontext.__gregs[_REG_GS] = \ 82 ucur.uc_mcontext.__gregs[_REG_GS], \ 83 (ucp)->uc_mcontext.__gregs[_REG_FS] = \ 84 ucur.uc_mcontext.__gregs[_REG_FS], \ 85 (ucp)->uc_mcontext.__gregs[_REG_ES] = \ 86 ucur.uc_mcontext.__gregs[_REG_ES], \ 87 (ucp)->uc_mcontext.__gregs[_REG_DS] = \ 88 ucur.uc_mcontext.__gregs[_REG_DS], \ 89 (ucp)->uc_mcontext.__gregs[_REG_CS] = \ 90 ucur.uc_mcontext.__gregs[_REG_CS], \ 91 (ucp)->uc_mcontext.__gregs[_REG_SS] = \ 92 ucur.uc_mcontext.__gregs[_REG_SS], \ 93 (ucp)->uc_mcontext.__gregs[_REG_EFL] = \ 94 ucur.uc_mcontext.__gregs[_REG_EFL]; \ 95 } while (/*CONSTCOND*/0); 96 97 /* 98 * Usable stack space below the ucontext_t. 99 * See comment in pthread_switch.S about STACK_SWITCH. 100 */ 101 #define STACKSPACE 32 /* room for 8 integer values */ 102 103 /* 104 * Conversions between struct reg and struct mcontext. Used by 105 * libpthread_dbg. 106 */ 107 108 #define PTHREAD_UCONTEXT_TO_REG(reg, uc) do { \ 109 (reg)->r_gs = (uc)->uc_mcontext.__gregs[_REG_GS]; \ 110 (reg)->r_fs = (uc)->uc_mcontext.__gregs[_REG_FS]; \ 111 (reg)->r_es = (uc)->uc_mcontext.__gregs[_REG_ES]; \ 112 (reg)->r_ds = (uc)->uc_mcontext.__gregs[_REG_DS]; \ 113 (reg)->r_edi = (uc)->uc_mcontext.__gregs[_REG_EDI]; \ 114 (reg)->r_esi = (uc)->uc_mcontext.__gregs[_REG_ESI]; \ 115 (reg)->r_ebp = (uc)->uc_mcontext.__gregs[_REG_EBP]; \ 116 (reg)->r_ebx = (uc)->uc_mcontext.__gregs[_REG_EBX]; \ 117 (reg)->r_edx = (uc)->uc_mcontext.__gregs[_REG_EDX]; \ 118 (reg)->r_ecx = (uc)->uc_mcontext.__gregs[_REG_ECX]; \ 119 (reg)->r_eax = (uc)->uc_mcontext.__gregs[_REG_EAX]; \ 120 (reg)->r_eip = (uc)->uc_mcontext.__gregs[_REG_EIP]; \ 121 (reg)->r_cs = (uc)->uc_mcontext.__gregs[_REG_CS]; \ 122 (reg)->r_eflags = (uc)->uc_mcontext.__gregs[_REG_EFL]; \ 123 (reg)->r_esp = (uc)->uc_mcontext.__gregs[_REG_UESP]; \ 124 (reg)->r_ss = (uc)->uc_mcontext.__gregs[_REG_SS]; \ 125 } while (/*CONSTCOND*/0) 126 127 #define PTHREAD_REG_TO_UCONTEXT(uc, reg) do { \ 128 (uc)->uc_mcontext.__gregs[_REG_GS] = (reg)->r_gs; \ 129 (uc)->uc_mcontext.__gregs[_REG_FS] = (reg)->r_fs; \ 130 (uc)->uc_mcontext.__gregs[_REG_ES] = (reg)->r_es; \ 131 (uc)->uc_mcontext.__gregs[_REG_DS] = (reg)->r_ds; \ 132 (uc)->uc_mcontext.__gregs[_REG_EDI] = (reg)->r_edi; \ 133 (uc)->uc_mcontext.__gregs[_REG_ESI] = (reg)->r_esi; \ 134 (uc)->uc_mcontext.__gregs[_REG_EBP] = (reg)->r_ebp; \ 135 (uc)->uc_mcontext.__gregs[_REG_EBX] = (reg)->r_ebx; \ 136 (uc)->uc_mcontext.__gregs[_REG_EDX] = (reg)->r_edx; \ 137 (uc)->uc_mcontext.__gregs[_REG_ECX] = (reg)->r_ecx; \ 138 (uc)->uc_mcontext.__gregs[_REG_EAX] = (reg)->r_eax; \ 139 (uc)->uc_mcontext.__gregs[_REG_EIP] = (reg)->r_eip; \ 140 (uc)->uc_mcontext.__gregs[_REG_CS] = (reg)->r_cs; \ 141 (uc)->uc_mcontext.__gregs[_REG_EFL] = (reg)->r_eflags; \ 142 (uc)->uc_mcontext.__gregs[_REG_UESP]= (reg)->r_esp; \ 143 (uc)->uc_mcontext.__gregs[_REG_SS] = (reg)->r_ss; \ 144 /*LINTED precision loss */ \ 145 (uc)->uc_flags = ((uc)->uc_flags | _UC_CPU) & ~_UC_USER; \ 146 } while (/*CONSTCOND*/0) 147 148 149 #define PTHREAD_UCONTEXT_TO_FPREG(freg, uc) \ 150 (void)memcpy((freg)->__data, \ 151 (uc)->uc_mcontext.__fpregs.__fp_reg_set.__fpchip_state.__fp_state, \ 152 sizeof(struct fpreg)) 153 154 #define PTHREAD_FPREG_TO_UCONTEXT(uc, freg) do { \ 155 (void)memcpy( \ 156 (uc)->uc_mcontext.__fpregs.__fp_reg_set.__fpchip_state.__fp_state, \ 157 (freg)->__data, sizeof(struct fpreg)); \ 158 /*LINTED precision loss */ \ 159 (uc)->uc_flags = ((uc)->uc_flags | _UC_FPU) & ~_UC_USER; \ 160 } while (/*CONSTCOND*/0) 161 162 #define PTHREAD_UCONTEXT_XREG_FLAG _UC_FXSAVE 163 164 #define PTHREAD_UCONTEXT_TO_XREG(xreg, uc) \ 165 (void)memcpy((xreg), \ 166 (uc)->uc_mcontext.__fpregs.__fp_reg_set.__fp_xmm_state.__fp_xmm, \ 167 sizeof(struct xmmregs)) 168 169 #define PTHREAD_XREG_TO_UCONTEXT(uc, xreg) do { \ 170 (void)memcpy( \ 171 (uc)->uc_mcontext.__fpregs.__fp_reg_set.__fp_xmm_state.__fp_xmm, \ 172 (xreg), \ 173 sizeof(struct xmmregs)); \ 174 (uc)->uc_flags = ((uc)->uc_flags | _UC_FXSAVE) & ~_UC_USER; \ 175 } while (/*CONSTCOND*/0) 176 177 #define pthread__smt_pause() __asm __volatile("rep; nop" ::: "memory") 178 /* #define PTHREAD__HAVE_THREADREG */ 179 180 /* Don't need additional memory barriers. */ 181 #define PTHREAD__ATOMIC_IS_MEMBAR 182 183 void pthread__threadreg_set(pthread_t); 184 185 static inline pthread_t 186 #ifdef __GNUC__ 187 __attribute__ ((__const__)) 188 #endif 189 pthread__threadreg_get(void) 190 { 191 pthread_t self; 192 193 __asm volatile("movl %%gs:0, %0" 194 : "=r" (self) 195 :); 196 197 return self; 198 } 199 200 static inline void * 201 _atomic_cas_ptr(volatile void *ptr, void *old, void *new) 202 { 203 volatile uintptr_t *cast = ptr; 204 void *ret; 205 206 __asm __volatile ("lock; cmpxchgl %2, %1" 207 : "=a" (ret), "=m" (*cast) 208 : "r" (new), "m" (*cast), "0" (old)); 209 210 return ret; 211 } 212 213 static inline void * 214 _atomic_cas_ptr_ni(volatile void *ptr, void *old, void *new) 215 { 216 volatile uintptr_t *cast = ptr; 217 void *ret; 218 219 __asm __volatile ("cmpxchgl %2, %1" 220 : "=a" (ret), "=m" (*cast) 221 : "r" (new), "m" (*cast), "0" (old)); 222 223 return ret; 224 } 225 226 #endif /* _LIB_PTHREAD_I386_MD_H */ 227