]> git.saurik.com Git - apple/libc.git/blame - x86_64/sys/OSAtomic.s
Libc-825.24.tar.gz
[apple/libc.git] / x86_64 / sys / OSAtomic.s
CommitLineData
8e029c65 1/*
224c7076 2 * Copyright (c) 2007 Apple Inc. All rights reserved.
8e029c65
A
3 * Copyright (c) 2004-2006 Apple Computer, Inc. All rights reserved.
4 *
5 * @APPLE_LICENSE_HEADER_START@
6 *
7 * This file contains Original Code and/or Modifications of Original Code
8 * as defined in and that are subject to the Apple Public Source License
9 * Version 2.0 (the 'License'). You may not use this file except in
10 * compliance with the License. Please obtain a copy of the License at
11 * http://www.opensource.apple.com/apsl/ and read it before using this
12 * file.
13 *
14 * The Original Code and all software distributed under the License are
15 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
16 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
17 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
18 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
19 * Please see the License for the specific language governing rights and
20 * limitations under the License.
21 *
22 * @APPLE_LICENSE_HEADER_END@
23 */
24
25#include <machine/cpu_capabilities.h>
ad3c9f2a
A
26#include "platfunc.h"
27#include <architecture/i386/asm_help.h>
8e029c65
A
28
29#define DECLARE(x) \
1f2f436a
A
30 .align 2, 0x90 ; \
31 .globl x ; \
32 .globl x ## Barrier ; \
8e029c65
A
33x: ; \
34x ## Barrier:
35
36.text
37
1f2f436a
A
38#define ATOMIC_UP 0
39#define ATOMIC_MP 1
40#define ATOMIC_RET_ORIG 0
41#define ATOMIC_RET_NEW 1
42
43// compare and exchange 32-bit
44// xchg32 <new> <dst> <mp>
45.macro xchg32
46 .if $2 == ATOMIC_MP
47 lock
48 .endif
49 cmpxchgl $0, ($1)
50.endm
51
52// xchg64 <new> <dst> <mp>
53.macro xchg64
54 .if $2 == ATOMIC_MP
55 lock
56 .endif
57 cmpxchg $0, ($1)
58.endm
59
60#define ATOMIC_ARITHMETIC(instr, orig, mp) \
61 movl (%rsi), %eax /* get 2nd arg -> eax */ ;\
621: movl %eax, %edx /* copy value to new reg */ ;\
63 instr %edi, %edx /* apply instr to %edx with arg2 */ ;\
64 xchg32 %edx, %rsi, mp /* do the compare swap (see macro above) */ ;\
65 jnz 1b /* jump if failed */ ;\
66 .if orig == 1 /* to return the new value, overwrite eax */ ;\
67 movl %edx, %eax /* return the new value */ ;\
68 .endif
69
70// Used in OSAtomicTestAndSet( uint32_t n, void *value ), assumes ABI parameter loctions
71// Manpage says bit to test/set is (0x80 >> (n & 7)) of byte (addr + (n >> 3))
72#define ATOMIC_BIT_OP(instr, mp) \
73 xorl $7, %edi /* bit position is numbered big endian so convert to little endian */ ;\
74 shlq $3, %rsi ;\
75 addq %rdi, %rsi /* generate bit address */ ;\
76 movq %rsi, %rdi ;\
77 andq $31, %rdi /* keep bit offset in range 0..31 */ ;\
78 xorq %rdi, %rsi /* 4-byte align address */ ;\
79 shrq $3, %rsi /* get 4-byte aligned address */ ;\
80 .if mp == ATOMIC_MP /* don't plant the lock in UP code */ ;\
81 lock /* lock the bit test */ ;\
82 .endif ;\
83 instr %edi, (%rsi) /* do the bit test, supplied into the macro */ ;\
84 setc %al ;\
85 movzbl %al,%eax /* widen in case caller assumes we return an int */
8e029c65
A
86
87// uint32_t OSAtomicAnd32( uint32_t mask, uint32_t *value);
1f2f436a
A
88PLATFUNC_FUNCTION_START(OSAtomicAnd32, up, 64, 2)
89PLATFUNC_FUNCTION_START(OSAtomicAnd32Barrier, up, 64, 2)
90 ATOMIC_ARITHMETIC(andl, ATOMIC_RET_NEW, ATOMIC_UP)
91 ret
92
93PLATFUNC_FUNCTION_START_GENERIC(OSAtomicAnd32, mp, 64, 2)
94PLATFUNC_FUNCTION_START_GENERIC(OSAtomicAnd32Barrier, mp, 64, 2)
95 ATOMIC_ARITHMETIC(andl, ATOMIC_RET_NEW, ATOMIC_MP)
8e029c65 96 ret
8e029c65
A
97
98// uint32_t OSAtomicOr32( uint32_t mask, uint32_t *value);
1f2f436a
A
99PLATFUNC_FUNCTION_START(OSAtomicOr32, up, 64, 2)
100PLATFUNC_FUNCTION_START(OSAtomicOr32Barrier, up, 64, 2)
101 ATOMIC_ARITHMETIC(orl, ATOMIC_RET_NEW, ATOMIC_UP)
8e029c65
A
102 ret
103
1f2f436a
A
104PLATFUNC_FUNCTION_START_GENERIC(OSAtomicOr32, mp, 64, 2)
105PLATFUNC_FUNCTION_START_GENERIC(OSAtomicOr32Barrier, mp, 64, 2)
106 ATOMIC_ARITHMETIC(orl, ATOMIC_RET_NEW, ATOMIC_MP)
107 ret
8e029c65
A
108
109// uint32_t OSAtomicXor32( uint32_t mask, uint32_t *value);
1f2f436a
A
110PLATFUNC_FUNCTION_START(OSAtomicXor32, up, 64, 2)
111PLATFUNC_FUNCTION_START(OSAtomicXor32Barrier, up, 64, 2)
112 ATOMIC_ARITHMETIC(xorl, ATOMIC_RET_NEW, ATOMIC_UP)
8e029c65
A
113 ret
114
1f2f436a
A
115PLATFUNC_FUNCTION_START_GENERIC(OSAtomicXor32, mp, 64, 2)
116PLATFUNC_FUNCTION_START_GENERIC(OSAtomicXor32Barrier, mp, 64, 2)
117 ATOMIC_ARITHMETIC(xorl, ATOMIC_RET_NEW, ATOMIC_MP)
118 ret
8e029c65 119
224c7076 120// uint32_t OSAtomicAnd32Orig( uint32_t mask, uint32_t *value);
1f2f436a
A
121PLATFUNC_FUNCTION_START(OSAtomicAnd32Orig, up, 64, 2)
122PLATFUNC_FUNCTION_START(OSAtomicAnd32OrigBarrier, up, 64, 2)
123 ATOMIC_ARITHMETIC(andl, ATOMIC_RET_ORIG, ATOMIC_UP)
224c7076
A
124 ret
125
1f2f436a
A
126PLATFUNC_FUNCTION_START_GENERIC(OSAtomicAnd32Orig, mp, 64, 2)
127PLATFUNC_FUNCTION_START_GENERIC(OSAtomicAnd32OrigBarrier, mp, 64, 2)
128 ATOMIC_ARITHMETIC(andl, ATOMIC_RET_ORIG, ATOMIC_MP)
224c7076
A
129 ret
130
1f2f436a
A
131// uint32_t OSAtomicOr32Orig( uint32_t mask, uint32_t *value);
132PLATFUNC_FUNCTION_START(OSAtomicOr32Orig, up, 64, 2)
133PLATFUNC_FUNCTION_START(OSAtomicOr32OrigBarrier, up, 64, 2)
134 ATOMIC_ARITHMETIC(orl, ATOMIC_RET_ORIG, ATOMIC_UP)
135 ret
136
137PLATFUNC_FUNCTION_START_GENERIC(OSAtomicOr32Orig, mp, 64, 2)
138PLATFUNC_FUNCTION_START_GENERIC(OSAtomicOr32OrigBarrier, mp, 64, 2)
139 ATOMIC_ARITHMETIC(orl, ATOMIC_RET_ORIG, ATOMIC_MP)
140 ret
224c7076
A
141
142// uint32_t OSAtomicXor32Orig( uint32_t mask, uint32_t *value);
1f2f436a
A
143PLATFUNC_FUNCTION_START(OSAtomicXor32Orig, up, 64, 2)
144PLATFUNC_FUNCTION_START(OSAtomicXor32OrigBarrier, up, 64, 2)
145 ATOMIC_ARITHMETIC(xorl, ATOMIC_RET_ORIG, ATOMIC_UP)
224c7076
A
146 ret
147
1f2f436a
A
148PLATFUNC_FUNCTION_START_GENERIC(OSAtomicXor32Orig, mp, 64, 2)
149PLATFUNC_FUNCTION_START_GENERIC(OSAtomicXor32OrigBarrier, mp, 64, 2)
150 ATOMIC_ARITHMETIC(xorl, ATOMIC_RET_ORIG, ATOMIC_MP)
151 ret
224c7076 152
8e029c65 153// bool OSAtomicCompareAndSwap32( int32_t old, int32_t new, int32_t *value);
1f2f436a
A
154PLATFUNC_FUNCTION_START(OSAtomicCompareAndSwapInt, up, 64, 2)
155PLATFUNC_FUNCTION_START(OSAtomicCompareAndSwapIntBarrier, up, 64, 2)
156PLATFUNC_FUNCTION_START(OSAtomicCompareAndSwap32, up, 64, 2)
157PLATFUNC_FUNCTION_START(OSAtomicCompareAndSwap32Barrier, up, 64, 2)
158 movl %edi, %eax
159 xchg32 %esi, %rdx, ATOMIC_UP
8e029c65 160 sete %al
224c7076 161 movzbl %al,%eax // widen in case caller assumes we return an int
8e029c65
A
162 ret
163
1f2f436a
A
164PLATFUNC_FUNCTION_START_GENERIC(OSAtomicCompareAndSwapInt, mp, 64, 2)
165PLATFUNC_FUNCTION_START_GENERIC(OSAtomicCompareAndSwapIntBarrier, mp, 64, 2)
166PLATFUNC_FUNCTION_START_GENERIC(OSAtomicCompareAndSwap32, mp, 64, 2)
167PLATFUNC_FUNCTION_START_GENERIC(OSAtomicCompareAndSwap32Barrier, mp, 64, 2)
168 movl %edi, %eax
169 xchg32 %esi, %rdx, ATOMIC_MP
170 sete %al
171 movzbl %al,%eax // widen in case caller assumes we return an int
172 ret
8e029c65
A
173
174// bool OSAtomicCompareAndSwap64( int64_t old, int64_t new, int64_t *value);
1f2f436a
A
175PLATFUNC_FUNCTION_START(OSAtomicCompareAndSwapPtr, up, 64, 2)
176PLATFUNC_FUNCTION_START(OSAtomicCompareAndSwapPtrBarrier, up, 64, 2)
177PLATFUNC_FUNCTION_START(OSAtomicCompareAndSwapLong, up, 64, 2)
178PLATFUNC_FUNCTION_START(OSAtomicCompareAndSwapLongBarrier, up, 64, 2)
179PLATFUNC_FUNCTION_START(OSAtomicCompareAndSwap64, up, 64, 2)
180PLATFUNC_FUNCTION_START(OSAtomicCompareAndSwap64Barrier, up, 64, 2)
181 mov %rdi, %rax
182 xchg64 %rsi, %rdx, ATOMIC_UP
183 sete %al
184 movzbl %al,%eax // widen in case caller assumes we return an int
185 ret
186
187PLATFUNC_FUNCTION_START_GENERIC(OSAtomicCompareAndSwapPtr, mp, 64, 2)
188PLATFUNC_FUNCTION_START_GENERIC(OSAtomicCompareAndSwapPtrBarrier, mp, 64, 2)
189PLATFUNC_FUNCTION_START_GENERIC(OSAtomicCompareAndSwapLong, mp, 64, 2)
190PLATFUNC_FUNCTION_START_GENERIC(OSAtomicCompareAndSwapLongBarrier, mp, 64, 2)
191PLATFUNC_FUNCTION_START_GENERIC(OSAtomicCompareAndSwap64, mp, 64, 2)
192PLATFUNC_FUNCTION_START_GENERIC(OSAtomicCompareAndSwap64Barrier, mp, 64, 2)
193 mov %rdi, %rax
194 xchg64 %rsi, %rdx, ATOMIC_MP
8e029c65 195 sete %al
224c7076 196 movzbl %al,%eax // widen in case caller assumes we return an int
8e029c65 197 ret
8e029c65
A
198
199// int32_t OSAtomicAdd32( int32_t amt, int32_t *value );
1f2f436a
A
200PLATFUNC_FUNCTION_START(OSAtomicAdd32, up, 64, 2)
201PLATFUNC_FUNCTION_START(OSAtomicAdd32Barrier, up, 64, 2)
8e029c65 202 movl %edi, %eax // save amt to add
1f2f436a
A
203 xaddl %edi, (%rsi) // swap and add value, returns old value in %edi
204 addl %edi, %eax // add old value to amt as return value
8e029c65
A
205 ret
206
1f2f436a
A
207PLATFUNC_FUNCTION_START_GENERIC(OSAtomicAdd32, mp, 64, 2)
208PLATFUNC_FUNCTION_START_GENERIC(OSAtomicAdd32Barrier, mp, 64, 2)
209 movl %edi, %eax // save amt to add
210 lock // lock prefix breaks tabs ;)
211 xaddl %edi, (%rsi) // swap and add value, returns old value in %edi
212 addl %edi, %eax // add old value to amt as return value
213 ret
8e029c65
A
214
215// int64_t OSAtomicAdd64( int64_t amt, int64_t *value );
1f2f436a
A
216PLATFUNC_FUNCTION_START(OSAtomicAdd64, up, 64, 2)
217PLATFUNC_FUNCTION_START(OSAtomicAdd64Barrier, up, 64, 2)
8e029c65 218 movq %rdi, %rax // save amt to add
1f2f436a
A
219 xadd %rdi, (%rsi) // swap and add value, returns old value in %rsi
220 addq %rdi, %rax // add old value to amt as return value
8e029c65
A
221 ret
222
1f2f436a
A
223PLATFUNC_FUNCTION_START_GENERIC(OSAtomicAdd64, mp, 64, 2)
224PLATFUNC_FUNCTION_START_GENERIC(OSAtomicAdd64Barrier, mp, 64, 2)
225 movq %rdi, %rax // save amt to add
226 lock
227 xadd %rdi, (%rsi) // swap and add value, returns old value in %rsi
228 addq %rdi, %rax // add old value to amt as return value
229 ret
8e029c65
A
230
231// bool OSAtomicTestAndSet( uint32_t n, void *value );
1f2f436a
A
232PLATFUNC_FUNCTION_START(OSAtomicTestAndSet, up, 64, 2)
233PLATFUNC_FUNCTION_START(OSAtomicTestAndSetBarrier, up, 64, 2)
234 ATOMIC_BIT_OP(btsl, ATOMIC_UP)
8e029c65
A
235 ret
236
1f2f436a
A
237PLATFUNC_FUNCTION_START_GENERIC(OSAtomicTestAndSet, mp, 64, 2)
238PLATFUNC_FUNCTION_START_GENERIC(OSAtomicTestAndSetBarrier, mp, 64, 2)
239 ATOMIC_BIT_OP(btsl, ATOMIC_MP)
240 ret
8e029c65
A
241
242// bool OSAtomicTestAndClear( uint32_t n, void *value );
1f2f436a
A
243PLATFUNC_FUNCTION_START(OSAtomicTestAndClear, up, 64, 2)
244PLATFUNC_FUNCTION_START(OSAtomicTestAndClearBarrier, up, 64, 2)
245 ATOMIC_BIT_OP(btrl, ATOMIC_UP)
8e029c65
A
246 ret
247
1f2f436a
A
248PLATFUNC_FUNCTION_START_GENERIC(OSAtomicTestAndClear, mp, 64, 2)
249PLATFUNC_FUNCTION_START_GENERIC(OSAtomicTestAndClearBarrier, mp, 64, 2)
250 ATOMIC_BIT_OP(btrl, ATOMIC_MP)
8e029c65
A
251 ret
252
8e029c65
A
253// void OSMemoryBarrier( void );
254 .align 2, 0x90
255 .globl _OSMemoryBarrier
256_OSMemoryBarrier:
1f2f436a
A
257 mfence
258 ret
224c7076
A
259
260/*
261 * typedef volatile struct {
262 * void *opaque1; <-- ptr to 1st queue element or null
263 * long opaque2; <-- generation count
264 * } OSQueueHead;
265 *
266 * void OSAtomicEnqueue( OSQueueHead *list, void *new, size_t offset);
267 */
268 .align 2
269 .globl _OSAtomicEnqueue
270_OSAtomicEnqueue: // %rdi == list head, %rsi == new, %rdx == offset
271 pushq %rbx
272 movq %rsi,%rbx // %rbx == new
273 movq %rdx,%rsi // %rsi == offset
274 movq (%rdi),%rax // %rax == ptr to 1st element in Q
275 movq 8(%rdi),%rdx // %rdx == current generation count
2761:
277 movq %rax,(%rbx,%rsi)// link to old list head from new element
278 movq %rdx,%rcx
279 incq %rcx // increment generation count
280 lock // always lock for now...
281 cmpxchg16b (%rdi) // ...push on new element
282 jnz 1b
283 popq %rbx
8e029c65 284 ret
1f2f436a
A
285
286
287 /* void* OSAtomicDequeue( OSQueueHead *list, size_t offset); */
224c7076
A
288 .align 2
289 .globl _OSAtomicDequeue
290_OSAtomicDequeue: // %rdi == list head, %rsi == offset
291 pushq %rbx
292 movq (%rdi),%rax // %rax == ptr to 1st element in Q
293 movq 8(%rdi),%rdx // %rdx == current generation count
2941:
295 testq %rax,%rax // list empty?
296 jz 2f // yes
297 movq (%rax,%rsi),%rbx // point to 2nd in Q
298 movq %rdx,%rcx
299 incq %rcx // increment generation count
300 lock // always lock for now...
301 cmpxchg16b (%rdi) // ...pop off 1st element
302 jnz 1b
3032:
304 popq %rbx
305 ret // ptr to 1st element in Q still in %rax
1f2f436a
A
306
307/*
308 * typedef volatile struct {
309 * void *opaque1; <-- ptr to first queue element or null
310 * void *opaque2; <-- ptr to last queue element or null
311 * int opaque3; <-- spinlock
312 * } OSFifoQueueHead;
313 *
314 * void OSAtomicFifoEnqueue( OSFifoQueueHead *list, void *new, size_t offset);
315 */
316 .align 2
317 .globl _OSAtomicFifoEnqueue
318_OSAtomicFifoEnqueue:
319 pushq %rbx
320 xorl %ebx,%ebx // clear "preemption pending" flag
ad3c9f2a
A
321 movq _commpage_pfz_base(%rip),%rcx
322 addq $(_COMM_TEXT_PFZ_ENQUEUE_OFFSET), %rcx
1f2f436a
A
323 call *%rcx
324 testl %ebx,%ebx // pending preemption?
325 jz 1f
326 call _preempt // call into the kernel to pfz_exit
3271:
328 popq %rbx
329 ret
330
331
332/* void* OSAtomicFifoDequeue( OSFifoQueueHead *list, size_t offset); */
333 .align 2
334 .globl _OSAtomicFifoDequeue
335_OSAtomicFifoDequeue:
336 pushq %rbx
337 xorl %ebx,%ebx // clear "preemption pending" flag
ad3c9f2a 338 movq _commpage_pfz_base(%rip), %rcx
1f2f436a 339 movq %rsi,%rdx // move offset to %rdx to be like the Enqueue case
ad3c9f2a 340 addq $(_COMM_TEXT_PFZ_DEQUEUE_OFFSET), %rcx
1f2f436a
A
341 call *%rcx
342 testl %ebx,%ebx // pending preemption?
343 jz 1f
344 call _preempt // call into the kernel to pfz_exit
3451:
346 popq %rbx
347 ret // ptr to 1st element in Q in %rax
348
349// Local Variables:
350// tab-width: 8
351// End: