|
|
1.1 root 1: /*
2: * Copyright (c) 2000 Apple Computer, Inc. All rights reserved.
3: *
4: * @APPLE_LICENSE_HEADER_START@
5: *
6: * The contents of this file constitute Original Code as defined in and
7: * are subject to the Apple Public Source License Version 1.1 (the
8: * "License"). You may not use this file except in compliance with the
9: * License. Please obtain a copy of the License at
10: * http://www.apple.com/publicsource and read it before using this file.
11: *
12: * This Original Code and all software distributed under the License are
13: * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER
14: * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
15: * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
16: * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the
17: * License for the specific language governing rights and limitations
18: * under the License.
19: *
20: * @APPLE_LICENSE_HEADER_END@
21: */
22:
23: #include <cpus.h>
24: #include <mach_assert.h>
25: #include <mach_ldebug.h>
26: #include <mach_rt.h>
27:
28: #include <kern/etap_options.h>
29:
30: #include <ppc/asm.h>
31: #include <ppc/proc_reg.h>
32: #include <assym.s>
33:
34: #define STRING ascii
35:
36: #define SWT_HI 0+FM_SIZE
37: #define SWT_LO 4+FM_SIZE
38: #define MISSED 8+FM_SIZE
39:
40: #include <ppc/POWERMAC/mp/mp.h>
41:
42: #define PROLOG(space) \
43: stwu r1,-(FM_ALIGN(space)+FM_SIZE)(r1) __ASMNL__ \
44: mflr r0 __ASMNL__ \
45: stw r3,FM_ARG0(r1) __ASMNL__ \
46: stw r0,(FM_ALIGN(space)+FM_SIZE+FM_LR_SAVE)(r1) __ASMNL__
47:
48: #define EPILOG \
49: lwz r1,0(r1) __ASMNL__ \
50: lwz r0,FM_LR_SAVE(r1) __ASMNL__ \
51: mtlr r0 __ASMNL__
52:
53: #if MACH_LDEBUG
54: /*
55: * Routines for general lock debugging.
56: */
57:
58: /*
59: * Checks for expected lock types and calls "panic" on
60: * mismatch. Detects calls to Mutex functions with
61: * type simplelock and vice versa.
62: */
63: #define CHECK_MUTEX_TYPE() \
64: lwz r10,MUTEX_TYPE(r3) __ASMNL__ \
65: cmpwi r10,MUTEX_TAG __ASMNL__ \
66: beq+ 1f __ASMNL__ \
67: lis r3,HIGH_ADDR(not_a_mutex) __ASMNL__ \
68: ori r3,r3,LOW_ADDR(not_a_mutex) __ASMNL__ \
69: bl EXT(panic) __ASMNL__ \
70: lwz r3,FM_ARG0(r1) __ASMNL__ \
71: 1:
72:
73: .data
74: not_a_mutex:
75: STRINGD "not a mutex!\n\000"
76: .text
77:
78: #define CHECK_SIMPLE_LOCK_TYPE() \
79: lwz r10,SLOCK_TYPE(r3) __ASMNL__ \
80: cmpwi r10,USLOCK_TAG __ASMNL__ \
81: beq+ 1f __ASMNL__ \
82: lis r3,HIGH_ADDR(not_a_slock) __ASMNL__ \
83: ori r3,r3,LOW_ADDR(not_a_slock) __ASMNL__ \
84: bl EXT(panic) __ASMNL__ \
85: lwz r3,FM_ARG0(r1) __ASMNL__ \
86: 1:
87:
88: .data
89: not_a_slock:
90: STRINGD "not a simple lock!\n\000"
91: .text
92:
93: #define CHECK_NO_SIMPLELOCKS() \
94: mfsprg r10,0 __ASMNL__ \
95: lwz r10,PP_CPU_DATA(r10) __ASMNL__ \
96: lwz r10,CPU_SIMPLE_LOCK_COUNT(r10) __ASMNL__ \
97: cmpwi r10,0 __ASMNL__ \
98: beq+ 1f __ASMNL__ \
99: lis r3,HIGH_ADDR(simple_locks_held) __ASMNL__ \
100: ori r3,r3,LOW_ADDR(simple_locks_held) __ASMNL__ \
101: bl EXT(panic) __ASMNL__ \
102: lwz r3,FM_ARG0(r1) __ASMNL__ \
103: 1:
104:
105: .data
106: simple_locks_held:
107: STRINGD "simple locks held!\n\000"
108: .text
109:
110: /*
111: * Verifies return to the correct thread in "unlock" situations.
112: */
113: #define CHECK_THREAD(thread_offset) \
114: mfsprg r10,0 __ASMNL__ \
115: lwz r10,PP_CPU_DATA(r10) __ASMNL__ \
116: lwz r10,CPU_ACTIVE_THREAD(r10) __ASMNL__ \
117: cmpwi r10,0 __ASMNL__ \
118: beq- 1f __ASMNL__ \
119: lwz r9,thread_offset(r3) __ASMNL__ \
120: cmpw r9,r10 __ASMNL__ \
121: beq+ 1f __ASMNL__ \
122: lis r3,HIGH_ADDR(wrong_thread) __ASMNL__ \
123: ori r3,r3,LOW_ADDR(wrong_thread) __ASMNL__ \
124: bl EXT(panic) __ASMNL__ \
125: lwz r3,FM_ARG0(r1) __ASMNL__ \
126: 1:
127:
128: .data
129: wrong_thread:
130: STRINGD "wrong thread!\n\000"
131: .text
132:
133: #define CHECK_MYLOCK(thread_offset) \
134: mfsprg r10,0 __ASMNL__ \
135: lwz r10,PP_CPU_DATA(r10) __ASMNL__ \
136: lwz r10,CPU_ACTIVE_THREAD(r10) __ASMNL__ \
137: cmpwi r10,0 __ASMNL__ \
138: beq- 1f __ASMNL__ \
139: lwz r9, thread_offset(r3) __ASMNL__ \
140: cmpw r9,r10 __ASMNL__ \
141: bne+ 1f __ASMNL__ \
142: lis r3, HIGH_ADDR(mylock_attempt) __ASMNL__ \
143: ori r3,r3,LOW_ADDR(mylock_attempt) __ASMNL__ \
144: bl EXT(panic) __ASMNL__ \
145: lwz r3,FM_ARG0(r1) __ASMNL__ \
146: 1:
147:
148: .data
149: mylock_attempt:
150: STRINGD "mylock attempt!\n\000"
151: .text
152:
153: #else /* MACH_LDEBUG */
154:
155: #define CHECK_MUTEX_TYPE()
156: #define CHECK_SIMPLE_LOCK_TYPE()
157: #define CHECK_THREAD(thread_offset)
158: #define CHECK_NO_SIMPLELOCKS()
159: #define CHECK_MYLOCK(thread_offset)
160:
161: #endif /* MACH_LDEBUG */
162:
163: /*
164: * void hw_lock_init(hw_lock_t)
165: *
166: * Initialize a hardware lock. These locks should be cache aligned and a multiple
167: * of cache size.
168: */
169:
170: ENTRY(hw_lock_init, TAG_NO_FRAME_USED)
171:
172: li r0, 0 /* set lock to free == 0 */
173: stw r0, 0(r3) /* Initialize the lock */
174: blr
175:
176: /*
177: * void hw_lock_unlock(hw_lock_t)
178: *
179: * Unconditionally release lock.
180: * MACH_RT: release preemption level.
181: */
182:
183:
184: .align 5
185: .globl EXT(hw_lock_unlock)
186:
187: LEXT(hw_lock_unlock)
188:
189: #if 0
190: lis r0,HIGH_ADDR(CutTrace) /* (TEST/DEBUG) */
191: lis r5,0xFFFF /* (TEST/DEBUG) */
192: oris r0,r0,LOW_ADDR(CutTrace) /* (TEST/DEBUG) */
193: sc /* (TEST/DEBUG) */
194: #endif
195: sync /* Flush writes done under lock */
196: li r0, 0 /* set lock to free */
197: stw r0, 0(r3)
198:
199: #if MACH_RT
200: b epStart /* Go enable preemption... */
201: #else
202: blr
203: #endif
204:
205:
206: /*
207: * Special case for internal use. Uses same lock code, but sets up so
208: * that there will be no disabling of preemption after locking. Generally
209: * used for mutex locks when obtaining the interlock although there is
210: * nothing stopping other uses.
211: */
212:
213: lockLock: lis r4,HIGH_ADDR(EXT(LockTimeOut)) /* Get the high part */
214: ori r4,r4,LOW_ADDR(EXT(LockTimeOut)) /* And the low part */
215: cmplwi cr1,r1,0 /* Set flag to disable disable preemption */
216: lwz r4,0(r4) /* Get the timerout value */
217: b lockComm /* Join on up... */
218:
219: /*
220: * void hw_lock_lock(hw_lock_t)
221: *
222: * Acquire lock, spinning until it becomes available.
223: * MACH_RT: also return with preemption disabled.
224: * Apparently not used except by mach_perf.
225: * We will just set a default timeout and jump into the NORMAL timeout lock.
226: */
227:
228: .align 5
229: .globl EXT(hw_lock_lock)
230:
231: LEXT(hw_lock_lock)
232:
233: lockDisa: lis r4,HIGH_ADDR(EXT(LockTimeOut)) /* Get the high part */
234: ori r4,r4,LOW_ADDR(EXT(LockTimeOut)) /* And the low part */
235: cmplw cr1,r1,r1 /* Set flag to enable disable preemption */
236: lwz r4,0(r4) /* Get the timerout value */
237: b lockComm /* Join on up... */
238:
239: /*
240: * unsigned int hw_lock_to(hw_lock_t, unsigned int timeout)
241: *
242: * Try to acquire spin-lock. Return success (1) or failure (0).
243: * Attempt will fail after timeout ticks of the timebase.
244: * We try fairly hard to get this lock. We disable for interruptions, but
245: * reenable after a "short" timeout (128 ticks, we may want to change this).
246: * After checking to see if the large timeout value (passed in) has expired and a
247: * sufficient number of cycles have gone by (to insure pending 'rupts are taken),
248: * we return either in abject failure, or disable and go back to the lock sniff routine.
249: * If the sniffer finds the lock free, it jumps right up and tries to grab it.
250: *
251: * One programming note: NEVER DO NOTHING IN HERE NO HOW THAT WILL FORCE US TO CALL
252: * THIS WITH TRANSLATION OR INTERRUPTIONS EITHER ON OR OFF, GOSH DARN IT!
253: *
254: */
255: .align 5
256: .globl EXT(hw_lock_to)
257:
258: LEXT(hw_lock_to)
259:
260: #if 0
261: lis r0,HIGH_ADDR(CutTrace) /* (TEST/DEBUG) */
262: lis r5,0xEEEE /* (TEST/DEBUG) */
263: oris r0,r0,LOW_ADDR(CutTrace) /* (TEST/DEBUG) */
264: sc /* (TEST/DEBUG) */
265: #endif
266: cmplw cr1,r1,r1 /* Set flag to enable disable preemption */
267:
268: lockComm: mfmsr r9 /* Get the MSR value */
269: mr r5,r3 /* Get the address of the lock */
270: rlwinm r7,r9,0,MSR_EE_BIT+1,MSR_EE_BIT-1 /* Get MSR that is uninterruptible */
271:
272: mtmsr r7 /* Turn off interruptions */
273: mftb r8 /* Get the low part of the time base */
274:
275: lwarx r6,0,r5 ; ?
276:
277: lcktry: lwarx r6,0,r5 /* Grab the lock value */
278: li r3,1 /* Use part of the delay time */
279: mr. r6,r6 /* Is it locked? */
280: bne- lcksniff /* Yeah, wait for it to clear... */
281: stwcx. r3,0,r5 /* Try to seize that there durn lock */
282: #if MACH_RT
283: bne- lcktry /* Couldn't get it... */
284: beq+ cr1,daPreComm /* We got it, go disable preemption if we're supposed to... */
285: mtmsr r9 ; Restore interrupt state
286: blr /* Go on home... */
287: #else /* MACH_RT */
288: beq+ lckgot /* We got it, yahoo... */
289: b lcktry /* Just start up again if the store failed... */
290: #endif /* MACH_RT */
291:
292: .align 5
293:
294: lcksniff: lwz r3,0(r5) /* Get that lock in here */
295: mr. r3,r3 /* Is it free yet? */
296: beq+ lcktry /* Yeah, try for it again... */
297:
298: mftb r10 /* Time stamp us now */
299: sub r10,r10,r8 /* Get the elapsed time */
300: cmplwi r10,128 /* Have we been spinning for 128 tb ticks? */
301: blt+ lcksniff /* Not yet... */
302:
303: mtmsr r9 /* Say, any interrupts pending? */
304:
305: /* The following instructions force the pipeline to be interlocked to that only one
306: instruction is issued per cycle. The insures that we stay enabled for a long enough
307: time; if it's too short, pending interruptions will not have a chance to be taken */
308:
309: subi r4,r4,128 /* Back off elapsed time from timeout value */
310: or r4,r4,r4 /* Do nothing here but force a single cycle delay */
311: mr. r4,r4 /* See if we used the whole timeout */
312: li r3,0 /* Assume a timeout return code */
313: or r4,r4,r4 /* Do nothing here but force a single cycle delay */
314:
315: ble- lckfail /* We failed */
316: mtmsr r7 /* Disable for interruptions */
317: mftb r8 /* Get the low part of the time base */
318: b lcksniff /* Now that we've opened an enable window, keep trying... */
319:
320: #if !MACH_RT
321: lckgot: mtmsr r9 /* Enable for interruptions */
322: isync /* Make sure we don't use a speculativily loaded value */
323: blr
324: #endif /* !MACH_RT */
325:
326: lckfail: /* We couldn't get the lock */
327: li r3,0 /* Set failure return code */
328: blr /* Return, head hanging low... */
329:
330:
331: /*
332: * unsigned int hw_lock_bit(hw_lock_t, unsigned int bit, unsigned int timeout)
333: *
334: * Try to acquire spin-lock. The second parameter is the bit mask to test and set.
335: * multiple bits may be set. Return success (1) or failure (0).
336: * Attempt will fail after timeout ticks of the timebase.
337: * We try fairly hard to get this lock. We disable for interruptions, but
338: * reenable after a "short" timeout (128 ticks, we may want to shorten this).
339: * After checking to see if the large timeout value (passed in) has expired and a
340: * sufficient number of cycles have gone by (to insure pending 'rupts are taken),
341: * we return either in abject failure, or disable and go back to the lock sniff routine.
342: * If the sniffer finds the lock free, it jumps right up and tries to grab it.
343: *
344: * NOTE WELL!!!! THE ROUTINE hw_lock_phys_vir KNOWS WHAT REGISTERS THIS GUY
345: * USES. THIS SAVES A TRANSLATION OFF TO ON TRANSITION AND BACK AND A SAVE AND
346: * RESTORE FROM THE STACK.
347: *
348: */
349:
350: .align 5
351:
352: nop ; Force loop alignment to cache line
353: nop
354: nop
355: nop
356:
357: .globl EXT(hw_lock_bit)
358:
359: LEXT(hw_lock_bit)
360:
361: mfmsr r9 /* Get the MSR value */
362: rlwinm r7,r9,0,MSR_EE_BIT+1,MSR_EE_BIT-1 /* Get MSR that is uninterruptible */
363:
364: mtmsr r7 /* Turn off interruptions */
365:
366: mftb r8 /* Get the low part of the time base */
367:
368: lwarx r0,0,r3 ; ?
369:
370: bittry: lwarx r6,0,r3 /* Grab the lock value */
371: and. r0,r6,r4 /* See if any of the lock bits are on */
372: or r6,r6,r4 /* Turn on the lock bits */
373: bne- bitsniff /* Yeah, wait for it to clear... */
374: stwcx. r6,0,r3 /* Try to seize that there durn lock */
375: beq+ bitgot /* We got it, yahoo... */
376: b bittry /* Just start up again if the store failed... */
377:
378: .align 5
379:
380: bitsniff: lwz r6,0(r3) /* Get that lock in here */
381: and. r0,r6,r4 /* See if any of the lock bits are on */
382: beq+ bittry /* Yeah, try for it again... */
383:
384: mftb r6 /* Time stamp us now */
385: sub r6,r6,r8 /* Get the elapsed time */
386: cmplwi r6,128 /* Have we been spinning for 128 tb ticks? */
387: blt+ bitsniff /* Not yet... */
388:
389: mtmsr r9 /* Say, any interrupts pending? */
390:
391: /* The following instructions force the pipeline to be interlocked to that only one
392: instruction is issued per cycle. The insures that we stay enabled for a long enough
393: time. If it's too short, pending interruptions will not have a chance to be taken
394: */
395:
396: subi r5,r5,128 /* Back off elapsed time from timeout value */
397: or r5,r5,r5 /* Do nothing here but force a single cycle delay */
398: mr. r5,r5 /* See if we used the whole timeout */
399: or r5,r5,r5 /* Do nothing here but force a single cycle delay */
400:
401: ble- bitfail /* We failed */
402: mtmsr r7 /* Disable for interruptions */
403: mftb r8 /* Get the low part of the time base */
404: b bitsniff /* Now that we've opened an enable window, keep trying... */
405:
406: .align 5
407:
408: bitgot: mtmsr r9 /* Enable for interruptions */
409: li r3,1 /* Set good return code */
410: isync /* Make sure we don't use a speculativily loaded value */
411: blr
412:
413: bitfail: li r3,0 /* Set failure return code */
414: blr /* Return, head hanging low... */
415:
416:
417: /*
418: * unsigned int hw_unlock_bit(hw_lock_t, unsigned int bit)
419: *
420: * Release bit based spin-lock. The second parameter is the bit mask to clear.
421: * Multiple bits may be cleared.
422: *
423: * NOTE WELL!!!! THE ROUTINE hw_lock_phys_vir KNOWS WHAT REGISTERS THIS GUY
424: * USES. THIS SAVES A TRANSLATION OFF TO ON TRANSITION AND BACK AND A SAVE AND
425: * RESTORE FROM THE STACK.
426: */
427:
428: .align 5
429: .globl EXT(hw_unlock_bit)
430:
431: LEXT(hw_unlock_bit)
432:
433: sync
434: lwarx r0,0,r3 ; ?
435:
436: ubittry: lwarx r0,0,r3 /* Grab the lock value */
437: andc r0,r0,r4 /* Clear the lock bits */
438: stwcx. r0,0,r3 /* Try to clear that there durn lock */
439: bne- ubittry /* Try again, couldn't save it... */
440:
441: blr /* Leave... */
442:
443: /*
444: * unsigned int hw_lock_mbits(hw_lock_t, unsigned int bits, unsigned int value,
445: * unsigned int newb, unsigned int timeout)
446: *
447: * Try to acquire spin-lock. The second parameter is the bit mask to check.
448: * The third is the value of those bits and the 4th is what to set them to.
449: * Return success (1) or failure (0).
450: * Attempt will fail after timeout ticks of the timebase.
451: * We try fairly hard to get this lock. We disable for interruptions, but
452: * reenable after a "short" timeout (128 ticks, we may want to shorten this).
453: * After checking to see if the large timeout value (passed in) has expired and a
454: * sufficient number of cycles have gone by (to insure pending 'rupts are taken),
455: * we return either in abject failure, or disable and go back to the lock sniff routine.
456: * If the sniffer finds the lock free, it jumps right up and tries to grab it.
457: *
458: */
459:
460: .align 5
461:
462: nop ; Force loop alignment to cache line
463: nop
464: nop
465: nop
466:
467: .globl EXT(hw_lock_mbits)
468:
469: LEXT(hw_lock_mbits)
470:
471: mfmsr r9 ; Get the MSR value
472: rlwinm r8,r9,0,MSR_EE_BIT+1,MSR_EE_BIT-1 ; Get MSR that is uninterruptible
473:
474: mtmsr r8 ; Turn off interruptions
475:
476: mftb r10 ; Get the low part of the time base
477:
478: lwarx r0,0,r3 ; ?
479:
480: mbittry: lwarx r12,0,r3 ; Grab the lock value
481: and r0,r12,r4 ; Clear extra bits
482: or r12,r12,r6 ; Turn on the lock bits
483: cmplw r0,r5 ; Are these the right bits?
484: bne- mbitsniff ; Nope, wait for it to clear...
485: stwcx. r12,0,r3 ; Try to seize that there durn lock
486: beq+ mbitgot ; We got it, yahoo...
487: b mbittry ; Just start up again if the store failed...
488:
489: .align 5
490:
491: mbitsniff: lwz r12,0(r3) ; Get that lock in here
492: and r0,r12,r4 ; Clear extra bits
493: or r12,r12,r6 ; Turn on the lock bits
494: cmplw r0,r5 ; Are these the right bits?
495: beq+ mbittry ; Yeah, try for it again...
496:
497: mftb r11 ; Time stamp us now
498: sub r11,r11,r10 ; Get the elapsed time
499: cmplwi r11,128 ; Have we been spinning for 128 tb ticks?
500: blt+ mbitsniff ; Not yet...
501:
502: mtmsr r9 ; Say, any interrupts pending?
503:
504: ; The following instructions force the pipeline to be interlocked to that only one
505: ; instruction is issued per cycle. The insures that we stay enabled for a long enough
506: ; time. If it is too short, pending interruptions will not have a chance to be taken
507:
508: subi r7,r7,128 ; Back off elapsed time from timeout value
509: or r7,r7,r7 ; Do nothing here but force a single cycle delay
510: mr. r7,r7 ; See if we used the whole timeout
511: or r7,r7,r7 ; Do nothing here but force a single cycle delay
512:
513: ble- mbitfail ; We failed
514: mtmsr r8 ; Disable for interruptions
515: mftb r10 ; Get the low part of the time base
516: b mbitsniff ; Now that we have opened an enable window, keep trying...
517:
518: .align 5
519:
520: mbitgot: mtmsr r9 ; Enable for interruptions
521: li r3,1 ; Set good return code
522: isync ; Make sure we do not use a speculativily loaded value
523: blr
524:
525: mbitfail: li r3,0 ; Set failure return code
526: blr ; Return, head hanging low...
527:
528:
529: /*
530: * unsigned int hw_cpu_sync(unsigned int *, unsigned int timeout)
531: *
532: * Spin until word hits 0 or timeout.
533: * Return success (1) or failure (0).
534: * Attempt will fail after timeout ticks of the timebase.
535: *
536: * The theory is that a processor will bump a counter as it signals
537: * other processors. Then it will spin untl the counter hits 0 (or
538: * times out). The other processors, as it receives the signal will
539: * decrement the counter.
540: *
541: * The other processors use interlocked update to decrement, this one
542: * does not need to interlock.
543: *
544: */
545:
546: .align 5
547:
548: .globl EXT(hw_cpu_sync)
549:
550: LEXT(hw_cpu_sync)
551:
552: mftb r10 ; Get the low part of the time base
553: mr r9,r3 ; Save the sync word address
554: li r3,1 ; Assume we work
555:
556: csynctry: lwz r11,0(r9) ; Grab the sync value
557: mr. r11,r11 ; Counter hit 0?
558: beqlr- ; Yeah, we are sunk...
559: mftb r12 ; Time stamp us now
560:
561: sub r12,r12,r10 ; Get the elapsed time
562: cmplw r4,r12 ; Have we gone too long?
563: bge+ csynctry ; Not yet...
564:
565: li r3,0 ; Set failure...
566: blr ; Return, head hanging low...
567:
568:
569: /*
570: * unsigned int hw_lock_try(hw_lock_t)
571: *
572: * try to acquire spin-lock. Return success (1) or failure (0)
573: * MACH_RT: returns with preemption disabled on success.
574: *
575: */
576: .align 5
577: .globl EXT(hw_lock_try)
578:
579: LEXT(hw_lock_try)
580:
581: #if 0
582: lis r0,HIGH_ADDR(CutTrace) /* (TEST/DEBUG) */
583: lis r5,0x9999 /* (TEST/DEBUG) */
584: oris r0,r0,LOW_ADDR(CutTrace) /* (TEST/DEBUG) */
585: sc /* (TEST/DEBUG) */
586: #endif
587: mfmsr r9 /* Save the MSR value */
588: li r4, 1 /* value to be stored... 1==taken */
589: rlwinm r7,r9,0,MSR_EE_BIT+1,MSR_EE_BIT-1 /* Clear interruption bit */
590:
591: #if MACH_LDEBUG
592: lis r5, 0x10 /* roughly 1E6 */
593: mtctr r5
594: #endif /* MACH_LDEBUG */
595:
596: mtmsr r7 /* Disable interruptions and thus, preemption */
597:
598: lwarx r5,0,r3 ; ?
599:
600: .L_lock_try_loop:
601:
602: #if MACH_LDEBUG
603: bdnz+ 0f /* Count attempts */
604: mtmsr r9 /* Restore enablement */
605: BREAKPOINT_TRAP /* Get to debugger */
606: mtmsr r7 /* Disable interruptions and thus, preemption */
607: 0:
608: #endif /* MACH_LDEBUG */
609:
610: lwarx r5,0,r3 /* Ld from addr of arg and reserve */
611:
612: cmpwi r5, 0 /* TEST... */
613: bne- .L_lock_try_failed /* branch if taken. Predict free */
614:
615: stwcx. r4, 0,r3 /* And SET (if still reserved) */
616: mfsprg r6,0 /* Get the per_proc block */
617: bne- .L_lock_try_loop /* If set failed, loop back */
618:
619: lwz r6,PP_CPU_DATA(r6) /* Get the pointer to the CPU data from per proc */
620: isync
621:
622: #if MACH_RT
623: lwz r5,CPU_PREEMPTION_LEVEL(r6) /* Get the preemption level */
624: addi r5,r5,1 /* Bring up the disable count */
625: stw r5,CPU_PREEMPTION_LEVEL(r6) /* Save it back */
626:
627: #endif /* MACH_RT */
628:
629: mtmsr r9 /* Allow interruptions now */
630: li r3,1 /* Set that the lock was free */
631: blr
632:
633: .L_lock_try_failed:
634: mtmsr r9 /* Allow interruptions now */
635: li r3,0 /* FAILURE - lock was taken */
636: blr
637:
638: /*
639: * unsigned int hw_lock_held(hw_lock_t)
640: *
641: * Return 1 if lock is held
642: * MACH_RT: doesn't change preemption state.
643: * N.B. Racy, of course.
644: *
645: */
646: .align 5
647: .globl EXT(hw_lock_held)
648:
649: LEXT(hw_lock_held)
650:
651: #if 0
652: lis r0,HIGH_ADDR(CutTrace) /* (TEST/DEBUG) */
653: lis r5,0x8888 /* (TEST/DEBUG) */
654: oris r0,r0,LOW_ADDR(CutTrace) /* (TEST/DEBUG) */
655: sc /* (TEST/DEBUG) */
656: #endif
657: isync /* Make sure we don't use a speculativily fetched lock */
658: lwz r3, 0(r3) /* Return value of lock */
659: blr
660:
661: /*
662: * unsigned int hw_compare_and_store(unsigned int old, unsigned int new, unsigned int *area)
663: *
664: * Compare old to area if equal, store new, and return true
665: * else return false and no store
666: * This is an atomic operation
667: *
668: */
669: .align 5
670: .globl EXT(hw_compare_and_store)
671:
672: LEXT(hw_compare_and_store)
673:
674: mr r6,r3 /* Save the old value */
675:
676: lwarx r9,0,r5 ; ?
677:
678: cstry: lwarx r9,0,r5 /* Grab the area value */
679: li r3,1 /* Assume it works */
680: cmplw cr0,r9,r6 /* Does it match the old value? */
681: bne- csfail /* No, it must have changed... */
682: stwcx. r4,0,r5 /* Try to save the new value */
683: bne- cstry /* Didn't get it, try again... */
684: isync /* Just hold up prefetch */
685: blr /* Return... */
686:
687: csfail: li r3,0 /* Set failure */
688: blr /* Better luck next time... */
689:
690:
691: /*
692: * unsigned int hw_atomic_add(unsigned int *area, int *val)
693: *
694: * Atomically add the second parameter to the first.
695: * Returns the result.
696: *
697: */
698: .align 5
699: .globl EXT(hw_atomic_add)
700:
701: LEXT(hw_atomic_add)
702:
703: mr r6,r3 /* Save the area */
704:
705: lwarx r3,0,r6 ; ?
706:
707: addtry: lwarx r3,0,r6 /* Grab the area value */
708: add r3,r3,r4 /* Add the value */
709: stwcx. r3,0,r6 /* Try to save the new value */
710: bne- addtry /* Didn't get it, try again... */
711: blr /* Return... */
712:
713:
714: /*
715: * unsigned int hw_atomic_sub(unsigned int *area, int *val)
716: *
717: * Atomically subtract the second parameter from the first.
718: * Returns the result.
719: *
720: */
721: .align 5
722: .globl EXT(hw_atomic_sub)
723:
724: LEXT(hw_atomic_sub)
725:
726: mr r6,r3 /* Save the area */
727:
728: lwarx r3,0,r6 ; ?
729:
730: subtry: lwarx r3,0,r6 /* Grab the area value */
731: sub r3,r3,r4 /* Subtract the value */
732: stwcx. r3,0,r6 /* Try to save the new value */
733: bne- subtry /* Didn't get it, try again... */
734: blr /* Return... */
735:
736:
737: /*
738: * void hw_queue_atomic(unsigned int * anchor, unsigned int * elem, unsigned int disp)
739: *
740: * Atomically inserts the element at the head of the list
741: * anchor is the pointer to the first element
742: * element is the pointer to the element to insert
743: * disp is the displacement into the element to the chain pointer
744: *
745: */
746: .align 5
747: .globl EXT(hw_queue_atomic)
748:
749: LEXT(hw_queue_atomic)
750:
751: mr r7,r4 /* Make end point the same as start */
752: mr r8,r5 /* Copy the displacement also */
753: b hw_queue_comm /* Join common code... */
754:
755: /*
756: * void hw_queue_atomic_list(unsigned int * anchor, unsigned int * first, unsigned int * last, unsigned int disp)
757: *
758: * Atomically inserts the list of elements at the head of the list
759: * anchor is the pointer to the first element
760: * first is the pointer to the first element to insert
761: * last is the pointer to the last element to insert
762: * disp is the displacement into the element to the chain pointer
763: *
764: */
765: .align 5
766: .globl EXT(hw_queue_atomic_list)
767:
768: LEXT(hw_queue_atomic_list)
769:
770: mr r7,r5 /* Make end point the same as start */
771: mr r8,r6 /* Copy the displacement also */
772:
773: hw_queue_comm:
774: lwarx r9,0,r3 ; ?
775:
776: hw_queue_comm2:
777: lwarx r9,0,r3 /* Pick up the anchor */
778: stwx r9,r8,r7 /* Chain that to the end of the new stuff */
779: stwcx. r4,0,r3 /* Try to chain into the front */
780: bne- hw_queue_comm2 /* Didn't make it, try again... */
781:
782: blr /* Return... */
783:
784: /*
785: * unsigned int *hw_dequeue_atomic(unsigned int *anchor, unsigned int disp)
786: *
787: * Atomically removes the first element in a list and returns it.
788: * anchor is the pointer to the first element
789: * disp is the displacement into the element to the chain pointer
790: * Returns element if found, 0 if empty.
791: *
792: */
793: .align 5
794: .globl EXT(hw_dequeue_atomic)
795:
796: LEXT(hw_dequeue_atomic)
797:
798: mr r5,r3 /* Save the anchor */
799:
800: hw_dequeue_comm:
801: lwarx r9,0,r3 ; ?
802:
803: hw_dequeue_comm2:
804: lwarx r3,0,r5 /* Pick up the anchor */
805: mr. r3,r3 /* Is the list empty? */
806: beqlr- /* Leave it list empty... */
807: lwzx r9,r4,r3 /* Get the next in line */
808: stwcx. r9,0,r5 /* Try to chain into the front */
809: beqlr+ ; Got the thing, go away with it...
810: b hw_dequeue_comm2 ; Did not make it, try again...
811:
812: /*
813: * void mutex_init(mutex_t* l, etap_event_t etap)
814: */
815:
816: ENTRY(mutex_init,TAG_NO_FRAME_USED)
817:
818: PROLOG(0)
819: li r10, 0
820: stw r10, MUTEX_ILK(r3) /* clear interlock */
821: stw r10, MUTEX_LOCKED(r3) /* clear locked flag */
822: sth r10, MUTEX_WAITERS(r3) /* init waiter count */
823:
824: #if MACH_LDEBUG
825: stw r10, MUTEX_PC(r3) /* init caller pc */
826: stw r10, MUTEX_THREAD(r3) /* and owning thread */
827: li r10, MUTEX_TAG
828: stw r10, MUTEX_TYPE(r3) /* set lock type */
829: #endif /* MACH_LDEBUG */
830:
831: #if ETAP_LOCK_TRACE
832: bl EXT(etap_mutex_init) /* init ETAP data */
833: #endif /* ETAP_LOCK_TRACE */
834:
835: EPILOG
836: blr
837:
838: /*
839: * void _mutex_lock(mutex_t*)
840: */
841:
842: .align 5
843: .globl EXT(_mutex_lock)
844:
845: LEXT(_mutex_lock)
846:
847: PROLOG(12)
848:
849: #if ETAP_LOCK_TRACE
850: li r0, 0
851: stw r0,SWT_HI(r1) /* set wait time to 0 (HI) */
852: stw r0,SWT_LO(r1) /* set wait time to 0 (LO) */
853: stw r0,MISSED(r1) /* clear local miss marker */
854: #endif /* ETAP_LOCK_TRACE */
855:
856: CHECK_MUTEX_TYPE()
857: CHECK_NO_SIMPLELOCKS()
858:
859: .L_ml_retry:
860: #if 0
861: mfsprg r4,0 /* (TEST/DEBUG) */
862: lwz r4,PP_CPU_DATA(r4) /* (TEST/DEBUG) */
863: lis r0,HIGH_ADDR(CutTrace) /* (TEST/DEBUG) */
864: lwz r4,CPU_ACTIVE_THREAD(r4) /* (TEST/DEBUG) */
865: lis r5,0xAAAA /* (TEST/DEBUG) */
866: oris r0,r0,LOW_ADDR(CutTrace) /* (TEST/DEBUG) */
867: sc /* (TEST/DEBUG) */
868: #endif
869:
870: bl lockDisa /* Go get a lock on the mutex's interlock lock */
871: mr. r4,r3 /* Did we get it? */
872: lwz r3,FM_ARG0(r1) /* Restore the lock address */
873: bne+ mlGotInt /* We got it just fine... */
874:
875: lis r3,HIGH_ADDR(mutex_failed1) ; Get the failed mutex message
876: ori r3,r3,LOW_ADDR(mutex_failed1) ; Get the failed mutex message
877: bl EXT(panic) ; Call panic
878: BREAKPOINT_TRAP ; We die here anyway, can not get the lock
879:
880: .data
881: mutex_failed1:
882: STRINGD "We can't get a mutex interlock lock on mutex_lock\n\000"
883: .text
884:
885: mlGotInt:
886:
887: /* Note that there is no reason to do a load and reserve here. We already
888: hold the interlock lock and no one can touch this field unless they
889: have that, so, we're free to play */
890:
891: lwz r4,MUTEX_LOCKED(r3) /* Get the mutex's lock field */
892:
893: li r10,1 /* Set the lock value */
894:
895: mr. r4,r4 /* So, can we have it? */
896: bne- mlInUse /* Nope, sombody's playing already... */
897:
898: stw r10,MUTEX_LOCKED(r3) /* Take it unto ourselves */
899:
900: #if MACH_LDEBUG
901: mfsprg r9,0 /* Get the per_proc block */
902: lwz r10,0(r1) /* Get previous save frame */
903: lwz r9,PP_CPU_DATA(r9) /* Point to the cpu data area */
904: lwz r10,FM_LR_SAVE(r10) /* Get our caller's address */
905: lwz r8, CPU_ACTIVE_THREAD(r9) /* Get the active thread */
906: stw r10,MUTEX_PC(r3) /* Save our caller */
907: mr. r8,r8 /* Is there any thread? */
908: stw r8,MUTEX_THREAD(r3) /* Set the mutex's holding thread */
909: beq- .L_ml_no_active_thread /* No owning thread... */
910: lwz r9,THREAD_MUTEX_COUNT(r8) /* Get the mutex count */
911: addi r9,r9,1 /* Bump it up */
912: stw r9,THREAD_MUTEX_COUNT(r8) /* Stash it back */
913: .L_ml_no_active_thread:
914: #endif /* MACH_LDEBUG */
915:
916: li r10,0 /* Get the unlock value */
917: sync /* Push it all out */
918: stw r10,MUTEX_ILK(r3) /* free the interlock */
919:
920: #if ETAP_LOCK_TRACE
921: mflr r4
922: lwz r5,SWT_HI(r1)
923: lwz r6,SWT_LO(r1)
924: bl EXT(etap_mutex_hold) /* collect hold timestamp */
925: #endif /* ETAP_LOCK_TRACE */
926:
927: EPILOG /* Restore all saved registers */
928:
929: #if MACH_RT
930: b epStart /* Go enable preemption... */
931: #else
932: blr /* Return... */
933: #endif
934:
935: /*
936: * We come to here when we have a resource conflict. In other words,
937: * the mutex is held.
938: */
939:
940: mlInUse:
941:
942: #if ETAP_LOCK_TRACE
943: lwz r7,MISSED(r1)
944: cmpwi r7,0 /* did we already take a wait timestamp ? */
945: bne .L_ml_block /* yup. carry-on */
946: bl EXT(etap_mutex_miss) /* get wait timestamp */
947: stw r3,SWT_HI(r1) /* store timestamp */
948: stw r4,SWT_LO(r1)
949: li r7, 1 /* mark wait timestamp as taken */
950: stw r7,MISSED(r1)
951: lwz r3,FM_ARG0(r1) /* restore r3 (saved in prolog) */
952: .L_ml_block:
953: #endif /* ETAP_LOCK_TRACE */
954:
955: CHECK_MYLOCK(MUTEX_THREAD) /* Assert we don't own the lock already */
956:
957:
958: /* Note that we come in here with the interlock set. The wait routine
959: * will unlock it before waiting.
960: */
961: bl EXT(mutex_lock_wait) /* Wait for our turn at the lock */
962:
963: lwz r3,FM_ARG0(r1) /* restore r3 (saved in prolog) */
964: b .L_ml_retry /* and try again... */
965:
966:
967: /*
968: * void _mutex_try(mutex_t*)
969: *
970: */
971:
972: .align 5
973: .globl EXT(_mutex_try)
974:
975: LEXT(_mutex_try)
976:
977: PROLOG(8) /* reserve space for SWT_HI and SWT_LO */
978:
979: #if ETAP_LOCK_TRACE
980: li r5, 0
981: stw r5, STW_HI(r1) /* set wait time to 0 (HI) */
982: stw r5, SWT_LO(r1) /* set wait time to 0 (LO) */
983: #endif /* ETAP_LOCK_TRACE */
984:
985: #if 0
986: lis r0,HIGH_ADDR(CutTrace) /* (TEST/DEBUG) */
987: lis r5,0xBBBB /* (TEST/DEBUG) */
988: oris r0,r0,LOW_ADDR(CutTrace) /* (TEST/DEBUG) */
989: sc /* (TEST/DEBUG) */
990: #endif
991: CHECK_MUTEX_TYPE()
992: CHECK_NO_SIMPLELOCKS()
993:
994: lwz r6,MUTEX_LOCKED(r3) /* Quick check */
995: mr. r6,r6 /* to see if someone has this lock already */
996: bne- mtFail /* Someone's got it already... */
997:
998: bl lockLock /* Go get a lock on the mutex's interlock lock */
999: mr. r4,r3 /* Did we get it? */
1000: lwz r3,FM_ARG0(r1) /* Restore the lock address */
1001: bne+ mtGotInt /* We got it just fine... */
1002:
1003: lis r3,HIGH_ADDR(mutex_failed2) ; Get the failed mutex message
1004: ori r3,r3,LOW_ADDR(mutex_failed2) ; Get the failed mutex message
1005: bl EXT(panic) ; Call panic
1006: BREAKPOINT_TRAP ; We die here anyway, can not get the lock
1007:
1008: .data
1009: mutex_failed2:
1010: STRINGD "We can't get a mutex interlock lock on mutex_try\n\000"
1011: .text
1012:
1013: mtGotInt:
1014:
1015: /* Note that there is no reason to do a load and reserve here. We already
1016: hold the interlock and no one can touch at this field unless they
1017: have that, so, we're free to play */
1018:
1019: lwz r4,MUTEX_LOCKED(r3) /* Get the mutex's lock field */
1020:
1021: li r10,1 /* Set the lock value */
1022:
1023: mr. r4,r4 /* So, can we have it? */
1024: bne- mtInUse /* Nope, sombody's playing already... */
1025:
1026: stw r10,MUTEX_LOCKED(r3) /* Take it unto ourselves */
1027:
1028: #if MACH_LDEBUG
1029: mfsprg r9,0 /* Get the per_proc block */
1030: lwz r10,0(r1) /* Get previous save frame */
1031: lwz r9,PP_CPU_DATA(r9) /* Point to the cpu data area */
1032: lwz r10,FM_LR_SAVE(r10) /* Get our caller's address */
1033: lwz r8, CPU_ACTIVE_THREAD(r9) /* Get the active thread */
1034: stw r10,MUTEX_PC(r3) /* Save our caller */
1035: mr. r8,r8 /* Is there any thread? */
1036: stw r8,MUTEX_THREAD(r3) /* Set the mutex's holding thread */
1037: beq- .L_mt_no_active_thread /* No owning thread... */
1038: lwz r9, THREAD_MUTEX_COUNT(r8) /* Get the mutex count */
1039: addi r9, r9, 1 /* Bump it up */
1040: stw r9, THREAD_MUTEX_COUNT(r8) /* Stash it back */
1041: .L_mt_no_active_thread:
1042: #endif /* MACH_LDEBUG */
1043:
1044: li r10,0 /* Get the unlock value */
1045: sync /* Push it all out */
1046: stw r10,MUTEX_ILK(r3) /* free the interlock */
1047:
1048: #if ETAP_LOCK_TRACE
1049: lwz r4,0(r1) /* Back chain the stack */
1050: lwz r5,SWT_HI(r1)
1051: lwz r4,FM_LR_SAVE(r4) /* Get our caller's address */
1052: lwz r6,SWT_LO(r1)
1053: bl EXT(etap_mutex_hold) /* collect hold timestamp */
1054: #endif /* ETAP_LOCK_TRACE */
1055:
1056: EPILOG /* Restore all saved registers */
1057: blr /* Return... */
1058:
1059: /*
1060: * We come to here when we have a resource conflict. In other words,
1061: * the mutex is held.
1062: */
1063:
1064: mtInUse: li r10,0 /* Get the unlock value */
1065: sync /* Push it all out */
1066: stw r10,MUTEX_ILK(r3) /* free the interlock */
1067:
1068: mtFail: li r3,0 /* Set failure code */
1069: EPILOG /* Restore all saved registers */
1070: blr /* Return... */
1071:
1072:
1073: /*
1074: * void mutex_unlock(mutex_t* l)
1075: */
1076:
1077: .align 5
1078: .globl EXT(mutex_unlock)
1079:
1080: LEXT(mutex_unlock)
1081:
1082: PROLOG(0)
1083:
1084: #if ETAP_LOCK_TRACE
1085: bl EXT(etap_mutex_unlock) /* collect ETAP data */
1086: lwz r3,FM_ARG0(r1) /* restore r3 (saved in prolog) */
1087: #endif /* ETAP_LOCK_TRACE */
1088:
1089: CHECK_MUTEX_TYPE()
1090: CHECK_THREAD(MUTEX_THREAD)
1091:
1092: #if 0
1093: mfsprg r4,0 /* (TEST/DEBUG) */
1094: lwz r4,PP_CPU_DATA(r4) /* (TEST/DEBUG) */
1095: lis r0,HIGH_ADDR(CutTrace) /* (TEST/DEBUG) */
1096: lwz r4,CPU_ACTIVE_THREAD(r4) /* (TEST/DEBUG) */
1097: lis r5,0xCCCC /* (TEST/DEBUG) */
1098: oris r0,r0,LOW_ADDR(CutTrace) /* (TEST/DEBUG) */
1099: sc /* (TEST/DEBUG) */
1100: #endif
1101: bl lockDisa /* Go get a lock on the mutex's interlock lock */
1102: mr. r4,r3 /* Did we get it? */
1103: lwz r3,FM_ARG0(r1) /* Restore the lock address */
1104: bne+ muGotInt /* We got it just fine... */
1105:
1106: lis r3,HIGH_ADDR(mutex_failed3) ; Get the failed mutex message
1107: ori r3,r3,LOW_ADDR(mutex_failed3) ; Get the failed mutex message
1108: bl EXT(panic) ; Call panic
1109: BREAKPOINT_TRAP ; We die here anyway, can not get the lock
1110:
1111: .data
1112: mutex_failed3:
1113: STRINGD "We can't get a mutex interlock lock on mutex_unlock\n\000"
1114: .text
1115:
1116:
1117: muGotInt:
1118: lhz r10,MUTEX_WAITERS(r3) /* are there any waiters ? */
1119: cmpwi r10,0
1120: beq+ muUnlock /* Nope, we're done... */
1121:
1122: bl EXT(mutex_unlock_wakeup) /* yes, wake a thread */
1123: lwz r3,FM_ARG0(r1) /* restore r3 (saved in prolog) */
1124: li r10,0 /* Get unlock value */
1125:
1126: muUnlock:
1127: #if MACH_LDEBUG
1128: mfsprg r9,0
1129: lwz r9,PP_CPU_DATA(r9)
1130: lwz r9,CPU_ACTIVE_THREAD(r9)
1131: stw r10,MUTEX_THREAD(r3) /* disown thread */
1132: cmpwi r9,0
1133: beq- .L_mu_no_active_thread
1134: lwz r8,THREAD_MUTEX_COUNT(r9)
1135: subi r8,r8,1
1136: stw r8,THREAD_MUTEX_COUNT(r9)
1137: .L_mu_no_active_thread:
1138: #endif /* MACH_LDEBUG */
1139:
1140: stw r10,MUTEX_LOCKED(r3) /* release the mutex */
1141: sync /* Make sure it's all there before we release */
1142: stw r10,MUTEX_ILK(r3) /* unlock the interlock */
1143:
1144: EPILOG /* Deal with the stack now, enable_preemption doesn't always want one */
1145: #if MACH_RT
1146: b epStart /* Go enable preemption... */
1147: #else
1148: blr /* Return... */
1149: #endif
1150:
1151: /*
1152: * void interlock_unlock(hw_lock_t lock)
1153: */
1154:
1155: .align 5
1156: .globl EXT(interlock_unlock)
1157:
1158: LEXT(interlock_unlock)
1159:
1160: #if 0
1161: lis r0,HIGH_ADDR(CutTrace) /* (TEST/DEBUG) */
1162: lis r5,0xDDDD /* (TEST/DEBUG) */
1163: oris r0,r0,LOW_ADDR(CutTrace) /* (TEST/DEBUG) */
1164: sc /* (TEST/DEBUG) */
1165: #endif
1166: li r10,0
1167: sync
1168: stw r10,0(r3)
1169:
1170: #if MACH_RT
1171: b epStart /* Go enable preemption... */
1172: #else
1173: blr /* Return... */
1174: #endif
1175:
1176: #if MACH_RT
1177: /*
1178: * Here is where we enable preemption. We need to be protected
1179: * against ourselves, we can't chance getting interrupted and modifying
1180: * our processor wide preemption count after we'sve loaded it up. So,
1181: * we need to disable all 'rupts. Actually, we could use a compare
1182: * and swap to do this, but, since there are no MP considerations
1183: * (we are dealing with a CPU local field) it is much, much faster
1184: * to disable.
1185: *
1186: * Note that if we are not genned MP, the calls here will be no-opped via
1187: * a #define and since the _mp forms are the same, likewise a #define
1188: * will be used to route to the other forms
1189: */
1190:
1191: /* This version does not check if we get preempted or not */
1192:
1193:
1194: .align 4
1195: .globl EXT(_enable_preemption_no_check)
1196:
1197: LEXT(_enable_preemption_no_check)
1198: cmplw cr1,r1,r1 /* Force zero cr so we know not to check if preempted */
1199: b epCommn /* Join up with the other enable code... */
1200:
1201:
1202: /* This version checks if we get preempted or not */
1203:
1204: .align 5
1205: .globl EXT(_enable_preemption)
1206:
1207: LEXT(_enable_preemption)
1208:
1209: epStart: cmplwi cr1,r1,0 /* Force non-zero cr so we know to check if preempted */
1210:
1211: /*
1212: * Common enable preemption code
1213: */
1214:
1215: epCommn: mfmsr r9 /* Save the old MSR */
1216: rlwinm r8,r9,0,MSR_EE_BIT+1,MSR_EE_BIT-1 /* Clear interruptions */
1217: mtmsr r8 /* Interrupts off */
1218:
1219: mfsprg r3,0 /* Get the per_proc block */
1220: lwz r6,PP_CPU_DATA(r3) /* Get the pointer to the CPU data from per proc */
1221: li r8,-1 /* Get a decrimenter */
1222: lwz r5,CPU_PREEMPTION_LEVEL(r6) /* Get the preemption level */
1223: add. r5,r5,r8 /* Bring down the disable count */
1224: #if 0
1225: mfsprg r4,1 ; (TEST/DEBUG) Note the next 3 keep from interrpting too early
1226: mr. r4,r4 ; (TEST/DEBUG)
1227: beq- epskptrc0 ; (TEST/DEBUG)
1228: lis r0,hi16(CutTrace) ; (TEST/DEBUG)
1229: lis r4,0xBBBB ; (TEST/DEBUG)
1230: oris r0,r0,lo16(CutTrace) ; (TEST/DEBUG)
1231: sc ; (TEST/DEBUG)
1232: epskptrc0: mr. r5,r5 ; (TEST/DEBUG)
1233: #endif
1234: #if MACH_LDEBUG
1235: blt- epTooFar /* Yeah, we did... */
1236: #endif /* MACH_LDEBUG */
1237: stw r5,CPU_PREEMPTION_LEVEL(r6) /* Save it back */
1238:
1239: beq+ epCheckPreempt /* Go check if we need to be preempted... */
1240:
1241: epNoCheck: mtmsr r9 /* Restore the interrupt level */
1242: blr /* Leave... */
1243:
1244: #if MACH_LDEBUG
1245: epTooFar:
1246: lis r6,HIGH_ADDR(EXT(panic)) /* First half of panic call */
1247: lis r3,HIGH_ADDR(epTooFarStr) /* First half of panic string */
1248: ori r6,r6,LOW_ADDR(EXT(panic)) /* Second half of panic call */
1249: ori r3,r3,LOW_ADDR(epTooFarStr) /* Second half of panic string */
1250: mtlr r6 /* Get the address of the panic routine */
1251: mtmsr r9 /* Restore interruptions */
1252: blrl /* Panic... */
1253:
1254: .data
1255: epTooFarStr:
1256: STRINGD "_enable_preemption: preemption_level <= 0!\000"
1257: .text
1258: #endif /* MACH_LDEBUG */
1259:
1260: .align 5
1261:
1262: epCheckPreempt:
1263: lwz r7,PP_NEED_AST(r3) /* Get the AST request address */
1264: lwz r6,PP_CPU_DATA(r3) /* Get the pointer to the CPU data from per proc */
1265: li r5,AST_URGENT /* Get the requests we do honor */
1266: lwz r7,0(r7) /* Get the actual, real live, extra special AST word */
1267: lis r0,HIGH_ADDR(DoPreemptCall) /* Just in case, get the top of firmware call */
1268: and. r7,r7,r5 ; Should we preempt?
1269: ori r0,r0,LOW_ADDR(DoPreemptCall) /* Merge in bottom part */
1270: beq+ epCPno ; No preemption here...
1271:
1272: andi. r3,r9,lo16(MASK(MSR_EE)) ; We cannot preempt if interruptions are off
1273:
1274: epCPno: mtmsr r9 /* Allow interrupts if we can */
1275: beqlr+ ; We probably will not preempt...
1276: sc /* Do the preemption */
1277: blr /* Now, go away now... */
1278:
1279: /*
1280: * Here is where we disable preemption. Since preemption is on a
1281: * per processor basis (a thread runs on one CPU at a time) we don't
1282: * need any cross-processor synchronization. We do, however, need to
1283: * be interrupt safe, so we don't preempt while in the process of
1284: * disabling it. We could use SPLs, but since we always want complete
1285: * disablement, and this is platform specific code, we'll just kick the
1286: * MSR. We'll save a couple of orders of magnitude over using SPLs.
1287: */
1288:
1289: .align 5
1290:
1291: nop ; Use these 5 nops to force daPreComm
1292: nop ; to a line boundary.
1293: nop
1294: nop
1295: nop
1296:
1297: .globl EXT(_disable_preemption)
1298:
1299: LEXT(_disable_preemption)
1300:
1301: daPreAll: mfmsr r9 /* Save the old MSR */
1302: rlwinm r8,r9,0,MSR_EE_BIT+1,MSR_EE_BIT-1 /* Clear interruptions */
1303: mtmsr r8 /* Interrupts off */
1304:
1305: daPreComm: mfsprg r6,0 /* Get the per_proc block */
1306: lwz r6,PP_CPU_DATA(r6) /* Get the pointer to the CPU data from per proc */
1307: lwz r5,CPU_PREEMPTION_LEVEL(r6) /* Get the preemption level */
1308: addi r5,r5,1 /* Bring up the disable count */
1309: stw r5,CPU_PREEMPTION_LEVEL(r6) /* Save it back */
1310: #if 0
1311: mfsprg r4,1 ; (TEST/DEBUG) Note the next 3 keep from interrpting too early
1312: mr. r4,r4 ; (TEST/DEBUG)
1313: beq- epskptrc1 ; (TEST/DEBUG)
1314: lis r0,hi16(CutTrace) ; (TEST/DEBUG)
1315: lis r4,0xAAAA ; (TEST/DEBUG)
1316: oris r0,r0,lo16(CutTrace) ; (TEST/DEBUG)
1317: sc ; (TEST/DEBUG)
1318: epskptrc1: ; (TEST/DEBUG)
1319: #endif
1320:
1321: #if 0
1322: lwz r6,CPU_ACTIVE_THREAD(r6) ; Get the pointer to the currently active thread
1323: mr. r6,r6 ; During boot?
1324: beq- nopredeb ; Yes, do not do backtrace...
1325: lwz r6,THREAD_TOP_ACT(r6) ; Point to the active activation
1326: lwz r6,ACT_MACT_PCB(r6) ; Get the last savearea used
1327: mr. r0,r6 ; Any saved context?
1328: beq- nosaveds ; No...
1329: lwz r0,saver1(r6) ; Get end of savearea chain
1330:
1331: nosaveds: li r11,0 ; Clear callers callers callers return
1332: li r10,0 ; Clear callers callers callers callers return
1333: li r8,0 ; Clear callers callers callers callers callers return
1334: lwz r2,0(r1) ; Get callers callers stack frame
1335: lwz r12,8(r2) ; Get our callers return
1336: lwz r4,0(r2) ; Back chain
1337:
1338: xor r2,r4,r2 ; Form difference
1339: cmplwi r2,8192 ; Within a couple of pages?
1340: mr r2,r4 ; Move register
1341: bge- nosaveher2 ; No, no back chain then...
1342: lwz r11,8(r2) ; Get our callers return
1343: lwz r4,0(r2) ; Back chain
1344:
1345: xor r2,r4,r2 ; Form difference
1346: cmplwi r2,8192 ; Within a couple of pages?
1347: mr r2,r4 ; Move register
1348: bge- nosaveher2 ; No, no back chain then...
1349: lwz r10,8(r2) ; Get our callers return
1350: lwz r4,0(r2) ; Back chain
1351:
1352: xor r2,r4,r2 ; Form difference
1353: cmplwi r2,8192 ; Within a couple of pages?
1354: mr r2,r4 ; Move register
1355: bge- nosaveher2 ; No, no back chain then...
1356: lwz r8,8(r2) ; Get our callers return
1357:
1358: nosaveher2:
1359: addi r5,r5,-1 ; Get index to slot
1360: mfspr r6,pir ; Get our processor
1361: mflr r4 ; Get our return
1362: rlwinm r6,r6,8,0,23 ; Index to processor slot
1363: lis r2,hi16(EXT(DBGpreempt)) ; Stack high order
1364: rlwinm r5,r5,4,0,27 ; Index to stack slot
1365: ori r2,r2,lo16(EXT(DBGpreempt)) ; Stack low order
1366: add r2,r2,r5 ; Point to slot
1367: add r2,r2,r6 ; Move to processor
1368: stw r4,0(r2) ; Save our return
1369: stw r11,4(r2) ; Save callers caller
1370: stw r10,8(r2) ; Save callers callers caller
1371: stw r8,12(r2) ; Save callers callers callers caller
1372: nopredeb:
1373: #endif
1374: mtmsr r9 /* Allow interruptions now */
1375:
1376: blr /* Return... */
1377:
1378: /*
1379: * Return the active thread for both inside and outside osfmk consumption
1380: */
1381:
1382: .align 5
1383: .globl EXT(current_thread)
1384:
1385: LEXT(current_thread)
1386:
1387: mfmsr r9 /* Save the old MSR */
1388: rlwinm r8,r9,0,MSR_EE_BIT+1,MSR_EE_BIT-1 /* Clear interruptions */
1389: mtmsr r8 /* Interrupts off */
1390: mfsprg r6,0 /* Get the per_proc */
1391: lwz r6,PP_CPU_DATA(r6) /* Get the pointer to the CPU data from per proc */
1392: lwz r3,CPU_ACTIVE_THREAD(r6) /* Get the active thread */
1393: mtmsr r9 /* Restore interruptions to entry */
1394: blr /* Return... */
1395:
1396:
1397: /*
1398: * Return the current preemption level
1399: */
1400:
1401: .align 5
1402: .globl EXT(get_preemption_level)
1403:
1404: LEXT(get_preemption_level)
1405:
1406: mfmsr r9 /* Save the old MSR */
1407: rlwinm r8,r9,0,MSR_EE_BIT+1,MSR_EE_BIT-1 /* Clear interruptions */
1408: mtmsr r8 /* Interrupts off */
1409: mfsprg r6,0 /* Get the per_proc */
1410: lwz r6,PP_CPU_DATA(r6) /* Get the pointer to the CPU data from per proc */
1411: lwz r3,CPU_PREEMPTION_LEVEL(r6) /* Get the preemption level */
1412: mtmsr r9 /* Restore interruptions to entry */
1413: blr /* Return... */
1414:
1415:
1416: /*
1417: * Return the simple lock count
1418: */
1419:
1420: .align 5
1421: .globl EXT(get_simple_lock_count)
1422:
1423: LEXT(get_simple_lock_count)
1424:
1425: mfmsr r9 /* Save the old MSR */
1426: rlwinm r8,r9,0,MSR_EE_BIT+1,MSR_EE_BIT-1 /* Clear interruptions */
1427: mtmsr r8 /* Interrupts off */
1428: mfsprg r6,0 /* Get the per_proc */
1429: lwz r6,PP_CPU_DATA(r6) /* Get the pointer to the CPU data from per proc */
1430: lwz r3,CPU_SIMPLE_LOCK_COUNT(r6) /* Get the simple lock count */
1431: mtmsr r9 /* Restore interruptions to entry */
1432: blr /* Return... */
1433:
1434: #endif /* MACH_RT */
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.