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