|
|
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: * @OSF_COPYRIGHT@
24: */
25:
26: /* Low level routines dealing with exception entry and exit.
27: * There are various types of exception:
28: *
29: * Interrupt, trap, system call and debugger entry. Each has it's own
30: * handler since the state save routine is different for each. The
31: * code is very similar (a lot of cut and paste).
32: *
33: * The code for the FPU disabled handler (lazy fpu) is in cswtch.s
34: */
35:
36: #include <debug.h>
37: #include <mach_assert.h>
38: #include <mach/exception_types.h>
39: #include <mach/ppc/vm_param.h>
40:
41: #include <assym.s>
42:
43: #include <ppc/asm.h>
44: #include <ppc/proc_reg.h>
45: #include <ppc/trap.h>
46: #include <ppc/exception.h>
47: #include <ppc/spl.h>
48:
49:
50: #define VERIFYSAVE 0
51: #define FPVECDBG 0
52:
53: /*
54: * thandler(type)
55: *
56: * ENTRY: VM switched ON
57: * Interrupts OFF
58: * R3 contains exception code
59: * R4 points to the saved context (virtual address)
60: * Everything is saved in savearea
61: */
62:
63: /*
64: * If pcb.ksp == 0 then the kernel stack is already busy,
65: * we save ppc_saved state below the current stack pointer,
66: * leaving enough space for the `red zone' in case the
67: * trapped thread was in the middle of saving state below
68: * its stack pointer.
69: *
70: * otherwise we save a ppc_saved_state in the pcb, and switch to
71: * the kernel stack (setting pcb.ksp to 0)
72: *
73: * on return, we do the reverse, the last state is popped from the pcb
74: * and pcb.ksp is set to the top of stack
75: */
76:
77:
78: #if DEBUG
79:
80: /* TRAP_SPACE_NEEDED is the space assumed free on the kernel stack when
81: * another trap is taken. We need at least enough space for a saved state
82: * structure plus two small backpointer frames, and we add a few
83: * hundred bytes for the space needed by the C (which may be less but
84: * may be much more). We're trying to catch kernel stack overflows :-)
85: */
86:
87: #define TRAP_SPACE_NEEDED FM_REDZONE+(2*FM_SIZE)+256
88:
89: #endif /* DEBUG */
90:
91: .text
92:
93: ENTRY(thandler, TAG_NO_FRAME_USED) /* What tag should this have?! */
94:
95: mfsprg r25,0 /* Get the per_proc */
96:
97: lwz r1,PP_ISTACKPTR(r25) ; Get interrupt stack pointer
98:
99:
100: lwz r6,PP_CPU_DATA(r25) /* Get point to cpu specific data */
101: cmpwi cr0,r1,0 ; Are we on interrupt stack?
102: lwz r6,CPU_ACTIVE_THREAD(r6) /* Get the pointer to the currently active thread */
103: beq- cr0,EXT(ihandler) ; Yes, not allowed except when debugger
104: ; is active. We will let the ihandler do this...
105: lwz r9,THREAD_TOP_ACT(r6) /* Point to the active activation */
106: lwz r26,ACT_MACT_BDA(r9) /* Pick up the pointer to the blue box data area */
107: lwz r8,ACT_MACT_PCB(r9) /* Get the last savearea used */
108: mr. r26,r26 /* Do we have Blue Box Assist active? */
109: lwz r1,ACT_MACT_KSP(r9) /* Get the stack */
110: bnel- checkassist /* See if we should assist this */
111: stw r4,ACT_MACT_PCB(r9) /* Point to our savearea */
112: stw r8,SAVprev(r4) /* Queue the new save area in the front */
113:
114: #if VERIFYSAVE
115: bl versave ; (TEST/DEBUG)
116: #endif
117:
118: cmpwi cr1,r1, 0 /* zero implies already on kstack */
119: stw r9,SAVact(r4) /* Point the savearea at its activation */
120: bne cr1,.L_kstackfree /* This test is also used below */
121: lwz r1,saver1(r4) /* Get the stack at 'rupt time */
122:
123:
124: /* On kernel stack, allocate stack frame and check for overflow */
125: #if DEBUG
126: /*
127: * Test if we will overflow the Kernel Stack. We
128: * check that there is at least TRAP_SPACE_NEEDED bytes
129: * free on the kernel stack
130: */
131:
132: lwz r7,THREAD_KERNEL_STACK(r6)
133: addi r7,r7,TRAP_SPACE_NEEDED
134: cmp cr0,r1,r7
135: bng- EXT(ihandler)
136: #endif /* DEBUG */
137:
138: subi r1,r1,FM_REDZONE /* Back up stack and leave room for a red zone */
139:
140: .L_kstackfree:
141: #if 0
142: lis r0,HIGH_ADDR(CutTrace) /* (TEST/DEBUG) */
143: oris r0,r0,LOW_ADDR(CutTrace) /* (TEST/DEBUG) */
144: sc /* (TEST/DEBUG) */
145: #endif
146: lwz r7,savesrr1(r4) /* Pick up the entry MSR */
147: mfmsr r8 /* Get the kernel's MSR state */
148: li r0,0 /* Make this 0 */
149: rlwimi r8,r7,0,MSR_EE_BIT,MSR_EE_BIT /* Copy in the interrupt mask from the save area */
150:
151: beq cr1,.L_state_on_kstack /* using above test for pcb/stack */
152:
153: stw r0,ACT_MACT_KSP(r9) /* Show that we have taken the stack */
154:
155: .L_state_on_kstack:
156: rlwinm. r6,r7,0,MSR_VEC_BIT,MSR_VEC_BIT ; Was vector on?
157: lwz r6,saver1(r4) /* Grab interrupt time stack */
158: beq+ tvecoff ; Vector off, do not save vrsave...
159: mfspr r7,vrsave ; Get the VRSAVE register
160: stw r7,liveVRS(r25) ; Set the live value
161:
162: tvecoff: subi r1,r1,FM_SIZE /* Push a header onto the current stack */
163: stw r6,FM_BACKPTR(r1) /* Link backwards */
164:
165: #if DEBUG
166: /* If debugging, we need two frames, the first being a dummy
167: * which links back to the trapped routine. The second is
168: * that which the C routine below will need
169: */
170: lwz r7,savesrr0(r4) /* Get the point of interruption */
171: stw r7,FM_LR_SAVE(r1) /* save old instr ptr as LR value */
172: stwu r1, -FM_SIZE(r1) /* and make new frame */
173: #endif /* DEBUG */
174:
175:
176: /* call trap handler proper, with
177: * ARG0 = type (not yet, holds pcb ptr)
178: * ARG1 = saved_state ptr (already there)
179: * ARG2 = dsisr (already there)
180: * ARG3 = dar (already there)
181: */
182:
183: lwz r3,saveexception(r4) /* Get the exception code */
184: lwz r5,savedsisr(r4) /* Get the saved DSISR */
185: lwz r6,savedar(r4) /* Get the DAR */
186:
187: mtmsr r8 /* Turn on interrupts if enabled at 'rupt time */
188:
189: /* syscall exception might warp here if there's nothing left
190: * to do except generate a trap
191: */
192:
193: .L_call_trap:
194: #if 0
195: lis r0,HIGH_ADDR(CutTrace) /* (TEST/DEBUG) */
196: oris r0,r0,LOW_ADDR(CutTrace) /* (TEST/DEBUG) */
197: sc /* (TEST/DEBUG) */
198: #endif
199:
200: bl EXT(trap)
201:
202: /*
203: * Ok, return from C function
204: *
205: * This is also the point where new threads come when they are created.
206: * The new thread is setup to look like a thread that took an
207: * interrupt and went immediatly into trap.
208: *
209: */
210:
211: thread_return:
212:
213: lwz r4,SAVprev(r3) /* Pick up the previous savearea */
214: mfmsr r7 /* Get the MSR */
215: lwz r11,SAVflags(r3) /* Get the flags of the current savearea */
216: rlwinm r7,r7,0,MSR_EE_BIT+1,MSR_EE_BIT-1 /* Clear the interrupt enable mask */
217: mtmsr r7 /* Disable for interrupts */
218:
219: mfsprg r10,0 /* Restore the per_proc info */
220:
221: lwz r8,savesrr1(r3) ; Get the MSR we are going to
222: lwz r1,PP_CPU_DATA(r10) /* Get the CPU data area */
223: rlwinm r11,r11,0,15,13 /* Clear the syscall flag */
224: lwz r1,CPU_ACTIVE_THREAD(r1) /* and the active thread */
225: rlwinm. r8,r8,0,MSR_PR_BIT,MSR_PR_BIT ; Are we going to the user?
226: lwz r8,THREAD_TOP_ACT(r1) /* Now find the current activation */
227: stw r11,SAVflags(r3) /* Save back the flags (with reset stack cleared) */
228:
229: #if 0
230: lis r0,HIGH_ADDR(CutTrace) /* (TEST/DEBUG) */
231: oris r0,r0,LOW_ADDR(CutTrace) /* (TEST/DEBUG) */
232: sc /* (TEST/DEBUG) */
233: #endif
234: stw r4,ACT_MACT_PCB(r8) /* Point to the previous savearea (or 0 if none) */
235:
236: beq- chkfac ; We are not leaving the kernel yet...
237:
238: lwz r5,THREAD_KERNEL_STACK(r1) /* Get the base pointer to the stack */
239: addi r5,r5,KERNEL_STACK_SIZE-FM_SIZE /* Reset to empty */
240: stw r5,ACT_MACT_KSP(r8) /* Save the empty stack pointer */
241: b chkfac /* Go end it all... */
242:
243:
244:
245: /*
246: * shandler(type)
247: *
248: * ENTRY: VM switched ON
249: * Interrupts OFF
250: * R3 contains exception code
251: * R4 points to the saved context (virtual address)
252: * Everything is saved in savearea
253: */
254:
255: /*
256: * If pcb.ksp == 0 then the kernel stack is already busy,
257: * this is an error - jump to the debugger entry
258: *
259: * otherwise depending upon the type of
260: * syscall, look it up in the kernel table
261: * or pass it to the server.
262: *
263: * on return, we do the reverse, the state is popped from the pcb
264: * and pcb.ksp is set to the top of stack.
265: */
266:
267: ENTRY(shandler, TAG_NO_FRAME_USED)
268:
269: mfsprg r25,0 /* Get the per proc area */
270: lwz r0,saver0(r4) /* Get the original syscall number */
271: lwz r17,PP_ISTACKPTR(r25) ; Get interrupt stack pointer
272: andi. r15,r0,0x7000 /* Isolate the fastpath code */
273: lwz r16,PP_CPU_DATA(r25) /* Assume we need this */
274: mr. r17,r17 ; Are we on interrupt stack?
275: lwz r7,savesrr1(r4) ; Get the SRR1 value
276: beq- EXT(ihandler) ; On interrupt stack, not allowed...
277: lwz r16,CPU_ACTIVE_THREAD(r16) /* Get the thread pointer */
278:
279:
280: rlwinm. r6,r7,0,MSR_VEC_BIT,MSR_VEC_BIT ; Was vector on?
281: beq+ svecoff ; Vector off, do not save vrsave...
282: mfspr r7,vrsave ; Get the VRSAVE register
283: stw r7,liveVRS(r25) ; Set the live value
284:
285: svecoff: lwz r13,THREAD_TOP_ACT(r16) /* Pick up the active thread */
286: cmplwi r15,0x7000 /* Do we have a fast path trap? */
287: lwz r14,ACT_MACT_PCB(r13) /* Now point to the PCB */
288: beql+ fastpath /* We think it's a fastpath... */
289:
290: lwz r1,ACT_MACT_KSP(r13) /* Get the kernel stack pointer */
291: #if DEBUG
292: mr. r1,r1 /* Are we already on the kernel stack? */
293: li r3,T_SYSTEM_CALL /* Yup, pretend we had an interrupt... */
294: beq- EXT(ihandler) /* Bad boy, bad boy... What'cha gonna do when they come for you? */
295: #endif /* DEBUG */
296:
297: stw r4,ACT_MACT_PCB(r13) /* Point to our savearea */
298: li r0,0 /* Clear this out */
299: stw r14,SAVprev(r4) /* Queue the new save area in the front */
300: stw r13,SAVact(r4) /* Point the savearea at its activation */
301:
302: #if VERIFYSAVE
303: bl versave ; (TEST/DEBUG)
304: #endif
305:
306: mr r30,r4 /* Save pointer to the new context savearea */
307: lwz r15,saver1(r4) /* Grab interrupt time stack */
308: stw r0,ACT_MACT_KSP(r13) /* Mark stack as busy with 0 val */
309: stw r15,FM_BACKPTR(r1) /* Link backwards */
310:
311: #if DEBUG
312: /* If debugging, we need two frames, the first being a dummy
313: * which links back to the trapped routine. The second is
314: * that which the C routine below will need
315: */
316: lwz r8,savesrr0(r30) /* Get the point of interruption */
317: stw r8,FM_LR_SAVE(r1) /* save old instr ptr as LR value */
318: stwu r1, -FM_SIZE(r1) /* and make new frame */
319: #endif /* DEBUG */
320:
321: mfmsr r0 /* Get the MSR */
322: lwz r15,SAVflags(r4) /* Get the savearea flags */
323: ori r0,r0,lo16(MASK(MSR_EE)) /* Turn on interruption enabled bit */
324: oris r15,r15,SAVsyscall >> 16 /* Mark that it this is a syscall */
325: stwu r1,-(FM_SIZE+ARG_SIZE)(r1) /* Make a stack frame */
326: stw r15,SAVflags(r30) /* Save syscall marker */
327:
328: mtmsr r0 /* Enable interruptions */
329:
330:
331: /* Call a function that can print out our syscall info */
332: /* Note that we don't care about any volatiles yet */
333: mr r4,r30
334: bl EXT(syscall_trace)
335:
336: lwz r0,saver0(r30) /* Get the system call selector */
337: mr. r0,r0 /* What kind is it? */
338: blt- .L_kernel_syscall /* -ve syscall - go to kernel */
339: /* +ve syscall - go to server */
340: cmpwi cr0, r0,0x7FFA
341: beq- .L_notify_interrupt_syscall
342: /* +ve syscall - go to server */
343: #ifdef MACH_BSD
344: mr r3,r30 /* Get PCB/savearea */
345: lwz r4,saver4(r30) /* Restore r4 */
346: lwz r5,saver5(r30) /* Restore r5 */
347: lwz r6,saver6(r30) /* Restore r6 */
348: lwz r7,saver7(r30) /* Restore r7 */
349: lwz r8,saver8(r30) /* Restore r8 */
350: lwz r9,saver9(r30) /* Restore r9 */
351: lwz r10,saver10(r30) /* Restore r10 */
352: bl EXT(unix_syscall) /* Check out unix... */
353: #endif
354:
355: .L_call_server_syscall_exception:
356: li r3,EXC_SYSCALL /* doexception(EXC_SYSCALL, num, 1) */
357:
358: .L_call_server_exception:
359: mr r4,r0 /* Set syscall selector */
360: li r5,1
361: b EXT(doexception) /* Go away, never to return... */
362:
363: /* The above, but with EXC_MACH_SYSCALL */
364: .L_call_server_mach_syscall:
365: li r3,EXC_MACH_SYSCALL
366: b .L_call_server_exception /* Join the common above... */
367:
368: .L_notify_interrupt_syscall:
369: lwz r3,saver3(r30) ; Get the new PC address to pass in
370: bl EXT(syscall_notify_interrupt)
371: b .L_syscall_return
372:
373:
374:
375: /* Once here, we know that the syscall was -ve
376: * we should still have r1=ksp,
377: * r16 = pointer to current thread,
378: * r13 = pointer to top activation,
379: * r0 = syscall number
380: * r30 = pointer to saved state (in pcb)
381: */
382: .L_kernel_syscall:
383:
384: /*
385: * Are we allowed to do mach system calls?
386: */
387:
388: addis r31,0,HIGH_ADDR(EXT(realhost))
389: lwz r29,ACT_MACH_EXC_PORT(r13) /* See if we have one of these ports */
390: ori r31,r31,LOW_ADDR(EXT(realhost))
391: lwz r31,HOST_SELF(r31) /* Find ourselves */
392:
393: /* If thread_exception_port == realhost->hostname do syscall */
394: cmpw cr1,r29,r31 /* Are we the host? */
395: mr. r29,r29 /* Is our port null? */
396: beq+ cr1,.L_syscall_do_mach_syscall /* We are the host... */
397: bne+ .L_call_server_mach_syscall /* Not host and not null, call the handler... */
398:
399: lwz r29,ACT_TASK(r13) /* Get our task */
400: lwz r29,TASK_MACH_EXC_PORT(r29) /* Now get the exception port for it */
401:
402: /* If task_exception_port == realhost->hostname do syscall */
403: cmpw cr1,r29,r31 /* Is this the host? */
404: mr. r29,r29 /* Is it null? */
405: beq+ cr1,.L_syscall_do_mach_syscall /* We are the host... */
406: bne+ .L_call_server_mach_syscall /* Not host and not null, call the handler... */
407:
408: /* else the syscall has failed, treat as priv instruction trap,
409: * set SRR1 to indicate privileged instruction
410: */
411:
412: li r3,T_PROGRAM
413: lwz r29,savesrr1(r30)
414: mr r4,r30
415: li r5,0
416: oris r29,r29,MASK(SRR1_PRG_PRV_INS)>>16
417: li r6,0
418: stw r29,savesrr1(r30)
419: b .L_call_trap
420:
421: /* When here, we know that we're allowed to do a mach syscall,
422: * and still have syscall number in r0, pcb pointer in r30
423: */
424:
425: .L_syscall_do_mach_syscall:
426: neg r31, r0 /* Make number +ve and put in r31*/
427:
428: #ifdef MACHO_SYSCALL_BEGIN
429: /*
430: * There's a bit of a problem with supporting both ELF and
431: * MACHO generated binaries. Each has their own location for
432: * storing the 8th and above arguments on the stack.
433: *
434: * Current the MACHO generated system calls have a BIT
435: * set telling the kernel its a MACHO style ABI.
436: */
437:
438: li r29,MACHO_SYSCALL_BEGIN
439: and. r25,r31,r29
440: beq not_macho
441:
442: andc r31,r31,r29 /* Clear the bit to get real trap */
443: li r25,FM_MACHO_ARG0-4
444: b continue2
445:
446: not_macho:
447: li r25,FM_ELF_ARG0-4
448:
449: continue2:
450: #endif
451:
452: /* If out of range, call server with syscall exception */
453: addis r29, 0, HIGH_CADDR(EXT(mach_trap_count))
454: addi r29, r29, LOW_ADDR(EXT(mach_trap_count))
455: lwz r29, 0(r29)
456:
457: cmp cr0, r31, r29
458: bge- cr0, .L_call_server_syscall_exception
459:
460: addis r29, 0, HIGH_CADDR(EXT(mach_trap_table))
461: addi r29, r29, LOW_ADDR(EXT(mach_trap_table))
462:
463: /* multiply the trap number to get offset into table */
464: slwi r31, r31, MACH_TRAP_OFFSET_POW2
465:
466: /* r31 now holds offset into table of our trap entry,
467: * add on the table base, and it then holds pointer to entry
468: */
469: add r31, r31, r29
470:
471: /* If the function is kern_invalid, prepare to send an exception.
472: This is messy, but parallels the x86. We need it for task_by_pid,
473: at least. */
474: lis r29, HIGH_CADDR(EXT(kern_invalid))
475: addi r29, r29, LOW_ADDR(EXT(kern_invalid))
476: lwz r0, MACH_TRAP_FUNCTION(r31)
477: cmp cr0, r0, r29
478: beq- .L_call_server_syscall_exception
479:
480: /* get arg count. If argc > 8 then not all args were in regs,
481: * so we must perform copyin.
482: */
483: lwz r29, MACH_TRAP_ARGC(r31)
484: cmpwi cr0, r29, 8
485: ble+ .L_syscall_got_args
486:
487: /* argc > 8 - perform a copyin */
488: /* if the syscall came from kernel space, we can just copy */
489:
490: lwz r0,savesrr1(r30) /* Pick up exception time MSR */
491: andi. r0,r0,MASK(MSR_PR) /* Check the priv bit */
492: bne+ .L_syscall_arg_copyin /* We're not priviliged... */
493:
494: /* we came from a privilaged task, just do a copy */
495: /* get user's stack pointer */
496:
497: lwz r28,saver1(r30) /* Get the stack pointer */
498:
499: subi r29,r29,8 /* Get the number of arguments to copy */
500:
501: #ifdef MACHO_SYSCALL_BEGIN
502: add r28,r28,r25 /* Point to source - 4 */
503: #else
504: addi r28,r28,COPYIN_ARG0_OFFSET-4 /* Point to source - 4 */
505: #endif
506: addi r27,r1,FM_ARG0-4 /* Point to sink - 4 */
507:
508: .L_syscall_copy_word_loop:
509: addic. r29,r29,-1 /* Count down the number of arguments left */
510: lwz r0,4(r28) /* Pick up the argument from the stack */
511: addi r28,r28,4 /* Point to the next source */
512: stw r0,4(r27) /* Store the argument */
513: addi r27,r27,4 /* Point to the next sink */
514: bne+ .L_syscall_copy_word_loop /* Move all arguments... */
515: b .L_syscall_got_args /* Go call it now... */
516:
517:
518: /* we came from a user task, pay the price of a real copyin */
519: /* set recovery point */
520:
521: .L_syscall_arg_copyin:
522: addis r28,0,HIGH_CADDR(.L_syscall_copyin_recover)
523: addi r28,r28,LOW_ADDR(.L_syscall_copyin_recover)
524: stw r28,THREAD_RECOVER(r16) /* R16 still holds thread ptr */
525:
526: /* We can manipulate the COPYIN segment register quite easily
527: * here, but we've also got to make sure we don't go over a
528: * segment boundary - hence some mess.
529: * Registers from 12-29 are free for our use.
530: */
531:
532:
533: lwz r28,saver1(r30) /* Get the stack pointer */
534: subi r29,r29,8 /* Get the number of arguments to copy */
535: mfsr r10,SR_UNUSED_BY_KERN ; Get the user state SR value
536:
537: #ifdef MACHO_SYSCALL_BEGIN
538: add r28,r28,r25 /* Set source in user land */
539: addi r28,r28,4
540: #else
541: addi r28,r28,COPYIN_ARG0_OFFSET /* Set source in user land */
542: #endif
543:
544: /* set up SR_COPYIN to allow us to copy, we may need to loop
545: * around if we change segments. We know that this previously
546: * pointed to user space, so the sid doesn't need setting.
547: */
548: .L_syscall_copyin_seg_loop:
549:
550: rlwimi r10,r28,24,8,11 ; Blast the segment number into the SR
551: rlwinm r26,r28,0,4,31 ; Clear the segment number from source address
552: mtsr SR_COPYIN,r10 ; Set the copyin SR
553: isync
554:
555: oris r26,r26,(SR_COPYIN_NUM << (28-16)) ; Insert the copyin segment number into source address
556:
557: /* Make r27 point to address-4 of where we will store copied args */
558: addi r27,r1,FM_ARG0-4
559:
560: .L_syscall_copyin_word_loop:
561:
562: lwz r0,0(r26) /* MAY CAUSE PAGE FAULT! */
563: subi r29,r29,1 ; Decrement count
564: addi r26,r26,4 ; Bump input
565: stw r0,4(r27) ; Save the copied in word
566: mr. r29,r29 ; Are they all moved?
567: addi r27,r27,4 ; Bump output
568: beq+ .L_syscall_copyin_done ; Escape if we are done...
569:
570: rlwinm. r0,r26,0,4,29 ; Did we just step into a new segment?
571: addi r28,r28,4 ; Bump up user state address also
572: bne+ .L_syscall_copyin_word_loop ; We are still on the same segment...
573: b .L_syscall_copyin_seg_loop /* On new segment! remap */
574:
575: /* Don't bother restoring SR_COPYIN, we can leave it trashed */
576: /* clear thread recovery as we're done touching user data */
577:
578: .L_syscall_copyin_done:
579: li r0,0
580: stw r0,THREAD_RECOVER(r16) /* R16 still holds thread ptr */
581:
582: .L_syscall_got_args:
583: lwz r8,ACT_TASK(r13) /* Get our task */
584: lis r10,hi16(EXT(c_syscalls_mach)) /* Get top half of counter address */
585: lwz r7,TASK_SYSCALLS_MACH(r8) ; Get the current count
586: lwz r3,saver3(r30) /* Restore r3 */
587: addi r7,r7,1 ; Bump it
588: ori r10,r10,lo16(EXT(c_syscalls_mach)) /* Get low half of counter address */
589: stw r7,TASK_SYSCALLS_MACH(r8) ; Save it
590: lwz r4,saver4(r30) /* Restore r4 */
591: lwz r9,0(r10) /* Get counter */
592: lwz r5,saver5(r30) /* Restore r5 */
593: lwz r6,saver6(r30) /* Restore r6 */
594: addi r9,r9,1 /* Add 1 */
595: lwz r7,saver7(r30) /* Restore r7 */
596: lwz r8,saver8(r30) /* Restore r8 */
597: stw r9,0(r10) /* Save it back */
598: lwz r9,saver9(r30) /* Restore r9 */
599: lwz r10,saver10(r30) /* Restore r10 */
600:
601: lwz r0,MACH_TRAP_FUNCTION(r31)
602:
603: /* calling this function, all the callee-saved registers are
604: * still valid except for r30 and r31 which are in the PCB
605: * r30 holds pointer to saved state (ie. pcb)
606: * r31 is scrap
607: */
608: mtctr r0
609: bctrl /* perform the actual syscall */
610:
611: /* 'standard' syscall returns here - INTERRUPTS ARE STILL ON */
612:
613: /* r3 contains value that we're going to return to the user
614: */
615:
616: /*
617: * Ok, return from C function, ARG0 = return value
618: *
619: * get the active thread's PCB pointer and thus pointer to user state
620: * saved state is still in R30 and the active thread is in R16 .
621: */
622:
623: /* Store return value into saved state structure, since
624: * we need to pick up the value from here later - the
625: * syscall may perform a thread_set_syscall_return
626: * followed by a thread_exception_return, ending up
627: * at thread_syscall_return below, with SS_R3 having
628: * been set up already
629: */
630:
631: /* When we are here, r16 should point to the current thread,
632: * r30 should point to the current pcb
633: */
634:
635: /* save off return value, we must load it
636: * back anyway for thread_exception_return
637: * TODO NMGS put in register?
638: */
639: .L_syscall_return:
640: mr r31,r16 /* Move the current thread pointer */
641: stw r3,saver3(r30) /* Stash the return code */
642:
643: /* Call a function that records the end of */
644: /* the mach system call */
645: mr r4,r30
646: bl EXT(syscall_trace_end)
647:
648: #if 0
649: lis r0,HIGH_ADDR(CutTrace) /* (TEST/DEBUG) */
650: mr r4,r31 /* (TEST/DEBUG) */
651: oris r0,r0,LOW_ADDR(CutTrace) /* (TEST/DEBUG) */
652: mr r5,r30 /* (TEST/DEBUG) */
653: sc /* (TEST/DEBUG) */
654: #endif
655:
656: .L_thread_syscall_ret_check_ast:
657: mfmsr r12 /* Get the current MSR */
658: rlwinm r12,r12,0,MSR_EE_BIT+1,MSR_EE_BIT-1 /* Turn of interruptions enable bit */
659: mtmsr r12 /* Turn interruptions off */
660:
661: mfsprg r10,0 /* Get the per_processor block */
662:
663: /* Check to see if there's an outstanding AST */
664:
665: lwz r4,PP_NEED_AST(r10)
666: lwz r4,0(r4)
667: cmpi cr0,r4, 0
668: beq cr0,.L_syscall_no_ast
669:
670: /* Yes there is, call ast_taken
671: * pretending that the user thread took an AST exception here,
672: * ast_taken will save all state and bring us back here
673: */
674:
675: #if DEBUG
676: /* debug assert - make sure that we're not returning to kernel */
677: lwz r3,savesrr1(r30)
678: andi. r3,r3,MASK(MSR_PR)
679: bne+ 0f /* returning to user level, check */
680:
681: BREAKPOINT_TRAP
682: 0:
683: #endif /* DEBUG */
684:
685: li r3, 0
686: li r4, AST_ALL
687: li r5, 1
688: bl EXT(ast_taken)
689:
690: b .L_thread_syscall_ret_check_ast
691:
692: /* thread_exception_return returns to here, almost all
693: * registers intact. It expects a full context restore
694: * of what it hasn't restored itself (ie. what we use).
695: *
696: * In particular for us,
697: * we still have r31 points to the current thread,
698: * r30 points to the current pcb
699: */
700:
701: .L_syscall_no_ast:
702: .L_thread_syscall_return:
703:
704: mr r3,r30 ; Get savearea to the correct register for common exit
705: lwz r8,THREAD_TOP_ACT(r31) /* Now find the current activation */
706:
707: lwz r11,SAVflags(r30) /* Get the flags */
708: lwz r5,THREAD_KERNEL_STACK(r31) /* Get the base pointer to the stack */
709: rlwinm r11,r11,0,15,13 /* Clear the syscall flag */
710: lwz r4,SAVprev(r30) ; Get the previous save area
711: stw r11,SAVflags(r30) /* Stick back the flags */
712: addi r5,r5,KERNEL_STACK_SIZE-FM_SIZE /* Reset to empty */
713: stw r4,ACT_MACT_PCB(r8) ; Save previous save area
714: stw r5,ACT_MACT_KSP(r8) /* Save the empty stack pointer */
715:
716: b chkfac ; Go end it all...
717:
718:
719: .L_syscall_copyin_recover:
720:
721: /* This is the catcher for any data faults in the copyin
722: * of arguments from the user's stack.
723: * r30 still holds a pointer to the PCB
724: *
725: * call syscall_error(EXC_BAD_ACCESS, EXC_PPC_VM_PROT_READ, sp, ssp),
726: *
727: * we already had a frame so we can do this
728: */
729:
730: li r3,EXC_BAD_ACCESS
731: li r4,EXC_PPC_VM_PROT_READ
732: lwz r5,saver1(r30)
733: mr r6,r30
734:
735: bl EXT(syscall_error)
736: b .L_syscall_return
737:
738:
739: /*
740: * thread_exception_return()
741: *
742: * Return to user mode directly from within a system call.
743: */
744:
745: ENTRY(thread_exception_return, TAG_NO_FRAME_USED)
746:
747: .L_thread_exc_ret_check_ast:
748:
749: mfmsr r3 /* Get the MSR */
750: rlwinm r3,r3,0,MSR_EE_BIT+1,MSR_EE_BIT-1 /* Clear EE */
751: mtmsr r3 /* Disable interrupts */
752:
753: /* Check to see if there's an outstanding AST */
754: /* We don't bother establishing a call frame even though CHECK_AST
755: can invoke ast_taken(), because it can just borrow our caller's
756: frame, given that we're not going to return.
757: */
758:
759: mfsprg r10,0 /* Get the per_processor block */
760: lwz r4,PP_NEED_AST(r10)
761: lwz r4,0(r4)
762: cmpi cr0,r4, 0
763: beq cr0,.L_exc_ret_no_ast
764:
765: /* Yes there is, call ast_taken
766: * pretending that the user thread took an AST exception here,
767: * ast_taken will save all state and bring us back here
768: */
769:
770: #if DEBUG
771: /* debug assert - make sure that we're not returning to kernel
772: *
773: * get the active thread's PCB pointer and thus pointer to user state
774: */
775: lwz r30,PP_CPU_DATA(r10)
776: lwz r30,CPU_ACTIVE_THREAD(r30)
777: lwz r30,THREAD_TOP_ACT(r30)
778: lwz r30,ACT_MACT_PCB(r30)
779:
780: lwz r3,savesrr1(r30)
781: andi. r3,r3,MASK(MSR_PR)
782: bne+ ret_user2 /* returning to user level, check */
783:
784: BREAKPOINT_TRAP
785: ret_user2:
786: #endif /* DEBUG */
787:
788: li r3,0
789: li r4,AST_ALL
790: li r5,1
791:
792: bl EXT(ast_taken)
793: b .L_thread_exc_ret_check_ast /* check for a second AST (rare)*/
794:
795: /* arriving here, interrupts should be disabled */
796: /* Get the active thread's PCB pointer to restore regs
797: */
798: .L_exc_ret_no_ast:
799:
800: lwz r31,PP_CPU_DATA(r10)
801: lwz r31,CPU_ACTIVE_THREAD(r31)
802: lwz r30,THREAD_TOP_ACT(r31)
803: lwz r30,ACT_MACT_PCB(r30)
804:
805: /* If the MSR_SYSCALL_MASK isn't set, then we came from a trap,
806: * so warp into the return_from_trap (thread_return) routine,
807: * which takes PCB pointer in R3, not in r30!
808: */
809: lwz r0,SAVflags(r30)
810: mr r3,r30 /* Copy pcb pointer into r3 in case */
811: andis. r0,r0,SAVsyscall>>16 /* Are we returning from a syscall? */
812: beq- cr0,thread_return /* Nope, must be a thread return... */
813: b .L_thread_syscall_return
814:
815: /*
816: * thread_bootstrap_return()
817: *
818: */
819:
820: ENTRY(thread_bootstrap_return, TAG_NO_FRAME_USED)
821:
822: mfmsr r12 /* Get the current MSR */
823: rlwinm r12,r12,0,MSR_EE_BIT+1,MSR_EE_BIT-1 /* Turn of interruptions enable bit */
824: mtmsr r12 /* Turn interruptions off */
825:
826: mfsprg r10,0 /* Get the per_processor block */
827:
828:
829: #if 0
830: lis r0,HIGH_ADDR(CutTrace) /* (TEST/DEBUG) */
831: oris r0,r0,LOW_ADDR(CutTrace) /* (TEST/DEBUG) */
832: sc /* (TEST/DEBUG) */
833: #endif
834:
835: lwz r31,PP_CPU_DATA(r10)
836:
837: lwz r31,CPU_ACTIVE_THREAD(r31)
838: lwz r31,THREAD_TOP_ACT(r31)
839:
840: .L_bootstrap_ret_check_ast:
841: mfmsr r12 /* Get the current MSR */
842: rlwinm r12,r12,0,MSR_EE_BIT+1,MSR_EE_BIT-1 /* Turn off interruptions enable bit */
843: mtmsr r12 /* Turn interruptions off */
844: mfsprg r10,0 /* Get the per_processor block */
845: /* Check for any outstanding ASTs and deal with them */
846: lwz r4,PP_NEED_AST(r10)
847: lwz r4,0(r4)
848: cmpi cr0,r4, 0
849: beq cr0,.L_bootstrap_ret_no_ast
850:
851: /* we have a pending AST, now is the time to jump, args as below
852: * void ast_taken(boolean_t preemption, ast_t mask, boolean_t interrupts)
853: */
854: li r3, 0
855: li r4,AST_ALL
856: li r5,1
857:
858: bl EXT(ast_taken)
859: b .L_bootstrap_ret_check_ast /* Check for another AST (rare) */
860:
861:
862: /* Back from dealing with ASTs, if there were any.
863: * r31 still holds pointer to ACT.
864: *
865: * Time to deal with kloading or kloaded threads
866: */
867: .L_bootstrap_ret_no_ast:
868: lwz r3,ACT_KLOADING(r31)
869: li r0,0
870: cmpi cr0,r3, 0
871: li r9,1
872: beq+ .L_bootstrap_ret_no_kload
873: stw r0,ACT_KLOADING(r31)
874: lwz r3,PP_ACTIVE_KLOADED(r10)
875: stw r0,ACT_KLOADED(r31)
876: stw r31,0(r3)
877:
878: /* Ok, we're all set, jump to thread_return as if we
879: * were just coming back from a trap (ie. r3 set up to point to pcb)
880: */
881: .L_bootstrap_ret_no_kload:
882:
883: lwz r3,ACT_MACT_PCB(r31) /* Point to our saved context */
884: #if 0
885: lis r0,HIGH_ADDR(CutTrace) /* (TEST/DEBUG) */
886: oris r0,r0,LOW_ADDR(CutTrace) /* (TEST/DEBUG) */
887: sc /* (TEST/DEBUG) */
888: #endif
889:
890: b thread_return
891:
892: /*
893: * ihandler(type)
894: *
895: * ENTRY: VM switched ON
896: * Interrupts OFF
897: * R3 contains exception code
898: * R4 points to the saved context (virtual address)
899: * Everything is saved in savearea
900: *
901: */
902:
903: ENTRY(ihandler, TAG_NO_FRAME_USED) /* What tag should this have?! */
904:
905: /*
906: * get the value of istackptr, if it's zero then we're already on the
907: * interrupt stack, otherwise it points to a saved_state structure
908: * at the top of the interrupt stack.
909: */
910:
911: lwz r10,savesrr1(r4) /* Get SRR0 */
912: mfsprg r25,0 /* Get the per_proc block */
913: li r14,0 /* Zero this for now */
914: lwz r16,PP_CPU_DATA(r25) /* Assume we need this */
915: rlwinm. r10,r10,0,MSR_VEC_BIT,MSR_VEC_BIT ; Was vector on?
916: lwz r1, PP_ISTACKPTR(r25) /* Get the interrupt stack */
917: li r13,0 /* Zero this for now */
918: lwz r16,CPU_ACTIVE_THREAD(r16) /* Get the thread pointer */
919:
920: beq+ ivecoff ; Vector off, do not save vrsave...
921: mfspr r7,vrsave ; Get the VRSAVE register
922: stw r7,liveVRS(r25) ; Set the live value
923:
924: ivecoff: li r0,0 /* Get a constant 0 */
925: cmplwi cr1,r16,0 /* Are we still booting? */
926: mr. r1,r1 /* Is it active? */
927: beq- cr1,ihboot1 /* We're still coming up... */
928: lwz r13,THREAD_TOP_ACT(r16) /* Pick up the active thread */
929: lwz r14,ACT_MACT_PCB(r13) /* Now point to the PCB */
930:
931: ihboot1: lwz r9,saver1(r4) /* Pick up the 'rupt time stack */
932: stw r14,SAVprev(r4) /* Queue the new save area in the front */
933: stw r13,SAVact(r4) /* Point the savearea at its activation */
934: beq- cr1,ihboot4 /* We're still coming up... */
935: stw r4,ACT_MACT_PCB(r13) /* Point to our savearea */
936:
937: ihboot4: bne .L_istackfree /* Nope... */
938:
939: /* We're already on the interrupt stack, get back the old
940: * stack pointer and make room for a frame
941: */
942:
943: subi r1,r9,FM_REDZONE /* Back up beyond the red zone */
944: b ihsetback /* Go set up the back chain... */
945:
946: .L_istackfree:
947: lwz r10,SAVflags(r4)
948: stw r0,PP_ISTACKPTR(r25) /* Mark the stack in use */
949: oris r10,r10,HIGH_ADDR(SAVrststk) /* Indicate we reset stack when we return from this one */
950: stw r10,SAVflags(r4) /* Stick it back */
951:
952: /*
953: * To summarise, when we reach here, the state has been saved and
954: * the stack is marked as busy. We now generate a small
955: * stack frame with backpointers to follow the calling
956: * conventions. We set up the backpointers to the trapped
957: * routine allowing us to backtrace.
958: */
959:
960: ihsetback: subi r1,r1,FM_SIZE /* Make a new frame */
961: stw r9,FM_BACKPTR(r1) /* point back to previous stackptr */
962:
963: #if VERIFYSAVE
964: bl versave ; (TEST/DEBUG)
965: #endif
966:
967: #if DEBUG
968: /* If debugging, we need two frames, the first being a dummy
969: * which links back to the trapped routine. The second is
970: * that which the C routine below will need
971: */
972: lwz r5,savesrr0(r4) /* Get interrupt address */
973: stw r5,FM_LR_SAVE(r1) /* save old instr ptr as LR value */
974: stwu r1,-FM_SIZE(r1) /* Make another new frame for C routine */
975: #endif /* DEBUG */
976:
977: lwz r5,savedsisr(r4) /* Get the DSISR */
978: lwz r6,savedar(r4) /* Get the DAR */
979:
980: bl EXT(interrupt)
981:
982:
983: /* interrupt() returns a pointer to the saved state in r3
984: *
985: * Ok, back from C. Disable interrupts while we restore things
986: */
987: .globl EXT(ihandler_ret)
988:
989: LEXT(ihandler_ret) /* Marks our return point from debugger entry */
990:
991: mfmsr r0 /* Get our MSR */
992: rlwinm r0,r0,0,MSR_EE_BIT+1,MSR_EE_BIT-1 /* Flip off the interrupt enabled bit */
993: mtmsr r0 /* Make sure interrupts are disabled */
994: mfsprg r10,0 /* Get the per_proc block */
995:
996: lwz r8,PP_CPU_DATA(r10) /* Get the CPU data area */
997: lwz r7,SAVflags(r3) /* Pick up the flags */
998: lwz r8,CPU_ACTIVE_THREAD(r8) /* and the active thread */
999: lwz r9,SAVprev(r3) /* Get previous save area */
1000: cmplwi cr1,r8,0 /* Are we still initializing? */
1001: lwz r12,savesrr1(r3) /* Get the MSR we will load on return */
1002: beq- cr1,ihboot2 /* Skip if we are still in init... */
1003: lwz r8,THREAD_TOP_ACT(r8) /* Pick up the active thread */
1004:
1005: ihboot2: andis. r11,r7,HIGH_ADDR(SAVrststk) /* Is this the first on the stack? */
1006: beq- cr1,ihboot3 /* Skip if we are still in init... */
1007: stw r9,ACT_MACT_PCB(r8) /* Point to previous context savearea */
1008:
1009: ihboot3: mr r4,r3 /* Move the savearea pointer */
1010: beq .L_no_int_ast2 /* Get going if not the top o' stack... */
1011:
1012:
1013: /* We're the last frame on the stack. Restore istackptr to empty state.
1014: *
1015: * Check for ASTs if one of the below is true:
1016: * returning to user mode
1017: * returning to a kloaded server
1018: */
1019: lwz r9,PP_INTSTACK_TOP_SS(r10) /* Get the empty stack value */
1020: andc r7,r7,r11 /* Remove the stack reset bit in case we pass this one */
1021: stw r9,PP_ISTACKPTR(r25) /* Save that saved state ptr */
1022: andi. r6,r12,MASK(MSR_PR) /* Are we going to problem state? (Sorry, ancient IBM term for non-privileged) */
1023: stw r7,SAVflags(r4) /* Save the flags */
1024: beq- .L_no_int_ast ; In kernel space, no AST check...
1025:
1026: lwz r11,PP_NEED_AST(r10) /* Get the AST request address */
1027: lwz r11,0(r11) /* Get the request */
1028: li r3,T_AST /* Assume the worst */
1029: mr. r11,r11 /* Are there any pending? */
1030: beq .L_no_int_ast /* Nope... */
1031:
1032: /*
1033: * There is a pending AST. Massage things to make it look like
1034: * we took a trap and jump into the trap handler. To do this
1035: * we essentially pretend to return from the interrupt but
1036: * at the last minute jump into the trap handler with an AST
1037: * trap instead of performing an rfi.
1038: */
1039:
1040: stw r3,saveexception(r4) /* Set the exception code to T_AST */
1041: b EXT(thandler) /* hyperspace into AST trap */
1042:
1043: .L_no_int_ast:
1044: mr r3,r4 ; Get into the right register for common code
1045: .L_no_int_ast2:
1046: rlwinm r7,r7,0,15,13 /* Clear the syscall bit */
1047: li r4,0 ; Assume for a moment that we are in init
1048: stw r7,SAVflags(r3) /* Set the flags */
1049: beq- cr1,chkfac ; Jump away if we are in init...
1050: lwz r4,ACT_MACT_PCB(r8) ; Get the new level marker
1051:
1052:
1053: ;
1054: ; This section is common to all exception exits. It throws away vector
1055: ; and floating point saveareas as the exception level of a thread is
1056: ; exited.
1057: ;
1058: ; It also enables the facility if its context is live
1059: ; Requires:
1060: ; R3 = Savearea to be released (virtual)
1061: ; R4 = New top of savearea stack (could be 0)
1062: ; R8 = pointer to activation
1063: ; R10 = per_proc block
1064: ;
1065: chkfac: mr. r8,r8 ; Are we still in boot?
1066: beq- chkenax ; Yeah, skip it all...
1067:
1068: lwz r20,ACT_MACT_FPUlvl(r8) ; Get the FPU level
1069: lwz r12,savesrr1(r3) ; Get the current MSR
1070: cmplw r20,r3 ; Are we returning from the active level?
1071: lwz r23,PP_FPU_THREAD(r10) ; Get floating point owner
1072: rlwinm r12,r12,0,MSR_FP_BIT+1,MSR_FP_BIT-1 ; Turn off floating point for now
1073: cmplw cr1,r23,r8 ; Are we the facility owner?
1074: lhz r26,PP_CPU_NUMBER(r10) ; Get the current CPU number
1075: beq- chkfpfree ; Leaving active level, can not possibly enable...
1076: bne- cr1,chkvec ; Not our facility, nothing to do here...
1077:
1078: #if FPVECDBG
1079: lis r0,HIGH_ADDR(CutTrace) ; (TEST/DEBUG)
1080: li r2,0x3301 ; (TEST/DEBUG)
1081: oris r0,r0,LOW_ADDR(CutTrace) ; (TEST/DEBUG)
1082: sc ; (TEST/DEBUG)
1083: #endif
1084:
1085: lwz r24,ACT_MACT_FPUcpu(r8) ; Get the CPU this context was enabled on last
1086: cmplw r4,r20 ; Are we going to be in the right level?
1087: cmplw cr1,r24,r26 ; Are we on the right CPU?
1088: li r0,0 ; Get a constant 0
1089: beq+ cr1,chkfpnlvl ; Right CPU...
1090:
1091: stw r0,PP_FPU_THREAD(r10) ; Show facility unowned so we do not get back here
1092: b chkvec ; Go check out the vector facility...
1093:
1094: chkfpnlvl: bne- chkvec ; Different level, can not enable...
1095: lwz r24,ACT_MACT_FPU(r8) ; Get the floating point save area
1096: ori r12,r12,lo16(MASK(MSR_FP)) ; Enable facility
1097: mr. r24,r24 ; Does the savearea exist?
1098: li r0,1 ; Get set to invalidate
1099: beq- chkvec ; Nothing to invalidate...
1100: lwz r25,SAVlvlfp(r24) ; Get the level of top savearea
1101: cmplw r4,r25 ; Is the top one ours?
1102: bne+ chkvec ; Not ours...
1103: stw r0,SAVlvlfp(r24) ; Invalidate the first one
1104:
1105: #if 0
1106: mfmsr r0 ; (TEST/DEBUG)
1107: ori r0,r0,0x2000 ; (TEST/DEBUG)
1108: mtmsr r0 ; (TEST/DEBUG)
1109: isync ; (TEST/DEBUG)
1110:
1111: stfd f0,savevr0(r3) ; (TEST/DEBUG)
1112: stfd f1,savevr0+8(r3) ; (TEST/DEBUG)
1113: stfd f2,savevr0+0x10(r3) ; (TEST/DEBUG)
1114: stfd f3,savevr0+0x18(r3) ; (TEST/DEBUG)
1115: stfd f4,savevr0+0x20(r3) ; (TEST/DEBUG)
1116: stfd f5,savevr0+0x28(r3) ; (TEST/DEBUG)
1117: stfd f6,savevr0+0x30(r3) ; (TEST/DEBUG)
1118: stfd f7,savevr0+0x38(r3) ; (TEST/DEBUG)
1119: stfd f8,savevr0+0x40(r3) ; (TEST/DEBUG)
1120: stfd f9,savevr0+0x48(r3) ; (TEST/DEBUG)
1121: stfd f10,savevr0+0x50(r3) ; (TEST/DEBUG)
1122: stfd f11,savevr0+0x58(r3) ; (TEST/DEBUG)
1123: stfd f12,savevr0+0x60(r3) ; (TEST/DEBUG)
1124: stfd f13,savevr0+0x68(r3) ; (TEST/DEBUG)
1125: stfd f14,savevr0+0x70(r3) ; (TEST/DEBUG)
1126: stfd f15,savevr0+0x78(r3) ; (TEST/DEBUG)
1127: stfd f16,savevr0+0x80(r3) ; (TEST/DEBUG)
1128: stfd f17,savevr0+0x88(r3 ; (TEST/DEBUG)
1129: stfd f18,savevr0+0x90(r3) ; (TEST/DEBUG)
1130: stfd f19,savevr0+0x98(r3) ; (TEST/DEBUG)
1131: stfd f20,savevr0+0xA0(r3) ; (TEST/DEBUG)
1132: stfd f21,savevr0+0xA8(r3) ; (TEST/DEBUG)
1133: stfd f22,savevr0+0xB0(r3) ; (TEST/DEBUG)
1134: stfd f23,savevr0+0xB8(r3) ; (TEST/DEBUG)
1135: stfd f24,savevr0+0xC0(r3) ; (TEST/DEBUG)
1136: stfd f25,savevr0+0xC8(r3) ; (TEST/DEBUG)
1137: stfd f26,savevr0+0xD0(r3) ; (TEST/DEBUG)
1138: stfd f27,savevr0+0xD8(r3) ; (TEST/DEBUG)
1139: stfd f28,savevr0+0xE0(r3) ; (TEST/DEBUG)
1140: stfd f29,savevr0+0xE8(r3) ; (TEST/DEBUG)
1141: stfd f30,savevr0+0xF0(r3) ; (TEST/DEBUG)
1142: stfd f31,savevr0+0xF8(r3) ; (TEST/DEBUG)
1143:
1144: li r2,64 ; (TEST/DEBUG)
1145: la r20,savevr0(r3) ; (TEST/DEBUG)
1146: la r21,savefp0(r24) ; (TEST/DEBUG)
1147:
1148: ckmurderdeath2:
1149: lwz r22,0(r20) ; (TEST/DEBUG)
1150: subic. r2,r2,1 ; (TEST/DEBUG)
1151: lwz r23,0(r21) ; (TEST/DEBUG)
1152: addi r20,r20,4 ; (TEST/DEBUG)
1153: cmplw cr1,r22,r23 ; (TEST/DEBUG)
1154: addi r21,r21,4 ; (TEST/DEBUG)
1155: bne- cr1,diekilldead2 ; (TEST/DEBUG)
1156: bne+ ckmurderdeath2 ; (TEST/DEBUG)
1157: b dontdiekilldead2 ; (TEST/DEBUG)
1158:
1159: diekilldead2: ; (TEST/DEBUG)
1160: mr r4,r24 ; (TEST/DEBUG)
1161: BREAKPOINT_TRAP ; (TEST/DEBUG)
1162:
1163: dontdiekilldead2:
1164: lfd f0,savevr0(r3) ; (TEST/DEBUG)
1165: lfd f1,savevr0+8(r3) ; (TEST/DEBUG)
1166: #endif
1167:
1168:
1169:
1170: b chkvec ; Go check out the vector facility...
1171:
1172: chkfpfree: li r0,0 ; Clear a register
1173: lwz r24,ACT_MACT_FPU(r8) ; Get the floating point save area
1174:
1175: bne- cr1,chkfpnfr ; Not our facility, do not clear...
1176: stw r0,PP_FPU_THREAD(r10) ; Clear floating point owner
1177: chkfpnfr:
1178:
1179: #if FPVECDBG
1180: lis r0,HIGH_ADDR(CutTrace) ; (TEST/DEBUG)
1181: li r2,0x3302 ; (TEST/DEBUG)
1182: oris r0,r0,LOW_ADDR(CutTrace) ; (TEST/DEBUG)
1183: sc ; (TEST/DEBUG)
1184: #endif
1185:
1186: mr. r24,r24 ; Do we even have a savearea?
1187: beq+ chkvec ; Nope...
1188:
1189: #if FPVECDBG
1190: rlwinm. r0,r24,0,0,15 ; (TEST/DEBUG)
1191: bne+ notbadxxx1 ; (TEST/DEBUG)
1192: BREAKPOINT_TRAP ; (TEST/DEBUG)
1193: notbadxxx1: ; (TEST/DEBUG)
1194: lis r0,HIGH_ADDR(CutTrace) ; (TEST/DEBUG)
1195: li r2,0x3303 ; (TEST/DEBUG)
1196: oris r0,r0,LOW_ADDR(CutTrace) ; (TEST/DEBUG)
1197: sc ; (TEST/DEBUG)
1198: #endif
1199:
1200: lwz r25,SAVlvlfp(r24) ; Get the level of top savearea
1201: cmplwi r25,1 ; Is the top area invalid?
1202: cmplw cr1,r25,r3 ; Is it for the returned from context?
1203: beq fptoss ; It is invalid...
1204: bne cr1,chkvec ; Not for the returned context...
1205:
1206: fptoss: lwz r25,SAVprefp(r24) ; Get previous savearea
1207: #if FPVECDBG
1208: lis r0,HIGH_ADDR(CutTrace) ; (TEST/DEBUG)
1209: li r2,0x3304 ; (TEST/DEBUG)
1210: oris r0,r0,LOW_ADDR(CutTrace) ; (TEST/DEBUG)
1211: mr r5,r25 ; (TEST/DEBUG)
1212: sc ; (TEST/DEBUG)
1213: #endif
1214: mr. r25,r25 ; Is there one?
1215: stw r25,ACT_MACT_FPU(r8) ; Set the new pointer
1216: beq fptoplvl ; Nope, we are at the top...
1217: #if FPVECDBG
1218: rlwinm. r0,r25,0,0,15 ; (TEST/DEBUG)
1219: bne+ notbadxxx2 ; (TEST/DEBUG)
1220: BREAKPOINT_TRAP ; (TEST/DEBUG)
1221: notbadxxx2: ; (TEST/DEBUG)
1222: #endif
1223: lwz r25,SAVlvlfp(r25) ; Get the new level
1224:
1225: fptoplvl: lwz r19,SAVflags(r24) ; Get the savearea flags
1226: #if FPVECDBG
1227: rlwinm. r0,r19,0,1,1 ; (TEST/DEBUG)
1228: bne+ donotdie3 ; (TEST/DEBUG)
1229: BREAKPOINT_TRAP ; (TEST/DEBUG)
1230: donotdie3: ; (TEST/DEBUG)
1231: #endif
1232:
1233: #if FPVECDBG
1234: lis r0,HIGH_ADDR(CutTrace) ; (TEST/DEBUG)
1235: li r2,0x3305 ; (TEST/DEBUG)
1236: oris r0,r0,LOW_ADDR(CutTrace) ; (TEST/DEBUG)
1237: sc ; (TEST/DEBUG)
1238: #endif
1239: rlwinm r22,r24,0,0,19 ; Round down to the base savearea block
1240: rlwinm r19,r19,0,2,0 ; Remove the floating point in use flag
1241: stw r25,ACT_MACT_FPUlvl(r8) ; Set the new top level
1242: andis. r0,r19,hi16(SAVinuse) ; Still in use?
1243: stw r19,SAVflags(r24) ; Set the savearea flags
1244: bne- chkvec ; Yes, go check out vector...
1245: #if FPVECDBG
1246: lis r0,HIGH_ADDR(CutTrace) ; (TEST/DEBUG)
1247: li r2,0x3306 ; (TEST/DEBUG)
1248: oris r0,r0,LOW_ADDR(CutTrace) ; (TEST/DEBUG)
1249: sc ; (TEST/DEBUG)
1250: #endif
1251: #if FPVECDBG
1252: rlwinm. r0,r24,0,0,15 ; (TEST/DEBUG)
1253: bne+ notbadxxx3 ; (TEST/DEBUG)
1254: BREAKPOINT_TRAP ; (TEST/DEBUG)
1255: notbadxxx3: ; (TEST/DEBUG)
1256: #endif
1257: lwz r23,SACvrswap(r22) ; Get the conversion from virtual to real
1258: lwz r20,PP_QUICKFRET(r10) ; Get the old quick fret head
1259: xor r23,r24,r23 ; Convert to physical
1260: stw r20,SAVqfret(r24) ; Back chain the quick release queue
1261: stw r23,PP_QUICKFRET(r10) ; Anchor it
1262:
1263: ;
1264: ; Check out vector stuff (and translate savearea to physical for exit)
1265: ;
1266: chkvec:
1267: lwz r20,ACT_MACT_VMXlvl(r8) ; Get the vector level
1268: lwz r23,PP_VMX_THREAD(r10) ; Get vector owner
1269: cmplw r20,r3 ; Are we returning from the active level?
1270: rlwinm r12,r12,0,MSR_VEC_BIT+1,MSR_VEC_BIT-1 ; Turn off vector for now
1271: cmplw cr1,r23,r8 ; Are we the facility owner?
1272: beq- chkvecfree ; Leaving active level, can not possibly enable...
1273: bne- cr1,setena ; Not our facility, nothing to do here...
1274:
1275: #if FPVECDBG
1276: lis r0,HIGH_ADDR(CutTrace) ; (TEST/DEBUG)
1277: li r2,0x3401 ; (TEST/DEBUG)
1278: oris r0,r0,LOW_ADDR(CutTrace) ; (TEST/DEBUG)
1279: sc ; (TEST/DEBUG)
1280: #endif
1281:
1282: lwz r24,ACT_MACT_VMXcpu(r8) ; Get the CPU this context was enabled on last
1283: cmplw r4,r20 ; Are we going to be in the right level?
1284: cmplw cr1,r24,r26 ; Are we on the right CPU?
1285: li r0,0 ; Get a constant 0
1286: beq+ cr1,chkvecnlvl ; Right CPU...
1287:
1288: stw r0,PP_VMX_THREAD(r10) ; Show facility unowned so we do not get back here
1289: b setena ; Go actually exit...
1290:
1291: chkvecnlvl: bne- setena ; Different level, can not enable...
1292: lwz r24,ACT_MACT_VMX(r8) ; Get the vector save area
1293: oris r12,r12,hi16(MASK(MSR_VEC)) ; Enable facility
1294: mr. r24,r24 ; Does the savearea exist?
1295: li r0,1 ; Get set to invalidate
1296: beq- setena ; Nothing to invalidate...
1297: lwz r25,SAVlvlvec(r24) ; Get the level of top savearea
1298: cmplw r4,r25 ; Is the top one ours?
1299: bne+ setena ; Not ours...
1300: stw r0,SAVlvlvec(r24) ; Invalidate the first one
1301: b setena ; Actually exit...
1302:
1303: chkvecfree: li r0,0 ; Clear a register
1304: lwz r24,ACT_MACT_VMX(r8) ; Get the vector save area
1305: bne- cr1,chkvecnfr ; Not our facility, do not clear...
1306: stw r0,PP_VMX_THREAD(r10) ; Clear vector owner
1307: chkvecnfr:
1308:
1309: #if FPVECDBG
1310: lis r0,HIGH_ADDR(CutTrace) ; (TEST/DEBUG)
1311: li r2,0x3402 ; (TEST/DEBUG)
1312: oris r0,r0,LOW_ADDR(CutTrace) ; (TEST/DEBUG)
1313: sc ; (TEST/DEBUG)
1314: #endif
1315:
1316: mr. r24,r24 ; Do we even have a savearea?
1317: beq+ setena ; Nope...
1318:
1319: #if FPVECDBG
1320: lis r0,HIGH_ADDR(CutTrace) ; (TEST/DEBUG)
1321: li r2,0x3403 ; (TEST/DEBUG)
1322: oris r0,r0,LOW_ADDR(CutTrace) ; (TEST/DEBUG)
1323: sc ; (TEST/DEBUG)
1324: #endif
1325: lwz r25,SAVlvlvec(r24) ; Get the level
1326: cmplwi r25,1 ; Is the top area invalid?
1327: cmplw cr1,r25,r3 ; Is it for the returned from context?
1328: beq vectoss ; It is invalid...
1329: bne cr1,setena ; Not for the returned context...
1330:
1331: vectoss: lwz r25,SAVprevec(r24) ; Get previous savearea
1332: #if FPVECDBG
1333: lis r0,HIGH_ADDR(CutTrace) ; (TEST/DEBUG)
1334: li r2,0x3504 ; (TEST/DEBUG)
1335: oris r0,r0,LOW_ADDR(CutTrace) ; (TEST/DEBUG)
1336: mr r5,r25 ; (TEST/DEBUG)
1337: sc ; (TEST/DEBUG)
1338: #endif
1339: mr. r25,r25 ; Is there one?
1340: stw r25,ACT_MACT_VMX(r8) ; Set the new pointer
1341: beq vectoplvl ; Nope, we are at the top...
1342: lwz r25,SAVlvlvec(r25) ; Get the new level
1343:
1344: vectoplvl: lwz r19,SAVflags(r24) ; Get the savearea flags
1345:
1346: #if FPVECDBG
1347: lis r0,HIGH_ADDR(CutTrace) ; (TEST/DEBUG)
1348: li r2,0x3405 ; (TEST/DEBUG)
1349: oris r0,r0,LOW_ADDR(CutTrace) ; (TEST/DEBUG)
1350: sc ; (TEST/DEBUG)
1351: #endif
1352: rlwinm r22,r24,0,0,19 ; Round down to the base savearea block
1353: rlwinm r19,r19,0,3,1 ; Remove the vector in use flag
1354: stw r25,ACT_MACT_VMXlvl(r8) ; Set the new top level
1355: andis. r0,r19,hi16(SAVinuse) ; Still in use?
1356: stw r19,SAVflags(r24) ; Set the savearea flags
1357: bne- setena ; Yes, all done...
1358: #if FPVECDBG
1359: lis r0,HIGH_ADDR(CutTrace) ; (TEST/DEBUG)
1360: li r2,0x3406 ; (TEST/DEBUG)
1361: oris r0,r0,LOW_ADDR(CutTrace) ; (TEST/DEBUG)
1362: sc ; (TEST/DEBUG)
1363: #endif
1364: lwz r23,SACvrswap(r22) ; Get the conversion from virtual to real
1365: lwz r20,PP_QUICKFRET(r10) ; Get the old quick fret head
1366: xor r23,r24,r23 ; Convert to physical
1367: stw r20,SAVqfret(r24) ; Back chain the quick release queue
1368: stw r23,PP_QUICKFRET(r10) ; Anchor it
1369:
1370: setena: stw r12,savesrr1(r3) ; Turn facility on or off
1371:
1372: chkenax: lwz r6,SAVflags(r3) ; Pick up the flags of the old savearea
1373:
1374:
1375: #if DEBUG
1376: lwz r20,SAVact(r3) ; (TEST/DEBUG) Make sure our restore
1377: lwz r21,PP_CPU_DATA(r10) ; (TEST/DEBUG) context is associated
1378: lwz r21,CPU_ACTIVE_THREAD(r21) ; (TEST/DEBUG) with the current act.
1379: cmpwi r21,0 ; (TEST/DEBUG)
1380: beq- yeswereok ; (TEST/DEBUG)
1381: lwz r21,THREAD_TOP_ACT(r21) ; (TEST/DEBUG)
1382: cmplw r21,r20 ; (TEST/DEBUG)
1383: beq+ yeswereok ; (TEST/DEBUG)
1384: BREAKPOINT_TRAP ; (TEST/DEBUG)
1385:
1386: yeswereok:
1387: #endif
1388:
1389: rlwinm r5,r3,0,0,19 ; Round savearea down to page bndry
1390: rlwinm r6,r6,0,1,31 ; Mark savearea free
1391: lwz r5,SACvrswap(r5) ; Get the conversion from virtual to real
1392: stw r6,SAVflags(r3) ; Set savearea flags
1393: xor r3,r3,r5 ; Flip to physical address
1394: b EXT(exception_exit) ; We are all done now...
1395:
1396:
1397:
1398: /*
1399: * Here's where we handle the fastpath stuff
1400: * We'll do what we can here because registers are already
1401: * loaded and it will be less confusing that moving them around.
1402: * If we need to though, we'll branch off somewhere's else.
1403: *
1404: * Registers when we get here:
1405: *
1406: * r0 = syscall number
1407: * r4 = savearea/pcb
1408: * r13 = activation
1409: * r14 = previous savearea (if any)
1410: * r16 = thread
1411: * r25 = per_proc
1412: */
1413:
1414: fastpath: cmplwi cr3,r0,0x7FF1 ; Is it CthreadSetSelfNumber?
1415: bnelr- cr3 ; Not a fast path...
1416:
1417: /*
1418: * void cthread_set_self(cproc_t p)
1419: *
1420: * set's thread state "user_value"
1421: *
1422: * This op is invoked as follows:
1423: * li r0, CthreadSetSelfNumber // load the fast-trap number
1424: * sc // invoke fast-trap
1425: * blr
1426: *
1427: */
1428:
1429: CthreadSetSelfNumber:
1430:
1431: lwz r5,saver3(r4) /* Retrieve the self number */
1432: stw r5,CTHREAD_SELF(r13) /* Remember it */
1433: stw r5,UAW(r25) /* Prime the per_proc_info with it */
1434:
1435:
1436: .globl EXT(fastexit)
1437: EXT(fastexit):
1438: lwz r8,SAVflags(r4) /* Pick up the flags */
1439: rlwinm r9,r4,0,0,19 /* Round down to the base savearea block */
1440: rlwinm r8,r8,0,1,31 /* Clear the attached bit */
1441: lwz r9,SACvrswap(r9) /* Get the conversion from virtual to real */
1442: stw r8,SAVflags(r4) /* Set the flags */
1443: xor r3,r4,r9 /* Switch savearea to physical addressing */
1444: b EXT(exception_exit) /* Go back to the caller... */
1445:
1446:
1447: /*
1448: * Here's where we check for a hit on the Blue Box Assist
1449: * Most registers are non-volatile, so be careful here. If we don't
1450: * recognize the trap instruction we go back for regular processing.
1451: * Otherwise we transfer to the assist code.
1452: */
1453:
1454: checkassist:
1455: lwz r23,savesrr1(r4) /* Get the interrupted MSR */
1456: lwz r24,ACT_MACT_BTS(r9) /* Get the table start */
1457: rlwinm. r23,r23,0,MSR_PR_BIT,MSR_PR_BIT /* Are we in userland? */
1458: lwz r27,savesrr0(r4) /* Get trapped address */
1459: beqlr- /* No assist in kernel mode... */
1460:
1461: checkassistBP: /* Safe place to breakpoint */
1462:
1463: sub r24,r27,r24 /* See how far into it we are */
1464: rlwinm r24,r24,PKTDSHIFT,0,27 /* Get displacement to control block */
1465: cmplwi r24,BBMAXTRAP*PKTDSIZE /* Do we fit in the list? */
1466: bgtlr- /* Nope, it's a regular trap... */
1467: b EXT(atomic_switch_trap) /* Go to the assist... */
1468:
1469: #if MACH_KDB
1470: /*
1471: * Here's where we jump into the debugger. This is called from
1472: * either an MP signal from another processor, or a command-power NMI
1473: * on the main processor.
1474: *
1475: * Note that somewhere in our stack should be a return into the interrupt
1476: * handler. If there isn't, we'll crash off the end of the stack, actually,
1477: * it'll just quietly return. hahahahaha.
1478: */
1479:
1480: ENTRY(kdb_kintr, TAG_NO_FRAME_USED)
1481:
1482: lis r9,HIGH_ADDR(EXT(ihandler_ret)) /* Top part of interrupt return */
1483: lis r10,HIGH_ADDR(EXT(intercept_ret)) /* Top part of intercept return */
1484: ori r9,r9,LOW_ADDR(EXT(ihandler_ret)) /* Bottom part of interrupt return */
1485: ori r10,r10,LOW_ADDR(EXT(intercept_ret)) /* Bottom part of intercept return */
1486:
1487: lwz r8,0(r1) /* Get our caller's stack frame */
1488:
1489: srchrets: mr. r8,r8 /* Have we reached the end of our rope? */
1490: beqlr- /* Yeah, just bail... */
1491: lwz r7,FM_LR_SAVE(r8) /* The whoever called them */
1492: cmplw cr0,r9,r7 /* Was it the interrupt handler? */
1493: beq srchfnd /* Yeah... */
1494: lwz r8,0(r8) /* Chain back to the previous frame */
1495: b srchrets /* Ok, check again... */
1496:
1497: srchfnd: stw r10,FM_LR_SAVE(r8) /* Modify return to come to us instead */
1498: blr /* Finish up and get back here... */
1499:
1500: /*
1501: * We come here when we've returned all the way to the interrupt handler.
1502: * That way we can enter the debugger with the registers and stack which
1503: * existed at the point of interruption.
1504: *
1505: * R3 points to the saved state at entry
1506: */
1507:
1508: ENTRY(intercept_ret, TAG_NO_FRAME_USED)
1509:
1510: lis r6,HIGH_ADDR(EXT(kdb_trap)) /* Get the top part of the KDB enter routine */
1511: mr r5,r3 /* Move saved state to the correct parameter */
1512: ori r6,r6,LOW_ADDR(EXT(kdb_trap)) /* Get the last part of the KDB enter routine */
1513: li r4,0 /* Set a code of 0 */
1514: mr r13,r3 /* Save the saved state pointer in a non-volatile */
1515: mtlr r6 /* Set the routine address */
1516: li r3,-1 /* Show we had an interrupt type */
1517:
1518: blrl /* Go enter KDB */
1519:
1520: mr r3,r13 /* Put the saved state where expected */
1521: b EXT(ihandler_ret) /* Go return from the interruption... */
1522:
1523: #endif
1524:
1525: #if VERIFYSAVE
1526: ;
1527: ; Savearea chain verification
1528: ;
1529:
1530: versave:
1531:
1532: #if 0
1533: ;
1534: ; Make sure that only the top FPU savearea is marked invalid
1535: ;
1536:
1537: lis r28,hi16(EXT(default_pset)) ; (TEST/DEBUG)
1538: lis r27,hi16(EXT(DebugWork)) ; (TEST/DEBUG)
1539: ori r28,r28,lo16(EXT(default_pset)) ; (TEST/DEBUG)
1540: ori r27,r27,lo16(EXT(DebugWork)) ; (TEST/DEBUG)
1541: li r20,0 ; (TEST/DEBUG)
1542: lwz r26,0(r27) ; (TEST/DEBUG)
1543: lwz r27,psthreadcnt(r28) ; (TEST/DEBUG)
1544: mr. r26,r26 ; (TEST/DEBUG)
1545: lwz r28,psthreads(r28) ; (TEST/DEBUG)
1546: bnelr- ; (TEST/DEBUG)
1547:
1548: fcknxtth: mr. r27,r27 ; (TEST/DEBUG)
1549: beqlr- ; (TEST/DEBUG)
1550:
1551: lwz r26,THREAD_TOP_ACT(r28) ; (TEST/DEBUG)
1552:
1553: fckact: mr. r26,r26 ; (TEST/DEBUG)
1554: bne+ fckact2 ; (TEST/DEBUG)
1555:
1556: lwz r28,THREAD_PSTHRN(r28) ; (TEST/DEBUG) Next in line
1557: subi r27,r27,1 ; (TEST/DEBUG)
1558: b fcknxtth ; (TEST/DEBUG)
1559:
1560: fckact2: lwz r20,ACT_MACT_FPU(r26) ; (TEST/DEBUG) Get FPU chain
1561: mr. r20,r20 ; (TEST/DEBUG) Are there any?
1562: beq+ fcknact ; (TEST/DEBUG) No...
1563:
1564: fckact3: lwz r20,SAVprefp(r20) ; (TEST/DEBUG) Get next in list
1565: mr. r20,r20 ; (TEST/DEBUG) Check next savearea
1566: beq+ fcknact ; (TEST/DEBUG) No...
1567:
1568: lwz r29,SAVlvlfp(r20) ; (TEST/DEBUG) Get the level
1569:
1570: cmplwi r29,1 ; (TEST/DEBUG) Is it invalid??
1571: bne+ fckact3 ; (TEST/DEBUG) Nope...
1572:
1573: lis r27,hi16(EXT(DebugWork)) ; (TEST/DEBUG)
1574: ori r27,r27,lo16(EXT(DebugWork)) ; (TEST/DEBUG)
1575: stw r27,0(r27) ; (TEST/DEBUG)
1576: BREAKPOINT_TRAP ; (TEST/DEBUG)
1577:
1578: fcknact: lwz r26,ACT_LOWER(r26) ; (TEST/DEBUG) Next activation
1579: b fckact ; (TEST/DEBUG)
1580: #endif
1581:
1582: #if 1
1583: ;
1584: ; Make sure there are no circular links in the float chain
1585: ; And that FP is marked busy in it.
1586: ; And the only the top is marked invalid.
1587: ; And that the owning PCB is correct.
1588: ;
1589:
1590: lis r28,hi16(EXT(default_pset)) ; (TEST/DEBUG)
1591: lis r27,hi16(EXT(DebugWork)) ; (TEST/DEBUG)
1592: ori r28,r28,lo16(EXT(default_pset)) ; (TEST/DEBUG)
1593: ori r27,r27,lo16(EXT(DebugWork)) ; (TEST/DEBUG)
1594: li r20,0 ; (TEST/DEBUG)
1595: lwz r26,0(r27) ; (TEST/DEBUG)
1596: lwz r27,psthreadcnt(r28) ; (TEST/DEBUG)
1597: mr. r26,r26 ; (TEST/DEBUG)
1598: lwz r28,psthreads(r28) ; (TEST/DEBUG)
1599: bnelr- ; (TEST/DEBUG)
1600:
1601: fcknxtth: mr. r27,r27 ; (TEST/DEBUG)
1602: beqlr- ; (TEST/DEBUG)
1603:
1604: lwz r26,THREAD_TOP_ACT(r28) ; (TEST/DEBUG)
1605:
1606: fckact: mr. r26,r26 ; (TEST/DEBUG)
1607: bne+ fckact2 ; (TEST/DEBUG)
1608:
1609: lwz r28,THREAD_PSTHRN(r28) ; (TEST/DEBUG) Next in line
1610: subi r27,r27,1 ; (TEST/DEBUG)
1611: b fcknxtth ; (TEST/DEBUG)
1612:
1613: fckact2: lwz r20,ACT_MACT_FPU(r26) ; (TEST/DEBUG) Get FPU chain
1614: li r29,1 ; (TEST/DEBUG)
1615: li r22,0 ; (TEST/DEBUG)
1616:
1617: fckact3: mr. r20,r20 ; (TEST/DEBUG) Are there any?
1618: beq+ fckact5 ; (TEST/DEBUG) No...
1619:
1620: addi r22,r22,1 ; (TEST/DEBUG) Count chain depth
1621:
1622: lwz r21,SAVflags(r20) ; (TEST/DEBUG) Get the flags
1623: rlwinm. r21,r21,0,1,1 ; (TEST/DEBUG) FP busy?
1624: bne+ fckact3a ; (TEST/DEBUG) Yeah...
1625: lis r27,hi16(EXT(DebugWork)) ; (TEST/DEBUG)
1626: ori r27,r27,lo16(EXT(DebugWork)) ; (TEST/DEBUG)
1627: stw r27,0(r27) ; (TEST/DEBUG)
1628: BREAKPOINT_TRAP ; (TEST/DEBUG) Die
1629:
1630: fckact3a: cmplwi r22,1 ; (TEST/DEBUG) At first SA?
1631: beq+ fckact3b ; (TEST/DEBUG) Yeah, invalid is ok...
1632: lwz r21,SAVlvlfp(r20) ; (TEST/DEBUG) Get level
1633: cmplwi r21,1 ; (TEST/DEBUG) Is it invalid?
1634: bne+ fckact3b ; (TEST/DEBUG) Nope, it is ok...
1635: lis r27,hi16(EXT(DebugWork)) ; (TEST/DEBUG)
1636: ori r27,r27,lo16(EXT(DebugWork)) ; (TEST/DEBUG)
1637: stw r27,0(r27) ; (TEST/DEBUG)
1638: BREAKPOINT_TRAP ; (TEST/DEBUG) Die
1639:
1640: fckact3b: lwz r21,SAVact(r20) ; (TEST/DEBUG) Get the owner
1641: cmplw r21,r26 ; (TEST/DEBUG) Correct activation?
1642: beq+ fckact3c ; (TEST/DEBUG) Yup...
1643: lis r27,hi16(EXT(DebugWork)) ; (TEST/DEBUG)
1644: ori r27,r27,lo16(EXT(DebugWork)) ; (TEST/DEBUG)
1645: stw r27,0(r27) ; (TEST/DEBUG)
1646: BREAKPOINT_TRAP ; (TEST/DEBUG) Die
1647:
1648: fckact3c: ; (TEST/DEBUG)
1649: lbz r21,SAVflags+3(r20) ; (TEST/DEBUG) Pick up the test byte
1650: mr. r21,r21 ; (TEST/DEBUG) marked?
1651: beq+ fckact4 ; (TEST/DEBUG) No, good...
1652:
1653: lis r27,hi16(EXT(DebugWork)) ; (TEST/DEBUG)
1654: ori r27,r27,lo16(EXT(DebugWork)) ; (TEST/DEBUG)
1655: stw r27,0(r27) ; (TEST/DEBUG)
1656: BREAKPOINT_TRAP ; (TEST/DEBUG)
1657:
1658: fckact4: stb r29,SAVflags+3(r20) ; (TEST/DEBUG) Set the test byte
1659: lwz r20,SAVprefp(r20) ; (TEST/DEBUG) Next in list
1660: b fckact3 ; (TEST/DEBUG) Try it...
1661:
1662: fckact5: lwz r20,ACT_MACT_FPU(r26) ; (TEST/DEBUG) Get FPU chain
1663: li r29,0 ; (TEST/DEBUG)
1664:
1665: fckact6: mr. r20,r20 ; (TEST/DEBUG) Are there any?
1666: beq+ fcknact ; (TEST/DEBUG) No...
1667:
1668: stb r29,SAVflags+3(r20) ; (TEST/DEBUG) Clear the test byte
1669: lwz r20,SAVprefp(r20) ; (TEST/DEBUG) Next in list
1670: b fckact6 ; (TEST/DEBUG) Try it...
1671:
1672: fcknact: lwz r26,ACT_LOWER(r26) ; (TEST/DEBUG) Next activation
1673: b fckact ; (TEST/DEBUG)
1674: #endif
1675:
1676:
1677: #if 0
1678: ;
1679: ; Make sure in use count matches found savearea. This is
1680: ; not always accurate. There is a variable "fuzz" factor in count.
1681:
1682: lis r28,hi16(EXT(default_pset)) ; (TEST/DEBUG)
1683: lis r27,hi16(EXT(DebugWork)) ; (TEST/DEBUG)
1684: ori r28,r28,lo16(EXT(default_pset)) ; (TEST/DEBUG)
1685: ori r27,r27,lo16(EXT(DebugWork)) ; (TEST/DEBUG)
1686: li r20,0 ; (TEST/DEBUG)
1687: lwz r26,0(r27) ; (TEST/DEBUG)
1688: lwz r27,psthreadcnt(r28) ; (TEST/DEBUG)
1689: mr. r26,r26 ; (TEST/DEBUG)
1690: lwz r28,psthreads(r28) ; (TEST/DEBUG)
1691: bnelr- ; (TEST/DEBUG)
1692:
1693: cknxtth: mr. r27,r27 ; (TEST/DEBUG)
1694: beq- cktotal ; (TEST/DEBUG)
1695:
1696: lwz r26,THREAD_TOP_ACT(r28) ; (TEST/DEBUG)
1697:
1698: ckact: mr. r26,r26 ; (TEST/DEBUG)
1699: bne+ ckact2 ; (TEST/DEBUG)
1700:
1701: lwz r28,THREAD_PSTHRN(r28) ; (TEST/DEBUG) Next in line
1702: subi r27,r27,1 ; (TEST/DEBUG)
1703: b cknxtth ; (TEST/DEBUG)
1704:
1705: ckact2: lwz r29,ACT_MACT_PCB(r26) ; (TEST/DEBUG)
1706:
1707: cknorm: mr. r29,r29 ; (TEST/DEBUG)
1708: beq- cknormd ; (TEST/DEBUG)
1709:
1710: addi r20,r20,1 ; (TEST/DEBUG) Count normal savearea
1711:
1712: lwz r29,SAVprev(r29) ; (TEST/DEBUG)
1713: b cknorm ; (TEST/DEBUG)
1714:
1715: cknormd: lwz r29,ACT_MACT_FPU(r26) ; (TEST/DEBUG)
1716:
1717: ckfpu: mr. r29,r29 ; (TEST/DEBUG)
1718: beq- ckfpud ; (TEST/DEBUG)
1719:
1720: lwz r21,SAVflags(r29) ; (TEST/DEBUG)
1721: rlwinm. r21,r21,0,0,0 ; (TEST/DEBUG) See if already counted
1722: bne- cknfpu ; (TEST/DEBUG)
1723:
1724: addi r20,r20,1 ; (TEST/DEBUG) Count fpu savearea
1725:
1726: cknfpu: lwz r29,SAVprefp(r29) ; (TEST/DEBUG)
1727: b ckfpu ; (TEST/DEBUG)
1728:
1729: ckfpud: lwz r29,ACT_MACT_VMX(r26) ; (TEST/DEBUG)
1730:
1731: ckvmx: mr. r29,r29 ; (TEST/DEBUG)
1732: beq- ckvmxd ; (TEST/DEBUG)
1733:
1734: lwz r21,SAVflags(r29) ; (TEST/DEBUG)
1735: rlwinm. r21,r21,0,0,1 ; (TEST/DEBUG) See if already counted
1736: bne- cknvmx ; (TEST/DEBUG)
1737:
1738: addi r20,r20,1 ; (TEST/DEBUG) Count vector savearea
1739:
1740: cknvmx: lwz r29,SAVprevec(r29) ; (TEST/DEBUG)
1741: b ckvmx ; (TEST/DEBUG)
1742:
1743: ckvmxd: lwz r26,ACT_LOWER(r26) ; (TEST/DEBUG) Next activation
1744: b ckact ; (TEST/DEBUG)
1745:
1746: cktotal: lis r28,hi16(EXT(saveanchor)) ; (TEST/DEBUG)
1747: lis r27,hi16(EXT(real_ncpus)) ; (TEST/DEBUG)
1748: ori r28,r28,lo16(EXT(saveanchor)) ; (TEST/DEBUG)
1749: ori r27,r27,lo16(EXT(real_ncpus)) ; (TEST/DEBUG)
1750:
1751: lwz r21,SVinuse(r28) ; (TEST/DEBUG)
1752: lwz r27,0(r27) ; (TEST/DEBUG) Get the number of CPUs
1753: sub. r29,r21,r20 ; (TEST/DEBUG) Get number accounted for
1754: blt- badsave ; (TEST/DEBUG) Have too many in use...
1755: sub r26,r29,r27 ; (TEST/DEBUG) Should be 1 unaccounted for for each processor
1756: cmpwi r26,10 ; (TEST/DEBUG) Allow a 10 area slop factor
1757: bltlr+ ; (TEST/DEBUG)
1758:
1759: badsave: lis r27,hi16(EXT(DebugWork)) ; (TEST/DEBUG)
1760: ori r27,r27,lo16(EXT(DebugWork)) ; (TEST/DEBUG)
1761: stw r27,0(r27) ; (TEST/DEBUG)
1762: BREAKPOINT_TRAP ; (TEST/DEBUG)
1763: #endif
1764: #endif
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.