1/* $NetBSD: lock_stubs.S,v 1.38 2022/09/08 06:57:44 knakahara Exp $ */ 2 3/*- 4 * Copyright (c) 2006, 2007, 2008, 2009 The NetBSD Foundation, Inc. 5 * All rights reserved. 6 * 7 * This code is derived from software contributed to The NetBSD Foundation 8 * by Andrew Doran. 9 * 10 * Redistribution and use in source and binary forms, with or without 11 * modification, are permitted provided that the following conditions 12 * are met: 13 * 1. Redistributions of source code must retain the above copyright 14 * notice, this list of conditions and the following disclaimer. 15 * 2. Redistributions in binary form must reproduce the above copyright 16 * notice, this list of conditions and the following disclaimer in the 17 * documentation and/or other materials provided with the distribution. 18 * 19 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 20 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 21 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 22 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 23 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 24 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 25 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 26 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 27 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 28 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 29 * POSSIBILITY OF SUCH DAMAGE. 30 */ 31 32/* 33 * Where possible we make each routine fit into an assumed 64-byte cache 34 * line. Please check alignment with 'objdump -d' after making changes. 35 */ 36 37#include <machine/asm.h> 38__KERNEL_RCSID(0, "$NetBSD: lock_stubs.S,v 1.38 2022/09/08 06:57:44 knakahara Exp $"); 39 40#include "opt_lockdebug.h" 41 42#include <machine/cputypes.h> 43#include <machine/frameasm.h> 44 45#include "assym.h" 46 47#define ALIGN64 .align 64 48#define ALIGN32 .align 32 49#define LOCK(num) \ 50 HOTPATCH(HP_NAME_NOLOCK, 1) ; \ 51 lock 52#define RET(num) \ 53 HOTPATCH(HP_NAME_RETFENCE, 3) ; \ 54 ret; nop; nop ; \ 55 ret 56 57#define ENDLABEL(name,a) .align a; LABEL(name) 58 59#if !defined(LOCKDEBUG) 60 61/* 62 * void mutex_enter(kmutex_t *mtx); 63 * 64 * Acquire a mutex and post a load fence. 65 */ 66 ALIGN64 67 68ENTRY(mutex_enter) 69 movl 4(%esp), %edx 70 xorl %eax, %eax 71 movl %fs:CPU_INFO_CURLWP(%eax), %ecx 72 LOCK(1) 73 cmpxchgl %ecx, (%edx) 74 jnz 1f 75 RET(1) 761: 77 jmp _C_LABEL(mutex_vector_enter) 78END(mutex_enter) 79 80/* 81 * void mutex_exit(kmutex_t *mtx); 82 * 83 * Release a mutex and post a load fence. 84 * 85 * See comments in mutex_vector_enter() about doing this operation unlocked 86 * on multiprocessor systems, and comments in arch/x86/include/lock.h about 87 * memory ordering on Intel x86 systems. 88 */ 89ENTRY(mutex_exit) 90 movl 4(%esp), %edx 91 xorl %ecx, %ecx 92 movl %fs:CPU_INFO_CURLWP(%ecx), %eax 93 cmpxchgl %ecx, (%edx) 94 jnz 1f 95 ret 961: 97 jmp _C_LABEL(mutex_vector_exit) 98END(mutex_exit) 99 100/* 101 * void rw_enter(krwlock_t *rwl, krw_t op); 102 * 103 * Acquire one hold on a RW lock. 104 */ 105ENTRY(rw_enter) 106 movl 4(%esp), %edx 107 cmpl $RW_READER, 8(%esp) 108 jne 2f 109 110 /* 111 * Reader 112 */ 113 movl (%edx), %eax 1140: 115 testb $(RW_WRITE_LOCKED|RW_WRITE_WANTED), %al 116 jnz 3f 117 leal RW_READ_INCR(%eax), %ecx 118 LOCK(2) 119 cmpxchgl %ecx, (%edx) 120 jnz 1f 121 RET(2) 1221: 123 jmp 0b 124 125 /* 126 * Writer 127 */ 1282: xorl %eax, %eax 129 movl %fs:CPU_INFO_CURLWP(%eax), %ecx 130 orl $RW_WRITE_LOCKED, %ecx 131 LOCK(3) 132 cmpxchgl %ecx, (%edx) 133 jnz 3f 134 RET(3) 1353: 136 jmp _C_LABEL(rw_vector_enter) 137END(rw_enter) 138 139/* 140 * void rw_exit(krwlock_t *rwl); 141 * 142 * Release one hold on a RW lock. 143 */ 144ENTRY(rw_exit) 145 movl 4(%esp), %edx 146 movl (%edx), %eax 147 testb $RW_WRITE_LOCKED, %al 148 jnz 2f 149 150 /* 151 * Reader 152 */ 1530: testb $RW_HAS_WAITERS, %al 154 jnz 3f 155 cmpl $RW_READ_INCR, %eax 156 jb 3f 157 leal -RW_READ_INCR(%eax), %ecx 158 LOCK(4) 159 cmpxchgl %ecx, (%edx) 160 jnz 1f 161 ret 1621: 163 jmp 0b 164 165 /* 166 * Writer 167 */ 1682: leal -RW_WRITE_LOCKED(%eax), %ecx 169 subl CPUVAR(CURLWP), %ecx 170 jnz 3f 171 LOCK(5) 172 cmpxchgl %ecx, (%edx) 173 jnz 3f 174 ret 175 176 /* 177 * Slow path. 178 */ 1793: jmp _C_LABEL(rw_vector_exit) 180END(rw_exit) 181 182/* 183 * int rw_tryenter(krwlock_t *rwl, krw_t op); 184 * 185 * Try to acquire one hold on a RW lock. 186 */ 187ENTRY(rw_tryenter) 188 movl 4(%esp), %edx 189 cmpl $RW_READER, 8(%esp) 190 jne 2f 191 192 /* 193 * Reader 194 */ 195 movl (%edx), %eax 1960: 197 testb $(RW_WRITE_LOCKED|RW_WRITE_WANTED), %al 198 jnz 4f 199 leal RW_READ_INCR(%eax), %ecx 200 LOCK(12) 201 cmpxchgl %ecx, (%edx) 202 jnz 1f 203 movl %edx, %eax /* nonzero */ 204 RET(4) 2051: 206 jmp 0b 207 208 /* 209 * Writer 210 */ 2112: 212 xorl %eax, %eax 213 movl %fs:CPU_INFO_CURLWP(%eax), %ecx 214 orl $RW_WRITE_LOCKED, %ecx 215 LOCK(13) 216 cmpxchgl %ecx, (%edx) 217 movl $0, %eax 218 setz %al 2193: 220 RET(5) 2214: 222 xorl %eax, %eax 223 jmp 3b 224END(rw_tryenter) 225 226 227/* 228 * void mutex_spin_enter(kmutex_t *mtx); 229 * 230 * Acquire a spin mutex and post a load fence. 231 */ 232ENTRY(mutex_spin_enter) 233 movl 4(%esp), %edx 234 movb CPUVAR(ILEVEL), %cl 235 movb MTX_IPL(%edx), %ch 236 movl $0x01, %eax 237 cmpb %ch, %cl 238 jg 1f 239 movb %ch, CPUVAR(ILEVEL) /* splraiseipl() */ 2401: 241 subl %eax, CPUVAR(MTX_COUNT) /* decl does not set CF */ 242 jnc 2f 243 movb %cl, CPUVAR(MTX_OLDSPL) 2442: 245 xchgb %al, MTX_LOCK(%edx) /* lock it */ 246 testb %al, %al 247 jnz 3f 248 RET(6) 2493: 250 jmp _C_LABEL(mutex_spin_retry) 251 252 ALIGN64 253LABEL(mutex_spin_enter_end) 254END(mutex_spin_enter) 255 256#ifndef XENPV 257/* 258 * Release a spin mutex and post a store fence. Must occupy 128 bytes. 259 */ 260ENTRY(mutex_spin_exit) 261 HOTPATCH(HP_NAME_MUTEX_EXIT, 128) 262 movl 4(%esp), %edx 263 movl CPUVAR(MTX_OLDSPL), %ecx 264 incl CPUVAR(MTX_COUNT) 265 movb $0, MTX_LOCK(%edx) /* zero */ 266 jnz 1f 267 movl CPUVAR(IUNMASK)(,%ecx,8), %edx 268 movl CPUVAR(IUNMASK)+4(,%ecx,8), %eax 269 cli 270 testl CPUVAR(IPENDING), %edx 271 movl %ecx, 4(%esp) 272 jnz _C_LABEL(Xspllower) /* does sti */ 273 testl CPUVAR(IPENDING)+4, %eax 274 jnz _C_LABEL(Xspllower) /* does sti */ 275 movb %cl, CPUVAR(ILEVEL) 276 sti 2771: ret 278 .space 32, 0xCC 279 .align 32 280END(mutex_spin_exit) 281#else /* XENPV */ 282STRONG_ALIAS(mutex_spin_exit, i686_mutex_spin_exit) 283#endif /* !XENPV */ 284 285/* 286 * Patch for i686 CPUs where cli/sti is prohibitively expensive. 287 * Must be the same size as mutex_spin_exit(), that is, 128 bytes. 288 */ 289ENTRY(i686_mutex_spin_exit) 290 mov 4(%esp),%edx 291 movl CPUVAR(MTX_OLDSPL), %ecx 292 incl CPUVAR(MTX_COUNT) 293 movb $0, MTX_LOCK(%edx) /* zero */ 294 jnz 1f 295 pushl %ebx 296 pushl %esi 297 pushl %edi 298 movl %ecx, %esi 299 movl %ecx, %edi 300 shll $24, %edi 3010: 302 movl CPUVAR(IPENDING), %eax 303 testl %eax, CPUVAR(IUNMASK)(,%esi,8) 304 jnz 2f 305 movl CPUVAR(IPENDING)+4, %edx 306 testl %edx, CPUVAR(IUNMASK)+4(,%esi,8) 307 jnz 2f 308 movl %eax, %ebx 309 movl %edx, %ecx 310 andl $0x00ffffff, %ecx 311 orl %edi, %ecx 312 cmpxchg8b CPUVAR(ISTATE) /* swap in new ilevel */ 313 jnz 0b 314 popl %edi 315 popl %esi 316 popl %ebx 3171: 318 ret 3192: 320 movl %esi,%ecx 321 popl %edi 322 popl %esi 323 popl %ebx 324 movl %ecx,4(%esp) 325 326 /* The reference must be absolute, hence the indirect jump. */ 327 movl $Xspllower,%eax 328 jmp *%eax 329 330 .space 16, 0xCC 331 .align 32 332LABEL(i686_mutex_spin_exit_end) 333END(i686_mutex_spin_exit) 334 335#endif /* !LOCKDEBUG */ 336 337/* 338 * Spinlocks. 339 */ 340ENTRY(__cpu_simple_lock_init) 341 movl 4(%esp), %edx 342 movb $0, (%edx) 343 ret 344END(__cpu_simple_lock_init) 345 346ENTRY(__cpu_simple_lock) 347 movl 4(%esp), %edx 348 movl $0x0100, %eax 3491: 350 LOCK(6) 351 cmpxchgb %ah, (%edx) 352 jnz 2f 353 RET(7) 3542: 355 movl $0x0100, %eax 356 pause 357 nop 358 nop 359 cmpb $0, (%edx) 360 je 1b 361 jmp 2b 362END(__cpu_simple_lock) 363 364ENTRY(__cpu_simple_unlock) 365 movl 4(%esp), %edx 366 movb $0, (%edx) 367 ret 368END(__cpu_simple_unlock) 369 370ENTRY(__cpu_simple_lock_try) 371 movl 4(%esp), %edx 372 movl $0x0100, %eax 373 LOCK(7) 374 cmpxchgb %ah, (%edx) 375 movl $0, %eax 376 setz %al 377 RET(8) 378END(__cpu_simple_lock_try) 379 380