lock_stubs.S revision 1.8
11.8Sbouyer/* $NetBSD: lock_stubs.S,v 1.8 2007/11/22 16:16:42 bouyer 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.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.2Sad 621.7Sad#define LOCK(name) LABEL(name) lock 631.2Sad 641.2Sad#ifndef LOCKDEBUG 651.2Sad 661.2Sad/* 671.2Sad * void mutex_enter(kmutex_t *mtx); 681.2Sad * 691.2Sad * Acquire a mutex and post a load fence. 701.2Sad */ 711.2Sad .align 64 721.2Sad 731.2SadNENTRY(mutex_enter) /* 0x0000, 25 bytes */ 741.2Sad movq CPUVAR(CURLWP), %rcx 751.2Sad xorq %rax, %rax 761.7Sad LOCK(lockpatch1) 771.2Sad cmpxchgq %rcx, MTX_OWNER(%rdi) 781.2Sad jnz,pn _C_LABEL(mutex_vector_enter) 791.2Sad ret 801.2Sad 811.2Sad/* 821.2Sad * void mutex_exit(kmutex_t *mtx); 831.2Sad * 841.2Sad * Release a mutex and post a load fence. 851.2Sad * 861.2Sad * See comments in mutex_vector_enter() about doing this operation unlocked 871.2Sad * on multiprocessor systems, and comments in arch/x86/include/lock.h about 881.2Sad * memory ordering on Intel x86 systems. 891.2Sad */ 901.2SadNENTRY(mutex_exit) /* 0x0020, 24 bytes */ 911.2Sad movq CPUVAR(CURLWP), %rax 921.2Sad xorq %rdx, %rdx 931.2Sad cmpxchgq %rdx, MTX_OWNER(%rdi) 941.2Sad jnz,pn _C_LABEL(mutex_vector_exit) 951.2Sad ret 961.2Sad 971.2Sad/* 981.2Sad * void mutex_spin_enter(kmutex_t *mtx); 991.2Sad * 1001.2Sad * Acquire a spin mutex and post a load fence. 1011.2Sad */ 1021.4SadNENTRY(mutex_spin_enter) 1031.4Sad movq CPUVAR(SELF), %r8 1041.2Sad#if defined(FULL) 1051.2Sad movl $0x0100, %eax /* new + expected value */ 1061.2Sad#endif 1071.4Sad movl CPU_INFO_ILEVEL(%r8), %esi 1081.4Sad subl $1, CPU_INFO_MTX_COUNT(%r8) /* decl doesnt set CF */ 1091.2Sad movzbl MTX_IPL(%rdi), %ecx /* new SPL */ 1101.4Sad cmovncl CPU_INFO_MTX_OLDSPL(%r8), %esi 1111.2Sad cmpl %ecx, %esi /* higher? */ 1121.4Sad movl %esi, CPU_INFO_MTX_OLDSPL(%r8) 1131.2Sad cmovgl %esi, %ecx 1141.4Sad movl %ecx, CPU_INFO_ILEVEL(%r8) /* splraiseipl() */ 1151.2Sad#if defined(FULL) 1161.7Sad LOCK(lockpatch11) 1171.2Sad cmpxchgb %ah, MTX_LOCK(%rdi) /* lock */ 1181.2Sad jnz,pn _C_LABEL(mutex_spin_retry) /* failed; hard case */ 1191.2Sad#endif 1201.2Sad ret 1211.2Sad 1221.2Sad/* 1231.2Sad * void mutex_spin_exit(kmutex_t *mtx); 1241.2Sad * 1251.2Sad * Release a spin mutex and post a load fence. 1261.2Sad */ 1271.4SadNENTRY(mutex_spin_exit) 1281.2Sad#ifdef DIAGNOSTIC 1291.2Sad 1301.2Sad movl $0x0001, %eax /* new + expected value */ 1311.4Sad movq CPUVAR(SELF), %r8 1321.2Sad cmpxchgb %ah, MTX_LOCK(%rdi) /* unlock */ 1331.2Sad jnz,pn _C_LABEL(mutex_vector_exit) /* hard case if problems */ 1341.4Sad movl CPU_INFO_MTX_OLDSPL(%r8), %edi 1351.4Sad incl CPU_INFO_MTX_COUNT(%r8) 1361.2Sad jnz 1f 1371.4Sad cmpl CPU_INFO_ILEVEL(%r8), %edi 1381.2Sad jae 1f 1391.4Sad movl CPU_INFO_IUNMASK(%r8,%rdi,4), %esi 1401.8Sbouyer CLI(ax,10) 1411.4Sad testl CPU_INFO_IPENDING(%r8), %esi 1421.2Sad jnz _C_LABEL(Xspllower) 1431.4Sad movl %edi, CPU_INFO_ILEVEL(%r8) 1441.8Sbouyer STI(ax,10) 1451.2Sad1: rep /* double byte ret as branch */ 1461.2Sad ret /* target: see AMD docs */ 1471.2Sad 1481.2Sad#else /* DIAGNOSTIC */ 1491.2Sad 1501.4Sad movq CPUVAR(SELF), %rsi 1511.2Sad#ifdef MULTIPROCESSOR 1521.2Sad movb $0x00, MTX_LOCK(%rdi) 1531.2Sad#endif 1541.4Sad movl CPU_INFO_MTX_OLDSPL(%rsi), %ecx 1551.4Sad incl CPU_INFO_MTX_COUNT(%rsi) 1561.4Sad movl CPU_INFO_ILEVEL(%rsi),%edx 1571.2Sad cmovnzl %edx,%ecx 1581.2Sad cmpl %edx,%ecx /* new level is lower? */ 1591.2Sad pushq %rbx 1601.2Sad jae,pn 2f 1611.2Sad1: 1621.4Sad movl CPU_INFO_IPENDING(%rsi),%eax 1631.4Sad testl %eax,CPU_INFO_IUNMASK(%rsi,%rcx,4)/* deferred interrupts? */ 1641.2Sad movl %eax,%ebx 1651.2Sad jnz,pn 3f 1661.4Sad cmpxchg8b CPU_INFO_ISTATE(%rsi) /* swap in new ilevel */ 1671.3Syamt jnz,pn 1b 1681.2Sad2: 1691.2Sad popq %rbx 1701.2Sad ret 1711.2Sad3: 1721.2Sad popq %rbx 1731.2Sad movl %ecx, %edi 1741.2Sad jmp _C_LABEL(Xspllower) 1751.2Sad 1761.2Sad#endif /* DIAGNOSTIC */ 1771.2Sad 1781.2Sad/* 1791.2Sad * void rw_enter(krwlock_t *rwl, krw_t op); 1801.2Sad * 1811.2Sad * Acquire one hold on a RW lock. 1821.2Sad */ 1831.2SadNENTRY(rw_enter) /* 0x00c0, 62 bytes */ 1841.2Sad cmpl $RW_READER, %esi 1851.2Sad jne 2f 1861.2Sad 1871.2Sad /* 1881.2Sad * Reader: this is the most common case. 1891.2Sad */ 1901.2Sad1: movq RW_OWNER(%rdi), %rax 1911.2Sad testb $(RW_WRITE_LOCKED|RW_WRITE_WANTED), %al 1921.2Sad leaq RW_READ_INCR(%rax), %rdx 1931.2Sad jnz,pn _C_LABEL(rw_vector_enter) 1941.7Sad LOCK(lockpatch2) 1951.2Sad cmpxchgq %rdx, RW_OWNER(%rdi) 1961.2Sad jnz,pn 1b 1971.2Sad ret 1981.2Sad 1991.2Sad /* 2001.2Sad * Writer: if the compare-and-set fails, don't bother retrying. 2011.2Sad */ 2021.2Sad2: movq CPUVAR(CURLWP), %rcx 2031.2Sad xorq %rax, %rax 2041.2Sad orq $RW_WRITE_LOCKED, %rcx 2051.7Sad LOCK(lockpatch3) 2061.2Sad cmpxchgq %rcx, RW_OWNER(%rdi) 2071.2Sad jnz,pn _C_LABEL(rw_vector_enter) 2081.2Sad ret 2091.2Sad 2101.2Sad/* 2111.2Sad * void rw_exit(krwlock_t *rwl); 2121.2Sad * 2131.2Sad * Release one hold on a RW lock. 2141.2Sad */ 2151.2SadNENTRY(rw_exit) /* 0x0100, 64 bytes */ 2161.2Sad movq RW_OWNER(%rdi), %rax 2171.2Sad testb $RW_WRITE_LOCKED, %al 2181.2Sad jnz 2f 2191.2Sad 2201.2Sad /* 2211.2Sad * Reader 2221.2Sad */ 2231.2Sad1: testb $RW_HAS_WAITERS, %al 2241.2Sad jnz,pn 3f 2251.2Sad cmpq $RW_READ_INCR, %rax 2261.2Sad leaq -RW_READ_INCR(%rax), %rdx 2271.2Sad jb,pn 3f 2281.7Sad LOCK(lockpatch4) 2291.2Sad cmpxchgq %rdx, RW_OWNER(%rdi) 2301.2Sad jnz,pn 1b 2311.2Sad ret 2321.2Sad 2331.2Sad /* 2341.2Sad * Writer 2351.2Sad */ 2361.2Sad2: leaq -RW_WRITE_LOCKED(%rax), %rdx 2371.2Sad subq CPUVAR(CURLWP), %rdx 2381.2Sad jnz,pn 3f 2391.7Sad LOCK(lockpatch5) 2401.2Sad cmpxchgq %rdx, RW_OWNER(%rdi) 2411.2Sad jnz 3f 2421.2Sad ret 2431.2Sad 2441.2Sad3: jmp _C_LABEL(rw_vector_exit) 2451.2Sad 2461.2Sad#endif /* LOCKDEBUG */ 2471.2Sad 2481.2Sad/* 2491.2Sad * int _lock_cas(uintptr_t *val, uintptr_t old, uintptr_t new); 2501.2Sad * 2511.2Sad * Perform an atomic compare-and-set operation. 2521.2Sad */ 2531.2SadNENTRY(_lock_cas) /* 0x0140, 19 bytes */ 2541.2Sad movq %rsi, %rax 2551.7Sad LOCK(lockpatch6) 2561.2Sad cmpxchgq %rdx, (%rdi) 2571.2Sad movq $0, %rax 2581.2Sad setz %al /* = 1 if success */ 2591.2Sad ret 2601.2Sad 2611.2Sad/* 2621.7Sad * Memory barrier operations, may be patched at runtime. 2631.2Sad */ 2641.7Sad .align 8 2651.7SadENTRY(mb_read) 2661.7Sad LOCK(lockpatch7) 2671.7Sad addq $0, 0(%rsp) 2681.2Sad ret 2691.2SadEND(mb_read_end, 8) 2701.2Sad 2711.7SadENTRY(mb_write) 2721.7Sad nop 2731.2Sad ret 2741.2SadEND(mb_write_end, 8) 2751.2Sad 2761.7SadENTRY(mb_memory) 2771.7Sad LOCK(lockpatch8) 2781.7Sad addq $0, 0(%rsp) 2791.7Sad ret 2801.7SadEND(mb_memory_end, 8) 2811.7Sad 2821.7SadENTRY(sse2_mb_read) 2831.7Sad lfence 2841.7Sad ret 2851.7SadEND(sse2_mb_read_end, 8) 2861.7Sad 2871.7SadENTRY(sse2_mb_memory) 2881.2Sad mfence 2891.2Sad ret 2901.7SadEND(sse2_mb_memory_end, 8) 2911.2Sad 2921.2Sad/* 2931.2Sad * Make sure code after the ret is properly encoded with nopness 2941.2Sad * by gas, or could stall newer processors. 2951.2Sad */ 2961.2Sad 2971.7SadENTRY(x86_mb_nop) 2981.7Sad nop 2991.2Sad ret 3001.2SadEND(x86_mb_nop_end, 8) 3011.7Sad 3021.7Sad/* 3031.7Sad * XXX Don't belong here. 3041.7Sad */ 3051.7SadENTRY(atomic_inc_uint) 3061.7Sad LOCK(lockpatch9) 3071.7Sad incl (%rdi) 3081.7Sad ret 3091.7Sad 3101.7SadENTRY(atomic_dec_uint_nv) 3111.7Sad movl $-1, %eax 3121.7Sad LOCK(lockpatch10) 3131.7Sad xaddl %eax, (%rdi) 3141.7Sad decl %eax 3151.7Sad ret 3161.7Sad 3171.7Sad/* 3181.7Sad * Patchpoints to replace with NOP when ncpu == 1. 3191.7Sad */ 3201.7Sad#ifndef LOCKDEBUG 3211.7SadLABEL(x86_lockpatch) 3221.7Sad .quad lockpatch1, lockpatch2, lockpatch3, lockpatch4 3231.7Sad .quad lockpatch5, lockpatch6, lockpatch7, lockpatch8 3241.7Sad .quad lockpatch9, lockpatch10 3251.7Sad#ifdef FULL 3261.7Sad .quad lockpatch11 3271.7Sad#endif 3281.7Sad .quad 0 3291.7Sad#endif 330