]> git.saurik.com Git - apple/xnu.git/blob - osfmk/ppc/hw_exception.s
af24433e1d5aff63f2ede45cee39633a53a72cee
[apple/xnu.git] / osfmk / ppc / hw_exception.s
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 #if DEBUG
78
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 :-)
84 */
85
86 #define TRAP_SPACE_NEEDED FM_REDZONE+(2*FM_SIZE)+256
87
88 #endif /* DEBUG */
89
90 .text
91
92 ENTRY(thandler, TAG_NO_FRAME_USED) /* What tag should this have?! */
93
94 mfsprg r25,0 /* Get the per_proc */
95
96 lwz r1,PP_ISTACKPTR(r25) ; Get interrupt stack pointer
97
98
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 */
112
113 #if VERIFYSAVE
114 bl versave ; (TEST/DEBUG)
115 #endif
116
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 */
121
122
123 /* On kernel stack, allocate stack frame and check for overflow */
124 #if DEBUG
125 /*
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
129 */
130
131 lwz r7,THREAD_KERNEL_STACK(r6)
132 addi r7,r7,TRAP_SPACE_NEEDED
133 cmp cr0,r1,r7
134 bng- EXT(ihandler)
135 #endif /* DEBUG */
136
137 subi r1,r1,FM_REDZONE /* Back up stack and leave room for a red zone */
138
139 .L_kstackfree:
140 #if 0
141 lis r0,HIGH_ADDR(CutTrace) /* (TEST/DEBUG) */
142 oris r0,r0,LOW_ADDR(CutTrace) /* (TEST/DEBUG) */
143 sc /* (TEST/DEBUG) */
144 #endif
145 lwz r7,savesrr1(r4) /* Pick up the entry MSR */
146 li r0,0 /* Make this 0 */
147
148 beq cr1,.L_state_on_kstack /* using above test for pcb/stack */
149
150 stw r0,ACT_MACT_KSP(r13) /* Show that we have taken the stack */
151
152 .L_state_on_kstack:
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
158
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
164
165 tfpoff: stw r6,FM_BACKPTR(r1) /* Link backwards */
166
167 #if DEBUG
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
171 */
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 */
175 #endif /* DEBUG */
176
177
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)
183 */
184
185
186 lwz r3,saveexception(r4) /* Get the exception code */
187 lwz r0,ACT_MACT_SPF(r13) ; Get the special flags
188
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)
192
193 lwz r5,savedsisr(r4) /* Get the saved DSISR */
194
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)
197
198 cmpi cr2,r3,T_PREEMPT ; Is this a preemption?
199
200 crandc cr0_eq,cr7_eq,cr0_eq ; Do not intercept if we are in the kernel (cr0_eq == 1 if yes)
201
202 lwz r6,savedar(r4) /* Get the DAR */
203
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...
206
207 /* syscall exception might warp here if there's nothing left
208 * to do except generate a trap
209 */
210
211 .L_call_trap:
212 #if 0
213 lis r0,HIGH_ADDR(CutTrace) /* (TEST/DEBUG) */
214 oris r0,r0,LOW_ADDR(CutTrace) /* (TEST/DEBUG) */
215 sc /* (TEST/DEBUG) */
216 #endif
217
218 bl EXT(trap)
219
220 /*
221 * Ok, return from C function
222 *
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.
226 *
227 */
228
229 thread_return:
230
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 */
236
237 mfsprg r10,0 /* Restore the per_proc info */
238
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) */
246
247 #if 0
248 lis r0,HIGH_ADDR(CutTrace) /* (TEST/DEBUG) */
249 oris r0,r0,LOW_ADDR(CutTrace) /* (TEST/DEBUG) */
250 sc /* (TEST/DEBUG) */
251 #endif
252 stw r4,ACT_MACT_PCB(r8) /* Point to the previous savearea (or 0 if none) */
253
254 beq- chkfac ; We are not leaving the kernel yet...
255
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... */
260
261
262
263 /*
264 * shandler(type)
265 *
266 * ENTRY: VM switched ON
267 * Interrupts OFF
268 * R3 contains exception code
269 * R4 points to the saved context (virtual address)
270 * Everything is saved in savearea
271 */
272
273 /*
274 * If pcb.ksp == 0 then the kernel stack is already busy,
275 * this is an error - jump to the debugger entry
276 *
277 * otherwise depending upon the type of
278 * syscall, look it up in the kernel table
279 * or pass it to the server.
280 *
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.
283 */
284
285 /*
286 * NOTE:
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
291 */
292
293 ENTRY(shandler, TAG_NO_FRAME_USED)
294
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 */
305
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
309
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
315
316 ; Check if SCs are being redirected for the BlueBox or to VMM
317
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...
328
329 noassist:
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... */
333
334 lwz r1,ACT_MACT_KSP(r13) /* Get the kernel stack pointer */
335 #if DEBUG
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? */
339 #endif /* DEBUG */
340
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 */
345
346 #if VERIFYSAVE
347 bl versave ; (TEST/DEBUG)
348 #endif
349
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 */
354
355 #if DEBUG
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
359 */
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 */
363 #endif /* DEBUG */
364
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...
375
376 beq- ppcscall ; Call the ppc-only system call handler...
377
378 mtmsr r11 /* Enable interruptions */
379
380 /* Call a function that can print out our syscall info */
381 /* Note that we don't care about any volatiles yet */
382 mr r4,r30
383 bl EXT(syscall_trace)
384
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 */
389 cmpwi cr0,r0,0x7FFA
390 beq- .L_notify_interrupt_syscall
391
392 #ifdef MACH_BSD
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... */
402 #endif
403
404 .L_call_server_syscall_exception:
405 li r3,EXC_SYSCALL /* doexception(EXC_SYSCALL, num, 1) */
406
407 .L_call_server_exception:
408 mr r4,r0 /* Set syscall selector */
409 li r5,1
410 b EXT(doexception) /* Go away, never to return... */
411
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... */
416
417 .L_notify_interrupt_syscall:
418 lwz r3,saver3(r30) ; Get the new PC address to pass in
419 bl EXT(syscall_notify_interrupt)
420 b .L_syscall_return
421
422 ;
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.
430 ;
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.
434 ;
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
439 ;
440 ; Note: the last option is intended for special diagnostics calls that
441 ; want the thread to return and execute before checking for preemption.
442 ;
443
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
450
451 ;
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.
455 ;
456
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...
462 blrl ; Call it
463
464
465 .globl EXT(ppcscret)
466 LEXT(ppcscret)
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...
473
474
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)
481 */
482 .L_kernel_syscall:
483 neg r31, r0 /* Make number +ve and put in r31*/
484
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))
488 lwz r29, 0(r29)
489
490 cmp cr0, r31, r29
491 bge- cr0, .L_call_server_syscall_exception
492
493 addis r29, 0, HIGH_CADDR(EXT(mach_trap_table))
494 addi r29, r29, LOW_ADDR(EXT(mach_trap_table))
495
496 /* multiply the trap number to get offset into table */
497 slwi r31, r31, MACH_TRAP_OFFSET_POW2
498
499 /* r31 now holds offset into table of our trap entry,
500 * add on the table base, and it then holds pointer to entry
501 */
502 add r31, r31, r29
503
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,
506 at least. */
507 lis r29, HIGH_CADDR(EXT(kern_invalid))
508 addi r29, r29, LOW_ADDR(EXT(kern_invalid))
509 lwz r0, MACH_TRAP_FUNCTION(r31)
510 cmp cr0, r0, r29
511 beq- .L_call_server_syscall_exception
512
513 /* get arg count. If argc > 8 then not all args were in regs,
514 * so we must perform copyin.
515 */
516 lwz r29, MACH_TRAP_ARGC(r31)
517 cmpwi cr0, r29, 8
518 ble+ .L_syscall_got_args
519
520 /* argc > 8 - perform a copyin */
521 /* if the syscall came from kernel space, we can just copy */
522
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... */
526
527 /* we came from a privilaged task, just do a copy */
528 /* get user's stack pointer */
529
530 lwz r28,saver1(r30) /* Get the stack pointer */
531
532 subi r29,r29,8 /* Get the number of arguments to copy */
533
534 addi r28,r28,COPYIN_ARG0_OFFSET-4 /* Point to source - 4 */
535 addi r27,r1,FM_ARG0-4 /* Point to sink - 4 */
536
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... */
545
546
547 /* we came from a user task, pay the price of a real copyin */
548 /* set recovery point */
549
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 */
557
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.
562 */
563
564
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 */
568
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.
572 */
573
574 rlwinm r7,r28,6,26,29 ; Get index to the segment slot
575
576 .L_syscall_copyin_seg_loop:
577
578
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
582 isync
583
584 oris r26,r26,(SR_COPYIN_NUM << (28-16)) ; Insert the copyin segment number into source address
585
586 /* Make r27 point to address-4 of where we will store copied args */
587 addi r27,r1,FM_ARG0-4
588
589 .L_syscall_copyin_word_loop:
590
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...
598
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...
602
603 addi r7,r7,4 ; Bump to next slot
604 b .L_syscall_copyin_seg_loop /* On new segment! remap */
605
606 /* Don't bother restoring SR_COPYIN, we can leave it trashed */
607 /* clear thread recovery as we're done touching user data */
608
609 .L_syscall_copyin_done:
610 li r0,0
611 stw r0,THREAD_RECOVER(r16) /* R16 still holds thread ptr */
612
613 .L_syscall_got_args:
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 */
631
632 lwz r0,MACH_TRAP_FUNCTION(r31)
633
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)
637 * r31 is scrap
638 */
639 mtctr r0
640 bctrl /* perform the actual syscall */
641
642 /* 'standard' syscall returns here - INTERRUPTS ARE STILL ON */
643
644 /* r3 contains value that we're going to return to the user
645 */
646
647 /*
648 * Ok, return from C function, ARG0 = return value
649 *
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 .
652 */
653
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
660 */
661
662 /* When we are here, r16 should point to the current thread,
663 * r30 should point to the current pcb
664 */
665
666 /* save off return value, we must load it
667 * back anyway for thread_exception_return
668 * TODO NMGS put in register?
669 */
670 .L_syscall_return:
671 mr r31,r16 /* Move the current thread pointer */
672 stw r3,saver3(r30) /* Stash the return code */
673
674 /* Call a function that records the end of */
675 /* the mach system call */
676 mr r4,r30
677 bl EXT(syscall_trace_end)
678
679 #if 0
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) */
685 #endif
686
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 */
691
692 mfsprg r10,0 /* Get the per_processor block */
693
694 /* Check to see if there's an outstanding AST */
695
696 lwz r4,PP_NEED_AST(r10)
697 lwz r4,0(r4)
698 cmpi cr0,r4, 0
699 beq cr0,.L_syscall_no_ast
700
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
704 */
705
706 #if DEBUG
707 /* debug assert - make sure that we're not returning to kernel */
708 lwz r3,savesrr1(r30)
709 andi. r3,r3,MASK(MSR_PR)
710 bne+ 0f /* returning to user level, check */
711
712 BREAKPOINT_TRAP
713 0:
714 #endif /* DEBUG */
715
716 li r3, 0
717 li r4, AST_ALL
718 li r5, 1
719 bl EXT(ast_taken)
720
721 b .L_thread_syscall_ret_check_ast
722
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).
726 *
727 * In particular for us,
728 * we still have r31 points to the current thread,
729 * r30 points to the current pcb
730 */
731
732 .L_syscall_no_ast:
733 .L_thread_syscall_return:
734
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 */
737
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 */
746
747 b chkfac ; Go end it all...
748
749
750 .L_syscall_copyin_recover:
751
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
755 *
756 * call syscall_error(EXC_BAD_ACCESS, EXC_PPC_VM_PROT_READ, sp, ssp),
757 *
758 * we already had a frame so we can do this
759 */
760
761 li r3,EXC_BAD_ACCESS
762 li r4,EXC_PPC_VM_PROT_READ
763 lwz r5,saver1(r30)
764 mr r6,r30
765
766 bl EXT(syscall_error)
767 b .L_syscall_return
768
769
770 /*
771 * thread_bootstrap_return()
772 *
773 * NOTE: THIS IS GOING AWAY IN A FEW DAYS....
774 *
775 */
776
777 ENTRY(thread_bootstrap_return, TAG_NO_FRAME_USED)
778 b .L_thread_exc_ret_check_ast ; Do the same as thread_exception_return...
779
780 /*
781 * thread_exception_return()
782 *
783 * Return to user mode directly from within a system call.
784 */
785
786 ENTRY(thread_exception_return, TAG_NO_FRAME_USED)
787
788 .L_thread_exc_ret_check_ast:
789
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 */
793
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.
798 */
799
800 mfsprg r10,0 /* Get the per_processor block */
801 lwz r4,PP_NEED_AST(r10)
802 lwz r4,0(r4)
803 cmpi cr0,r4, 0
804 beq cr0,.L_exc_ret_no_ast
805
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
809 */
810
811
812 li r3,0
813 li r4,AST_ALL
814 li r5,1
815
816 bl EXT(ast_taken)
817 b .L_thread_exc_ret_check_ast /* check for a second AST (rare)*/
818
819 /* arriving here, interrupts should be disabled */
820 /* Get the active thread's PCB pointer to restore regs
821 */
822 .L_exc_ret_no_ast:
823
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...
830 #if DEBUG
831 /*
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
834 */
835
836 lwz r3,savesrr1(r30)
837 andi. r3,r3,MASK(MSR_PR)
838 bne+ ret_user2 ; We are ok...
839
840 BREAKPOINT_TRAP
841 ret_user2:
842 #endif /* DEBUG */
843
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!
847 */
848 lwz r0,SAVflags(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
853
854 ;
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...
858
859 makeDummyCtx:
860 bl EXT(save_get) ; Get a save_area
861 li r0,0 ; Get a 0
862 addi r2,r3,savefp0 ; Point past what we are clearing
863 mr r4,r3 ; Save the start
864
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...
869
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
873
874 b thread_return ; Go let em try to execute, hah!
875
876 /*
877 * ihandler(type)
878 *
879 * ENTRY: VM switched ON
880 * Interrupts OFF
881 * R3 contains exception code
882 * R4 points to the saved context (virtual address)
883 * Everything is saved in savearea
884 *
885 */
886
887 ENTRY(ihandler, TAG_NO_FRAME_USED)
888
889 /*
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.
893 */
894
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 */
905
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
909
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
915
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 */
920
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 */
926
927 ihboot4: bne .L_istackfree /* Nope... */
928
929 /* We're already on the interrupt stack, get back the old
930 * stack pointer and make room for a frame
931 */
932
933 subi r1,r9,FM_REDZONE /* Back up beyond the red zone */
934 b ihsetback /* Go set up the back chain... */
935
936 .L_istackfree:
937 lwz r10,SAVflags(r4)
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 */
941
942 /*
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.
948 */
949
950 ihsetback: subi r1,r1,FM_SIZE /* Make a new frame */
951 stw r9,FM_BACKPTR(r1) /* point back to previous stackptr */
952
953 #if VERIFYSAVE
954 bl versave ; (TEST/DEBUG)
955 #endif
956
957 #if 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
961 */
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 */
965 #endif /* DEBUG */
966
967 lwz r5,savedsisr(r4) /* Get the DSISR */
968 lwz r6,savedar(r4) /* Get the DAR */
969
970 bl EXT(interrupt)
971
972
973 /* interrupt() returns a pointer to the saved state in r3
974 *
975 * Ok, back from C. Disable interrupts while we restore things
976 */
977 .globl EXT(ihandler_ret)
978
979 LEXT(ihandler_ret) /* Marks our return point from debugger entry */
980
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 */
985
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 */
994
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 */
998
999 ihboot3: mr r4,r3 /* Move the savearea pointer */
1000 beq .L_no_int_ast2 /* Get going if not the top o' stack... */
1001
1002
1003 /* We're the last frame on the stack. Restore istackptr to empty state.
1004 *
1005 * Check for ASTs if one of the below is true:
1006 * returning to user mode
1007 * returning to a kloaded server
1008 */
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... */
1024 b .L_call_thandler
1025
1026 .L_kernel_int_ast:
1027 andi. r11,r11,AST_URGENT /* AST_URGENT */
1028 li r3,T_PREEMPT /* Assume the worst */
1029 beq .L_no_int_ast /* Nope... */
1030
1031 .L_call_thandler:
1032
1033 /*
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.
1039 */
1040
1041 stw r3,saveexception(r4) /* Set the exception code to T_AST/T_PREEMPT */
1042 b EXT(thandler) /* hyperspace into AST trap */
1043
1044 .L_no_int_ast:
1045 mr r3,r4 ; Get into the right register for common code
1046 .L_no_int_ast2:
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
1052
1053
1054 ;
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
1057 ; exited.
1058 ;
1059 ; It also enables the facility if its context is live
1060 ; Requires:
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
1065 ;
1066 chkfac: mr. r8,r8 ; Are we still in boot?
1067 beq- chkenax ; Yeah, skip it all...
1068
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...
1078
1079 #if FPVECDBG
1080 lis r0,HIGH_ADDR(CutTrace) ; (TEST/DEBUG)
1081 li r2,0x3301 ; (TEST/DEBUG)
1082 oris r0,r0,LOW_ADDR(CutTrace) ; (TEST/DEBUG)
1083 sc ; (TEST/DEBUG)
1084 #endif
1085
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...
1091
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...
1094
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
1105
1106 #if 0
1107 mfmsr r0 ; (TEST/DEBUG)
1108 ori r0,r0,0x2000 ; (TEST/DEBUG)
1109 mtmsr r0 ; (TEST/DEBUG)
1110 isync ; (TEST/DEBUG)
1111
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)
1144
1145 li r2,64 ; (TEST/DEBUG)
1146 la r20,savevr0(r3) ; (TEST/DEBUG)
1147 la r21,savefp0(r24) ; (TEST/DEBUG)
1148
1149 ckmurderdeath2:
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)
1159
1160 diekilldead2: ; (TEST/DEBUG)
1161 mr r4,r24 ; (TEST/DEBUG)
1162 BREAKPOINT_TRAP ; (TEST/DEBUG)
1163
1164 dontdiekilldead2:
1165 lfd f0,savevr0(r3) ; (TEST/DEBUG)
1166 lfd f1,savevr0+8(r3) ; (TEST/DEBUG)
1167 #endif
1168
1169
1170
1171 b chkvec ; Go check out the vector facility...
1172
1173 chkfpfree: li r0,0 ; Clear a register
1174 lwz r24,ACT_MACT_FPU(r8) ; Get the floating point save area
1175
1176 bne- cr1,chkfpnfr ; Not our facility, do not clear...
1177 stw r0,PP_FPU_THREAD(r10) ; Clear floating point owner
1178 chkfpnfr:
1179
1180 #if FPVECDBG
1181 lis r0,HIGH_ADDR(CutTrace) ; (TEST/DEBUG)
1182 li r2,0x3302 ; (TEST/DEBUG)
1183 oris r0,r0,LOW_ADDR(CutTrace) ; (TEST/DEBUG)
1184 sc ; (TEST/DEBUG)
1185 #endif
1186
1187 mr. r24,r24 ; Do we even have a savearea?
1188 beq+ chkvec ; Nope...
1189
1190 #if FPVECDBG
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)
1198 sc ; (TEST/DEBUG)
1199 #endif
1200
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...
1206
1207 fptoss: lwz r25,SAVprefp(r24) ; Get previous savearea
1208 #if FPVECDBG
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)
1213 sc ; (TEST/DEBUG)
1214 #endif
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...
1218 #if FPVECDBG
1219 rlwinm. r0,r25,0,0,15 ; (TEST/DEBUG)
1220 bne+ notbadxxx2 ; (TEST/DEBUG)
1221 BREAKPOINT_TRAP ; (TEST/DEBUG)
1222 notbadxxx2: ; (TEST/DEBUG)
1223 #endif
1224 lwz r25,SAVlvlfp(r25) ; Get the new level
1225
1226 fptoplvl: lwz r19,SAVflags(r24) ; Get the savearea flags
1227 #if FPVECDBG
1228 rlwinm. r0,r19,0,1,1 ; (TEST/DEBUG)
1229 bne+ donotdie3 ; (TEST/DEBUG)
1230 BREAKPOINT_TRAP ; (TEST/DEBUG)
1231 donotdie3: ; (TEST/DEBUG)
1232 #endif
1233
1234 #if FPVECDBG
1235 lis r0,HIGH_ADDR(CutTrace) ; (TEST/DEBUG)
1236 li r2,0x3305 ; (TEST/DEBUG)
1237 oris r0,r0,LOW_ADDR(CutTrace) ; (TEST/DEBUG)
1238 sc ; (TEST/DEBUG)
1239 #endif
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...
1246 #if FPVECDBG
1247 lis r0,HIGH_ADDR(CutTrace) ; (TEST/DEBUG)
1248 li r2,0x3306 ; (TEST/DEBUG)
1249 oris r0,r0,LOW_ADDR(CutTrace) ; (TEST/DEBUG)
1250 sc ; (TEST/DEBUG)
1251 #endif
1252 #if FPVECDBG
1253 rlwinm. r0,r24,0,0,15 ; (TEST/DEBUG)
1254 bne+ notbadxxx3 ; (TEST/DEBUG)
1255 BREAKPOINT_TRAP ; (TEST/DEBUG)
1256 notbadxxx3: ; (TEST/DEBUG)
1257 #endif
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
1263
1264 ;
1265 ; Check out vector stuff (and translate savearea to physical for exit)
1266 ;
1267 chkvec:
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...
1275
1276 #if FPVECDBG
1277 lis r0,HIGH_ADDR(CutTrace) ; (TEST/DEBUG)
1278 li r2,0x3401 ; (TEST/DEBUG)
1279 oris r0,r0,LOW_ADDR(CutTrace) ; (TEST/DEBUG)
1280 sc ; (TEST/DEBUG)
1281 #endif
1282
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...
1288
1289 stw r0,PP_VMX_THREAD(r10) ; Show facility unowned so we do not get back here
1290 b setena ; Go actually exit...
1291
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...
1303
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
1308 chkvecnfr:
1309
1310 #if FPVECDBG
1311 lis r0,HIGH_ADDR(CutTrace) ; (TEST/DEBUG)
1312 li r2,0x3402 ; (TEST/DEBUG)
1313 oris r0,r0,LOW_ADDR(CutTrace) ; (TEST/DEBUG)
1314 sc ; (TEST/DEBUG)
1315 #endif
1316
1317 mr. r24,r24 ; Do we even have a savearea?
1318 beq+ setena ; Nope...
1319
1320 #if FPVECDBG
1321 lis r0,HIGH_ADDR(CutTrace) ; (TEST/DEBUG)
1322 li r2,0x3403 ; (TEST/DEBUG)
1323 oris r0,r0,LOW_ADDR(CutTrace) ; (TEST/DEBUG)
1324 sc ; (TEST/DEBUG)
1325 #endif
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...
1331
1332 vectoss: lwz r25,SAVprevec(r24) ; Get previous savearea
1333 #if FPVECDBG
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)
1338 sc ; (TEST/DEBUG)
1339 #endif
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
1344
1345 vectoplvl: lwz r19,SAVflags(r24) ; Get the savearea flags
1346
1347 #if FPVECDBG
1348 lis r0,HIGH_ADDR(CutTrace) ; (TEST/DEBUG)
1349 li r2,0x3405 ; (TEST/DEBUG)
1350 oris r0,r0,LOW_ADDR(CutTrace) ; (TEST/DEBUG)
1351 sc ; (TEST/DEBUG)
1352 #endif
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...
1359 #if FPVECDBG
1360 lis r0,HIGH_ADDR(CutTrace) ; (TEST/DEBUG)
1361 li r2,0x3406 ; (TEST/DEBUG)
1362 oris r0,r0,LOW_ADDR(CutTrace) ; (TEST/DEBUG)
1363 sc ; (TEST/DEBUG)
1364 #endif
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
1370
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....
1374
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
1381
1382 setenaa: stw r12,savesrr1(r3) ; Turn facility on or off
1383
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...
1389
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...
1397
1398 subfc r6,r21,r23 ; Subtract current from qact time
1399 li r0,0 ; Make a 0
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...
1407
1408 mtdec r13 ; Set our value
1409
1410 chkenax: lwz r6,SAVflags(r3) ; Pick up the flags of the old savearea
1411
1412
1413 #if DEBUG
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)
1423
1424 yeswereok:
1425 #endif
1426
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...
1433
1434
1435
1436 /*
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.
1441 *
1442 * Registers when we get here:
1443 *
1444 * r0 = syscall number
1445 * r4 = savearea/pcb
1446 * r13 = activation
1447 * r14 = previous savearea (if any)
1448 * r16 = thread
1449 * r25 = per_proc
1450 */
1451
1452 fastpath: cmplwi cr3,r0,0x7FF1 ; Is it CthreadSetSelfNumber?
1453 bnelr- cr3 ; Not a fast path...
1454
1455 /*
1456 * void cthread_set_self(cproc_t p)
1457 *
1458 * set's thread state "user_value"
1459 *
1460 * This op is invoked as follows:
1461 * li r0, CthreadSetSelfNumber // load the fast-trap number
1462 * sc // invoke fast-trap
1463 * blr
1464 *
1465 */
1466
1467 CthreadSetSelfNumber:
1468
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 */
1472
1473
1474 .globl EXT(fastexit)
1475 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... */
1483
1484
1485 /*
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.
1490 */
1491
1492 checkassist:
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 */
1496
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...
1505
1506 checkassistBP: /* Safe place to breakpoint */
1507
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... */
1512
1513 ;
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.
1519 ;
1520
1521 exitFromVM: mr r30,r4 ; Get the savearea
1522 mr r3,r13 ; Get the activation
1523
1524 b EXT(vmm_exit) ; Do it to it
1525
1526 .align 5
1527 .globl EXT(retFromVM)
1528
1529 LEXT(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)
1538
1539 stw r4,ACT_MACT_PCB(r8) ; Point to the previous savearea (or 0 if none)
1540
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...
1545
1546
1547 #if MACH_KDB
1548 /*
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.
1552 *
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.
1556 */
1557
1558 ENTRY(kdb_kintr, TAG_NO_FRAME_USED)
1559
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 */
1564
1565 lwz r8,0(r1) /* Get our caller's stack frame */
1566
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... */
1574
1575 srchfnd: stw r10,FM_LR_SAVE(r8) /* Modify return to come to us instead */
1576 blr /* Finish up and get back here... */
1577
1578 /*
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.
1582 *
1583 * R3 points to the saved state at entry
1584 */
1585
1586 ENTRY(intercept_ret, TAG_NO_FRAME_USED)
1587
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 */
1595
1596 blrl /* Go enter KDB */
1597
1598 mr r3,r13 /* Put the saved state where expected */
1599 b EXT(ihandler_ret) /* Go return from the interruption... */
1600
1601 #endif
1602
1603 #if VERIFYSAVE
1604 ;
1605 ; Savearea chain verification
1606 ;
1607
1608 versave:
1609
1610 #if 0
1611 ;
1612 ; Make sure that only the top FPU savearea is marked invalid
1613 ;
1614
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)
1625
1626 fcknxtth: mr. r27,r27 ; (TEST/DEBUG)
1627 beqlr- ; (TEST/DEBUG)
1628
1629 lwz r26,THREAD_TOP_ACT(r28) ; (TEST/DEBUG)
1630
1631 fckact: mr. r26,r26 ; (TEST/DEBUG)
1632 bne+ fckact2 ; (TEST/DEBUG)
1633
1634 lwz r28,THREAD_PSTHRN(r28) ; (TEST/DEBUG) Next in line
1635 subi r27,r27,1 ; (TEST/DEBUG)
1636 b fcknxtth ; (TEST/DEBUG)
1637
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...
1641
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...
1645
1646 lwz r29,SAVlvlfp(r20) ; (TEST/DEBUG) Get the level
1647
1648 cmplwi r29,1 ; (TEST/DEBUG) Is it invalid??
1649 bne+ fckact3 ; (TEST/DEBUG) Nope...
1650
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)
1655
1656 fcknact: lwz r26,ACT_LOWER(r26) ; (TEST/DEBUG) Next activation
1657 b fckact ; (TEST/DEBUG)
1658 #endif
1659
1660 #if 1
1661 ;
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.
1666 ;
1667
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)
1678
1679 fcknxtth: mr. r27,r27 ; (TEST/DEBUG)
1680 beqlr- ; (TEST/DEBUG)
1681
1682 lwz r26,THREAD_TOP_ACT(r28) ; (TEST/DEBUG)
1683
1684 fckact: mr. r26,r26 ; (TEST/DEBUG)
1685 bne+ fckact2 ; (TEST/DEBUG)
1686
1687 lwz r28,THREAD_PSTHRN(r28) ; (TEST/DEBUG) Next in line
1688 subi r27,r27,1 ; (TEST/DEBUG)
1689 b fcknxtth ; (TEST/DEBUG)
1690
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)
1694
1695 fckact3: mr. r20,r20 ; (TEST/DEBUG) Are there any?
1696 beq+ fckact5 ; (TEST/DEBUG) No...
1697
1698 addi r22,r22,1 ; (TEST/DEBUG) Count chain depth
1699
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
1707
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
1717
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
1725
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...
1730
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)
1735
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...
1739
1740 fckact5: lwz r20,ACT_MACT_FPU(r26) ; (TEST/DEBUG) Get FPU chain
1741 li r29,0 ; (TEST/DEBUG)
1742
1743 fckact6: mr. r20,r20 ; (TEST/DEBUG) Are there any?
1744 beq+ fcknact ; (TEST/DEBUG) No...
1745
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...
1749
1750 fcknact: lwz r26,ACT_LOWER(r26) ; (TEST/DEBUG) Next activation
1751 b fckact ; (TEST/DEBUG)
1752 #endif
1753
1754
1755 #if 0
1756 ;
1757 ; Make sure in use count matches found savearea. This is
1758 ; not always accurate. There is a variable "fuzz" factor in count.
1759
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)
1770
1771 cknxtth: mr. r27,r27 ; (TEST/DEBUG)
1772 beq- cktotal ; (TEST/DEBUG)
1773
1774 lwz r26,THREAD_TOP_ACT(r28) ; (TEST/DEBUG)
1775
1776 ckact: mr. r26,r26 ; (TEST/DEBUG)
1777 bne+ ckact2 ; (TEST/DEBUG)
1778
1779 lwz r28,THREAD_PSTHRN(r28) ; (TEST/DEBUG) Next in line
1780 subi r27,r27,1 ; (TEST/DEBUG)
1781 b cknxtth ; (TEST/DEBUG)
1782
1783 ckact2: lwz r29,ACT_MACT_PCB(r26) ; (TEST/DEBUG)
1784
1785 cknorm: mr. r29,r29 ; (TEST/DEBUG)
1786 beq- cknormd ; (TEST/DEBUG)
1787
1788 addi r20,r20,1 ; (TEST/DEBUG) Count normal savearea
1789
1790 lwz r29,SAVprev(r29) ; (TEST/DEBUG)
1791 b cknorm ; (TEST/DEBUG)
1792
1793 cknormd: lwz r29,ACT_MACT_FPU(r26) ; (TEST/DEBUG)
1794
1795 ckfpu: mr. r29,r29 ; (TEST/DEBUG)
1796 beq- ckfpud ; (TEST/DEBUG)
1797
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)
1801
1802 addi r20,r20,1 ; (TEST/DEBUG) Count fpu savearea
1803
1804 cknfpu: lwz r29,SAVprefp(r29) ; (TEST/DEBUG)
1805 b ckfpu ; (TEST/DEBUG)
1806
1807 ckfpud: lwz r29,ACT_MACT_VMX(r26) ; (TEST/DEBUG)
1808
1809 ckvmx: mr. r29,r29 ; (TEST/DEBUG)
1810 beq- ckvmxd ; (TEST/DEBUG)
1811
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)
1815
1816 addi r20,r20,1 ; (TEST/DEBUG) Count vector savearea
1817
1818 cknvmx: lwz r29,SAVprevec(r29) ; (TEST/DEBUG)
1819 b ckvmx ; (TEST/DEBUG)
1820
1821 ckvmxd: lwz r26,ACT_LOWER(r26) ; (TEST/DEBUG) Next activation
1822 b ckact ; (TEST/DEBUG)
1823
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)
1828
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)
1836
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)
1841 #endif
1842 #endif