]> git.saurik.com Git - apple/xnu.git/blame - osfmk/i386/i386_lock.s
xnu-792.12.6.tar.gz
[apple/xnu.git] / osfmk / i386 / i386_lock.s
CommitLineData
1c79356b
A
1/*
2 * Copyright (c) 2000 Apple Computer, Inc. All rights reserved.
3 *
8ad349bb 4 * @APPLE_LICENSE_OSREFERENCE_HEADER_START@
1c79356b 5 *
8ad349bb
A
6 * This file contains Original Code and/or Modifications of Original Code
7 * as defined in and that are subject to the Apple Public Source License
8 * Version 2.0 (the 'License'). You may not use this file except in
9 * compliance with the License. The rights granted to you under the
10 * License may not be used to create, or enable the creation or
11 * redistribution of, unlawful or unlicensed copies of an Apple operating
12 * system, or to circumvent, violate, or enable the circumvention or
13 * violation of, any terms of an Apple operating system software license
14 * agreement.
15 *
16 * Please obtain a copy of the License at
17 * http://www.opensource.apple.com/apsl/ and read it before using this
18 * file.
19 *
20 * The Original Code and all software distributed under the License are
21 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
22 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
23 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
24 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
25 * Please see the License for the specific language governing rights and
26 * limitations under the License.
27 *
28 * @APPLE_LICENSE_OSREFERENCE_HEADER_END@
1c79356b
A
29 */
30/*
31 * @OSF_COPYRIGHT@
32 */
33/*
34 * Mach Operating System
35 * Copyright (c) 1989 Carnegie-Mellon University
36 * All rights reserved. The CMU software License Agreement specifies
37 * the terms and conditions for use and redistribution.
38 */
39
1c79356b
A
40#include <mach_rt.h>
41#include <platforms.h>
42#include <mach_ldebug.h>
43#include <i386/asm.h>
1c79356b 44
9bccf70c 45#include "assym.s"
1c79356b 46
91447636
A
47#define PAUSE rep; nop
48
1c79356b
A
49/*
50 * When performance isn't the only concern, it's
51 * nice to build stack frames...
52 */
91447636
A
53#define BUILD_STACK_FRAMES (GPROF || \
54 ((MACH_LDEBUG || ETAP_LOCK_TRACE) && MACH_KDB))
1c79356b
A
55
56#if BUILD_STACK_FRAMES
57
91447636
A
58/* STack-frame-relative: */
59#define L_PC B_PC
60#define L_ARG0 B_ARG0
61#define L_ARG1 B_ARG1
62
63#define LEAF_ENTRY(name) \
64 Entry(name); \
65 FRAME; \
66 MCOUNT
67
68#define LEAF_ENTRY2(n1,n2) \
69 Entry(n1); \
70 Entry(n2); \
71 FRAME; \
72 MCOUNT
73
74#define LEAF_RET \
75 EMARF; \
76 ret
1c79356b 77
91447636 78#else /* BUILD_STACK_FRAMES */
1c79356b 79
91447636
A
80/* Stack-pointer-relative: */
81#define L_PC S_PC
82#define L_ARG0 S_ARG0
83#define L_ARG1 S_ARG1
84
85#define LEAF_ENTRY(name) \
86 Entry(name)
87
88#define LEAF_ENTRY2(n1,n2) \
89 Entry(n1); \
90 Entry(n2)
91
92#define LEAF_RET \
93 ret
1c79356b 94
91447636 95#endif /* BUILD_STACK_FRAMES */
1c79356b 96
91447636
A
97
98/* Non-leaf routines always have a stack frame: */
99
100#define NONLEAF_ENTRY(name) \
101 Entry(name); \
102 FRAME; \
103 MCOUNT
104
105#define NONLEAF_ENTRY2(n1,n2) \
106 Entry(n1); \
107 Entry(n2); \
108 FRAME; \
109 MCOUNT
110
111#define NONLEAF_RET \
112 EMARF; \
113 ret
1c79356b
A
114
115
55e303ae
A
116#define M_ILK (%edx)
117#define M_LOCKED MUTEX_LOCKED(%edx)
118#define M_WAITERS MUTEX_WAITERS(%edx)
119#define M_PROMOTED_PRI MUTEX_PROMOTED_PRI(%edx)
91447636
A
120#define M_ITAG MUTEX_ITAG(%edx)
121#define M_PTR MUTEX_PTR(%edx)
1c79356b 122#if MACH_LDEBUG
55e303ae
A
123#define M_TYPE MUTEX_TYPE(%edx)
124#define M_PC MUTEX_PC(%edx)
125#define M_THREAD MUTEX_THREAD(%edx)
1c79356b
A
126#endif /* MACH_LDEBUG */
127
55e303ae 128#include <i386/mp.h>
1c79356b 129#define CX(addr,reg) addr(,reg,4)
1c79356b
A
130
131#if MACH_LDEBUG
132/*
133 * Routines for general lock debugging.
134 */
8ad349bb
A
135#define S_TYPE SLOCK_TYPE(%edx)
136#define S_PC SLOCK_PC(%edx)
137#define S_THREAD SLOCK_THREAD(%edx)
138#define S_DURATIONH SLOCK_DURATIONH(%edx)
139#define S_DURATIONL SLOCK_DURATIONL(%edx)
1c79356b
A
140
141/*
142 * Checks for expected lock types and calls "panic" on
143 * mismatch. Detects calls to Mutex functions with
144 * type simplelock and vice versa.
145 */
146#define CHECK_MUTEX_TYPE() \
9bccf70c 147 cmpl $ MUTEX_TAG,M_TYPE ; \
1c79356b
A
148 je 1f ; \
149 pushl $2f ; \
150 call EXT(panic) ; \
151 hlt ; \
152 .data ; \
1532: String "not a mutex!" ; \
154 .text ; \
1551:
156
8ad349bb
A
157#define CHECK_SIMPLE_LOCK_TYPE() \
158 cmpl $ USLOCK_TAG,S_TYPE ; \
159 je 1f ; \
160 pushl $2f ; \
161 call EXT(panic) ; \
162 hlt ; \
163 .data ; \
1642: String "not a simple lock!" ; \
165 .text ; \
1661:
167
1c79356b
A
168/*
169 * If one or more simplelocks are currently held by a thread,
170 * an attempt to acquire a mutex will cause this check to fail
171 * (since a mutex lock may context switch, holding a simplelock
172 * is not a good thing).
173 */
91447636 174#if MACH_RT
1c79356b 175#define CHECK_PREEMPTION_LEVEL() \
91447636 176 cmpl $0,%gs:CPU_PREEMPTION_LEVEL ; \
1c79356b
A
177 je 1f ; \
178 pushl $2f ; \
179 call EXT(panic) ; \
180 hlt ; \
181 .data ; \
1822: String "preemption_level != 0!" ; \
183 .text ; \
1841:
185#else /* MACH_RT */
186#define CHECK_PREEMPTION_LEVEL()
187#endif /* MACH_RT */
188
189#define CHECK_NO_SIMPLELOCKS() \
91447636 190 cmpl $0,%gs:CPU_SIMPLE_LOCK_COUNT ; \
1c79356b
A
191 je 1f ; \
192 pushl $2f ; \
193 call EXT(panic) ; \
194 hlt ; \
195 .data ; \
1962: String "simple_locks_held!" ; \
197 .text ; \
1981:
199
200/*
201 * Verifies return to the correct thread in "unlock" situations.
202 */
203#define CHECK_THREAD(thd) \
91447636 204 movl %gs:CPU_ACTIVE_THREAD,%ecx ; \
1c79356b
A
205 testl %ecx,%ecx ; \
206 je 1f ; \
207 cmpl %ecx,thd ; \
208 je 1f ; \
209 pushl $2f ; \
210 call EXT(panic) ; \
211 hlt ; \
212 .data ; \
2132: String "wrong thread!" ; \
214 .text ; \
2151:
216
217#define CHECK_MYLOCK(thd) \
91447636 218 movl %gs:CPU_ACTIVE_THREAD,%ecx ; \
1c79356b
A
219 testl %ecx,%ecx ; \
220 je 1f ; \
221 cmpl %ecx,thd ; \
222 jne 1f ; \
223 pushl $2f ; \
224 call EXT(panic) ; \
225 hlt ; \
226 .data ; \
2272: String "mylock attempt!" ; \
228 .text ; \
2291:
230
231#define METER_SIMPLE_LOCK_LOCK(reg) \
232 pushl reg ; \
233 call EXT(meter_simple_lock) ; \
234 popl reg
235
236#define METER_SIMPLE_LOCK_UNLOCK(reg) \
237 pushl reg ; \
238 call EXT(meter_simple_unlock) ; \
239 popl reg
240
241#else /* MACH_LDEBUG */
242#define CHECK_MUTEX_TYPE()
243#define CHECK_SIMPLE_LOCK_TYPE
244#define CHECK_THREAD(thd)
245#define CHECK_PREEMPTION_LEVEL()
246#define CHECK_NO_SIMPLELOCKS()
247#define CHECK_MYLOCK(thd)
248#define METER_SIMPLE_LOCK_LOCK(reg)
249#define METER_SIMPLE_LOCK_UNLOCK(reg)
250#endif /* MACH_LDEBUG */
251
252
253/*
254 * void hw_lock_init(hw_lock_t)
255 *
256 * Initialize a hardware lock.
257 */
91447636 258LEAF_ENTRY(hw_lock_init)
1c79356b 259 movl L_ARG0,%edx /* fetch lock pointer */
91447636
A
260 movl $0,0(%edx) /* clear the lock */
261 LEAF_RET
1c79356b
A
262
263/*
264 * void hw_lock_lock(hw_lock_t)
265 *
266 * Acquire lock, spinning until it becomes available.
267 * MACH_RT: also return with preemption disabled.
268 */
91447636 269LEAF_ENTRY(hw_lock_lock)
1c79356b
A
270 movl L_ARG0,%edx /* fetch lock pointer */
271
8ad349bb
A
272 movl L_PC,%ecx
2731: DISABLE_PREEMPTION
91447636
A
274 movl 0(%edx), %eax
275 testl %eax,%eax /* lock locked? */
276 jne 3f /* branch if so */
277 lock; cmpxchgl %ecx,0(%edx) /* try to acquire the HW lock */
1c79356b 278 jne 3f
9bccf70c 279 movl $1,%eax /* In case this was a timeout call */
91447636 280 LEAF_RET /* if yes, then nothing left to do */
8ad349bb
A
281
2823: ENABLE_PREEMPTION /* no reason we can't be preemptable */
91447636
A
283 PAUSE /* pause for hyper-threading */
284 jmp 1b /* try again */
1c79356b 285
55e303ae
A
286/*
287 * unsigned int hw_lock_to(hw_lock_t, unsigned int)
288 *
289 * Acquire lock, spinning until it becomes available or timeout.
290 * MACH_RT: also return with preemption disabled.
291 */
91447636 292LEAF_ENTRY(hw_lock_to)
55e303ae 2931:
91447636 294 movl L_ARG0,%edx /* fetch lock pointer */
8ad349bb 295 movl L_PC,%ecx
55e303ae
A
296 /*
297 * Attempt to grab the lock immediately
298 * - fastpath without timeout nonsense.
299 */
91447636
A
300 DISABLE_PREEMPTION
301 movl 0(%edx), %eax
302 testl %eax,%eax /* lock locked? */
303 jne 2f /* branch if so */
304 lock; cmpxchgl %ecx,0(%edx) /* try to acquire the HW lock */
305 jne 2f /* branch on failure */
55e303ae 306 movl $1,%eax
91447636 307 LEAF_RET
55e303ae
A
308
3092:
310#define INNER_LOOP_COUNT 1000
311 /*
312 * Failed to get the lock so set the timeout
313 * and then spin re-checking the lock but pausing
314 * every so many (INNER_LOOP_COUNT) spins to check for timeout.
315 */
316 movl L_ARG1,%ecx /* fetch timeout */
317 push %edi
318 push %ebx
319 mov %edx,%edi
320
321 rdtsc /* read cyclecount into %edx:%eax */
322 addl %ecx,%eax /* fetch and timeout */
323 adcl $0,%edx /* add carry */
324 mov %edx,%ecx
325 mov %eax,%ebx /* %ecx:%ebx is the timeout expiry */
8ad349bb
A
3263:
327 ENABLE_PREEMPTION /* no reason not to be preempted now */
55e303ae
A
3284:
329 /*
330 * The inner-loop spin to look for the lock being freed.
331 */
55e303ae
A
332 mov $(INNER_LOOP_COUNT),%edx
3335:
91447636
A
334 PAUSE /* pause for hyper-threading */
335 movl 0(%edi),%eax /* spin checking lock value in cache */
336 testl %eax,%eax
55e303ae
A
337 je 6f /* zero => unlocked, try to grab it */
338 decl %edx /* decrement inner loop count */
339 jnz 5b /* time to check for timeout? */
340
341 /*
342 * Here after spinning INNER_LOOP_COUNT times, check for timeout
343 */
344 rdtsc /* cyclecount into %edx:%eax */
345 cmpl %ecx,%edx /* compare high-order 32-bits */
346 jb 4b /* continue spinning if less, or */
347 cmpl %ebx,%eax /* compare low-order 32-bits */
8ad349bb 348 jb 5b /* continue if less, else bail */
55e303ae
A
349 xor %eax,%eax /* with 0 return value */
350 pop %ebx
351 pop %edi
91447636 352 LEAF_RET
55e303ae
A
353
3546:
355 /*
356 * Here to try to grab the lock that now appears to be free
357 * after contention.
358 */
8ad349bb
A
359 movl 8+L_PC,%edx /* calling pc (8+ for pushed regs) */
360 DISABLE_PREEMPTION
91447636 361 lock; cmpxchgl %edx,0(%edi) /* try to acquire the HW lock */
8ad349bb 362 jne 3b /* no - spin again */
55e303ae
A
363 movl $1,%eax /* yes */
364 pop %ebx
365 pop %edi
91447636 366 LEAF_RET
55e303ae 367
1c79356b
A
368/*
369 * void hw_lock_unlock(hw_lock_t)
370 *
371 * Unconditionally release lock.
372 * MACH_RT: release preemption level.
373 */
91447636 374LEAF_ENTRY(hw_lock_unlock)
1c79356b 375 movl L_ARG0,%edx /* fetch lock pointer */
91447636
A
376 movl $0,0(%edx) /* clear the lock */
377 ENABLE_PREEMPTION
378 LEAF_RET
1c79356b
A
379
380/*
381 * unsigned int hw_lock_try(hw_lock_t)
382 * MACH_RT: returns with preemption disabled on success.
383 */
91447636 384LEAF_ENTRY(hw_lock_try)
1c79356b
A
385 movl L_ARG0,%edx /* fetch lock pointer */
386
8ad349bb 387 movl L_PC,%ecx
91447636
A
388 DISABLE_PREEMPTION
389 movl 0(%edx),%eax
390 testl %eax,%eax
391 jne 1f
392 lock; cmpxchgl %ecx,0(%edx) /* try to acquire the HW lock */
393 jne 1f
1c79356b
A
394
395 movl $1,%eax /* success */
91447636 396 LEAF_RET
1c79356b 397
8ad349bb 3981: ENABLE_PREEMPTION /* failure: release preemption... */
1c79356b 399 xorl %eax,%eax /* ...and return failure */
91447636 400 LEAF_RET
1c79356b
A
401
402/*
403 * unsigned int hw_lock_held(hw_lock_t)
404 * MACH_RT: doesn't change preemption state.
405 * N.B. Racy, of course.
406 */
91447636 407LEAF_ENTRY(hw_lock_held)
1c79356b
A
408 movl L_ARG0,%edx /* fetch lock pointer */
409
91447636
A
410 movl 0(%edx),%eax /* check lock value */
411 testl %eax,%eax
55e303ae 412 movl $1,%ecx
91447636
A
413 cmovne %ecx,%eax /* 0 => unlocked, 1 => locked */
414 LEAF_RET
1c79356b 415
91447636
A
416LEAF_ENTRY(mutex_init)
417 movl L_ARG0,%edx /* fetch lock pointer */
418 xorl %eax,%eax
419 movl %eax,M_ILK /* clear interlock */
420 movl %eax,M_LOCKED /* clear locked flag */
421 movw %ax,M_WAITERS /* init waiter count */
422 movw %ax,M_PROMOTED_PRI
1c79356b 423
91447636
A
424#if MACH_LDEBUG
425 movl $ MUTEX_TAG,M_TYPE /* set lock type */
426 movl %eax,M_PC /* init caller pc */
427 movl %eax,M_THREAD /* and owning thread */
428#endif
1c79356b 429
91447636 430 LEAF_RET
1c79356b 431
91447636 432NONLEAF_ENTRY2(mutex_lock,_mutex_lock)
1c79356b 433
91447636 434 movl B_ARG0,%edx /* fetch lock pointer */
1c79356b 435
91447636
A
436 CHECK_MUTEX_TYPE()
437 CHECK_NO_SIMPLELOCKS()
438 CHECK_PREEMPTION_LEVEL()
1c79356b 439
91447636
A
440 pushf /* save interrupt state */
441 cli /* disable interrupts */
1c79356b 442
8ad349bb
A
443ml_retry:
444 movl B_PC,%ecx
445
446ml_get_hw:
91447636
A
447 movl M_ILK,%eax /* read interlock */
448 testl %eax,%eax /* unlocked? */
8ad349bb
A
449 je 1f /* yes - attempt to lock it */
450 PAUSE /* no - pause */
451 jmp ml_get_hw /* try again */
4521:
91447636 453 lock; cmpxchgl %ecx,M_ILK /* atomic compare and exchange */
8ad349bb 454 jne ml_get_hw /* branch on failure to retry */
91447636
A
455
456 movl M_LOCKED,%ecx /* get lock owner */
457 testl %ecx,%ecx /* is the mutex locked? */
8ad349bb 458 jne ml_fail /* yes, we lose */
91447636
A
459 movl %gs:CPU_ACTIVE_THREAD,%ecx
460 movl %ecx,M_LOCKED
1c79356b
A
461
462#if MACH_LDEBUG
91447636
A
463 movl %ecx,M_THREAD
464 movl B_PC,%ecx
465 movl %ecx,M_PC
1c79356b 466#endif
1c79356b 467
91447636
A
468 pushl %edx /* save mutex address */
469 pushl %edx
470 call EXT(lck_mtx_lock_acquire)
471 addl $4,%esp
472 popl %edx /* restore mutex address */
1c79356b 473
91447636 474 xorl %eax,%eax
8ad349bb 475 movl %eax,M_ILK
1c79356b 476
8ad349bb 477 popf /* restore interrupt state */
c0fea474 478
8ad349bb 479 NONLEAF_RET
c0fea474 480
8ad349bb
A
481ml_fail:
482ml_block:
91447636
A
483 CHECK_MYLOCK(M_THREAD)
484 pushl M_LOCKED
485 pushl %edx /* push mutex address */
486 call EXT(lck_mtx_lock_wait) /* wait for the lock */
487 addl $8,%esp
488 movl B_ARG0,%edx /* refetch mutex address */
8ad349bb 489 jmp ml_retry /* and try again */
1c79356b 490
91447636 491NONLEAF_ENTRY2(mutex_try,_mutex_try)
1c79356b 492
91447636 493 movl B_ARG0,%edx /* fetch lock pointer */
1c79356b 494
91447636
A
495 CHECK_MUTEX_TYPE()
496 CHECK_NO_SIMPLELOCKS()
1c79356b 497
8ad349bb
A
498 movl B_PC,%ecx
499
91447636
A
500 pushf /* save interrupt state */
501 cli /* disable interrupts */
1c79356b 502
8ad349bb 503mt_get_hw:
91447636
A
504 movl M_ILK,%eax /* read interlock */
505 testl %eax,%eax /* unlocked? */
8ad349bb
A
506 je 1f /* yes - attempt to lock it */
507 PAUSE /* no - pause */
508 jmp mt_get_hw /* try again */
5091:
91447636 510 lock; cmpxchgl %ecx,M_ILK /* atomic compare and exchange */
8ad349bb 511 jne mt_get_hw /* branch on failure to retry */
1c79356b 512
91447636
A
513 movl M_LOCKED,%ecx /* get lock owner */
514 testl %ecx,%ecx /* is the mutex locked? */
8ad349bb 515 jne mt_fail /* yes, we lose */
91447636
A
516 movl %gs:CPU_ACTIVE_THREAD,%ecx
517 movl %ecx,M_LOCKED
1c79356b
A
518
519#if MACH_LDEBUG
91447636
A
520 movl %ecx,M_THREAD
521 movl B_PC,%ecx
522 movl %ecx,M_PC
1c79356b 523#endif
1c79356b 524
8ad349bb
A
525 pushl %edx /* save mutex address */
526 pushl %edx
527 call EXT(lck_mtx_lock_acquire)
528 addl $4,%esp
529 popl %edx /* restore mutex address */
530
91447636
A
531 xorl %eax,%eax
532 movl %eax,M_ILK
8ad349bb 533
91447636 534 popf /* restore interrupt state */
1c79356b 535
91447636 536 movl $1,%eax
1c79356b 537
91447636 538 NONLEAF_RET
1c79356b 539
8ad349bb 540mt_fail:
1c79356b 541 xorl %eax,%eax
91447636 542 movl %eax,M_ILK
1c79356b 543
91447636 544 popf /* restore interrupt state */
1c79356b 545
91447636 546 xorl %eax,%eax
1c79356b 547
91447636 548 NONLEAF_RET
1c79356b 549
91447636
A
550NONLEAF_ENTRY(mutex_unlock)
551 movl B_ARG0,%edx /* fetch lock pointer */
1c79356b
A
552
553 CHECK_MUTEX_TYPE()
91447636 554 CHECK_THREAD(M_THREAD)
1c79356b 555
8ad349bb
A
556 movl B_PC,%ecx
557
91447636
A
558 pushf /* save interrupt state */
559 cli /* disable interrupts */
1c79356b 560
8ad349bb 561mu_get_hw:
91447636
A
562 movl M_ILK,%eax /* read interlock */
563 testl %eax,%eax /* unlocked? */
8ad349bb
A
564 je 1f /* yes - attempt to lock it */
565 PAUSE /* no - pause */
566 jmp mu_get_hw /* try again */
5671:
91447636 568 lock; cmpxchgl %ecx,M_ILK /* atomic compare and exchange */
8ad349bb 569 jne mu_get_hw /* branch on failure to retry */
1c79356b 570
91447636 571 cmpw $0,M_WAITERS /* are there any waiters? */
8ad349bb 572 jne mu_wakeup /* yes, more work to do */
91447636 573
8ad349bb 574mu_doit:
9bccf70c 575
1c79356b 576#if MACH_LDEBUG
91447636 577 movl $0,M_THREAD /* disown thread */
1c79356b
A
578#endif
579
55e303ae 580 xorl %ecx,%ecx
91447636 581 movl %ecx,M_LOCKED /* unlock the mutex */
1c79356b 582
91447636 583 movl %ecx,M_ILK
1c79356b 584
91447636 585 popf /* restore interrupt state */
1c79356b 586
91447636 587 NONLEAF_RET
1c79356b 588
8ad349bb 589mu_wakeup:
91447636 590 pushl M_LOCKED
1c79356b 591 pushl %edx /* push mutex address */
91447636 592 call EXT(lck_mtx_unlock_wakeup)/* yes, wake a thread */
9bccf70c 593 addl $8,%esp
91447636 594 movl B_ARG0,%edx /* restore lock pointer */
8ad349bb 595 jmp mu_doit
1c79356b 596
91447636
A
597/*
598 * lck_mtx_lock()
599 * lck_mtx_try_lock()
600 * lck_mutex_unlock()
601 *
602 * These are variants of mutex_lock(), mutex_try() and mutex_unlock() without
603 * DEBUG checks (which require fields not present in lck_mtx_t's).
604 */
605NONLEAF_ENTRY(lck_mtx_lock)
1c79356b 606
91447636
A
607 movl B_ARG0,%edx /* fetch lock pointer */
608 cmpl $(MUTEX_IND),M_ITAG /* is this indirect? */
609 cmove M_PTR,%edx /* yes - take indirection */
1c79356b 610
1c79356b 611 CHECK_NO_SIMPLELOCKS()
91447636 612 CHECK_PREEMPTION_LEVEL()
1c79356b 613
91447636
A
614 pushf /* save interrupt state */
615 cli /* disable interrupts */
9bccf70c 616
8ad349bb
A
617lml_retry:
618 movl B_PC,%ecx
619
620lml_get_hw:
91447636
A
621 movl M_ILK,%eax /* read interlock */
622 testl %eax,%eax /* unlocked? */
8ad349bb
A
623 je 1f /* yes - attempt to lock it */
624 PAUSE /* no - pause */
625 jmp lml_get_hw /* try again */
6261:
91447636 627 lock; cmpxchgl %ecx,M_ILK /* atomic compare and exchange */
8ad349bb 628 jne lml_get_hw /* branch on failure to retry */
91447636
A
629
630 movl M_LOCKED,%ecx /* get lock owner */
631 testl %ecx,%ecx /* is the mutex locked? */
8ad349bb 632 jne lml_fail /* yes, we lose */
91447636
A
633 movl %gs:CPU_ACTIVE_THREAD,%ecx
634 movl %ecx,M_LOCKED
9bccf70c 635
91447636 636 pushl %edx /* save mutex address */
9bccf70c 637 pushl %edx
91447636 638 call EXT(lck_mtx_lock_acquire)
9bccf70c 639 addl $4,%esp
91447636 640 popl %edx /* restore mutex address */
9bccf70c 641
91447636 642 xorl %eax,%eax
8ad349bb 643 movl %eax,M_ILK
9bccf70c 644
8ad349bb 645 popf /* restore interrupt state */
c0fea474 646
8ad349bb 647 NONLEAF_RET
c0fea474 648
8ad349bb 649lml_fail:
91447636
A
650 CHECK_MYLOCK(M_THREAD)
651 pushl %edx /* save mutex address */
652 pushl M_LOCKED
9bccf70c 653 pushl %edx /* push mutex address */
91447636
A
654 call EXT(lck_mtx_lock_wait) /* wait for the lock */
655 addl $8,%esp
656 popl %edx /* restore mutex address */
8ad349bb 657 jmp lml_retry /* and try again */
9bccf70c 658
91447636 659NONLEAF_ENTRY(lck_mtx_try_lock)
1c79356b 660
91447636
A
661 movl B_ARG0,%edx /* fetch lock pointer */
662 cmpl $(MUTEX_IND),M_ITAG /* is this indirect? */
663 cmove M_PTR,%edx /* yes - take indirection */
9bccf70c 664
91447636
A
665 CHECK_NO_SIMPLELOCKS()
666 CHECK_PREEMPTION_LEVEL()
1c79356b 667
8ad349bb
A
668 movl B_PC,%ecx
669
91447636
A
670 pushf /* save interrupt state */
671 cli /* disable interrupts */
9bccf70c 672
8ad349bb 673lmt_get_hw:
91447636
A
674 movl M_ILK,%eax /* read interlock */
675 testl %eax,%eax /* unlocked? */
8ad349bb
A
676 je 1f /* yes - attempt to lock it */
677 PAUSE /* no - pause */
678 jmp lmt_get_hw /* try again */
6791:
91447636 680 lock; cmpxchgl %ecx,M_ILK /* atomic compare and exchange */
8ad349bb 681 jne lmt_get_hw /* branch on failure to retry */
91447636
A
682
683 movl M_LOCKED,%ecx /* get lock owner */
684 testl %ecx,%ecx /* is the mutex locked? */
8ad349bb 685 jne lmt_fail /* yes, we lose */
91447636
A
686 movl %gs:CPU_ACTIVE_THREAD,%ecx
687 movl %ecx,M_LOCKED
688
8ad349bb
A
689 pushl %edx /* save mutex address */
690 pushl %edx
691 call EXT(lck_mtx_lock_acquire)
692 addl $4,%esp
693 popl %edx /* restore mutex address */
694
9bccf70c 695 xorl %eax,%eax
91447636 696 movl %eax,M_ILK
9bccf70c 697
91447636 698 popf /* restore interrupt state */
1c79356b 699
91447636
A
700 movl $1,%eax /* return success */
701 NONLEAF_RET
1c79356b 702
8ad349bb 703lmt_fail:
91447636
A
704 xorl %eax,%eax
705 movl %eax,M_ILK
1c79356b 706
91447636 707 popf /* restore interrupt state */
1c79356b 708
91447636
A
709 xorl %eax,%eax /* return failure */
710 NONLEAF_RET
1c79356b 711
91447636 712NONLEAF_ENTRY(lck_mtx_unlock)
1c79356b 713
91447636
A
714 movl B_ARG0,%edx /* fetch lock pointer */
715 cmpl $(MUTEX_IND),M_ITAG /* is this indirect? */
716 cmove M_PTR,%edx /* yes - take indirection */
1c79356b 717
8ad349bb
A
718 movl B_PC,%ecx
719
91447636
A
720 pushf /* save interrupt state */
721 cli /* disable interrupts */
1c79356b 722
8ad349bb 723lmu_get_hw:
91447636
A
724 movl M_ILK,%eax /* read interlock */
725 testl %eax,%eax /* unlocked? */
8ad349bb
A
726 je 1f /* yes - attempt to lock it */
727 PAUSE /* no - pause */
728 jmp lmu_get_hw /* try again */
7291:
91447636 730 lock; cmpxchgl %ecx,M_ILK /* atomic compare and exchange */
8ad349bb 731 jne lmu_get_hw /* branch on failure to retry */
1c79356b 732
91447636 733 cmpw $0,M_WAITERS /* are there any waiters? */
8ad349bb 734 jne lmu_wakeup /* yes, more work to do */
91447636 735
8ad349bb 736lmu_doit:
55e303ae 737 xorl %ecx,%ecx
91447636 738 movl %ecx,M_LOCKED /* unlock the mutex */
1c79356b 739
91447636 740 movl %ecx,M_ILK
1c79356b 741
91447636 742 popf /* restore interrupt state */
1c79356b 743
91447636
A
744 NONLEAF_RET
745
8ad349bb 746lmu_wakeup:
91447636
A
747 pushl %edx /* save mutex address */
748 pushl M_LOCKED
1c79356b 749 pushl %edx /* push mutex address */
91447636 750 call EXT(lck_mtx_unlock_wakeup)/* yes, wake a thread */
9bccf70c 751 addl $8,%esp
91447636 752 popl %edx /* restore mutex pointer */
8ad349bb 753 jmp lmu_doit
1c79356b 754
91447636
A
755LEAF_ENTRY(lck_mtx_ilk_unlock)
756 movl L_ARG0,%edx /* no indirection here */
1c79356b 757
91447636
A
758 xorl %eax,%eax
759 movl %eax,M_ILK
1c79356b 760
91447636 761 LEAF_RET
1c79356b 762
91447636 763LEAF_ENTRY(_disable_preemption)
1c79356b 764#if MACH_RT
91447636 765 _DISABLE_PREEMPTION
1c79356b 766#endif /* MACH_RT */
91447636 767 LEAF_RET
1c79356b 768
91447636 769LEAF_ENTRY(_enable_preemption)
1c79356b
A
770#if MACH_RT
771#if MACH_ASSERT
91447636 772 cmpl $0,%gs:CPU_PREEMPTION_LEVEL
1c79356b 773 jg 1f
91447636 774 pushl %gs:CPU_PREEMPTION_LEVEL
1c79356b
A
775 pushl $2f
776 call EXT(panic)
777 hlt
778 .data
7792: String "_enable_preemption: preemption_level(%d) < 0!"
780 .text
7811:
782#endif /* MACH_ASSERT */
91447636 783 _ENABLE_PREEMPTION
1c79356b 784#endif /* MACH_RT */
91447636 785 LEAF_RET
1c79356b 786
91447636 787LEAF_ENTRY(_enable_preemption_no_check)
1c79356b
A
788#if MACH_RT
789#if MACH_ASSERT
91447636 790 cmpl $0,%gs:CPU_PREEMPTION_LEVEL
1c79356b
A
791 jg 1f
792 pushl $2f
793 call EXT(panic)
794 hlt
795 .data
7962: String "_enable_preemption_no_check: preemption_level <= 0!"
797 .text
7981:
799#endif /* MACH_ASSERT */
91447636 800 _ENABLE_PREEMPTION_NO_CHECK
1c79356b 801#endif /* MACH_RT */
91447636 802 LEAF_RET
1c79356b
A
803
804
91447636
A
805LEAF_ENTRY(_mp_disable_preemption)
806#if MACH_RT
807 _DISABLE_PREEMPTION
808#endif /* MACH_RT */
809 LEAF_RET
1c79356b 810
91447636
A
811LEAF_ENTRY(_mp_enable_preemption)
812#if MACH_RT
1c79356b 813#if MACH_ASSERT
91447636 814 cmpl $0,%gs:CPU_PREEMPTION_LEVEL
1c79356b 815 jg 1f
91447636 816 pushl %gs:CPU_PREEMPTION_LEVEL
1c79356b
A
817 pushl $2f
818 call EXT(panic)
819 hlt
820 .data
8212: String "_mp_enable_preemption: preemption_level (%d) <= 0!"
822 .text
8231:
824#endif /* MACH_ASSERT */
91447636
A
825 _ENABLE_PREEMPTION
826#endif /* MACH_RT */
827 LEAF_RET
1c79356b 828
91447636
A
829LEAF_ENTRY(_mp_enable_preemption_no_check)
830#if MACH_RT
1c79356b 831#if MACH_ASSERT
91447636 832 cmpl $0,%gs:CPU_PREEMPTION_LEVEL
1c79356b
A
833 jg 1f
834 pushl $2f
835 call EXT(panic)
836 hlt
837 .data
8382: String "_mp_enable_preemption_no_check: preemption_level <= 0!"
839 .text
8401:
841#endif /* MACH_ASSERT */
91447636
A
842 _ENABLE_PREEMPTION_NO_CHECK
843#endif /* MACH_RT */
844 LEAF_RET
1c79356b
A
845
846
91447636
A
847LEAF_ENTRY(i_bit_set)
848 movl L_ARG0,%edx
849 movl L_ARG1,%eax
1c79356b 850 lock
c0fea474 851 bts %edx,(%eax)
91447636 852 LEAF_RET
1c79356b 853
91447636
A
854LEAF_ENTRY(i_bit_clear)
855 movl L_ARG0,%edx
856 movl L_ARG1,%eax
1c79356b 857 lock
c0fea474 858 btr %edx,(%eax)
91447636 859 LEAF_RET
1c79356b 860
91447636
A
861LEAF_ENTRY(bit_lock)
862 movl L_ARG0,%ecx
863 movl L_ARG1,%eax
1c79356b
A
8641:
865 lock
866 bts %ecx,(%eax)
867 jb 1b
91447636 868 LEAF_RET
1c79356b 869
91447636
A
870LEAF_ENTRY(bit_lock_try)
871 movl L_ARG0,%ecx
872 movl L_ARG1,%eax
1c79356b
A
873 lock
874 bts %ecx,(%eax)
875 jb bit_lock_failed
91447636 876 LEAF_RET /* %eax better not be null ! */
1c79356b
A
877bit_lock_failed:
878 xorl %eax,%eax
91447636 879 LEAF_RET
1c79356b 880
91447636
A
881LEAF_ENTRY(bit_unlock)
882 movl L_ARG0,%ecx
883 movl L_ARG1,%eax
1c79356b
A
884 lock
885 btr %ecx,(%eax)
91447636 886 LEAF_RET