lock_stubs.S revision 1.2
11.2Sad/*	$NetBSD: lock_stubs.S,v 1.2 2007/02/09 21:55:01 ad Exp $	*/
21.2Sad
31.2Sad/*-
41.2Sad * Copyright (c) 2006, 2007 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.2Sad#include <machine/intrdefs.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.2Sad#if defined(MULTIPROCESSOR)
611.2Sad#define	LOCK		lock
621.2Sad#else
631.2Sad#define	LOCK		/* nothing */
641.2Sad#endif
651.2Sad
661.2Sad#define	END(name,a)	.align	a; LABEL(name)
671.2Sad
681.2Sad#ifndef LOCKDEBUG
691.2Sad
701.2Sad/*
711.2Sad * void mutex_enter(kmutex_t *mtx);
721.2Sad *
731.2Sad * Acquire a mutex and post a load fence.
741.2Sad */
751.2Sad	.align	64
761.2Sad
771.2SadNENTRY(mutex_enter)				/* 0x0000, 25 bytes */
781.2Sad	movq	CPUVAR(CURLWP), %rcx
791.2Sad	xorq	%rax, %rax
801.2Sad	LOCK
811.2Sad	cmpxchgq %rcx, MTX_OWNER(%rdi)
821.2Sad	jnz,pn	_C_LABEL(mutex_vector_enter)
831.2Sad	ret
841.2Sad
851.2Sad/*
861.2Sad * void mutex_exit(kmutex_t *mtx);
871.2Sad *
881.2Sad * Release a mutex and post a load fence.
891.2Sad *
901.2Sad * See comments in mutex_vector_enter() about doing this operation unlocked
911.2Sad * on multiprocessor systems, and comments in arch/x86/include/lock.h about
921.2Sad * memory ordering on Intel x86 systems.
931.2Sad */
941.2Sad	.align	32
951.2Sad
961.2SadNENTRY(mutex_exit)				/* 0x0020, 24 bytes */
971.2Sad	movq	CPUVAR(CURLWP), %rax
981.2Sad	xorq	%rdx, %rdx
991.2Sad	cmpxchgq %rdx, MTX_OWNER(%rdi)
1001.2Sad	jnz,pn	_C_LABEL(mutex_vector_exit)
1011.2Sad	ret
1021.2Sad
1031.2Sad/*
1041.2Sad * void mutex_spin_enter(kmutex_t *mtx);
1051.2Sad *
1061.2Sad * Acquire a spin mutex and post a load fence.
1071.2Sad */
1081.2Sad	.align	64
1091.2Sad
1101.2SadNENTRY(mutex_spin_enter)			/* 0x0040, 58 bytes */
1111.2Sad	movq	CPUVAR(SELF200), %r8
1121.2Sad#if defined(FULL)
1131.2Sad	movl	$0x0100, %eax			/* new + expected value */
1141.2Sad#endif
1151.2Sad	movl	(CPU_INFO_ILEVEL-0x200)(%r8), %esi
1161.2Sad	subl	$1, (CPU_INFO_MTX_COUNT-0x200)(%r8)/* decl doesnt set CF */
1171.2Sad	movzbl	MTX_IPL(%rdi), %ecx		/* new SPL */
1181.2Sad	cmovncl	(CPU_INFO_MTX_OLDSPL-0x200)(%r8), %esi
1191.2Sad	cmpl	%ecx, %esi			/* higher? */
1201.2Sad	movl	%esi, (CPU_INFO_MTX_OLDSPL-0x200)(%r8)
1211.2Sad	cmovgl	%esi, %ecx
1221.2Sad	movl	%ecx, (CPU_INFO_ILEVEL-0x200)(%r8) /* splraiseipl() */
1231.2Sad#if defined(FULL)
1241.2Sad	LOCK
1251.2Sad	cmpxchgb %ah, MTX_LOCK(%rdi)		/* lock */
1261.2Sad	jnz,pn	_C_LABEL(mutex_spin_retry)	/* failed; hard case */
1271.2Sad#endif
1281.2Sad	ret
1291.2Sad
1301.2Sad/*
1311.2Sad * void mutex_spin_exit(kmutex_t *mtx);
1321.2Sad *
1331.2Sad * Release a spin mutex and post a load fence.
1341.2Sad */
1351.2Sad	.align	64
1361.2Sad
1371.2SadNENTRY(mutex_spin_exit)				/* 0x0080, 60 bytes */
1381.2Sad#ifdef DIAGNOSTIC
1391.2Sad
1401.2Sad	movl	$0x0001, %eax			/* new + expected value */
1411.2Sad	movq	CPUVAR(SELF200), %r8
1421.2Sad	cmpxchgb %ah, MTX_LOCK(%rdi)		/* unlock */
1431.2Sad	jnz,pn	_C_LABEL(mutex_vector_exit)	/* hard case if problems */
1441.2Sad	movl	(CPU_INFO_MTX_OLDSPL-0x200)(%r8), %edi
1451.2Sad	incl	(CPU_INFO_MTX_COUNT-0x200)(%r8)
1461.2Sad	jnz	1f
1471.2Sad	cmpl	(CPU_INFO_ILEVEL-0x200)(%r8), %edi
1481.2Sad	jae	1f
1491.2Sad	movl	(CPU_INFO_IUNMASK-0x200)(%r8,%rdi,4), %esi
1501.2Sad	cli
1511.2Sad	testl	(CPU_INFO_IPENDING-0x200)(%r8), %esi
1521.2Sad	jnz	_C_LABEL(Xspllower)
1531.2Sad	movl	%edi, (CPU_INFO_ILEVEL-0x200)(%r8)
1541.2Sad	sti
1551.2Sad1:	rep					/* double byte ret as branch */
1561.2Sad	ret					/* target: see AMD docs */
1571.2Sad
1581.2Sad#else	/* DIAGNOSTIC */
1591.2Sad
1601.2Sad	movq	CPUVAR(SELF200), %rsi
1611.2Sad#ifdef MULTIPROCESSOR
1621.2Sad	movb	$0x00, MTX_LOCK(%rdi)
1631.2Sad#endif
1641.2Sad	movl	(CPU_INFO_MTX_OLDSPL-0x200)(%rsi), %ecx
1651.2Sad	incl	(CPU_INFO_MTX_COUNT-0x200)(%rsi)
1661.2Sad	movl	(CPU_INFO_ILEVEL-0x200)(%rsi),%edx
1671.2Sad	cmovnzl	%edx,%ecx
1681.2Sad	cmpl	%edx,%ecx			/* new level is lower? */
1691.2Sad	pushq	%rbx
1701.2Sad	jae,pn	2f
1711.2Sad1:
1721.2Sad	movl	(CPU_INFO_IPENDING-0x200)(%rsi),%eax
1731.2Sad	testl	%eax,(CPU_INFO_IUNMASK-0x200)(%rsi,%rcx,4)/* deferred interrupts? */
1741.2Sad	movl	%eax,%ebx
1751.2Sad	jnz,pn	3f
1761.2Sad	cmpxchg8b (CPU_INFO_ISTATE-0x200)(%rsi)	/* swap in new ilevel */
1771.2Sad	jnz,pn	3f
1781.2Sad2:
1791.2Sad	popq	%rbx
1801.2Sad	ret
1811.2Sad3:
1821.2Sad	popq	%rbx
1831.2Sad	movl	%ecx, %edi
1841.2Sad	jmp	_C_LABEL(Xspllower)
1851.2Sad
1861.2Sad#endif	/* DIAGNOSTIC */
1871.2Sad
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.2Sad	.align	64
1941.2Sad
1951.2SadNENTRY(rw_enter)				/* 0x00c0, 62 bytes */
1961.2Sad	cmpl	$RW_READER, %esi
1971.2Sad	jne	2f
1981.2Sad
1991.2Sad	/*
2001.2Sad	 * Reader: this is the most common case.
2011.2Sad	 */
2021.2Sad1:	movq	RW_OWNER(%rdi), %rax
2031.2Sad	testb	$(RW_WRITE_LOCKED|RW_WRITE_WANTED), %al
2041.2Sad	leaq	RW_READ_INCR(%rax), %rdx
2051.2Sad	jnz,pn	_C_LABEL(rw_vector_enter)
2061.2Sad	LOCK
2071.2Sad	cmpxchgq %rdx, RW_OWNER(%rdi)
2081.2Sad	jnz,pn	1b
2091.2Sad	ret
2101.2Sad
2111.2Sad	/*
2121.2Sad	 * Writer: if the compare-and-set fails, don't bother retrying.
2131.2Sad	 */
2141.2Sad2:	movq	CPUVAR(CURLWP), %rcx
2151.2Sad	xorq	%rax, %rax
2161.2Sad	orq	$RW_WRITE_LOCKED, %rcx
2171.2Sad	LOCK
2181.2Sad	cmpxchgq %rcx, RW_OWNER(%rdi)
2191.2Sad	jnz,pn	_C_LABEL(rw_vector_enter)
2201.2Sad	ret
2211.2Sad
2221.2Sad/*
2231.2Sad * void	rw_exit(krwlock_t *rwl);
2241.2Sad *
2251.2Sad * Release one hold on a RW lock.
2261.2Sad */
2271.2Sad	.align	64
2281.2Sad
2291.2SadNENTRY(rw_exit)					/* 0x0100, 64 bytes */
2301.2Sad	movq	RW_OWNER(%rdi), %rax
2311.2Sad	testb	$RW_WRITE_LOCKED, %al
2321.2Sad	jnz	2f
2331.2Sad
2341.2Sad	/*
2351.2Sad	 * Reader
2361.2Sad	 */
2371.2Sad1:	testb	$RW_HAS_WAITERS, %al
2381.2Sad	jnz,pn	3f
2391.2Sad	cmpq	$RW_READ_INCR, %rax
2401.2Sad	leaq	-RW_READ_INCR(%rax), %rdx
2411.2Sad	jb,pn	3f
2421.2Sad	LOCK
2431.2Sad	cmpxchgq %rdx, RW_OWNER(%rdi)
2441.2Sad	jnz,pn	1b
2451.2Sad	ret
2461.2Sad
2471.2Sad	/*
2481.2Sad	 * Writer
2491.2Sad	 */
2501.2Sad2:	leaq	-RW_WRITE_LOCKED(%rax), %rdx
2511.2Sad	subq	CPUVAR(CURLWP), %rdx
2521.2Sad	jnz,pn	3f
2531.2Sad	LOCK
2541.2Sad	cmpxchgq %rdx, RW_OWNER(%rdi)
2551.2Sad	jnz	3f
2561.2Sad	ret
2571.2Sad
2581.2Sad3:	jmp	_C_LABEL(rw_vector_exit)
2591.2Sad
2601.2Sad#endif	/* LOCKDEBUG */
2611.2Sad
2621.2Sad/*
2631.2Sad * int _lock_cas(uintptr_t *val, uintptr_t old, uintptr_t new);
2641.2Sad *
2651.2Sad * Perform an atomic compare-and-set operation.
2661.2Sad */
2671.2Sad	.align	32
2681.2Sad
2691.2SadNENTRY(_lock_cas)				/* 0x0140, 19 bytes */
2701.2Sad	movq	%rsi, %rax
2711.2Sad	LOCK
2721.2Sad	cmpxchgq %rdx, (%rdi)
2731.2Sad	movq	$0, %rax
2741.2Sad	setz	%al				/* = 1 if success */
2751.2Sad	ret
2761.2Sad
2771.2Sad/*
2781.2Sad * Memory barrier operations.
2791.2Sad */
2801.2Sad
2811.2Sad	.align	8
2821.2Sad
2831.2SadNENTRY(mb_read)
2841.2Sad	lfence
2851.2Sad	ret
2861.2SadEND(mb_read_end, 8)
2871.2Sad
2881.2SadNENTRY(mb_write)
2891.2Sad	/* Nothing just yet */
2901.2Sad	ret
2911.2SadEND(mb_write_end, 8)
2921.2Sad
2931.2SadNENTRY(mb_memory)
2941.2Sad	mfence
2951.2Sad	ret
2961.2SadEND(mb_memory_end, 8)
2971.2Sad
2981.2Sad/*
2991.2Sad * Make sure code after the ret is properly encoded with nopness
3001.2Sad * by gas, or could stall newer processors.
3011.2Sad */
3021.2Sad
3031.2SadNENTRY(x86_mb_nop)
3041.2Sad	ret
3051.2SadEND(x86_mb_nop_end, 8)
306