lock_stubs.S revision 1.13
11.13Sad/*	$NetBSD: lock_stubs.S,v 1.13 2008/01/25 19:02:32 ad Exp $	*/
21.2Sad
31.2Sad/*-
41.13Sad * Copyright (c) 2006, 2007, 2008 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.2Sad * 3. All advertising materials mentioning features or use of this software
191.2Sad *    must display the following acknowledgement:
201.2Sad *	This product includes software developed by the NetBSD
211.2Sad *	Foundation, Inc. and its contributors.
221.2Sad * 4. Neither the name of The NetBSD Foundation nor the names of its
231.2Sad *    contributors may be used to endorse or promote products derived
241.2Sad *    from this software without specific prior written permission.
251.2Sad *
261.2Sad * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
271.2Sad * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
281.2Sad * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
291.2Sad * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
301.2Sad * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
311.2Sad * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
321.2Sad * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
331.2Sad * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
341.2Sad * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
351.2Sad * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
361.2Sad * POSSIBILITY OF SUCH DAMAGE.
371.2Sad */
381.2Sad
391.2Sad/*
401.2Sad * AMD64 lock stubs.  Calling convention:
411.2Sad *
421.2Sad * %rdi		arg 1
431.2Sad * %rsi		arg 2
441.2Sad * %rdx		arg 3
451.2Sad * %rax		return value
461.2Sad */
471.2Sad
481.2Sad#include "opt_multiprocessor.h"
491.2Sad#include "opt_lockdebug.h"
501.2Sad
511.2Sad#include <machine/asm.h>
521.8Sbouyer#include <machine/frameasm.h>
531.2Sad
541.2Sad#include "assym.h"
551.2Sad
561.2Sad#if defined(DIAGNOSTIC) || defined(MULTIPROCESSOR) || defined(LOCKDEBUG)
571.2Sad#define	FULL
581.2Sad#endif
591.2Sad
601.7Sad#define	END(name,a)	.align	a; LABEL(name)
611.11Sad#define	LOCK(num)	.Lpatch/**/num: lock
621.2Sad
631.2Sad#ifndef LOCKDEBUG
641.2Sad
651.2Sad/*
661.2Sad * void mutex_enter(kmutex_t *mtx);
671.2Sad *
681.2Sad * Acquire a mutex and post a load fence.
691.2Sad */
701.2Sad	.align	64
711.2Sad
721.11SadNENTRY(mutex_enter)
731.2Sad	movq	CPUVAR(CURLWP), %rcx
741.2Sad	xorq	%rax, %rax
751.11Sad	LOCK(1)
761.2Sad	cmpxchgq %rcx, MTX_OWNER(%rdi)
771.2Sad	jnz,pn	_C_LABEL(mutex_vector_enter)
781.2Sad	ret
791.2Sad
801.2Sad/*
811.2Sad * void mutex_exit(kmutex_t *mtx);
821.2Sad *
831.2Sad * Release a mutex and post a load fence.
841.2Sad *
851.2Sad * See comments in mutex_vector_enter() about doing this operation unlocked
861.2Sad * on multiprocessor systems, and comments in arch/x86/include/lock.h about
871.2Sad * memory ordering on Intel x86 systems.
881.2Sad */
891.11SadNENTRY(mutex_exit)
901.2Sad	movq	CPUVAR(CURLWP), %rax
911.2Sad	xorq	%rdx, %rdx
921.2Sad	cmpxchgq %rdx, MTX_OWNER(%rdi)
931.2Sad	jnz,pn	_C_LABEL(mutex_vector_exit)
941.2Sad	ret
951.2Sad
961.2Sad/*
971.2Sad * void mutex_spin_enter(kmutex_t *mtx);
981.2Sad *
991.2Sad * Acquire a spin mutex and post a load fence.
1001.2Sad */
1011.4SadNENTRY(mutex_spin_enter)
1021.4Sad	movq	CPUVAR(SELF), %r8
1031.2Sad#if defined(FULL)
1041.2Sad	movl	$0x0100, %eax			/* new + expected value */
1051.2Sad#endif
1061.4Sad	movl	CPU_INFO_ILEVEL(%r8), %esi
1071.4Sad	subl	$1, CPU_INFO_MTX_COUNT(%r8)	/* decl doesnt set CF */
1081.2Sad	movzbl	MTX_IPL(%rdi), %ecx		/* new SPL */
1091.4Sad	cmovncl	CPU_INFO_MTX_OLDSPL(%r8), %esi
1101.2Sad	cmpl	%ecx, %esi			/* higher? */
1111.4Sad	movl	%esi, CPU_INFO_MTX_OLDSPL(%r8)
1121.2Sad	cmovgl	%esi, %ecx
1131.4Sad	movl	%ecx, CPU_INFO_ILEVEL(%r8)	/* splraiseipl() */
1141.2Sad#if defined(FULL)
1151.11Sad	LOCK(11)
1161.2Sad	cmpxchgb %ah, MTX_LOCK(%rdi)		/* lock */
1171.2Sad	jnz,pn	_C_LABEL(mutex_spin_retry)	/* failed; hard case */
1181.2Sad#endif
1191.2Sad	ret
1201.2Sad
1211.2Sad/*
1221.2Sad * void mutex_spin_exit(kmutex_t *mtx);
1231.2Sad *
1241.2Sad * Release a spin mutex and post a load fence.
1251.2Sad */
1261.4SadNENTRY(mutex_spin_exit)
1271.2Sad#ifdef DIAGNOSTIC
1281.2Sad
1291.2Sad	movl	$0x0001, %eax			/* new + expected value */
1301.4Sad	movq	CPUVAR(SELF), %r8
1311.2Sad	cmpxchgb %ah, MTX_LOCK(%rdi)		/* unlock */
1321.2Sad	jnz,pn	_C_LABEL(mutex_vector_exit)	/* hard case if problems */
1331.4Sad	movl	CPU_INFO_MTX_OLDSPL(%r8), %edi
1341.4Sad	incl	CPU_INFO_MTX_COUNT(%r8)
1351.2Sad	jnz	1f
1361.4Sad	cmpl	CPU_INFO_ILEVEL(%r8), %edi
1371.2Sad	jae	1f
1381.4Sad	movl	CPU_INFO_IUNMASK(%r8,%rdi,4), %esi
1391.12Sdsl	CLI(ax)
1401.4Sad	testl	CPU_INFO_IPENDING(%r8), %esi
1411.2Sad	jnz	_C_LABEL(Xspllower)
1421.4Sad	movl	%edi, CPU_INFO_ILEVEL(%r8)
1431.12Sdsl	STI(ax)
1441.2Sad1:	rep					/* double byte ret as branch */
1451.2Sad	ret					/* target: see AMD docs */
1461.2Sad
1471.2Sad#else	/* DIAGNOSTIC */
1481.2Sad
1491.4Sad	movq	CPUVAR(SELF), %rsi
1501.2Sad#ifdef MULTIPROCESSOR
1511.2Sad	movb	$0x00, MTX_LOCK(%rdi)
1521.2Sad#endif
1531.4Sad	movl	CPU_INFO_MTX_OLDSPL(%rsi), %ecx
1541.4Sad	incl	CPU_INFO_MTX_COUNT(%rsi)
1551.4Sad	movl	CPU_INFO_ILEVEL(%rsi),%edx
1561.2Sad	cmovnzl	%edx,%ecx
1571.2Sad	cmpl	%edx,%ecx			/* new level is lower? */
1581.2Sad	pushq	%rbx
1591.2Sad	jae,pn	2f
1601.2Sad1:
1611.4Sad	movl	CPU_INFO_IPENDING(%rsi),%eax
1621.4Sad	testl	%eax,CPU_INFO_IUNMASK(%rsi,%rcx,4)/* deferred interrupts? */
1631.2Sad	movl	%eax,%ebx
1641.2Sad	jnz,pn	3f
1651.4Sad	cmpxchg8b CPU_INFO_ISTATE(%rsi)		/* swap in new ilevel */
1661.3Syamt	jnz,pn	1b
1671.2Sad2:
1681.2Sad	popq	%rbx
1691.2Sad	ret
1701.2Sad3:
1711.2Sad	popq	%rbx
1721.2Sad	movl	%ecx, %edi
1731.2Sad	jmp	_C_LABEL(Xspllower)
1741.2Sad
1751.2Sad#endif	/* DIAGNOSTIC */
1761.2Sad
1771.2Sad/*
1781.2Sad * void	rw_enter(krwlock_t *rwl, krw_t op);
1791.2Sad *
1801.2Sad * Acquire one hold on a RW lock.
1811.2Sad */
1821.11SadNENTRY(rw_enter)
1831.2Sad	cmpl	$RW_READER, %esi
1841.2Sad	jne	2f
1851.2Sad
1861.2Sad	/*
1871.2Sad	 * Reader: this is the most common case.
1881.2Sad	 */
1891.2Sad1:	movq	RW_OWNER(%rdi), %rax
1901.2Sad	testb	$(RW_WRITE_LOCKED|RW_WRITE_WANTED), %al
1911.2Sad	leaq	RW_READ_INCR(%rax), %rdx
1921.2Sad	jnz,pn	_C_LABEL(rw_vector_enter)
1931.11Sad	LOCK(2)
1941.2Sad	cmpxchgq %rdx, RW_OWNER(%rdi)
1951.2Sad	jnz,pn	1b
1961.2Sad	ret
1971.2Sad
1981.2Sad	/*
1991.2Sad	 * Writer: if the compare-and-set fails, don't bother retrying.
2001.2Sad	 */
2011.2Sad2:	movq	CPUVAR(CURLWP), %rcx
2021.2Sad	xorq	%rax, %rax
2031.2Sad	orq	$RW_WRITE_LOCKED, %rcx
2041.11Sad	LOCK(3)
2051.2Sad	cmpxchgq %rcx, RW_OWNER(%rdi)
2061.2Sad	jnz,pn	_C_LABEL(rw_vector_enter)
2071.2Sad	ret
2081.2Sad
2091.2Sad/*
2101.2Sad * void	rw_exit(krwlock_t *rwl);
2111.2Sad *
2121.2Sad * Release one hold on a RW lock.
2131.2Sad */
2141.11SadNENTRY(rw_exit)
2151.2Sad	movq	RW_OWNER(%rdi), %rax
2161.2Sad	testb	$RW_WRITE_LOCKED, %al
2171.2Sad	jnz	2f
2181.2Sad
2191.2Sad	/*
2201.2Sad	 * Reader
2211.2Sad	 */
2221.2Sad1:	testb	$RW_HAS_WAITERS, %al
2231.2Sad	jnz,pn	3f
2241.2Sad	cmpq	$RW_READ_INCR, %rax
2251.2Sad	leaq	-RW_READ_INCR(%rax), %rdx
2261.2Sad	jb,pn	3f
2271.11Sad	LOCK(4)
2281.2Sad	cmpxchgq %rdx, RW_OWNER(%rdi)
2291.2Sad	jnz,pn	1b
2301.2Sad	ret
2311.2Sad
2321.2Sad	/*
2331.2Sad	 * Writer
2341.2Sad	 */
2351.2Sad2:	leaq	-RW_WRITE_LOCKED(%rax), %rdx
2361.2Sad	subq	CPUVAR(CURLWP), %rdx
2371.2Sad	jnz,pn	3f
2381.11Sad	LOCK(5)
2391.2Sad	cmpxchgq %rdx, RW_OWNER(%rdi)
2401.2Sad	jnz	3f
2411.2Sad	ret
2421.2Sad
2431.2Sad3:	jmp	_C_LABEL(rw_vector_exit)
2441.2Sad
2451.13Sad/*
2461.13Sad * int	rw_tryenter(krwlock_t *rwl, krw_t op);
2471.13Sad *
2481.13Sad * Try to acquire one hold on a RW lock.
2491.13Sad */
2501.13SadNENTRY(rw_tryenter)
2511.13Sad	cmpl	$RW_READER, %esi
2521.13Sad	jne	2f
2531.13Sad
2541.13Sad	/*
2551.13Sad	 * Reader: this is the most common case.
2561.13Sad	 */
2571.13Sad1:	movq	RW_OWNER(%rdi), %rax
2581.13Sad	testb	$(RW_WRITE_LOCKED|RW_WRITE_WANTED), %al
2591.13Sad	leaq	RW_READ_INCR(%rax), %rdx
2601.13Sad	jnz	3f
2611.13Sad	LOCK(8)
2621.13Sad	cmpxchgq %rdx, RW_OWNER(%rdi)
2631.13Sad	movl	$0, %eax
2641.13Sad	setz	%al
2651.13Sad	ret
2661.13Sad
2671.13Sad	/*
2681.13Sad	 * Writer: if the compare-and-set fails, don't bother retrying.
2691.13Sad	 */
2701.13Sad2:	movq	CPUVAR(CURLWP), %rcx
2711.13Sad	xorq	%rax, %rax
2721.13Sad	orq	$RW_WRITE_LOCKED, %rcx
2731.13Sad	LOCK(9)
2741.13Sad	cmpxchgq %rcx, RW_OWNER(%rdi)
2751.13Sad	movl	$0, %eax
2761.13Sad	setz	%al
2771.13Sad	ret
2781.13Sad
2791.13Sad3:	xorl	%eax, %eax
2801.13Sad	ret
2811.13Sad
2821.2Sad#endif	/* LOCKDEBUG */
2831.2Sad
2841.2Sad/*
2851.11Sad * Spinlocks.
2861.2Sad */
2871.11SadNENTRY(__cpu_simple_lock_init)
2881.11Sad	movb	$0, (%rdi)
2891.2Sad	ret
2901.2Sad
2911.11SadNENTRY(__cpu_simple_lock)
2921.11Sad	movl	$0x0100, %eax
2931.11Sad1:
2941.11Sad	LOCK(6)
2951.11Sad	cmpxchgb %ah, (%rdi)
2961.11Sad	jnz	2f
2971.2Sad	ret
2981.11Sad2:
2991.11Sad	movl	$0x0100, %eax
3001.11Sad	pause
3011.11Sad	nop
3021.7Sad	nop
3031.11Sad	cmpb	$0, (%rdi)
3041.11Sad	je	1b
3051.11Sad	jmp	2b
3061.11Sad
3071.11SadNENTRY(__cpu_simple_unlock)
3081.11Sad	movb	$0, (%rdi)
3091.2Sad	ret
3101.7Sad
3111.11SadNENTRY(__cpu_simple_lock_try)
3121.11Sad	movl	$0x0100, %eax
3131.11Sad	LOCK(7)
3141.11Sad	cmpxchgb %ah, (%rdi)
3151.11Sad	movl	$0, %eax
3161.11Sad	setz	%al
3171.2Sad	ret
3181.2Sad
3191.2Sad/*
3201.7Sad * Patchpoints to replace with NOP when ncpu == 1.
3211.7Sad */
3221.7Sad#ifndef LOCKDEBUG
3231.7SadLABEL(x86_lockpatch)
3241.11Sad	.quad	.Lpatch1, .Lpatch2, .Lpatch3, .Lpatch4
3251.13Sad	.quad	.Lpatch5, .Lpatch6, .Lpatch7, .Lpatch8
3261.13Sad	.quad	.Lpatch9
3271.7Sad#ifdef FULL
3281.11Sad	.quad	.Lpatch11
3291.7Sad#endif
3301.7Sad	.quad	0
3311.7Sad#endif
332