11.38Sknakahar/* $NetBSD: lock_stubs.S,v 1.38 2022/09/13 05:36:29 knakahara 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.37Sknakahar movzbl CPUVAR(ILEVEL), %esi 951.2Sad movzbl MTX_IPL(%rdi), %ecx /* new SPL */ 961.2Sad cmpl %ecx, %esi /* higher? */ 971.2Sad cmovgl %esi, %ecx 981.37Sknakahar movb %cl, 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.38Sknakahar cmpb CPU_INFO_ILEVEL(%r8), %dil 1281.2Sad jae 1f 1291.38Sknakahar movq CPU_INFO_IUNMASK(%r8,%rdi,8), %rsi 1301.12Sdsl CLI(ax) 1311.38Sknakahar testq CPU_INFO_IPENDING(%r8), %rsi 1321.2Sad jnz _C_LABEL(Xspllower) 1331.38Sknakahar movb %dil, CPU_INFO_ILEVEL(%r8) 1341.12Sdsl STI(ax) 1351.2Sad1: rep /* double byte ret as branch */ 1361.2Sad ret /* target: see AMD docs */ 1371.2Sad 1381.2Sad#else /* DIAGNOSTIC */ 1391.2Sad 1401.4Sad movq CPUVAR(SELF), %rsi 1411.2Sad movb $0x00, MTX_LOCK(%rdi) 1421.4Sad movl CPU_INFO_MTX_OLDSPL(%rsi), %ecx 1431.4Sad incl CPU_INFO_MTX_COUNT(%rsi) 1441.38Sknakahar movzbl CPU_INFO_ILEVEL(%rsi),%edx 1451.2Sad cmovnzl %edx,%ecx 1461.2Sad cmpl %edx,%ecx /* new level is lower? */ 1471.21Sad jae 2f 1481.38Sknakahar xorq %rdi,%rdi /* rdi: ci_ipending mask */ 1491.38Sknakahar notq %rdi 1501.38Sknakahar shrq $8,%rdi 1511.38Sknakahar movq %rcx,%r9 /* r9: shifted new level */ 1521.38Sknakahar shlq $56,%r9 1531.2Sad1: 1541.38Sknakahar movq CPU_INFO_IPENDING(%rsi),%rax 1551.38Sknakahar testq %rax,CPU_INFO_IUNMASK(%rsi,%rcx,8)/* deferred interrupts? */ 1561.21Sad jnz 3f 1571.38Sknakahar movq %rax,%r8 1581.38Sknakahar andq %rdi,%r8 1591.38Sknakahar orq %r9,%r8 1601.38Sknakahar cmpxchgq %r8,CPU_INFO_ISTATE(%rsi) /* swap in new ilevel */ 1611.21Sad jnz 4f 1621.2Sad2: 1631.2Sad ret 1641.2Sad3: 1651.2Sad movl %ecx, %edi 1661.2Sad jmp _C_LABEL(Xspllower) 1671.21Sad4: 1681.21Sad jmp 1b 1691.2Sad 1701.2Sad#endif /* DIAGNOSTIC */ 1711.2Sad 1721.25SuebayasiEND(mutex_spin_exit) 1731.25Suebayasi 1741.2Sad/* 1751.2Sad * void rw_enter(krwlock_t *rwl, krw_t op); 1761.2Sad * 1771.2Sad * Acquire one hold on a RW lock. 1781.2Sad */ 1791.19SchsENTRY(rw_enter) 1801.35Sad cmpl $RW_READER, %esi 1811.2Sad jne 2f 1821.2Sad 1831.2Sad /* 1841.35Sad * Reader: this is the most common case. 1851.2Sad */ 1861.35Sad movq (%rdi), %rax 1871.21Sad0: 1881.2Sad testb $(RW_WRITE_LOCKED|RW_WRITE_WANTED), %al 1891.21Sad jnz 3f 1901.32Smaxv leaq RW_READ_INCR(%rax), %rdx 1911.32Smaxv LOCK 1921.21Sad cmpxchgq %rdx, (%rdi) 1931.21Sad jnz 1f 1941.32Smaxv RET 1951.21Sad1: 1961.21Sad jmp 0b 1971.2Sad 1981.2Sad /* 1991.2Sad * Writer: if the compare-and-set fails, don't bother retrying. 2001.2Sad */ 2011.2Sad2: movq CPUVAR(CURLWP), %rcx 2021.35Sad xorq %rax, %rax 2031.2Sad orq $RW_WRITE_LOCKED, %rcx 2041.32Smaxv LOCK 2051.21Sad cmpxchgq %rcx, (%rdi) 2061.14Sad jnz 3f 2071.32Smaxv RET 2081.14Sad3: 2091.14Sad jmp _C_LABEL(rw_vector_enter) 2101.25SuebayasiEND(rw_enter) 2111.2Sad 2121.2Sad/* 2131.2Sad * void rw_exit(krwlock_t *rwl); 2141.2Sad * 2151.2Sad * Release one hold on a RW lock. 2161.2Sad */ 2171.19SchsENTRY(rw_exit) 2181.21Sad movq (%rdi), %rax 2191.2Sad testb $RW_WRITE_LOCKED, %al 2201.2Sad jnz 2f 2211.2Sad 2221.2Sad /* 2231.2Sad * Reader 2241.2Sad */ 2251.21Sad0: testb $RW_HAS_WAITERS, %al 2261.14Sad jnz 3f 2271.2Sad cmpq $RW_READ_INCR, %rax 2281.21Sad jb 3f 2291.2Sad leaq -RW_READ_INCR(%rax), %rdx 2301.32Smaxv LOCK 2311.21Sad cmpxchgq %rdx, (%rdi) 2321.21Sad jnz 1f 2331.2Sad ret 2341.21Sad1: 2351.21Sad jmp 0b 2361.2Sad 2371.2Sad /* 2381.2Sad * Writer 2391.2Sad */ 2401.2Sad2: leaq -RW_WRITE_LOCKED(%rax), %rdx 2411.2Sad subq CPUVAR(CURLWP), %rdx 2421.14Sad jnz 3f 2431.32Smaxv LOCK 2441.21Sad cmpxchgq %rdx, (%rdi) 2451.2Sad jnz 3f 2461.2Sad ret 2471.2Sad 2481.2Sad3: jmp _C_LABEL(rw_vector_exit) 2491.25SuebayasiEND(rw_exit) 2501.2Sad 2511.13Sad/* 2521.13Sad * int rw_tryenter(krwlock_t *rwl, krw_t op); 2531.13Sad * 2541.13Sad * Try to acquire one hold on a RW lock. 2551.13Sad */ 2561.19SchsENTRY(rw_tryenter) 2571.35Sad cmpl $RW_READER, %esi 2581.13Sad jne 2f 2591.13Sad 2601.13Sad /* 2611.35Sad * Reader: this is the most common case. 2621.13Sad */ 2631.35Sad movq (%rdi), %rax 2641.21Sad0: 2651.13Sad testb $(RW_WRITE_LOCKED|RW_WRITE_WANTED), %al 2661.22Sad jnz 4f 2671.32Smaxv leaq RW_READ_INCR(%rax), %rdx 2681.32Smaxv LOCK 2691.21Sad cmpxchgq %rdx, (%rdi) 2701.21Sad jnz 1f 2711.21Sad movl %edx, %eax /* nonzero */ 2721.32Smaxv RET 2731.21Sad1: 2741.21Sad jmp 0b 2751.13Sad 2761.13Sad /* 2771.13Sad * Writer: if the compare-and-set fails, don't bother retrying. 2781.13Sad */ 2791.13Sad2: movq CPUVAR(CURLWP), %rcx 2801.35Sad xorq %rax, %rax 2811.13Sad orq $RW_WRITE_LOCKED, %rcx 2821.32Smaxv LOCK 2831.21Sad cmpxchgq %rcx, (%rdi) 2841.18Sad movl $0, %eax 2851.13Sad setz %al 2861.22Sad3: 2871.32Smaxv RET 2881.13Sad ret 2891.22Sad4: 2901.22Sad xorl %eax, %eax 2911.22Sad jmp 3b 2921.25SuebayasiEND(rw_tryenter) 2931.13Sad 2941.2Sad#endif /* LOCKDEBUG */ 2951.2Sad 2961.2Sad/* 2971.11Sad * Spinlocks. 2981.2Sad */ 2991.19SchsENTRY(__cpu_simple_lock_init) 3001.11Sad movb $0, (%rdi) 3011.2Sad ret 3021.25SuebayasiEND(__cpu_simple_lock_init) 3031.2Sad 3041.29SmaxvENTRY(__cpu_simple_lock) 3051.11Sad movl $0x0100, %eax 3061.11Sad1: 3071.32Smaxv LOCK 3081.11Sad cmpxchgb %ah, (%rdi) 3091.11Sad jnz 2f 3101.32Smaxv RET 3111.11Sad2: 3121.11Sad movl $0x0100, %eax 3131.11Sad pause 3141.11Sad nop 3151.7Sad nop 3161.11Sad cmpb $0, (%rdi) 3171.11Sad je 1b 3181.11Sad jmp 2b 3191.25SuebayasiEND(__cpu_simple_lock) 3201.11Sad 3211.29SmaxvENTRY(__cpu_simple_unlock) 3221.11Sad movb $0, (%rdi) 3231.2Sad ret 3241.25SuebayasiEND(__cpu_simple_unlock) 3251.7Sad 3261.19SchsENTRY(__cpu_simple_lock_try) 3271.11Sad movl $0x0100, %eax 3281.32Smaxv LOCK 3291.11Sad cmpxchgb %ah, (%rdi) 3301.11Sad movl $0, %eax 3311.22Sad setz %al 3321.33Smaxv KMSAN_INIT_RET(4) 3331.32Smaxv RET 3341.25SuebayasiEND(__cpu_simple_lock_try) 3351.2Sad 336