1/*	$NetBSD: atomic.S,v 1.19 2011/01/12 23:12:10 joerg Exp $	*/
2
3/*-
4 * Copyright (c) 2007 The NetBSD Foundation, Inc.
5 * All rights reserved.
6 *
7 * This code is derived from software contributed to The NetBSD Foundation
8 * by Jason R. Thorpe, and 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#include <sys/param.h>
33#include <machine/asm.h>
34
35#ifdef _KERNEL
36#define	ALIAS(f, t)	STRONG_ALIAS(f,t)
37#else
38#define	ALIAS(f, t)	WEAK_ALIAS(f,t)
39#endif
40
41#ifdef _HARDKERNEL
42#define	LOCK(n)		.Lpatch ## n:	lock
43#define	ENDLABEL(a)	_ALIGN_TEXT; LABEL(a)
44#else
45#define	LOCK(n)		lock
46#define	ENDLABEL(a)	/* nothing */
47#endif
48
49	.text
50
51ENTRY(_atomic_add_32)
52	movl	4(%esp), %edx
53	movl	8(%esp), %eax
54	LOCK(1)
55	addl	%eax, (%edx)
56	ret
57
58ENTRY(_atomic_add_32_nv)
59	movl	4(%esp), %edx
60	movl	8(%esp), %eax
61	movl	%eax, %ecx
62	LOCK(2)
63	xaddl	%eax, (%edx)
64	addl	%ecx, %eax
65	ret
66
67ENTRY(_atomic_and_32)
68	movl	4(%esp), %edx
69	movl	8(%esp), %eax
70	LOCK(3)
71	andl	%eax, (%edx)
72	ret
73
74ENTRY(_atomic_and_32_nv)
75	movl	4(%esp), %edx
76	movl	(%edx), %eax
770:
78	movl	%eax, %ecx
79	andl	8(%esp), %ecx
80	LOCK(4)
81	cmpxchgl %ecx, (%edx)
82	jnz	1f
83	movl	%ecx, %eax
84	ret
851:
86	jmp	0b
87
88ENTRY(_atomic_dec_32)
89	movl	4(%esp), %edx
90	LOCK(5)
91	decl	(%edx)
92	ret
93
94ENTRY(_atomic_dec_32_nv)
95	movl	4(%esp), %edx
96	movl	$-1, %eax
97	LOCK(6)
98	xaddl	%eax, (%edx)
99	decl	%eax
100	ret
101
102ENTRY(_atomic_inc_32)
103	movl	4(%esp), %edx
104	LOCK(7)
105	incl	(%edx)
106	ret
107
108ENTRY(_atomic_inc_32_nv)
109	movl	4(%esp), %edx
110	movl	$1, %eax
111	LOCK(8)
112	xaddl	%eax, (%edx)
113	incl	%eax
114	ret
115
116ENTRY(_atomic_or_32)
117	movl	4(%esp), %edx
118	movl	8(%esp), %eax
119	LOCK(9)
120	orl	%eax, (%edx)
121	ret
122
123ENTRY(_atomic_or_32_nv)
124	movl	4(%esp), %edx
125	movl	(%edx), %eax
1260:
127	movl	%eax, %ecx
128	orl	8(%esp), %ecx
129	LOCK(10)
130	cmpxchgl %ecx, (%edx)
131	jnz	1f
132	movl	%ecx, %eax
133	ret
1341:
135	jmp	0b
136
137ENTRY(_atomic_swap_32)
138	movl	4(%esp), %edx
139	movl	8(%esp), %eax
140	xchgl	%eax, (%edx)
141	ret
142
143ENTRY(_atomic_cas_32)
144	movl	4(%esp), %edx
145	movl	8(%esp), %eax
146	movl	12(%esp), %ecx
147	LOCK(12)
148	cmpxchgl %ecx, (%edx)
149	/* %eax now contains the old value */
150	ret
151
152ENTRY(_atomic_cas_32_ni)
153	movl	4(%esp), %edx
154	movl	8(%esp), %eax
155	movl	12(%esp), %ecx
156	cmpxchgl %ecx, (%edx)
157	/* %eax now contains the old value */
158	ret
159
160ENTRY(_membar_consumer)
161	LOCK(13)
162	addl	$0, -4(%esp)
163	ret
164ENDLABEL(membar_consumer_end)
165
166ENTRY(_membar_producer)
167	/* A store is enough */
168	movl	$0, -4(%esp)
169	ret
170ENDLABEL(membar_producer_end)
171
172ENTRY(_membar_sync)
173	LOCK(14)
174	addl	$0, -4(%esp)
175	ret
176ENDLABEL(membar_sync_end)
177
178#ifdef _HARDKERNEL
179ENTRY(_atomic_cas_64)
180	pushf
181	cli
182	pushl	%edi
183	pushl	%ebx
184	movl	12(%esp), %edi
185	movl	16(%esp), %eax
186	movl	20(%esp), %edx
187	movl	24(%esp), %ebx
188	movl	28(%esp), %ecx
189	cmpl	0(%edi), %eax
190	jne	2f
191	cmpl	4(%edi), %edx
192	jne	2f
193	movl	%ebx, 0(%edi)
194	movl	%ecx, 4(%edi)
1951:
196	popl	%ebx
197	popl	%edi
198	popf
199	ret
2002:
201	movl	0(%edi), %eax
202	movl	4(%edi), %edx
203	jmp	1b
204ENDLABEL(_atomic_cas_64_end)
205
206ENTRY(_atomic_cas_cx8)
207	pushl	%edi
208	pushl	%ebx
209	movl	12(%esp), %edi
210	movl	16(%esp), %eax
211	movl	20(%esp), %edx
212	movl	24(%esp), %ebx
213	movl	28(%esp), %ecx
214	LOCK(15)
215	cmpxchg8b (%edi)
216	popl	%ebx
217	popl	%edi
218	ret
219#ifdef GPROF
220	.space	16, 0x90
221#else
222	.space	32, 0x90
223#endif
224ENDLABEL(_atomic_cas_cx8_end)
225
226ENTRY(sse2_lfence)
227	lfence
228	ret
229ENDLABEL(sse2_lfence_end)
230
231ENTRY(sse2_mfence)
232	mfence
233	ret
234ENDLABEL(sse2_mfence_end)
235
236atomic_lockpatch:
237	.globl	atomic_lockpatch
238	.long	.Lpatch1, .Lpatch2, .Lpatch3, .Lpatch4, .Lpatch5
239	.long	.Lpatch6, .Lpatch7, .Lpatch8, .Lpatch9, .Lpatch10
240	.long	.Lpatch12, .Lpatch13, .Lpatch14, .Lpatch15, 0
241#else
242ENTRY(_atomic_cas_64)
243	pushl	%edi
244	pushl	%ebx
245	movl	12(%esp), %edi
246	movl	16(%esp), %eax
247	movl	20(%esp), %edx
248	movl	24(%esp), %ebx
249	movl	28(%esp), %ecx
250	lock
251	cmpxchg8b (%edi)
252	popl	%ebx
253	popl	%edi
254	ret
255#endif	/* _HARDKERNEL */
256
257ALIAS(atomic_add_32,_atomic_add_32)
258ALIAS(atomic_add_int,_atomic_add_32)
259ALIAS(atomic_add_long,_atomic_add_32)
260ALIAS(atomic_add_ptr,_atomic_add_32)
261
262ALIAS(atomic_add_32_nv,_atomic_add_32_nv)
263ALIAS(atomic_add_int_nv,_atomic_add_32_nv)
264ALIAS(atomic_add_long_nv,_atomic_add_32_nv)
265ALIAS(atomic_add_ptr_nv,_atomic_add_32_nv)
266
267ALIAS(atomic_and_32,_atomic_and_32)
268ALIAS(atomic_and_uint,_atomic_and_32)
269ALIAS(atomic_and_ulong,_atomic_and_32)
270ALIAS(atomic_and_ptr,_atomic_and_32)
271
272ALIAS(atomic_and_32_nv,_atomic_and_32_nv)
273ALIAS(atomic_and_uint_nv,_atomic_and_32_nv)
274ALIAS(atomic_and_ulong_nv,_atomic_and_32_nv)
275ALIAS(atomic_and_ptr_nv,_atomic_and_32_nv)
276
277ALIAS(atomic_dec_32,_atomic_dec_32)
278ALIAS(atomic_dec_uint,_atomic_dec_32)
279ALIAS(atomic_dec_ulong,_atomic_dec_32)
280ALIAS(atomic_dec_ptr,_atomic_dec_32)
281
282ALIAS(atomic_dec_32_nv,_atomic_dec_32_nv)
283ALIAS(atomic_dec_uint_nv,_atomic_dec_32_nv)
284ALIAS(atomic_dec_ulong_nv,_atomic_dec_32_nv)
285ALIAS(atomic_dec_ptr_nv,_atomic_dec_32_nv)
286
287ALIAS(atomic_inc_32,_atomic_inc_32)
288ALIAS(atomic_inc_uint,_atomic_inc_32)
289ALIAS(atomic_inc_ulong,_atomic_inc_32)
290ALIAS(atomic_inc_ptr,_atomic_inc_32)
291
292ALIAS(atomic_inc_32_nv,_atomic_inc_32_nv)
293ALIAS(atomic_inc_uint_nv,_atomic_inc_32_nv)
294ALIAS(atomic_inc_ulong_nv,_atomic_inc_32_nv)
295ALIAS(atomic_inc_ptr_nv,_atomic_inc_32_nv)
296
297ALIAS(atomic_or_32,_atomic_or_32)
298ALIAS(atomic_or_uint,_atomic_or_32)
299ALIAS(atomic_or_ulong,_atomic_or_32)
300ALIAS(atomic_or_ptr,_atomic_or_32)
301
302ALIAS(atomic_or_32_nv,_atomic_or_32_nv)
303ALIAS(atomic_or_uint_nv,_atomic_or_32_nv)
304ALIAS(atomic_or_ulong_nv,_atomic_or_32_nv)
305ALIAS(atomic_or_ptr_nv,_atomic_or_32_nv)
306
307ALIAS(atomic_swap_32,_atomic_swap_32)
308ALIAS(atomic_swap_uint,_atomic_swap_32)
309ALIAS(atomic_swap_ulong,_atomic_swap_32)
310ALIAS(atomic_swap_ptr,_atomic_swap_32)
311
312ALIAS(atomic_cas_32,_atomic_cas_32)
313ALIAS(atomic_cas_uint,_atomic_cas_32)
314ALIAS(atomic_cas_ulong,_atomic_cas_32)
315ALIAS(atomic_cas_ptr,_atomic_cas_32)
316
317ALIAS(atomic_cas_32_ni,_atomic_cas_32_ni)
318ALIAS(atomic_cas_uint_ni,_atomic_cas_32_ni)
319ALIAS(atomic_cas_ulong_ni,_atomic_cas_32_ni)
320ALIAS(atomic_cas_ptr_ni,_atomic_cas_32_ni)
321
322ALIAS(atomic_cas_64,_atomic_cas_64)
323ALIAS(atomic_cas_64_ni,_atomic_cas_64)
324
325ALIAS(membar_consumer,_membar_consumer)
326ALIAS(membar_producer,_membar_producer)
327ALIAS(membar_enter,_membar_consumer)
328ALIAS(membar_exit,_membar_producer)
329ALIAS(membar_sync,_membar_sync)
330
331STRONG_ALIAS(_atomic_add_int,_atomic_add_32)
332STRONG_ALIAS(_atomic_add_long,_atomic_add_32)
333STRONG_ALIAS(_atomic_add_ptr,_atomic_add_32)
334
335STRONG_ALIAS(_atomic_add_int_nv,_atomic_add_32_nv)
336STRONG_ALIAS(_atomic_add_long_nv,_atomic_add_32_nv)
337STRONG_ALIAS(_atomic_add_ptr_nv,_atomic_add_32_nv)
338
339STRONG_ALIAS(_atomic_and_uint,_atomic_and_32)
340STRONG_ALIAS(_atomic_and_ulong,_atomic_and_32)
341STRONG_ALIAS(_atomic_and_ptr,_atomic_and_32)
342
343STRONG_ALIAS(_atomic_and_uint_nv,_atomic_and_32_nv)
344STRONG_ALIAS(_atomic_and_ulong_nv,_atomic_and_32_nv)
345STRONG_ALIAS(_atomic_and_ptr_nv,_atomic_and_32_nv)
346
347STRONG_ALIAS(_atomic_dec_uint,_atomic_dec_32)
348STRONG_ALIAS(_atomic_dec_ulong,_atomic_dec_32)
349STRONG_ALIAS(_atomic_dec_ptr,_atomic_dec_32)
350
351STRONG_ALIAS(_atomic_dec_uint_nv,_atomic_dec_32_nv)
352STRONG_ALIAS(_atomic_dec_ulong_nv,_atomic_dec_32_nv)
353STRONG_ALIAS(_atomic_dec_ptr_nv,_atomic_dec_32_nv)
354
355STRONG_ALIAS(_atomic_inc_uint,_atomic_inc_32)
356STRONG_ALIAS(_atomic_inc_ulong,_atomic_inc_32)
357STRONG_ALIAS(_atomic_inc_ptr,_atomic_inc_32)
358
359STRONG_ALIAS(_atomic_inc_uint_nv,_atomic_inc_32_nv)
360STRONG_ALIAS(_atomic_inc_ulong_nv,_atomic_inc_32_nv)
361STRONG_ALIAS(_atomic_inc_ptr_nv,_atomic_inc_32_nv)
362
363STRONG_ALIAS(_atomic_or_uint,_atomic_or_32)
364STRONG_ALIAS(_atomic_or_ulong,_atomic_or_32)
365STRONG_ALIAS(_atomic_or_ptr,_atomic_or_32)
366
367STRONG_ALIAS(_atomic_or_uint_nv,_atomic_or_32_nv)
368STRONG_ALIAS(_atomic_or_ulong_nv,_atomic_or_32_nv)
369STRONG_ALIAS(_atomic_or_ptr_nv,_atomic_or_32_nv)
370
371STRONG_ALIAS(_atomic_swap_uint,_atomic_swap_32)
372STRONG_ALIAS(_atomic_swap_ulong,_atomic_swap_32)
373STRONG_ALIAS(_atomic_swap_ptr,_atomic_swap_32)
374
375STRONG_ALIAS(_atomic_cas_uint,_atomic_cas_32)
376STRONG_ALIAS(_atomic_cas_ulong,_atomic_cas_32)
377STRONG_ALIAS(_atomic_cas_ptr,_atomic_cas_32)
378
379STRONG_ALIAS(_atomic_cas_uint_ni,_atomic_cas_32_ni)
380STRONG_ALIAS(_atomic_cas_ulong_ni,_atomic_cas_32_ni)
381STRONG_ALIAS(_atomic_cas_ptr_ni,_atomic_cas_32_ni)
382
383STRONG_ALIAS(_membar_enter,_membar_consumer)
384STRONG_ALIAS(_membar_exit,_membar_producer)
385