lock_stubs.S revision 1.4
11.4Sad/* $NetBSD: lock_stubs.S,v 1.4 2007/08/29 23:38:02 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.2SadNENTRY(mutex_exit) /* 0x0020, 24 bytes */ 951.2Sad movq CPUVAR(CURLWP), %rax 961.2Sad xorq %rdx, %rdx 971.2Sad cmpxchgq %rdx, MTX_OWNER(%rdi) 981.2Sad jnz,pn _C_LABEL(mutex_vector_exit) 991.2Sad ret 1001.2Sad 1011.2Sad/* 1021.2Sad * void mutex_spin_enter(kmutex_t *mtx); 1031.2Sad * 1041.2Sad * Acquire a spin mutex and post a load fence. 1051.2Sad */ 1061.4SadNENTRY(mutex_spin_enter) 1071.4Sad movq CPUVAR(SELF), %r8 1081.2Sad#if defined(FULL) 1091.2Sad movl $0x0100, %eax /* new + expected value */ 1101.2Sad#endif 1111.4Sad movl CPU_INFO_ILEVEL(%r8), %esi 1121.4Sad subl $1, CPU_INFO_MTX_COUNT(%r8) /* decl doesnt set CF */ 1131.2Sad movzbl MTX_IPL(%rdi), %ecx /* new SPL */ 1141.4Sad cmovncl CPU_INFO_MTX_OLDSPL(%r8), %esi 1151.2Sad cmpl %ecx, %esi /* higher? */ 1161.4Sad movl %esi, CPU_INFO_MTX_OLDSPL(%r8) 1171.2Sad cmovgl %esi, %ecx 1181.4Sad movl %ecx, CPU_INFO_ILEVEL(%r8) /* splraiseipl() */ 1191.2Sad#if defined(FULL) 1201.2Sad LOCK 1211.2Sad cmpxchgb %ah, MTX_LOCK(%rdi) /* lock */ 1221.2Sad jnz,pn _C_LABEL(mutex_spin_retry) /* failed; hard case */ 1231.2Sad#endif 1241.2Sad ret 1251.2Sad 1261.2Sad/* 1271.2Sad * void mutex_spin_exit(kmutex_t *mtx); 1281.2Sad * 1291.2Sad * Release a spin mutex and post a load fence. 1301.2Sad */ 1311.4SadNENTRY(mutex_spin_exit) 1321.2Sad#ifdef DIAGNOSTIC 1331.2Sad 1341.2Sad movl $0x0001, %eax /* new + expected value */ 1351.4Sad movq CPUVAR(SELF), %r8 1361.2Sad cmpxchgb %ah, MTX_LOCK(%rdi) /* unlock */ 1371.2Sad jnz,pn _C_LABEL(mutex_vector_exit) /* hard case if problems */ 1381.4Sad movl CPU_INFO_MTX_OLDSPL(%r8), %edi 1391.4Sad incl CPU_INFO_MTX_COUNT(%r8) 1401.2Sad jnz 1f 1411.4Sad cmpl CPU_INFO_ILEVEL(%r8), %edi 1421.2Sad jae 1f 1431.4Sad movl CPU_INFO_IUNMASK(%r8,%rdi,4), %esi 1441.2Sad cli 1451.4Sad testl CPU_INFO_IPENDING(%r8), %esi 1461.2Sad jnz _C_LABEL(Xspllower) 1471.4Sad movl %edi, CPU_INFO_ILEVEL(%r8) 1481.2Sad sti 1491.2Sad1: rep /* double byte ret as branch */ 1501.2Sad ret /* target: see AMD docs */ 1511.2Sad 1521.2Sad#else /* DIAGNOSTIC */ 1531.2Sad 1541.4Sad movq CPUVAR(SELF), %rsi 1551.2Sad#ifdef MULTIPROCESSOR 1561.2Sad movb $0x00, MTX_LOCK(%rdi) 1571.2Sad#endif 1581.4Sad movl CPU_INFO_MTX_OLDSPL(%rsi), %ecx 1591.4Sad incl CPU_INFO_MTX_COUNT(%rsi) 1601.4Sad movl CPU_INFO_ILEVEL(%rsi),%edx 1611.2Sad cmovnzl %edx,%ecx 1621.2Sad cmpl %edx,%ecx /* new level is lower? */ 1631.2Sad pushq %rbx 1641.2Sad jae,pn 2f 1651.2Sad1: 1661.4Sad movl CPU_INFO_IPENDING(%rsi),%eax 1671.4Sad testl %eax,CPU_INFO_IUNMASK(%rsi,%rcx,4)/* deferred interrupts? */ 1681.2Sad movl %eax,%ebx 1691.2Sad jnz,pn 3f 1701.4Sad cmpxchg8b CPU_INFO_ISTATE(%rsi) /* swap in new ilevel */ 1711.3Syamt jnz,pn 1b 1721.2Sad2: 1731.2Sad popq %rbx 1741.2Sad ret 1751.2Sad3: 1761.2Sad popq %rbx 1771.2Sad movl %ecx, %edi 1781.2Sad jmp _C_LABEL(Xspllower) 1791.2Sad 1801.2Sad#endif /* DIAGNOSTIC */ 1811.2Sad 1821.2Sad/* 1831.2Sad * void rw_enter(krwlock_t *rwl, krw_t op); 1841.2Sad * 1851.2Sad * Acquire one hold on a RW lock. 1861.2Sad */ 1871.2SadNENTRY(rw_enter) /* 0x00c0, 62 bytes */ 1881.2Sad cmpl $RW_READER, %esi 1891.2Sad jne 2f 1901.2Sad 1911.2Sad /* 1921.2Sad * Reader: this is the most common case. 1931.2Sad */ 1941.2Sad1: movq RW_OWNER(%rdi), %rax 1951.2Sad testb $(RW_WRITE_LOCKED|RW_WRITE_WANTED), %al 1961.2Sad leaq RW_READ_INCR(%rax), %rdx 1971.2Sad jnz,pn _C_LABEL(rw_vector_enter) 1981.2Sad LOCK 1991.2Sad cmpxchgq %rdx, RW_OWNER(%rdi) 2001.2Sad jnz,pn 1b 2011.2Sad ret 2021.2Sad 2031.2Sad /* 2041.2Sad * Writer: if the compare-and-set fails, don't bother retrying. 2051.2Sad */ 2061.2Sad2: movq CPUVAR(CURLWP), %rcx 2071.2Sad xorq %rax, %rax 2081.2Sad orq $RW_WRITE_LOCKED, %rcx 2091.2Sad LOCK 2101.2Sad cmpxchgq %rcx, RW_OWNER(%rdi) 2111.2Sad jnz,pn _C_LABEL(rw_vector_enter) 2121.2Sad ret 2131.2Sad 2141.2Sad/* 2151.2Sad * void rw_exit(krwlock_t *rwl); 2161.2Sad * 2171.2Sad * Release one hold on a RW lock. 2181.2Sad */ 2191.2SadNENTRY(rw_exit) /* 0x0100, 64 bytes */ 2201.2Sad movq RW_OWNER(%rdi), %rax 2211.2Sad testb $RW_WRITE_LOCKED, %al 2221.2Sad jnz 2f 2231.2Sad 2241.2Sad /* 2251.2Sad * Reader 2261.2Sad */ 2271.2Sad1: testb $RW_HAS_WAITERS, %al 2281.2Sad jnz,pn 3f 2291.2Sad cmpq $RW_READ_INCR, %rax 2301.2Sad leaq -RW_READ_INCR(%rax), %rdx 2311.2Sad jb,pn 3f 2321.2Sad LOCK 2331.2Sad cmpxchgq %rdx, RW_OWNER(%rdi) 2341.2Sad jnz,pn 1b 2351.2Sad ret 2361.2Sad 2371.2Sad /* 2381.2Sad * Writer 2391.2Sad */ 2401.2Sad2: leaq -RW_WRITE_LOCKED(%rax), %rdx 2411.2Sad subq CPUVAR(CURLWP), %rdx 2421.2Sad jnz,pn 3f 2431.2Sad LOCK 2441.2Sad cmpxchgq %rdx, RW_OWNER(%rdi) 2451.2Sad jnz 3f 2461.2Sad ret 2471.2Sad 2481.2Sad3: jmp _C_LABEL(rw_vector_exit) 2491.2Sad 2501.2Sad#endif /* LOCKDEBUG */ 2511.2Sad 2521.2Sad/* 2531.2Sad * int _lock_cas(uintptr_t *val, uintptr_t old, uintptr_t new); 2541.2Sad * 2551.2Sad * Perform an atomic compare-and-set operation. 2561.2Sad */ 2571.2SadNENTRY(_lock_cas) /* 0x0140, 19 bytes */ 2581.2Sad movq %rsi, %rax 2591.2Sad LOCK 2601.2Sad cmpxchgq %rdx, (%rdi) 2611.2Sad movq $0, %rax 2621.2Sad setz %al /* = 1 if success */ 2631.2Sad ret 2641.2Sad 2651.2Sad/* 2661.2Sad * Memory barrier operations. 2671.2Sad */ 2681.2SadNENTRY(mb_read) 2691.2Sad lfence 2701.2Sad ret 2711.2SadEND(mb_read_end, 8) 2721.2Sad 2731.2SadNENTRY(mb_write) 2741.2Sad /* Nothing just yet */ 2751.2Sad ret 2761.2SadEND(mb_write_end, 8) 2771.2Sad 2781.2SadNENTRY(mb_memory) 2791.2Sad mfence 2801.2Sad ret 2811.2SadEND(mb_memory_end, 8) 2821.2Sad 2831.2Sad/* 2841.2Sad * Make sure code after the ret is properly encoded with nopness 2851.2Sad * by gas, or could stall newer processors. 2861.2Sad */ 2871.2Sad 2881.2SadNENTRY(x86_mb_nop) 2891.2Sad ret 2901.2SadEND(x86_mb_nop_end, 8) 291