Annotation of src/sys/arch/i386/i386/lock_stubs.S, Revision 1.2.8.7
1.2.8.7 ! ad 1: /* $NetBSD: lock_stubs.S,v 1.2.8.6 2007/12/03 18:36:42 ad Exp $ */
1.2 ad 2:
3: /*-
4: * Copyright (c) 2006, 2007 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: * 3. All advertising materials mentioning features or use of this software
19: * must display the following acknowledgement:
20: * This product includes software developed by the NetBSD
21: * Foundation, Inc. and its contributors.
22: * 4. Neither the name of The NetBSD Foundation nor the names of its
23: * contributors may be used to endorse or promote products derived
24: * from this software without specific prior written permission.
25: *
26: * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
27: * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
28: * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
29: * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
30: * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
31: * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
32: * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
33: * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
34: * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
35: * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
36: * POSSIBILITY OF SUCH DAMAGE.
37: */
38:
39: /*
40: * The sizes listed against each function are for a kernel compiled
1.2.8.6 ad 41: * with options MULTIPROCESSOR && DIAGNOSTIC. Where possible we make
42: * each routine fit into an assumed 64-byte cache line. Please check
43: * alignment with 'objdump -d' after making changes.
1.2 ad 44: */
45:
46: #include "opt_multiprocessor.h"
47: #include "opt_lockdebug.h"
48: #include "opt_ddb.h"
49:
50: #include <machine/asm.h>
51: #include <machine/cputypes.h>
52:
53: #include "assym.h"
54:
1.2.8.7 ! ad 55: #if defined(DIAGNOSTIC) || defined(MULTIPROCESSOR) || defined(LOCKDEBUG)
! 56: #define FULL
! 57: #endif
! 58:
1.2 ad 59: #define ALIGN64 .align 64
60: #define ALIGN32 .align 32
1.2.8.6 ad 61: #define LOCK(name) LABEL(name) lock
1.2 ad 62: #define END(name,a) .align a; LABEL(name)
63:
64: #if !defined(LOCKDEBUG)
65:
66: /*
67: * void mutex_enter(kmutex_t *mtx);
68: *
69: * Acquire a mutex and post a load fence.
70: */
71: ALIGN64
72:
1.2.8.6 ad 73: ENTRY(mutex_enter)
74: movl 4(%esp), %edx
1.2 ad 75: movl CPUVAR(CURLWP), %ecx
76: xorl %eax, %eax
1.2.8.6 ad 77: LOCK(lockpatch1)
1.2 ad 78: cmpxchgl %ecx, MTX_OWNER(%edx)
79: jnz,pn _C_LABEL(mutex_vector_enter)
80: ret
81:
82: /*
83: * void mutex_exit(kmutex_t *mtx);
84: *
85: * Release a mutex and post a load fence.
86: *
87: * See comments in mutex_vector_enter() about doing this operation unlocked
88: * on multiprocessor systems, and comments in arch/x86/include/lock.h about
89: * memory ordering on Intel x86 systems.
90: */
1.2.8.6 ad 91: ENTRY(mutex_exit)
92: movl 4(%esp), %edx
1.2 ad 93: movl CPUVAR(CURLWP), %eax
94: xorl %ecx, %ecx
95: cmpxchgl %ecx, MTX_OWNER(%edx)
96: jnz,pn _C_LABEL(mutex_vector_exit)
97: ret
98:
99: /*
100: * void rw_enter(krwlock_t *rwl, krw_t op);
101: *
102: * Acquire one hold on a RW lock.
103: */
1.2.8.6 ad 104: ENTRY(rw_enter)
105: movl 4(%esp), %edx
1.2 ad 106: cmpl $RW_READER, 8(%esp)
107: jne 2f
108:
109: /*
110: * Reader
111: */
112: 1: movl RW_OWNER(%edx), %eax
113: testb $(RW_WRITE_LOCKED|RW_WRITE_WANTED), %al
114: leal RW_READ_INCR(%eax), %ecx
115: jnz,pn _C_LABEL(rw_vector_enter)
1.2.8.6 ad 116: LOCK(lockpatch2)
1.2 ad 117: cmpxchgl %ecx, RW_OWNER(%edx)
118: jnz,pn 1b
119: ret
120:
121: /*
122: * Writer
123: */
124: 2: movl CPUVAR(CURLWP), %ecx
125: xorl %eax, %eax
126: orl $RW_WRITE_LOCKED, %ecx
1.2.8.6 ad 127: LOCK(lockpatch3)
1.2 ad 128: cmpxchgl %ecx, RW_OWNER(%edx)
129: jnz,pn _C_LABEL(rw_vector_enter)
130: ret
131:
132: /*
133: * void rw_exit(krwlock_t *rwl);
134: *
135: * Release one hold on a RW lock.
136: */
1.2.8.6 ad 137: ENTRY(rw_exit)
138: movl 4(%esp), %edx
1.2 ad 139: movl RW_OWNER(%edx), %eax
140: testb $RW_WRITE_LOCKED, %al
141: jnz 2f
142:
143: /*
144: * Reader
145: */
146: 1: testb $RW_HAS_WAITERS, %al
147: jnz,pn 3f
148: cmpl $RW_READ_INCR, %eax
149: leal -RW_READ_INCR(%eax), %ecx
150: jb,pn 3f
1.2.8.6 ad 151: LOCK(lockpatch4)
1.2 ad 152: cmpxchgl %ecx, RW_OWNER(%edx)
153: jnz,pn 1b
154: ret
155:
156: /*
157: * Writer
158: */
159: 2: leal -RW_WRITE_LOCKED(%eax), %ecx
160: subl CPUVAR(CURLWP), %ecx
161: jnz,pn 3f
1.2.8.6 ad 162: LOCK(lockpatch5)
1.2 ad 163: cmpxchgl %ecx, RW_OWNER(%edx)
164: jnz,pn 3f
165: ret
166:
167: /*
168: * Slow path.
169: */
170: 3: jmp _C_LABEL(rw_vector_exit)
171:
172: #ifndef __XEN__
173:
174: /*
175: * void mutex_spin_enter(kmutex_t *mtx);
176: *
177: * Acquire a spin mutex and post a load fence.
178: */
1.2.8.7 ! ad 179: ENTRY(mutex_spin_enter)
! 180: movl 4(%esp), %edx
! 181: movl CPUVAR(ILEVEL), %ecx
! 182: subl $1, CPUVAR(MTX_COUNT) /* decl does not set CF */
1.2 ad 183: jnc 1f
1.2.8.7 ! ad 184: movl %ecx, CPUVAR(MTX_OLDSPL)
1.2 ad 185: 1: movb MTX_IPL(%edx), %ch
186: cmpb %ch, %cl
187: jg,pn 2f
1.2.8.7 ! ad 188: movb %ch, CPUVAR(ILEVEL) /* splraiseipl() */
1.2 ad 189: 2:
1.2.8.7 ! ad 190: #ifdef FULL
1.2 ad 191: mov $0x0100, %eax /* new + expected value */
1.2.8.7 ! ad 192: LOCK(lockpatch11)
1.2 ad 193: cmpxchgb %ah, MTX_LOCK(%edx) /* lock it */
194: jnz,pn _C_LABEL(mutex_spin_retry)
1.2.8.7 ! ad 195: #endif
1.2 ad 196: ret
197:
198: ALIGN64
199: LABEL(mutex_spin_enter_end)
200:
201: /*
202: * Release a spin mutex and post a store fence.
203: */
1.2.8.7 ! ad 204: ENTRY(mutex_spin_exit)
! 205: movl 4(%esp), %edx
! 206: movl CPUVAR(MTX_OLDSPL), %ecx
! 207: incl CPUVAR(MTX_COUNT)
! 208: movb $0, MTX_LOCK(%edx) /* zero */
1.2 ad 209: jnz 1f
1.2.8.7 ! ad 210: movl %fs:CPU_INFO_IUNMASK(,%ecx,4), %edx
1.2 ad 211: cli
1.2.8.7 ! ad 212: testl CPUVAR(IPENDING), %edx
! 213: movl %ecx, 4(%esp)
1.2 ad 214: jnz _C_LABEL(Xspllower) /* does sti */
1.2.8.7 ! ad 215: movl %ecx, CPUVAR(ILEVEL)
1.2 ad 216: sti
217: 1: ret
1.2.8.4 ad 218: nop /* XXX round up */
219: .align 32
1.2 ad 220: LABEL(mutex_spin_exit_end)
221:
222: /*
223: * Patch for i686 CPUs where cli/sti is prohibitavely expensive.
224: * Must be the same size as mutex_spin_exit().
225: */
1.2.8.2 ad 226: ENTRY(i686_mutex_spin_exit)
1.2 ad 227: mov 4(%esp),%edx
1.2.8.6 ad 228: movl CPUVAR(MTX_OLDSPL), %ecx
229: incl CPUVAR(MTX_COUNT)
230: movb %ch, MTX_LOCK(%edx) /* zero */
1.2 ad 231: jnz 1f
1.2.8.6 ad 232: pushl %ebx
1.2.8.1 ad 233: 0:
1.2.8.6 ad 234: movl CPUVAR(IPENDING), %eax
235: testl %eax, %fs:CPU_INFO_IUNMASK(,%ecx,4)
1.2 ad 236: movl %eax, %ebx
237: /*
238: * On a P4 this jump is cheaper than patching in junk using
239: * cmovnz. Is cmpxchg expensive if it fails?
240: */
1.2.8.6 ad 241: jnz 2f
242: cmpxchg8b CPUVAR(ISTATE) /* swap in new ilevel */
243: jnz 0b
1.2 ad 244: popl %ebx
1.2.8.6 ad 245: 1:
1.2 ad 246: ret
247: 2:
248: popl %ebx
249: movl %ecx,4(%esp)
250: LABEL(i686_mutex_spin_exit_patch)
251: jmp _C_LABEL(Xspllower)
1.2.8.3 ad 252: .align 32
1.2 ad 253: LABEL(i686_mutex_spin_exit_end)
254:
255: #else /* !__XEN__ */
256:
257: /* For now; strong alias not working for some reason. */
1.2.8.5 ad 258: ENTRY(mutex_spin_enter)
1.2 ad 259: jmp _C_LABEL(mutex_vector_enter)
260:
1.2.8.5 ad 261: ENTRY(mutex_spin_exit)
1.2 ad 262: jmp _C_LABEL(mutex_vector_exit)
263:
264: #endif /* !__XEN__ */
265:
266: #endif /* !LOCKDEBUG */
267:
268: /*
269: * int _lock_cas(uintptr_t *val, uintptr_t old, uintptr_t new);
270: *
271: * Perform an atomic compare-and-set operation.
272: */
1.2.8.6 ad 273: ENTRY(_lock_cas)
274: mov 4(%esp),%edx
1.2 ad 275: movl 8(%esp), %eax
276: movl 12(%esp), %ecx
1.2.8.6 ad 277: LOCK(lockpatch6)
1.2 ad 278: cmpxchgl %ecx, (%edx)
279: movl $0, %eax
280: setz %al
281: ret
282:
283: /*
284: * Memory barrier operations, may be patched at runtime.
285: */
286: .align 8
287:
1.2.8.5 ad 288: ENTRY(mb_read)
1.2.8.6 ad 289: LOCK(lockpatch7)
1.2 ad 290: addl $0, 0(%esp)
291: ret
292: END(mb_read_end, 8)
293:
1.2.8.5 ad 294: ENTRY(mb_write)
1.2.8.6 ad 295: nop
1.2 ad 296: ret
297: END(mb_write_end, 8)
298:
1.2.8.5 ad 299: ENTRY(mb_memory)
1.2.8.6 ad 300: LOCK(lockpatch8)
1.2 ad 301: addl $0, 0(%esp)
302: ret
303: END(mb_memory_end, 8)
304:
1.2.8.5 ad 305: ENTRY(sse2_mb_read)
1.2 ad 306: lfence
307: ret
308: END(sse2_mb_read_end, 8)
309:
1.2.8.5 ad 310: ENTRY(sse2_mb_memory)
1.2 ad 311: mfence
312: ret
313: END(sse2_mb_memory_end, 8)
314:
315: /*
1.2.8.6 ad 316: * Patchpoints to replace with NOP when ncpu == 1.
1.2 ad 317: */
1.2.8.6 ad 318: #ifndef LOCKDEBUG
319: LABEL(x86_lockpatch)
320: .long lockpatch1, lockpatch2, lockpatch3, lockpatch4
321: .long lockpatch5, lockpatch6, lockpatch7, lockpatch8
322: #if defined(FULL) && !defined(__XEN__)
323: .long lockpatch11
324: #endif
325: .long 0
326: #endif
CVSweb <webmaster@jp.NetBSD.org>