1 /* 2 * CDDL HEADER START 3 * 4 * The contents of this file are subject to the terms of the 5 * Common Development and Distribution License (the "License"). 6 * You may not use this file except in compliance with the License. 7 * 8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9 * or http://www.opensolaris.org/os/licensing. 10 * See the License for the specific language governing permissions 11 * and limitations under the License. 12 * 13 * When distributing Covered Code, include this CDDL HEADER in each 14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15 * If applicable, add the following below this CDDL HEADER, with the 16 * fields enclosed by brackets "[]" replaced with your own identifying 17 * information: Portions Copyright [yyyy] [name of copyright owner] 18 * 19 * CDDL HEADER END 20 */ 21 22 /* 23 * Copyright 2007 Sun Microsystems, Inc. All rights reserved. 24 * Use is subject to license terms. 25 */ 26 27 #ifndef _THR_INLINES_H 28 #define _THR_INLINES_H 29 30 #include <sys/ccompile.h> 31 32 #if !defined(__lint) && defined(__GNUC__) 33 34 /* inlines for gcc */ 35 36 /* 37 * ON-usable GCC 4.x emits register pseudo-ops declaring %g7 as ignored, rather 38 * than scratch, GCC 3 does the reverse. All uses, both ones it generated 39 * (_curthread) and ones it didn't (__curthread) must agree. 40 */ 41 #if __GNUC__ > 3 42 #define SPARC_REG_SPEC "#ignore" 43 #else 44 #define SPARC_REG_SPEC "#scratch" 45 #endif 46 47 extern __GNU_INLINE ulwp_t * 48 _curthread(void) 49 { 50 #if defined(__amd64) 51 ulwp_t *__value; 52 __asm__ __volatile__("movq %%fs:0, %0" : "=r" (__value)); 53 #elif defined(__i386) 54 ulwp_t *__value; 55 __asm__ __volatile__("movl %%gs:0, %0" : "=r" (__value)); 56 #elif defined(__sparc) 57 register ulwp_t *__value __asm__("g7"); 58 #else 59 #error "port me" 60 #endif 61 return (__value); 62 } 63 64 extern __GNU_INLINE ulwp_t * 65 __curthread(void) 66 { 67 ulwp_t *__value; 68 __asm__ __volatile__( 69 #if defined(__amd64) 70 "movq %%fs:0, %0\n\t" 71 #elif defined(__i386) 72 "movl %%gs:0, %0\n\t" 73 #elif defined(__sparcv9) 74 ".register %%g7, " SPARC_REG_SPEC "\n\t" 75 "ldx [%%g7 + 80], %0\n\t" 76 #elif defined(__sparc) 77 ".register %%g7, " SPARC_REG_SPEC "\n\t" 78 "ld [%%g7 + 80], %0\n\t" 79 #else 80 #error "port me" 81 #endif 82 : "=r" (__value)); 83 return (__value); 84 } 85 86 extern __GNU_INLINE greg_t 87 stkptr(void) 88 { 89 #if defined(__amd64) 90 register greg_t __value __asm__("rsp"); 91 #elif defined(__i386) 92 register greg_t __value __asm__("esp"); 93 #elif defined(__sparc) 94 register greg_t __value __asm__("sp"); 95 #else 96 #error "port me" 97 #endif 98 return (__value); 99 } 100 101 extern __GNU_INLINE hrtime_t 102 gethrtime(void) /* note: caller-saved registers are trashed */ 103 { 104 #if defined(__amd64) 105 hrtime_t __value; 106 __asm__ __volatile__( 107 "movl $3, %%eax\n\t" 108 "int $0xd2" 109 : "=a" (__value) 110 : : "rcx", "rdx", "rsi", "rdi", "r8", "r9", "r10", "r11", "cc"); 111 #elif defined(__i386) 112 hrtime_t __value; 113 __asm__ __volatile__( 114 "movl $3, %%eax\n\t" 115 "int $0xd2" 116 : "=A" (__value) 117 : : "ecx", "cc"); 118 #elif defined(__sparcv9) 119 register hrtime_t __value __asm__("o0"); 120 __asm__ __volatile__( 121 "ta 0x24\n\t" 122 "sllx %%o0, 32, %0\n\t" 123 "or %%o1, %0, %0" 124 : "=r" (__value) 125 : : "o1", "o2", "o3", "o4", "o5", "cc"); 126 #elif defined(__sparc) 127 register hrtime_t __value __asm__("o0"); 128 __asm__ __volatile__( 129 "ta 0x24" 130 : "=r" (__value) 131 : : "o2", "o3", "o4", "o5", "cc"); 132 #else 133 #error "port me" 134 #endif 135 return (__value); 136 } 137 138 extern __GNU_INLINE int 139 set_lock_byte(volatile uint8_t *__lockp) 140 { 141 int __value; 142 #if defined(__x86) 143 __asm__ __volatile__( 144 "movl $1, %0\n\t" 145 "xchgb %%dl, %1" 146 : "+d" (__value), "+m" (*__lockp)); 147 #elif defined(__sparc) 148 __asm__ __volatile__( 149 "ldstub %1, %0\n\t" 150 "membar #LoadLoad" 151 : "=r" (__value), "+m" (*__lockp)); 152 #else 153 #error "port me" 154 #endif 155 return (__value); 156 } 157 158 extern __GNU_INLINE uint32_t 159 atomic_swap_32(volatile uint32_t *__memory, uint32_t __value) 160 { 161 #if defined(__x86) 162 __asm__ __volatile__( 163 "xchgl %0, %1" 164 : "+q" (__value), "+m" (*__memory)); 165 return (__value); 166 #elif defined(__sparc) 167 uint32_t __tmp1, __tmp2; 168 __asm__ __volatile__( 169 "ld [%3], %0\n\t" 170 "1:\n\t" 171 "mov %4, %1\n\t" 172 "cas [%3], %0, %1\n\t" 173 "cmp %0, %1\n\t" 174 "bne,a,pn %%icc, 1b\n\t" 175 " mov %1, %0" 176 : "=&r" (__tmp1), "=&r" (__tmp2), "=m" (*__memory) 177 : "r" (__memory), "r" (__value) 178 : "cc"); 179 return (__tmp2); 180 #else 181 #error "port me" 182 #endif 183 } 184 185 extern __GNU_INLINE uint32_t 186 atomic_cas_32(volatile uint32_t *__memory, uint32_t __cmp, uint32_t __newvalue) 187 { 188 uint32_t __oldvalue; 189 #if defined(__x86) 190 __asm__ __volatile__( 191 "lock; cmpxchgl %3, %0" 192 : "=m" (*__memory), "=a" (__oldvalue) 193 : "a" (__cmp), "r" (__newvalue)); 194 #elif defined(__sparc) 195 __asm__ __volatile__( 196 "cas [%2], %3, %1" 197 : "=m" (*__memory), "=&r" (__oldvalue) 198 : "r" (__memory), "r" (__cmp), "1" (__newvalue)); 199 #else 200 #error "port me" 201 #endif 202 return (__oldvalue); 203 } 204 205 extern __GNU_INLINE void 206 atomic_inc_32(volatile uint32_t *__memory) 207 { 208 #if defined(__x86) 209 __asm__ __volatile__( 210 "lock; incl %0" 211 : "+m" (*__memory)); 212 #elif defined(__sparc) 213 uint32_t __tmp1, __tmp2; 214 __asm__ __volatile__( 215 "ld [%3], %0\n\t" 216 "1:\n\t" 217 "add %0, 1, %1\n\t" 218 "cas [%3], %0, %1\n\t" 219 "cmp %0, %1\n\t" 220 "bne,a,pn %%icc, 1b\n\t" 221 " mov %1, %0" 222 : "=&r" (__tmp1), "=&r" (__tmp2), "=m" (*__memory) 223 : "r" (__memory) 224 : "cc"); 225 #else 226 #error "port me" 227 #endif 228 } 229 230 extern __GNU_INLINE void 231 atomic_dec_32(volatile uint32_t *__memory) 232 { 233 #if defined(__x86) 234 __asm__ __volatile__( 235 "lock; decl %0" 236 : "+m" (*__memory)); 237 #elif defined(__sparc) 238 uint32_t __tmp1, __tmp2; 239 __asm__ __volatile__( 240 "ld [%3], %0\n\t" 241 "1:\n\t" 242 "sub %0, 1, %1\n\t" 243 "cas [%3], %0, %1\n\t" 244 "cmp %0, %1\n\t" 245 "bne,a,pn %%icc, 1b\n\t" 246 " mov %1, %0" 247 : "=&r" (__tmp1), "=&r" (__tmp2), "=m" (*__memory) 248 : "r" (__memory) 249 : "cc"); 250 #else 251 #error "port me" 252 #endif 253 } 254 255 extern __GNU_INLINE void 256 atomic_and_32(volatile uint32_t *__memory, uint32_t __bits) 257 { 258 #if defined(__x86) 259 __asm__ __volatile__( 260 "lock; andl %1, %0" 261 : "+m" (*__memory) 262 : "r" (__bits)); 263 #elif defined(__sparc) 264 uint32_t __tmp1, __tmp2; 265 __asm__ __volatile__( 266 "ld [%3], %0\n\t" 267 "1:\n\t" 268 "and %0, %4, %1\n\t" 269 "cas [%3], %0, %1\n\t" 270 "cmp %0, %1\n\t" 271 "bne,a,pn %%icc, 1b\n\t" 272 " mov %1, %0" 273 : "=&r" (__tmp1), "=&r" (__tmp2), "=m" (*__memory) 274 : "r" (__memory), "r" (__bits) 275 : "cc"); 276 #else 277 #error "port me" 278 #endif 279 } 280 281 extern __GNU_INLINE void 282 atomic_or_32(volatile uint32_t *__memory, uint32_t __bits) 283 { 284 #if defined(__x86) 285 __asm__ __volatile__( 286 "lock; orl %1, %0" 287 : "+m" (*__memory) 288 : "r" (__bits)); 289 #elif defined(__sparc) 290 uint32_t __tmp1, __tmp2; 291 __asm__ __volatile__( 292 "ld [%3], %0\n\t" 293 "1:\n\t" 294 "or %0, %4, %1\n\t" 295 "cas [%3], %0, %1\n\t" 296 "cmp %0, %1\n\t" 297 "bne,a,pn %%icc, 1b\n\t" 298 " mov %1, %0" 299 : "=&r" (__tmp1), "=&r" (__tmp2), "=m" (*__memory) 300 : "r" (__memory), "r" (__bits) 301 : "cc"); 302 #else 303 #error "port me" 304 #endif 305 } 306 307 #if defined(__sparc) /* only needed on sparc */ 308 309 extern __GNU_INLINE ulong_t 310 caller(void) 311 { 312 register ulong_t __value __asm__("i7"); 313 return (__value); 314 } 315 316 extern __GNU_INLINE ulong_t 317 getfp(void) 318 { 319 register ulong_t __value __asm__("fp"); 320 return (__value); 321 } 322 323 #endif /* __sparc */ 324 325 #if defined(__x86) /* only needed on x86 */ 326 327 extern __GNU_INLINE void 328 ht_pause(void) 329 { 330 __asm__ __volatile__("rep; nop"); 331 } 332 333 #endif /* __x86 */ 334 335 #endif /* !__lint && __GNUC__ */ 336 337 #endif /* _THR_INLINES_H */