2 * Copyright (c) 2000 Apple Computer, Inc. All rights reserved.
4 * @APPLE_LICENSE_HEADER_START@
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.
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
20 * @APPLE_LICENSE_HEADER_END@
26 /* Low level routines dealing with exception entry and exit.
27 * There are various types of exception:
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).
33 * The code for the FPU disabled handler (lazy fpu) is in cswtch.s
37 #include <mach_assert.h>
38 #include <mach/exception_types.h>
39 #include <mach/ppc/vm_param.h>
44 #include <ppc/proc_reg.h>
46 #include <ppc/exception.h>
56 * ENTRY: VM switched ON
58 * R3 contains exception code
59 * R4 points to the saved context (virtual address)
60 * Everything is saved in savearea
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
70 * otherwise we save a ppc_saved_state in the pcb, and switch to
71 * the kernel stack (setting pcb.ksp to 0)
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
79 /* TRAP_SPACE_NEEDED is the space assumed free on the kernel stack when
80 * another trap is taken. We need at least enough space for a saved state
81 * structure plus two small backpointer frames, and we add a few
82 * hundred bytes for the space needed by the C (which may be less but
83 * may be much more). We're trying to catch kernel stack overflows :-)
86 #define TRAP_SPACE_NEEDED FM_REDZONE+(2*FM_SIZE)+256
92 ENTRY(thandler, TAG_NO_FRAME_USED) /* What tag should this have?! */
94 mfsprg r25,0 /* Get the per_proc */
96 lwz r1,PP_ISTACKPTR(r25) ; Get interrupt stack pointer
99 lwz r6,PP_CPU_DATA(r25) /* Get point to cpu specific data */
100 cmpwi cr0,r1,0 ; Are we on interrupt stack?
101 lwz r6,CPU_ACTIVE_THREAD(r6) /* Get the pointer to the currently active thread */
102 beq- cr0,EXT(ihandler) ; Yes, not allowed except when debugger
103 ; is active. We will let the ihandler do this...
104 lwz r13,THREAD_TOP_ACT(r6) /* Point to the active activation */
105 lwz r26,ACT_MACT_BEDA(r13) /* Pick up the pointer to the blue box data area */
106 lwz r8,ACT_MACT_PCB(r13) /* Get the last savearea used */
107 mr. r26,r26 /* Do we have Blue Box Assist active? */
108 lwz r1,ACT_MACT_KSP(r13) /* Get the stack */
109 bnel- checkassist /* See if we should assist this */
110 stw r4,ACT_MACT_PCB(r13) /* Point to our savearea */
111 stw r8,SAVprev(r4) /* Queue the new save area in the front */
114 bl versave ; (TEST/DEBUG)
117 cmpwi cr1,r1, 0 /* zero implies already on kstack */
118 stw r13,SAVact(r4) /* Point the savearea at its activation */
119 bne cr1,.L_kstackfree /* This test is also used below */
120 lwz r1,saver1(r4) /* Get the stack at 'rupt time */
123 /* On kernel stack, allocate stack frame and check for overflow */
126 * Test if we will overflow the Kernel Stack. We
127 * check that there is at least TRAP_SPACE_NEEDED bytes
128 * free on the kernel stack
131 lwz r7,THREAD_KERNEL_STACK(r6)
132 addi r7,r7,TRAP_SPACE_NEEDED
137 subi r1,r1,FM_REDZONE /* Back up stack and leave room for a red zone */
141 lis r0,HIGH_ADDR(CutTrace) /* (TEST/DEBUG) */
142 oris r0,r0,LOW_ADDR(CutTrace) /* (TEST/DEBUG) */
143 sc /* (TEST/DEBUG) */
145 lwz r7,savesrr1(r4) /* Pick up the entry MSR */
146 li r0,0 /* Make this 0 */
148 beq cr1,.L_state_on_kstack /* using above test for pcb/stack */
150 stw r0,ACT_MACT_KSP(r13) /* Show that we have taken the stack */
153 rlwinm. r6,r7,0,MSR_VEC_BIT,MSR_VEC_BIT ; Was vector on?
154 lwz r6,saver1(r4) /* Grab interrupt time stack */
155 beq+ tvecoff ; Vector off, do not save vrsave...
156 lwz r3,savevrsave(r4) ; Get the VRSAVE register
157 stw r3,liveVRS(r25) ; Set the live value
159 tvecoff: rlwinm. r3,r7,0,MSR_FP_BIT,MSR_FP_BIT ; Was floating point on?
160 subi r1,r1,FM_SIZE /* Push a header onto the current stack */
161 beq+ tfpoff /* Floating point was off... */
162 lwz r3,savexfpscr(r4) ; Grab the just saved FPSCR
163 stw r3,liveFPSCR(r25) ; Make it the live copy
165 tfpoff: stw r6,FM_BACKPTR(r1) /* Link backwards */
168 /* If debugging, we need two frames, the first being a dummy
169 * which links back to the trapped routine. The second is
170 * that which the C routine below will need
172 lwz r3,savesrr0(r4) /* Get the point of interruption */
173 stw r3,FM_LR_SAVE(r1) /* save old instr ptr as LR value */
174 stwu r1, -FM_SIZE(r1) /* and make new frame */
178 /* call trap handler proper, with
179 * ARG0 = type (not yet, holds pcb ptr)
180 * ARG1 = saved_state ptr (already there)
181 * ARG2 = dsisr (already there)
182 * ARG3 = dar (already there)
186 lwz r3,saveexception(r4) /* Get the exception code */
187 lwz r0,ACT_MACT_SPF(r13) ; Get the special flags
189 addi r5,r3,-T_DATA_ACCESS ; Adjust to start of range
190 rlwinm. r0,r0,0,runningVMbit,runningVMbit ; Are we in VM state? (cr0_eq == 0 if yes)
191 cmplwi cr2,r5,T_RUNMODE_TRACE-T_DATA_ACCESS ; Are we still in range? (cr_gt if not)
193 lwz r5,savedsisr(r4) /* Get the saved DSISR */
195 crnor cr7_eq,cr0_eq,cr2_gt ; We should intercept if in VM and is a true trap (cr7_eq == 1 if yes)
196 rlwinm. r0,r7,0,MSR_PR_BIT,MSR_PR_BIT ; Are we trapping from supervisor state? (cr0_eq == 1 if yes)
198 cmpi cr2,r3,T_PREEMPT ; Is this a preemption?
200 crandc cr0_eq,cr7_eq,cr0_eq ; Do not intercept if we are in the kernel (cr0_eq == 1 if yes)
202 lwz r6,savedar(r4) /* Get the DAR */
204 beq- cr2, .L_call_trap /* Don't turn on interrupts for T_PREEMPT */
205 beq- exitFromVM ; Any true trap but T_MACHINE_CHECK exits us from the VM...
207 /* syscall exception might warp here if there's nothing left
208 * to do except generate a trap
213 lis r0,HIGH_ADDR(CutTrace) /* (TEST/DEBUG) */
214 oris r0,r0,LOW_ADDR(CutTrace) /* (TEST/DEBUG) */
215 sc /* (TEST/DEBUG) */
221 * Ok, return from C function
223 * This is also the point where new threads come when they are created.
224 * The new thread is setup to look like a thread that took an
225 * interrupt and went immediatly into trap.
231 mfmsr r7 /* Get the MSR */
232 lwz r4,SAVprev(r3) /* Pick up the previous savearea */
233 rlwinm r7,r7,0,MSR_EE_BIT+1,MSR_EE_BIT-1 /* Clear the interrupt enable mask */
234 lwz r11,SAVflags(r3) /* Get the flags of the current savearea */
235 mtmsr r7 /* Disable for interrupts */
237 mfsprg r10,0 /* Restore the per_proc info */
239 lwz r8,savesrr1(r3) ; Get the MSR we are going to
240 lwz r1,PP_CPU_DATA(r10) /* Get the CPU data area */
241 rlwinm r11,r11,0,15,13 /* Clear the syscall flag */
242 lwz r1,CPU_ACTIVE_THREAD(r1) /* and the active thread */
243 rlwinm. r8,r8,0,MSR_PR_BIT,MSR_PR_BIT ; Are we going to the user?
244 lwz r8,THREAD_TOP_ACT(r1) /* Now find the current activation */
245 stw r11,SAVflags(r3) /* Save back the flags (with reset stack cleared) */
248 lis r0,HIGH_ADDR(CutTrace) /* (TEST/DEBUG) */
249 oris r0,r0,LOW_ADDR(CutTrace) /* (TEST/DEBUG) */
250 sc /* (TEST/DEBUG) */
252 stw r4,ACT_MACT_PCB(r8) /* Point to the previous savearea (or 0 if none) */
254 beq- chkfac ; We are not leaving the kernel yet...
256 lwz r5,THREAD_KERNEL_STACK(r1) /* Get the base pointer to the stack */
257 addi r5,r5,KERNEL_STACK_SIZE-FM_SIZE /* Reset to empty */
258 stw r5,ACT_MACT_KSP(r8) /* Save the empty stack pointer */
259 b chkfac /* Go end it all... */
266 * ENTRY: VM switched ON
268 * R3 contains exception code
269 * R4 points to the saved context (virtual address)
270 * Everything is saved in savearea
274 * If pcb.ksp == 0 then the kernel stack is already busy,
275 * this is an error - jump to the debugger entry
277 * otherwise depending upon the type of
278 * syscall, look it up in the kernel table
279 * or pass it to the server.
281 * on return, we do the reverse, the state is popped from the pcb
282 * and pcb.ksp is set to the top of stack.
287 * mach system calls are negative
288 * BSD system calls are low positive
289 * PPC-only system calls are in the range 0x6xxx
290 * PPC-only "fast" traps are in the range 0x7xxx
293 ENTRY(shandler, TAG_NO_FRAME_USED)
295 mfsprg r25,0 /* Get the per proc area */
296 lwz r0,saver0(r4) /* Get the original syscall number */
297 lwz r17,PP_ISTACKPTR(r25) ; Get interrupt stack pointer
298 rlwinm r15,r0,0,0,19 ; Clear the bottom of call number for fast check
299 lwz r16,PP_CPU_DATA(r25) /* Assume we need this */
300 mr. r17,r17 ; Are we on interrupt stack?
301 lwz r7,savesrr1(r4) ; Get the SRR1 value
302 beq- EXT(ihandler) ; On interrupt stack, not allowed...
303 rlwinm. r6,r7,0,MSR_VEC_BIT,MSR_VEC_BIT ; Was vector on?
304 lwz r16,CPU_ACTIVE_THREAD(r16) /* Get the thread pointer */
306 beq+ svecoff ; Vector off, do not save vrsave...
307 lwz r7,savevrsave(r4) ; Get the VRSAVE register
308 stw r7,liveVRS(r25) ; Set the live value
310 svecoff: rlwinm. r6,r7,0,MSR_FP_BIT,MSR_FP_BIT ; Was floating point on?
311 lwz r13,THREAD_TOP_ACT(r16) /* Pick up the active thread */
312 beq+ sfpoff ; Skip if floating point is off...
313 lwz r9,savexfpscr(r4) ; Grab the just saved FPSCR
314 stw r9,liveFPSCR(r25) ; Make it the live copy
316 ; Check if SCs are being redirected for the BlueBox or to VMM
318 sfpoff: lwz r6,ACT_MACT_SPF(r13) ; Pick up activation special flags
319 lwz r26,ACT_MACT_BEDA(r13) ; Pick up the pointer to the blue box exception area
320 rlwinm. r9,r6,0,runningVMbit,runningVMbit ; Are we running in alternate context right now?
321 cmpwi cr1,r26,0 ; Do we have Blue Box Assist active?
322 crmove cr2_eq,cr0_eq ; Remember if we are in VMM
323 rlwinm. r6,r6,0,bbNoMachSCbit,bbNoMachSCbit ; Are mach SCs redirected for this thread
324 beq+ noassist ; Take branch if SCs are not redirected
325 beq- cr1,noassist ; No assist for non-bluebox threads
326 mr r9,r13 ; Setup ACT for atomic_switch api
327 b EXT(atomic_switch_syscall) ; Go to the assist...
330 cmplwi r15,0x7000 /* Do we have a fast path trap? */
331 lwz r14,ACT_MACT_PCB(r13) /* Now point to the PCB */
332 beql+ fastpath /* We think it's a fastpath... */
334 lwz r1,ACT_MACT_KSP(r13) /* Get the kernel stack pointer */
336 mr. r1,r1 /* Are we already on the kernel stack? */
337 li r3,T_SYSTEM_CALL /* Yup, pretend we had an interrupt... */
338 beq- EXT(ihandler) /* Bad boy, bad boy... What'cha gonna do when they come for you? */
341 stw r4,ACT_MACT_PCB(r13) /* Point to our savearea */
342 li r0,0 /* Clear this out */
343 stw r14,SAVprev(r4) /* Queue the new save area in the front */
344 stw r13,SAVact(r4) /* Point the savearea at its activation */
347 bl versave ; (TEST/DEBUG)
350 mr r30,r4 /* Save pointer to the new context savearea */
351 lwz r15,saver1(r4) /* Grab interrupt time stack */
352 stw r0,ACT_MACT_KSP(r13) /* Mark stack as busy with 0 val */
353 stw r15,FM_BACKPTR(r1) /* Link backwards */
356 /* If debugging, we need two frames, the first being a dummy
357 * which links back to the trapped routine. The second is
358 * that which the C routine below will need
360 lwz r8,savesrr0(r30) /* Get the point of interruption */
361 stw r8,FM_LR_SAVE(r1) /* save old instr ptr as LR value */
362 stwu r1, -FM_SIZE(r1) /* and make new frame */
365 mfmsr r11 /* Get the MSR */
366 lwz r15,SAVflags(r4) /* Get the savearea flags */
367 ori r11,r11,lo16(MASK(MSR_EE)) /* Turn on interruption enabled bit */
368 lwz r0,saver0(r30) ; Get R0 back
369 oris r15,r15,SAVsyscall >> 16 /* Mark that it this is a syscall */
370 rlwinm r10,r0,0,0,19 ; Keep only the top part
371 stwu r1,-(FM_SIZE+ARG_SIZE)(r1) /* Make a stack frame */
372 cmplwi r10,0x6000 ; Is it the special ppc-only guy?
373 stw r15,SAVflags(r30) /* Save syscall marker */
374 bne- cr2,exitFromVM ; It is time to exit from alternate context...
376 beq- ppcscall ; Call the ppc-only system call handler...
378 mtmsr r11 /* Enable interruptions */
380 /* Call a function that can print out our syscall info */
381 /* Note that we don't care about any volatiles yet */
383 bl EXT(syscall_trace)
385 lwz r0,saver0(r30) /* Get the system call selector */
386 mr. r0,r0 /* What kind is it? */
387 blt- .L_kernel_syscall /* -ve syscall - go to kernel */
388 /* +ve syscall - go to server */
390 beq- .L_notify_interrupt_syscall
393 mr r3,r30 /* Get PCB/savearea */
394 lwz r4,saver4(r30) /* Restore r4 */
395 lwz r5,saver5(r30) /* Restore r5 */
396 lwz r6,saver6(r30) /* Restore r6 */
397 lwz r7,saver7(r30) /* Restore r7 */
398 lwz r8,saver8(r30) /* Restore r8 */
399 lwz r9,saver9(r30) /* Restore r9 */
400 lwz r10,saver10(r30) /* Restore r10 */
401 bl EXT(unix_syscall) /* Check out unix... */
404 .L_call_server_syscall_exception:
405 li r3,EXC_SYSCALL /* doexception(EXC_SYSCALL, num, 1) */
407 .L_call_server_exception:
408 mr r4,r0 /* Set syscall selector */
410 b EXT(doexception) /* Go away, never to return... */
412 /* The above, but with EXC_MACH_SYSCALL */
413 .L_call_server_mach_syscall:
414 li r3,EXC_MACH_SYSCALL
415 b .L_call_server_exception /* Join the common above... */
417 .L_notify_interrupt_syscall:
418 lwz r3,saver3(r30) ; Get the new PC address to pass in
419 bl EXT(syscall_notify_interrupt)
423 ; Handle PPC-only system call interface
424 ; These are called with interruptions disabled
425 ; and the savearea/pcb as the first parameter.
426 ; It is up to the callee to enable interruptions if
427 ; they should be. We are in a state here where
428 ; both interrupts and preemption is ok, but because we could
429 ; be calling diagnostic code we will not enable.
431 ; Also, the callee is responsible for finding any parameters
432 ; in the savearea/pcb. It also must set saver3 with any return
433 ; code before returning.
435 ; There are 3 possible return codes:
436 ; 0 the call is disabled or something, we treat this like it was bogus
437 ; + the call finished ok, check for AST
438 ; - the call finished ok, do not check for AST
440 ; Note: the last option is intended for special diagnostics calls that
441 ; want the thread to return and execute before checking for preemption.
444 ppcscall: rlwinm r11,r0,2,18,29 ; Make an index into the table
445 lis r10,hi16(EXT(PPCcalls)) ; Get PPC-only system call table
446 cmplwi r11,PPCcallmax ; See if we are too big
447 ori r10,r10,lo16(EXT(PPCcalls)) ; Merge in low half
448 bgt- .L_call_server_syscall_exception ; Bogus call...
449 lwzx r11,r10,r11 ; Get function address
452 ; Note: make sure we do not change the savearea in R30 to
453 ; a different register without checking. Some of the PPCcalls
454 ; depend upon it being there.
457 mr r3,r30 ; Pass the savearea
458 mr r4,r13 ; Pass the activation
459 mr. r11,r11 ; See if there is a function here
460 mtlr r11 ; Set the function address
461 beq- .L_call_server_syscall_exception ; Disabled call...
467 mr. r3,r3 ; See what we should do
468 mr r31,r16 ; Restore the current thread pointer
469 bgt+ .L_thread_syscall_ret_check_ast ; Take normal AST checking return....
470 blt+ .L_thread_syscall_return ; Return, but no ASTs....
471 lwz r0,saver0(r30) ; Restore the system call number
472 b .L_call_server_syscall_exception ; Go to common exit...
475 /* Once here, we know that the syscall was -ve
476 * we should still have r1=ksp,
477 * r16 = pointer to current thread,
478 * r13 = pointer to top activation,
479 * r0 = syscall number
480 * r30 = pointer to saved state (in pcb)
483 neg r31, r0 /* Make number +ve and put in r31*/
485 /* If out of range, call server with syscall exception */
486 addis r29, 0, HIGH_CADDR(EXT(mach_trap_count))
487 addi r29, r29, LOW_ADDR(EXT(mach_trap_count))
491 bge- cr0, .L_call_server_syscall_exception
493 addis r29, 0, HIGH_CADDR(EXT(mach_trap_table))
494 addi r29, r29, LOW_ADDR(EXT(mach_trap_table))
496 /* multiply the trap number to get offset into table */
497 slwi r31, r31, MACH_TRAP_OFFSET_POW2
499 /* r31 now holds offset into table of our trap entry,
500 * add on the table base, and it then holds pointer to entry
504 /* If the function is kern_invalid, prepare to send an exception.
505 This is messy, but parallels the x86. We need it for task_by_pid,
507 lis r29, HIGH_CADDR(EXT(kern_invalid))
508 addi r29, r29, LOW_ADDR(EXT(kern_invalid))
509 lwz r0, MACH_TRAP_FUNCTION(r31)
511 beq- .L_call_server_syscall_exception
513 /* get arg count. If argc > 8 then not all args were in regs,
514 * so we must perform copyin.
516 lwz r29, MACH_TRAP_ARGC(r31)
518 ble+ .L_syscall_got_args
520 /* argc > 8 - perform a copyin */
521 /* if the syscall came from kernel space, we can just copy */
523 lwz r0,savesrr1(r30) /* Pick up exception time MSR */
524 andi. r0,r0,MASK(MSR_PR) /* Check the priv bit */
525 bne+ .L_syscall_arg_copyin /* We're not priviliged... */
527 /* we came from a privilaged task, just do a copy */
528 /* get user's stack pointer */
530 lwz r28,saver1(r30) /* Get the stack pointer */
532 subi r29,r29,8 /* Get the number of arguments to copy */
534 addi r28,r28,COPYIN_ARG0_OFFSET-4 /* Point to source - 4 */
535 addi r27,r1,FM_ARG0-4 /* Point to sink - 4 */
537 .L_syscall_copy_word_loop:
538 addic. r29,r29,-1 /* Count down the number of arguments left */
539 lwz r0,4(r28) /* Pick up the argument from the stack */
540 addi r28,r28,4 /* Point to the next source */
541 stw r0,4(r27) /* Store the argument */
542 addi r27,r27,4 /* Point to the next sink */
543 bne+ .L_syscall_copy_word_loop /* Move all arguments... */
544 b .L_syscall_got_args /* Go call it now... */
547 /* we came from a user task, pay the price of a real copyin */
548 /* set recovery point */
550 .L_syscall_arg_copyin:
551 lwz r8,ACT_VMMAP(r13) ; Get the vm_map for this activation
552 lis r28,hi16(.L_syscall_copyin_recover)
553 lwz r8,VMMAP_PMAP(r8) ; Get the pmap
554 ori r28,r28,lo16(.L_syscall_copyin_recover)
555 addi r8,r8,PMAP_SEGS ; Point to the pmap SR slots
556 stw r28,THREAD_RECOVER(r16) /* R16 still holds thread ptr */
558 /* We can manipulate the COPYIN segment register quite easily
559 * here, but we've also got to make sure we don't go over a
560 * segment boundary - hence some mess.
561 * Registers from 12-29 are free for our use.
565 lwz r28,saver1(r30) /* Get the stack pointer */
566 subi r29,r29,8 /* Get the number of arguments to copy */
567 addi r28,r28,COPYIN_ARG0_OFFSET /* Set source in user land */
569 /* set up SR_COPYIN to allow us to copy, we may need to loop
570 * around if we change segments. We know that this previously
571 * pointed to user space, so the sid doesn't need setting.
574 rlwinm r7,r28,6,26,29 ; Get index to the segment slot
576 .L_syscall_copyin_seg_loop:
579 lwzx r10,r8,r7 ; Get the source SR value
580 rlwinm r26,r28,0,4,31 ; Clear the segment number from source address
581 mtsr SR_COPYIN,r10 ; Set the copyin SR
584 oris r26,r26,(SR_COPYIN_NUM << (28-16)) ; Insert the copyin segment number into source address
586 /* Make r27 point to address-4 of where we will store copied args */
587 addi r27,r1,FM_ARG0-4
589 .L_syscall_copyin_word_loop:
591 lwz r0,0(r26) /* MAY CAUSE PAGE FAULT! */
592 subi r29,r29,1 ; Decrement count
593 addi r26,r26,4 ; Bump input
594 stw r0,4(r27) ; Save the copied in word
595 mr. r29,r29 ; Are they all moved?
596 addi r27,r27,4 ; Bump output
597 beq+ .L_syscall_copyin_done ; Escape if we are done...
599 rlwinm. r0,r26,0,4,29 ; Did we just step into a new segment?
600 addi r28,r28,4 ; Bump up user state address also
601 bne+ .L_syscall_copyin_word_loop ; We are still on the same segment...
603 addi r7,r7,4 ; Bump to next slot
604 b .L_syscall_copyin_seg_loop /* On new segment! remap */
606 /* Don't bother restoring SR_COPYIN, we can leave it trashed */
607 /* clear thread recovery as we're done touching user data */
609 .L_syscall_copyin_done:
611 stw r0,THREAD_RECOVER(r16) /* R16 still holds thread ptr */
614 lwz r8,ACT_TASK(r13) /* Get our task */
615 lis r10,hi16(EXT(c_syscalls_mach)) /* Get top half of counter address */
616 lwz r7,TASK_SYSCALLS_MACH(r8) ; Get the current count
617 lwz r3,saver3(r30) /* Restore r3 */
618 addi r7,r7,1 ; Bump it
619 ori r10,r10,lo16(EXT(c_syscalls_mach)) /* Get low half of counter address */
620 stw r7,TASK_SYSCALLS_MACH(r8) ; Save it
621 lwz r4,saver4(r30) /* Restore r4 */
622 lwz r9,0(r10) /* Get counter */
623 lwz r5,saver5(r30) /* Restore r5 */
624 lwz r6,saver6(r30) /* Restore r6 */
625 addi r9,r9,1 /* Add 1 */
626 lwz r7,saver7(r30) /* Restore r7 */
627 lwz r8,saver8(r30) /* Restore r8 */
628 stw r9,0(r10) /* Save it back */
629 lwz r9,saver9(r30) /* Restore r9 */
630 lwz r10,saver10(r30) /* Restore r10 */
632 lwz r0,MACH_TRAP_FUNCTION(r31)
634 /* calling this function, all the callee-saved registers are
635 * still valid except for r30 and r31 which are in the PCB
636 * r30 holds pointer to saved state (ie. pcb)
640 bctrl /* perform the actual syscall */
642 /* 'standard' syscall returns here - INTERRUPTS ARE STILL ON */
644 /* r3 contains value that we're going to return to the user
648 * Ok, return from C function, ARG0 = return value
650 * get the active thread's PCB pointer and thus pointer to user state
651 * saved state is still in R30 and the active thread is in R16 .
654 /* Store return value into saved state structure, since
655 * we need to pick up the value from here later - the
656 * syscall may perform a thread_set_syscall_return
657 * followed by a thread_exception_return, ending up
658 * at thread_syscall_return below, with SS_R3 having
659 * been set up already
662 /* When we are here, r16 should point to the current thread,
663 * r30 should point to the current pcb
666 /* save off return value, we must load it
667 * back anyway for thread_exception_return
668 * TODO NMGS put in register?
671 mr r31,r16 /* Move the current thread pointer */
672 stw r3,saver3(r30) /* Stash the return code */
674 /* Call a function that records the end of */
675 /* the mach system call */
677 bl EXT(syscall_trace_end)
680 lis r0,HIGH_ADDR(CutTrace) /* (TEST/DEBUG) */
681 mr r4,r31 /* (TEST/DEBUG) */
682 oris r0,r0,LOW_ADDR(CutTrace) /* (TEST/DEBUG) */
683 mr r5,r30 /* (TEST/DEBUG) */
684 sc /* (TEST/DEBUG) */
687 .L_thread_syscall_ret_check_ast:
688 mfmsr r12 /* Get the current MSR */
689 rlwinm r12,r12,0,MSR_EE_BIT+1,MSR_EE_BIT-1 /* Turn off interruptions enable bit */
690 mtmsr r12 /* Turn interruptions off */
692 mfsprg r10,0 /* Get the per_processor block */
694 /* Check to see if there's an outstanding AST */
696 lwz r4,PP_NEED_AST(r10)
699 beq cr0,.L_syscall_no_ast
701 /* Yes there is, call ast_taken
702 * pretending that the user thread took an AST exception here,
703 * ast_taken will save all state and bring us back here
707 /* debug assert - make sure that we're not returning to kernel */
709 andi. r3,r3,MASK(MSR_PR)
710 bne+ 0f /* returning to user level, check */
721 b .L_thread_syscall_ret_check_ast
723 /* thread_exception_return returns to here, almost all
724 * registers intact. It expects a full context restore
725 * of what it hasn't restored itself (ie. what we use).
727 * In particular for us,
728 * we still have r31 points to the current thread,
729 * r30 points to the current pcb
733 .L_thread_syscall_return:
735 mr r3,r30 ; Get savearea to the correct register for common exit
736 lwz r8,THREAD_TOP_ACT(r31) /* Now find the current activation */
738 lwz r11,SAVflags(r30) /* Get the flags */
739 lwz r5,THREAD_KERNEL_STACK(r31) /* Get the base pointer to the stack */
740 rlwinm r11,r11,0,15,13 /* Clear the syscall flag */
741 lwz r4,SAVprev(r30) ; Get the previous save area
742 stw r11,SAVflags(r30) /* Stick back the flags */
743 addi r5,r5,KERNEL_STACK_SIZE-FM_SIZE /* Reset to empty */
744 stw r4,ACT_MACT_PCB(r8) ; Save previous save area
745 stw r5,ACT_MACT_KSP(r8) /* Save the empty stack pointer */
747 b chkfac ; Go end it all...
750 .L_syscall_copyin_recover:
752 /* This is the catcher for any data faults in the copyin
753 * of arguments from the user's stack.
754 * r30 still holds a pointer to the PCB
756 * call syscall_error(EXC_BAD_ACCESS, EXC_PPC_VM_PROT_READ, sp, ssp),
758 * we already had a frame so we can do this
762 li r4,EXC_PPC_VM_PROT_READ
766 bl EXT(syscall_error)
771 * thread_bootstrap_return()
773 * NOTE: THIS IS GOING AWAY IN A FEW DAYS....
777 ENTRY(thread_bootstrap_return, TAG_NO_FRAME_USED)
778 b .L_thread_exc_ret_check_ast ; Do the same as thread_exception_return...
781 * thread_exception_return()
783 * Return to user mode directly from within a system call.
786 ENTRY(thread_exception_return, TAG_NO_FRAME_USED)
788 .L_thread_exc_ret_check_ast:
790 mfmsr r3 /* Get the MSR */
791 rlwinm r3,r3,0,MSR_EE_BIT+1,MSR_EE_BIT-1 /* Clear EE */
792 mtmsr r3 /* Disable interrupts */
794 /* Check to see if there's an outstanding AST */
795 /* We don't bother establishing a call frame even though CHECK_AST
796 can invoke ast_taken(), because it can just borrow our caller's
797 frame, given that we're not going to return.
800 mfsprg r10,0 /* Get the per_processor block */
801 lwz r4,PP_NEED_AST(r10)
804 beq cr0,.L_exc_ret_no_ast
806 /* Yes there is, call ast_taken
807 * pretending that the user thread took an AST exception here,
808 * ast_taken will save all state and bring us back here
817 b .L_thread_exc_ret_check_ast /* check for a second AST (rare)*/
819 /* arriving here, interrupts should be disabled */
820 /* Get the active thread's PCB pointer to restore regs
824 lwz r31,PP_CPU_DATA(r10)
825 lwz r31,CPU_ACTIVE_THREAD(r31)
826 lwz r30,THREAD_TOP_ACT(r31)
827 lwz r30,ACT_MACT_PCB(r30)
828 mr. r30,r30 ; Is there any context yet?
829 beq- makeDummyCtx ; No, hack one up...
832 * debug assert - make sure that we're not returning to kernel
833 * get the active thread's PCB pointer and thus pointer to user state
837 andi. r3,r3,MASK(MSR_PR)
838 bne+ ret_user2 ; We are ok...
844 /* If the MSR_SYSCALL_MASK isn't set, then we came from a trap,
845 * so warp into the return_from_trap (thread_return) routine,
846 * which takes PCB pointer in R3, not in r30!
849 mr r3,r30 /* Copy pcb pointer into r3 in case */
850 andis. r0,r0,SAVsyscall>>16 /* Are we returning from a syscall? */
851 beq- cr0,thread_return /* Nope, must be a thread return... */
852 b .L_thread_syscall_return
855 ; This is where we handle someone trying who did a thread_create followed
856 ; by a thread_resume with no intervening thread_set_state. Just make an
857 ; empty context, initialize it to trash and let em execute at 0...
860 bl EXT(save_get) ; Get a save_area
862 addi r2,r3,savefp0 ; Point past what we are clearing
863 mr r4,r3 ; Save the start
865 cleardummy: stw r0,0(r4) ; Clear stuff
866 addi r4,r4,4 ; Next word
867 cmplw r4,r2 ; Still some more?
868 blt+ cleardummy ; Yeah...
870 lis r2,hi16(MSR_EXPORT_MASK_SET) ; Set the high part of the user MSR
871 ori r2,r2,lo16(MSR_EXPORT_MASK_SET) ; And the low part
872 stw r2,savesrr1(r3) ; Set the default user MSR
874 b thread_return ; Go let em try to execute, hah!
879 * ENTRY: VM switched ON
881 * R3 contains exception code
882 * R4 points to the saved context (virtual address)
883 * Everything is saved in savearea
887 ENTRY(ihandler, TAG_NO_FRAME_USED)
890 * get the value of istackptr, if it's zero then we're already on the
891 * interrupt stack, otherwise it points to a saved_state structure
892 * at the top of the interrupt stack.
895 lwz r10,savesrr1(r4) /* Get SRR1 */
896 mfsprg r25,0 /* Get the per_proc block */
897 li r14,0 /* Zero this for now */
898 rlwinm. r13,r10,0,MSR_VEC_BIT,MSR_VEC_BIT ; Was vector on?
899 lwz r16,PP_CPU_DATA(r25) /* Assume we need this */
900 crmove cr1_eq,cr0_eq ; Remember vector enablement
901 lwz r1,PP_ISTACKPTR(r25) /* Get the interrupt stack */
902 rlwinm. r10,r10,0,MSR_FP_BIT,MSR_FP_BIT ; Was floating point on?
903 li r13,0 /* Zero this for now */
904 lwz r16,CPU_ACTIVE_THREAD(r16) /* Get the thread pointer */
906 beq+ cr1,ivecoff ; Vector off, do not save vrsave...
907 lwz r7,savevrsave(r4) ; Get the VRSAVE register
908 stw r7,liveVRS(r25) ; Set the live value
910 ivecoff: li r0,0 /* Get a constant 0 */
911 cmplwi cr1,r16,0 /* Are we still booting? */
912 beq+ ifpoff ; Skip if floating point is off...
913 lwz r9,savexfpscr(r4) ; Grab the just saved FPSCR
914 stw r9,liveFPSCR(r25) ; Make it the live copy
916 ifpoff: mr. r1,r1 /* Is it active? */
917 beq- cr1,ihboot1 /* We're still coming up... */
918 lwz r13,THREAD_TOP_ACT(r16) /* Pick up the active thread */
919 lwz r14,ACT_MACT_PCB(r13) /* Now point to the PCB */
921 ihboot1: lwz r9,saver1(r4) /* Pick up the 'rupt time stack */
922 stw r14,SAVprev(r4) /* Queue the new save area in the front */
923 stw r13,SAVact(r4) /* Point the savearea at its activation */
924 beq- cr1,ihboot4 /* We're still coming up... */
925 stw r4,ACT_MACT_PCB(r13) /* Point to our savearea */
927 ihboot4: bne .L_istackfree /* Nope... */
929 /* We're already on the interrupt stack, get back the old
930 * stack pointer and make room for a frame
933 subi r1,r9,FM_REDZONE /* Back up beyond the red zone */
934 b ihsetback /* Go set up the back chain... */
938 stw r0,PP_ISTACKPTR(r25) /* Mark the stack in use */
939 oris r10,r10,HIGH_ADDR(SAVrststk) /* Indicate we reset stack when we return from this one */
940 stw r10,SAVflags(r4) /* Stick it back */
943 * To summarise, when we reach here, the state has been saved and
944 * the stack is marked as busy. We now generate a small
945 * stack frame with backpointers to follow the calling
946 * conventions. We set up the backpointers to the trapped
947 * routine allowing us to backtrace.
950 ihsetback: subi r1,r1,FM_SIZE /* Make a new frame */
951 stw r9,FM_BACKPTR(r1) /* point back to previous stackptr */
954 bl versave ; (TEST/DEBUG)
958 /* If debugging, we need two frames, the first being a dummy
959 * which links back to the trapped routine. The second is
960 * that which the C routine below will need
962 lwz r5,savesrr0(r4) /* Get interrupt address */
963 stw r5,FM_LR_SAVE(r1) /* save old instr ptr as LR value */
964 stwu r1,-FM_SIZE(r1) /* Make another new frame for C routine */
967 lwz r5,savedsisr(r4) /* Get the DSISR */
968 lwz r6,savedar(r4) /* Get the DAR */
973 /* interrupt() returns a pointer to the saved state in r3
975 * Ok, back from C. Disable interrupts while we restore things
977 .globl EXT(ihandler_ret)
979 LEXT(ihandler_ret) /* Marks our return point from debugger entry */
981 mfmsr r0 /* Get our MSR */
982 rlwinm r0,r0,0,MSR_EE_BIT+1,MSR_EE_BIT-1 /* Flip off the interrupt enabled bit */
983 mtmsr r0 /* Make sure interrupts are disabled */
984 mfsprg r10,0 /* Get the per_proc block */
986 lwz r8,PP_CPU_DATA(r10) /* Get the CPU data area */
987 lwz r7,SAVflags(r3) /* Pick up the flags */
988 lwz r8,CPU_ACTIVE_THREAD(r8) /* and the active thread */
989 lwz r9,SAVprev(r3) /* Get previous save area */
990 cmplwi cr1,r8,0 /* Are we still initializing? */
991 lwz r12,savesrr1(r3) /* Get the MSR we will load on return */
992 beq- cr1,ihboot2 /* Skip if we are still in init... */
993 lwz r8,THREAD_TOP_ACT(r8) /* Pick up the active thread */
995 ihboot2: andis. r11,r7,HIGH_ADDR(SAVrststk) /* Is this the first on the stack? */
996 beq- cr1,ihboot3 /* Skip if we are still in init... */
997 stw r9,ACT_MACT_PCB(r8) /* Point to previous context savearea */
999 ihboot3: mr r4,r3 /* Move the savearea pointer */
1000 beq .L_no_int_ast2 /* Get going if not the top o' stack... */
1003 /* We're the last frame on the stack. Restore istackptr to empty state.
1005 * Check for ASTs if one of the below is true:
1006 * returning to user mode
1007 * returning to a kloaded server
1009 lwz r9,PP_INTSTACK_TOP_SS(r10) /* Get the empty stack value */
1010 lwz r5,PP_CPU_DATA(r10) /* Get cpu_data ptr */
1011 andc r7,r7,r11 /* Remove the stack reset bit in case we pass this one */
1012 stw r9,PP_ISTACKPTR(r10) /* Save that saved state ptr */
1013 lwz r3,CPU_PREEMPTION_LEVEL(r5) /* Get preemption level */
1014 stw r7,SAVflags(r4) /* Save the flags */
1015 cmplwi r3, 0 /* Check for preemption */
1016 bne .L_no_int_ast /* Don't preempt if level is not zero */
1017 andi. r6,r12,MASK(MSR_PR) /* privilege mode */
1018 lwz r11,PP_NEED_AST(r10) /* Get the AST request address */
1019 lwz r11,0(r11) /* Get the request */
1020 beq- .L_kernel_int_ast /* In kernel space, AST_URGENT check */
1021 li r3,T_AST /* Assume the worst */
1022 mr. r11,r11 /* Are there any pending? */
1023 beq .L_no_int_ast /* Nope... */
1027 andi. r11,r11,AST_URGENT /* AST_URGENT */
1028 li r3,T_PREEMPT /* Assume the worst */
1029 beq .L_no_int_ast /* Nope... */
1034 * There is a pending AST. Massage things to make it look like
1035 * we took a trap and jump into the trap handler. To do this
1036 * we essentially pretend to return from the interrupt but
1037 * at the last minute jump into the trap handler with an AST
1038 * trap instead of performing an rfi.
1041 stw r3,saveexception(r4) /* Set the exception code to T_AST/T_PREEMPT */
1042 b EXT(thandler) /* hyperspace into AST trap */
1045 mr r3,r4 ; Get into the right register for common code
1047 rlwinm r7,r7,0,15,13 /* Clear the syscall bit */
1048 li r4,0 ; Assume for a moment that we are in init
1049 stw r7,SAVflags(r3) /* Set the flags */
1050 beq- cr1,chkfac ; Jump away if we are in init...
1051 lwz r4,ACT_MACT_PCB(r8) ; Get the new level marker
1055 ; This section is common to all exception exits. It throws away vector
1056 ; and floating point saveareas as the exception level of a thread is
1059 ; It also enables the facility if its context is live
1061 ; R3 = Savearea to be released (virtual)
1062 ; R4 = New top of savearea stack (could be 0)
1063 ; R8 = pointer to activation
1064 ; R10 = per_proc block
1066 chkfac: mr. r8,r8 ; Are we still in boot?
1067 beq- chkenax ; Yeah, skip it all...
1069 lwz r20,ACT_MACT_FPUlvl(r8) ; Get the FPU level
1070 lwz r12,savesrr1(r3) ; Get the current MSR
1071 cmplw r20,r3 ; Are we returning from the active level?
1072 lwz r23,PP_FPU_THREAD(r10) ; Get floating point owner
1073 rlwinm r12,r12,0,MSR_FP_BIT+1,MSR_FP_BIT-1 ; Turn off floating point for now
1074 cmplw cr1,r23,r8 ; Are we the facility owner?
1075 lhz r26,PP_CPU_NUMBER(r10) ; Get the current CPU number
1076 beq- chkfpfree ; Leaving active level, can not possibly enable...
1077 bne- cr1,chkvec ; Not our facility, nothing to do here...
1080 lis r0,HIGH_ADDR(CutTrace) ; (TEST/DEBUG)
1081 li r2,0x3301 ; (TEST/DEBUG)
1082 oris r0,r0,LOW_ADDR(CutTrace) ; (TEST/DEBUG)
1086 lwz r24,ACT_MACT_FPUcpu(r8) ; Get the CPU this context was enabled on last
1087 cmplw r4,r20 ; Are we going to be in the right level?
1088 cmplw cr1,r24,r26 ; Are we on the right CPU?
1089 li r0,0 ; Get a constant 0
1090 beq+ cr1,chkfpnlvl ; Right CPU...
1092 stw r0,PP_FPU_THREAD(r10) ; Show facility unowned so we do not get back here
1093 b chkvec ; Go check out the vector facility...
1095 chkfpnlvl: bne- chkvec ; Different level, can not enable...
1096 lwz r24,ACT_MACT_FPU(r8) ; Get the floating point save area
1097 ori r12,r12,lo16(MASK(MSR_FP)) ; Enable facility
1098 mr. r24,r24 ; Does the savearea exist?
1099 li r0,1 ; Get set to invalidate
1100 beq- chkvec ; Nothing to invalidate...
1101 lwz r25,SAVlvlfp(r24) ; Get the level of top savearea
1102 cmplw r4,r25 ; Is the top one ours?
1103 bne+ chkvec ; Not ours...
1104 stw r0,SAVlvlfp(r24) ; Invalidate the first one
1107 mfmsr r0 ; (TEST/DEBUG)
1108 ori r0,r0,0x2000 ; (TEST/DEBUG)
1109 mtmsr r0 ; (TEST/DEBUG)
1110 isync ; (TEST/DEBUG)
1112 stfd f0,savevr0(r3) ; (TEST/DEBUG)
1113 stfd f1,savevr0+8(r3) ; (TEST/DEBUG)
1114 stfd f2,savevr0+0x10(r3) ; (TEST/DEBUG)
1115 stfd f3,savevr0+0x18(r3) ; (TEST/DEBUG)
1116 stfd f4,savevr0+0x20(r3) ; (TEST/DEBUG)
1117 stfd f5,savevr0+0x28(r3) ; (TEST/DEBUG)
1118 stfd f6,savevr0+0x30(r3) ; (TEST/DEBUG)
1119 stfd f7,savevr0+0x38(r3) ; (TEST/DEBUG)
1120 stfd f8,savevr0+0x40(r3) ; (TEST/DEBUG)
1121 stfd f9,savevr0+0x48(r3) ; (TEST/DEBUG)
1122 stfd f10,savevr0+0x50(r3) ; (TEST/DEBUG)
1123 stfd f11,savevr0+0x58(r3) ; (TEST/DEBUG)
1124 stfd f12,savevr0+0x60(r3) ; (TEST/DEBUG)
1125 stfd f13,savevr0+0x68(r3) ; (TEST/DEBUG)
1126 stfd f14,savevr0+0x70(r3) ; (TEST/DEBUG)
1127 stfd f15,savevr0+0x78(r3) ; (TEST/DEBUG)
1128 stfd f16,savevr0+0x80(r3) ; (TEST/DEBUG)
1129 stfd f17,savevr0+0x88(r3 ; (TEST/DEBUG)
1130 stfd f18,savevr0+0x90(r3) ; (TEST/DEBUG)
1131 stfd f19,savevr0+0x98(r3) ; (TEST/DEBUG)
1132 stfd f20,savevr0+0xA0(r3) ; (TEST/DEBUG)
1133 stfd f21,savevr0+0xA8(r3) ; (TEST/DEBUG)
1134 stfd f22,savevr0+0xB0(r3) ; (TEST/DEBUG)
1135 stfd f23,savevr0+0xB8(r3) ; (TEST/DEBUG)
1136 stfd f24,savevr0+0xC0(r3) ; (TEST/DEBUG)
1137 stfd f25,savevr0+0xC8(r3) ; (TEST/DEBUG)
1138 stfd f26,savevr0+0xD0(r3) ; (TEST/DEBUG)
1139 stfd f27,savevr0+0xD8(r3) ; (TEST/DEBUG)
1140 stfd f28,savevr0+0xE0(r3) ; (TEST/DEBUG)
1141 stfd f29,savevr0+0xE8(r3) ; (TEST/DEBUG)
1142 stfd f30,savevr0+0xF0(r3) ; (TEST/DEBUG)
1143 stfd f31,savevr0+0xF8(r3) ; (TEST/DEBUG)
1145 li r2,64 ; (TEST/DEBUG)
1146 la r20,savevr0(r3) ; (TEST/DEBUG)
1147 la r21,savefp0(r24) ; (TEST/DEBUG)
1150 lwz r22,0(r20) ; (TEST/DEBUG)
1151 subic. r2,r2,1 ; (TEST/DEBUG)
1152 lwz r23,0(r21) ; (TEST/DEBUG)
1153 addi r20,r20,4 ; (TEST/DEBUG)
1154 cmplw cr1,r22,r23 ; (TEST/DEBUG)
1155 addi r21,r21,4 ; (TEST/DEBUG)
1156 bne- cr1,diekilldead2 ; (TEST/DEBUG)
1157 bne+ ckmurderdeath2 ; (TEST/DEBUG)
1158 b dontdiekilldead2 ; (TEST/DEBUG)
1160 diekilldead2: ; (TEST/DEBUG)
1161 mr r4,r24 ; (TEST/DEBUG)
1162 BREAKPOINT_TRAP ; (TEST/DEBUG)
1165 lfd f0,savevr0(r3) ; (TEST/DEBUG)
1166 lfd f1,savevr0+8(r3) ; (TEST/DEBUG)
1171 b chkvec ; Go check out the vector facility...
1173 chkfpfree: li r0,0 ; Clear a register
1174 lwz r24,ACT_MACT_FPU(r8) ; Get the floating point save area
1176 bne- cr1,chkfpnfr ; Not our facility, do not clear...
1177 stw r0,PP_FPU_THREAD(r10) ; Clear floating point owner
1181 lis r0,HIGH_ADDR(CutTrace) ; (TEST/DEBUG)
1182 li r2,0x3302 ; (TEST/DEBUG)
1183 oris r0,r0,LOW_ADDR(CutTrace) ; (TEST/DEBUG)
1187 mr. r24,r24 ; Do we even have a savearea?
1188 beq+ chkvec ; Nope...
1191 rlwinm. r0,r24,0,0,15 ; (TEST/DEBUG)
1192 bne+ notbadxxx1 ; (TEST/DEBUG)
1193 BREAKPOINT_TRAP ; (TEST/DEBUG)
1194 notbadxxx1: ; (TEST/DEBUG)
1195 lis r0,HIGH_ADDR(CutTrace) ; (TEST/DEBUG)
1196 li r2,0x3303 ; (TEST/DEBUG)
1197 oris r0,r0,LOW_ADDR(CutTrace) ; (TEST/DEBUG)
1201 lwz r25,SAVlvlfp(r24) ; Get the level of top savearea
1202 cmplwi r25,1 ; Is the top area invalid?
1203 cmplw cr1,r25,r3 ; Is it for the returned from context?
1204 beq fptoss ; It is invalid...
1205 bne cr1,chkvec ; Not for the returned context...
1207 fptoss: lwz r25,SAVprefp(r24) ; Get previous savearea
1209 lis r0,HIGH_ADDR(CutTrace) ; (TEST/DEBUG)
1210 li r2,0x3304 ; (TEST/DEBUG)
1211 oris r0,r0,LOW_ADDR(CutTrace) ; (TEST/DEBUG)
1212 mr r5,r25 ; (TEST/DEBUG)
1215 mr. r25,r25 ; Is there one?
1216 stw r25,ACT_MACT_FPU(r8) ; Set the new pointer
1217 beq fptoplvl ; Nope, we are at the top...
1219 rlwinm. r0,r25,0,0,15 ; (TEST/DEBUG)
1220 bne+ notbadxxx2 ; (TEST/DEBUG)
1221 BREAKPOINT_TRAP ; (TEST/DEBUG)
1222 notbadxxx2: ; (TEST/DEBUG)
1224 lwz r25,SAVlvlfp(r25) ; Get the new level
1226 fptoplvl: lwz r19,SAVflags(r24) ; Get the savearea flags
1228 rlwinm. r0,r19,0,1,1 ; (TEST/DEBUG)
1229 bne+ donotdie3 ; (TEST/DEBUG)
1230 BREAKPOINT_TRAP ; (TEST/DEBUG)
1231 donotdie3: ; (TEST/DEBUG)
1235 lis r0,HIGH_ADDR(CutTrace) ; (TEST/DEBUG)
1236 li r2,0x3305 ; (TEST/DEBUG)
1237 oris r0,r0,LOW_ADDR(CutTrace) ; (TEST/DEBUG)
1240 rlwinm r22,r24,0,0,19 ; Round down to the base savearea block
1241 rlwinm r19,r19,0,2,0 ; Remove the floating point in use flag
1242 stw r25,ACT_MACT_FPUlvl(r8) ; Set the new top level
1243 andis. r0,r19,hi16(SAVinuse) ; Still in use?
1244 stw r19,SAVflags(r24) ; Set the savearea flags
1245 bne- chkvec ; Yes, go check out vector...
1247 lis r0,HIGH_ADDR(CutTrace) ; (TEST/DEBUG)
1248 li r2,0x3306 ; (TEST/DEBUG)
1249 oris r0,r0,LOW_ADDR(CutTrace) ; (TEST/DEBUG)
1253 rlwinm. r0,r24,0,0,15 ; (TEST/DEBUG)
1254 bne+ notbadxxx3 ; (TEST/DEBUG)
1255 BREAKPOINT_TRAP ; (TEST/DEBUG)
1256 notbadxxx3: ; (TEST/DEBUG)
1258 lwz r23,SACvrswap(r22) ; Get the conversion from virtual to real
1259 lwz r20,PP_QUICKFRET(r10) ; Get the old quick fret head
1260 xor r23,r24,r23 ; Convert to physical
1261 stw r20,SAVqfret(r24) ; Back chain the quick release queue
1262 stw r23,PP_QUICKFRET(r10) ; Anchor it
1265 ; Check out vector stuff (and translate savearea to physical for exit)
1268 lwz r20,ACT_MACT_VMXlvl(r8) ; Get the vector level
1269 lwz r23,PP_VMX_THREAD(r10) ; Get vector owner
1270 cmplw r20,r3 ; Are we returning from the active level?
1271 rlwinm r12,r12,0,MSR_VEC_BIT+1,MSR_VEC_BIT-1 ; Turn off vector for now
1272 cmplw cr1,r23,r8 ; Are we the facility owner?
1273 beq- chkvecfree ; Leaving active level, can not possibly enable...
1274 bne- cr1,setena ; Not our facility, nothing to do here...
1277 lis r0,HIGH_ADDR(CutTrace) ; (TEST/DEBUG)
1278 li r2,0x3401 ; (TEST/DEBUG)
1279 oris r0,r0,LOW_ADDR(CutTrace) ; (TEST/DEBUG)
1283 lwz r24,ACT_MACT_VMXcpu(r8) ; Get the CPU this context was enabled on last
1284 cmplw r4,r20 ; Are we going to be in the right level?
1285 cmplw cr1,r24,r26 ; Are we on the right CPU?
1286 li r0,0 ; Get a constant 0
1287 beq+ cr1,chkvecnlvl ; Right CPU...
1289 stw r0,PP_VMX_THREAD(r10) ; Show facility unowned so we do not get back here
1290 b setena ; Go actually exit...
1292 chkvecnlvl: bne- setena ; Different level, can not enable...
1293 lwz r24,ACT_MACT_VMX(r8) ; Get the vector save area
1294 oris r12,r12,hi16(MASK(MSR_VEC)) ; Enable facility
1295 mr. r24,r24 ; Does the savearea exist?
1296 li r0,1 ; Get set to invalidate
1297 beq- setena ; Nothing to invalidate...
1298 lwz r25,SAVlvlvec(r24) ; Get the level of top savearea
1299 cmplw r4,r25 ; Is the top one ours?
1300 bne+ setena ; Not ours...
1301 stw r0,SAVlvlvec(r24) ; Invalidate the first one
1302 b setena ; Actually exit...
1304 chkvecfree: li r0,0 ; Clear a register
1305 lwz r24,ACT_MACT_VMX(r8) ; Get the vector save area
1306 bne- cr1,chkvecnfr ; Not our facility, do not clear...
1307 stw r0,PP_VMX_THREAD(r10) ; Clear vector owner
1311 lis r0,HIGH_ADDR(CutTrace) ; (TEST/DEBUG)
1312 li r2,0x3402 ; (TEST/DEBUG)
1313 oris r0,r0,LOW_ADDR(CutTrace) ; (TEST/DEBUG)
1317 mr. r24,r24 ; Do we even have a savearea?
1318 beq+ setena ; Nope...
1321 lis r0,HIGH_ADDR(CutTrace) ; (TEST/DEBUG)
1322 li r2,0x3403 ; (TEST/DEBUG)
1323 oris r0,r0,LOW_ADDR(CutTrace) ; (TEST/DEBUG)
1326 lwz r25,SAVlvlvec(r24) ; Get the level
1327 cmplwi r25,1 ; Is the top area invalid?
1328 cmplw cr1,r25,r3 ; Is it for the returned from context?
1329 beq vectoss ; It is invalid...
1330 bne cr1,setena ; Not for the returned context...
1332 vectoss: lwz r25,SAVprevec(r24) ; Get previous savearea
1334 lis r0,HIGH_ADDR(CutTrace) ; (TEST/DEBUG)
1335 li r2,0x3504 ; (TEST/DEBUG)
1336 oris r0,r0,LOW_ADDR(CutTrace) ; (TEST/DEBUG)
1337 mr r5,r25 ; (TEST/DEBUG)
1340 mr. r25,r25 ; Is there one?
1341 stw r25,ACT_MACT_VMX(r8) ; Set the new pointer
1342 beq vectoplvl ; Nope, we are at the top...
1343 lwz r25,SAVlvlvec(r25) ; Get the new level
1345 vectoplvl: lwz r19,SAVflags(r24) ; Get the savearea flags
1348 lis r0,HIGH_ADDR(CutTrace) ; (TEST/DEBUG)
1349 li r2,0x3405 ; (TEST/DEBUG)
1350 oris r0,r0,LOW_ADDR(CutTrace) ; (TEST/DEBUG)
1353 rlwinm r22,r24,0,0,19 ; Round down to the base savearea block
1354 rlwinm r19,r19,0,3,1 ; Remove the vector in use flag
1355 stw r25,ACT_MACT_VMXlvl(r8) ; Set the new top level
1356 andis. r0,r19,hi16(SAVinuse) ; Still in use?
1357 stw r19,SAVflags(r24) ; Set the savearea flags
1358 bne- setena ; Yes, all done...
1360 lis r0,HIGH_ADDR(CutTrace) ; (TEST/DEBUG)
1361 li r2,0x3406 ; (TEST/DEBUG)
1362 oris r0,r0,LOW_ADDR(CutTrace) ; (TEST/DEBUG)
1365 lwz r23,SACvrswap(r22) ; Get the conversion from virtual to real
1366 lwz r20,PP_QUICKFRET(r10) ; Get the old quick fret head
1367 xor r23,r24,r23 ; Convert to physical
1368 stw r20,SAVqfret(r24) ; Back chain the quick release queue
1369 stw r23,PP_QUICKFRET(r10) ; Anchor it
1371 setena: rlwinm r20,r12,(((31-vectorCngbit)+(MSR_VEC_BIT+1))&31),vectorCngbit,vectorCngbit ; Set flag if we enabled vector
1372 rlwimi. r20,r12,(((31-floatCngbit)+(MSR_FP_BIT+1))&31),floatCngbit,floatCngbit ; Set flag if we enabled floats
1373 beq setenaa ; Neither float nor vector turned on....
1375 lwz r5,ACT_MACT_SPF(r8) ; Get activation copy
1376 lwz r6,spcFlags(r10) ; Get per_proc copy
1377 or r5,r5,r20 ; Set vector/float changed bits in activation
1378 or r6,r6,r20 ; Set vector/float changed bits in per_proc
1379 stw r5,ACT_MACT_SPF(r8) ; Set activation copy
1380 stw r6,spcFlags(r10) ; Set per_proc copy
1382 setenaa: stw r12,savesrr1(r3) ; Turn facility on or off
1384 mfdec r24 ; Get decrementer
1385 lwz r22,qactTimer(r8) ; Get high order quick activation timer
1386 mr. r24,r24 ; See if it has popped already...
1387 lwz r23,qactTimer+4(r8) ; Get low order qact timer
1388 ble- chkenax ; We have popped or are just about to...
1390 segtb: mftbu r20 ; Get the upper time base
1391 mftb r21 ; Get the low
1392 mftbu r19 ; Get upper again
1393 or. r0,r22,r23 ; Any time set?
1394 cmplw cr1,r20,r19 ; Did they change?
1395 beq+ chkenax ; No time set....
1396 bne- cr1,segtb ; Timebase ticked, get them again...
1398 subfc r6,r21,r23 ; Subtract current from qact time
1400 subfe r5,r20,r22 ; Finish subtract
1401 subfze r0,r0 ; Get a 0 if qact was bigger than current, -1 otherwise
1402 andc. r12,r5,r0 ; Set 0 if qact has passed
1403 andc r13,r6,r0 ; Set 0 if qact has passed
1404 bne chkenax ; If high order is non-zero, this is too big for a decrementer
1405 cmplw r13,r24 ; Is this earlier than the decrementer? (logical compare takes care of high bit on)
1406 bge+ chkenax ; No, do not reset decrementer...
1408 mtdec r13 ; Set our value
1410 chkenax: lwz r6,SAVflags(r3) ; Pick up the flags of the old savearea
1414 lwz r20,SAVact(r3) ; (TEST/DEBUG) Make sure our restore
1415 lwz r21,PP_CPU_DATA(r10) ; (TEST/DEBUG) context is associated
1416 lwz r21,CPU_ACTIVE_THREAD(r21) ; (TEST/DEBUG) with the current act.
1417 cmpwi r21,0 ; (TEST/DEBUG)
1418 beq- yeswereok ; (TEST/DEBUG)
1419 lwz r21,THREAD_TOP_ACT(r21) ; (TEST/DEBUG)
1420 cmplw r21,r20 ; (TEST/DEBUG)
1421 beq+ yeswereok ; (TEST/DEBUG)
1422 BREAKPOINT_TRAP ; (TEST/DEBUG)
1427 rlwinm r5,r3,0,0,19 ; Round savearea down to page bndry
1428 rlwinm r6,r6,0,1,31 ; Mark savearea free
1429 lwz r5,SACvrswap(r5) ; Get the conversion from virtual to real
1430 stw r6,SAVflags(r3) ; Set savearea flags
1431 xor r3,r3,r5 ; Flip to physical address
1432 b EXT(exception_exit) ; We are all done now...
1437 * Here's where we handle the fastpath stuff
1438 * We'll do what we can here because registers are already
1439 * loaded and it will be less confusing that moving them around.
1440 * If we need to though, we'll branch off somewhere's else.
1442 * Registers when we get here:
1444 * r0 = syscall number
1447 * r14 = previous savearea (if any)
1452 fastpath: cmplwi cr3,r0,0x7FF1 ; Is it CthreadSetSelfNumber?
1453 bnelr- cr3 ; Not a fast path...
1456 * void cthread_set_self(cproc_t p)
1458 * set's thread state "user_value"
1460 * This op is invoked as follows:
1461 * li r0, CthreadSetSelfNumber // load the fast-trap number
1462 * sc // invoke fast-trap
1467 CthreadSetSelfNumber:
1469 lwz r5,saver3(r4) /* Retrieve the self number */
1470 stw r5,CTHREAD_SELF(r13) /* Remember it */
1471 stw r5,UAW(r25) /* Prime the per_proc_info with it */
1474 .globl EXT(fastexit)
1476 lwz r8,SAVflags(r4) /* Pick up the flags */
1477 rlwinm r9,r4,0,0,19 /* Round down to the base savearea block */
1478 rlwinm r8,r8,0,1,31 /* Clear the attached bit */
1479 lwz r9,SACvrswap(r9) /* Get the conversion from virtual to real */
1480 stw r8,SAVflags(r4) /* Set the flags */
1481 xor r3,r4,r9 /* Switch savearea to physical addressing */
1482 b EXT(exception_exit) /* Go back to the caller... */
1486 * Here's where we check for a hit on the Blue Box Assist
1487 * Most registers are non-volatile, so be careful here. If we don't
1488 * recognize the trap instruction we go back for regular processing.
1489 * Otherwise we transfer to the assist code.
1493 lwz r23,saveexception(r4) /* Get the exception code */
1494 cmpi cr0, r23, T_AST /* Check for T_AST trap */
1495 beqlr- /* Go handle it */
1497 lwz r23,savesrr1(r4) /* Get the interrupted MSR */
1498 lwz r24,ACT_MACT_BTS(r13) /* Get the table start */
1499 rlwinm. r27,r23,0,MSR_PR_BIT,MSR_PR_BIT ; Are we in userland?
1500 rlwinm r23,r23,0,SRR1_PRG_TRAP_BIT,SRR1_PRG_TRAP_BIT ; See if this was actually a trap instruction
1501 beqlr- /* No assist in kernel mode... */
1502 mr. r23,r23 ; Check for trap
1503 lwz r27,savesrr0(r4) /* Get trapped address */
1504 beqlr- ; No assist if not trap instruction...
1506 checkassistBP: /* Safe place to breakpoint */
1508 sub r24,r27,r24 /* See how far into it we are */
1509 cmplwi r24,BB_MAX_TRAP /* Do we fit in the list? */
1510 bgtlr- /* Nope, it's a regular trap... */
1511 b EXT(atomic_switch_trap) /* Go to the assist... */
1514 ; Virtual Machine Monitor
1515 ; Here is where we exit from the emulated context
1516 ; Note that most registers get trashed here
1517 ; R3 and R30 are preserved across the call and hold the activation
1518 ; and savearea respectivily.
1521 exitFromVM: mr r30,r4 ; Get the savearea
1522 mr r3,r13 ; Get the activation
1524 b EXT(vmm_exit) ; Do it to it
1527 .globl EXT(retFromVM)
1530 mfsprg r10,0 ; Restore the per_proc info
1531 mr r8,r3 ; Get the activation
1532 lwz r4,SAVprev(r30) ; Pick up the previous savearea
1533 mr r3,r30 ; Put savearea in proper register for common code
1534 lwz r11,SAVflags(r30) ; Get the flags of the current savearea
1535 rlwinm r11,r11,0,15,13 ; Clear the syscall flag
1536 lwz r1,ACT_THREAD(r8) ; and the active thread
1537 stw r11,SAVflags(r3) ; Save back the flags (with reset stack cleared)
1539 stw r4,ACT_MACT_PCB(r8) ; Point to the previous savearea (or 0 if none)
1541 lwz r5,THREAD_KERNEL_STACK(r1) ; Get the base pointer to the stack
1542 addi r5,r5,KERNEL_STACK_SIZE-FM_SIZE ; Reset to empty
1543 stw r5,ACT_MACT_KSP(r8) ; Save the empty stack pointer
1544 b chkfac ; Go end it all...
1549 * Here's where we jump into the debugger. This is called from
1550 * either an MP signal from another processor, or a command-power NMI
1551 * on the main processor.
1553 * Note that somewhere in our stack should be a return into the interrupt
1554 * handler. If there isn't, we'll crash off the end of the stack, actually,
1555 * it'll just quietly return. hahahahaha.
1558 ENTRY(kdb_kintr, TAG_NO_FRAME_USED)
1560 lis r9,HIGH_ADDR(EXT(ihandler_ret)) /* Top part of interrupt return */
1561 lis r10,HIGH_ADDR(EXT(intercept_ret)) /* Top part of intercept return */
1562 ori r9,r9,LOW_ADDR(EXT(ihandler_ret)) /* Bottom part of interrupt return */
1563 ori r10,r10,LOW_ADDR(EXT(intercept_ret)) /* Bottom part of intercept return */
1565 lwz r8,0(r1) /* Get our caller's stack frame */
1567 srchrets: mr. r8,r8 /* Have we reached the end of our rope? */
1568 beqlr- /* Yeah, just bail... */
1569 lwz r7,FM_LR_SAVE(r8) /* The whoever called them */
1570 cmplw cr0,r9,r7 /* Was it the interrupt handler? */
1571 beq srchfnd /* Yeah... */
1572 lwz r8,0(r8) /* Chain back to the previous frame */
1573 b srchrets /* Ok, check again... */
1575 srchfnd: stw r10,FM_LR_SAVE(r8) /* Modify return to come to us instead */
1576 blr /* Finish up and get back here... */
1579 * We come here when we've returned all the way to the interrupt handler.
1580 * That way we can enter the debugger with the registers and stack which
1581 * existed at the point of interruption.
1583 * R3 points to the saved state at entry
1586 ENTRY(intercept_ret, TAG_NO_FRAME_USED)
1588 lis r6,HIGH_ADDR(EXT(kdb_trap)) /* Get the top part of the KDB enter routine */
1589 mr r5,r3 /* Move saved state to the correct parameter */
1590 ori r6,r6,LOW_ADDR(EXT(kdb_trap)) /* Get the last part of the KDB enter routine */
1591 li r4,0 /* Set a code of 0 */
1592 mr r13,r3 /* Save the saved state pointer in a non-volatile */
1593 mtlr r6 /* Set the routine address */
1594 li r3,-1 /* Show we had an interrupt type */
1596 blrl /* Go enter KDB */
1598 mr r3,r13 /* Put the saved state where expected */
1599 b EXT(ihandler_ret) /* Go return from the interruption... */
1605 ; Savearea chain verification
1612 ; Make sure that only the top FPU savearea is marked invalid
1615 lis r28,hi16(EXT(default_pset)) ; (TEST/DEBUG)
1616 lis r27,hi16(EXT(DebugWork)) ; (TEST/DEBUG)
1617 ori r28,r28,lo16(EXT(default_pset)) ; (TEST/DEBUG)
1618 ori r27,r27,lo16(EXT(DebugWork)) ; (TEST/DEBUG)
1619 li r20,0 ; (TEST/DEBUG)
1620 lwz r26,0(r27) ; (TEST/DEBUG)
1621 lwz r27,psthreadcnt(r28) ; (TEST/DEBUG)
1622 mr. r26,r26 ; (TEST/DEBUG)
1623 lwz r28,psthreads(r28) ; (TEST/DEBUG)
1624 bnelr- ; (TEST/DEBUG)
1626 fcknxtth: mr. r27,r27 ; (TEST/DEBUG)
1627 beqlr- ; (TEST/DEBUG)
1629 lwz r26,THREAD_TOP_ACT(r28) ; (TEST/DEBUG)
1631 fckact: mr. r26,r26 ; (TEST/DEBUG)
1632 bne+ fckact2 ; (TEST/DEBUG)
1634 lwz r28,THREAD_PSTHRN(r28) ; (TEST/DEBUG) Next in line
1635 subi r27,r27,1 ; (TEST/DEBUG)
1636 b fcknxtth ; (TEST/DEBUG)
1638 fckact2: lwz r20,ACT_MACT_FPU(r26) ; (TEST/DEBUG) Get FPU chain
1639 mr. r20,r20 ; (TEST/DEBUG) Are there any?
1640 beq+ fcknact ; (TEST/DEBUG) No...
1642 fckact3: lwz r20,SAVprefp(r20) ; (TEST/DEBUG) Get next in list
1643 mr. r20,r20 ; (TEST/DEBUG) Check next savearea
1644 beq+ fcknact ; (TEST/DEBUG) No...
1646 lwz r29,SAVlvlfp(r20) ; (TEST/DEBUG) Get the level
1648 cmplwi r29,1 ; (TEST/DEBUG) Is it invalid??
1649 bne+ fckact3 ; (TEST/DEBUG) Nope...
1651 lis r27,hi16(EXT(DebugWork)) ; (TEST/DEBUG)
1652 ori r27,r27,lo16(EXT(DebugWork)) ; (TEST/DEBUG)
1653 stw r27,0(r27) ; (TEST/DEBUG)
1654 BREAKPOINT_TRAP ; (TEST/DEBUG)
1656 fcknact: lwz r26,ACT_LOWER(r26) ; (TEST/DEBUG) Next activation
1657 b fckact ; (TEST/DEBUG)
1662 ; Make sure there are no circular links in the float chain
1663 ; And that FP is marked busy in it.
1664 ; And the only the top is marked invalid.
1665 ; And that the owning PCB is correct.
1668 lis r28,hi16(EXT(default_pset)) ; (TEST/DEBUG)
1669 lis r27,hi16(EXT(DebugWork)) ; (TEST/DEBUG)
1670 ori r28,r28,lo16(EXT(default_pset)) ; (TEST/DEBUG)
1671 ori r27,r27,lo16(EXT(DebugWork)) ; (TEST/DEBUG)
1672 li r20,0 ; (TEST/DEBUG)
1673 lwz r26,0(r27) ; (TEST/DEBUG)
1674 lwz r27,psthreadcnt(r28) ; (TEST/DEBUG)
1675 mr. r26,r26 ; (TEST/DEBUG)
1676 lwz r28,psthreads(r28) ; (TEST/DEBUG)
1677 bnelr- ; (TEST/DEBUG)
1679 fcknxtth: mr. r27,r27 ; (TEST/DEBUG)
1680 beqlr- ; (TEST/DEBUG)
1682 lwz r26,THREAD_TOP_ACT(r28) ; (TEST/DEBUG)
1684 fckact: mr. r26,r26 ; (TEST/DEBUG)
1685 bne+ fckact2 ; (TEST/DEBUG)
1687 lwz r28,THREAD_PSTHRN(r28) ; (TEST/DEBUG) Next in line
1688 subi r27,r27,1 ; (TEST/DEBUG)
1689 b fcknxtth ; (TEST/DEBUG)
1691 fckact2: lwz r20,ACT_MACT_FPU(r26) ; (TEST/DEBUG) Get FPU chain
1692 li r29,1 ; (TEST/DEBUG)
1693 li r22,0 ; (TEST/DEBUG)
1695 fckact3: mr. r20,r20 ; (TEST/DEBUG) Are there any?
1696 beq+ fckact5 ; (TEST/DEBUG) No...
1698 addi r22,r22,1 ; (TEST/DEBUG) Count chain depth
1700 lwz r21,SAVflags(r20) ; (TEST/DEBUG) Get the flags
1701 rlwinm. r21,r21,0,1,1 ; (TEST/DEBUG) FP busy?
1702 bne+ fckact3a ; (TEST/DEBUG) Yeah...
1703 lis r27,hi16(EXT(DebugWork)) ; (TEST/DEBUG)
1704 ori r27,r27,lo16(EXT(DebugWork)) ; (TEST/DEBUG)
1705 stw r27,0(r27) ; (TEST/DEBUG)
1706 BREAKPOINT_TRAP ; (TEST/DEBUG) Die
1708 fckact3a: cmplwi r22,1 ; (TEST/DEBUG) At first SA?
1709 beq+ fckact3b ; (TEST/DEBUG) Yeah, invalid is ok...
1710 lwz r21,SAVlvlfp(r20) ; (TEST/DEBUG) Get level
1711 cmplwi r21,1 ; (TEST/DEBUG) Is it invalid?
1712 bne+ fckact3b ; (TEST/DEBUG) Nope, it is ok...
1713 lis r27,hi16(EXT(DebugWork)) ; (TEST/DEBUG)
1714 ori r27,r27,lo16(EXT(DebugWork)) ; (TEST/DEBUG)
1715 stw r27,0(r27) ; (TEST/DEBUG)
1716 BREAKPOINT_TRAP ; (TEST/DEBUG) Die
1718 fckact3b: lwz r21,SAVact(r20) ; (TEST/DEBUG) Get the owner
1719 cmplw r21,r26 ; (TEST/DEBUG) Correct activation?
1720 beq+ fckact3c ; (TEST/DEBUG) Yup...
1721 lis r27,hi16(EXT(DebugWork)) ; (TEST/DEBUG)
1722 ori r27,r27,lo16(EXT(DebugWork)) ; (TEST/DEBUG)
1723 stw r27,0(r27) ; (TEST/DEBUG)
1724 BREAKPOINT_TRAP ; (TEST/DEBUG) Die
1726 fckact3c: ; (TEST/DEBUG)
1727 lbz r21,SAVflags+3(r20) ; (TEST/DEBUG) Pick up the test byte
1728 mr. r21,r21 ; (TEST/DEBUG) marked?
1729 beq+ fckact4 ; (TEST/DEBUG) No, good...
1731 lis r27,hi16(EXT(DebugWork)) ; (TEST/DEBUG)
1732 ori r27,r27,lo16(EXT(DebugWork)) ; (TEST/DEBUG)
1733 stw r27,0(r27) ; (TEST/DEBUG)
1734 BREAKPOINT_TRAP ; (TEST/DEBUG)
1736 fckact4: stb r29,SAVflags+3(r20) ; (TEST/DEBUG) Set the test byte
1737 lwz r20,SAVprefp(r20) ; (TEST/DEBUG) Next in list
1738 b fckact3 ; (TEST/DEBUG) Try it...
1740 fckact5: lwz r20,ACT_MACT_FPU(r26) ; (TEST/DEBUG) Get FPU chain
1741 li r29,0 ; (TEST/DEBUG)
1743 fckact6: mr. r20,r20 ; (TEST/DEBUG) Are there any?
1744 beq+ fcknact ; (TEST/DEBUG) No...
1746 stb r29,SAVflags+3(r20) ; (TEST/DEBUG) Clear the test byte
1747 lwz r20,SAVprefp(r20) ; (TEST/DEBUG) Next in list
1748 b fckact6 ; (TEST/DEBUG) Try it...
1750 fcknact: lwz r26,ACT_LOWER(r26) ; (TEST/DEBUG) Next activation
1751 b fckact ; (TEST/DEBUG)
1757 ; Make sure in use count matches found savearea. This is
1758 ; not always accurate. There is a variable "fuzz" factor in count.
1760 lis r28,hi16(EXT(default_pset)) ; (TEST/DEBUG)
1761 lis r27,hi16(EXT(DebugWork)) ; (TEST/DEBUG)
1762 ori r28,r28,lo16(EXT(default_pset)) ; (TEST/DEBUG)
1763 ori r27,r27,lo16(EXT(DebugWork)) ; (TEST/DEBUG)
1764 li r20,0 ; (TEST/DEBUG)
1765 lwz r26,0(r27) ; (TEST/DEBUG)
1766 lwz r27,psthreadcnt(r28) ; (TEST/DEBUG)
1767 mr. r26,r26 ; (TEST/DEBUG)
1768 lwz r28,psthreads(r28) ; (TEST/DEBUG)
1769 bnelr- ; (TEST/DEBUG)
1771 cknxtth: mr. r27,r27 ; (TEST/DEBUG)
1772 beq- cktotal ; (TEST/DEBUG)
1774 lwz r26,THREAD_TOP_ACT(r28) ; (TEST/DEBUG)
1776 ckact: mr. r26,r26 ; (TEST/DEBUG)
1777 bne+ ckact2 ; (TEST/DEBUG)
1779 lwz r28,THREAD_PSTHRN(r28) ; (TEST/DEBUG) Next in line
1780 subi r27,r27,1 ; (TEST/DEBUG)
1781 b cknxtth ; (TEST/DEBUG)
1783 ckact2: lwz r29,ACT_MACT_PCB(r26) ; (TEST/DEBUG)
1785 cknorm: mr. r29,r29 ; (TEST/DEBUG)
1786 beq- cknormd ; (TEST/DEBUG)
1788 addi r20,r20,1 ; (TEST/DEBUG) Count normal savearea
1790 lwz r29,SAVprev(r29) ; (TEST/DEBUG)
1791 b cknorm ; (TEST/DEBUG)
1793 cknormd: lwz r29,ACT_MACT_FPU(r26) ; (TEST/DEBUG)
1795 ckfpu: mr. r29,r29 ; (TEST/DEBUG)
1796 beq- ckfpud ; (TEST/DEBUG)
1798 lwz r21,SAVflags(r29) ; (TEST/DEBUG)
1799 rlwinm. r21,r21,0,0,0 ; (TEST/DEBUG) See if already counted
1800 bne- cknfpu ; (TEST/DEBUG)
1802 addi r20,r20,1 ; (TEST/DEBUG) Count fpu savearea
1804 cknfpu: lwz r29,SAVprefp(r29) ; (TEST/DEBUG)
1805 b ckfpu ; (TEST/DEBUG)
1807 ckfpud: lwz r29,ACT_MACT_VMX(r26) ; (TEST/DEBUG)
1809 ckvmx: mr. r29,r29 ; (TEST/DEBUG)
1810 beq- ckvmxd ; (TEST/DEBUG)
1812 lwz r21,SAVflags(r29) ; (TEST/DEBUG)
1813 rlwinm. r21,r21,0,0,1 ; (TEST/DEBUG) See if already counted
1814 bne- cknvmx ; (TEST/DEBUG)
1816 addi r20,r20,1 ; (TEST/DEBUG) Count vector savearea
1818 cknvmx: lwz r29,SAVprevec(r29) ; (TEST/DEBUG)
1819 b ckvmx ; (TEST/DEBUG)
1821 ckvmxd: lwz r26,ACT_LOWER(r26) ; (TEST/DEBUG) Next activation
1822 b ckact ; (TEST/DEBUG)
1824 cktotal: lis r28,hi16(EXT(saveanchor)) ; (TEST/DEBUG)
1825 lis r27,hi16(EXT(real_ncpus)) ; (TEST/DEBUG)
1826 ori r28,r28,lo16(EXT(saveanchor)) ; (TEST/DEBUG)
1827 ori r27,r27,lo16(EXT(real_ncpus)) ; (TEST/DEBUG)
1829 lwz r21,SVinuse(r28) ; (TEST/DEBUG)
1830 lwz r27,0(r27) ; (TEST/DEBUG) Get the number of CPUs
1831 sub. r29,r21,r20 ; (TEST/DEBUG) Get number accounted for
1832 blt- badsave ; (TEST/DEBUG) Have too many in use...
1833 sub r26,r29,r27 ; (TEST/DEBUG) Should be 1 unaccounted for for each processor
1834 cmpwi r26,10 ; (TEST/DEBUG) Allow a 10 area slop factor
1835 bltlr+ ; (TEST/DEBUG)
1837 badsave: lis r27,hi16(EXT(DebugWork)) ; (TEST/DEBUG)
1838 ori r27,r27,lo16(EXT(DebugWork)) ; (TEST/DEBUG)
1839 stw r27,0(r27) ; (TEST/DEBUG)
1840 BREAKPOINT_TRAP ; (TEST/DEBUG)