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