lock_stubs.S revision 1.32
11.32Smaxv/*	$NetBSD: lock_stubs.S,v 1.32 2019/09/05 12:57:30 maxv Exp $	*/
21.2Sad
31.32Smaxv/*
41.22Sad * Copyright (c) 2006, 2007, 2008, 2009 The NetBSD Foundation, Inc.
51.2Sad * All rights reserved.
61.2Sad *
71.2Sad * This code is derived from software contributed to The NetBSD Foundation
81.2Sad * by Andrew Doran.
91.2Sad *
101.2Sad * Redistribution and use in source and binary forms, with or without
111.2Sad * modification, are permitted provided that the following conditions
121.2Sad * are met:
131.2Sad * 1. Redistributions of source code must retain the above copyright
141.2Sad *    notice, this list of conditions and the following disclaimer.
151.2Sad * 2. Redistributions in binary form must reproduce the above copyright
161.2Sad *    notice, this list of conditions and the following disclaimer in the
171.2Sad *    documentation and/or other materials provided with the distribution.
181.32Smaxv *
191.2Sad * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
201.2Sad * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
211.2Sad * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
221.2Sad * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
231.2Sad * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
241.2Sad * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
251.2Sad * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
261.2Sad * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
271.2Sad * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
281.2Sad * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
291.2Sad * POSSIBILITY OF SUCH DAMAGE.
301.2Sad */
311.2Sad
321.2Sad#include "opt_multiprocessor.h"
331.2Sad#include "opt_lockdebug.h"
341.2Sad
351.2Sad#include <machine/asm.h>
361.8Sbouyer#include <machine/frameasm.h>
371.2Sad
381.2Sad#include "assym.h"
391.2Sad
401.32Smaxv#define LOCK	\
411.27Smaxv	HOTPATCH(HP_NAME_NOLOCK, 1)	; \
421.27Smaxv	lock
431.32Smaxv#define RET	\
441.28Smaxv	HOTPATCH(HP_NAME_RETFENCE, 3)	; \
451.28Smaxv	ret; nop; nop			; \
461.28Smaxv	ret
471.2Sad
481.2Sad#ifndef LOCKDEBUG
491.2Sad
501.32Smaxv	.align	64
511.32Smaxv
521.2Sad/*
531.2Sad * void mutex_enter(kmutex_t *mtx);
541.2Sad *
551.2Sad * Acquire a mutex and post a load fence.
561.2Sad */
571.19SchsENTRY(mutex_enter)
581.2Sad	movq	CPUVAR(CURLWP), %rcx
591.2Sad	xorq	%rax, %rax
601.32Smaxv	LOCK
611.21Sad	cmpxchgq %rcx, (%rdi)
621.14Sad	jnz	1f
631.32Smaxv	RET
641.14Sad1:
651.14Sad	jmp	_C_LABEL(mutex_vector_enter)
661.25SuebayasiEND(mutex_enter)
671.2Sad
681.2Sad/*
691.2Sad * void mutex_exit(kmutex_t *mtx);
701.2Sad *
711.2Sad * Release a mutex and post a load fence.
721.2Sad *
731.2Sad * See comments in mutex_vector_enter() about doing this operation unlocked
741.2Sad * on multiprocessor systems, and comments in arch/x86/include/lock.h about
751.2Sad * memory ordering on Intel x86 systems.
761.2Sad */
771.19SchsENTRY(mutex_exit)
781.2Sad	movq	CPUVAR(CURLWP), %rax
791.2Sad	xorq	%rdx, %rdx
801.21Sad	cmpxchgq %rdx, (%rdi)
811.14Sad	jnz	1f
821.2Sad	ret
831.14Sad1:
841.14Sad	jmp	_C_LABEL(mutex_vector_exit)
851.25SuebayasiEND(mutex_exit)
861.2Sad
871.2Sad/*
881.2Sad * void mutex_spin_enter(kmutex_t *mtx);
891.2Sad *
901.2Sad * Acquire a spin mutex and post a load fence.
911.2Sad */
921.19SchsENTRY(mutex_spin_enter)
931.20Sad	movl	$1, %eax
941.14Sad	movl	CPUVAR(ILEVEL), %esi
951.2Sad	movzbl	MTX_IPL(%rdi), %ecx		/* new SPL */
961.2Sad	cmpl	%ecx, %esi			/* higher? */
971.2Sad	cmovgl	%esi, %ecx
981.14Sad	movl	%ecx, CPUVAR(ILEVEL)		/* splraiseipl() */
991.20Sad	subl	%eax, CPUVAR(MTX_COUNT)		/* decl doesnt set CF */
1001.14Sad	cmovncl	CPUVAR(MTX_OLDSPL), %esi
1011.14Sad	movl	%esi, CPUVAR(MTX_OLDSPL)
1021.20Sad	xchgb	%al, MTX_LOCK(%rdi)		/* lock */
1031.21Sad#ifdef MULTIPROCESSOR	/* XXX for xen */
1041.20Sad	testb	%al, %al
1051.14Sad	jnz	1f
1061.2Sad#endif
1071.32Smaxv	RET
1081.14Sad1:
1091.14Sad	jmp	_C_LABEL(mutex_spin_retry)	/* failed; hard case */
1101.25SuebayasiEND(mutex_spin_enter)
1111.2Sad
1121.2Sad/*
1131.2Sad * void mutex_spin_exit(kmutex_t *mtx);
1141.2Sad *
1151.2Sad * Release a spin mutex and post a load fence.
1161.2Sad */
1171.19SchsENTRY(mutex_spin_exit)
1181.2Sad#ifdef DIAGNOSTIC
1191.2Sad
1201.2Sad	movl	$0x0001, %eax			/* new + expected value */
1211.4Sad	movq	CPUVAR(SELF), %r8
1221.2Sad	cmpxchgb %ah, MTX_LOCK(%rdi)		/* unlock */
1231.21Sad	jnz	_C_LABEL(mutex_vector_exit)	/* hard case if problems */
1241.4Sad	movl	CPU_INFO_MTX_OLDSPL(%r8), %edi
1251.4Sad	incl	CPU_INFO_MTX_COUNT(%r8)
1261.2Sad	jnz	1f
1271.4Sad	cmpl	CPU_INFO_ILEVEL(%r8), %edi
1281.2Sad	jae	1f
1291.31Scherry#if !defined(XENPV)
1301.4Sad	movl	CPU_INFO_IUNMASK(%r8,%rdi,4), %esi
1311.12Sdsl	CLI(ax)
1321.4Sad	testl	CPU_INFO_IPENDING(%r8), %esi
1331.2Sad	jnz	_C_LABEL(Xspllower)
1341.30Scherry#endif
1351.30Scherry#if defined(XEN)
1361.30Scherry	movl	CPU_INFO_XUNMASK(%r8,%rdi,4), %esi
1371.30Scherry	CLI(ax)
1381.30Scherry	testl	CPU_INFO_XPENDING(%r8), %esi
1391.30Scherry	jnz	_C_LABEL(Xspllower)
1401.30Scherry#endif
1411.4Sad	movl	%edi, CPU_INFO_ILEVEL(%r8)
1421.12Sdsl	STI(ax)
1431.2Sad1:	rep					/* double byte ret as branch */
1441.2Sad	ret					/* target: see AMD docs */
1451.2Sad
1461.2Sad#else	/* DIAGNOSTIC */
1471.2Sad
1481.4Sad	movq	CPUVAR(SELF), %rsi
1491.2Sad	movb	$0x00, MTX_LOCK(%rdi)
1501.4Sad	movl	CPU_INFO_MTX_OLDSPL(%rsi), %ecx
1511.4Sad	incl	CPU_INFO_MTX_COUNT(%rsi)
1521.4Sad	movl	CPU_INFO_ILEVEL(%rsi),%edx
1531.2Sad	cmovnzl	%edx,%ecx
1541.21Sad	pushq	%rbx
1551.2Sad	cmpl	%edx,%ecx			/* new level is lower? */
1561.21Sad	jae	2f
1571.2Sad1:
1581.31Scherry#if !defined(XENPV)
1591.4Sad	movl	CPU_INFO_IPENDING(%rsi),%eax
1601.4Sad	testl	%eax,CPU_INFO_IUNMASK(%rsi,%rcx,4)/* deferred interrupts? */
1611.21Sad	jnz	3f
1621.2Sad	movl	%eax,%ebx
1631.4Sad	cmpxchg8b CPU_INFO_ISTATE(%rsi)		/* swap in new ilevel */
1641.21Sad	jnz	4f
1651.30Scherry#endif
1661.30Scherry#if defined(XEN)
1671.30Scherry	movl	CPU_INFO_XPENDING(%rsi),%eax
1681.30Scherry	testl	%eax,CPU_INFO_XUNMASK(%rsi,%rcx,4)/* deferred interrupts? */
1691.30Scherry	jnz	3f
1701.30Scherry	movl	%edx, %eax
1711.30Scherry	cmpxchgl %ecx, CPU_INFO_ILEVEL(%rsi)
1721.30Scherry	jnz	4f
1731.30Scherry#endif
1741.2Sad2:
1751.2Sad	popq	%rbx
1761.2Sad	ret
1771.2Sad3:
1781.2Sad	popq	%rbx
1791.2Sad	movl	%ecx, %edi
1801.2Sad	jmp	_C_LABEL(Xspllower)
1811.21Sad4:
1821.21Sad	jmp	1b
1831.2Sad
1841.2Sad#endif	/* DIAGNOSTIC */
1851.2Sad
1861.25SuebayasiEND(mutex_spin_exit)
1871.25Suebayasi
1881.2Sad/*
1891.2Sad * void	rw_enter(krwlock_t *rwl, krw_t op);
1901.2Sad *
1911.2Sad * Acquire one hold on a RW lock.
1921.2Sad */
1931.19SchsENTRY(rw_enter)
1941.2Sad	cmpl	$RW_READER, %esi
1951.2Sad	jne	2f
1961.2Sad
1971.2Sad	/*
1981.2Sad	 * Reader: this is the most common case.
1991.2Sad	 */
2001.21Sad	movq	(%rdi), %rax
2011.21Sad0:
2021.2Sad	testb	$(RW_WRITE_LOCKED|RW_WRITE_WANTED), %al
2031.21Sad	jnz	3f
2041.32Smaxv	leaq	RW_READ_INCR(%rax), %rdx
2051.32Smaxv	LOCK
2061.21Sad	cmpxchgq %rdx, (%rdi)
2071.21Sad	jnz	1f
2081.32Smaxv	RET
2091.21Sad1:
2101.21Sad	jmp	0b
2111.2Sad
2121.2Sad	/*
2131.2Sad	 * Writer: if the compare-and-set fails, don't bother retrying.
2141.2Sad	 */
2151.2Sad2:	movq	CPUVAR(CURLWP), %rcx
2161.2Sad	xorq	%rax, %rax
2171.2Sad	orq	$RW_WRITE_LOCKED, %rcx
2181.32Smaxv	LOCK
2191.21Sad	cmpxchgq %rcx, (%rdi)
2201.14Sad	jnz	3f
2211.32Smaxv	RET
2221.14Sad3:
2231.14Sad	jmp	_C_LABEL(rw_vector_enter)
2241.25SuebayasiEND(rw_enter)
2251.2Sad
2261.2Sad/*
2271.2Sad * void	rw_exit(krwlock_t *rwl);
2281.2Sad *
2291.2Sad * Release one hold on a RW lock.
2301.2Sad */
2311.19SchsENTRY(rw_exit)
2321.21Sad	movq	(%rdi), %rax
2331.2Sad	testb	$RW_WRITE_LOCKED, %al
2341.2Sad	jnz	2f
2351.2Sad
2361.2Sad	/*
2371.2Sad	 * Reader
2381.2Sad	 */
2391.21Sad0:	testb	$RW_HAS_WAITERS, %al
2401.14Sad	jnz	3f
2411.2Sad	cmpq	$RW_READ_INCR, %rax
2421.21Sad	jb	3f
2431.2Sad	leaq	-RW_READ_INCR(%rax), %rdx
2441.32Smaxv	LOCK
2451.21Sad	cmpxchgq %rdx, (%rdi)
2461.21Sad	jnz	1f
2471.2Sad	ret
2481.21Sad1:
2491.21Sad	jmp	0b
2501.2Sad
2511.2Sad	/*
2521.2Sad	 * Writer
2531.2Sad	 */
2541.2Sad2:	leaq	-RW_WRITE_LOCKED(%rax), %rdx
2551.2Sad	subq	CPUVAR(CURLWP), %rdx
2561.14Sad	jnz	3f
2571.32Smaxv	LOCK
2581.21Sad	cmpxchgq %rdx, (%rdi)
2591.2Sad	jnz	3f
2601.2Sad	ret
2611.2Sad
2621.2Sad3:	jmp	_C_LABEL(rw_vector_exit)
2631.25SuebayasiEND(rw_exit)
2641.2Sad
2651.13Sad/*
2661.13Sad * int	rw_tryenter(krwlock_t *rwl, krw_t op);
2671.13Sad *
2681.13Sad * Try to acquire one hold on a RW lock.
2691.13Sad */
2701.19SchsENTRY(rw_tryenter)
2711.13Sad	cmpl	$RW_READER, %esi
2721.13Sad	jne	2f
2731.13Sad
2741.13Sad	/*
2751.13Sad	 * Reader: this is the most common case.
2761.13Sad	 */
2771.21Sad	movq	(%rdi), %rax
2781.21Sad0:
2791.13Sad	testb	$(RW_WRITE_LOCKED|RW_WRITE_WANTED), %al
2801.22Sad	jnz	4f
2811.32Smaxv	leaq	RW_READ_INCR(%rax), %rdx
2821.32Smaxv	LOCK
2831.21Sad	cmpxchgq %rdx, (%rdi)
2841.21Sad	jnz	1f
2851.21Sad	movl	%edx, %eax			/* nonzero */
2861.32Smaxv	RET
2871.21Sad1:
2881.21Sad	jmp	0b
2891.13Sad
2901.13Sad	/*
2911.13Sad	 * Writer: if the compare-and-set fails, don't bother retrying.
2921.13Sad	 */
2931.13Sad2:	movq	CPUVAR(CURLWP), %rcx
2941.13Sad	xorq	%rax, %rax
2951.13Sad	orq	$RW_WRITE_LOCKED, %rcx
2961.32Smaxv	LOCK
2971.21Sad	cmpxchgq %rcx, (%rdi)
2981.18Sad	movl	$0, %eax
2991.13Sad	setz	%al
3001.22Sad3:
3011.32Smaxv	RET
3021.13Sad	ret
3031.22Sad4:
3041.22Sad	xorl	%eax, %eax
3051.22Sad	jmp	3b
3061.25SuebayasiEND(rw_tryenter)
3071.13Sad
3081.2Sad#endif	/* LOCKDEBUG */
3091.2Sad
3101.2Sad/*
3111.11Sad * Spinlocks.
3121.2Sad */
3131.19SchsENTRY(__cpu_simple_lock_init)
3141.11Sad	movb	$0, (%rdi)
3151.2Sad	ret
3161.25SuebayasiEND(__cpu_simple_lock_init)
3171.2Sad
3181.29SmaxvENTRY(__cpu_simple_lock)
3191.11Sad	movl	$0x0100, %eax
3201.11Sad1:
3211.32Smaxv	LOCK
3221.11Sad	cmpxchgb %ah, (%rdi)
3231.11Sad	jnz	2f
3241.32Smaxv	RET
3251.11Sad2:
3261.11Sad	movl	$0x0100, %eax
3271.11Sad	pause
3281.11Sad	nop
3291.7Sad	nop
3301.11Sad	cmpb	$0, (%rdi)
3311.11Sad	je	1b
3321.11Sad	jmp	2b
3331.25SuebayasiEND(__cpu_simple_lock)
3341.11Sad
3351.29SmaxvENTRY(__cpu_simple_unlock)
3361.11Sad	movb	$0, (%rdi)
3371.2Sad	ret
3381.25SuebayasiEND(__cpu_simple_unlock)
3391.7Sad
3401.19SchsENTRY(__cpu_simple_lock_try)
3411.11Sad	movl	$0x0100, %eax
3421.32Smaxv	LOCK
3431.11Sad	cmpxchgb %ah, (%rdi)
3441.11Sad	movl	$0, %eax
3451.22Sad	setz	%al
3461.32Smaxv	RET
3471.25SuebayasiEND(__cpu_simple_lock_try)
3481.2Sad
349