atomic.h revision 84679
1/*- 2 * Copyright (c) 1998 Doug Rabson 3 * All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions 7 * are met: 8 * 1. Redistributions of source code must retain the above copyright 9 * notice, this list of conditions and the following disclaimer. 10 * 2. Redistributions in binary form must reproduce the above copyright 11 * notice, this list of conditions and the following disclaimer in the 12 * documentation and/or other materials provided with the distribution. 13 * 14 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 15 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 18 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 20 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 21 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 22 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 23 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 24 * SUCH DAMAGE. 25 * 26 * $FreeBSD: head/sys/amd64/include/atomic.h 84679 2001-10-08 20:58:24Z jhb $ 27 */ 28#ifndef _MACHINE_ATOMIC_H_ 29#define _MACHINE_ATOMIC_H_ 30 31/* 32 * Various simple arithmetic on memory which is atomic in the presence 33 * of interrupts and multiple processors. 34 * 35 * atomic_set_char(P, V) (*(u_char*)(P) |= (V)) 36 * atomic_clear_char(P, V) (*(u_char*)(P) &= ~(V)) 37 * atomic_add_char(P, V) (*(u_char*)(P) += (V)) 38 * atomic_subtract_char(P, V) (*(u_char*)(P) -= (V)) 39 * 40 * atomic_set_short(P, V) (*(u_short*)(P) |= (V)) 41 * atomic_clear_short(P, V) (*(u_short*)(P) &= ~(V)) 42 * atomic_add_short(P, V) (*(u_short*)(P) += (V)) 43 * atomic_subtract_short(P, V) (*(u_short*)(P) -= (V)) 44 * 45 * atomic_set_int(P, V) (*(u_int*)(P) |= (V)) 46 * atomic_clear_int(P, V) (*(u_int*)(P) &= ~(V)) 47 * atomic_add_int(P, V) (*(u_int*)(P) += (V)) 48 * atomic_subtract_int(P, V) (*(u_int*)(P) -= (V)) 49 * atomic_readandclear_int(P) (return *(u_int*)P; *(u_int*)P = 0;) 50 * 51 * atomic_set_long(P, V) (*(u_long*)(P) |= (V)) 52 * atomic_clear_long(P, V) (*(u_long*)(P) &= ~(V)) 53 * atomic_add_long(P, V) (*(u_long*)(P) += (V)) 54 * atomic_subtract_long(P, V) (*(u_long*)(P) -= (V)) 55 * atomic_readandclear_long(P) (return *(u_long*)P; *(u_long*)P = 0;) 56 */ 57 58/* 59 * The above functions are expanded inline in the statically-linked 60 * kernel. Lock prefixes are generated if an SMP kernel is being 61 * built. 62 * 63 * Kernel modules call real functions which are built into the kernel. 64 * This allows kernel modules to be portable between UP and SMP systems. 65 */ 66#if defined(KLD_MODULE) 67#define ATOMIC_ASM(NAME, TYPE, OP, V) \ 68void atomic_##NAME##_##TYPE(volatile u_##TYPE *p, u_##TYPE v); 69 70int atomic_cmpset_int(volatile u_int *dst, u_int exp, u_int src); 71 72#define ATOMIC_STORE_LOAD(TYPE, LOP, SOP) \ 73u_##TYPE atomic_load_acq_##TYPE(volatile u_##TYPE *p); \ 74void atomic_store_rel_##TYPE(volatile u_##TYPE *p, u_##TYPE v); 75 76#else /* !KLD_MODULE */ 77 78/* 79 * For userland, assume the SMP case and use lock prefixes so that 80 * the binaries will run on both types of systems. 81 */ 82#if defined(SMP) || !defined(_KERNEL) 83#if defined(LOCORE) 84#define MPLOCKED lock ; 85#else /* !LOCORE */ 86#define MPLOCKED "lock ; " 87#endif /* LOCORE */ 88#else /* SMP || !_KERNEL */ 89#define MPLOCKED 90#endif /* SMP || !_KERNEL */ 91 92#if !defined(LOCORE) 93/* 94 * The assembly is volatilized to demark potential before-and-after side 95 * effects if an interrupt or SMP collision were to occur. 96 */ 97#define ATOMIC_ASM(NAME, TYPE, OP, V) \ 98static __inline void \ 99atomic_##NAME##_##TYPE(volatile u_##TYPE *p, u_##TYPE v)\ 100{ \ 101 __asm __volatile(MPLOCKED OP \ 102 : "=m" (*p) \ 103 : "0" (*p), "ir" (V)); \ 104} 105 106/* 107 * Atomic compare and set, used by the mutex functions 108 * 109 * if (*dst == exp) *dst = src (all 32 bit words) 110 * 111 * Returns 0 on failure, non-zero on success 112 */ 113 114#if defined(I386_CPU) 115static __inline int 116atomic_cmpset_int(volatile u_int *dst, u_int exp, u_int src) 117{ 118 int res = exp; 119 120 __asm __volatile( 121 " pushfl ; " 122 " cli ; " 123 " cmpl %1,%3 ; " 124 " jne 1f ; " 125 " movl %2,%3 ; " 126 "1: " 127 " sete %%al; " 128 " movzbl %%al,%0 ; " 129 " popfl ; " 130 "# atomic_cmpset_int" 131 : "=a" (res) /* 0 (result) */ 132 : "0" (exp), /* 1 */ 133 "r" (src), /* 2 */ 134 "m" (*(dst)) /* 3 */ 135 : "memory"); 136 137 return (res); 138} 139#else /* defined(I386_CPU) */ 140static __inline int 141atomic_cmpset_int(volatile u_int *dst, u_int exp, u_int src) 142{ 143 int res = exp; 144 145 __asm __volatile ( 146 " " MPLOCKED " " 147 " cmpxchgl %2,%3 ; " 148 " setz %%al ; " 149 " movzbl %%al,%0 ; " 150 "1: " 151 "# atomic_cmpset_int" 152 : "=a" (res) /* 0 (result) */ 153 : "0" (exp), /* 1 */ 154 "r" (src), /* 2 */ 155 "m" (*(dst)) /* 3 */ 156 : "memory"); 157 158 return (res); 159} 160#endif /* defined(I386_CPU) */ 161 162#if defined(I386_CPU) 163/* 164 * We assume that a = b will do atomic loads and stores. 165 * 166 * XXX: This is _NOT_ safe on a P6 or higher because it does not guarantee 167 * memory ordering. These should only be used on a 386. 168 */ 169#define ATOMIC_STORE_LOAD(TYPE, LOP, SOP) \ 170static __inline u_##TYPE \ 171atomic_load_acq_##TYPE(volatile u_##TYPE *p) \ 172{ \ 173 return (*p); \ 174} \ 175 \ 176static __inline void \ 177atomic_store_rel_##TYPE(volatile u_##TYPE *p, u_##TYPE v)\ 178{ \ 179 *p = v; \ 180 __asm __volatile("" : : : "memory"); \ 181} 182#else 183 184#define ATOMIC_STORE_LOAD(TYPE, LOP, SOP) \ 185static __inline u_##TYPE \ 186atomic_load_acq_##TYPE(volatile u_##TYPE *p) \ 187{ \ 188 u_##TYPE res; \ 189 \ 190 __asm __volatile(MPLOCKED LOP \ 191 : "=a" (res), /* 0 (result) */\ 192 "+m" (*p) /* 1 */ \ 193 : : "cc", "memory"); \ 194 \ 195 return (res); \ 196} \ 197 \ 198/* \ 199 * The XCHG instruction asserts LOCK automagically. \ 200 */ \ 201static __inline void \ 202atomic_store_rel_##TYPE(volatile u_##TYPE *p, u_##TYPE v)\ 203{ \ 204 __asm __volatile(SOP \ 205 : "+m" (*p), /* 0 */ \ 206 "+r" (v) /* 1 */ \ 207 : : "memory"); \ 208} 209#endif /* defined(I386_CPU) */ 210#endif /* !defined(LOCORE) */ 211#endif /* KLD_MODULE */ 212 213#if !defined(LOCORE) 214ATOMIC_ASM(set, char, "orb %b2,%0", v) 215ATOMIC_ASM(clear, char, "andb %b2,%0", ~v) 216ATOMIC_ASM(add, char, "addb %b2,%0", v) 217ATOMIC_ASM(subtract, char, "subb %b2,%0", v) 218 219ATOMIC_ASM(set, short, "orw %w2,%0", v) 220ATOMIC_ASM(clear, short, "andw %w2,%0", ~v) 221ATOMIC_ASM(add, short, "addw %w2,%0", v) 222ATOMIC_ASM(subtract, short, "subw %w2,%0", v) 223 224ATOMIC_ASM(set, int, "orl %2,%0", v) 225ATOMIC_ASM(clear, int, "andl %2,%0", ~v) 226ATOMIC_ASM(add, int, "addl %2,%0", v) 227ATOMIC_ASM(subtract, int, "subl %2,%0", v) 228 229ATOMIC_ASM(set, long, "orl %2,%0", v) 230ATOMIC_ASM(clear, long, "andl %2,%0", ~v) 231ATOMIC_ASM(add, long, "addl %2,%0", v) 232ATOMIC_ASM(subtract, long, "subl %2,%0", v) 233 234ATOMIC_STORE_LOAD(char, "cmpxchgb %b0,%1", "xchgb %b1,%0") 235ATOMIC_STORE_LOAD(short,"cmpxchgw %w0,%1", "xchgw %w1,%0") 236ATOMIC_STORE_LOAD(int, "cmpxchgl %0,%1", "xchgl %1,%0") 237ATOMIC_STORE_LOAD(long, "cmpxchgl %0,%1", "xchgl %1,%0") 238 239#undef ATOMIC_ASM 240#undef ATOMIC_STORE_LOAD 241 242#define atomic_set_acq_char atomic_set_char 243#define atomic_set_rel_char atomic_set_char 244#define atomic_clear_acq_char atomic_clear_char 245#define atomic_clear_rel_char atomic_clear_char 246#define atomic_add_acq_char atomic_add_char 247#define atomic_add_rel_char atomic_add_char 248#define atomic_subtract_acq_char atomic_subtract_char 249#define atomic_subtract_rel_char atomic_subtract_char 250 251#define atomic_set_acq_short atomic_set_short 252#define atomic_set_rel_short atomic_set_short 253#define atomic_clear_acq_short atomic_clear_short 254#define atomic_clear_rel_short atomic_clear_short 255#define atomic_add_acq_short atomic_add_short 256#define atomic_add_rel_short atomic_add_short 257#define atomic_subtract_acq_short atomic_subtract_short 258#define atomic_subtract_rel_short atomic_subtract_short 259 260#define atomic_set_acq_int atomic_set_int 261#define atomic_set_rel_int atomic_set_int 262#define atomic_clear_acq_int atomic_clear_int 263#define atomic_clear_rel_int atomic_clear_int 264#define atomic_add_acq_int atomic_add_int 265#define atomic_add_rel_int atomic_add_int 266#define atomic_subtract_acq_int atomic_subtract_int 267#define atomic_subtract_rel_int atomic_subtract_int 268#define atomic_cmpset_acq_int atomic_cmpset_int 269#define atomic_cmpset_rel_int atomic_cmpset_int 270 271#define atomic_set_acq_long atomic_set_long 272#define atomic_set_rel_long atomic_set_long 273#define atomic_clear_acq_long atomic_clear_long 274#define atomic_clear_rel_long atomic_clear_long 275#define atomic_add_acq_long atomic_add_long 276#define atomic_add_rel_long atomic_add_long 277#define atomic_subtract_acq_long atomic_subtract_long 278#define atomic_subtract_rel_long atomic_subtract_long 279#define atomic_cmpset_long atomic_cmpset_int 280#define atomic_cmpset_acq_long atomic_cmpset_acq_int 281#define atomic_cmpset_rel_long atomic_cmpset_rel_int 282 283#define atomic_cmpset_acq_ptr atomic_cmpset_ptr 284#define atomic_cmpset_rel_ptr atomic_cmpset_ptr 285 286#define atomic_set_8 atomic_set_char 287#define atomic_set_acq_8 atomic_set_acq_char 288#define atomic_set_rel_8 atomic_set_rel_char 289#define atomic_clear_8 atomic_clear_char 290#define atomic_clear_acq_8 atomic_clear_acq_char 291#define atomic_clear_rel_8 atomic_clear_rel_char 292#define atomic_add_8 atomic_add_char 293#define atomic_add_acq_8 atomic_add_acq_char 294#define atomic_add_rel_8 atomic_add_rel_char 295#define atomic_subtract_8 atomic_subtract_char 296#define atomic_subtract_acq_8 atomic_subtract_acq_char 297#define atomic_subtract_rel_8 atomic_subtract_rel_char 298#define atomic_load_acq_8 atomic_load_acq_char 299#define atomic_store_rel_8 atomic_store_rel_char 300 301#define atomic_set_16 atomic_set_short 302#define atomic_set_acq_16 atomic_set_acq_short 303#define atomic_set_rel_16 atomic_set_rel_short 304#define atomic_clear_16 atomic_clear_short 305#define atomic_clear_acq_16 atomic_clear_acq_short 306#define atomic_clear_rel_16 atomic_clear_rel_short 307#define atomic_add_16 atomic_add_short 308#define atomic_add_acq_16 atomic_add_acq_short 309#define atomic_add_rel_16 atomic_add_rel_short 310#define atomic_subtract_16 atomic_subtract_short 311#define atomic_subtract_acq_16 atomic_subtract_acq_short 312#define atomic_subtract_rel_16 atomic_subtract_rel_short 313#define atomic_load_acq_16 atomic_load_acq_short 314#define atomic_store_rel_16 atomic_store_rel_short 315 316#define atomic_set_32 atomic_set_int 317#define atomic_set_acq_32 atomic_set_acq_int 318#define atomic_set_rel_32 atomic_set_rel_int 319#define atomic_clear_32 atomic_clear_int 320#define atomic_clear_acq_32 atomic_clear_acq_int 321#define atomic_clear_rel_32 atomic_clear_rel_int 322#define atomic_add_32 atomic_add_int 323#define atomic_add_acq_32 atomic_add_acq_int 324#define atomic_add_rel_32 atomic_add_rel_int 325#define atomic_subtract_32 atomic_subtract_int 326#define atomic_subtract_acq_32 atomic_subtract_acq_int 327#define atomic_subtract_rel_32 atomic_subtract_rel_int 328#define atomic_load_acq_32 atomic_load_acq_int 329#define atomic_store_rel_32 atomic_store_rel_int 330#define atomic_cmpset_32 atomic_cmpset_int 331#define atomic_cmpset_acq_32 atomic_cmpset_acq_int 332#define atomic_cmpset_rel_32 atomic_cmpset_rel_int 333#define atomic_readandclear_32 atomic_readandclear_int 334 335#if !defined(WANT_FUNCTIONS) 336static __inline int 337atomic_cmpset_ptr(volatile void *dst, void *exp, void *src) 338{ 339 340 return (atomic_cmpset_int((volatile u_int *)dst, (u_int)exp, 341 (u_int)src)); 342} 343 344static __inline void * 345atomic_load_acq_ptr(volatile void *p) 346{ 347 return (void *)atomic_load_acq_int((volatile u_int *)p); 348} 349 350static __inline void 351atomic_store_rel_ptr(volatile void *p, void *v) 352{ 353 atomic_store_rel_int((volatile u_int *)p, (u_int)v); 354} 355 356#define ATOMIC_PTR(NAME) \ 357static __inline void \ 358atomic_##NAME##_ptr(volatile void *p, uintptr_t v) \ 359{ \ 360 atomic_##NAME##_int((volatile u_int *)p, v); \ 361} \ 362 \ 363static __inline void \ 364atomic_##NAME##_acq_ptr(volatile void *p, uintptr_t v) \ 365{ \ 366 atomic_##NAME##_acq_int((volatile u_int *)p, v);\ 367} \ 368 \ 369static __inline void \ 370atomic_##NAME##_rel_ptr(volatile void *p, uintptr_t v) \ 371{ \ 372 atomic_##NAME##_rel_int((volatile u_int *)p, v);\ 373} 374 375ATOMIC_PTR(set) 376ATOMIC_PTR(clear) 377ATOMIC_PTR(add) 378ATOMIC_PTR(subtract) 379 380#undef ATOMIC_PTR 381 382static __inline u_int 383atomic_readandclear_int(volatile u_int *addr) 384{ 385 u_int result; 386 387 __asm __volatile ( 388 " xorl %0,%0 ; " 389 " xchgl %1,%0 ; " 390 "# atomic_readandclear_int" 391 : "=&r" (result) /* 0 (result) */ 392 : "m" (*addr)); /* 1 (addr) */ 393 394 return (result); 395} 396 397static __inline u_long 398atomic_readandclear_long(volatile u_long *addr) 399{ 400 u_long result; 401 402 __asm __volatile ( 403 " xorl %0,%0 ; " 404 " xchgl %1,%0 ; " 405 "# atomic_readandclear_int" 406 : "=&r" (result) /* 0 (result) */ 407 : "m" (*addr)); /* 1 (addr) */ 408 409 return (result); 410} 411#endif /* !defined(WANT_FUNCTIONS) */ 412#endif /* !defined(LOCORE) */ 413#endif /* ! _MACHINE_ATOMIC_H_ */ 414