lock_stubs.S revision 1.33
11.33Smaxv/* $NetBSD: lock_stubs.S,v 1.33 2019/11/14 16:23:52 maxv Exp $ */ 21.2Sad 31.32Smaxv/* 41.22Sad * Copyright (c) 2006, 2007, 2008, 2009 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.32Smaxv * 191.2Sad * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 201.2Sad * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 211.2Sad * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 221.2Sad * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 231.2Sad * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 241.2Sad * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 251.2Sad * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 261.2Sad * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 271.2Sad * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 281.2Sad * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 291.2Sad * POSSIBILITY OF SUCH DAMAGE. 301.2Sad */ 311.2Sad 321.2Sad#include "opt_multiprocessor.h" 331.2Sad#include "opt_lockdebug.h" 341.2Sad 351.2Sad#include <machine/asm.h> 361.8Sbouyer#include <machine/frameasm.h> 371.2Sad 381.2Sad#include "assym.h" 391.2Sad 401.32Smaxv#define LOCK \ 411.27Smaxv HOTPATCH(HP_NAME_NOLOCK, 1) ; \ 421.27Smaxv lock 431.32Smaxv#define RET \ 441.28Smaxv HOTPATCH(HP_NAME_RETFENCE, 3) ; \ 451.28Smaxv ret; nop; nop ; \ 461.28Smaxv ret 471.2Sad 481.2Sad#ifndef LOCKDEBUG 491.2Sad 501.32Smaxv .align 64 511.32Smaxv 521.2Sad/* 531.2Sad * void mutex_enter(kmutex_t *mtx); 541.2Sad * 551.2Sad * Acquire a mutex and post a load fence. 561.2Sad */ 571.19SchsENTRY(mutex_enter) 581.2Sad movq CPUVAR(CURLWP), %rcx 591.2Sad xorq %rax, %rax 601.32Smaxv LOCK 611.21Sad cmpxchgq %rcx, (%rdi) 621.14Sad jnz 1f 631.32Smaxv RET 641.14Sad1: 651.14Sad jmp _C_LABEL(mutex_vector_enter) 661.25SuebayasiEND(mutex_enter) 671.2Sad 681.2Sad/* 691.2Sad * void mutex_exit(kmutex_t *mtx); 701.2Sad * 711.2Sad * Release a mutex and post a load fence. 721.2Sad * 731.2Sad * See comments in mutex_vector_enter() about doing this operation unlocked 741.2Sad * on multiprocessor systems, and comments in arch/x86/include/lock.h about 751.2Sad * memory ordering on Intel x86 systems. 761.2Sad */ 771.19SchsENTRY(mutex_exit) 781.2Sad movq CPUVAR(CURLWP), %rax 791.2Sad xorq %rdx, %rdx 801.21Sad cmpxchgq %rdx, (%rdi) 811.14Sad jnz 1f 821.2Sad ret 831.14Sad1: 841.14Sad jmp _C_LABEL(mutex_vector_exit) 851.25SuebayasiEND(mutex_exit) 861.2Sad 871.2Sad/* 881.2Sad * void mutex_spin_enter(kmutex_t *mtx); 891.2Sad * 901.2Sad * Acquire a spin mutex and post a load fence. 911.2Sad */ 921.19SchsENTRY(mutex_spin_enter) 931.20Sad movl $1, %eax 941.14Sad movl CPUVAR(ILEVEL), %esi 951.2Sad movzbl MTX_IPL(%rdi), %ecx /* new SPL */ 961.2Sad cmpl %ecx, %esi /* higher? */ 971.2Sad cmovgl %esi, %ecx 981.14Sad movl %ecx, CPUVAR(ILEVEL) /* splraiseipl() */ 991.20Sad subl %eax, CPUVAR(MTX_COUNT) /* decl doesnt set CF */ 1001.14Sad cmovncl CPUVAR(MTX_OLDSPL), %esi 1011.14Sad movl %esi, CPUVAR(MTX_OLDSPL) 1021.20Sad xchgb %al, MTX_LOCK(%rdi) /* lock */ 1031.21Sad#ifdef MULTIPROCESSOR /* XXX for xen */ 1041.20Sad testb %al, %al 1051.14Sad jnz 1f 1061.2Sad#endif 1071.32Smaxv RET 1081.14Sad1: 1091.14Sad jmp _C_LABEL(mutex_spin_retry) /* failed; hard case */ 1101.25SuebayasiEND(mutex_spin_enter) 1111.2Sad 1121.2Sad/* 1131.2Sad * void mutex_spin_exit(kmutex_t *mtx); 1141.2Sad * 1151.2Sad * Release a spin mutex and post a load fence. 1161.2Sad */ 1171.19SchsENTRY(mutex_spin_exit) 1181.2Sad#ifdef DIAGNOSTIC 1191.2Sad 1201.2Sad movl $0x0001, %eax /* new + expected value */ 1211.4Sad movq CPUVAR(SELF), %r8 1221.2Sad cmpxchgb %ah, MTX_LOCK(%rdi) /* unlock */ 1231.21Sad jnz _C_LABEL(mutex_vector_exit) /* hard case if problems */ 1241.4Sad movl CPU_INFO_MTX_OLDSPL(%r8), %edi 1251.4Sad incl CPU_INFO_MTX_COUNT(%r8) 1261.2Sad jnz 1f 1271.4Sad cmpl CPU_INFO_ILEVEL(%r8), %edi 1281.2Sad jae 1f 1291.31Scherry#if !defined(XENPV) 1301.4Sad movl CPU_INFO_IUNMASK(%r8,%rdi,4), %esi 1311.12Sdsl CLI(ax) 1321.4Sad testl CPU_INFO_IPENDING(%r8), %esi 1331.2Sad jnz _C_LABEL(Xspllower) 1341.30Scherry#endif 1351.30Scherry#if defined(XEN) 1361.30Scherry movl CPU_INFO_XUNMASK(%r8,%rdi,4), %esi 1371.30Scherry CLI(ax) 1381.30Scherry testl CPU_INFO_XPENDING(%r8), %esi 1391.30Scherry jnz _C_LABEL(Xspllower) 1401.30Scherry#endif 1411.4Sad movl %edi, CPU_INFO_ILEVEL(%r8) 1421.12Sdsl STI(ax) 1431.2Sad1: rep /* double byte ret as branch */ 1441.2Sad ret /* target: see AMD docs */ 1451.2Sad 1461.2Sad#else /* DIAGNOSTIC */ 1471.2Sad 1481.4Sad movq CPUVAR(SELF), %rsi 1491.2Sad movb $0x00, MTX_LOCK(%rdi) 1501.4Sad movl CPU_INFO_MTX_OLDSPL(%rsi), %ecx 1511.4Sad incl CPU_INFO_MTX_COUNT(%rsi) 1521.4Sad movl CPU_INFO_ILEVEL(%rsi),%edx 1531.2Sad cmovnzl %edx,%ecx 1541.21Sad pushq %rbx 1551.2Sad cmpl %edx,%ecx /* new level is lower? */ 1561.21Sad jae 2f 1571.2Sad1: 1581.31Scherry#if !defined(XENPV) 1591.4Sad movl CPU_INFO_IPENDING(%rsi),%eax 1601.4Sad testl %eax,CPU_INFO_IUNMASK(%rsi,%rcx,4)/* deferred interrupts? */ 1611.21Sad jnz 3f 1621.2Sad movl %eax,%ebx 1631.4Sad cmpxchg8b CPU_INFO_ISTATE(%rsi) /* swap in new ilevel */ 1641.21Sad jnz 4f 1651.30Scherry#endif 1661.30Scherry#if defined(XEN) 1671.30Scherry movl CPU_INFO_XPENDING(%rsi),%eax 1681.30Scherry testl %eax,CPU_INFO_XUNMASK(%rsi,%rcx,4)/* deferred interrupts? */ 1691.30Scherry jnz 3f 1701.30Scherry movl %edx, %eax 1711.30Scherry cmpxchgl %ecx, CPU_INFO_ILEVEL(%rsi) 1721.30Scherry jnz 4f 1731.30Scherry#endif 1741.2Sad2: 1751.2Sad popq %rbx 1761.2Sad ret 1771.2Sad3: 1781.2Sad popq %rbx 1791.2Sad movl %ecx, %edi 1801.2Sad jmp _C_LABEL(Xspllower) 1811.21Sad4: 1821.21Sad jmp 1b 1831.2Sad 1841.2Sad#endif /* DIAGNOSTIC */ 1851.2Sad 1861.25SuebayasiEND(mutex_spin_exit) 1871.25Suebayasi 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.19SchsENTRY(rw_enter) 1941.2Sad cmpl $RW_READER, %esi 1951.2Sad jne 2f 1961.2Sad 1971.2Sad /* 1981.2Sad * Reader: this is the most common case. 1991.2Sad */ 2001.21Sad movq (%rdi), %rax 2011.21Sad0: 2021.2Sad testb $(RW_WRITE_LOCKED|RW_WRITE_WANTED), %al 2031.21Sad jnz 3f 2041.32Smaxv leaq RW_READ_INCR(%rax), %rdx 2051.32Smaxv LOCK 2061.21Sad cmpxchgq %rdx, (%rdi) 2071.21Sad jnz 1f 2081.32Smaxv RET 2091.21Sad1: 2101.21Sad jmp 0b 2111.2Sad 2121.2Sad /* 2131.2Sad * Writer: if the compare-and-set fails, don't bother retrying. 2141.2Sad */ 2151.2Sad2: movq CPUVAR(CURLWP), %rcx 2161.2Sad xorq %rax, %rax 2171.2Sad orq $RW_WRITE_LOCKED, %rcx 2181.32Smaxv LOCK 2191.21Sad cmpxchgq %rcx, (%rdi) 2201.14Sad jnz 3f 2211.32Smaxv RET 2221.14Sad3: 2231.14Sad jmp _C_LABEL(rw_vector_enter) 2241.25SuebayasiEND(rw_enter) 2251.2Sad 2261.2Sad/* 2271.2Sad * void rw_exit(krwlock_t *rwl); 2281.2Sad * 2291.2Sad * Release one hold on a RW lock. 2301.2Sad */ 2311.19SchsENTRY(rw_exit) 2321.21Sad movq (%rdi), %rax 2331.2Sad testb $RW_WRITE_LOCKED, %al 2341.2Sad jnz 2f 2351.2Sad 2361.2Sad /* 2371.2Sad * Reader 2381.2Sad */ 2391.21Sad0: testb $RW_HAS_WAITERS, %al 2401.14Sad jnz 3f 2411.2Sad cmpq $RW_READ_INCR, %rax 2421.21Sad jb 3f 2431.2Sad leaq -RW_READ_INCR(%rax), %rdx 2441.32Smaxv LOCK 2451.21Sad cmpxchgq %rdx, (%rdi) 2461.21Sad jnz 1f 2471.2Sad ret 2481.21Sad1: 2491.21Sad jmp 0b 2501.2Sad 2511.2Sad /* 2521.2Sad * Writer 2531.2Sad */ 2541.2Sad2: leaq -RW_WRITE_LOCKED(%rax), %rdx 2551.2Sad subq CPUVAR(CURLWP), %rdx 2561.14Sad jnz 3f 2571.32Smaxv LOCK 2581.21Sad cmpxchgq %rdx, (%rdi) 2591.2Sad jnz 3f 2601.2Sad ret 2611.2Sad 2621.2Sad3: jmp _C_LABEL(rw_vector_exit) 2631.25SuebayasiEND(rw_exit) 2641.2Sad 2651.13Sad/* 2661.13Sad * int rw_tryenter(krwlock_t *rwl, krw_t op); 2671.13Sad * 2681.13Sad * Try to acquire one hold on a RW lock. 2691.13Sad */ 2701.19SchsENTRY(rw_tryenter) 2711.13Sad cmpl $RW_READER, %esi 2721.13Sad jne 2f 2731.13Sad 2741.13Sad /* 2751.13Sad * Reader: this is the most common case. 2761.13Sad */ 2771.21Sad movq (%rdi), %rax 2781.21Sad0: 2791.13Sad testb $(RW_WRITE_LOCKED|RW_WRITE_WANTED), %al 2801.22Sad jnz 4f 2811.32Smaxv leaq RW_READ_INCR(%rax), %rdx 2821.32Smaxv LOCK 2831.21Sad cmpxchgq %rdx, (%rdi) 2841.21Sad jnz 1f 2851.21Sad movl %edx, %eax /* nonzero */ 2861.32Smaxv RET 2871.21Sad1: 2881.21Sad jmp 0b 2891.13Sad 2901.13Sad /* 2911.13Sad * Writer: if the compare-and-set fails, don't bother retrying. 2921.13Sad */ 2931.13Sad2: movq CPUVAR(CURLWP), %rcx 2941.13Sad xorq %rax, %rax 2951.13Sad orq $RW_WRITE_LOCKED, %rcx 2961.32Smaxv LOCK 2971.21Sad cmpxchgq %rcx, (%rdi) 2981.18Sad movl $0, %eax 2991.13Sad setz %al 3001.22Sad3: 3011.32Smaxv RET 3021.13Sad ret 3031.22Sad4: 3041.22Sad xorl %eax, %eax 3051.22Sad jmp 3b 3061.25SuebayasiEND(rw_tryenter) 3071.13Sad 3081.2Sad#endif /* LOCKDEBUG */ 3091.2Sad 3101.2Sad/* 3111.11Sad * Spinlocks. 3121.2Sad */ 3131.19SchsENTRY(__cpu_simple_lock_init) 3141.11Sad movb $0, (%rdi) 3151.2Sad ret 3161.25SuebayasiEND(__cpu_simple_lock_init) 3171.2Sad 3181.29SmaxvENTRY(__cpu_simple_lock) 3191.11Sad movl $0x0100, %eax 3201.11Sad1: 3211.32Smaxv LOCK 3221.11Sad cmpxchgb %ah, (%rdi) 3231.11Sad jnz 2f 3241.32Smaxv RET 3251.11Sad2: 3261.11Sad movl $0x0100, %eax 3271.11Sad pause 3281.11Sad nop 3291.7Sad nop 3301.11Sad cmpb $0, (%rdi) 3311.11Sad je 1b 3321.11Sad jmp 2b 3331.25SuebayasiEND(__cpu_simple_lock) 3341.11Sad 3351.29SmaxvENTRY(__cpu_simple_unlock) 3361.11Sad movb $0, (%rdi) 3371.2Sad ret 3381.25SuebayasiEND(__cpu_simple_unlock) 3391.7Sad 3401.19SchsENTRY(__cpu_simple_lock_try) 3411.11Sad movl $0x0100, %eax 3421.32Smaxv LOCK 3431.11Sad cmpxchgb %ah, (%rdi) 3441.11Sad movl $0, %eax 3451.22Sad setz %al 3461.33Smaxv KMSAN_INIT_RET(4) 3471.32Smaxv RET 3481.25SuebayasiEND(__cpu_simple_lock_try) 3491.2Sad 350