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.
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.
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]
22 * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
23 * Use is subject to license terms.
26 #pragma ident "%Z%%M% %I% %E% SMI"
28 #if defined(lint) || defined(__lint)
29 #include <sys/types.h>
30 #include <sys/thread.h>
31 #include <sys/cpuvar.h>
37 #include <sys/mutex_impl.h>
38 #include <sys/asm_linkage.h>
39 #include <sys/asm_misc.h>
40 #include <sys/regset.h>
41 #include <sys/rwlock_impl.h>
42 #include <sys/lockstat.h>
45 * lock_try(lp), ulock_try(lp)
46 * - returns non-zero on success.
47 * - doesn't block interrupts so don't use this to spin on a lock.
49 * ulock_try() is for a lock in the user address space.
52 #if defined(lint) || defined(__lint)
61 lock_spin_try
(lock_t
*lp
)
79 .lock_try_lockstat_patch_point:
85 movq
%gs
:CPU_THREAD
, %rdx
/* rdx = thread addr */
86 movq
%rdi
, %rsi
/* rsi = lock addr */
87 movl $LS_LOCK_TRY_ACQUIRE
, %edi
/* edi = event */
97 SET_SIZE
(lock_spin_try
)
101 movq kernelbase
(%rip
), %rax
102 cmpq
%rax
, %rdi
/* test uaddr < kernelbase */
103 jb ulock_pass
/* uaddr < kernelbase, proceed */
105 movq
%rdi
, %r12 /* preserve lock ptr for debugging */
106 leaq
.ulock_panic_msg(%rip), %rdi
107 pushq
%rbp
/* align stack properly */
109 xorl
%eax
, %eax
/* clear for varargs */
125 movl
4(%esp
),%ecx
/* ecx = lock addr */
127 xchgb
%dl
, (%ecx
) /* using dl will avoid partial */
128 testb
%dl
,%dl
/* stalls on P6 ? */
130 .lock_try_lockstat_patch_point:
132 movl
%gs
:CPU_THREAD
, %edx
/* edx = thread addr */
135 movl $LS_LOCK_TRY_ACQUIRE
, %eax
143 movl
4(%esp
),%ecx
/* ecx = lock addr */
145 xchgb
%dl
, (%ecx
) /* using dl will avoid partial */
146 testb
%dl
,%dl
/* stalls on P6 ? */
149 SET_SIZE
(lock_spin_try
)
153 movl kernelbase
, %eax
154 cmpl %eax
, 4(%esp
) /* test uaddr < kernelbase */
155 jb ulock_pass
/* uaddr < kernelbase, proceed */
157 pushl $
.ulock_panic_msg
170 #endif /* !__amd64 */
175 .string "ulock_try: Argument is above kernelbase"
183 * - unlock lock without changing interrupt priority level.
186 #if defined(lint) || defined(__lint)
190 lock_clear
(lock_t
*lp
)
195 ulock_clear
(lock_t
*lp
)
204 .lock_clear_lockstat_patch_point:
206 movq
%rdi
, %rsi
/* rsi = lock addr */
207 movq
%gs
:CPU_THREAD
, %rdx
/* rdx = thread addr */
208 movl $LS_LOCK_CLEAR_RELEASE
, %edi
/* edi = event */
214 movq kernelbase
(%rip
), %rcx
215 cmpq
%rcx
, %rdi
/* test uaddr < kernelbase */
216 jb ulock_clr
/* uaddr < kernelbase, proceed */
218 leaq
.ulock_clear_msg(%rip), %rdi
219 pushq
%rbp
/* align stack properly */
221 xorl
%eax
, %eax
/* clear for varargs */
228 SET_SIZE
(ulock_clear
)
235 .lock_clear_lockstat_patch_point:
237 movl
%gs
:CPU_THREAD
, %edx
/* edx = thread addr */
238 movl
%eax
, %ecx
/* ecx = lock pointer */
239 movl $LS_LOCK_CLEAR_RELEASE
, %eax
245 movl kernelbase
, %ecx
246 cmpl %ecx
, 4(%esp
) /* test uaddr < kernelbase */
247 jb ulock_clr
/* uaddr < kernelbase, proceed */
249 pushl $
.ulock_clear_msg
258 SET_SIZE
(ulock_clear
)
260 #endif /* !__amd64 */
265 .string "ulock_clear: Argument is above kernelbase"
273 * lock_set_spl(lock_t *lp, int new_pil, u_short *old_pil)
274 * Drops lp, sets pil to new_pil, stores old pil in *old_pil.
277 #if defined(lint) || defined(__lint)
281 lock_set_spl
(lock_t
*lp
, int new_pil
, u_short
*old_pil
)
292 movl
%esi
, 8(%rsp
) /* save priority level */
293 movq
%rdx
, 16(%rsp
) /* save old pil ptr */
294 movq
%rdi
, 24(%rsp
) /* save lock pointer */
295 movl
%esi
, %edi
/* pass priority level */
296 call splr
/* raise priority level */
297 movq
24(%rsp
), %rdi
/* rdi = lock addr */
299 xchgb
%dl
, (%rdi
) /* try to set lock */
300 testb
%dl
, %dl
/* did we get the lock? ... */
301 jnz
.lss_miss /* ... no, go to C for the hard case */
302 movq
16(%rsp
), %rdx
/* rdx = old pil addr */
303 movw
%ax
, (%rdx
) /* store old pil */
305 .lock_set_spl_lockstat_patch_point:
307 movq
%rdi
, %rsi
/* rsi = lock addr */
308 movq
%gs
:CPU_THREAD
, %rdx
/* rdx = thread addr */
309 movl $LS_LOCK_SET_SPL_ACQUIRE
, %edi
312 movl
8(%rsp
), %esi
/* new_pil */
313 movq
16(%rsp
), %rdx
/* old_pil_addr */
314 movl
%eax
, %ecx
/* original pil */
315 leave
/* unwind stack */
316 jmp lock_set_spl_spin
317 SET_SIZE
(lock_set_spl
)
322 movl
8(%esp
), %eax
/* get priority level */
324 call splr
/* raise priority level */
325 movl
8(%esp
), %ecx
/* ecx = lock addr */
328 xchgb
%dl
, (%ecx
) /* try to set lock */
329 testb
%dl
, %dl
/* did we get the lock? ... */
330 movl
12(%esp
), %edx
/* edx = olp pil addr (ZF unaffected) */
331 jnz
.lss_miss /* ... no, go to C for the hard case */
332 movw
%ax
, (%edx
) /* store old pil */
333 .lock_set_spl_lockstat_patch_point:
335 movl
%gs
:CPU_THREAD
, %edx
/* edx = thread addr*/
336 movl $LS_LOCK_SET_SPL_ACQUIRE
, %eax
339 pushl
%eax
/* original pil */
340 pushl
%edx
/* old_pil addr */
341 pushl
16(%esp
) /* new_pil */
342 pushl
%ecx
/* lock addr */
343 call lock_set_spl_spin
346 SET_SIZE
(lock_set_spl
)
348 #endif /* !__amd64 */
361 lock_init
(lock_t
*lp
)
381 #endif /* !__amd64 */
390 #if defined(lint) || defined(__lint)
403 xchgb
%dl
, (%rdi
) /* try to set lock */
404 testb
%dl
, %dl
/* did we get it? */
405 jnz lock_set_spin
/* no, go to C for the hard case */
406 .lock_set_lockstat_patch_point:
408 movq
%rdi
, %rsi
/* rsi = lock addr */
409 movq
%gs
:CPU_THREAD
, %rdx
/* rdx = thread addr */
410 movl $LS_LOCK_SET_ACQUIRE
, %edi
417 movl
4(%esp
), %ecx
/* ecx = lock addr */
419 xchgb
%dl
, (%ecx
) /* try to set lock */
420 testb
%dl
, %dl
/* did we get it? */
421 jnz lock_set_spin
/* no, go to C for the hard case */
422 .lock_set_lockstat_patch_point:
424 movl
%gs
:CPU_THREAD
, %edx
/* edx = thread addr */
425 movl $LS_LOCK_SET_ACQUIRE
, %eax
429 #endif /* !__amd64 */
434 * lock_clear_splx(lp, s)
437 #if defined(lint) || defined(__lint)
441 lock_clear_splx
(lock_t
*lp
, int s
)
448 ENTRY
(lock_clear_splx
)
449 movb $
0, (%rdi
) /* clear lock */
450 .lock_clear_splx_lockstat_patch_point:
453 movl
%esi
, %edi
/* arg for splx */
454 jmp splx
/* let splx do its thing */
455 .lock_clear_splx_lockstat:
456 pushq
%rbp
/* align stack properly */
458 subq $
16, %rsp
/* space to save args across splx */
459 movq
%rdi
, 8(%rsp
) /* save lock ptr across splx call */
460 movl
%esi
, %edi
/* arg for splx */
461 call splx
/* lower the priority */
462 movq
8(%rsp
), %rsi
/* rsi = lock ptr */
463 leave
/* unwind stack */
464 movq
%gs
:CPU_THREAD
, %rdx
/* rdx = thread addr */
465 movl $LS_LOCK_CLEAR_SPLX_RELEASE
, %edi
467 SET_SIZE
(lock_clear_splx
)
471 ENTRY
(lock_clear_splx
)
472 movl
4(%esp
), %eax
/* eax = lock addr */
473 movb $
0, (%eax
) /* clear lock */
474 .lock_clear_splx_lockstat_patch_point:
477 movl
8(%esp
), %edx
/* edx = desired pil */
478 movl
%edx
, 4(%esp
) /* set spl arg up for splx */
479 jmp splx
/* let splx do it's thing */
480 .lock_clear_splx_lockstat:
481 movl
8(%esp
), %edx
/* edx = desired pil */
482 pushl
%ebp
/* set up stack frame */
486 leave
/* unwind stack */
487 movl
4(%esp
), %ecx
/* ecx = lock pointer */
488 movl
%gs
:CPU_THREAD
, %edx
/* edx = thread addr */
489 movl $LS_LOCK_CLEAR_SPLX_RELEASE
, %eax
491 SET_SIZE
(lock_clear_splx
)
493 #endif /* !__amd64 */
495 #if defined(__GNUC_AS__)
496 #define LOCK_CLEAR_SPLX_LOCKSTAT_PATCH_VAL \
497 (.lock_clear_splx_lockstat - .lock_clear_splx_lockstat_patch_point - 2)
499 #define LOCK_CLEAR_SPLX_LOCKSTAT_PATCH_POINT \
500 (.lock_clear_splx_lockstat_patch_point + 1)
502 #define LOCK_CLEAR_SPLX_LOCKSTAT_PATCH_VAL \
503 [.lock_clear_splx_lockstat - .lock_clear_splx_lockstat_patch_point - 2]
505 #define LOCK_CLEAR_SPLX_LOCKSTAT_PATCH_POINT \
506 [.lock_clear_splx_lockstat_patch_point + 1]
512 * mutex_enter() and mutex_exit().
514 * These routines handle the simple cases of mutex_enter() (adaptive
515 * lock, not held) and mutex_exit() (adaptive lock, held, no waiters).
516 * If anything complicated is going on we punt to mutex_vector_enter().
518 * mutex_tryenter() is similar to mutex_enter() but returns zero if
519 * the lock cannot be acquired, nonzero on success.
521 * If mutex_exit() gets preempted in the window between checking waiters
522 * and clearing the lock, we can miss wakeups. Disabling preemption
523 * in the mutex code is prohibitively expensive, so instead we detect
524 * mutex preemption by examining the trapped PC in the interrupt path.
525 * If we interrupt a thread in mutex_exit() that has not yet cleared
526 * the lock, cmnint() resets its PC back to the beginning of
527 * mutex_exit() so it will check again for waiters when it resumes.
529 * The lockstat code below is activated when the lockstat driver
530 * calls lockstat_hot_patch() to hot-patch the kernel mutex code.
531 * Note that we don't need to test lockstat_event_mask here -- we won't
532 * patch this code in unless we're gathering ADAPTIVE_HOLD lockstats.
534 #if defined(lint) || defined(__lint)
538 mutex_enter
(kmutex_t
*lp
)
543 mutex_tryenter
(kmutex_t
*lp
)
548 mutex_adaptive_tryenter
(mutex_impl_t
*lp
)
553 mutex_exit
(kmutex_t
*lp
)
560 ENTRY_NP
(mutex_enter
)
561 movq
%gs
:CPU_THREAD
, %rdx
/* rdx = thread ptr */
562 xorl
%eax
, %eax
/* rax = 0 (unheld adaptive) */
564 cmpxchgq
%rdx
, (%rdi
)
565 jnz mutex_vector_enter
566 .mutex_enter_lockstat_patch_point:
567 #if defined(OPTERON_WORKAROUND_6323525)
568 .mutex_enter_6323525_patch_point:
569 ret
/* nop space for lfence */
572 .mutex_enter_lockstat_6323525_patch_point: /* new patch point if lfence */
574 #else /* OPTERON_WORKAROUND_6323525 */
576 #endif /* OPTERON_WORKAROUND_6323525 */
578 movl $LS_MUTEX_ENTER_ACQUIRE
, %edi
580 * expects %rdx=thread, %rsi=lock, %edi=lockstat event
582 ALTENTRY
(lockstat_wrapper
)
583 incb T_LOCKSTAT
(%rdx
) /* curthread->t_lockstat++ */
584 leaq lockstat_probemap
(%rip
), %rax
585 movl
(%rax
, %rdi
, DTRACE_IDSIZE
), %eax
586 testl
%eax
, %eax
/* check for non-zero probe */
588 pushq
%rbp
/* align stack properly */
592 leave
/* unwind stack */
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 */
598 SET_SIZE
(lockstat_wrapper
)
599 SET_SIZE
(mutex_enter
)
602 * expects %rcx=thread, %rdx=arg, %rsi=lock, %edi=lockstat event
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 */
610 pushq
%rbp
/* align stack properly */
614 leave
/* unwind stack */
616 movq
%gs
:CPU_THREAD
, %rdx
/* reload thread ptr */
617 decb T_LOCKSTAT
(%rdx
) /* curthread->t_lockstat-- */
618 movl $
1, %eax
/* return success if tryenter */
620 SET_SIZE
(lockstat_wrapper_arg
)
623 ENTRY
(mutex_tryenter
)
624 movq
%gs
:CPU_THREAD
, %rdx
/* rdx = thread ptr */
625 xorl
%eax
, %eax
/* rax = 0 (unheld adaptive) */
627 cmpxchgq
%rdx
, (%rdi
)
628 jnz mutex_vector_tryenter
629 not %eax
/* return success (nonzero) */
630 #if defined(OPTERON_WORKAROUND_6323525)
631 .mutex_tryenter_lockstat_patch_point:
632 .mutex_tryenter_6323525_patch_point:
633 ret
/* nop space for lfence */
636 .mutex_tryenter_lockstat_6323525_patch_point: /* new patch point if lfence */
638 #else /* OPTERON_WORKAROUND_6323525 */
639 .mutex_tryenter_lockstat_patch_point:
641 #endif /* OPTERON_WORKAROUND_6323525 */
643 movl $LS_MUTEX_ENTER_ACQUIRE
, %edi
645 SET_SIZE
(mutex_tryenter
)
647 ENTRY
(mutex_adaptive_tryenter
)
648 movq
%gs
:CPU_THREAD
, %rdx
/* rdx = thread ptr */
649 xorl
%eax
, %eax
/* rax = 0 (unheld adaptive) */
651 cmpxchgq
%rdx
, (%rdi
)
653 not %eax
/* return success (nonzero) */
654 #if defined(OPTERON_WORKAROUND_6323525)
655 .mutex_atryenter_6323525_patch_point:
656 ret
/* nop space for lfence */
660 #else /* OPTERON_WORKAROUND_6323525 */
662 #endif /* OPTERON_WORKAROUND_6323525 */
664 xorl
%eax
, %eax
/* return failure */
666 SET_SIZE
(mutex_adaptive_tryenter
)
668 .globl mutex_owner_running_critical_start
670 ENTRY
(mutex_owner_running
)
671 mutex_owner_running_critical_start
:
672 movq
(%rdi
), %r11 /* get owner field */
673 andq $MUTEX_THREAD
, %r11 /* remove waiters bit */
674 cmpq $
0, %r11 /* if free, skip */
675 je
1f
/* go return 0 */
676 movq T_CPU
(%r11), %r8 /* get owner->t_cpu */
677 movq CPU_THREAD
(%r8), %r9 /* get t_cpu->cpu_thread */
678 .mutex_owner_running_critical_end:
679 cmpq
%r11, %r9 /* owner == running thread? */
680 je
2f
/* yes, go return cpu */
682 xorq
%rax
, %rax
/* return 0 */
685 movq
%r8, %rax
/* return cpu */
687 SET_SIZE
(mutex_owner_running
)
689 .globl mutex_owner_running_critical_size
690 .type mutex_owner_running_critical_size, @object
692 mutex_owner_running_critical_size
:
693 .quad .mutex_owner_running_critical_end - mutex_owner_running_critical_start
694 SET_SIZE
(mutex_owner_running_critical_size
)
696 .globl mutex_exit_critical_start
699 mutex_exit_critical_start
: /* If interrupted, restart here */
700 movq
%gs
:CPU_THREAD
, %rdx
702 jne mutex_vector_exit
/* wrong type or wrong owner */
703 movq $
0, (%rdi
) /* clear owner AND lock */
704 .mutex_exit_critical_end:
705 .mutex_exit_lockstat_patch_point:
708 movl $LS_MUTEX_EXIT_RELEASE
, %edi
712 .globl mutex_exit_critical_size
713 .type mutex_exit_critical_size, @object
715 mutex_exit_critical_size
:
716 .quad .mutex_exit_critical_end - mutex_exit_critical_start
717 SET_SIZE
(mutex_exit_critical_size
)
721 ENTRY_NP
(mutex_enter
)
722 movl
%gs
:CPU_THREAD
, %edx
/* edx = thread ptr */
723 movl
4(%esp
), %ecx
/* ecx = lock ptr */
724 xorl
%eax
, %eax
/* eax = 0 (unheld adaptive) */
726 cmpxchgl
%edx
, (%ecx
)
727 jnz mutex_vector_enter
728 #if defined(OPTERON_WORKAROUND_6323525)
729 .mutex_enter_lockstat_patch_point:
730 .mutex_enter_6323525_patch_point:
731 ret
/* nop space for lfence */
734 .mutex_enter_lockstat_6323525_patch_point: /* new patch point if lfence */
736 #else /* OPTERON_WORKAROUND_6323525 */
737 .mutex_enter_lockstat_patch_point:
739 #endif /* OPTERON_WORKAROUND_6323525 */
740 movl $LS_MUTEX_ENTER_ACQUIRE
, %eax
741 ALTENTRY
(lockstat_wrapper
) /* expects edx=thread, ecx=lock, */
742 /* eax=lockstat event */
743 pushl
%ebp
/* buy a frame */
745 incb T_LOCKSTAT
(%edx
) /* curthread->t_lockstat++ */
746 pushl
%edx
/* save thread pointer */
747 movl $lockstat_probemap
, %edx
748 movl
(%edx
, %eax
, DTRACE_IDSIZE
), %eax
749 testl
%eax
, %eax
/* check for non-zero probe */
751 pushl
%ecx
/* push lock */
752 pushl
%eax
/* push probe ID */
756 popl
%edx
/* restore thread pointer */
757 decb T_LOCKSTAT
(%edx
) /* curthread->t_lockstat-- */
758 movl $
1, %eax
/* return success if tryenter */
759 popl
%ebp
/* pop off frame */
761 SET_SIZE
(lockstat_wrapper
)
762 SET_SIZE
(mutex_enter
)
764 ENTRY
(lockstat_wrapper_arg
) /* expects edx=thread, ecx=lock, */
765 /* eax=lockstat event, pushed arg */
766 incb T_LOCKSTAT
(%edx
) /* curthread->t_lockstat++ */
767 pushl
%edx
/* save thread pointer */
768 movl $lockstat_probemap
, %edx
769 movl
(%edx
, %eax
, DTRACE_IDSIZE
), %eax
770 testl
%eax
, %eax
/* check for non-zero probe */
772 pushl
%ebp
/* save %ebp */
773 pushl
8(%esp
) /* push arg1 */
774 movl
%ebp
, 12(%esp
) /* fake up the stack frame */
775 movl
%esp
, %ebp
/* fake up base pointer */
776 addl $
12, %ebp
/* adjust faked base pointer */
777 pushl
%ecx
/* push lock */
778 pushl
%eax
/* push probe ID */
780 addl $
12, %esp
/* adjust for arguments */
781 popl
%ebp
/* pop frame */
783 popl
%edx
/* restore thread pointer */
784 decb T_LOCKSTAT
(%edx
) /* curthread->t_lockstat-- */
785 movl $
1, %eax
/* return success if tryenter */
786 addl $
4, %esp
/* pop argument */
788 SET_SIZE
(lockstat_wrapper_arg
)
791 ENTRY
(mutex_tryenter
)
792 movl
%gs
:CPU_THREAD
, %edx
/* edx = thread ptr */
793 movl
4(%esp
), %ecx
/* ecx = lock ptr */
794 xorl
%eax
, %eax
/* eax = 0 (unheld adaptive) */
796 cmpxchgl
%edx
, (%ecx
)
797 jnz mutex_vector_tryenter
799 #if defined(OPTERON_WORKAROUND_6323525)
800 .mutex_tryenter_lockstat_patch_point:
801 .mutex_tryenter_6323525_patch_point:
802 ret
/* nop space for lfence */
805 .mutex_tryenter_lockstat_6323525_patch_point: /* new patch point if lfence */
807 #else /* OPTERON_WORKAROUND_6323525 */
808 .mutex_tryenter_lockstat_patch_point:
810 #endif /* OPTERON_WORKAROUND_6323525 */
811 movl $LS_MUTEX_ENTER_ACQUIRE
, %eax
813 SET_SIZE
(mutex_tryenter
)
815 ENTRY
(mutex_adaptive_tryenter
)
816 movl
%gs
:CPU_THREAD
, %edx
/* edx = thread ptr */
817 movl
4(%esp
), %ecx
/* ecx = lock ptr */
818 xorl
%eax
, %eax
/* eax = 0 (unheld adaptive) */
820 cmpxchgl
%edx
, (%ecx
)
823 #if defined(OPTERON_WORKAROUND_6323525)
824 .mutex_atryenter_6323525_patch_point:
825 ret
/* nop space for lfence */
829 #else /* OPTERON_WORKAROUND_6323525 */
831 #endif /* OPTERON_WORKAROUND_6323525 */
835 SET_SIZE
(mutex_adaptive_tryenter
)
837 .globl mutex_owner_running_critical_start
839 ENTRY
(mutex_owner_running
)
840 mutex_owner_running_critical_start
:
841 movl
4(%esp
), %eax
/* get owner field */
843 andl $MUTEX_THREAD
, %eax
/* remove waiters bit */
844 cmpl $
0, %eax
/* if free, skip */
845 je
1f
/* go return 0 */
846 movl T_CPU
(%eax
), %ecx
/* get owner->t_cpu */
847 movl CPU_THREAD
(%ecx
), %edx
/* get t_cpu->cpu_thread */
848 .mutex_owner_running_critical_end:
849 cmpl %eax
, %edx
/* owner == running thread? */
850 je
2f
/* yes, go return cpu */
852 xorl
%eax
, %eax
/* return 0 */
855 movl
%ecx
, %eax
/* return cpu */
858 SET_SIZE
(mutex_owner_running
)
860 .globl mutex_owner_running_critical_size
861 .type mutex_owner_running_critical_size, @object
863 mutex_owner_running_critical_size
:
864 .long .mutex_owner_running_critical_end - mutex_owner_running_critical_start
865 SET_SIZE
(mutex_owner_running_critical_size
)
867 .globl mutex_exit_critical_start
870 mutex_exit_critical_start
: /* If interrupted, restart here */
871 movl
%gs
:CPU_THREAD
, %edx
874 jne mutex_vector_exit
/* wrong type or wrong owner */
875 movl $
0, (%ecx
) /* clear owner AND lock */
876 .mutex_exit_critical_end:
877 .mutex_exit_lockstat_patch_point:
879 movl $LS_MUTEX_EXIT_RELEASE
, %eax
883 .globl mutex_exit_critical_size
884 .type mutex_exit_critical_size, @object
886 mutex_exit_critical_size
:
887 .long .mutex_exit_critical_end - mutex_exit_critical_start
888 SET_SIZE
(mutex_exit_critical_size
)
890 #endif /* !__amd64 */
895 * rw_enter() and rw_exit().
897 * These routines handle the simple cases of rw_enter (write-locking an unheld
898 * lock or read-locking a lock that's neither write-locked nor write-wanted)
899 * and rw_exit (no waiters or not the last reader). If anything complicated
900 * is going on we punt to rw_enter_sleep() and rw_exit_wakeup(), respectively.
902 #if defined(lint) || defined(__lint)
906 rw_enter
(krwlock_t
*lp
, krw_t rw
)
911 rw_exit
(krwlock_t
*lp
)
919 movq
%gs
:CPU_THREAD
, %rdx
/* rdx = thread ptr */
920 cmpl $RW_WRITER
, %esi
922 incl T_KPRI_REQ
(%rdx
) /* THREAD_KPRI_REQUEST() */
923 movq
(%rdi
), %rax
/* rax = old rw_wwwh value */
924 testl $RW_WRITE_LOCKED|RW_WRITE_WANTED
, %eax
926 leaq RW_READ_LOCK
(%rax
), %rdx
/* rdx = new rw_wwwh value */
928 cmpxchgq
%rdx
, (%rdi
) /* try to grab read lock */
930 .rw_read_enter_lockstat_patch_point:
932 movq
%gs
:CPU_THREAD
, %rcx
/* rcx = thread ptr */
933 movq
%rdi
, %rsi
/* rsi = lock ptr */
934 movl $LS_RW_ENTER_ACQUIRE
, %edi
935 movl $RW_READER
, %edx
936 jmp lockstat_wrapper_arg
938 orq $RW_WRITE_LOCKED
, %rdx
/* rdx = write-locked value */
939 xorl
%eax
, %eax
/* rax = unheld value */
941 cmpxchgq
%rdx
, (%rdi
) /* try to grab write lock */
944 #if defined(OPTERON_WORKAROUND_6323525)
945 .rw_write_enter_lockstat_patch_point:
946 .rw_write_enter_6323525_patch_point:
950 .rw_write_enter_lockstat_6323525_patch_point:
952 #else /* OPTERON_WORKAROUND_6323525 */
953 .rw_write_enter_lockstat_patch_point:
955 #endif /* OPTERON_WORKAROUND_6323525 */
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
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) */
971 cmpxchgq
%rdx
, (%rdi
) /* try to drop read lock */
973 movq
%gs
:CPU_THREAD
, %rcx
/* rcx = thread ptr */
974 decl T_KPRI_REQ
(%rcx
) /* THREAD_KPRI_RELEASE() */
975 .rw_read_exit_lockstat_patch_point:
977 movq
%rdi
, %rsi
/* rsi = lock ptr */
978 movl $LS_RW_EXIT_RELEASE
, %edi
979 movl $RW_READER
, %edx
980 jmp lockstat_wrapper_arg
981 .rw_not_single_reader:
982 testl $RW_WRITE_LOCKED
, %eax
/* write-locked or write-wanted? */
984 leaq
-RW_READ_LOCK
(%rax
), %rdx
/* rdx = new value */
985 cmpl $RW_READ_LOCK
, %edx
986 jge
.rw_read_exit /* not last reader, safe to drop */
987 jmp rw_exit_wakeup
/* last reader with waiters */
989 movq
%gs
:CPU_THREAD
, %rax
/* rax = thread ptr */
990 xorl
%edx
, %edx
/* rdx = new value (unheld) */
991 orq $RW_WRITE_LOCKED
, %rax
/* eax = write-locked value */
993 cmpxchgq
%rdx
, (%rdi
) /* try to drop read lock */
995 .rw_write_exit_lockstat_patch_point:
997 movq
%gs
:CPU_THREAD
, %rcx
/* rcx = thread ptr */
998 movq
%rdi
, %rsi
/* rsi - lock ptr */
999 movl $LS_RW_EXIT_RELEASE
, %edi
1000 movl $RW_WRITER
, %edx
1001 jmp lockstat_wrapper_arg
1007 movl
%gs
:CPU_THREAD
, %edx
/* edx = thread ptr */
1008 movl
4(%esp
), %ecx
/* ecx = lock ptr */
1009 cmpl $RW_WRITER
, 8(%esp
)
1011 incl T_KPRI_REQ
(%edx
) /* THREAD_KPRI_REQUEST() */
1012 movl
(%ecx
), %eax
/* eax = old rw_wwwh value */
1013 testl $RW_WRITE_LOCKED|RW_WRITE_WANTED
, %eax
1015 leal RW_READ_LOCK
(%eax
), %edx
/* edx = new rw_wwwh value */
1017 cmpxchgl
%edx
, (%ecx
) /* try to grab read lock */
1019 .rw_read_enter_lockstat_patch_point:
1021 movl
%gs
:CPU_THREAD
, %edx
/* edx = thread ptr */
1022 movl $LS_RW_ENTER_ACQUIRE
, %eax
1024 jmp lockstat_wrapper_arg
1026 orl $RW_WRITE_LOCKED
, %edx
/* edx = write-locked value */
1027 xorl
%eax
, %eax
/* eax = unheld value */
1029 cmpxchgl
%edx
, (%ecx
) /* try to grab write lock */
1032 #if defined(OPTERON_WORKAROUND_6323525)
1033 .rw_write_enter_lockstat_patch_point:
1034 .rw_write_enter_6323525_patch_point:
1038 .rw_write_enter_lockstat_6323525_patch_point:
1040 #else /* OPTERON_WORKAROUND_6323525 */
1041 .rw_write_enter_lockstat_patch_point:
1043 #endif /* OPTERON_WORKAROUND_6323525 */
1045 movl
%gs
:CPU_THREAD
, %edx
/* edx = thread ptr */
1046 movl $LS_RW_ENTER_ACQUIRE
, %eax
1048 jmp lockstat_wrapper_arg
1052 movl
4(%esp
), %ecx
/* ecx = lock ptr */
1053 movl
(%ecx
), %eax
/* eax = old rw_wwwh value */
1054 cmpl $RW_READ_LOCK
, %eax
/* single-reader, no waiters? */
1055 jne
.rw_not_single_reader
1056 xorl
%edx
, %edx
/* edx = new value (unheld) */
1059 cmpxchgl
%edx
, (%ecx
) /* try to drop read lock */
1061 movl
%gs
:CPU_THREAD
, %edx
/* edx = thread ptr */
1062 decl T_KPRI_REQ
(%edx
) /* THREAD_KPRI_RELEASE() */
1063 .rw_read_exit_lockstat_patch_point:
1065 movl $LS_RW_EXIT_RELEASE
, %eax
1067 jmp lockstat_wrapper_arg
1068 .rw_not_single_reader:
1069 testl $RW_WRITE_LOCKED
, %eax
/* write-locked or write-wanted? */
1071 leal
-RW_READ_LOCK
(%eax
), %edx
/* edx = new value */
1072 cmpl $RW_READ_LOCK
, %edx
1073 jge
.rw_read_exit /* not last reader, safe to drop */
1074 jmp rw_exit_wakeup
/* last reader with waiters */
1076 movl
%gs
:CPU_THREAD
, %eax
/* eax = thread ptr */
1077 xorl
%edx
, %edx
/* edx = new value (unheld) */
1078 orl $RW_WRITE_LOCKED
, %eax
/* eax = write-locked value */
1080 cmpxchgl
%edx
, (%ecx
) /* try to drop read lock */
1082 .rw_write_exit_lockstat_patch_point:
1084 movl
%gs
:CPU_THREAD
, %edx
/* edx = thread ptr */
1085 movl $LS_RW_EXIT_RELEASE
, %eax
1087 jmp lockstat_wrapper_arg
1090 #endif /* !__amd64 */
1094 #if defined(OPTERON_WORKAROUND_6323525)
1095 #if defined(lint) || defined(__lint)
1097 int workaround_6323525_patched;
1100 patch_workaround_6323525
(void
)
1106 * If it is necessary to patch the lock enter routines with the lfence
1107 * workaround, workaround_6323525_patched is set to a non-zero value so that
1108 * the lockstat_hat_patch routine can patch to the new location of the 'ret'
1111 DGDEF3
(workaround_6323525_patched
, 4, 4)
1114 #if defined(__amd64)
1116 #define HOT_MUTEX_PATCH(srcaddr, dstaddr, size) \
1118 movq $dstaddr
, %r13; \
1120 movq $srcaddr
, %r12; \
1125 movzbl
(%r12), %esi; \
1128 call hot_patch_kernel_text; \
1134 * patch_workaround_6323525: provide workaround for 6323525
1136 * The workaround is to place a fencing instruction (lfence) between the
1137 * mutex operation and the subsequent read-modify-write instruction.
1139 * This routine hot patches the lfence instruction on top of the space
1140 * reserved by nops in the lock enter routines.
1142 ENTRY_NP
(patch_workaround_6323525
)
1150 * lockstat_hot_patch() to use the alternate lockstat workaround
1151 * 6323525 patch points (points past the lfence instruction to the
1152 * new ret) when workaround_6323525_patched is set.
1154 movl $
1, workaround_6323525_patched
1157 * patch ret/nop/nop/nop to lfence/ret at the end of the lock enter
1158 * routines. The 4 bytes are patched in reverse order so that the
1159 * the existing ret is overwritten last. This provides lock enter
1160 * sanity during the intermediate patching stages.
1162 HOT_MUTEX_PATCH
(_lfence_insn
, .mutex_enter_6323525_patch_point, 4)
1163 HOT_MUTEX_PATCH
(_lfence_insn
, .mutex_tryenter_6323525_patch_point, 4)
1164 HOT_MUTEX_PATCH
(_lfence_insn
, .mutex_atryenter_6323525_patch_point, 4)
1165 HOT_MUTEX_PATCH
(_lfence_insn
, .rw_write_enter_6323525_patch_point, 4)
1176 SET_SIZE
(patch_workaround_6323525
)
1181 #define HOT_MUTEX_PATCH(srcaddr, dstaddr, size) \
1183 movl $srcaddr
, %esi; \
1185 movl $dstaddr
, %edi; \
1191 movzbl
(%esi
), %eax; \
1194 call hot_patch_kernel_text; \
1201 /* see comments above */
1202 ENTRY_NP
(patch_workaround_6323525
)
1209 movl $
1, workaround_6323525_patched
1211 HOT_MUTEX_PATCH
(_lfence_insn
, .mutex_enter_6323525_patch_point, 4)
1212 HOT_MUTEX_PATCH
(_lfence_insn
, .mutex_tryenter_6323525_patch_point, 4)
1213 HOT_MUTEX_PATCH
(_lfence_insn
, .mutex_atryenter_6323525_patch_point, 4)
1214 HOT_MUTEX_PATCH
(_lfence_insn
, .rw_write_enter_6323525_patch_point, 4)
1223 .byte 0xf, 0xae, 0xe8 / [lfence instruction]
1225 SET_SIZE
(patch_workaround_6323525
)
1227 #endif /* !__amd64 */
1229 #endif /* OPTERON_WORKAROUND_6323525 */
1232 #if defined(lint) || defined(__lint)
1235 lockstat_hot_patch
(void
)
1240 #if defined(__amd64)
1242 #define HOT_PATCH(addr, event, active_instr, normal_instr, len) \
1243 movq $normal_instr
, %rsi; \
1244 movq $active_instr
, %rdi; \
1245 leaq lockstat_probemap
(%rip
), %rax; \
1246 movl _MUL
(event
, DTRACE_IDSIZE
)(%rax
), %eax; \
1253 call hot_patch_kernel_text
1257 #define HOT_PATCH(addr, event, active_instr, normal_instr, len) \
1258 movl $normal_instr
, %ecx; \
1259 movl $active_instr
, %edx; \
1260 movl $lockstat_probemap
, %eax; \
1261 movl _MUL
(event
, DTRACE_IDSIZE
)(%eax
), %eax; \
1268 call hot_patch_kernel_text; \
1271 #endif /* !__amd64 */
1273 ENTRY
(lockstat_hot_patch
)
1274 #if defined(__amd64)
1275 pushq
%rbp
/* align stack properly */
1277 #endif /* __amd64 */
1279 #if defined(OPTERON_WORKAROUND_6323525)
1280 cmpl $
0, workaround_6323525_patched
1282 HOT_PATCH
(.mutex_enter_lockstat_6323525_patch_point,
1283 LS_MUTEX_ENTER_ACQUIRE
, NOP_INSTR
, RET_INSTR
, 1)
1284 HOT_PATCH
(.mutex_tryenter_lockstat_6323525_patch_point,
1285 LS_MUTEX_ENTER_ACQUIRE
, NOP_INSTR
, RET_INSTR
, 1)
1286 HOT_PATCH
(.rw_write_enter_lockstat_6323525_patch_point,
1287 LS_RW_ENTER_ACQUIRE
, NOP_INSTR
, RET_INSTR
, 1)
1290 HOT_PATCH
(.mutex_enter_lockstat_patch_point,
1291 LS_MUTEX_ENTER_ACQUIRE
, NOP_INSTR
, RET_INSTR
, 1)
1292 HOT_PATCH
(.mutex_tryenter_lockstat_patch_point,
1293 LS_MUTEX_ENTER_ACQUIRE
, NOP_INSTR
, RET_INSTR
, 1)
1294 HOT_PATCH
(.rw_write_enter_lockstat_patch_point,
1295 LS_RW_ENTER_ACQUIRE
, NOP_INSTR
, RET_INSTR
, 1)
1297 #else /* OPTERON_WORKAROUND_6323525 */
1298 HOT_PATCH
(.mutex_enter_lockstat_patch_point,
1299 LS_MUTEX_ENTER_ACQUIRE
, NOP_INSTR
, RET_INSTR
, 1)
1300 HOT_PATCH
(.mutex_tryenter_lockstat_patch_point,
1301 LS_MUTEX_ENTER_ACQUIRE
, NOP_INSTR
, RET_INSTR
, 1)
1302 HOT_PATCH
(.rw_write_enter_lockstat_patch_point,
1303 LS_RW_ENTER_ACQUIRE
, NOP_INSTR
, RET_INSTR
, 1)
1304 #endif /* !OPTERON_WORKAROUND_6323525 */
1305 HOT_PATCH
(.mutex_exit_lockstat_patch_point,
1306 LS_MUTEX_EXIT_RELEASE
, NOP_INSTR
, RET_INSTR
, 1)
1307 HOT_PATCH
(.rw_read_enter_lockstat_patch_point,
1308 LS_RW_ENTER_ACQUIRE
, NOP_INSTR
, RET_INSTR
, 1)
1309 HOT_PATCH
(.rw_write_exit_lockstat_patch_point,
1310 LS_RW_EXIT_RELEASE
, NOP_INSTR
, RET_INSTR
, 1)
1311 HOT_PATCH
(.rw_read_exit_lockstat_patch_point,
1312 LS_RW_EXIT_RELEASE
, NOP_INSTR
, RET_INSTR
, 1)
1313 HOT_PATCH
(.lock_set_lockstat_patch_point,
1314 LS_LOCK_SET_ACQUIRE
, NOP_INSTR
, RET_INSTR
, 1)
1315 HOT_PATCH
(.lock_try_lockstat_patch_point,
1316 LS_LOCK_TRY_ACQUIRE
, NOP_INSTR
, RET_INSTR
, 1)
1317 HOT_PATCH
(.lock_clear_lockstat_patch_point,
1318 LS_LOCK_CLEAR_RELEASE
, NOP_INSTR
, RET_INSTR
, 1)
1319 HOT_PATCH
(.lock_set_spl_lockstat_patch_point,
1320 LS_LOCK_SET_SPL_ACQUIRE
, NOP_INSTR
, RET_INSTR
, 1)
1322 HOT_PATCH
(LOCK_CLEAR_SPLX_LOCKSTAT_PATCH_POINT
,
1323 LS_LOCK_CLEAR_SPLX_RELEASE
,
1324 LOCK_CLEAR_SPLX_LOCKSTAT_PATCH_VAL
, 0, 1);
1325 #if defined(__amd64)
1326 leave
/* unwind stack */
1327 #endif /* __amd64 */
1329 SET_SIZE
(lockstat_hot_patch
)
1333 #if defined(lint) || defined(__lint)
1335 /* XX64 membar_*() should be inlines */
1350 membar_producer
(void
)
1354 membar_consumer
(void
)
1359 #if defined(__amd64)
1362 ALTENTRY
(membar_exit
)
1363 ALTENTRY
(membar_sync
)
1364 mfence
/* lighter weight than lock; xorq $0,(%rsp) */
1366 SET_SIZE
(membar_sync
)
1367 SET_SIZE
(membar_exit
)
1368 SET_SIZE
(membar_enter
)
1370 ENTRY
(membar_producer
)
1373 SET_SIZE
(membar_producer
)
1375 ENTRY
(membar_consumer
)
1378 SET_SIZE
(membar_consumer
)
1383 ALTENTRY
(membar_exit
)
1384 ALTENTRY
(membar_sync
)
1388 SET_SIZE
(membar_sync
)
1389 SET_SIZE
(membar_exit
)
1390 SET_SIZE
(membar_enter
)
1393 * On machines that support sfence and lfence, these
1394 * memory barriers can be more precisely implemented
1395 * without causing the whole world to stop
1397 ENTRY
(membar_producer
)
1398 .globl _patch_sfence_ret
1399 _patch_sfence_ret
: /* c.f. membar #StoreStore */
1403 SET_SIZE
(membar_producer
)
1405 ENTRY
(membar_consumer
)
1406 .globl _patch_lfence_ret
1407 _patch_lfence_ret
: /* c.f. membar #LoadLoad */
1411 SET_SIZE
(membar_consumer
)
1413 #endif /* !__amd64 */
1419 * Set thread in onproc state for the specified CPU.
1420 * Also set the thread lock pointer to the CPU's onproc lock.
1421 * Since the new lock isn't held, the store ordering is important.
1422 * If not done in assembler, the compiler could reorder the stores.
1424 #if defined(lint) || defined(__lint)
1427 thread_onproc
(kthread_id_t
t, cpu_t
*cp
)
1429 t-
>t_state
= TS_ONPROC;
1430 t-
>t_lockp
= &cp-
>cpu_thread_lock;
1435 #if defined(__amd64)
1437 ENTRY
(thread_onproc
)
1438 addq $CPU_THREAD_LOCK
, %rsi
/* pointer to disp_lock while running */
1439 movl $ONPROC_THREAD
, T_STATE
(%rdi
) /* set state to TS_ONPROC */
1440 movq
%rsi
, T_LOCKP
(%rdi
) /* store new lock pointer */
1442 SET_SIZE
(thread_onproc
)
1446 ENTRY
(thread_onproc
)
1449 addl $CPU_THREAD_LOCK
, %ecx
/* pointer to disp_lock while running */
1450 movl $ONPROC_THREAD
, T_STATE
(%eax
) /* set state to TS_ONPROC */
1451 movl
%ecx
, T_LOCKP
(%eax
) /* store new lock pointer */
1453 SET_SIZE
(thread_onproc
)
1455 #endif /* !__amd64 */
1460 * mutex_delay_default(void)
1461 * Spins for approx a few hundred processor cycles and returns to caller.
1464 #if defined(lint) || defined(__lint)
1467 mutex_delay_default
(void
)
1472 #if defined(__amd64)
1474 ENTRY
(mutex_delay_default
)
1479 SET_SIZE
(mutex_delay_default
)
1483 ENTRY
(mutex_delay_default
)
1494 SET_SIZE
(mutex_delay_default
)
1496 #endif /* !__amd64 */