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 2010 Sun Microsystems, Inc. All rights reserved. 24 * Use is subject to license terms. 25 */ 26 27 .file "atomic.s" 28 29#include <sys/asm_linkage.h> 30 31#if defined(_KERNEL) 32 /* 33 * Legacy kernel interfaces; they will go away (eventually). 34 */ 35 ANSI_PRAGMA_WEAK2(cas8,atomic_cas_8,function) 36 ANSI_PRAGMA_WEAK2(cas32,atomic_cas_32,function) 37 ANSI_PRAGMA_WEAK2(cas64,atomic_cas_64,function) 38 ANSI_PRAGMA_WEAK2(caslong,atomic_cas_ulong,function) 39 ANSI_PRAGMA_WEAK2(casptr,atomic_cas_ptr,function) 40 ANSI_PRAGMA_WEAK2(atomic_and_long,atomic_and_ulong,function) 41 ANSI_PRAGMA_WEAK2(atomic_or_long,atomic_or_ulong,function) 42#endif 43 44 ENTRY(atomic_inc_8) 45 ALTENTRY(atomic_inc_uchar) 46 lock 47 incb (%rdi) 48 ret 49 SET_SIZE(atomic_inc_uchar) 50 SET_SIZE(atomic_inc_8) 51 52 ENTRY(atomic_inc_16) 53 ALTENTRY(atomic_inc_ushort) 54 lock 55 incw (%rdi) 56 ret 57 SET_SIZE(atomic_inc_ushort) 58 SET_SIZE(atomic_inc_16) 59 60 ENTRY(atomic_inc_32) 61 ALTENTRY(atomic_inc_uint) 62 lock 63 incl (%rdi) 64 ret 65 SET_SIZE(atomic_inc_uint) 66 SET_SIZE(atomic_inc_32) 67 68 ENTRY(atomic_inc_64) 69 ALTENTRY(atomic_inc_ulong) 70 lock 71 incq (%rdi) 72 ret 73 SET_SIZE(atomic_inc_ulong) 74 SET_SIZE(atomic_inc_64) 75 76 ENTRY(atomic_inc_8_nv) 77 ALTENTRY(atomic_inc_uchar_nv) 78 xorl %eax, %eax / clear upper bits of %eax return register 79 incb %al / %al = 1 80 lock 81 xaddb %al, (%rdi) / %al = old value, (%rdi) = new value 82 incb %al / return new value 83 ret 84 SET_SIZE(atomic_inc_uchar_nv) 85 SET_SIZE(atomic_inc_8_nv) 86 87 ENTRY(atomic_inc_16_nv) 88 ALTENTRY(atomic_inc_ushort_nv) 89 xorl %eax, %eax / clear upper bits of %eax return register 90 incw %ax / %ax = 1 91 lock 92 xaddw %ax, (%rdi) / %ax = old value, (%rdi) = new value 93 incw %ax / return new value 94 ret 95 SET_SIZE(atomic_inc_ushort_nv) 96 SET_SIZE(atomic_inc_16_nv) 97 98 ENTRY(atomic_inc_32_nv) 99 ALTENTRY(atomic_inc_uint_nv) 100 xorl %eax, %eax / %eax = 0 101 incl %eax / %eax = 1 102 lock 103 xaddl %eax, (%rdi) / %eax = old value, (%rdi) = new value 104 incl %eax / return new value 105 ret 106 SET_SIZE(atomic_inc_uint_nv) 107 SET_SIZE(atomic_inc_32_nv) 108 109 ENTRY(atomic_inc_64_nv) 110 ALTENTRY(atomic_inc_ulong_nv) 111 xorq %rax, %rax / %rax = 0 112 incq %rax / %rax = 1 113 lock 114 xaddq %rax, (%rdi) / %rax = old value, (%rdi) = new value 115 incq %rax / return new value 116 ret 117 SET_SIZE(atomic_inc_ulong_nv) 118 SET_SIZE(atomic_inc_64_nv) 119 120 ENTRY(atomic_dec_8) 121 ALTENTRY(atomic_dec_uchar) 122 lock 123 decb (%rdi) 124 ret 125 SET_SIZE(atomic_dec_uchar) 126 SET_SIZE(atomic_dec_8) 127 128 ENTRY(atomic_dec_16) 129 ALTENTRY(atomic_dec_ushort) 130 lock 131 decw (%rdi) 132 ret 133 SET_SIZE(atomic_dec_ushort) 134 SET_SIZE(atomic_dec_16) 135 136 ENTRY(atomic_dec_32) 137 ALTENTRY(atomic_dec_uint) 138 lock 139 decl (%rdi) 140 ret 141 SET_SIZE(atomic_dec_uint) 142 SET_SIZE(atomic_dec_32) 143 144 ENTRY(atomic_dec_64) 145 ALTENTRY(atomic_dec_ulong) 146 lock 147 decq (%rdi) 148 ret 149 SET_SIZE(atomic_dec_ulong) 150 SET_SIZE(atomic_dec_64) 151 152 ENTRY(atomic_dec_8_nv) 153 ALTENTRY(atomic_dec_uchar_nv) 154 xorl %eax, %eax / clear upper bits of %eax return register 155 decb %al / %al = -1 156 lock 157 xaddb %al, (%rdi) / %al = old value, (%rdi) = new value 158 decb %al / return new value 159 ret 160 SET_SIZE(atomic_dec_uchar_nv) 161 SET_SIZE(atomic_dec_8_nv) 162 163 ENTRY(atomic_dec_16_nv) 164 ALTENTRY(atomic_dec_ushort_nv) 165 xorl %eax, %eax / clear upper bits of %eax return register 166 decw %ax / %ax = -1 167 lock 168 xaddw %ax, (%rdi) / %ax = old value, (%rdi) = new value 169 decw %ax / return new value 170 ret 171 SET_SIZE(atomic_dec_ushort_nv) 172 SET_SIZE(atomic_dec_16_nv) 173 174 ENTRY(atomic_dec_32_nv) 175 ALTENTRY(atomic_dec_uint_nv) 176 xorl %eax, %eax / %eax = 0 177 decl %eax / %eax = -1 178 lock 179 xaddl %eax, (%rdi) / %eax = old value, (%rdi) = new value 180 decl %eax / return new value 181 ret 182 SET_SIZE(atomic_dec_uint_nv) 183 SET_SIZE(atomic_dec_32_nv) 184 185 ENTRY(atomic_dec_64_nv) 186 ALTENTRY(atomic_dec_ulong_nv) 187 xorq %rax, %rax / %rax = 0 188 decq %rax / %rax = -1 189 lock 190 xaddq %rax, (%rdi) / %rax = old value, (%rdi) = new value 191 decq %rax / return new value 192 ret 193 SET_SIZE(atomic_dec_ulong_nv) 194 SET_SIZE(atomic_dec_64_nv) 195 196 ENTRY(atomic_add_8) 197 ALTENTRY(atomic_add_char) 198 lock 199 addb %sil, (%rdi) 200 ret 201 SET_SIZE(atomic_add_char) 202 SET_SIZE(atomic_add_8) 203 204 ENTRY(atomic_add_16) 205 ALTENTRY(atomic_add_short) 206 lock 207 addw %si, (%rdi) 208 ret 209 SET_SIZE(atomic_add_short) 210 SET_SIZE(atomic_add_16) 211 212 ENTRY(atomic_add_32) 213 ALTENTRY(atomic_add_int) 214 lock 215 addl %esi, (%rdi) 216 ret 217 SET_SIZE(atomic_add_int) 218 SET_SIZE(atomic_add_32) 219 220 ENTRY(atomic_add_64) 221 ALTENTRY(atomic_add_ptr) 222 ALTENTRY(atomic_add_long) 223 lock 224 addq %rsi, (%rdi) 225 ret 226 SET_SIZE(atomic_add_long) 227 SET_SIZE(atomic_add_ptr) 228 SET_SIZE(atomic_add_64) 229 230 ENTRY(atomic_or_8) 231 ALTENTRY(atomic_or_uchar) 232 lock 233 orb %sil, (%rdi) 234 ret 235 SET_SIZE(atomic_or_uchar) 236 SET_SIZE(atomic_or_8) 237 238 ENTRY(atomic_or_16) 239 ALTENTRY(atomic_or_ushort) 240 lock 241 orw %si, (%rdi) 242 ret 243 SET_SIZE(atomic_or_ushort) 244 SET_SIZE(atomic_or_16) 245 246 ENTRY(atomic_or_32) 247 ALTENTRY(atomic_or_uint) 248 lock 249 orl %esi, (%rdi) 250 ret 251 SET_SIZE(atomic_or_uint) 252 SET_SIZE(atomic_or_32) 253 254 ENTRY(atomic_or_64) 255 ALTENTRY(atomic_or_ulong) 256 lock 257 orq %rsi, (%rdi) 258 ret 259 SET_SIZE(atomic_or_ulong) 260 SET_SIZE(atomic_or_64) 261 262 ENTRY(atomic_and_8) 263 ALTENTRY(atomic_and_uchar) 264 lock 265 andb %sil, (%rdi) 266 ret 267 SET_SIZE(atomic_and_uchar) 268 SET_SIZE(atomic_and_8) 269 270 ENTRY(atomic_and_16) 271 ALTENTRY(atomic_and_ushort) 272 lock 273 andw %si, (%rdi) 274 ret 275 SET_SIZE(atomic_and_ushort) 276 SET_SIZE(atomic_and_16) 277 278 ENTRY(atomic_and_32) 279 ALTENTRY(atomic_and_uint) 280 lock 281 andl %esi, (%rdi) 282 ret 283 SET_SIZE(atomic_and_uint) 284 SET_SIZE(atomic_and_32) 285 286 ENTRY(atomic_and_64) 287 ALTENTRY(atomic_and_ulong) 288 lock 289 andq %rsi, (%rdi) 290 ret 291 SET_SIZE(atomic_and_ulong) 292 SET_SIZE(atomic_and_64) 293 294 ENTRY(atomic_add_8_nv) 295 ALTENTRY(atomic_add_char_nv) 296 movzbl %sil, %eax / %al = delta addend, clear upper bits 297 lock 298 xaddb %sil, (%rdi) / %sil = old value, (%rdi) = sum 299 addb %sil, %al / new value = original value + delta 300 ret 301 SET_SIZE(atomic_add_char_nv) 302 SET_SIZE(atomic_add_8_nv) 303 304 ENTRY(atomic_add_16_nv) 305 ALTENTRY(atomic_add_short_nv) 306 movzwl %si, %eax / %ax = delta addend, clean upper bits 307 lock 308 xaddw %si, (%rdi) / %si = old value, (%rdi) = sum 309 addw %si, %ax / new value = original value + delta 310 ret 311 SET_SIZE(atomic_add_short_nv) 312 SET_SIZE(atomic_add_16_nv) 313 314 ENTRY(atomic_add_32_nv) 315 ALTENTRY(atomic_add_int_nv) 316 mov %esi, %eax / %eax = delta addend 317 lock 318 xaddl %esi, (%rdi) / %esi = old value, (%rdi) = sum 319 add %esi, %eax / new value = original value + delta 320 ret 321 SET_SIZE(atomic_add_int_nv) 322 SET_SIZE(atomic_add_32_nv) 323 324 ENTRY(atomic_add_64_nv) 325 ALTENTRY(atomic_add_ptr_nv) 326 ALTENTRY(atomic_add_long_nv) 327 mov %rsi, %rax / %rax = delta addend 328 lock 329 xaddq %rsi, (%rdi) / %rsi = old value, (%rdi) = sum 330 addq %rsi, %rax / new value = original value + delta 331 ret 332 SET_SIZE(atomic_add_long_nv) 333 SET_SIZE(atomic_add_ptr_nv) 334 SET_SIZE(atomic_add_64_nv) 335 336 ENTRY(atomic_and_8_nv) 337 ALTENTRY(atomic_and_uchar_nv) 338 movb (%rdi), %al / %al = old value 3391: 340 movb %sil, %cl 341 andb %al, %cl / %cl = new value 342 lock 343 cmpxchgb %cl, (%rdi) / try to stick it in 344 jne 1b 345 movzbl %cl, %eax / return new value 346 ret 347 SET_SIZE(atomic_and_uchar_nv) 348 SET_SIZE(atomic_and_8_nv) 349 350 ENTRY(atomic_and_16_nv) 351 ALTENTRY(atomic_and_ushort_nv) 352 movw (%rdi), %ax / %ax = old value 3531: 354 movw %si, %cx 355 andw %ax, %cx / %cx = new value 356 lock 357 cmpxchgw %cx, (%rdi) / try to stick it in 358 jne 1b 359 movzwl %cx, %eax / return new value 360 ret 361 SET_SIZE(atomic_and_ushort_nv) 362 SET_SIZE(atomic_and_16_nv) 363 364 ENTRY(atomic_and_32_nv) 365 ALTENTRY(atomic_and_uint_nv) 366 movl (%rdi), %eax 3671: 368 movl %esi, %ecx 369 andl %eax, %ecx 370 lock 371 cmpxchgl %ecx, (%rdi) 372 jne 1b 373 movl %ecx, %eax 374 ret 375 SET_SIZE(atomic_and_uint_nv) 376 SET_SIZE(atomic_and_32_nv) 377 378 ENTRY(atomic_and_64_nv) 379 ALTENTRY(atomic_and_ulong_nv) 380 movq (%rdi), %rax 3811: 382 movq %rsi, %rcx 383 andq %rax, %rcx 384 lock 385 cmpxchgq %rcx, (%rdi) 386 jne 1b 387 movq %rcx, %rax 388 ret 389 SET_SIZE(atomic_and_ulong_nv) 390 SET_SIZE(atomic_and_64_nv) 391 392 ENTRY(atomic_or_8_nv) 393 ALTENTRY(atomic_or_uchar_nv) 394 movb (%rdi), %al / %al = old value 3951: 396 movb %sil, %cl 397 orb %al, %cl / %cl = new value 398 lock 399 cmpxchgb %cl, (%rdi) / try to stick it in 400 jne 1b 401 movzbl %cl, %eax / return new value 402 ret 403 SET_SIZE(atomic_and_uchar_nv) 404 SET_SIZE(atomic_and_8_nv) 405 406 ENTRY(atomic_or_16_nv) 407 ALTENTRY(atomic_or_ushort_nv) 408 movw (%rdi), %ax / %ax = old value 4091: 410 movw %si, %cx 411 orw %ax, %cx / %cx = new value 412 lock 413 cmpxchgw %cx, (%rdi) / try to stick it in 414 jne 1b 415 movzwl %cx, %eax / return new value 416 ret 417 SET_SIZE(atomic_or_ushort_nv) 418 SET_SIZE(atomic_or_16_nv) 419 420 ENTRY(atomic_or_32_nv) 421 ALTENTRY(atomic_or_uint_nv) 422 movl (%rdi), %eax 4231: 424 movl %esi, %ecx 425 orl %eax, %ecx 426 lock 427 cmpxchgl %ecx, (%rdi) 428 jne 1b 429 movl %ecx, %eax 430 ret 431 SET_SIZE(atomic_or_uint_nv) 432 SET_SIZE(atomic_or_32_nv) 433 434 ENTRY(atomic_or_64_nv) 435 ALTENTRY(atomic_or_ulong_nv) 436 movq (%rdi), %rax 4371: 438 movq %rsi, %rcx 439 orq %rax, %rcx 440 lock 441 cmpxchgq %rcx, (%rdi) 442 jne 1b 443 movq %rcx, %rax 444 ret 445 SET_SIZE(atomic_or_ulong_nv) 446 SET_SIZE(atomic_or_64_nv) 447 448 ENTRY(atomic_cas_8) 449 ALTENTRY(atomic_cas_uchar) 450 movzbl %sil, %eax 451 lock 452 cmpxchgb %dl, (%rdi) 453 ret 454 SET_SIZE(atomic_cas_uchar) 455 SET_SIZE(atomic_cas_8) 456 457 ENTRY(atomic_cas_16) 458 ALTENTRY(atomic_cas_ushort) 459 movzwl %si, %eax 460 lock 461 cmpxchgw %dx, (%rdi) 462 ret 463 SET_SIZE(atomic_cas_ushort) 464 SET_SIZE(atomic_cas_16) 465 466 ENTRY(atomic_cas_32) 467 ALTENTRY(atomic_cas_uint) 468 movl %esi, %eax 469 lock 470 cmpxchgl %edx, (%rdi) 471 ret 472 SET_SIZE(atomic_cas_uint) 473 SET_SIZE(atomic_cas_32) 474 475 ENTRY(atomic_cas_64) 476 ALTENTRY(atomic_cas_ulong) 477 ALTENTRY(atomic_cas_ptr) 478 movq %rsi, %rax 479 lock 480 cmpxchgq %rdx, (%rdi) 481 ret 482 SET_SIZE(atomic_cas_ptr) 483 SET_SIZE(atomic_cas_ulong) 484 SET_SIZE(atomic_cas_64) 485 486 ENTRY(atomic_swap_8) 487 ALTENTRY(atomic_swap_uchar) 488 movzbl %sil, %eax 489 lock 490 xchgb %al, (%rdi) 491 ret 492 SET_SIZE(atomic_swap_uchar) 493 SET_SIZE(atomic_swap_8) 494 495 ENTRY(atomic_swap_16) 496 ALTENTRY(atomic_swap_ushort) 497 movzwl %si, %eax 498 lock 499 xchgw %ax, (%rdi) 500 ret 501 SET_SIZE(atomic_swap_ushort) 502 SET_SIZE(atomic_swap_16) 503 504 ENTRY(atomic_swap_32) 505 ALTENTRY(atomic_swap_uint) 506 movl %esi, %eax 507 lock 508 xchgl %eax, (%rdi) 509 ret 510 SET_SIZE(atomic_swap_uint) 511 SET_SIZE(atomic_swap_32) 512 513 ENTRY(atomic_swap_64) 514 ALTENTRY(atomic_swap_ulong) 515 ALTENTRY(atomic_swap_ptr) 516 movq %rsi, %rax 517 lock 518 xchgq %rax, (%rdi) 519 ret 520 SET_SIZE(atomic_swap_ptr) 521 SET_SIZE(atomic_swap_ulong) 522 SET_SIZE(atomic_swap_64) 523 524 ENTRY(atomic_set_long_excl) 525 xorl %eax, %eax 526 lock 527 btsq %rsi, (%rdi) 528 jnc 1f 529 decl %eax / return -1 5301: 531 ret 532 SET_SIZE(atomic_set_long_excl) 533 534 ENTRY(atomic_clear_long_excl) 535 xorl %eax, %eax 536 lock 537 btrq %rsi, (%rdi) 538 jc 1f 539 decl %eax / return -1 5401: 541 ret 542 SET_SIZE(atomic_clear_long_excl) 543 544#if !defined(_KERNEL) 545 546 /* 547 * NOTE: membar_enter, and membar_exit are identical routines. 548 * We define them separately, instead of using an ALTENTRY 549 * definitions to alias them together, so that DTrace and 550 * debuggers will see a unique address for them, allowing 551 * more accurate tracing. 552 */ 553 554 ENTRY(membar_enter) 555 mfence 556 ret 557 SET_SIZE(membar_enter) 558 559 ENTRY(membar_exit) 560 mfence 561 ret 562 SET_SIZE(membar_exit) 563 564 ENTRY(membar_producer) 565 sfence 566 ret 567 SET_SIZE(membar_producer) 568 569 ENTRY(membar_consumer) 570 lfence 571 ret 572 SET_SIZE(membar_consumer) 573 574#endif /* !_KERNEL */ 575