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 * Copyright 2008 Sun Microsystems, Inc. All rights reserved. 23 * Use is subject to license terms. 24 * Copyright 2019 Joyent, Inc. 25 */ 26 27 #if defined(lint) || defined(__lint) 28 #include <sys/types.h> 29 #include <sys/thread.h> 30 #include <sys/cpuvar.h> 31 #include <vm/page.h> 32 #else /* __lint */ 33 #include "assym.h" 34 #endif /* __lint */ 35 36 #include <sys/mutex_impl.h> 37 #include <sys/asm_linkage.h> 38 #include <sys/asm_misc.h> 39 #include <sys/regset.h> 40 #include <sys/rwlock_impl.h> 41 #include <sys/lockstat.h> 42 43 /* 44 * lock_try(lp), ulock_try(lp) 45 * - returns non-zero on success. 46 * - doesn't block interrupts so don't use this to spin on a lock. 47 * 48 * ulock_try() is for a lock in the user address space. 49 */ 50 51 #if defined(lint) || defined(__lint) 52 53 /* ARGSUSED */ 54 int 55 lock_try(lock_t *lp) 56 { return (0); } 57 58 /* ARGSUSED */ 59 int 60 lock_spin_try(lock_t *lp) 61 { return (0); } 62 63 /* ARGSUSED */ 64 int 65 ulock_try(lock_t *lp) 66 { return (0); } 67 68 #else /* __lint */ 69 .globl kernelbase 70 71 #if defined(__amd64) 72 73 ENTRY(lock_try) 74 movb $-1, %dl 75 movzbq %dl, %rax 76 xchgb %dl, (%rdi) 77 xorb %dl, %al 78 .lock_try_lockstat_patch_point: 79 ret 80 testb %al, %al 81 jnz 0f 82 ret 83 0: 84 movq %gs:CPU_THREAD, %rdx /* rdx = thread addr */ 85 movq %rdi, %rsi /* rsi = lock addr */ 86 movl $LS_LOCK_TRY_ACQUIRE, %edi /* edi = event */ 87 jmp lockstat_wrapper 88 SET_SIZE(lock_try) 89 90 ENTRY(lock_spin_try) 91 movb $-1, %dl 92 movzbq %dl, %rax 93 xchgb %dl, (%rdi) 94 xorb %dl, %al 95 ret 96 SET_SIZE(lock_spin_try) 97 98 ENTRY(ulock_try) 99 #ifdef DEBUG 100 movq kernelbase(%rip), %rax 101 cmpq %rax, %rdi /* test uaddr < kernelbase */ 102 jb ulock_pass /* uaddr < kernelbase, proceed */ 103 104 movq %rdi, %r12 /* preserve lock ptr for debugging */ 105 leaq .ulock_panic_msg(%rip), %rdi 106 pushq %rbp /* align stack properly */ 107 movq %rsp, %rbp 108 xorl %eax, %eax /* clear for varargs */ 109 call panic 110 111 #endif /* DEBUG */ 112 113 ulock_pass: 114 movl $1, %eax 115 xchgb %al, (%rdi) 116 xorb $1, %al 117 ret 118 SET_SIZE(ulock_try) 119 120 #else 121 122 ENTRY(lock_try) 123 movl $1,%edx 124 movl 4(%esp),%ecx /* ecx = lock addr */ 125 xorl %eax,%eax 126 xchgb %dl, (%ecx) /* using dl will avoid partial */ 127 testb %dl,%dl /* stalls on P6 ? */ 128 setz %al 129 .lock_try_lockstat_patch_point: 130 ret 131 movl %gs:CPU_THREAD, %edx /* edx = thread addr */ 132 testl %eax, %eax 133 jz 0f 134 movl $LS_LOCK_TRY_ACQUIRE, %eax 135 jmp lockstat_wrapper 136 0: 137 ret 138 SET_SIZE(lock_try) 139 140 ENTRY(lock_spin_try) 141 movl $-1,%edx 142 movl 4(%esp),%ecx /* ecx = lock addr */ 143 xorl %eax,%eax 144 xchgb %dl, (%ecx) /* using dl will avoid partial */ 145 testb %dl,%dl /* stalls on P6 ? */ 146 setz %al 147 ret 148 SET_SIZE(lock_spin_try) 149 150 ENTRY(ulock_try) 151 #ifdef DEBUG 152 movl kernelbase, %eax 153 cmpl %eax, 4(%esp) /* test uaddr < kernelbase */ 154 jb ulock_pass /* uaddr < kernelbase, proceed */ 155 156 pushl $.ulock_panic_msg 157 call panic 158 159 #endif /* DEBUG */ 160 161 ulock_pass: 162 movl $1,%eax 163 movl 4(%esp),%ecx 164 xchgb %al, (%ecx) 165 xorb $1, %al 166 ret 167 SET_SIZE(ulock_try) 168 169 #endif /* !__amd64 */ 170 171 #ifdef DEBUG 172 .data 173 .ulock_panic_msg: 174 .string "ulock_try: Argument is above kernelbase" 175 .text 176 #endif /* DEBUG */ 177 178 #endif /* __lint */ 179 180 /* 181 * lock_clear(lp) 182 * - unlock lock without changing interrupt priority level. 183 */ 184 185 #if defined(lint) || defined(__lint) 186 187 /* ARGSUSED */ 188 void 189 lock_clear(lock_t *lp) 190 {} 191 192 /* ARGSUSED */ 193 void 194 ulock_clear(lock_t *lp) 195 {} 196 197 #else /* __lint */ 198 199 #if defined(__amd64) 200 201 ENTRY(lock_clear) 202 movb $0, (%rdi) 203 .lock_clear_lockstat_patch_point: 204 ret 205 movq %rdi, %rsi /* rsi = lock addr */ 206 movq %gs:CPU_THREAD, %rdx /* rdx = thread addr */ 207 movl $LS_LOCK_CLEAR_RELEASE, %edi /* edi = event */ 208 jmp lockstat_wrapper 209 SET_SIZE(lock_clear) 210 211 ENTRY(ulock_clear) 212 #ifdef DEBUG 213 movq kernelbase(%rip), %rcx 214 cmpq %rcx, %rdi /* test uaddr < kernelbase */ 215 jb ulock_clr /* uaddr < kernelbase, proceed */ 216 217 leaq .ulock_clear_msg(%rip), %rdi 218 pushq %rbp /* align stack properly */ 219 movq %rsp, %rbp 220 xorl %eax, %eax /* clear for varargs */ 221 call panic 222 #endif 223 224 ulock_clr: 225 movb $0, (%rdi) 226 ret 227 SET_SIZE(ulock_clear) 228 229 #else 230 231 ENTRY(lock_clear) 232 movl 4(%esp), %eax 233 movb $0, (%eax) 234 .lock_clear_lockstat_patch_point: 235 ret 236 movl %gs:CPU_THREAD, %edx /* edx = thread addr */ 237 movl %eax, %ecx /* ecx = lock pointer */ 238 movl $LS_LOCK_CLEAR_RELEASE, %eax 239 jmp lockstat_wrapper 240 SET_SIZE(lock_clear) 241 242 ENTRY(ulock_clear) 243 #ifdef DEBUG 244 movl kernelbase, %ecx 245 cmpl %ecx, 4(%esp) /* test uaddr < kernelbase */ 246 jb ulock_clr /* uaddr < kernelbase, proceed */ 247 248 pushl $.ulock_clear_msg 249 call panic 250 #endif 251 252 ulock_clr: 253 movl 4(%esp),%eax 254 xorl %ecx,%ecx 255 movb %cl, (%eax) 256 ret 257 SET_SIZE(ulock_clear) 258 259 #endif /* !__amd64 */ 260 261 #ifdef DEBUG 262 .data 263 .ulock_clear_msg: 264 .string "ulock_clear: Argument is above kernelbase" 265 .text 266 #endif /* DEBUG */ 267 268 269 #endif /* __lint */ 270 271 /* 272 * lock_set_spl(lock_t *lp, int new_pil, u_short *old_pil) 273 * Drops lp, sets pil to new_pil, stores old pil in *old_pil. 274 */ 275 276 #if defined(lint) || defined(__lint) 277 278 /* ARGSUSED */ 279 void 280 lock_set_spl(lock_t *lp, int new_pil, u_short *old_pil) 281 {} 282 283 #else /* __lint */ 284 285 #if defined(__amd64) 286 287 ENTRY(lock_set_spl) 288 pushq %rbp 289 movq %rsp, %rbp 290 subq $32, %rsp 291 movl %esi, 8(%rsp) /* save priority level */ 292 movq %rdx, 16(%rsp) /* save old pil ptr */ 293 movq %rdi, 24(%rsp) /* save lock pointer */ 294 movl %esi, %edi /* pass priority level */ 295 call splr /* raise priority level */ 296 movq 24(%rsp), %rdi /* rdi = lock addr */ 297 movb $-1, %dl 298 xchgb %dl, (%rdi) /* try to set lock */ 299 testb %dl, %dl /* did we get the lock? ... */ 300 jnz .lss_miss /* ... no, go to C for the hard case */ 301 movq 16(%rsp), %rdx /* rdx = old pil addr */ 302 movw %ax, (%rdx) /* store old pil */ 303 leave 304 .lock_set_spl_lockstat_patch_point: 305 ret 306 movq %rdi, %rsi /* rsi = lock addr */ 307 movq %gs:CPU_THREAD, %rdx /* rdx = thread addr */ 308 movl $LS_LOCK_SET_SPL_ACQUIRE, %edi 309 jmp lockstat_wrapper 310 .lss_miss: 311 movl 8(%rsp), %esi /* new_pil */ 312 movq 16(%rsp), %rdx /* old_pil_addr */ 313 movl %eax, %ecx /* original pil */ 314 leave /* unwind stack */ 315 jmp lock_set_spl_spin 316 SET_SIZE(lock_set_spl) 317 318 #else 319 320 ENTRY(lock_set_spl) 321 movl 8(%esp), %eax /* get priority level */ 322 pushl %eax 323 call splr /* raise priority level */ 324 movl 8(%esp), %ecx /* ecx = lock addr */ 325 movl $-1, %edx 326 addl $4, %esp 327 xchgb %dl, (%ecx) /* try to set lock */ 328 testb %dl, %dl /* did we get the lock? ... */ 329 movl 12(%esp), %edx /* edx = olp pil addr (ZF unaffected) */ 330 jnz .lss_miss /* ... no, go to C for the hard case */ 331 movw %ax, (%edx) /* store old pil */ 332 .lock_set_spl_lockstat_patch_point: 333 ret 334 movl %gs:CPU_THREAD, %edx /* edx = thread addr*/ 335 movl $LS_LOCK_SET_SPL_ACQUIRE, %eax 336 jmp lockstat_wrapper 337 .lss_miss: 338 pushl %eax /* original pil */ 339 pushl %edx /* old_pil addr */ 340 pushl 16(%esp) /* new_pil */ 341 pushl %ecx /* lock addr */ 342 call lock_set_spl_spin 343 addl $16, %esp 344 ret 345 SET_SIZE(lock_set_spl) 346 347 #endif /* !__amd64 */ 348 349 #endif /* __lint */ 350 351 /* 352 * void 353 * lock_init(lp) 354 */ 355 356 #if defined(__lint) 357 358 /* ARGSUSED */ 359 void 360 lock_init(lock_t *lp) 361 {} 362 363 #else /* __lint */ 364 365 #if defined(__amd64) 366 367 ENTRY(lock_init) 368 movb $0, (%rdi) 369 ret 370 SET_SIZE(lock_init) 371 372 #else 373 374 ENTRY(lock_init) 375 movl 4(%esp), %eax 376 movb $0, (%eax) 377 ret 378 SET_SIZE(lock_init) 379 380 #endif /* !__amd64 */ 381 382 #endif /* __lint */ 383 384 /* 385 * void 386 * lock_set(lp) 387 */ 388 389 #if defined(lint) || defined(__lint) 390 391 /* ARGSUSED */ 392 void 393 lock_set(lock_t *lp) 394 {} 395 396 #else /* __lint */ 397 398 #if defined(__amd64) 399 400 ENTRY(lock_set) 401 movb $-1, %dl 402 xchgb %dl, (%rdi) /* try to set lock */ 403 testb %dl, %dl /* did we get it? */ 404 jnz lock_set_spin /* no, go to C for the hard case */ 405 .lock_set_lockstat_patch_point: 406 ret 407 movq %rdi, %rsi /* rsi = lock addr */ 408 movq %gs:CPU_THREAD, %rdx /* rdx = thread addr */ 409 movl $LS_LOCK_SET_ACQUIRE, %edi 410 jmp lockstat_wrapper 411 SET_SIZE(lock_set) 412 413 #else 414 415 ENTRY(lock_set) 416 movl 4(%esp), %ecx /* ecx = lock addr */ 417 movl $-1, %edx 418 xchgb %dl, (%ecx) /* try to set lock */ 419 testb %dl, %dl /* did we get it? */ 420 jnz lock_set_spin /* no, go to C for the hard case */ 421 .lock_set_lockstat_patch_point: 422 ret 423 movl %gs:CPU_THREAD, %edx /* edx = thread addr */ 424 movl $LS_LOCK_SET_ACQUIRE, %eax 425 jmp lockstat_wrapper 426 SET_SIZE(lock_set) 427 428 #endif /* !__amd64 */ 429 430 #endif /* __lint */ 431 432 /* 433 * lock_clear_splx(lp, s) 434 */ 435 436 #if defined(lint) || defined(__lint) 437 438 /* ARGSUSED */ 439 void 440 lock_clear_splx(lock_t *lp, int s) 441 {} 442 443 #else /* __lint */ 444 445 #if defined(__amd64) 446 447 ENTRY(lock_clear_splx) 448 movb $0, (%rdi) /* clear lock */ 449 .lock_clear_splx_lockstat_patch_point: 450 jmp 0f 451 0: 452 movl %esi, %edi /* arg for splx */ 453 jmp splx /* let splx do its thing */ 454 .lock_clear_splx_lockstat: 455 pushq %rbp /* align stack properly */ 456 movq %rsp, %rbp 457 subq $16, %rsp /* space to save args across splx */ 458 movq %rdi, 8(%rsp) /* save lock ptr across splx call */ 459 movl %esi, %edi /* arg for splx */ 460 call splx /* lower the priority */ 461 movq 8(%rsp), %rsi /* rsi = lock ptr */ 462 leave /* unwind stack */ 463 movq %gs:CPU_THREAD, %rdx /* rdx = thread addr */ 464 movl $LS_LOCK_CLEAR_SPLX_RELEASE, %edi 465 jmp lockstat_wrapper 466 SET_SIZE(lock_clear_splx) 467 468 #else 469 470 ENTRY(lock_clear_splx) 471 movl 4(%esp), %eax /* eax = lock addr */ 472 movb $0, (%eax) /* clear lock */ 473 .lock_clear_splx_lockstat_patch_point: 474 jmp 0f 475 0: 476 movl 8(%esp), %edx /* edx = desired pil */ 477 movl %edx, 4(%esp) /* set spl arg up for splx */ 478 jmp splx /* let splx do it's thing */ 479 .lock_clear_splx_lockstat: 480 movl 8(%esp), %edx /* edx = desired pil */ 481 pushl %ebp /* set up stack frame */ 482 movl %esp, %ebp 483 pushl %edx 484 call splx 485 leave /* unwind stack */ 486 movl 4(%esp), %ecx /* ecx = lock pointer */ 487 movl %gs:CPU_THREAD, %edx /* edx = thread addr */ 488 movl $LS_LOCK_CLEAR_SPLX_RELEASE, %eax 489 jmp lockstat_wrapper 490 SET_SIZE(lock_clear_splx) 491 492 #endif /* !__amd64 */ 493 494 #if defined(__GNUC_AS__) 495 #define LOCK_CLEAR_SPLX_LOCKSTAT_PATCH_VAL \ 496 (.lock_clear_splx_lockstat - .lock_clear_splx_lockstat_patch_point - 2) 497 498 #define LOCK_CLEAR_SPLX_LOCKSTAT_PATCH_POINT \ 499 (.lock_clear_splx_lockstat_patch_point + 1) 500 #else 501 #define LOCK_CLEAR_SPLX_LOCKSTAT_PATCH_VAL \ 502 [.lock_clear_splx_lockstat - .lock_clear_splx_lockstat_patch_point - 2] 503 504 #define LOCK_CLEAR_SPLX_LOCKSTAT_PATCH_POINT \ 505 [.lock_clear_splx_lockstat_patch_point + 1] 506 #endif 507 508 #endif /* __lint */ 509 510 /* 511 * mutex_enter() and mutex_exit(). 512 * 513 * These routines handle the simple cases of mutex_enter() (adaptive 514 * lock, not held) and mutex_exit() (adaptive lock, held, no waiters). 515 * If anything complicated is going on we punt to mutex_vector_enter(). 516 * 517 * mutex_tryenter() is similar to mutex_enter() but returns zero if 518 * the lock cannot be acquired, nonzero on success. 519 * 520 * If mutex_exit() gets preempted in the window between checking waiters 521 * and clearing the lock, we can miss wakeups. Disabling preemption 522 * in the mutex code is prohibitively expensive, so instead we detect 523 * mutex preemption by examining the trapped PC in the interrupt path. 524 * If we interrupt a thread in mutex_exit() that has not yet cleared 525 * the lock, cmnint() resets its PC back to the beginning of 526 * mutex_exit() so it will check again for waiters when it resumes. 527 * 528 * The lockstat code below is activated when the lockstat driver 529 * calls lockstat_hot_patch() to hot-patch the kernel mutex code. 530 * Note that we don't need to test lockstat_event_mask here -- we won't 531 * patch this code in unless we're gathering ADAPTIVE_HOLD lockstats. 532 */ 533 #if defined(lint) || defined(__lint) 534 535 /* ARGSUSED */ 536 void 537 mutex_enter(kmutex_t *lp) 538 {} 539 540 /* ARGSUSED */ 541 int 542 mutex_tryenter(kmutex_t *lp) 543 { return (0); } 544 545 /* ARGSUSED */ 546 int 547 mutex_adaptive_tryenter(mutex_impl_t *lp) 548 { return (0); } 549 550 /* ARGSUSED */ 551 void 552 mutex_exit(kmutex_t *lp) 553 {} 554 555 #else 556 557 #if defined(__amd64) 558 559 ENTRY_NP(mutex_enter) 560 movq %gs:CPU_THREAD, %rdx /* rdx = thread ptr */ 561 xorl %eax, %eax /* rax = 0 (unheld adaptive) */ 562 lock 563 cmpxchgq %rdx, (%rdi) 564 jnz mutex_vector_enter 565 .mutex_enter_lockstat_patch_point: 566 #if defined(OPTERON_WORKAROUND_6323525) 567 .mutex_enter_6323525_patch_point: 568 ret /* nop space for lfence */ 569 nop 570 nop 571 .mutex_enter_lockstat_6323525_patch_point: /* new patch point if lfence */ 572 nop 573 #else /* OPTERON_WORKAROUND_6323525 */ 574 ret 575 #endif /* OPTERON_WORKAROUND_6323525 */ 576 movq %rdi, %rsi 577 movl $LS_MUTEX_ENTER_ACQUIRE, %edi 578 /* 579 * expects %rdx=thread, %rsi=lock, %edi=lockstat event 580 */ 581 ALTENTRY(lockstat_wrapper) 582 incb T_LOCKSTAT(%rdx) /* curthread->t_lockstat++ */ 583 leaq lockstat_probemap(%rip), %rax 584 movl (%rax, %rdi, DTRACE_IDSIZE), %eax 585 testl %eax, %eax /* check for non-zero probe */ 586 jz 1f 587 pushq %rbp /* align stack properly */ 588 movq %rsp, %rbp 589 movl %eax, %edi 590 movq lockstat_probe, %rax 591 INDIRECT_CALL_REG(rax) 592 leave /* unwind stack */ 593 1: 594 movq %gs:CPU_THREAD, %rdx /* reload thread ptr */ 595 decb T_LOCKSTAT(%rdx) /* curthread->t_lockstat-- */ 596 movl $1, %eax /* return success if tryenter */ 597 ret 598 SET_SIZE(lockstat_wrapper) 599 SET_SIZE(mutex_enter) 600 601 /* 602 * expects %rcx=thread, %rdx=arg, %rsi=lock, %edi=lockstat event 603 */ 604 ENTRY(lockstat_wrapper_arg) 605 incb T_LOCKSTAT(%rcx) /* curthread->t_lockstat++ */ 606 leaq lockstat_probemap(%rip), %rax 607 movl (%rax, %rdi, DTRACE_IDSIZE), %eax 608 testl %eax, %eax /* check for non-zero probe */ 609 jz 1f 610 pushq %rbp /* align stack properly */ 611 movq %rsp, %rbp 612 movl %eax, %edi 613 movq lockstat_probe, %rax 614 INDIRECT_CALL_REG(rax) 615 leave /* unwind stack */ 616 1: 617 movq %gs:CPU_THREAD, %rdx /* reload thread ptr */ 618 decb T_LOCKSTAT(%rdx) /* curthread->t_lockstat-- */ 619 movl $1, %eax /* return success if tryenter */ 620 ret 621 SET_SIZE(lockstat_wrapper_arg) 622 623 624 ENTRY(mutex_tryenter) 625 movq %gs:CPU_THREAD, %rdx /* rdx = thread ptr */ 626 xorl %eax, %eax /* rax = 0 (unheld adaptive) */ 627 lock 628 cmpxchgq %rdx, (%rdi) 629 jnz mutex_vector_tryenter 630 not %eax /* return success (nonzero) */ 631 #if defined(OPTERON_WORKAROUND_6323525) 632 .mutex_tryenter_lockstat_patch_point: 633 .mutex_tryenter_6323525_patch_point: 634 ret /* nop space for lfence */ 635 nop 636 nop 637 .mutex_tryenter_lockstat_6323525_patch_point: /* new patch point if lfence */ 638 nop 639 #else /* OPTERON_WORKAROUND_6323525 */ 640 .mutex_tryenter_lockstat_patch_point: 641 ret 642 #endif /* OPTERON_WORKAROUND_6323525 */ 643 movq %rdi, %rsi 644 movl $LS_MUTEX_ENTER_ACQUIRE, %edi 645 jmp lockstat_wrapper 646 SET_SIZE(mutex_tryenter) 647 648 ENTRY(mutex_adaptive_tryenter) 649 movq %gs:CPU_THREAD, %rdx /* rdx = thread ptr */ 650 xorl %eax, %eax /* rax = 0 (unheld adaptive) */ 651 lock 652 cmpxchgq %rdx, (%rdi) 653 jnz 0f 654 not %eax /* return success (nonzero) */ 655 #if defined(OPTERON_WORKAROUND_6323525) 656 .mutex_atryenter_6323525_patch_point: 657 ret /* nop space for lfence */ 658 nop 659 nop 660 nop 661 #else /* OPTERON_WORKAROUND_6323525 */ 662 ret 663 #endif /* OPTERON_WORKAROUND_6323525 */ 664 0: 665 xorl %eax, %eax /* return failure */ 666 ret 667 SET_SIZE(mutex_adaptive_tryenter) 668 669 .globl mutex_owner_running_critical_start 670 671 ENTRY(mutex_owner_running) 672 mutex_owner_running_critical_start: 673 movq (%rdi), %r11 /* get owner field */ 674 andq $MUTEX_THREAD, %r11 /* remove waiters bit */ 675 cmpq $0, %r11 /* if free, skip */ 676 je 1f /* go return 0 */ 677 movq T_CPU(%r11), %r8 /* get owner->t_cpu */ 678 movq CPU_THREAD(%r8), %r9 /* get t_cpu->cpu_thread */ 679 .mutex_owner_running_critical_end: 680 cmpq %r11, %r9 /* owner == running thread? */ 681 je 2f /* yes, go return cpu */ 682 1: 683 xorq %rax, %rax /* return 0 */ 684 ret 685 2: 686 movq %r8, %rax /* return cpu */ 687 ret 688 SET_SIZE(mutex_owner_running) 689 690 .globl mutex_owner_running_critical_size 691 .type mutex_owner_running_critical_size, @object 692 .align CPTRSIZE 693 mutex_owner_running_critical_size: 694 .quad .mutex_owner_running_critical_end - mutex_owner_running_critical_start 695 SET_SIZE(mutex_owner_running_critical_size) 696 697 .globl mutex_exit_critical_start 698 699 ENTRY(mutex_exit) 700 mutex_exit_critical_start: /* If interrupted, restart here */ 701 movq %gs:CPU_THREAD, %rdx 702 cmpq %rdx, (%rdi) 703 jne mutex_vector_exit /* wrong type or wrong owner */ 704 movq $0, (%rdi) /* clear owner AND lock */ 705 .mutex_exit_critical_end: 706 .mutex_exit_lockstat_patch_point: 707 ret 708 movq %rdi, %rsi 709 movl $LS_MUTEX_EXIT_RELEASE, %edi 710 jmp lockstat_wrapper 711 SET_SIZE(mutex_exit) 712 713 .globl mutex_exit_critical_size 714 .type mutex_exit_critical_size, @object 715 .align CPTRSIZE 716 mutex_exit_critical_size: 717 .quad .mutex_exit_critical_end - mutex_exit_critical_start 718 SET_SIZE(mutex_exit_critical_size) 719 720 #else 721 722 ENTRY_NP(mutex_enter) 723 movl %gs:CPU_THREAD, %edx /* edx = thread ptr */ 724 movl 4(%esp), %ecx /* ecx = lock ptr */ 725 xorl %eax, %eax /* eax = 0 (unheld adaptive) */ 726 lock 727 cmpxchgl %edx, (%ecx) 728 jnz mutex_vector_enter 729 #if defined(OPTERON_WORKAROUND_6323525) 730 .mutex_enter_lockstat_patch_point: 731 .mutex_enter_6323525_patch_point: 732 ret /* nop space for lfence */ 733 nop 734 nop 735 .mutex_enter_lockstat_6323525_patch_point: /* new patch point if lfence */ 736 nop 737 #else /* OPTERON_WORKAROUND_6323525 */ 738 .mutex_enter_lockstat_patch_point: 739 ret 740 #endif /* OPTERON_WORKAROUND_6323525 */ 741 movl $LS_MUTEX_ENTER_ACQUIRE, %eax 742 ALTENTRY(lockstat_wrapper) /* expects edx=thread, ecx=lock, */ 743 /* eax=lockstat event */ 744 pushl %ebp /* buy a frame */ 745 movl %esp, %ebp 746 incb T_LOCKSTAT(%edx) /* curthread->t_lockstat++ */ 747 pushl %edx /* save thread pointer */ 748 movl $lockstat_probemap, %edx 749 movl (%edx, %eax, DTRACE_IDSIZE), %eax 750 testl %eax, %eax /* check for non-zero probe */ 751 jz 1f 752 pushl %ecx /* push lock */ 753 pushl %eax /* push probe ID */ 754 call *lockstat_probe 755 addl $8, %esp 756 1: 757 popl %edx /* restore thread pointer */ 758 decb T_LOCKSTAT(%edx) /* curthread->t_lockstat-- */ 759 movl $1, %eax /* return success if tryenter */ 760 popl %ebp /* pop off frame */ 761 ret 762 SET_SIZE(lockstat_wrapper) 763 SET_SIZE(mutex_enter) 764 765 ENTRY(lockstat_wrapper_arg) /* expects edx=thread, ecx=lock, */ 766 /* eax=lockstat event, pushed arg */ 767 incb T_LOCKSTAT(%edx) /* curthread->t_lockstat++ */ 768 pushl %edx /* save thread pointer */ 769 movl $lockstat_probemap, %edx 770 movl (%edx, %eax, DTRACE_IDSIZE), %eax 771 testl %eax, %eax /* check for non-zero probe */ 772 jz 1f 773 pushl %ebp /* save %ebp */ 774 pushl 8(%esp) /* push arg1 */ 775 movl %ebp, 12(%esp) /* fake up the stack frame */ 776 movl %esp, %ebp /* fake up base pointer */ 777 addl $12, %ebp /* adjust faked base pointer */ 778 pushl %ecx /* push lock */ 779 pushl %eax /* push probe ID */ 780 call *lockstat_probe 781 addl $12, %esp /* adjust for arguments */ 782 popl %ebp /* pop frame */ 783 1: 784 popl %edx /* restore thread pointer */ 785 decb T_LOCKSTAT(%edx) /* curthread->t_lockstat-- */ 786 movl $1, %eax /* return success if tryenter */ 787 addl $4, %esp /* pop argument */ 788 ret 789 SET_SIZE(lockstat_wrapper_arg) 790 791 792 ENTRY(mutex_tryenter) 793 movl %gs:CPU_THREAD, %edx /* edx = thread ptr */ 794 movl 4(%esp), %ecx /* ecx = lock ptr */ 795 xorl %eax, %eax /* eax = 0 (unheld adaptive) */ 796 lock 797 cmpxchgl %edx, (%ecx) 798 jnz mutex_vector_tryenter 799 movl %ecx, %eax 800 #if defined(OPTERON_WORKAROUND_6323525) 801 .mutex_tryenter_lockstat_patch_point: 802 .mutex_tryenter_6323525_patch_point: 803 ret /* nop space for lfence */ 804 nop 805 nop 806 .mutex_tryenter_lockstat_6323525_patch_point: /* new patch point if lfence */ 807 nop 808 #else /* OPTERON_WORKAROUND_6323525 */ 809 .mutex_tryenter_lockstat_patch_point: 810 ret 811 #endif /* OPTERON_WORKAROUND_6323525 */ 812 movl $LS_MUTEX_ENTER_ACQUIRE, %eax 813 jmp lockstat_wrapper 814 SET_SIZE(mutex_tryenter) 815 816 ENTRY(mutex_adaptive_tryenter) 817 movl %gs:CPU_THREAD, %edx /* edx = thread ptr */ 818 movl 4(%esp), %ecx /* ecx = lock ptr */ 819 xorl %eax, %eax /* eax = 0 (unheld adaptive) */ 820 lock 821 cmpxchgl %edx, (%ecx) 822 jnz 0f 823 movl %ecx, %eax 824 #if defined(OPTERON_WORKAROUND_6323525) 825 .mutex_atryenter_6323525_patch_point: 826 ret /* nop space for lfence */ 827 nop 828 nop 829 nop 830 #else /* OPTERON_WORKAROUND_6323525 */ 831 ret 832 #endif /* OPTERON_WORKAROUND_6323525 */ 833 0: 834 xorl %eax, %eax 835 ret 836 SET_SIZE(mutex_adaptive_tryenter) 837 838 .globl mutex_owner_running_critical_start 839 840 ENTRY(mutex_owner_running) 841 mutex_owner_running_critical_start: 842 movl 4(%esp), %eax /* get owner field */ 843 movl (%eax), %eax 844 andl $MUTEX_THREAD, %eax /* remove waiters bit */ 845 cmpl $0, %eax /* if free, skip */ 846 je 1f /* go return 0 */ 847 movl T_CPU(%eax), %ecx /* get owner->t_cpu */ 848 movl CPU_THREAD(%ecx), %edx /* get t_cpu->cpu_thread */ 849 .mutex_owner_running_critical_end: 850 cmpl %eax, %edx /* owner == running thread? */ 851 je 2f /* yes, go return cpu */ 852 1: 853 xorl %eax, %eax /* return 0 */ 854 ret 855 2: 856 movl %ecx, %eax /* return cpu */ 857 ret 858 859 SET_SIZE(mutex_owner_running) 860 861 .globl mutex_owner_running_critical_size 862 .type mutex_owner_running_critical_size, @object 863 .align CPTRSIZE 864 mutex_owner_running_critical_size: 865 .long .mutex_owner_running_critical_end - mutex_owner_running_critical_start 866 SET_SIZE(mutex_owner_running_critical_size) 867 868 .globl mutex_exit_critical_start 869 870 ENTRY(mutex_exit) 871 mutex_exit_critical_start: /* If interrupted, restart here */ 872 movl %gs:CPU_THREAD, %edx 873 movl 4(%esp), %ecx 874 cmpl %edx, (%ecx) 875 jne mutex_vector_exit /* wrong type or wrong owner */ 876 movl $0, (%ecx) /* clear owner AND lock */ 877 .mutex_exit_critical_end: 878 .mutex_exit_lockstat_patch_point: 879 ret 880 movl $LS_MUTEX_EXIT_RELEASE, %eax 881 jmp lockstat_wrapper 882 SET_SIZE(mutex_exit) 883 884 .globl mutex_exit_critical_size 885 .type mutex_exit_critical_size, @object 886 .align CPTRSIZE 887 mutex_exit_critical_size: 888 .long .mutex_exit_critical_end - mutex_exit_critical_start 889 SET_SIZE(mutex_exit_critical_size) 890 891 #endif /* !__amd64 */ 892 893 #endif /* __lint */ 894 895 /* 896 * rw_enter() and rw_exit(). 897 * 898 * These routines handle the simple cases of rw_enter (write-locking an unheld 899 * lock or read-locking a lock that's neither write-locked nor write-wanted) 900 * and rw_exit (no waiters or not the last reader). If anything complicated 901 * is going on we punt to rw_enter_sleep() and rw_exit_wakeup(), respectively. 902 */ 903 #if defined(lint) || defined(__lint) 904 905 /* ARGSUSED */ 906 void 907 rw_enter(krwlock_t *lp, krw_t rw) 908 {} 909 910 /* ARGSUSED */ 911 void 912 rw_exit(krwlock_t *lp) 913 {} 914 915 #else /* __lint */ 916 917 #if defined(__amd64) 918 919 ENTRY(rw_enter) 920 cmpl $RW_WRITER, %esi 921 je .rw_write_enter 922 movq (%rdi), %rax /* rax = old rw_wwwh value */ 923 testl $RW_WRITE_LOCKED|RW_WRITE_WANTED, %eax 924 jnz rw_enter_sleep 925 leaq RW_READ_LOCK(%rax), %rdx /* rdx = new rw_wwwh value */ 926 lock 927 cmpxchgq %rdx, (%rdi) /* try to grab read lock */ 928 jnz rw_enter_sleep 929 .rw_read_enter_lockstat_patch_point: 930 ret 931 movq %gs:CPU_THREAD, %rcx /* rcx = thread ptr */ 932 movq %rdi, %rsi /* rsi = lock ptr */ 933 movl $LS_RW_ENTER_ACQUIRE, %edi 934 movl $RW_READER, %edx 935 jmp lockstat_wrapper_arg 936 .rw_write_enter: 937 movq %gs:CPU_THREAD, %rdx 938 orq $RW_WRITE_LOCKED, %rdx /* rdx = write-locked value */ 939 xorl %eax, %eax /* rax = unheld value */ 940 lock 941 cmpxchgq %rdx, (%rdi) /* try to grab write lock */ 942 jnz rw_enter_sleep 943 944 #if defined(OPTERON_WORKAROUND_6323525) 945 .rw_write_enter_lockstat_patch_point: 946 .rw_write_enter_6323525_patch_point: 947 ret 948 nop 949 nop 950 .rw_write_enter_lockstat_6323525_patch_point: 951 nop 952 #else /* OPTERON_WORKAROUND_6323525 */ 953 .rw_write_enter_lockstat_patch_point: 954 ret 955 #endif /* OPTERON_WORKAROUND_6323525 */ 956 957 movq %gs:CPU_THREAD, %rcx /* rcx = thread ptr */ 958 movq %rdi, %rsi /* rsi = lock ptr */ 959 movl $LS_RW_ENTER_ACQUIRE, %edi 960 movl $RW_WRITER, %edx 961 jmp lockstat_wrapper_arg 962 SET_SIZE(rw_enter) 963 964 ENTRY(rw_exit) 965 movq (%rdi), %rax /* rax = old rw_wwwh value */ 966 cmpl $RW_READ_LOCK, %eax /* single-reader, no waiters? */ 967 jne .rw_not_single_reader 968 xorl %edx, %edx /* rdx = new value (unheld) */ 969 .rw_read_exit: 970 lock 971 cmpxchgq %rdx, (%rdi) /* try to drop read lock */ 972 jnz rw_exit_wakeup 973 .rw_read_exit_lockstat_patch_point: 974 ret 975 movq %gs:CPU_THREAD, %rcx /* rcx = thread ptr */ 976 movq %rdi, %rsi /* rsi = lock ptr */ 977 movl $LS_RW_EXIT_RELEASE, %edi 978 movl $RW_READER, %edx 979 jmp lockstat_wrapper_arg 980 .rw_not_single_reader: 981 testl $RW_WRITE_LOCKED, %eax /* write-locked or write-wanted? */ 982 jnz .rw_write_exit 983 leaq -RW_READ_LOCK(%rax), %rdx /* rdx = new value */ 984 cmpl $RW_READ_LOCK, %edx 985 jge .rw_read_exit /* not last reader, safe to drop */ 986 jmp rw_exit_wakeup /* last reader with waiters */ 987 .rw_write_exit: 988 movq %gs:CPU_THREAD, %rax /* rax = thread ptr */ 989 xorl %edx, %edx /* rdx = new value (unheld) */ 990 orq $RW_WRITE_LOCKED, %rax /* eax = write-locked value */ 991 lock 992 cmpxchgq %rdx, (%rdi) /* try to drop read lock */ 993 jnz rw_exit_wakeup 994 .rw_write_exit_lockstat_patch_point: 995 ret 996 movq %gs:CPU_THREAD, %rcx /* rcx = thread ptr */ 997 movq %rdi, %rsi /* rsi - lock ptr */ 998 movl $LS_RW_EXIT_RELEASE, %edi 999 movl $RW_WRITER, %edx 1000 jmp lockstat_wrapper_arg 1001 SET_SIZE(rw_exit) 1002 1003 #else 1004 1005 ENTRY(rw_enter) 1006 movl 4(%esp), %ecx /* ecx = lock ptr */ 1007 cmpl $RW_WRITER, 8(%esp) 1008 je .rw_write_enter 1009 movl (%ecx), %eax /* eax = old rw_wwwh value */ 1010 testl $RW_WRITE_LOCKED|RW_WRITE_WANTED, %eax 1011 jnz rw_enter_sleep 1012 leal RW_READ_LOCK(%eax), %edx /* edx = new rw_wwwh value */ 1013 lock 1014 cmpxchgl %edx, (%ecx) /* try to grab read lock */ 1015 jnz rw_enter_sleep 1016 .rw_read_enter_lockstat_patch_point: 1017 ret 1018 movl %gs:CPU_THREAD, %edx /* edx = thread ptr */ 1019 movl $LS_RW_ENTER_ACQUIRE, %eax 1020 pushl $RW_READER 1021 jmp lockstat_wrapper_arg 1022 .rw_write_enter: 1023 movl %gs:CPU_THREAD, %edx 1024 orl $RW_WRITE_LOCKED, %edx /* edx = write-locked value */ 1025 xorl %eax, %eax /* eax = unheld value */ 1026 lock 1027 cmpxchgl %edx, (%ecx) /* try to grab write lock */ 1028 jnz rw_enter_sleep 1029 1030 #if defined(OPTERON_WORKAROUND_6323525) 1031 .rw_write_enter_lockstat_patch_point: 1032 .rw_write_enter_6323525_patch_point: 1033 ret 1034 nop 1035 nop 1036 .rw_write_enter_lockstat_6323525_patch_point: 1037 nop 1038 #else /* OPTERON_WORKAROUND_6323525 */ 1039 .rw_write_enter_lockstat_patch_point: 1040 ret 1041 #endif /* OPTERON_WORKAROUND_6323525 */ 1042 1043 movl %gs:CPU_THREAD, %edx /* edx = thread ptr */ 1044 movl $LS_RW_ENTER_ACQUIRE, %eax 1045 pushl $RW_WRITER 1046 jmp lockstat_wrapper_arg 1047 SET_SIZE(rw_enter) 1048 1049 ENTRY(rw_exit) 1050 movl 4(%esp), %ecx /* ecx = lock ptr */ 1051 movl (%ecx), %eax /* eax = old rw_wwwh value */ 1052 cmpl $RW_READ_LOCK, %eax /* single-reader, no waiters? */ 1053 jne .rw_not_single_reader 1054 xorl %edx, %edx /* edx = new value (unheld) */ 1055 .rw_read_exit: 1056 lock 1057 cmpxchgl %edx, (%ecx) /* try to drop read lock */ 1058 jnz rw_exit_wakeup 1059 .rw_read_exit_lockstat_patch_point: 1060 ret 1061 movl $LS_RW_EXIT_RELEASE, %eax 1062 pushl $RW_READER 1063 jmp lockstat_wrapper_arg 1064 .rw_not_single_reader: 1065 testl $RW_WRITE_LOCKED, %eax /* write-locked or write-wanted? */ 1066 jnz .rw_write_exit 1067 leal -RW_READ_LOCK(%eax), %edx /* edx = new value */ 1068 cmpl $RW_READ_LOCK, %edx 1069 jge .rw_read_exit /* not last reader, safe to drop */ 1070 jmp rw_exit_wakeup /* last reader with waiters */ 1071 .rw_write_exit: 1072 movl %gs:CPU_THREAD, %eax /* eax = thread ptr */ 1073 xorl %edx, %edx /* edx = new value (unheld) */ 1074 orl $RW_WRITE_LOCKED, %eax /* eax = write-locked value */ 1075 lock 1076 cmpxchgl %edx, (%ecx) /* try to drop read lock */ 1077 jnz rw_exit_wakeup 1078 .rw_write_exit_lockstat_patch_point: 1079 ret 1080 movl %gs:CPU_THREAD, %edx /* edx = thread ptr */ 1081 movl $LS_RW_EXIT_RELEASE, %eax 1082 pushl $RW_WRITER 1083 jmp lockstat_wrapper_arg 1084 SET_SIZE(rw_exit) 1085 1086 #endif /* !__amd64 */ 1087 1088 #endif /* __lint */ 1089 1090 #if defined(OPTERON_WORKAROUND_6323525) 1091 #if defined(lint) || defined(__lint) 1092 1093 int workaround_6323525_patched; 1094 1095 void 1096 patch_workaround_6323525(void) 1097 {} 1098 1099 #else /* lint */ 1100 1101 /* 1102 * If it is necessary to patch the lock enter routines with the lfence 1103 * workaround, workaround_6323525_patched is set to a non-zero value so that 1104 * the lockstat_hat_patch routine can patch to the new location of the 'ret' 1105 * instruction. 1106 */ 1107 DGDEF3(workaround_6323525_patched, 4, 4) 1108 .long 0 1109 1110 #if defined(__amd64) 1111 1112 #define HOT_MUTEX_PATCH(srcaddr, dstaddr, size) \ 1113 movq $size, %rbx; \ 1114 movq $dstaddr, %r13; \ 1115 addq %rbx, %r13; \ 1116 movq $srcaddr, %r12; \ 1117 addq %rbx, %r12; \ 1118 0: \ 1119 decq %r13; \ 1120 decq %r12; \ 1121 movzbl (%r12), %esi; \ 1122 movq $1, %rdx; \ 1123 movq %r13, %rdi; \ 1124 call hot_patch_kernel_text; \ 1125 decq %rbx; \ 1126 testq %rbx, %rbx; \ 1127 jg 0b; 1128 1129 /* 1130 * patch_workaround_6323525: provide workaround for 6323525 1131 * 1132 * The workaround is to place a fencing instruction (lfence) between the 1133 * mutex operation and the subsequent read-modify-write instruction. 1134 * 1135 * This routine hot patches the lfence instruction on top of the space 1136 * reserved by nops in the lock enter routines. 1137 */ 1138 ENTRY_NP(patch_workaround_6323525) 1139 pushq %rbp 1140 movq %rsp, %rbp 1141 pushq %r12 1142 pushq %r13 1143 pushq %rbx 1144 1145 /* 1146 * lockstat_hot_patch() to use the alternate lockstat workaround 1147 * 6323525 patch points (points past the lfence instruction to the 1148 * new ret) when workaround_6323525_patched is set. 1149 */ 1150 movl $1, workaround_6323525_patched 1151 1152 /* 1153 * patch ret/nop/nop/nop to lfence/ret at the end of the lock enter 1154 * routines. The 4 bytes are patched in reverse order so that the 1155 * the existing ret is overwritten last. This provides lock enter 1156 * sanity during the intermediate patching stages. 1157 */ 1158 HOT_MUTEX_PATCH(_lfence_insn, .mutex_enter_6323525_patch_point, 4) 1159 HOT_MUTEX_PATCH(_lfence_insn, .mutex_tryenter_6323525_patch_point, 4) 1160 HOT_MUTEX_PATCH(_lfence_insn, .mutex_atryenter_6323525_patch_point, 4) 1161 HOT_MUTEX_PATCH(_lfence_insn, .rw_write_enter_6323525_patch_point, 4) 1162 1163 popq %rbx 1164 popq %r13 1165 popq %r12 1166 movq %rbp, %rsp 1167 popq %rbp 1168 ret 1169 _lfence_insn: 1170 lfence 1171 ret 1172 SET_SIZE(patch_workaround_6323525) 1173 1174 1175 #else /* __amd64 */ 1176 1177 #define HOT_MUTEX_PATCH(srcaddr, dstaddr, size) \ 1178 movl $size, %ebx; \ 1179 movl $srcaddr, %esi; \ 1180 addl %ebx, %esi; \ 1181 movl $dstaddr, %edi; \ 1182 addl %ebx, %edi; \ 1183 0: \ 1184 decl %esi; \ 1185 decl %edi; \ 1186 pushl $1; \ 1187 movzbl (%esi), %eax; \ 1188 pushl %eax; \ 1189 pushl %edi; \ 1190 call hot_patch_kernel_text; \ 1191 addl $12, %esp; \ 1192 decl %ebx; \ 1193 testl %ebx, %ebx; \ 1194 jg 0b; 1195 1196 1197 /* see comments above */ 1198 ENTRY_NP(patch_workaround_6323525) 1199 pushl %ebp 1200 movl %esp, %ebp 1201 pushl %ebx 1202 pushl %esi 1203 pushl %edi 1204 1205 movl $1, workaround_6323525_patched 1206 1207 HOT_MUTEX_PATCH(_lfence_insn, .mutex_enter_6323525_patch_point, 4) 1208 HOT_MUTEX_PATCH(_lfence_insn, .mutex_tryenter_6323525_patch_point, 4) 1209 HOT_MUTEX_PATCH(_lfence_insn, .mutex_atryenter_6323525_patch_point, 4) 1210 HOT_MUTEX_PATCH(_lfence_insn, .rw_write_enter_6323525_patch_point, 4) 1211 1212 popl %edi 1213 popl %esi 1214 popl %ebx 1215 movl %ebp, %esp 1216 popl %ebp 1217 ret 1218 _lfence_insn: 1219 .byte 0xf, 0xae, 0xe8 / [lfence instruction] 1220 ret 1221 SET_SIZE(patch_workaround_6323525) 1222 1223 #endif /* !__amd64 */ 1224 #endif /* !lint */ 1225 #endif /* OPTERON_WORKAROUND_6323525 */ 1226 1227 1228 #if defined(lint) || defined(__lint) 1229 1230 void 1231 lockstat_hot_patch(void) 1232 {} 1233 1234 #else 1235 1236 #if defined(__amd64) 1237 1238 #define HOT_PATCH(addr, event, active_instr, normal_instr, len) \ 1239 movq $normal_instr, %rsi; \ 1240 movq $active_instr, %rdi; \ 1241 leaq lockstat_probemap(%rip), %rax; \ 1242 movl _MUL(event, DTRACE_IDSIZE)(%rax), %eax; \ 1243 testl %eax, %eax; \ 1244 jz 9f; \ 1245 movq %rdi, %rsi; \ 1246 9: \ 1247 movq $len, %rdx; \ 1248 movq $addr, %rdi; \ 1249 call hot_patch_kernel_text 1250 1251 #else 1252 1253 #define HOT_PATCH(addr, event, active_instr, normal_instr, len) \ 1254 movl $normal_instr, %ecx; \ 1255 movl $active_instr, %edx; \ 1256 movl $lockstat_probemap, %eax; \ 1257 movl _MUL(event, DTRACE_IDSIZE)(%eax), %eax; \ 1258 testl %eax, %eax; \ 1259 jz . + 4; \ 1260 movl %edx, %ecx; \ 1261 pushl $len; \ 1262 pushl %ecx; \ 1263 pushl $addr; \ 1264 call hot_patch_kernel_text; \ 1265 addl $12, %esp; 1266 1267 #endif /* !__amd64 */ 1268 1269 ENTRY(lockstat_hot_patch) 1270 #if defined(__amd64) 1271 pushq %rbp /* align stack properly */ 1272 movq %rsp, %rbp 1273 #endif /* __amd64 */ 1274 1275 #if defined(OPTERON_WORKAROUND_6323525) 1276 cmpl $0, workaround_6323525_patched 1277 je 1f 1278 HOT_PATCH(.mutex_enter_lockstat_6323525_patch_point, 1279 LS_MUTEX_ENTER_ACQUIRE, NOP_INSTR, RET_INSTR, 1) 1280 HOT_PATCH(.mutex_tryenter_lockstat_6323525_patch_point, 1281 LS_MUTEX_ENTER_ACQUIRE, NOP_INSTR, RET_INSTR, 1) 1282 HOT_PATCH(.rw_write_enter_lockstat_6323525_patch_point, 1283 LS_RW_ENTER_ACQUIRE, NOP_INSTR, RET_INSTR, 1) 1284 jmp 2f 1285 1: 1286 HOT_PATCH(.mutex_enter_lockstat_patch_point, 1287 LS_MUTEX_ENTER_ACQUIRE, NOP_INSTR, RET_INSTR, 1) 1288 HOT_PATCH(.mutex_tryenter_lockstat_patch_point, 1289 LS_MUTEX_ENTER_ACQUIRE, NOP_INSTR, RET_INSTR, 1) 1290 HOT_PATCH(.rw_write_enter_lockstat_patch_point, 1291 LS_RW_ENTER_ACQUIRE, NOP_INSTR, RET_INSTR, 1) 1292 2: 1293 #else /* OPTERON_WORKAROUND_6323525 */ 1294 HOT_PATCH(.mutex_enter_lockstat_patch_point, 1295 LS_MUTEX_ENTER_ACQUIRE, NOP_INSTR, RET_INSTR, 1) 1296 HOT_PATCH(.mutex_tryenter_lockstat_patch_point, 1297 LS_MUTEX_ENTER_ACQUIRE, NOP_INSTR, RET_INSTR, 1) 1298 HOT_PATCH(.rw_write_enter_lockstat_patch_point, 1299 LS_RW_ENTER_ACQUIRE, NOP_INSTR, RET_INSTR, 1) 1300 #endif /* !OPTERON_WORKAROUND_6323525 */ 1301 HOT_PATCH(.mutex_exit_lockstat_patch_point, 1302 LS_MUTEX_EXIT_RELEASE, NOP_INSTR, RET_INSTR, 1) 1303 HOT_PATCH(.rw_read_enter_lockstat_patch_point, 1304 LS_RW_ENTER_ACQUIRE, NOP_INSTR, RET_INSTR, 1) 1305 HOT_PATCH(.rw_write_exit_lockstat_patch_point, 1306 LS_RW_EXIT_RELEASE, NOP_INSTR, RET_INSTR, 1) 1307 HOT_PATCH(.rw_read_exit_lockstat_patch_point, 1308 LS_RW_EXIT_RELEASE, NOP_INSTR, RET_INSTR, 1) 1309 HOT_PATCH(.lock_set_lockstat_patch_point, 1310 LS_LOCK_SET_ACQUIRE, NOP_INSTR, RET_INSTR, 1) 1311 HOT_PATCH(.lock_try_lockstat_patch_point, 1312 LS_LOCK_TRY_ACQUIRE, NOP_INSTR, RET_INSTR, 1) 1313 HOT_PATCH(.lock_clear_lockstat_patch_point, 1314 LS_LOCK_CLEAR_RELEASE, NOP_INSTR, RET_INSTR, 1) 1315 HOT_PATCH(.lock_set_spl_lockstat_patch_point, 1316 LS_LOCK_SET_SPL_ACQUIRE, NOP_INSTR, RET_INSTR, 1) 1317 1318 HOT_PATCH(LOCK_CLEAR_SPLX_LOCKSTAT_PATCH_POINT, 1319 LS_LOCK_CLEAR_SPLX_RELEASE, 1320 LOCK_CLEAR_SPLX_LOCKSTAT_PATCH_VAL, 0, 1); 1321 #if defined(__amd64) 1322 leave /* unwind stack */ 1323 #endif /* __amd64 */ 1324 ret 1325 SET_SIZE(lockstat_hot_patch) 1326 1327 #endif /* __lint */ 1328 1329 #if defined(lint) || defined(__lint) 1330 1331 /* XX64 membar_*() should be inlines */ 1332 1333 void 1334 membar_sync(void) 1335 {} 1336 1337 void 1338 membar_enter(void) 1339 {} 1340 1341 void 1342 membar_exit(void) 1343 {} 1344 1345 void 1346 membar_producer(void) 1347 {} 1348 1349 void 1350 membar_consumer(void) 1351 {} 1352 1353 #else /* __lint */ 1354 1355 #if defined(__amd64) 1356 1357 ENTRY(membar_enter) 1358 ALTENTRY(membar_exit) 1359 ALTENTRY(membar_sync) 1360 mfence /* lighter weight than lock; xorq $0,(%rsp) */ 1361 ret 1362 SET_SIZE(membar_sync) 1363 SET_SIZE(membar_exit) 1364 SET_SIZE(membar_enter) 1365 1366 ENTRY(membar_producer) 1367 sfence 1368 ret 1369 SET_SIZE(membar_producer) 1370 1371 ENTRY(membar_consumer) 1372 lfence 1373 ret 1374 SET_SIZE(membar_consumer) 1375 1376 #else 1377 1378 ENTRY(membar_enter) 1379 ALTENTRY(membar_exit) 1380 ALTENTRY(membar_sync) 1381 lock 1382 xorl $0, (%esp) 1383 ret 1384 SET_SIZE(membar_sync) 1385 SET_SIZE(membar_exit) 1386 SET_SIZE(membar_enter) 1387 1388 /* 1389 * On machines that support sfence and lfence, these 1390 * memory barriers can be more precisely implemented 1391 * without causing the whole world to stop 1392 */ 1393 ENTRY(membar_producer) 1394 .globl _patch_sfence_ret 1395 _patch_sfence_ret: /* c.f. membar #StoreStore */ 1396 lock 1397 xorl $0, (%esp) 1398 ret 1399 SET_SIZE(membar_producer) 1400 1401 ENTRY(membar_consumer) 1402 .globl _patch_lfence_ret 1403 _patch_lfence_ret: /* c.f. membar #LoadLoad */ 1404 lock 1405 xorl $0, (%esp) 1406 ret 1407 SET_SIZE(membar_consumer) 1408 1409 #endif /* !__amd64 */ 1410 1411 #endif /* __lint */ 1412 1413 /* 1414 * thread_onproc() 1415 * Set thread in onproc state for the specified CPU. 1416 * Also set the thread lock pointer to the CPU's onproc lock. 1417 * Since the new lock isn't held, the store ordering is important. 1418 * If not done in assembler, the compiler could reorder the stores. 1419 */ 1420 #if defined(lint) || defined(__lint) 1421 1422 void 1423 thread_onproc(kthread_id_t t, cpu_t *cp) 1424 { 1425 t->t_state = TS_ONPROC; 1426 t->t_lockp = &cp->cpu_thread_lock; 1427 } 1428 1429 #else /* __lint */ 1430 1431 #if defined(__amd64) 1432 1433 ENTRY(thread_onproc) 1434 addq $CPU_THREAD_LOCK, %rsi /* pointer to disp_lock while running */ 1435 movl $ONPROC_THREAD, T_STATE(%rdi) /* set state to TS_ONPROC */ 1436 movq %rsi, T_LOCKP(%rdi) /* store new lock pointer */ 1437 ret 1438 SET_SIZE(thread_onproc) 1439 1440 #else 1441 1442 ENTRY(thread_onproc) 1443 movl 4(%esp), %eax 1444 movl 8(%esp), %ecx 1445 addl $CPU_THREAD_LOCK, %ecx /* pointer to disp_lock while running */ 1446 movl $ONPROC_THREAD, T_STATE(%eax) /* set state to TS_ONPROC */ 1447 movl %ecx, T_LOCKP(%eax) /* store new lock pointer */ 1448 ret 1449 SET_SIZE(thread_onproc) 1450 1451 #endif /* !__amd64 */ 1452 1453 #endif /* __lint */ 1454 1455 /* 1456 * mutex_delay_default(void) 1457 * Spins for approx a few hundred processor cycles and returns to caller. 1458 */ 1459 1460 #if defined(lint) || defined(__lint) 1461 1462 void 1463 mutex_delay_default(void) 1464 {} 1465 1466 #else /* __lint */ 1467 1468 #if defined(__amd64) 1469 1470 ENTRY(mutex_delay_default) 1471 movq $92,%r11 1472 0: decq %r11 1473 jg 0b 1474 ret 1475 SET_SIZE(mutex_delay_default) 1476 1477 #else 1478 1479 ENTRY(mutex_delay_default) 1480 push %ebp 1481 movl %esp,%ebp 1482 andl $-16,%esp 1483 push %ebx 1484 movl $93,%ebx 1485 0: decl %ebx 1486 jg 0b 1487 pop %ebx 1488 leave 1489 ret 1490 SET_SIZE(mutex_delay_default) 1491 1492 #endif /* !__amd64 */ 1493 #endif /* __lint */