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@
27 * Low-memory exception vector code for PowerPC MACH
29 * These are the only routines that are ever run with
30 * VM instruction translation switched off.
32 * The PowerPC is quite strange in that rather than having a set
33 * of exception vectors, the exception handlers are installed
34 * in well-known addresses in low memory. This code must be loaded
35 * at ZERO in physical memory. The simplest way of doing this is
36 * to load the kernel at zero, and specify this as the first file
37 * on the linker command line.
39 * When this code is loaded into place, it is loaded at virtual
40 * address KERNELBASE, which is mapped to zero (physical).
42 * This code handles all powerpc exceptions and is always entered
43 * in supervisor mode with translation off. It saves the minimum
44 * processor state before switching back on translation and
45 * jumping to the approprate routine.
47 * Vectors from 0x100 to 0x3fff occupy 0x100 bytes each (64 instructions)
49 * We use some of this space to decide which stack to use, and where to
50 * save the context etc, before jumping to a generic handler.
56 #include <db_machine_commands.h>
59 #include <mach_debug.h>
61 #include <ppc/proc_reg.h>
62 #include <ppc/exception.h>
63 #include <ppc/Performance.h>
64 #include <ppc/savearea.h>
65 #include <mach/ppc/vm_param.h>
73 #error The TRCSAVE option is broken.... Fix it
78 #define featAltivec 26
83 #define VECTOR_SEGMENT .section __VECTORS, __interrupts
88 .globl EXT(ExceptionVectorsStart)
90 EXT(ExceptionVectorsStart): /* Used if relocating the exception vectors */
91 baseR: /* Used so we have more readable code */
94 * System reset - call debugger
97 .globl EXT(ResetHandler)
105 mtsprg 2,r13 /* Save R13 */
106 mtsprg 3,r11 /* Save R11 */
107 lwz r13,lo16(EXT(ResetHandler)-EXT(ExceptionVectorsStart)+RESETHANDLER_TYPE)(br0) ; Get reset type
109 cmpi cr0,r13,RESET_HANDLER_START
112 li r11,RESET_HANDLER_NULL
113 stw r11,lo16(EXT(ResetHandler)-EXT(ExceptionVectorsStart)+RESETHANDLER_TYPE)(br0) ; Clear reset type
115 lwz r4,lo16(EXT(ResetHandler)-EXT(ExceptionVectorsStart)+RESETHANDLER_CALL)(br0)
116 lwz r3,lo16(EXT(ResetHandler)-EXT(ExceptionVectorsStart)+RESETHANDLER_ARG)(br0)
122 li r11,T_RESET /* Set 'rupt code */
123 b .L_exception_entry /* Join common... */
131 mtsprg 2,r13 /* Save R13 */
132 mtsprg 3,r11 /* Save R11 */
133 li r11,T_MACHINE_CHECK /* Set 'rupt code */
134 b .L_exception_entry /* Join common... */
137 * Data access - page fault, invalid memory rights for operation
142 mtsprg 2,r13 /* Save R13 */
143 mtsprg 3,r11 /* Save R11 */
144 li r11,T_DATA_ACCESS /* Set 'rupt code */
145 b .L_exception_entry /* Join common... */
148 * Instruction access - as for data access
153 mtsprg 2,r13 /* Save R13 */
154 mtsprg 3,r11 /* Save R11 */
155 li r11,T_INSTRUCTION_ACCESS /* Set 'rupt code */
156 b .L_exception_entry /* Join common... */
164 mtsprg 2,r13 /* Save R13 */
165 mtsprg 3,r11 /* Save R11 */
166 li r11,T_INTERRUPT /* Set 'rupt code */
167 b .L_exception_entry /* Join common... */
170 * Alignment - many reasons
175 mtsprg 2,r13 /* Save R13 */
176 mtsprg 3,r11 /* Save R11 */
177 li r11,T_ALIGNMENT /* Set 'rupt code */
178 b .L_exception_entry /* Join common... */
181 * Program - floating point exception, illegal inst, priv inst, user trap
186 mtsprg 2,r13 /* Save R13 */
187 mtsprg 3,r11 /* Save R11 */
188 li r11,T_PROGRAM /* Set 'rupt code */
189 b .L_exception_entry /* Join common... */
192 * Floating point disabled
197 mtsprg 2,r13 /* Save R13 */
198 mtsprg 3,r11 /* Save R11 */
199 li r11,T_FP_UNAVAILABLE /* Set 'rupt code */
200 b .L_exception_entry /* Join common... */
204 * Decrementer - DEC register has passed zero.
209 mtsprg 2,r13 /* Save R13 */
210 mtsprg 3,r11 /* Save R11 */
211 li r11,T_DECREMENTER /* Set 'rupt code */
212 b .L_exception_entry /* Join common... */
215 * I/O controller interface error - MACH does not use this
220 mtsprg 2,r13 /* Save R13 */
221 mtsprg 3,r11 /* Save R11 */
222 li r11,T_IO_ERROR /* Set 'rupt code */
223 b .L_exception_entry /* Join common... */
231 mtsprg 2,r13 /* Save R13 */
232 mtsprg 3,r11 /* Save R11 */
233 li r11,T_RESERVED /* Set 'rupt code */
234 b .L_exception_entry /* Join common... */
260 ; System call - generated by the sc instruction
262 ; We handle the ultra-fast traps right here. They are:
264 ; 0xFFFFFFFF - BlueBox only - MKIsPreemptiveTask
265 ; 0xFFFFFFFE - BlueBox only - kcNKIsPreemptiveTaskEnv
266 ; 0x00007FF2 - User state only - thread info
267 ; 0x00007FF3 - User state only - floating point / vector facility status
268 ; 0x00007FF4 - Kernel only - loadMSR
270 ; Note: none handled if virtual machine is running
271 ; Also, it we treat SCs as kernel SCs if the RI bit is set
276 mtsprg 2,r13 ; Save R13
277 mfsrr1 r13 ; Get SRR1 for loadMSR
278 mtsprg 3,r11 ; Save R11
279 rlwimi r13,r13,MSR_PR_BIT,0,0 ; Move PR bit to non-volatile CR0 bit 0
280 mfcr r11 ; Save the CR
281 mtcrf 0x81,r13 ; Get the moved PR and the RI for testing
283 cror 0,0,MSR_RI_BIT ; See if we have !PR or RI
284 mfsprg r13,0 ; Get the per_proc_area
285 bt- 0,uftInKern ; We are in the kernel...
287 cmplwi cr5,r0,0x7FF2 ; Ultra fast path cthread info call?
288 cmpwi cr6,r0,0x7FF3 ; Ultra fast path facility status?
289 cror cr1_eq,cr5_lt,cr6_gt ; Set true if not 0x7FF2 and not 0x7FF3 and not negative
290 lwz r13,spcFlags(r13) ; Get the special flags
291 bt- cr1_eq,notufp ; Exit if we can not be ultra fast...
293 rlwimi r13,r13,runningVMbit+1,31,31 ; Move VM flag after the 3 blue box flags
294 not. r0,r0 ; Flip bits and kind of subtract 1
295 mtcrf 1,r13 ; Set BB and VMM flags in CR7
297 cmplwi cr1,r0,1 ; Is this a bb fast path?
298 not r0,r0 ; Restore to entry state
299 bt- 31,notufp ; No fast paths if running VM (assume not)...
300 bf- bbNoMachSCbit,ufpUSuft ; We are not running BlueBox...
301 bgt cr1,notufp ; This can not be a bb ufp...
307 rlwimi r11,r13,bbPreemptivebit-cr0_eq,cr0_eq,cr0_eq ; Copy preemptive task flag into user cr0_eq
308 mfsprg r13,0 ; Get back pre_proc
311 bne cr1,ufpIsBBpre ; This is the "isPreemptiveTask" call...
313 lwz r0,ppbbTaskEnv(r13) ; Get the shadowed taskEnv from per_proc_area
316 mtcrf 0xFF,r11 ; Restore CR
317 mfsprg r11,3 ; Restore R11
318 mfsprg r13,2 ; Restore R13
319 rfi ; All done, go back...
322 ; Normal fast path...
325 ufpUSuft: bge+ notufp ; Bail if negative... (ARRRGGG -- BRANCH TO A BRANCH!!!!!)
326 mfsprg r11,3 ; Restore R11
327 mfsprg r3,0 ; Get the per_proc_area
328 mfsprg r13,2 ; Restore R13
329 bne- cr5,isvecfp ; This is the facility stat call
330 lwz r3,UAW(r3) ; Get the assist word
331 rfi ; All done, scream back... (no need to restore CR or R11, they are volatile)
333 isvecfp: lwz r3,spcFlags(r3) ; Get the facility status
336 notufp: mtcrf 0xFF,r11 ; Restore the used CRs
337 li r11,T_SYSTEM_CALL ; Set interrupt code
338 b .L_exception_entry ; Join common...
340 uftInKern: cmplwi r0,0x7FF4 ; Ultra fast path loadMSR?
341 bne- notufp ; Someone is trying to cheat...
343 mtcrf 0xFF,r11 ; Restore CR
344 lwz r11,pfAvailable(r13) ; Pick up the feature flags
345 mtsrr1 r3 ; Set new MSR
346 mfsprg r13,2 ; Restore R13
347 mtsprg 2,r11 ; Set the feature flags into sprg2
348 mfsprg r11,3 ; Restore R11
353 * Trace - generated by single stepping
354 * performance monitor BE branch enable tracing/logging
355 * is also done here now. while this is permanently in the
356 * system the impact is completely unnoticable as this code is
357 * only executed when (a) a single step or branch exception is
358 * hit, (b) in the single step debugger case there is so much
359 * overhead already the few extra instructions for testing for BE
360 * are not even noticable, (c) the BE logging code is *only* run
361 * when it is enabled by the tool which will not happen during
362 * normal system usage
364 * Note that this trace is available only to user state so we do not
365 * need to set sprg2 before returning.
370 mtsprg 2,r13 ; Save R13
371 mtsprg 3,r11 ; Save R11
372 mfsrr1 r13 ; Get the old MSR
373 mfcr r11 ; Get the CR
374 rlwinm. r13,r13,0,MSR_PR_BIT,MSR_PR_BIT ; Are we in supervisor state?
375 beq- notspectr ; Yes, not special trace...
376 mfsprg r13,0 ; Get the per_proc area
377 lhz r13,PP_CPU_FLAGS(r13) ; Get the flags
378 rlwinm. r13,r13,0,traceBEb+16,traceBEb+16 ; Special trace enabled?
379 bne+ specbrtr ; Yeah...
381 notspectr: mtcr r11 ; Restore CR
382 li r11,T_TRACE ; Set interrupt code
383 b .L_exception_entry ; Join common...
386 ; We are doing the special branch trace
389 specbrtr: mfsprg r13,0 ; Get the per_proc area
390 stw r1,emfp0(r13) ; Save in a scratch area
391 stw r2,emfp0+4(r13) ; Save in a scratch area
392 stw r3,emfp0+8(r13) ; Save in a scratch area
394 lis r2,hi16(EXT(pc_trace_buf)) ; Get the top of the buffer
395 lwz r3,spcTRp(r13) ; Pick up buffer position
396 mr. r1,r1 ; Is it time to count?
397 ori r2,r2,lo16(EXT(pc_trace_buf)) ; Get the bottom of the buffer
398 cmplwi cr1,r3,4092 ; Set cr1_eq if we should take exception
399 mfsrr0 r1 ; Get the pc
400 stwx r1,r2,r3 ; Save it in the buffer
401 addi r3,r3,4 ; Point to the next slot
402 rlwinm r3,r3,0,20,31 ; Wrap the slot at one page
403 stw r3,spcTRp(r13) ; Save the new slot
404 lwz r1,emfp0(r13) ; Restore work register
405 lwz r2,emfp0+4(r13) ; Restore work register
406 lwz r3,emfp0+8(r13) ; Restore work register
407 beq cr1,notspectr ; Buffer filled, make a rupt...
409 mtcr r11 ; Restore the CR
410 mfsprg r13,2 ; Restore R13
411 mfsprg r11,3 ; Restore R11
415 * Floating point assist
420 mtsprg 2,r13 /* Save R13 */
421 mtsprg 3,r11 /* Save R11 */
422 li r11,T_FP_ASSIST /* Set 'rupt code */
423 b .L_exception_entry /* Join common... */
427 * Performance monitor interruption
432 mtsprg 2,r13 /* Save R13 */
433 mtsprg 3,r11 /* Save R11 */
434 li r11,T_PERF_MON /* Set 'rupt code */
435 b .L_exception_entry /* Join common... */
444 mtsprg 2,r13 /* Save R13 */
445 mtsprg 3,r11 /* Save R11 */
446 li r11,T_VMX /* Set 'rupt code */
447 b .L_exception_entry /* Join common... */
452 * Instruction translation miss - we inline this code.
453 * Upon entry (done for us by the machine):
454 * srr0 : addr of instruction that missed
455 * srr1 : bits 0-3 = saved CR0
458 * msr[tgpr] = 1 (so gpr0-3 become our temporary variables)
459 * imiss: ea that missed
460 * icmp : the compare value for the va that missed
461 * hash1: pointer to first hash pteg
462 * hash2: pointer to 2nd hash pteg
465 * tmp0: saved counter
467 * tmp2: pointer to pteg
468 * tmp3: current compare value
470 * This code is taken from the 603e User's Manual with
471 * some bugfixes and minor improvements to save bytes and cycles
473 * NOTE: Do not touch sprg2 in here
479 mfctr tmp0 /* use tmp0 to save ctr */
482 .L_imiss_find_pte_in_pteg:
483 li tmp1, 8 /* count */
484 subi tmp2, tmp2, 8 /* offset for lwzu */
485 mtctr tmp1 /* count... */
488 lwz tmp1, 8(tmp2) /* check pte0 for match... */
492 bdnzf+ cr0, .L_imiss_pteg_loop
494 bc 0,2, .L_imiss_pteg_loop
496 beq+ cr0, .L_imiss_found_pte
498 /* Not found in PTEG, we must scan 2nd then give up */
500 andi. tmp1, tmp3, MASK(PTE0_HASH_ID)
501 bne- .L_imiss_do_no_hash_exception /* give up */
504 ori tmp3, tmp3, MASK(PTE0_HASH_ID)
505 b .L_imiss_find_pte_in_pteg
509 lwz tmp1, 4(tmp2) /* get pte1_t */
510 andi. tmp3, tmp1, MASK(PTE1_WIMG_GUARD) /* Fault? */
511 bne- .L_imiss_do_prot_exception /* Guarded - illegal */
513 /* Ok, we've found what we need to, restore and rfi! */
515 mtctr tmp0 /* restore ctr */
518 mtcrf 0x80, tmp3 /* Restore CR0 */
519 mtspr rpa, tmp1 /* set the pte */
520 ori tmp1, tmp1, MASK(PTE1_REFERENCED) /* set referenced */
525 .L_imiss_do_prot_exception:
526 /* set up srr1 to indicate protection exception... */
528 andi. tmp2, tmp3, 0xffff
529 addis tmp2, tmp2, MASK(SRR1_TRANS_PROT) >> 16
530 b .L_imiss_do_exception
532 .L_imiss_do_no_hash_exception:
533 /* clean up registers for protection exception... */
535 andi. tmp2, tmp3, 0xffff
536 addis tmp2, tmp2, MASK(SRR1_TRANS_HASH) >> 16
538 /* And the entry into the usual instruction fault handler ... */
539 .L_imiss_do_exception:
541 mtctr tmp0 /* Restore ctr */
542 mtsrr1 tmp2 /* Set up srr1 */
544 xoris tmp0, tmp0, MASK(MSR_TGPR)>>16 /* no TGPR */
545 mtcrf 0x80, tmp3 /* Restore CR0 */
546 mtmsr tmp0 /* reset MSR[TGPR] */
547 b .L_handler400 /* Instr Access */
550 * Data load translation miss
552 * Upon entry (done for us by the machine):
553 * srr0 : addr of instruction that missed
554 * srr1 : bits 0-3 = saved CR0
558 * msr[tgpr] = 1 (so gpr0-3 become our temporary variables)
559 * dmiss: ea that missed
560 * dcmp : the compare value for the va that missed
561 * hash1: pointer to first hash pteg
562 * hash2: pointer to 2nd hash pteg
565 * tmp0: saved counter
567 * tmp2: pointer to pteg
568 * tmp3: current compare value
570 * This code is taken from the 603e User's Manual with
571 * some bugfixes and minor improvements to save bytes and cycles
573 * NOTE: Do not touch sprg2 in here
579 mfctr tmp0 /* use tmp0 to save ctr */
582 .L_dlmiss_find_pte_in_pteg:
583 li tmp1, 8 /* count */
584 subi tmp2, tmp2, 8 /* offset for lwzu */
585 mtctr tmp1 /* count... */
588 lwz tmp1, 8(tmp2) /* check pte0 for match... */
591 #if 0 /* How to write this correctly? */
592 bdnzf+ cr0, .L_dlmiss_pteg_loop
594 bc 0,2, .L_dlmiss_pteg_loop
596 beq+ cr0, .L_dmiss_found_pte
598 /* Not found in PTEG, we must scan 2nd then give up */
600 andi. tmp1, tmp3, MASK(PTE0_HASH_ID) /* already at 2nd? */
601 bne- .L_dmiss_do_no_hash_exception /* give up */
604 ori tmp3, tmp3, MASK(PTE0_HASH_ID)
605 b .L_dlmiss_find_pte_in_pteg
609 lwz tmp1, 4(tmp2) /* get pte1_t */
611 /* Ok, we've found what we need to, restore and rfi! */
613 mtctr tmp0 /* restore ctr */
616 mtcrf 0x80, tmp3 /* Restore CR0 */
617 mtspr rpa, tmp1 /* set the pte */
618 ori tmp1, tmp1, MASK(PTE1_REFERENCED) /* set referenced */
619 tlbld tmp0 /* load up tlb */
620 sth tmp1, 6(tmp2) /* sth is faster? */
623 /* This code is shared with data store translation miss */
625 .L_dmiss_do_no_hash_exception:
626 /* clean up registers for protection exception... */
628 /* prepare to set DSISR_WRITE_BIT correctly from srr1 info */
629 rlwinm tmp1, tmp3, 9, 6, 6
630 addis tmp1, tmp1, MASK(DSISR_HASH) >> 16
632 /* And the entry into the usual data fault handler ... */
634 mtctr tmp0 /* Restore ctr */
635 andi. tmp2, tmp3, 0xffff /* Clean up srr1 */
636 mtsrr1 tmp2 /* Set srr1 */
641 xoris tmp0, tmp0, MASK(MSR_TGPR)>>16 /* no TGPR */
642 mtcrf 0x80, tmp3 /* Restore CR0 */
643 sync /* Needed on some */
644 mtmsr tmp0 /* reset MSR[TGPR] */
645 b .L_handler300 /* Data Access */
648 * Data store translation miss (similar to data load)
650 * Upon entry (done for us by the machine):
651 * srr0 : addr of instruction that missed
652 * srr1 : bits 0-3 = saved CR0
656 * msr[tgpr] = 1 (so gpr0-3 become our temporary variables)
657 * dmiss: ea that missed
658 * dcmp : the compare value for the va that missed
659 * hash1: pointer to first hash pteg
660 * hash2: pointer to 2nd hash pteg
663 * tmp0: saved counter
665 * tmp2: pointer to pteg
666 * tmp3: current compare value
668 * This code is taken from the 603e User's Manual with
669 * some bugfixes and minor improvements to save bytes and cycles
671 * NOTE: Do not touch sprg2 in here
677 mfctr tmp0 /* use tmp0 to save ctr */
680 .L_dsmiss_find_pte_in_pteg:
681 li tmp1, 8 /* count */
682 subi tmp2, tmp2, 8 /* offset for lwzu */
683 mtctr tmp1 /* count... */
686 lwz tmp1, 8(tmp2) /* check pte0 for match... */
690 #if 0 /* I don't know how to write this properly */
691 bdnzf+ cr0, .L_dsmiss_pteg_loop
693 bc 0,2, .L_dsmiss_pteg_loop
695 beq+ cr0, .L_dsmiss_found_pte
697 /* Not found in PTEG, we must scan 2nd then give up */
699 andi. tmp1, tmp3, MASK(PTE0_HASH_ID) /* already at 2nd? */
700 bne- .L_dmiss_do_no_hash_exception /* give up */
703 ori tmp3, tmp3, MASK(PTE0_HASH_ID)
704 b .L_dsmiss_find_pte_in_pteg
708 lwz tmp1, 4(tmp2) /* get pte1_t */
709 andi. tmp3, tmp1, MASK(PTE1_CHANGED) /* unchanged, check? */
710 beq- .L_dsmiss_check_prot /* yes, check prot */
713 /* Ok, we've found what we need to, restore and rfi! */
715 mtctr tmp0 /* restore ctr */
718 mtcrf 0x80, tmp3 /* Restore CR0 */
719 mtspr rpa, tmp1 /* set the pte */
720 tlbld tmp0 /* load up tlb */
723 .L_dsmiss_check_prot:
724 /* PTE is unchanged, we must check that we can write */
725 rlwinm. tmp3, tmp1, 30, 0, 1 /* check PP[1] */
726 bge- .L_dsmiss_check_prot_user_kern
727 andi. tmp3, tmp1, 1 /* check PP[0] */
728 beq+ .L_dsmiss_check_prot_ok
730 .L_dmiss_do_prot_exception:
731 /* clean up registers for protection exception... */
733 /* prepare to set DSISR_WRITE_BIT correctly from srr1 info */
734 rlwinm tmp1, tmp3, 9, 6, 6
735 addis tmp1, tmp1, MASK(DSISR_PROT) >> 16
737 /* And the entry into the usual data fault handler ... */
739 mtctr tmp0 /* Restore ctr */
740 andi. tmp2, tmp3, 0xffff /* Clean up srr1 */
741 mtsrr1 tmp2 /* Set srr1 */
746 xoris tmp0, tmp0, MASK(MSR_TGPR)>>16 /* no TGPR */
747 mtcrf 0x80, tmp3 /* Restore CR0 */
748 sync /* Needed on some */
749 mtmsr tmp0 /* reset MSR[TGPR] */
750 b .L_handler300 /* Data Access */
752 /* NB - if we knew we were on a 603e we could test just the MSR_KEY bit */
753 .L_dsmiss_check_prot_user_kern:
755 andi. tmp3, tmp3, MASK(MSR_PR)
756 beq+ .L_dsmiss_check_prot_kern
757 mfspr tmp3, dmiss /* check user privs */
758 mfsrin tmp3, tmp3 /* get excepting SR */
759 andis. tmp3, tmp3, 0x2000 /* Test SR ku bit */
760 beq+ .L_dsmiss_check_prot_ok
761 b .L_dmiss_do_prot_exception
763 .L_dsmiss_check_prot_kern:
764 mfspr tmp3, dmiss /* check kern privs */
766 andis. tmp3, tmp3, 0x4000 /* Test SR Ks bit */
767 bne- .L_dmiss_do_prot_exception
769 .L_dsmiss_check_prot_ok:
770 /* Ok, mark as referenced and changed before resolving the fault */
771 ori tmp1, tmp1, (MASK(PTE1_REFERENCED)|MASK(PTE1_CHANGED))
776 * Instruction address breakpoint
781 mtsprg 2,r13 /* Save R13 */
782 mtsprg 3,r11 /* Save R11 */
783 li r11,T_INSTRUCTION_BKPT /* Set 'rupt code */
784 b .L_exception_entry /* Join common... */
787 * System management interrupt
792 mtsprg 2,r13 /* Save R13 */
793 mtsprg 3,r11 /* Save R11 */
794 li r11,T_SYSTEM_MANAGEMENT /* Set 'rupt code */
795 b .L_exception_entry /* Join common... */
798 ; Altivec Java Mode Assist interrupt
803 mtsprg 2,r13 /* Save R13 */
804 mtsprg 3,r11 /* Save R11 */
805 li r11,T_ALTIVEC_ASSIST /* Set 'rupt code */
806 b .L_exception_entry /* Join common... */
809 ; Thermal interruption
814 mtsprg 2,r13 /* Save R13 */
815 mtsprg 3,r11 /* Save R11 */
816 li r11,T_THERMAL /* Set 'rupt code */
817 b .L_exception_entry /* Join common... */
820 * There is now a large gap of reserved traps
824 * Run mode/ trace exception - single stepping on 601 processors
829 mtsprg 2,r13 /* Save R13 */
830 mtsprg 3,r11 /* Save R11 */
831 li r11,T_RUNMODE_TRACE /* Set 'rupt code */
832 b .L_exception_entry /* Join common... */
835 * .L_exception_entry(type)
837 * This is the common exception handling routine called by any
838 * type of system exception.
840 * ENTRY: via a system exception handler, thus interrupts off, VM off.
841 * r3 has been saved in sprg3 and now contains a number
842 * representing the exception's origins
848 .globl EXT(exception_entry)
849 EXT(exception_entry):
850 .long .L_exception_entry-EXT(ExceptionVectorsStart) /* phys addr of fn */
859 * Here we will save off a mess of registers, the special ones and R0-R12. We use the DCBZ
860 * instruction to clear and allcoate a line in the cache. This way we won't take any cache
861 * misses, so these stores won't take all that long. Except the first line that is because
862 * we can't do a DCBZ if the L1 D-cache is off. The rest we will skip if they are
865 * Note that if we are attempting to sleep (as opposed to nap or doze) all interruptions
868 mfsprg r13,0 /* Load per_proc */
869 lwz r13,next_savearea(r13) /* Get the exception save area */
871 stw r1,saver1(r13) ; Save register 1
872 stw r0,saver0(r13) ; Save register 0
873 dcbtst 0,r13 ; We will need this in a bit
874 mfspr r1,hid0 ; Get HID0
875 mfcr r0 ; Save the CR
876 mtcrf 255,r1 ; Get set to test for cache and sleep
877 bf sleep,notsleep ; Skip if we are not trying to sleep
879 mtcrf 255,r0 ; Restore the CR
880 lwz r0,saver0(r13) ; Restore R0
881 lwz r1,saver1(r13) ; Restore R1
882 mfsprg r13,0 ; Get the per_proc
883 lwz r11,pfAvailable(r13) ; Get back the feature flags
884 mfsprg r13,2 ; Restore R13
885 mtsprg 2,r11 ; Set sprg2 to the features
886 mfsprg r11,3 ; Restore R11
887 rfi ; Jump back into sleep code...
888 .long 0 ; Leave these here please...
899 notsleep: stw r2,saver2(r13) ; Save this one
900 crmove featL1ena,dce ; Copy the cache enable bit
901 rlwinm r2,r1,0,nap+1,doze-1 ; Clear any possible nap and doze bits
902 mtspr hid0,r2 ; Clear the nap/doze bits
903 cmplw r2,r1 ; See if we were napping
904 la r1,saver8(r13) ; Point to the next line in case we need it
905 crnot wasNapping,cr0_eq ; Remember if we were napping
906 mfsprg r2,0 ; Get the per_proc area
907 bf- featL1ena,skipz1 ; L1 cache is disabled...
908 dcbz 0,r1 ; Reserve our line in cache
911 ; Remember, we are setting up CR6 with feature flags
913 skipz1: lwz r1,pfAvailable(r2) ; Get the CPU features flags
914 stw r3,saver3(r13) ; Save this one
915 la r3,savesrr0(r13) ; Point to the last line
916 mtcrf 0xE0,r1 ; Put the features flags (that we care about) in the CR
917 stw r4,saver4(r13) ; Save this one
918 stw r6,saver6(r13) ; Save this one
919 crmove featSMP,pfSMPcapb ; See if we have a PIR
920 stw r8,saver8(r13) ; Save this one
921 crmove featAltivec,pfAltivecb ; Set the Altivec flag
922 mfsrr0 r6 ; Get the interruption SRR0
923 stw r8,saver8(r13) ; Save this one
924 bf- featL1ena,skipz1a ; L1 cache is disabled...
925 dcbz 0,r3 ; Reserve our line in cache
926 skipz1a: crmove featFP,pfFloatb ; Remember that we have floating point
927 stw r7,saver7(r13) ; Save this one
928 lhz r8,PP_CPU_FLAGS(r2) ; Get the flags
929 mfsrr1 r7 ; Get the interrupt SRR1
930 rlwinm r8,r8,(((31-MSR_BE_BIT)+(traceBEb+16+1))&31),MSR_BE_BIT,MSR_BE_BIT ; Set BE bit if special trace is on
931 stw r6,savesrr0(r13) ; Save the SRR0
932 rlwinm r6,r7,(((31-MSR_BE_BIT)+(MSR_PR_BIT+1))&31),MSR_BE_BIT,MSR_BE_BIT ; Move PR bit to BE bit
933 stw r5,saver5(r13) ; Save this one
934 and r8,r6,r8 ; Remove BE bit only if problem state and special tracing on
935 mfsprg r6,2 ; Get interrupt time R13
936 mtsprg 2,r1 ; Set the feature flags
937 andc r7,r7,r8 ; Clear BE bit if special trace is on and PR is set
938 mfsprg r8,3 ; Get rupt time R11
939 stw r7,savesrr1(r13) ; Save SRR1
940 rlwinm. r7,r7,MSR_RI_BIT,MSR_RI_BIT ; Is this a special case access fault?
941 stw r6,saver13(r13) ; Save rupt R1
942 crnot specAccess,cr0_eq ; Set that we are doing a special access if RI is set
943 stw r8,saver11(r13) ; Save rupt time R11
945 getTB: mftbu r6 ; Get the upper timebase
946 mftb r7 ; Get the lower timebase
947 mftbu r8 ; Get the upper one again
948 cmplw r6,r8 ; Did the top tick?
949 bne- getTB ; Yeah, need to get it again...
951 stw r8,ruptStamp(r2) ; Save the top of time stamp
952 stw r8,SAVtime(r13) ; Save the top of time stamp
953 la r6,saver16(r13) ; Point to the next cache line
954 stw r7,ruptStamp+4(r2) ; Save the bottom of time stamp
955 stw r7,SAVtime+4(r13) ; Save the bottom of time stamp
957 bf- featL1ena,skipz2 ; L1 cache is disabled...
958 dcbz 0,r6 ; Allocate in cache
960 stw r9,saver9(r13) ; Save this one
962 stw r10,saver10(r13) ; Save this one
964 mfxer r10 ; Get the XER
966 bf+ wasNapping,notNapping ; Skip if not waking up from nap...
968 lwz r6,napStamp+4(r2) ; Pick up low order nap stamp
969 lis r3,hi16(EXT(machine_idle_ret)) ; Get high part of nap/doze return
970 lwz r5,napStamp(r2) ; and high order
971 subfc r7,r6,r7 ; Subtract low stamp from now
972 lwz r6,napTotal+4(r2) ; Pick up low total
973 subfe r5,r5,r8 ; Subtract high stamp and borrow from now
974 lwz r8,napTotal(r2) ; Pick up the high total
975 addc r6,r6,r7 ; Add low to total
976 ori r3,r3,lo16(EXT(machine_idle_ret)) ; Get low part of nap/doze return
977 adde r8,r8,r5 ; Add high and carry to total
978 stw r6,napTotal+4(r2) ; Save the low total
979 stw r8,napTotal(r2) ; Save the high total
980 stw r3,savesrr0(r13) ; Modify to return to nap/doze exit
982 rlwinm. r3,r1,0,pfSlowNapb,pfSlowNapb ; Should HID1 be restored?
985 lwz r3,pfHID1(r2) ; Get saved HID1 value
986 mtspr hid1, r3 ; Restore HID1
989 rlwinm. r3,r1,0,pfNoL2PFNapb,pfNoL2PFNapb ; Should MSSCR0 be restored?
992 lwz r3,pfMSSCR0(r2) ; Get saved MSSCR0 value
993 mtspr msscr0, r3 ; Restore MSSCR0
997 notNapping: stw r12,saver12(r13) ; Save this one
999 stw r14,saver14(r13) ; Save this one
1000 stw r15,saver15(r13) ; Save this one
1001 la r14,saver24(r13) ; Point to the next block to save into
1002 stw r0,savecr(r13) ; Save rupt CR
1003 mfctr r6 ; Get the CTR
1004 stw r16,saver16(r13) ; Save this one
1005 stw r4,savelr(r13) ; Save rupt LR
1007 bf- featL1ena,skipz4 ; L1 cache is disabled...
1008 dcbz 0,r14 ; Allocate next save area line
1010 stw r17,saver17(r13) ; Save this one
1011 stw r18,saver18(r13) ; Save this one
1012 stw r6,savectr(r13) ; Save rupt CTR
1013 stw r19,saver19(r13) ; Save this one
1014 lis r12,hi16(KERNEL_SEG_REG0_VALUE) ; Get the high half of the kernel SR0 value
1015 mfdar r6 ; Get the rupt DAR
1016 stw r20,saver20(r13) ; Save this one
1018 bf+ specAccess,noSRsave ; Do not save SRs if this is not a special access...
1019 mfsr r14,sr0 ; Get SR0
1020 stw r14,savesr0(r13) ; and save
1021 mfsr r14,sr1 ; Get SR1
1022 stw r14,savesr1(r13) ; and save
1023 mfsr r14,sr2 ; get SR2
1024 stw r14,savesr2(r13) ; and save
1025 mfsr r14,sr3 ; get SR3
1026 stw r14,savesr3(r13) ; and save
1028 noSRsave: mtsr sr0,r12 ; Set the kernel SR0
1029 stw r21,saver21(r13) ; Save this one
1030 addis r12,r12,0x0010 ; Point to the second segment of kernel
1031 stw r10,savexer(r13) ; Save the rupt XER
1032 mtsr sr1,r12 ; Set the kernel SR1
1033 stw r30,saver30(r13) ; Save this one
1034 addis r12,r12,0x0010 ; Point to the third segment of kernel
1035 stw r31,saver31(r13) ; Save this one
1036 mtsr sr2,r12 ; Set the kernel SR2
1037 stw r22,saver22(r13) ; Save this one
1038 addis r12,r12,0x0010 ; Point to the third segment of kernel
1039 stw r23,saver23(r13) ; Save this one
1040 mtsr sr3,r12 ; Set the kernel SR3
1041 stw r24,saver24(r13) ; Save this one
1042 stw r25,saver25(r13) ; Save this one
1043 mfdsisr r7 ; Get the rupt DSISR
1044 stw r26,saver26(r13) ; Save this one
1045 stw r27,saver27(r13) ; Save this one
1046 li r10,emfp0 ; Point to floating point save
1047 stw r28,saver28(r13) ; Save this one
1048 stw r29,saver29(r13) ; Save this one
1049 mfsr r14,sr14 ; Get the copyin/out segment register
1050 stw r6,savedar(r13) ; Save the rupt DAR
1051 bf- featL1ena,skipz5a ; Do not do this if no L1...
1052 dcbz r10,r2 ; Clear and allocate an L1 slot
1054 skipz5a: stw r7,savedsisr(r13) ; Save the rupt code DSISR
1055 stw r11,saveexception(r13) ; Save the exception code
1056 stw r14,savesr14(r13) ; Save copyin/copyout
1060 ; Here we will save some floating point and vector status
1061 ; and we also set a clean default status for a new interrupt level.
1062 ; Note that we assume that emfp0 is on an altivec boundary
1063 ; and that R10 points to it (as a displacemnt from R2).
1066 lis r8,hi16(MASK(MSR_VEC)) ; Get the vector enable bit
1067 mfmsr r6 ; Get the current MSR value
1068 ori r8,r8,lo16(MASK(MSR_FP)) ; Add in the float enable
1069 li r19,0 ; Assume no Altivec
1070 or r7,r6,r8 ; Enable floating point
1071 li r9,0 ; Get set to clear VRSAVE
1075 bf featAltivec,noavec ; No Altivec on this CPU...
1076 addi r14,r10,16 ; Displacement to second vector register
1077 stvxl v0,r10,r2 ; Save a register
1078 stvxl v1,r14,r2 ; Save a second register
1079 mfvscr v0 ; Get the vector status register
1080 la r28,savevscr(r13) ; Point to the status area
1081 vspltish v1,1 ; Turn on the non-Java bit and saturate
1082 stvxl v0,0,r28 ; Save the vector status
1083 vspltisw v0,1 ; Turn on the saturate bit
1084 mfspr r19,vrsave ; Get the VRSAVE register
1085 vxor v1,v1,v0 ; Turn off saturate
1086 mtspr vrsave,r9 ; Clear VRSAVE for each interrupt level
1087 mtvscr v1 ; Set the non-java, no saturate status for new level
1089 lvxl v0,r10,r2 ; Restore first work register
1090 lvxl v1,r14,r2 ; Restore second work register
1092 noavec: stw r19,savevrsave(r13) ; Save the vector register usage flags
1095 ; We need to save the FPSCR as if it is normal context.
1096 ; This is because pending exceptions will cause an exception even if
1097 ; FP is disabled. We need to clear the FPSCR when we first start running in the
1101 bf- featFP,nofpexe ; No possible floating point exceptions...
1103 stfd f0,emfp0(r2) ; Save FPR0
1104 stfd f1,emfp1(r2) ; Save FPR1
1105 mffs f0 ; Get the FPSCR
1106 fsub f1,f1,f1 ; Make a 0
1107 stfd f0,savefpscrpad(r13) ; Save the FPSCR
1108 mtfsf 0xFF,f1 ; Clear it
1109 lfd f0,emfp0(r2) ; Restore FPR0
1110 lfd f1,emfp1(r2) ; Restore FPR1
1112 nofpexe: mtmsr r6 ; Turn off FP and vector
1117 ; Everything is saved at this point, except for FPRs, and VMX registers.
1118 ; Time for us to get a new savearea and then trace interrupt if it is enabled.
1121 li r0,SAVgeneral ; Get the savearea type value
1122 lis r23,hi16(EXT(trcWork)) ; Get the trace work area address
1123 mr r14,r11 ; Save the interrupt code across the call
1124 stb r0,SAVflags+2(r13) ; Mark valid context
1125 ori r23,r23,lo16(EXT(trcWork)) ; Get the rest
1126 rlwinm r22,r11,30,0,31 ; Divide interrupt code by 2
1127 lwz r25,traceMask(r23) ; Get the trace mask
1128 addi r22,r22,10 ; Adjust code so we shift into CR5
1130 bl EXT(save_get_phys) ; Grab a savearea
1132 mfsprg r2,0 ; Get back the per_proc block
1133 rlwnm r7,r25,r22,22,22 ; Set CR5_EQ bit position to 0 if tracing allowed
1134 lhz r19,PP_CPU_NUMBER(r2) ; Get the logical processor number
1135 li r26,0x8 ; Get start of cpu mask
1136 mr r11,r14 ; Get the exception code back
1137 srw r26,r26,r19 ; Get bit position of cpu number
1138 mtcrf 0x04,r7 ; Set CR5 to show trace or not
1139 and. r26,r26,r25 ; See if we trace this cpu
1140 stw r3,next_savearea(r2) ; Remember the savearea we just got for the next rupt
1141 crandc cr5_eq,cr5_eq,cr0_eq ; Turn off tracing if cpu is disabled
1143 ; At this point, we can take another exception and lose nothing.
1146 lwz r0,saver0(r13) ; Get back interrupt time R0 (we need this whether we trace or not)
1148 bne+ cr5,skipTrace ; Skip all of this if no tracing here...
1151 ; We select a trace entry using a compare and swap on the next entry field.
1152 ; Since we do not lock the actual trace buffer, there is a potential that
1153 ; another processor could wrap an trash our entry. Who cares?
1156 lwz r25,traceStart(r23) ; Get the start of trace table
1157 lwz r26,traceEnd(r23) ; Get end of trace table
1159 trcsel: lwarx r20,0,r23 ; Get and reserve the next slot to allocate
1161 addi r22,r20,LTR_size ; Point to the next trace entry
1162 cmplw r22,r26 ; Do we need to wrap the trace table?
1163 bne+ gotTrcEnt ; No wrap, we got us a trace entry...
1165 mr r22,r25 ; Wrap back to start
1167 gotTrcEnt: stwcx. r22,0,r23 ; Try to update the current pointer
1168 bne- trcsel ; Collision, try again...
1171 dcbf 0,r23 ; Force to memory
1175 bf- featL1ena,skipz6 ; L1 cache is disabled...
1176 dcbz 0,r20 ; Clear and allocate first trace line
1180 ; Let us cut that trace entry now.
1184 li r14,32 ; Offset to second line
1186 lwz r16,ruptStamp(r2) ; Get top of time base
1187 lwz r17,ruptStamp+4(r2) ; Get the bottom of time stamp
1189 bf- featL1ena,skipz7 ; L1 cache is disabled...
1190 dcbz r14,r20 ; Zap the second half
1192 skipz7: stw r16,LTR_timeHi(r20) ; Set the upper part of TB
1193 lwz r1,saver1(r13) ; Get back interrupt time R1
1194 stw r17,LTR_timeLo(r20) ; Set the lower part of TB
1195 lwz r18,saver2(r13) ; Get back interrupt time R2
1196 stw r0,LTR_r0(r20) ; Save off register 0
1197 lwz r3,saver3(r13) ; Restore this one
1198 sth r19,LTR_cpu(r20) ; Stash the cpu number
1199 stw r1,LTR_r1(r20) ; Save off register 1
1200 lwz r4,saver4(r13) ; Restore this one
1201 stw r18,LTR_r2(r20) ; Save off register 2
1202 lwz r5,saver5(r13) ; Restore this one
1203 stw r3,LTR_r3(r20) ; Save off register 3
1204 lwz r16,savecr(r13) ; Get the CR value
1205 stw r4,LTR_r4(r20) ; Save off register 4
1206 mfsrr0 r17 ; Get SRR0 back, it is still good
1207 stw r5,LTR_r5(r20) ; Save off register 5
1208 mfsrr1 r18 ; SRR1 is still good in here
1209 stw r16,LTR_cr(r20) ; Save the CR
1210 stw r17,LTR_srr0(r20) ; Save the SSR0
1211 stw r18,LTR_srr1(r20) ; Save the SRR1
1212 mfdar r17 ; Get this back
1213 lwz r16,savelr(r13) ; Get the LR
1214 stw r17,LTR_dar(r20) ; Save the DAR
1215 mfctr r17 ; Get the CTR (still good in register)
1216 stw r16,LTR_lr(r20) ; Save the LR
1218 lwz r17,emfp1(r2) ; (TEST/DEBUG)
1220 stw r17,LTR_ctr(r20) ; Save off the CTR
1221 stw r13,LTR_save(r20) ; Save the savearea
1222 sth r11,LTR_excpt(r20) ; Save the exception type
1224 addi r17,r20,32 ; (TEST/DEBUG)
1225 dcbst br0,r20 ; (TEST/DEBUG)
1226 dcbst br0,r17 ; (TEST/DEBUG)
1231 ; We are done with the trace, except for maybe modifying the exception
1232 ; code later on. So, that means that we need to save R20 and CR5.
1234 ; So, finish setting up the kernel registers now.
1237 skipTrace: lhz r21,PP_CPU_NUMBER(r2) ; Get the logical processor number
1238 lis r12,hi16(EXT(hw_counts)) ; Get the high part of the interrupt counters
1239 lwz r7,savesrr1(r13) ; Get the entering MSR
1240 ori r12,r12,lo16(EXT(hw_counts)) ; Get the low part of the interrupt counters
1241 rlwinm r21,r21,8,20,23 ; Get index to processor counts
1242 mtcrf 0x80,r0 ; Set our CR0 to the high nybble of possible syscall code
1243 rlwinm r6,r0,1,0,31 ; Move sign bit to the end
1244 cmplwi cr1,r11,T_SYSTEM_CALL ; Did we get a system call?
1245 add r12,r12,r21 ; Point to the processor count area
1246 crandc cr0_lt,cr0_lt,cr0_gt ; See if we have R0 equal to 0b10xx...x
1247 lwzx r22,r12,r11 ; Get the old value
1248 cmplwi cr3,r11,T_IN_VAIN ; Was this all in vain? All for nothing?
1249 addi r22,r22,1 ; Count this one
1250 cmplwi cr2,r6,1 ; See if original R0 had the CutTrace request code in it
1251 stwx r22,r12,r11 ; Store it back
1253 beq- cr3,EatRupt ; Interrupt was all for nothing...
1254 cmplwi cr3,r11,T_MACHINE_CHECK ; Did we get a machine check?
1255 bne+ cr1,noCutT ; Not a system call...
1256 bnl+ cr0,noCutT ; R0 not 0b10xxx...x, can not be any kind of magical system call...
1257 rlwinm. r7,r7,0,MSR_PR_BIT,MSR_PR_BIT ; Did we come from user state?
1258 lis r1,hi16(EXT(dgWork)) ; Get the diagnostics flags
1259 beq+ FCisok ; From supervisor state...
1261 ori r1,r1,lo16(EXT(dgWork)) ; Again
1262 lwz r1,dgFlags(r1) ; Get the flags
1263 rlwinm. r1,r1,0,enaUsrFCallb,enaUsrFCallb ; Are they valid?
1266 FCisok: beq- cr2,isCutTrace ; This is a CutTrace system call...
1269 ; Here is where we call the firmware. If it returns T_IN_VAIN, that means
1270 ; that it has handled the interruption. Remember: thou shalt not trash R13
1271 ; or R20 while you are away. Anything else is ok.
1274 lwz r3,saver3(r13) ; Restore the first parameter
1275 bl EXT(FirmwareCall) ; Go handle the firmware call....
1277 cmplwi r3,T_IN_VAIN ; Was it handled?
1278 mfsprg r2,0 ; Restore the per_proc
1279 beq+ EatRupt ; Interrupt was handled...
1280 mr r11,r3 ; Put the rupt code into the right register
1281 b filter ; Go to the normal system call handler...
1286 li r7,-32768 ; Get a 0x8000 for the exception code
1287 bne- cr5,EatRupt ; Tracing is disabled...
1288 sth r7,LTR_excpt(r20) ; Modify the exception type to a CutTrace
1289 b EatRupt ; Time to go home...
1291 ; We are here because we did not have a CutTrace system call
1295 noCutT: beq- cr3,MachineCheck ; Whoa... Machine check...
1298 ; The following interrupts are the only ones that can be redriven
1299 ; by the higher level code or emulation routines.
1302 Redrive: cmplwi cr0,r11,T_IN_VAIN ; Did the signal handler eat the signal?
1303 mfsprg r2,0 ; Get the per_proc block
1304 beq+ cr0,EatRupt ; Bail now if we ate the rupt...
1308 ; Here ss where we check for the other fast-path exceptions: translation exceptions,
1309 ; emulated instructions, etc.
1312 filter: cmplwi cr3,r11,T_ALTIVEC_ASSIST ; Check for an Altivec denorm assist
1313 cmplwi cr4,r11,T_ALIGNMENT ; See if we got an alignment exception
1314 cmplwi cr1,r11,T_PROGRAM ; See if we got a program exception
1315 cmplwi cr2,r11,T_INSTRUCTION_ACCESS ; Check on an ISI
1316 bne+ cr3,noAltivecAssist ; It is not an assist...
1317 b EXT(AltivecAssist) ; It is an assist...
1322 bne+ cr4,noAlignAssist ; No alignment here...
1323 b EXT(AlignAssist) ; Go try to emulate...
1328 bne+ cr1,noEmulate ; No emulation here...
1329 b EXT(Emulate) ; Go try to emulate...
1333 noEmulate: cmplwi cr3,r11,T_CSWITCH ; Are we context switching
1334 cmplwi r11,T_DATA_ACCESS ; Check on a DSI
1335 beq- cr2,DSIorISI ; It is a PTE fault...
1336 beq- cr3,conswtch ; It is a context switch...
1337 bne+ PassUp ; It is not a PTE fault...
1340 ; This call will either handle the fault, in which case it will not
1341 ; return, or return to pass the fault up the line.
1344 DSIorISI: mr r3,r11 ; Move the rupt code
1346 bl EXT(handlePF) ; See if we can handle this fault
1348 lwz r0,savesrr1(r13) ; Get the MSR in use at exception time
1349 mfsprg r2,0 ; Get back per_proc
1350 cmplwi cr1,r3,T_IN_VAIN ; Was it handled?
1351 andi. r4,r0,lo16(MASK(MSR_RI)) ; See if the recover bit is on
1352 mr r11,r3 ; Put interrupt code back into the right register
1353 beq+ cr1,EatRupt ; Yeah, just blast back to the user...
1354 beq+ PassUp ; Not on, normal case...
1356 ; Here is where we handle the "recovery mode" stuff.
1357 ; This is set by an emulation routine to trap any faults when it is fetching data or
1360 ; If we get a fault, we turn off RI, set CR0_EQ to false, bump the PC, and set R0
1361 ; and R1 to the DAR and DSISR, respectively.
1363 lwz r4,savesrr0(r13) ; Get the failing instruction address
1364 lwz r5,savecr(r13) ; Get the condition register
1365 addi r4,r4,4 ; Skip failing instruction
1366 lwz r6,savedar(r13) ; Get the DAR
1367 rlwinm r5,r5,0,3,1 ; Clear CR0_EQ to let emulation code know we failed
1368 lwz r7,savedsisr(r13) ; Grab the DSISR
1369 stw r0,savesrr1(r13) ; Save the result MSR
1370 stw r4,savesrr0(r13) ; Save resume address
1371 stw r5,savecr(r13) ; And the resume CR
1372 stw r6,saver0(r13) ; Pass back the DAR
1373 stw r7,saver1(r13) ; Pass back the DSISR
1374 b EatRupt ; Resume emulated code
1377 ; Here is where we handle the context switch firmware call. The old
1378 ; context has been saved, and the new savearea in in saver3. We will just
1379 ; muck around with the savearea pointers, and then join the exit routine
1385 mr r29,r13 ; Save the save
1386 rlwinm r30,r13,0,0,19 ; Get the start of the savearea block
1387 lwz r5,saver3(r13) ; Switch to the new savearea
1388 lwz r30,SACvrswap(r30) ; get real to virtual translation
1389 mr r13,r5 ; Switch saveareas
1390 xor r27,r29,r30 ; Flip to virtual
1391 stw r27,saver3(r5) ; Push the new savearea to the switch to routine
1392 b EatRupt ; Start it up...
1395 ; Handle machine check here.
1404 lwz r27,savesrr1(r13) ; ?
1405 rlwinm. r11,r27,0,dcmck,dcmck ; ?
1408 mfspr r11,msscr0 ; ?
1412 lwz r27,savesrr1(r13) ; ?
1414 hiccup: cmplw r27,r27 ; ?
1418 oris r11,r11,hi16(dl1hwfm) ; ?
1419 mtspr msscr0,r11 ; ?
1421 rstbsy: mfspr r11,msscr0 ; ?
1423 rlwinm. r11,r11,0,dl1hwf,dl1hwf ; ?
1434 ; Check if the failure was in
1435 ; ml_probe_read. If so, this is expected, so modify the PC to
1436 ; ml_proble_read_mck and then eat the exception.
1438 lwz r30,savesrr0(r13) ; Get the failing PC
1439 lis r28,hi16(EXT(ml_probe_read_mck)) ; High order part
1440 lis r27,hi16(EXT(ml_probe_read)) ; High order part
1441 ori r28,r28,lo16(EXT(ml_probe_read_mck)) ; Get the low part
1442 ori r27,r27,lo16(EXT(ml_probe_read)) ; Get the low part
1443 cmplw r30,r28 ; Check highest possible
1444 cmplw cr1,r30,r27 ; Check lowest
1445 bge- PassUp ; Outside of range
1446 blt- cr1,PassUp ; Outside of range
1448 ; We need to fix up the BATs here because the probe
1449 ; routine messed them all up... As long as we are at it,
1450 ; fix up to return directly to caller of probe.
1453 lis r11,hi16(EXT(shadow_BAT)+shdDBAT) ; Get shadow address
1454 ori r11,r11,lo16(EXT(shadow_BAT)+shdDBAT) ; Get shadow address
1456 lwz r30,0(r11) ; Pick up DBAT 0 high
1457 lwz r28,4(r11) ; Pick up DBAT 0 low
1458 lwz r27,8(r11) ; Pick up DBAT 1 high
1459 lwz r18,16(r11) ; Pick up DBAT 2 high
1460 lwz r11,24(r11) ; Pick up DBAT 3 high
1463 mtdbatu 0,r30 ; Restore DBAT 0 high
1464 mtdbatl 0,r28 ; Restore DBAT 0 low
1465 mtdbatu 1,r27 ; Restore DBAT 1 high
1466 mtdbatu 2,r18 ; Restore DBAT 2 high
1467 mtdbatu 3,r11 ; Restore DBAT 3 high
1470 lwz r27,saver6(r13) ; Get the saved R6 value
1471 mtspr hid0,r27 ; Restore HID0
1474 lwz r28,savelr(r13) ; Get return point
1475 lwz r27,saver0(r13) ; Get the saved MSR
1476 li r30,0 ; Get a failure RC
1477 stw r28,savesrr0(r13) ; Set the return point
1478 stw r27,savesrr1(r13) ; Set the continued MSR
1479 stw r30,saver3(r13) ; Set return code
1480 b EatRupt ; Yum, yum, eat it all up...
1483 * Here's where we come back from some instruction emulator. If we come back with
1484 * T_IN_VAIN, the emulation is done and we should just reload state and directly
1485 * go back to the interrupted code. Otherwise, we'll check to see if
1486 * we need to redrive with a different interrupt, i.e., DSI.
1490 .globl EXT(EmulExit)
1494 cmplwi r11,T_IN_VAIN ; Was it emulated?
1495 lis r1,hi16(SAVredrive) ; Get redrive request
1496 mfsprg r2,0 ; Restore the per_proc area
1497 beq+ EatRupt ; Yeah, just blast back to the user...
1498 lwz r4,SAVflags(r13) ; Pick up the flags
1500 and. r0,r4,r1 ; Check if redrive requested
1501 andc r4,r4,r1 ; Clear redrive
1503 beq+ PassUp ; No redrive, just keep on going...
1505 stw r4,SAVflags(r13) ; Set the flags
1506 b Redrive ; Redrive the exception...
1509 ; Jump into main handler code switching on VM at the same time.
1511 ; We assume kernel data is mapped contiguously in physical
1512 ; memory, otherwise we would need to switch on (at least) virtual data.
1513 ; SRs are already set up.
1518 PassUp: lis r2,hi16(EXT(exception_handlers)) ; Get exception vector address
1519 ori r2,r2,lo16(EXT(exception_handlers)) ; And low half
1520 lwzx r6,r2,r11 ; Get the actual exception handler address
1522 PassUpDeb: mtsrr0 r6 ; Set up the handler address
1523 rlwinm r5,r13,0,0,19 ; Back off to the start of savearea block
1525 mfmsr r3 ; Get our MSR
1526 rlwinm r3,r3,0,MSR_BE_BIT+1,MSR_SE_BIT-1 ; Clear all but the trace bits
1527 li r2,MSR_SUPERVISOR_INT_OFF ; Get our normal MSR value
1528 lwz r5,SACvrswap(r5) ; Get real to virtual conversion
1529 or r2,r2,r3 ; Keep the trace bits if they are on
1530 mr r3,r11 ; Pass the exception code in the paramter reg
1531 mtsrr1 r2 ; Set up our normal MSR value
1532 xor r4,r13,r5 ; Pass up the virtual address of context savearea
1534 rfi ; Launch the exception handler
1536 .long 0 ; Leave these here gol durn it!
1546 * This routine is the only place where we return from an interruption.
1547 * Anyplace else is wrong. Even if I write the code, it's still wrong.
1548 * Feel free to come by and slap me if I do do it--even though I may
1549 * have had a good reason to do it.
1551 * All we need to remember here is that R13 must point to the savearea
1552 * that has the context we need to load up. Translation and interruptions
1555 * This code always loads the context in the savearea pointed to
1556 * by R13. In the process, it throws away the savearea. If there
1557 * is any tomfoolery with savearea stacks, it must be taken care of
1558 * before we get here.
1560 * Speaking of tomfoolery, this is where we synthesize interruptions
1566 EatRupt: mfsprg r29,0 ; Get the per_proc block back
1567 mr r31,r13 ; Move the savearea pointer to the far end of the register set
1569 lwz r30,quickfret(r29) ; Pick up the quick fret list, if any
1571 mfsprg r27,2 ; Get the processor features
1572 lwz r21,savesrr1(r31) ; Get destination MSR
1574 erchkfret: mr. r3,r30 ; Any savearea to quickly release?
1575 beq+ ernoqfret ; No quickfrets...
1576 lwz r30,SAVprev(r30) ; Chain back now
1578 bl EXT(save_ret_phys) ; Put it on the free list
1579 stw r30,quickfret(r29) ; Dequeue previous guy (really, it is ok to wait until after the release)
1580 b erchkfret ; Try the next one...
1585 ernoqfret: mtcrf 0x60,r27 ; Set CRs with thermal facilities
1586 rlwinm. r0,r21,0,MSR_EE_BIT,MSR_EE_BIT ; Are interruptions going to be enabled?
1587 crandc 31,pfThermalb,pfThermIntb ; See if we have both thermometer and not interrupt facility
1588 la r21,saver0(r31) ; Point to the first thing we restore
1589 crandc 31,cr0_eq,31 ; Factor in enablement
1590 bf 31,tempisok ; No thermal checking needed...
1593 ; We get to here if 1) there is a thermal facility, and 2) the hardware
1594 ; will or cannot interrupt, and 3) the interrupt will be enabled after this point.
1597 mfspr r16,thrm3 ; Get thermal 3
1598 mfspr r14,thrm1 ; Get thermal 2
1599 rlwinm. r16,r16,0,thrme,thrme ; Is the themometer enabled?
1600 mfspr r15,thrm2 ; Get thermal 2
1601 beq- tempisok ; No thermometer...
1602 rlwinm r16,r14,2,28,31 ; Cluster THRM1s TIE, V, TIN, and TIV at bottom 4 bits
1603 srawi r0,r15,31 ; Make a mask of 1s if temprature over
1604 rlwinm r30,r15,2,28,31 ; Cluster THRM2s TIE, V, TIN, and TIV at bottom 4 bits
1606 ; Note that the following compare check that V, TIN, and TIV are set and that TIE is cleared.
1607 ; This insures that we only emulate when the hardware is not set to interrupt.
1609 cmplwi cr0,r16,7 ; Is there a valid pending interruption for THRM1?
1610 cmplwi cr1,r30,7 ; Is there a valid pending interruption for THRM2?
1611 and r15,r15,r0 ; Keep high temp if that interrupted, zero if not
1612 cror cr0_eq,cr0_eq,cr1_eq ; Merge both
1613 andc r14,r14,r0 ; Keep low if high did not interrupt, zero if it did
1614 bne+ tempisok ; Nope, temprature is in range
1616 li r11,T_THERMAL ; Time to emulate a thermal interruption
1617 or r14,r14,r15 ; Get contents of interrupting register
1618 mr r13,r31 ; Make sure savearea is pointed to correctly
1619 stw r11,saveexception(r31) ; Set the exception code
1620 stw r14,savedar(r31) ; Set the contents of the interrupting register into the dar
1623 ; This code is here to prevent a problem that will probably never happen. If we are
1624 ; returning from an emulation routine (alignment, altivec assist, etc.) the SRs may
1625 ; not be set to the proper kernel values. Then, if we were to emulate a thermal here,
1626 ; we would end up running in the kernel with a bogus SR. So, to prevent
1627 ; this unfortunate circumstance, we slam the SRs here. (I worry too much...)
1630 lis r30,hi16(KERNEL_SEG_REG0_VALUE) ; Get the high half of the kernel SR0 value
1631 mtsr sr0,r30 ; Set the kernel SR0
1632 addis r30,r30,0x0010 ; Point to the second segment of kernel
1633 mtsr sr1,r30 ; Set the kernel SR1
1634 addis r30,r30,0x0010 ; Point to the third segment of kernel
1635 mtsr sr2,r30 ; Set the kernel SR2
1636 addis r30,r30,0x0010 ; Point to the third segment of kernel
1637 mtsr sr3,r30 ; Set the kernel SR3
1638 b Redrive ; Go process this new interruption...
1641 tempisok: dcbt 0,r21 ; Touch in the first thing we need
1644 ; Here we release the savearea.
1646 ; Important!!!! The savearea is released before we are done with it. When the
1647 ; local free savearea list (anchored at lclfree) gets too long, save_ret_phys
1648 ; will trim the list, making the extra saveareas allocatable by another processor
1649 ; The code in there must ALWAYS leave our savearea on the local list, otherwise
1650 ; we could be very, very unhappy. The code there always queues the "just released"
1651 ; savearea to the head of the local list. Then, if it needs to trim, it will
1652 ; start with the SECOND savearea, leaving ours intact.
1654 ; Build the SR values depending upon destination. If we are going to the kernel,
1655 ; the SRs are almost all the way set up. SR14 (or the currently used copyin/out register)
1656 ; must be set to whatever it was at the last exception because it varies. All the rest
1657 ; have been set up already.
1659 ; If we are going into user space, we need to check a bit more. SR0, SR1, SR2, and
1660 ; SR14 (current implementation) must be restored always. The others must be set if
1661 ; they are different that what was loaded last time (i.e., tasks have switched).
1662 ; We check the last loaded address space ID and if the same, we skip the loads.
1663 ; This is a performance gain because SR manipulations are slow.
1665 ; There is also the special case when MSR_RI is set. This happens when we are trying to
1666 ; make a special user state access when we are in the kernel. If we take an exception when
1667 ; during that, the SRs may have been modified. Therefore, we need to restore them to
1668 ; what they were before the exception because they could be non-standard. We saved them
1669 ; during exception entry, so we will just load them here.
1672 mr r3,r31 ; Get the exiting savearea in parm register
1673 bl EXT(save_ret_phys) ; Put it on the free list
1675 li r3,savesrr1 ; Get offset to the srr1 value
1677 lwarx r26,r3,r31 ; Get destination MSR and take reservation along the way (just so we can blow it away)
1678 lwz r7,PP_USERPMAP(r29) ; Pick up the user pmap we may launch
1679 rlwinm. r17,r26,0,MSR_RI_BIT,MSR_RI_BIT ; See if we are returning from a special fault
1680 cmplw cr3,r14,r14 ; Set that we do not need to stop streams
1682 beq+ nSpecAcc ; Do not reload the kernel SRs if this is not a special access...
1684 lwz r14,savesr0(r31) ; Get SR0 at fault time
1685 mtsr sr0,r14 ; Set SR0
1686 lwz r14,savesr1(r31) ; Get SR1 at fault time
1687 mtsr sr1,r14 ; Set SR1
1688 lwz r14,savesr2(r31) ; Get SR2 at fault time
1689 mtsr sr2,r14 ; Set SR2
1690 lwz r14,savesr3(r31) ; Get SR3 at fault timee
1691 mtsr sr3,r14 ; Set SR3
1692 b segsdone ; We are all set up now...
1696 nSpecAcc: rlwinm. r17,r26,0,MSR_PR_BIT,MSR_PR_BIT ; See if we are going to user or system
1697 li r14,PMAP_SEGS ; Point to segments
1698 bne+ gotouser ; We are going into user state...
1700 lwz r14,savesr14(r31) ; Get the copyin/out register at interrupt time
1701 mtsr sr14,r14 ; Set SR14
1702 b segsdone ; We are all set up now...
1706 gotouser: dcbt r14,r7 ; Touch the segment register contents
1707 lwz r9,spcFlags(r29) ; Pick up the special flags
1708 lwz r16,PP_LASTPMAP(r29) ; Pick up the last loaded pmap
1709 addi r14,r14,32 ; Second half of pmap segments
1710 rlwinm r9,r9,userProtKeybit-2,2,2 ; Isolate the user state protection key
1711 lwz r15,PMAP_SPACE(r7) ; Get the primary space
1712 lwz r13,PMAP_VFLAGS(r7) ; Get the flags
1713 dcbt r14,r7 ; Touch second page
1714 oris r15,r15,hi16(SEG_REG_PROT) ; Set segment 0 SR value
1715 mtcrf 0x0F,r13 ; Set CRs to correspond to the subordinate spaces
1716 xor r15,r15,r9 ; Flip to proper segment register key
1717 lhz r9,PP_CPU_FLAGS(r29) ; Get the processor flags
1719 addis r13,r15,0x0000 ; Get SR0 value
1720 bf 16,nlsr0 ; No alternate here...
1721 lwz r13,PMAP_SEGS+(0*4)(r7) ; Get SR0 value
1723 nlsr0: mtsr sr0,r13 ; Load up the SR
1724 rlwinm r9,r9,(((31-MSR_BE_BIT)+(traceBEb+16+1))&31),MSR_BE_BIT,MSR_BE_BIT ; Set BE bit if special trace is on
1726 addis r13,r15,0x0010 ; Get SR1 value
1727 bf 17,nlsr1 ; No alternate here...
1728 lwz r13,PMAP_SEGS+(1*4)(r7) ; Get SR1 value
1730 nlsr1: mtsr sr1,r13 ; Load up the SR
1731 or r26,r26,r9 ; Flip on the BE bit for special trace if needed
1733 cmplw cr3,r7,r16 ; Are we running the same segs as last time?
1735 addis r13,r15,0x0020 ; Get SR2 value
1736 bf 18,nlsr2 ; No alternate here...
1737 lwz r13,PMAP_SEGS+(2*4)(r7) ; Get SR2 value
1739 nlsr2: mtsr sr2,r13 ; Load up the SR
1741 addis r13,r15,0x0030 ; Get SR3 value
1742 bf 19,nlsr3 ; No alternate here...
1743 lwz r13,PMAP_SEGS+(3*4)(r7) ; Get SR3 value
1745 nlsr3: mtsr sr3,r13 ; Load up the SR
1747 addis r13,r15,0x00E0 ; Get SR14 value
1748 bf 30,nlsr14 ; No alternate here...
1749 lwz r13,PMAP_SEGS+(14*4)(r7) ; Get SR14 value
1751 nlsr14: mtsr sr14,r13 ; Load up the SR
1753 beq+ cr3,segsdone ; All done if same pmap as last time...
1755 stw r7,PP_LASTPMAP(r29) ; Remember what we just loaded
1757 addis r13,r15,0x0040 ; Get SR4 value
1758 bf 20,nlsr4 ; No alternate here...
1759 lwz r13,PMAP_SEGS+(4*4)(r7) ; Get SR4 value
1761 nlsr4: mtsr sr4,r13 ; Load up the SR
1763 addis r13,r15,0x0050 ; Get SR5 value
1764 bf 21,nlsr5 ; No alternate here...
1765 lwz r13,PMAP_SEGS+(5*4)(r7) ; Get SR5 value
1767 nlsr5: mtsr sr5,r13 ; Load up the SR
1769 addis r13,r15,0x0060 ; Get SR6 value
1770 bf 22,nlsr6 ; No alternate here...
1771 lwz r13,PMAP_SEGS+(6*4)(r7) ; Get SR6 value
1773 nlsr6: mtsr sr6,r13 ; Load up the SR
1775 addis r13,r15,0x0070 ; Get SR7 value
1776 bf 23,nlsr7 ; No alternate here...
1777 lwz r13,PMAP_SEGS+(7*4)(r7) ; Get SR7 value
1779 nlsr7: mtsr sr7,r13 ; Load up the SR
1781 addis r13,r15,0x0080 ; Get SR8 value
1782 bf 24,nlsr8 ; No alternate here...
1783 lwz r13,PMAP_SEGS+(8*4)(r7) ; Get SR8 value
1785 nlsr8: mtsr sr8,r13 ; Load up the SR
1787 addis r13,r15,0x0090 ; Get SR9 value
1788 bf 25,nlsr9 ; No alternate here...
1789 lwz r13,PMAP_SEGS+(9*4)(r7) ; Get SR9 value
1791 nlsr9: mtsr sr9,r13 ; Load up the SR
1793 addis r13,r15,0x00A0 ; Get SR10 value
1794 bf 26,nlsr10 ; No alternate here...
1795 lwz r13,PMAP_SEGS+(10*4)(r7) ; Get SR10 value
1797 nlsr10: mtsr sr10,r13 ; Load up the SR
1799 addis r13,r15,0x00B0 ; Get SR11 value
1800 bf 27,nlsr11 ; No alternate here...
1801 lwz r13,PMAP_SEGS+(11*4)(r7) ; Get SR11 value
1803 nlsr11: mtsr sr11,r13 ; Load up the SR
1805 addis r13,r15,0x00C0 ; Get SR12 value
1806 bf 28,nlsr12 ; No alternate here...
1807 lwz r13,PMAP_SEGS+(12*4)(r7) ; Get SR12 value
1809 nlsr12: mtsr sr12,r13 ; Load up the SR
1811 addis r13,r15,0x00D0 ; Get SR13 value
1812 bf 29,nlsr13 ; No alternate here...
1813 lwz r13,PMAP_SEGS+(13*4)(r7) ; Get SR13 value
1815 nlsr13: mtsr sr13,r13 ; Load up the SR
1817 addis r13,r15,0x00F0 ; Get SR15 value
1818 bf 31,nlsr15 ; No alternate here...
1819 lwz r13,PMAP_SEGS+(15*4)(r7) ; Get SR15 value
1821 nlsr15: mtsr sr15,r13 ; Load up the SR
1823 segsdone: stwcx. r26,r3,r31 ; Blow away any reservations we hold
1825 li r21,emfp0 ; Point to the fp savearea
1826 lwz r25,savesrr0(r31) ; Get the SRR0 to use
1827 la r28,saver8(r31) ; Point to the next line to use
1828 dcbt r21,r29 ; Start moving in a work area
1829 lwz r0,saver0(r31) ; Restore R0
1830 dcbt 0,r28 ; Touch it in
1831 lwz r1,saver1(r31) ; Restore R1
1832 lwz r2,saver2(r31) ; Restore R2
1833 la r28,saver16(r31) ; Point to the next line to get
1834 lwz r3,saver3(r31) ; Restore R3
1835 mtcrf 0x80,r27 ; Get facility availability flags (do not touch CR1-7)
1836 lwz r4,saver4(r31) ; Restore R4
1837 mtsrr0 r25 ; Restore the SRR0 now
1838 lwz r5,saver5(r31) ; Restore R5
1839 mtsrr1 r26 ; Restore the SRR1 now
1840 lwz r6,saver6(r31) ; Restore R6
1842 dcbt 0,r28 ; Touch that next line on in
1843 la r28,savevscr(r31) ; Point to the saved facility context
1845 lwz r7,saver7(r31) ; Restore R7
1846 lwz r8,saver8(r31) ; Restore R8
1847 lwz r9,saver9(r31) ; Restore R9
1848 mfmsr r26 ; Get the current MSR
1849 dcbt 0,r28 ; Touch saved facility context
1850 lwz r10,saver10(r31) ; Restore R10
1851 lwz r11,saver11(r31) ; Restore R11
1852 oris r26,r26,hi16(MASK(MSR_VEC)) ; Get the vector enable bit
1853 lwz r12,saver12(r31) ; Restore R12
1854 ori r26,r26,lo16(MASK(MSR_FP)) ; Add in the float enable
1855 lwz r13,saver13(r31) ; Restore R13
1856 la r28,saver24(r31) ; Point to the next line to do
1859 ; Note that floating point and vector will be enabled from here on until the RFI
1862 mtmsr r26 ; Turn on vectors and floating point
1865 dcbt 0,r28 ; Touch next line to do
1867 lwz r14,saver14(r31) ; Restore R14
1868 lwz r15,saver15(r31) ; Restore R15
1870 bf pfAltivecb,noavec3 ; No Altivec on this CPU...
1872 la r28,savevscr(r31) ; Point to the status area
1873 stvxl v0,r21,r29 ; Save a vector register
1874 lvxl v0,0,r28 ; Get the vector status
1875 lwz r27,savevrsave(r31) ; Get the vrsave
1876 mtvscr v0 ; Set the vector status
1878 lvxl v0,r21,r29 ; Restore work vector register
1879 beq+ cr3,noavec2 ; SRs have not changed, no need to stop the streams...
1880 dssall ; Kill all data streams
1883 noavec2: mtspr vrsave,r27 ; Set the vrsave
1885 noavec3: bf- pfFloatb,nofphere ; Skip if no floating point...
1887 stfd f0,emfp0(r29) ; Save FP0
1888 lfd f0,savefpscrpad(r31) ; Get the fpscr
1889 mtfsf 0xFF,f0 ; Restore fpscr
1890 lfd f0,emfp0(r29) ; Restore the used register
1892 nofphere: lwz r16,saver16(r31) ; Restore R16
1893 lwz r17,saver17(r31) ; Restore R17
1894 lwz r18,saver18(r31) ; Restore R18
1895 lwz r19,saver19(r31) ; Restore R19
1896 lwz r20,saver20(r31) ; Restore R20
1897 lwz r21,saver21(r31) ; Restore R21
1898 lwz r22,saver22(r31) ; Restore R22
1900 lwz r23,saver23(r31) ; Restore R23
1901 lwz r24,saver24(r31) ; Restore R24
1902 lwz r25,saver25(r31) ; Restore R25
1903 lwz r26,saver26(r31) ; Restore R26
1904 lwz r27,saver27(r31) ; Restore R27
1906 lwz r28,savecr(r31) ; Get CR to restore
1908 lwz r29,savexer(r31) ; Get XER to restore
1909 mtcr r28 ; Restore the CR
1910 lwz r28,savelr(r31) ; Get LR to restore
1911 mtxer r29 ; Restore the XER
1912 lwz r29,savectr(r31) ; Get the CTR to restore
1913 mtlr r28 ; Restore the LR
1914 lwz r28,saver30(r31) ; Get R30
1915 mtctr r29 ; Restore the CTR
1916 lwz r29,saver31(r31) ; Get R31
1917 mtsprg 2,r28 ; Save R30 for later
1918 lwz r28,saver28(r31) ; Restore R28
1919 mtsprg 3,r29 ; Save R31 for later
1920 lwz r29,saver29(r31) ; Restore R29
1922 mfsprg r31,0 ; Get per_proc
1923 mfsprg r30,2 ; Restore R30
1924 lwz r31,pfAvailable(r31) ; Get the feature flags
1925 mtsprg 2,r31 ; Set the feature flags
1926 mfsprg r31,3 ; Restore R31
1928 rfi ; Click heels three times and think very hard that there is no place like home...
1930 .long 0 ; Leave this here
1943 * exception_exit(savearea *)
1946 * ENTRY : IR and/or DR and/or interruptions can be on
1947 * R3 points to the physical address of a savearea
1951 .globl EXT(exception_exit)
1953 LEXT(exception_exit)
1955 mfsprg r29,2 ; Get feature flags
1956 mfmsr r30 ; Get the current MSR
1957 mtcrf 0x04,r29 ; Set the features
1958 rlwinm r30,r30,0,MSR_FP_BIT+1,MSR_FP_BIT-1 ; Force floating point off
1959 mr r31,r3 ; Get the savearea in the right register
1960 rlwinm r30,r30,0,MSR_VEC_BIT+1,MSR_VEC_BIT-1 ; Force vectors off
1961 li r10,savesrr0 ; Point to one of the first things we touch in the savearea on exit
1962 andi. r30,r30,0x7FCF ; Turn off externals, IR, and DR
1963 lis r1,hi16(SAVredrive) ; Get redrive request
1965 bt pfNoMSRirb,eeNoMSR ; No MSR...
1967 mtmsr r30 ; Translation and all off
1968 isync ; Toss prefetch
1971 eeNoMSR: li r0,loadMSR ; Get the MSR setter SC
1972 mr r3,r30 ; Get new MSR
1975 eeNoMSRx: dcbt r10,r31 ; Touch in the first stuff we restore
1976 mfsprg r2,0 ; Get the per_proc block
1977 lwz r4,SAVflags(r31) ; Pick up the flags
1978 mr r13,r31 ; Put savearea here also
1980 and. r0,r4,r1 ; Check if redrive requested
1981 andc r4,r4,r1 ; Clear redrive
1983 dcbt br0,r2 ; We will need this in just a sec
1985 beq+ EatRupt ; No redrive, just exit...
1987 lwz r11,saveexception(r13) ; Restore exception code
1988 stw r4,SAVflags(r13) ; Set the flags
1989 b Redrive ; Redrive the exception...
1993 * Start of the trace table
1996 .align 12 /* Align to 4k boundary */
1998 .globl EXT(traceTableBeg)
1999 EXT(traceTableBeg): /* Start of trace table */
2000 /* .fill 2048,4,0 Make an 8k trace table for now */
2001 .fill 13760,4,0 /* Make an .trace table for now */
2002 /* .fill 240000,4,0 Make an .trace table for now */
2003 .globl EXT(traceTableEnd)
2004 EXT(traceTableEnd): /* End of trace table */
2006 .globl EXT(ExceptionVectorsEnd)
2007 EXT(ExceptionVectorsEnd): /* Used if relocating the exception vectors */
2008 #ifndef HACKALERTHACKALERT
2010 * This .long needs to be here because the linker gets confused and tries to
2011 * include the final label in a section in the next section if there is nothing
2014 .long 0 /* (HACK/HACK/HACK) */
2019 .globl EXT(exception_end)
2021 .long EXT(ExceptionVectorsEnd) -EXT(ExceptionVectorsStart) /* phys fn */