Source to osfmk/ppc/lowmem_vectors.s
/*
* Copyright (c) 2000 Apple Computer, Inc. All rights reserved.
*
* @APPLE_LICENSE_HEADER_START@
*
* The contents of this file constitute Original Code as defined in and
* are subject to the Apple Public Source License Version 1.1 (the
* "License"). You may not use this file except in compliance with the
* License. Please obtain a copy of the License at
* http://www.apple.com/publicsource and read it before using this file.
*
* This Original Code and all software distributed under the License are
* distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER
* EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
* INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the
* License for the specific language governing rights and limitations
* under the License.
*
* @APPLE_LICENSE_HEADER_END@
*/
/*
* @OSF_COPYRIGHT@
*/
/*
* Low-memory exception vector code for PowerPC MACH
*
* These are the only routines that are ever run with
* VM instruction translation switched off.
*
* The PowerPC is quite strange in that rather than having a set
* of exception vectors, the exception handlers are installed
* in well-known addresses in low memory. This code must be loaded
* at ZERO in physical memory. The simplest way of doing this is
* to load the kernel at zero, and specify this as the first file
* on the linker command line.
*
* When this code is loaded into place, it is loaded at virtual
* address KERNELBASE, which is mapped to zero (physical).
*
* This code handles all powerpc exceptions and is always entered
* in supervisor mode with translation off. It saves the minimum
* processor state before switching back on translation and
* jumping to the approprate routine.
*
* Vectors from 0x100 to 0x3fff occupy 0x100 bytes each (64 instructions)
*
* We use some of this space to decide which stack to use, and where to
* save the context etc, before jumping to a generic handler.
*/
#include <assym.s>
#include <debug.h>
#include <cpus.h>
#include <db_machine_commands.h>
#include <mach_rt.h>
#include <mach_debug.h>
#include <ppc/asm.h>
#include <ppc/proc_reg.h>
#include <ppc/exception.h>
#include <ppc/Performance.h>
#include <mach/ppc/vm_param.h>
#include <ppc/POWERMAC/mp/MPPlugIn.h>
#define RUPTTRC 0
#define CHECKSAVE 0
#define PERFTIMES 0
#define ESPDEBUG 0
#define VECTOR_SEGMENT .section __VECTORS, __interrupts
VECTOR_SEGMENT
.globl EXT(ExceptionVectorsStart)
EXT(ExceptionVectorsStart): /* Used if relocating the exception vectors */
baseR: /* Used so we have more readable code */
/*
* System reset - call debugger
*/
. = 0xf0
.globl EXT(ResetHandler)
EXT(ResetHandler):
.long 0x0
.long 0x0
.long 0x0
. = 0x100
.L_handler100:
mtsprg 2,r13 /* Save R13 */
mtsprg 3,r11 /* Save R11 */
lwz r13,lo16(EXT(ResetHandler)-EXT(ExceptionVectorsStart)+RESETHANDLER_TYPE)(br0) ; Get reset type
mfcr r11
cmpi cr0,r13,RESET_HANDLER_START
bne resetexc
li r11,RESET_HANDLER_NULL
stw r11,lo16(EXT(ResetHandler)-EXT(ExceptionVectorsStart)+RESETHANDLER_TYPE)(br0) ; Clear reset type
lwz r4,lo16(EXT(ResetHandler)-EXT(ExceptionVectorsStart)+RESETHANDLER_CALL)(br0)
lwz r3,lo16(EXT(ResetHandler)-EXT(ExceptionVectorsStart)+RESETHANDLER_ARG)(br0)
mtlr r4
blr
resetexc:
mtcr r11
mfsprg r13,1 /* Get the exception save area */
li r11,T_RESET /* Set 'rupt code */
b .L_exception_entry /* Join common... */
/*
* This is the data used by the exception trace code
*/
. = 0x180
.L_TraceData:
.globl traceMask
traceMask: /* Allowable trace types indexed by vector >> 8 */
#if DEBUG
/* .long 0x02000000 */ /* Only alignment exceptions enabled */
.long 0xFFFFFFFF /* All enabled */
/* .long 0xFBBFFFFF */ /* EXT and DEC disabled */
/* .long 0xFFBFFFFF */ /* DEC disabled */
#else
.long 0x00000000 ; All disabled on non-debug systems
#endif
.globl EXT(traceCurr)
EXT(traceCurr): .long traceTableBeg-EXT(ExceptionVectorsStart) /* The next trace entry to use */
.globl EXT(traceStart)
EXT(traceStart): .long traceTableBeg-EXT(ExceptionVectorsStart) /* Start of the trace table */
.globl EXT(traceEnd)
EXT(traceEnd):
.long traceTableEnd-EXT(ExceptionVectorsStart) /* End (wrap point) of the trace */
.globl traceMsnd
traceMsnd: .long 0 /* Saved mask while in debugger */
/*
* Machine check (physical bus error) - call debugger
*/
. = 0x200
.L_handler200:
mtsprg 2,r13 /* Save R13 */
mtsprg 3,r11 /* Save R11 */
mfsprg r13,1 /* Get the exception save area */
li r11,T_MACHINE_CHECK /* Set 'rupt code */
b .L_exception_entry /* Join common... */
/*
* Data access - page fault, invalid memory rights for operation
*/
. = 0x300
.L_handler300:
mtsprg 2,r13 /* Save R13 */
mtsprg 3,r11 /* Save R11 */
mfsprg r13,1 /* Get the exception save area */
li r11,T_DATA_ACCESS /* Set 'rupt code */
b .L_exception_entry /* Join common... */
/*
* Instruction access - as for data access
*/
. = 0x400
.L_handler400:
mtsprg 2,r13 /* Save R13 */
mtsprg 3,r11 /* Save R11 */
mfsprg r13,1 /* Get the exception save area */
li r11,T_INSTRUCTION_ACCESS /* Set 'rupt code */
b .L_exception_entry /* Join common... */
/*
* External interrupt
*/
. = 0x500
.L_handler500:
mtsprg 2,r13 /* Save R13 */
mtsprg 3,r11 /* Save R11 */
mfsprg r13,1 /* Get the exception save area */
li r11,T_INTERRUPT /* Set 'rupt code */
b .L_exception_entry /* Join common... */
/*
* Alignment - many reasons
*/
. = 0x600
.L_handler600:
mtsprg 2,r13 /* Save R13 */
mtsprg 3,r11 /* Save R11 */
mfsprg r13,1 /* Get the exception save area */
li r11,T_ALIGNMENT /* Set 'rupt code */
b .L_exception_entry /* Join common... */
/*
* Program - floating point exception, illegal inst, priv inst, user trap
*/
. = 0x700
.L_handler700:
mtsprg 2,r13 /* Save R13 */
mtsprg 3,r11 /* Save R11 */
mfsprg r13,1 /* Get the exception save area */
li r11,T_PROGRAM /* Set 'rupt code */
b .L_exception_entry /* Join common... */
/*
* Floating point disabled
*/
. = 0x800
.L_handler800:
mtsprg 2,r13 /* Save R13 */
mtsprg 3,r11 /* Save R11 */
mfsprg r13,1 /* Get the exception save area */
li r11,T_FP_UNAVAILABLE /* Set 'rupt code */
b .L_exception_entry /* Join common... */
/*
* Decrementer - DEC register has passed zero.
*/
. = 0x900
.L_handler900:
mtsprg 2,r13 /* Save R13 */
mtsprg 3,r11 /* Save R11 */
mfsprg r13,1 /* Get the exception save area */
li r11,T_DECREMENTER /* Set 'rupt code */
b .L_exception_entry /* Join common... */
/*
* I/O controller interface error - MACH does not use this
*/
. = 0xA00
.L_handlerA00:
mtsprg 2,r13 /* Save R13 */
mtsprg 3,r11 /* Save R11 */
mfsprg r13,1 /* Get the exception save area */
li r11,T_IO_ERROR /* Set 'rupt code */
b .L_exception_entry /* Join common... */
/*
* Reserved
*/
. = 0xB00
.L_handlerB00:
mtsprg 2,r13 /* Save R13 */
mtsprg 3,r11 /* Save R11 */
mfsprg r13,1 /* Get the exception save area */
li r11,T_RESERVED /* Set 'rupt code */
b .L_exception_entry /* Join common... */
/*
* System call - generated by the sc instruction
*/
. = 0xC00
.L_handlerC00:
cmplwi r0,0x7FF2 ; Ultra fast path cthread info call?
blt+ notufp ; Not ultra fast...
cmplwi r0,0x7FF3 ; Ultra fast path fp/vec facility state?
bgt+ notufp ; Not ultra fast...
mfsprg r3,0 ; Get the per_proc_area
beq- isvecfp ; This is the facility stat call
lwz r3,UAW(r3) ; Get the assist word
rfi ; All done, scream back... (no need to restore CR or R11, they are volatile)
;
isvecfp: lwz r3,spcFlags(r3) ; Get the facility status
rfi ; Bail back...
;
.align 5
notufp: mtsprg 3,r11 /* Save R11 */
mtsprg 2,r13 /* Save R13 */
li r11,T_SYSTEM_CALL /* Set 'rupt code */
mfsprg r13,1 /* Get the exception save area */
b .L_exception_entry /* Join common... */
/*
* Trace - generated by single stepping
*/
. = 0xD00
.L_handlerD00:
mtsprg 2,r13 /* Save R13 */
mtsprg 3,r11 /* Save R11 */
mfsprg r13,1 /* Get the exception save area */
li r11,T_TRACE /* Set 'rupt code */
b .L_exception_entry /* Join common... */
/*
* Floating point assist
*/
. = 0xe00
.L_handlerE00:
mtsprg 2,r13 /* Save R13 */
mtsprg 3,r11 /* Save R11 */
mfsprg r13,1 /* Get the exception save area */
li r11,T_FP_ASSIST /* Set 'rupt code */
b .L_exception_entry /* Join common... */
/*
* Performance monitor interruption
*/
. = 0xF00
PMIhandler:
mtsprg 2,r13 /* Save R13 */
mtsprg 3,r11 /* Save R11 */
mfsprg r13,1 /* Get the exception save area */
li r11,T_PERF_MON /* Set 'rupt code */
b .L_exception_entry /* Join common... */
/*
* VMX exception
*/
. = 0xF20
VMXhandler:
mtsprg 2,r13 /* Save R13 */
mtsprg 3,r11 /* Save R11 */
mfsprg r13,1 /* Get the exception save area */
li r11,T_VMX /* Set 'rupt code */
b .L_exception_entry /* Join common... */
/*
* Instruction translation miss - we inline this code.
* Upon entry (done for us by the machine):
* srr0 : addr of instruction that missed
* srr1 : bits 0-3 = saved CR0
* 4 = lru way bit
* 16-31 = saved msr
* msr[tgpr] = 1 (so gpr0-3 become our temporary variables)
* imiss: ea that missed
* icmp : the compare value for the va that missed
* hash1: pointer to first hash pteg
* hash2: pointer to 2nd hash pteg
*
* Register usage:
* tmp0: saved counter
* tmp1: junk
* tmp2: pointer to pteg
* tmp3: current compare value
*
* This code is taken from the 603e User's Manual with
* some bugfixes and minor improvements to save bytes and cycles
*/
. = 0x1000
.L_handler1000:
mfspr tmp2, hash1
mfctr tmp0 /* use tmp0 to save ctr */
mfspr tmp3, icmp
.L_imiss_find_pte_in_pteg:
li tmp1, 8 /* count */
subi tmp2, tmp2, 8 /* offset for lwzu */
mtctr tmp1 /* count... */
.L_imiss_pteg_loop:
lwz tmp1, 8(tmp2) /* check pte0 for match... */
addi tmp2, tmp2, 8
cmpw cr0, tmp1, tmp3
#if 0
bdnzf+ cr0, .L_imiss_pteg_loop
#else
bc 0,2, .L_imiss_pteg_loop
#endif
beq+ cr0, .L_imiss_found_pte
/* Not found in PTEG, we must scan 2nd then give up */
andi. tmp1, tmp3, MASK(PTE0_HASH_ID)
bne- .L_imiss_do_no_hash_exception /* give up */
mfspr tmp2, hash2
ori tmp3, tmp3, MASK(PTE0_HASH_ID)
b .L_imiss_find_pte_in_pteg
.L_imiss_found_pte:
lwz tmp1, 4(tmp2) /* get pte1_t */
andi. tmp3, tmp1, MASK(PTE1_WIMG_GUARD) /* Fault? */
bne- .L_imiss_do_prot_exception /* Guarded - illegal */
/* Ok, we've found what we need to, restore and rfi! */
mtctr tmp0 /* restore ctr */
mfsrr1 tmp3
mfspr tmp0, imiss
mtcrf 0x80, tmp3 /* Restore CR0 */
mtspr rpa, tmp1 /* set the pte */
ori tmp1, tmp1, MASK(PTE1_REFERENCED) /* set referenced */
tlbli tmp0
sth tmp1, 6(tmp2)
rfi
.L_imiss_do_prot_exception:
/* set up srr1 to indicate protection exception... */
mfsrr1 tmp3
andi. tmp2, tmp3, 0xffff
addis tmp2, tmp2, MASK(SRR1_TRANS_PROT) >> 16
b .L_imiss_do_exception
.L_imiss_do_no_hash_exception:
/* clean up registers for protection exception... */
mfsrr1 tmp3
andi. tmp2, tmp3, 0xffff
addis tmp2, tmp2, MASK(SRR1_TRANS_HASH) >> 16
/* And the entry into the usual instruction fault handler ... */
.L_imiss_do_exception:
mtctr tmp0 /* Restore ctr */
mtsrr1 tmp2 /* Set up srr1 */
mfmsr tmp0
xoris tmp0, tmp0, MASK(MSR_TGPR)>>16 /* no TGPR */
mtcrf 0x80, tmp3 /* Restore CR0 */
mtmsr tmp0 /* reset MSR[TGPR] */
b .L_handler400 /* Instr Access */
/*
* Data load translation miss
*
* Upon entry (done for us by the machine):
* srr0 : addr of instruction that missed
* srr1 : bits 0-3 = saved CR0
* 4 = lru way bit
* 5 = 1 if store
* 16-31 = saved msr
* msr[tgpr] = 1 (so gpr0-3 become our temporary variables)
* dmiss: ea that missed
* dcmp : the compare value for the va that missed
* hash1: pointer to first hash pteg
* hash2: pointer to 2nd hash pteg
*
* Register usage:
* tmp0: saved counter
* tmp1: junk
* tmp2: pointer to pteg
* tmp3: current compare value
*
* This code is taken from the 603e User's Manual with
* some bugfixes and minor improvements to save bytes and cycles
*/
. = 0x1100
.L_handler1100:
mfspr tmp2, hash1
mfctr tmp0 /* use tmp0 to save ctr */
mfspr tmp3, dcmp
.L_dlmiss_find_pte_in_pteg:
li tmp1, 8 /* count */
subi tmp2, tmp2, 8 /* offset for lwzu */
mtctr tmp1 /* count... */
.L_dlmiss_pteg_loop:
lwz tmp1, 8(tmp2) /* check pte0 for match... */
addi tmp2, tmp2, 8
cmpw cr0, tmp1, tmp3
#if 0 /* How to write this correctly? */
bdnzf+ cr0, .L_dlmiss_pteg_loop
#else
bc 0,2, .L_dlmiss_pteg_loop
#endif
beq+ cr0, .L_dmiss_found_pte
/* Not found in PTEG, we must scan 2nd then give up */
andi. tmp1, tmp3, MASK(PTE0_HASH_ID) /* already at 2nd? */
bne- .L_dmiss_do_no_hash_exception /* give up */
mfspr tmp2, hash2
ori tmp3, tmp3, MASK(PTE0_HASH_ID)
b .L_dlmiss_find_pte_in_pteg
.L_dmiss_found_pte:
lwz tmp1, 4(tmp2) /* get pte1_t */
/* Ok, we've found what we need to, restore and rfi! */
mtctr tmp0 /* restore ctr */
mfsrr1 tmp3
mfspr tmp0, dmiss
mtcrf 0x80, tmp3 /* Restore CR0 */
mtspr rpa, tmp1 /* set the pte */
ori tmp1, tmp1, MASK(PTE1_REFERENCED) /* set referenced */
tlbld tmp0 /* load up tlb */
sth tmp1, 6(tmp2) /* sth is faster? */
rfi
/* This code is shared with data store translation miss */
.L_dmiss_do_no_hash_exception:
/* clean up registers for protection exception... */
mfsrr1 tmp3
/* prepare to set DSISR_WRITE_BIT correctly from srr1 info */
rlwinm tmp1, tmp3, 9, 6, 6
addis tmp1, tmp1, MASK(DSISR_HASH) >> 16
/* And the entry into the usual data fault handler ... */
mtctr tmp0 /* Restore ctr */
andi. tmp2, tmp3, 0xffff /* Clean up srr1 */
mtsrr1 tmp2 /* Set srr1 */
mtdsisr tmp1
mfspr tmp2, dmiss
mtdar tmp2
mfmsr tmp0
xoris tmp0, tmp0, MASK(MSR_TGPR)>>16 /* no TGPR */
mtcrf 0x80, tmp3 /* Restore CR0 */
sync /* Needed on some */
mtmsr tmp0 /* reset MSR[TGPR] */
b .L_handler300 /* Data Access */
/*
* Data store translation miss (similar to data load)
*
* Upon entry (done for us by the machine):
* srr0 : addr of instruction that missed
* srr1 : bits 0-3 = saved CR0
* 4 = lru way bit
* 5 = 1 if store
* 16-31 = saved msr
* msr[tgpr] = 1 (so gpr0-3 become our temporary variables)
* dmiss: ea that missed
* dcmp : the compare value for the va that missed
* hash1: pointer to first hash pteg
* hash2: pointer to 2nd hash pteg
*
* Register usage:
* tmp0: saved counter
* tmp1: junk
* tmp2: pointer to pteg
* tmp3: current compare value
*
* This code is taken from the 603e User's Manual with
* some bugfixes and minor improvements to save bytes and cycles
*/
. = 0x1200
.L_handler1200:
mfspr tmp2, hash1
mfctr tmp0 /* use tmp0 to save ctr */
mfspr tmp3, dcmp
.L_dsmiss_find_pte_in_pteg:
li tmp1, 8 /* count */
subi tmp2, tmp2, 8 /* offset for lwzu */
mtctr tmp1 /* count... */
.L_dsmiss_pteg_loop:
lwz tmp1, 8(tmp2) /* check pte0 for match... */
addi tmp2, tmp2, 8
cmpw cr0, tmp1, tmp3
#if 0 /* I don't know how to write this properly */
bdnzf+ cr0, .L_dsmiss_pteg_loop
#else
bc 0,2, .L_dsmiss_pteg_loop
#endif
beq+ cr0, .L_dsmiss_found_pte
/* Not found in PTEG, we must scan 2nd then give up */
andi. tmp1, tmp3, MASK(PTE0_HASH_ID) /* already at 2nd? */
bne- .L_dmiss_do_no_hash_exception /* give up */
mfspr tmp2, hash2
ori tmp3, tmp3, MASK(PTE0_HASH_ID)
b .L_dsmiss_find_pte_in_pteg
.L_dsmiss_found_pte:
lwz tmp1, 4(tmp2) /* get pte1_t */
andi. tmp3, tmp1, MASK(PTE1_CHANGED) /* unchanged, check? */
beq- .L_dsmiss_check_prot /* yes, check prot */
.L_dsmiss_resolved:
/* Ok, we've found what we need to, restore and rfi! */
mtctr tmp0 /* restore ctr */
mfsrr1 tmp3
mfspr tmp0, dmiss
mtcrf 0x80, tmp3 /* Restore CR0 */
mtspr rpa, tmp1 /* set the pte */
tlbld tmp0 /* load up tlb */
rfi
.L_dsmiss_check_prot:
/* PTE is unchanged, we must check that we can write */
rlwinm. tmp3, tmp1, 30, 0, 1 /* check PP[1] */
bge- .L_dsmiss_check_prot_user_kern
andi. tmp3, tmp1, 1 /* check PP[0] */
beq+ .L_dsmiss_check_prot_ok
.L_dmiss_do_prot_exception:
/* clean up registers for protection exception... */
mfsrr1 tmp3
/* prepare to set DSISR_WRITE_BIT correctly from srr1 info */
rlwinm tmp1, tmp3, 9, 6, 6
addis tmp1, tmp1, MASK(DSISR_PROT) >> 16
/* And the entry into the usual data fault handler ... */
mtctr tmp0 /* Restore ctr */
andi. tmp2, tmp3, 0xffff /* Clean up srr1 */
mtsrr1 tmp2 /* Set srr1 */
mtdsisr tmp1
mfspr tmp2, dmiss
mtdar tmp2
mfmsr tmp0
xoris tmp0, tmp0, MASK(MSR_TGPR)>>16 /* no TGPR */
mtcrf 0x80, tmp3 /* Restore CR0 */
sync /* Needed on some */
mtmsr tmp0 /* reset MSR[TGPR] */
b .L_handler300 /* Data Access */
/* NB - if we knew we were on a 603e we could test just the MSR_KEY bit */
.L_dsmiss_check_prot_user_kern:
mfsrr1 tmp3
andi. tmp3, tmp3, MASK(MSR_PR)
beq+ .L_dsmiss_check_prot_kern
mfspr tmp3, dmiss /* check user privs */
mfsrin tmp3, tmp3 /* get excepting SR */
andis. tmp3, tmp3, 0x2000 /* Test SR ku bit */
beq+ .L_dsmiss_check_prot_ok
b .L_dmiss_do_prot_exception
.L_dsmiss_check_prot_kern:
mfspr tmp3, dmiss /* check kern privs */
mfsrin tmp3, tmp3
andis. tmp3, tmp3, 0x4000 /* Test SR Ks bit */
bne- .L_dmiss_do_prot_exception
.L_dsmiss_check_prot_ok:
/* Ok, mark as referenced and changed before resolving the fault */
ori tmp1, tmp1, (MASK(PTE1_REFERENCED)|MASK(PTE1_CHANGED))
sth tmp1, 6(tmp2)
b .L_dsmiss_resolved
/*
* Instruction address breakpoint
*/
. = 0x1300
.L_handler1300:
mtsprg 2,r13 /* Save R13 */
mtsprg 3,r11 /* Save R11 */
mfsprg r13,1 /* Get the exception save area */
li r11,T_INSTRUCTION_BKPT /* Set 'rupt code */
b .L_exception_entry /* Join common... */
/*
* System management interrupt
*/
. = 0x1400
.L_handler1400:
mtsprg 2,r13 /* Save R13 */
mtsprg 3,r11 /* Save R11 */
mfsprg r13,1 /* Get the exception save area */
li r11,T_SYSTEM_MANAGEMENT /* Set 'rupt code */
b .L_exception_entry /* Join common... */
;
; Altivec Java Mode Assist interrupt
;
. = 0x1600
.L_handler1600:
mtsprg 2,r13 /* Save R13 */
mtsprg 3,r11 /* Save R11 */
mfsprg r13,1 /* Get the exception save area */
li r11,T_ALTIVEC_ASSIST /* Set 'rupt code */
b .L_exception_entry /* Join common... */
/*
* There is now a large gap of reserved traps
*/
/*
* Run mode/ trace exception - single stepping on 601 processors
*/
. = 0x2000
.L_handler2000:
mtsprg 2,r13 /* Save R13 */
mtsprg 3,r11 /* Save R11 */
mfsprg r13,1 /* Get the exception save area */
li r11,T_RUNMODE_TRACE /* Set 'rupt code */
b .L_exception_entry /* Join common... */
/*
* .L_exception_entry(type)
*
* This is the common exception handling routine called by any
* type of system exception.
*
* ENTRY: via a system exception handler, thus interrupts off, VM off.
* r3 has been saved in sprg3 and now contains a number
* representing the exception's origins
*
*/
.data
.align ALIGN
#ifdef __ELF__
.type EXT(exception_entry),@object
.size EXT(exception_entry), 4
#endif
.globl EXT(exception_entry)
EXT(exception_entry):
.long .L_exception_entry-EXT(ExceptionVectorsStart) /* phys addr of fn */
VECTOR_SEGMENT
.align 2
.L_exception_entry:
/*
*
* Here we will save off a mess of registers, the special ones and R0-R12. We use the DCBZ
* instruction to clear and allcoate a line in the cache. This way we won't take any cache
* misses, so these stores won't take all that long.
*
*
*/
dcbz 0,r13 /* Allocate the first line of the savearea in the cache */
stw r1,saver1(r13) /* Save this one */
li r1,32 /* Point to the second line */
stw r0,saver0(r13) /* Save this one */
dcbz r1,r13 /* Reserve our line in cache */
#if PERFTIMES && DEBUG
mftb r1 ; Get the time of interruption
stw r1,0x17C(br0) ; Save the time of interruption
#endif
stw r2,saver2(r13) /* Save this one */
stw r3,saver3(r13) /* Save this one */
stw r6,saver6(r13) /* Save this one */
stw r4,saver4(r13) /* Save this one */
stw r8,saver8(r13) /* Save this one */
mfsrr0 r6 /* Get the interruption SRR0 */
stw r7,saver7(r13) /* Save this one */
mfsrr1 r7 /* Get the interrupt SRR1 */
stw r6,savesrr0(r13) /* Save the SRR0 */
stw r5,saver5(r13) /* Save this one */
mfsprg r6,2 /* Get interrupt time R13 */
stw r7,savesrr1(r13) /* Save SRR1 */
mfsprg r8,3 /* Get 'rupt time R11 */
stw r6,saver13(r13) /* Save 'rupt R1 */
la r6,saver14(r13) /* Point to the next cache line */
stw r8,saver11(r13) /* Save 'rupt time R11 */
dcbz 0,r6 /* Allocate in cache */
stw r9,saver9(r13) /* Save this one */
mfcr r7 /* Get the CR */
#if 0
cmplwi r13,0x1000 ; (TEST/DEBUG)
bgt+ notpage0yy ; (TEST/DEBUG)
li r9,1 ; (TEST/DEBUG)
lwz r9,0(br0) ; (TEST/DEBUG)
dcbst br0,r9 ; (TEST/DEBUG)
notpage0aa: b notpage0aa ; (TEST/DEBUG)
notpage0yy: lwz r9,0(br0) ; (TEST/DEBUG)
mr. r9,r9 ; (TEST/DEBUG)
notpage0bb: bne- notpage0bb ; (TEST/DEBUG)
#endif
la r9,saver30(r13) /* Point to the trailing end */
stw r10,saver10(r13) /* Save this one */
mflr r8 /* Get the LR */
stw r12,saver12(r13) /* Save this one */
dcbz 0,r9 /* Allocate the last in the area */
stw r14,saver14(r13) /* Save this one */
la r10,saver22(r13) /* Point to the next block to save into */
stw r15,saver15(r13) /* Save this one */
stw r7,savecr(r13) /* Save 'rupt CR */
mfctr r6 /* Get the CTR */
stw r16,saver16(r13) /* Save this one */
stw r8,savelr(r13) /* Save 'rupt LR */
dcbz 0,r10 /* Allocate next save area line */
stw r17,saver17(r13) /* Save this one */
stw r18,saver18(r13) /* Save this one */
stw r6,savectr(r13) /* Save 'rupt CTR */
mfxer r7 /* Get the XER */
stw r19,saver19(r13) /* Save this one */
lis r12,HIGH_ADDR(KERNEL_SEG_REG0_VALUE) /* Get the high half of the kernel SR0 value */
mfdar r6 /* Get the 'rupt DAR */
stw r20,saver20(r13) /* Save this one */
#if 0
mfsr r10,sr0 ; (TEST/DEBUG)
mfsr r20,sr1 ; (TEST/DEBUG)
stw r10,savesr0(r13) ; (TEST/DEBUG)
mfsr r10,sr2 ; (TEST/DEBUG)
mfsr r19,sr3 ; (TEST/DEBUG)
stw r20,savesr1(r13) ; (TEST/DEBUG)
mfsr r14,sr4 ; (TEST/DEBUG)
mfsr r15,sr5 ; (TEST/DEBUG)
stw r10,savesr2(r13) ; (TEST/DEBUG)
mfsr r16,sr6 ; (TEST/DEBUG)
mfsr r17,sr7 ; (TEST/DEBUG)
stw r19,savesr3(r13) ; (TEST/DEBUG)
mfsr r10,sr8 ; (TEST/DEBUG)
mfsr r20,sr9 ; (TEST/DEBUG)
stw r14,savesr4(r13) ; (TEST/DEBUG)
mfsr r14,sr10 ; (TEST/DEBUG)
mfsr r19,sr11 ; (TEST/DEBUG)
stw r15,savesr5(r13) ; (TEST/DEBUG)
mfsr r15,sr13 ; (TEST/DEBUG)
stw r16,savesr6(r13) ; (TEST/DEBUG)
mfsr r16,sr14 ; (TEST/DEBUG)
stw r17,savesr7(r13) ; (TEST/DEBUG)
mfsr r17,sr15 ; (TEST/DEBUG)
stw r10,savesr8(r13) ; (TEST/DEBUG)
stw r20,savesr9(r13) ; (TEST/DEBUG)
stw r14,savesr10(r13) ; (TEST/DEBUG)
stw r19,savesr11(r13) ; (TEST/DEBUG)
stw r15,savesr13(r13) ; (TEST/DEBUG)
stw r16,savesr14(r13) ; (TEST/DEBUG)
stw r17,savesr15(r13) ; (TEST/DEBUG)
#endif
mtsr sr0,r12 /* Set the kernel SR0 */
stw r21,saver21(r13) /* Save this one */
addis r12,r12,0x0010 ; Point to the second segment of kernel
stw r7,savexer(r13) /* Save the 'rupt XER */
mtsr sr1,r12 /* Set the kernel SR1 */
stw r30,saver30(r13) /* Save this one */
addis r12,r12,0x0010 ; Point to the third segment of kernel
stw r31,saver31(r13) /* Save this one */
mtsr sr2,r12 /* Set the kernel SR2 */
stw r22,saver22(r13) /* Save this one */
addis r12,r12,0x0010 ; Point to the third segment of kernel
la r10,savedar(r13) /* Point to exception info block */
stw r23,saver23(r13) /* Save this one */
mtsr sr3,r12 /* Set the kernel SR3 */
stw r24,saver24(r13) /* Save this one */
stw r25,saver25(r13) /* Save this one */
mfdsisr r7 /* Get the 'rupt DSISR */
stw r26,saver26(r13) /* Save this one */
dcbz 0,r10 /* Allocate exception info line */
stw r27,saver27(r13) /* Save this one */
stw r28,saver28(r13) /* Save this one */
stw r29,saver29(r13) /* Save this one */
mfsr r14,sr14 ; Get the copyin/out segment register
stw r6,savedar(r13) /* Save the 'rupt DAR */
stw r7,savedsisr(r13) /* Save the 'rupt code DSISR */
stw r11,saveexception(r13) /* Save the exception code */
stw r14,savesr14(r13) ; Save copyin/copyout
lis r8,HIGH_ADDR(EXT(saveanchor)) /* Get the high part of the anchor */
mfpvr r20 /* Get the PVR */
ori r8,r8,LOW_ADDR(EXT(saveanchor)) /* Bottom half of the anchor */
li r21,0x3612 /* Mask of processors with a PIR */
rlwinm r20,r20,16,16,31 /* Isolate the CPU type */
srw r21,r21,r20 /* Isolate the PIR valid bit */
cmplwi cr1,r20,PROCESSOR_VERSION_Max ; Do we have Altivec?
rlwinm r21,r21,0,31,31 /* Isolate the PIR valid */
li r19,0 ; Assume no Altivec
blt cr1,noavec ; No possible AltiVec here...
mfspr r19,vrsave ; Get the VRSAVE register
noavec: cmplwi cr6,r21,1 /* Check if PIR is valid */
stw r19,savevrsave(r13) ; Save the vector register usage flags
#if 0
lwz r14,savesrr0(r13) /* (TEST/DEBUG) */
cmplw cr7,r5,r5 /* (TEST/DEBUG) */
rlwinm. r14,r14,0,0,15 /* (TEST/DEBUG) */
cmplwi cr2,r11,T_INTERRUPT /* (TEST/DEBUG) */
beq- noeattrace2 /* (TEST/DEBUG) */
cmplwi r11,T_SYSTEM_CALL /* (TEST/DEBUG) */
rlwinm r14,r0,1,0,31 /* (TEST/DEBUG) */
beq cr2,eatatjoes /* (TEST/DEBUG) */
bne+ noeattrace2 /* (TEST/DEBUG) */
cmplwi r14,0x001B /* (TEST/DEBUG) */
bne+ noeattrace2 /* (TEST/DEBUG) */
eatatjoes: cmplwi cr7,r13,0 /* (TEST/DEBUG) */
noeattrace2:
#else
cmplw cr7,r13,r13 /* (TEST/DEBUG) */
#endif
#if RUPTTRC
lwz r9,0(br0) /* (TEST/DEBUG) */
lis r14,0x7FFF /* (TEST/DEBUG) */
mr. r9,r9 /* (TEST/DEBUG) */
beq+ nono1 /* (TEST/DEBUG) */
bne cr7,nono1 /* (TEST/DEBUG) */
mfdec r9 /* (TEST/DEBUG) */
or r14,r14,r9 /* (TEST/DEBUG) */
mtdec r14 /* (TEST/DEBUG) */
li r14,0x20 /* (TEST/DEBUG) */
lwarx r15,0,r14 ; ?
mpwait0: lwarx r15,0,r14 /* (TEST/DEBUG) */
mr. r15,r15 /* (TEST/DEBUG) */
bne- mpwait0 /* (TEST/DEBUG) */
stwcx. r14,0,r14 /* (TEST/DEBUG) */
bne- mpwait0 /* (TEST/DEBUG) */
stw r0,0x280(br0) /* (TEST/DEBUG) */
stmw r1,0x284(br0) /* (TEST/DEBUG) */
bne cr6,nopir0 /* (TEST/DEBUG) */
mfspr r4,pir /* (TEST/DEBUG) */
b gotpir0 /* (TEST/DEBUG) */
nopir0: li r4,0 /* (TEST/DEBUG) */
gotpir0: /* (TEST/DEBUG) */
lis r31,HIGH_ADDR(EXT(dbgDispLL)) /* (TEST/DEBUG) */
rlwinm r4,r4,24,4,7 /* (TEST/DEBUG) */
li r3,0 /* (TEST/DEBUG) */
rlwimi r4,r11,30,8,31 /* (TEST/DEBUG) */
mfsrr0 r5 /* (TEST/DEBUG) */
oris r4,r4,0x3030 /* (TEST/DEBUG) */
ori r31,r31,LOW_ADDR(EXT(dbgDispLL)) /* (TEST/DEBUG) */
ori r4,r4,0x3030 /* (TEST/DEBUG) */
mtlr r31 /* (TEST/DEBUG) */
blrl /* (TEST/DEBUG) */
bne cr6,nopir1 /* (TEST/DEBUG) */
mfspr r4,pir /* (TEST/DEBUG) */
b gotpir1 /* (TEST/DEBUG) */
nopir1: li r4,0 /* (TEST/DEBUG) */
gotpir1: /* (TEST/DEBUG) */
lis r31,HIGH_ADDR(EXT(dbgDispLL)) /* (TEST/DEBUG) */
rlwinm r4,r4,24,4,7 /* (TEST/DEBUG) */
lwz r5,savelr(r13) /* (TEST/DEBUG) */
li r3,0 /* (TEST/DEBUG) */
oris r4,r4,0x3030 /* (TEST/DEBUG) */
ori r31,r31,LOW_ADDR(EXT(dbgDispLL)) /* (TEST/DEBUG) */
ori r4,r4,0x3130 /* (TEST/DEBUG) */
mtlr r31 /* (TEST/DEBUG) */
blrl /* (TEST/DEBUG) */
bne cr6,nopir2 /* (TEST/DEBUG) */
mfspr r4,pir /* (TEST/DEBUG) */
b gotpir2 /* (TEST/DEBUG) */
nopir2: li r4,0 /* (TEST/DEBUG) */
gotpir2: /* (TEST/DEBUG) */
lis r31,HIGH_ADDR(EXT(dbgDispLL)) /* (TEST/DEBUG) */
rlwinm r4,r4,24,4,7 /* (TEST/DEBUG) */
li r3,0 /* (TEST/DEBUG) */
mr r5,r13 /* (TEST/DEBUG) */
oris r4,r4,0x3030 /* (TEST/DEBUG) */
ori r31,r31,LOW_ADDR(EXT(dbgDispLL)) /* (TEST/DEBUG) */
ori r4,r4,0x3131 /* (TEST/DEBUG) */
mtlr r31 /* (TEST/DEBUG) */
blrl /* (TEST/DEBUG) */
lmw r1,0x284(br0) /* (TEST/DEBUG) */
lwz r0,0x280(br0) /* (TEST/DEBUG) */
li r15,0 /* (TEST/DEBUG) */
stw r15,0x20(br0) /* (TEST/DEBUG) */
mtdec r9 /* (TEST/DEBUG) */
nono1:
#endif
/*
* Everything is saved at this point, except for FPRs, and VMX registers
*
* Time for a new save area. Allocate the trace table entry now also
* Note that we haven't touched R0-R5 yet. Except for R1, that's in the save
*/
#if 0
mfsrr1 r20 ; (TEST/DEBUG)
mfsrr0 r7 ; (TEST/DEBUG)
lis r9,0x8000 ; (TEST/DEBUG)
mfmsr r25 ; (TEST/DEBUG)
ori r15,r25,0x10 ; (TEST/DEBUG)
mtmsr r15 ; (TEST/DEBUG)
isync ; (TEST/DEBUG)
ori r9,r9,lo16(0x870C) ; (TEST/DEBUG)
stw r11,0(r9) ; (TEST/DEBUG)
stw r7,0(r9) ; (TEST/DEBUG)
mtmsr r25 ; (TEST/DEBUG)
isync ; (TEST/DEBUG)
mtsrr1 r20 ; (TEST/DEBUG)
mtsrr0 r7 ; (TEST/DEBUG)
#endif
lwarx r9,0,r8 ; ?
lllck: lwarx r9,0,r8 /* Grab the lock value */
li r7,1 /* Use part of the delay time */
mr. r9,r9 /* Is it locked? */
bne- lllcks /* Yeah, wait for it to clear... */
stwcx. r7,0,r8 /* Try to seize that there durn lock */
beq+ lllckd /* Got it... */
b lllck /* Collision, try again... */
lllcks: lwz r9,SVlock(r8) /* Get that lock in here */
mr. r9,r9 /* Is it free yet? */
beq+ lllck /* Yeah, try for it again... */
b lllcks /* Sniff away... */
lllckd: isync /* Purge any speculative executions here */
rlwinm r7,r11,30,0,31 /* Save 'rupt code shifted right 2 */
#if 1
lwz r14,LOW_ADDR(traceMask-EXT(ExceptionVectorsStart))(br0) /* Get the trace mask */
#else
li r14,-1 /* (TEST/DEBUG) */
#endif
addi r7,r7,10 /* Adjust for CR5_EQ position */
lwz r15,SVfree(r8) /* Get the head of the save area list */
lwz r25,SVinuse(r8) /* Get the in use count */
rlwnm r7,r14,r7,22,22 /* Set CR5_EQ bit position to 0 if tracing allowed */
lwz r20,LOW_ADDR(EXT(traceCurr)-EXT(ExceptionVectorsStart))(br0) /* Pick up the current trace entry */
mtcrf 0x04,r7 /* Set CR5 to show trace or not */
lwz r14,SACalloc(r15) /* Pick up the allocation bits */
addi r25,r25,1 /* Bump up the in use count for the new savearea */
lwz r21,LOW_ADDR(EXT(traceEnd)-EXT(ExceptionVectorsStart))(br0) /* Grab up the end of it all */
mr. r14,r14 /* Can we use the first one? */
blt use1st /* Yeah... */
andis. r14,r14,0x8000 /* Show we used the second and remember if it was the last */
addi r10,r15,0x0800 /* Point to the first one */
b gotsave /* We have the area now... */
use1st: andis. r14,r14,0x4000 /* Mark first gone and remember if empty */
mr r10,r15 /* Set the save area */
gotsave: stw r14,SACalloc(r15) /* Put back the allocation bits */
bne nodqsave /* There's still an empty slot, don't dequeue... */
lwz r16,SACnext(r15) /* Get the next in line */
stw r16,SVfree(r8) /* Dequeue our now empty save area block */
nodqsave: addi r22,r20,LTR_size /* Point to the next trace entry */
stw r25,SVinuse(r8) /* Set the in use count */
li r17,0 /* Clear this for the lock */
cmplw r22,r21 /* Do we need to wrap the trace table? */
stw r17,SAVprev(r10) /* Clear back pointer for the newly allocated guy */
mtsprg 1,r10 /* Get set for the next 'rupt */
bne+ gotTrcEnt /* We got a trace entry... */
lwz r22,LOW_ADDR(EXT(traceStart)-EXT(ExceptionVectorsStart))(br0) /* Wrap back to the top */
gotTrcEnt: bne- cr5,skipTrace1 /* Don't want to trace this kind... */
stw r22,LOW_ADDR(EXT(traceCurr)-EXT(ExceptionVectorsStart))(br0) /* Set the next entry for the next guy */
#if ESPDEBUG
li r22,0x180 ; (TEST/DEBUG)
dcbst br0,r22 ; (TEST/DEBUG)
sync ; (TEST/DEBUG)
#endif
dcbz 0,r20 /* Allocate cache for the entry */
skipTrace1: sync /* Make sure all stores are done */
stw r17,SVlock(r8) /* Unlock both save and trace areas */
#if RUPTTRC
lis r14,0x7FFF /* (TEST/DEBUG) */
mfdec r17 /* (TEST/DEBUG) */
or r14,r14,r17 /* (TEST/DEBUG) */
mtdec r14 /* (TEST/DEBUG) */
li r14,0x20 /* (TEST/DEBUG) */
lwarx r16,0,r14 ; ?
mpwait1: lwarx r16,0,r14 /* (TEST/DEBUG) */
mr. r16,r16 /* (TEST/DEBUG) */
bne- mpwait1 /* (TEST/DEBUG) */
stwcx. r14,0,r14 /* (TEST/DEBUG) */
bne- mpwait1 /* (TEST/DEBUG) */
stw r0,0x280(br0) /* (TEST/DEBUG) */
stmw r1,0x284(br0) /* (TEST/DEBUG) */
bne cr7,nono2 /* (TEST/DEBUG) */
lwz r0,0(br0) /* (TEST/DEBUG) */
mr. r0,r0 /* (TEST/DEBUG) */
beq+ nono2 /* (TEST/DEBUG) */
bne cr6,nopir3 /* (TEST/DEBUG) */
mfspr r4,pir /* (TEST/DEBUG) */
b gotpir3 /* (TEST/DEBUG) */
nopir3: li r4,0 /* (TEST/DEBUG) */
gotpir3: /* (TEST/DEBUG) */
lis r31,HIGH_ADDR(EXT(dbgDispLL)) /* (TEST/DEBUG) */
rlwinm r4,r4,24,4,7 /* (TEST/DEBUG) */
li r3,0 /* (TEST/DEBUG) */
mr r5,r10 /* (TEST/DEBUG) */
oris r4,r4,0x3030 /* (TEST/DEBUG) */
ori r31,r31,LOW_ADDR(EXT(dbgDispLL)) /* (TEST/DEBUG) */
ori r4,r4,0x3230 /* (TEST/DEBUG) */
mtlr r31 /* (TEST/DEBUG) */
blrl /* (TEST/DEBUG) */
nono2:
lmw r1,0x284(br0) /* (TEST/DEBUG) */
lwz r0,0x280(br0) /* (TEST/DEBUG) */
li r16,0 /* (TEST/DEBUG) */
stw r16,0x20(br0) /* (TEST/DEBUG) */
mtdec r17 /* (TEST/DEBUG) */
#endif
/*
* At this point, we can take another exception and lose nothing.
*
* We still have the current savearea pointed to by R13, the next by R10 and
* sprg1. R20 contains the pointer to a trace entry and CR5_eq says
* to do the trace or not.
*
* Note that R13 was chosen as the save area pointer because the SIGP,
* firmware, and DSI/ISI handlers aren't supposed to touch anything
* over R12. But, actually, the DSI/ISI stuff does.
*
*
* Let's cut that trace entry now.
*/
bne- cr5,skipTrace2 /* Don't want to trace this kind... */
li r14,32 /* Second line of entry */
getTB: mftbu r16 /* Get the upper timebase */
mftb r17 /* Get the lower timebase */
mftbu r18 /* Get the upper one again */
cmplw r16,r18 /* Did the top tick? */
bne- getTB /* Yeah, need to get it again... */
dcbz r14,r20 /* Zap the second half */
stw r16,LTR_timeHi(r20) /* Set the upper part of TB */
bne cr6,nopir4 /* Is there a processor ID number on this guy? */
mfspr r19,pir /* Get the processor address */
b gotpir4 /* Got it... */
nopir4: li r19,0 /* Assume processor 0 for those underprivileged folks */
gotpir4:
lwz r1,saver1(r13) /* Get back interrupt time R1 */
stw r17,LTR_timeLo(r20) /* Set the lower part of TB */
rlwinm r19,r19,0,27,31 /* Cut the junk */
stw r0,LTR_r0(r20) /* Save off register 0 */
sth r19,LTR_cpu(r20) /* Stash the cpu address */
stw r1,LTR_r1(r20) /* Save off register 1 */
stw r2,LTR_r2(r20) /* Save off register 2 */
stw r3,LTR_r3(r20) /* Save off register 3 */
lwz r16,savecr(r13) /* We don't remember the CR anymore, get it */
stw r4,LTR_r4(r20) /* Save off register 4 */
mfsrr0 r17 /* Get this back, it's still good */
stw r5,LTR_r5(r20) /* Save off register 5 */
mfsrr1 r18 /* This is still good in here also */
stw r16,LTR_cr(r20) /* Save the CR (or dec) */
stw r17,LTR_srr0(r20) /* Save the SSR0 */
stw r18,LTR_srr1(r20) /* Save the SRR1 */
mfdar r17 /* Get this back */
mflr r16 /* Get the LR */
stw r17,LTR_dar(r20) /* Save the DAR */
mfctr r17 /* Get the CTR */
stw r16,LTR_lr(r20) /* Save the LR */
#if 0
lis r17,HIGH_ADDR(EXT(saveanchor)) ; (TEST/DEBUG)
ori r17,r17,LOW_ADDR(EXT(saveanchor)) ; (TEST/DEBUG)
lwz r16,SVcount(r17) ; (TEST/DEBUG)
lwz r17,SVinuse(r17) ; (TEST/DEBUG)
rlwimi r17,r16,16,0,15 ; (TEST/DEBUG)
#endif
stw r17,LTR_ctr(r20) /* Save off the CTR */
stw r13,LTR_save(r20) /* Save the savearea */
sth r11,LTR_excpt(r20) /* Save the exception type */
#if ESPDEBUG
addi r17,r20,32 ; (TEST/DEBUG)
dcbst br0,r20 ; (TEST/DEBUG)
dcbst br0,r17 ; (TEST/DEBUG)
sync ; (TEST/DEBUG)
#endif
/*
* We're done with the trace, except for maybe modifying the exception
* code later on. So, that means that we need to save R20 and CR5, but
* R0 to R5 are clear now.
*
* So, let's finish setting up the kernel registers now.
*/
skipTrace2:
#if PERFTIMES && DEBUG
li r3,68 ; Indicate interrupt
mr r4,r11 ; Get code to log
mr r5,r13 ; Get savearea to log
mr r8,r0 ; Save R0
bl EXT(dbgLog2) ; Cut log entry
mr r0,r8 ; Restore R0
#endif
mfsprg r2,0 /* Get the per processor block */
#if 0
lis r19,0xF300 /* (TEST/DEBUG) */
ori r19,r19,0x0020 /* (TEST/DEBUG) */
dcbi 0,r19 /* (TEST/DEBUG) */
sync /* (TEST/DEBUG) */
eieio /* (TEST/DEBUG) */
lwz r18,0x000C(r19) /* (TEST/DEBUG) */
eieio /* (TEST/DEBUG) */
dcbi 0,r19 /* (TEST/DEBUG) */
rlwinm. r4,r18,0,19,19 /* (TEST/DEBUG) */
rlwinm r18,r18,0,20,18 /* (TEST/DEBUG) */
sync /* (TEST/DEBUG) */
eieio /* (TEST/DEBUG) */
beq+ nonmi /* (TEST/DEBUG) */
stw r18,0x0008(r19) /* (TEST/DEBUG) */
dcbi 0,r19 /* (TEST/DEBUG) */
sync /* (TEST/DEBUG) */
eieio /* (TEST/DEBUG) */
BREAKPOINT_TRAP /* (TEST/DEBUG) */
nonmi: /* (TEST/DEBUG) */
#endif
#if 0
lis r4,hi16(EXT(hash_table_base)) ; (TEST/DEBUG)
ori r4,r4,lo16(EXT(hash_table_base)) ; (TEST/DEBUG)
lwz r8,0(r4) ; (TEST/DEBUG)
lwz r4,4(r4) ; (TEST/DEBUG)
add r8,r4,r8 ; (TEST/DEBUG)
yyyck: lwz r12,4(r8) ; (TEST/DEBUG)
rlwimn. r12,r12,0,24,31 ; (TEST/DEBUG)
bne+ yyyok ; (TEST/DEBUG)
BREAKPOINT_TRAP ; (TEST/DEBUG)
yyyok: addi r8,r8,0x40 ; (TEST/DEBUG)
subic r4,r4,0x40 ; (TEST/DEBUG)
bgt+ yyyck ; (TEST/DEBUG)
#endif
#if CHECKSAVE
lis r4,0x7FFF /* (TEST/DEBUG) */
mfdec r12 /* (TEST/DEBUG) */
or r4,r4,r12 /* (TEST/DEBUG) */
mtdec r4 /* (TEST/DEBUG) */
li r4,0x20 /* (TEST/DEBUG) */
lwarx r8,0,r4 ; ?
mpwait2: lwarx r8,0,r4 /* (TEST/DEBUG) */
mr. r8,r8 /* (TEST/DEBUG) */
bne- mpwait2 /* (TEST/DEBUG) */
stwcx. r4,0,r4 /* (TEST/DEBUG) */
bne- mpwait2 /* (TEST/DEBUG) */
isync /* (TEST/DEBUG) */
lwz r4,0xD80(br0) /* (TEST/DEBUG) */
mr. r4,r4 /* (TEST/DEBUG) */
li r4,1 /* (TEST/DEBUG) */
bne- doncheksv /* (TEST/DEBUG) */
lis r8,HIGH_ADDR(EXT(saveanchor)) /* (TEST/DEBUG) */
ori r8,r8,LOW_ADDR(EXT(saveanchor)) /* (TEST/DEBUG) */
stw r4,0xD80(br0) /* (TEST/DEBUG) */
lwarx r4,0,r8 ; ?
mpwait2x: lwarx r4,0,r8 /* (TEST/DEBUG) */
mr. r4,r4 /* (TEST/DEBUG) */
bne- mpwait2x /* (TEST/DEBUG) */
stwcx. r8,0,r8 /* (TEST/DEBUG) */
bne- mpwait2x /* (TEST/DEBUG) */
isync /* (TEST/DEBUG) */
#if 0
rlwinm r4,r13,0,0,19 /* (TEST/DEBUG) */
lwz r21,SACflags(r4) /* (TEST/DEBUG) */
rlwinm r22,r21,24,24,31 /* (TEST/DEBUG) */
cmplwi r22,0x00EE /* (TEST/DEBUG) */
lwz r22,SACvrswap(r4) /* (TEST/DEBUG) */
bne- currbad /* (TEST/DEBUG) */
andis. r21,r21,hi16(sac_perm) /* (TEST/DEBUG) */
bne- currnotbad /* (TEST/DEBUG) */
mr. r22,r22 /* (TEST/DEBUG) */
bne+ currnotbad /* (TEST/DEBUG) */
currbad: lis r23,hi16(EXT(debugbackpocket)) /* (TEST/DEBUG) */
ori r23,r23,lo16(EXT(debugbackpocket)) /* (TEST/DEBUG) */
stw r23,SVfree(r8) /* (TEST/DEBUG) */
mfsprg r25,1 /* (TEST/DEBUG) */
mtsprg 1,r23 /* (TEST/DEBUG) */
lwz r26,SACalloc(r23) /* (TEST/DEBUG) */
rlwinm r26,r26,0,1,31 /* (TEST/DEBUG) */
stw r26,SACalloc(r23) /* (TEST/DEBUG) */
sync /* (TEST/DEBUG) */
li r28,0 /* (TEST/DEBUG) */
stw r28,0x20(br0) /* (TEST/DEBUG) */
stw r28,0(r8) /* (TEST/DEBUG) */
BREAKPOINT_TRAP /* (TEST/DEBUG) */
currnotbad:
#endif
lwz r28,SVcount(r8) /* (TEST/DEBUG) */
#if RUPTTRC
stw r0,0x280(br0) /* (TEST/DEBUG) */
stmw r1,0x284(br0) /* (TEST/DEBUG) */
bne cr7,nono90 /* (TEST/DEBUG) */
lwz r0,0(br0) /* (TEST/DEBUG) */
mr. r0,r0 /* (TEST/DEBUG) */
beq+ nono90 /* (TEST/DEBUG) */
bne cr6,nopir5 /* (TEST/DEBUG) */
mfspr r4,pir /* (TEST/DEBUG) */
b gotpir0 /* (TEST/DEBUG) */
nopir5: li r4,0 /* (TEST/DEBUG) */
gotpir5: /* (TEST/DEBUG) */
lis r31,HIGH_ADDR(EXT(dbgDispLL)) /* (TEST/DEBUG) */
rlwinm r4,r4,24,4,7 /* (TEST/DEBUG) */
li r3,0 /* (TEST/DEBUG) */
mr r5,r28 /* (TEST/DEBUG) */
oris r4,r4,0x3036 /* (TEST/DEBUG) */
ori r31,r31,LOW_ADDR(EXT(dbgDispLL)) /* (TEST/DEBUG) */
ori r4,r4,0x3636 /* (TEST/DEBUG) */
mtlr r31 /* (TEST/DEBUG) */
blrl /* (TEST/DEBUG) */
nono90:
lmw r1,0x284(br0) /* (TEST/DEBUG) */
lwz r0,0x280(br0) /* (TEST/DEBUG) */
#endif
lwz r21,SVinuse(r8) /* (TEST/DEBUG) */
lwz r23,SVmin(r8) /* (TEST/DEBUG) */
sub r22,r28,r21 /* (TEST/DEBUG) */
cmpw r22,r23 /* (TEST/DEBUG) */
bge+ cksave0 /* (TEST/DEBUG) */
li r4,0 /* (TEST/DEBUG) */
stw r4,0x20(br0) /* (TEST/DEBUG) */
stw r4,0(r8) /* (TEST/DEBUG) */
BREAKPOINT_TRAP /* (TEST/DEBUG) */
cksave0: lwz r28,SVfree(r8) /* (TEST/DEBUG) */
li r24,0 /* (TEST/DEBUG) */
li r29,1 /* (TEST/SAVE) */
cksave0a: mr. r28,r28 /* (TEST/DEBUG) */
beq- cksave3 /* (TEST/DEBUG) */
rlwinm. r21,r28,0,4,19 /* (TEST/DEBUG) */
bne+ cksave1 /* (TEST/DEBUG) */
li r4,0 /* (TEST/DEBUG) */
stw r4,0x20(br0) /* (TEST/DEBUG) */
stw r4,0(r8) /* (TEST/DEBUG) */
BREAKPOINT_TRAP /* (TEST/DEBUG) */
cksave1: rlwinm. r21,r28,0,21,3 /* (TEST/DEBUG) */
beq+ cksave2 /* (TEST/DEBUG) */
li r4,0 /* (TEST/DEBUG) */
stw r4,0x20(br0) /* (TEST/DEBUG) */
stw r4,0(r8) /* (TEST/DEBUG) */
BREAKPOINT_TRAP /* (TEST/DEBUG) */
cksave2: lwz r25,SACalloc(r28) /* (TEST/DEBUG) */
lbz r26,SACflags+2(r28) /* (TEST/DEBUG) */
lbz r21,SACflags+3(r28) /* (TEST/DEBUG) */
cmplwi r26,0x00EE /* (TEST/DEBUG) */
stb r29,SACflags+3(r28) /* (TEST/DEBUG) */
beq+ cksave2z
li r4,0 /* (TEST/DEBUG) */
stw r4,0x20(br0) /* (TEST/DEBUG) */
stw r4,0(r8) /* (TEST/DEBUG) */
BREAKPOINT_TRAP /* (TEST/DEBUG) */
cksave2z: mr. r21,r21 /* (TEST/DEBUG) */
beq+ cksave2a /* (TEST/DEBUG) */
li r4,0 /* (TEST/DEBUG) */
stw r4,0x20(br0) /* (TEST/DEBUG) */
stw r4,0(r8) /* (TEST/DEBUG) */
BREAKPOINT_TRAP /* (TEST/DEBUG) */
cksave2a: rlwinm r26,r25,1,31,31 /* (TEST/DEBUG) */
rlwinm r27,r25,2,31,31 /* (TEST/DEBUG) */
add r24,r24,r26 /* (TEST/DEBUG) */
add r24,r24,r27 /* (TEST/DEBUG) */
lwz r28,SACnext(r28) /* (TEST/DEBUG) */
b cksave0a /* (TEST/DEBUG) */
cksave3: cmplw r24,r22 /* (TEST/DEBUG) */
beq+ cksave4 /* (TEST/DEBUG) */
li r4,0 /* (TEST/DEBUG) */
stw r4,0x20(br0) /* (TEST/DEBUG) */
stw r4,0(r8) /* (TEST/DEBUG) */
BREAKPOINT_TRAP /* (TEST/DEBUG) */
cksave4: lwz r28,SVfree(r8) /* (TEST/DEBUG) */
li r24,0 /* (TEST/DEBUG) */
cksave5: mr. r28,r28 /* (TEST/DEBUG) */
beq- cksave6 /* (TEST/DEBUG) */
stb r24,SACflags+3(r28) /* (TEST/DEBUG) */
lwz r28,SACnext(r28) /* (TEST/DEBUG) */
b cksave5 /* (TEST/DEBUG) */
cksave6:
li r4,0 /* (TEST/DEBUG) */
stw r4,0xD80(br0) /* (TEST/DEBUG) */
stw r4,0(r8) /* (TEST/DEBUG) */
doncheksv:
li r4,0 /* (TEST/DEBUG) */
stw r4,0x20(br0) /* (TEST/DEBUG) */
mtdec r12 /* (TEST/DEBUG) */
#endif
#if 0
lhz r4,0x980(br0) ; (TEST/DEBUG)
xoris r4,r4,lo16(0xFFF8) ; (TEST/DEBUG)
mr. r4,r4 ; (TEST/DEBUG)
beq- dontkillmedead ; (TEST/DEBUG)
mfmsr r12 ; (TEST/DEBUG)
ori r4,r12,0x2000 ; (TEST/DEBUG)
mtmsr r4 ; (TEST/DEBUG)
isync ; (TEST/DEBUG)
stfd f13,0x980(br0) ; (TEST/DEBUG)
mtmsr r12 ; (TEST/DEBUG)
isync ; (TEST/DEBUG)
lhz r4,0x980(br0) ; (TEST/DEBUG)
xoris r4,r4,lo16(0xFFF8) ; (TEST/DEBUG)
mr. r4,r4 ; (TEST/DEBUG)
bne+ dontkillmedead ; (TEST/DEBUG)
BREAKPOINT_TRAP ; (TEST/DEBUG)
dontkillmedead: ; (TEST/DEBUG)
#endif
lis r4,HIGH_ADDR(EXT(MPspec)) /* Get the MP control block */
dcbt 0,r2 /* We'll need the per_proc in a sec */
cmplwi cr0,r11,T_INTERRUPT /* Do we have an external interrupt? */
ori r4,r4,LOW_ADDR(EXT(MPspec)) /* Get the bottom half of the MP control block */
bne+ notracex /* Not an external... */
/*
* Here we check to see if there was a interprocessor signal
*/
lwz r4,MPSSIGPhandler(r4) /* Get the address of the SIGP interrupt filter */
lhz r3,PP_CPU_FLAGS(r2) /* Get the CPU flags */
cmplwi cr1,r4,0 /* Check if signal filter is initialized yet */
andi. r3,r3,LOW_ADDR(SIGPactive) /* See if this processor has started up */
mtlr r4 /* Load up filter address */
beq- cr1,notracex /* We don't have a filter yet... */
beq- notracex /* This processor hasn't started filtering yet... */
blrl /* Filter the interrupt */
mfsprg r2,0 /* Make sure we have the per processor block */
cmplwi cr0,r3,kMPIOInterruptPending /* See what the filter says */
li r11,T_INTERRUPT /* Assume we have a regular external 'rupt */
beq+ modRupt /* Yeah, we figured it would be... */
li r11,T_SIGP /* Assume we had a signal processor interrupt */
bgt+ modRupt /* Yeah, at this point we would assume so... */
li r11,T_IN_VAIN /* Nothing there actually, so eat it */
modRupt: stw r11,PP_SAVE_EXCEPTION_TYPE(r2) /* Set that it was either in vain or a SIGP */
stw r11,saveexception(r13) /* Save the exception code here also */
bne- cr5,notracex /* Jump if no tracing... */
sth r11,LTR_excpt(r20) /* Save the exception type */
notracex:
#if 0
bne cr6,nopir6 /* (TEST/DEBUG) */
mfspr r7,pir /* (TEST/DEBUG) */
b gotpir6 /* (TEST/DEBUG) */
nopir6: li r7,0 /* (TEST/DEBUG) */
gotpir6: /* (TEST/DEBUG) */
lis r6,HIGH_ADDR(EXT(RuptCtrs)) /* (TEST/DEBUG) */
rlwinm r7,r7,8,23,23 /* (TEST/DEBUG) */
lis r12,HIGH_ADDR(EXT(GratefulDeb)) /* (TEST/DEBUG) */
rlwimi r7,r7,1,22,22 /* (TEST/DEBUG) */
ori r6,r6,LOW_ADDR(EXT(RuptCtrs)) /* (TEST/DEBUG) */
rlwinm r1,r11,2,0,29 /* (TEST/DEBUG) */
add r6,r6,r7 /* (TEST/DEBUG) */
ori r12,r12,LOW_ADDR(EXT(GratefulDeb)) /* (TEST/DEBUG) */
lwz r21,(47*16)+8(r6) /* (TEST/DEBUG) */
lwz r22,(47*16)+12(r6) /* (TEST/DEBUG) */
add r1,r1,r6 /* (TEST/DEBUG) */
mftb r24 /* (TEST/DEBUG) */
sub r22,r24,r22 /* (TEST/DEBUG) */
lwz r4,4(r6) /* (TEST/DEBUG) */
cmplw cr2,r22,r21 /* (TEST/DEBUG) */
lwz r7,4(r1) /* (TEST/DEBUG) */
lwz r21,8(r6) /* (TEST/DEBUG) */
blt+ cr2,nottime /* (TEST/DEBUG) */
stw r24,(47*16)+12(r6) /* (TEST/DEBUG) */
nottime: addi r4,r4,1 /* (TEST/DEBUG) */
lwz r22,8(r1) /* (TEST/DEBUG) */
addi r7,r7,1 /* (TEST/DEBUG) */
stw r4,4(r6) /* (TEST/DEBUG) */
lwz r3,0(r6) /* (TEST/DEBUG) */
mr. r21,r21 /* (TEST/DEBUG) */
stw r7,4(r1) /* (TEST/DEBUG) */
mtlr r12 /* (TEST/DEBUG) */
lwz r1,0(r1) /* (TEST/DEBUG) */
beq- nottimed1 /* (TEST/DEBUG) */
blt+ cr2,isnttime1 /* (TEST/DEBUG) */
nottimed1: mr. r3,r3 /* (TEST/DEBUG) */
bgelrl+ /* (TEST/DEBUG) */
isnttime1: mr. r22,r22 /* (TEST/DEBUG) */
beq- nottimed2 /* (TEST/DEBUG) */
blt+ cr2,isnttime2 /* (TEST/DEBUG) */
nottimed2: mr. r3,r1 /* (TEST/DEBUG) */
mtlr r12 /* (TEST/DEBUG) */
mr r4,r7 /* (TEST/DEBUG) */
bgelrl+ /* (TEST/DEBUG) */
mr r3,r11 /* (TEST/DEBUG) */
isnttime2: cmplwi r11,T_DATA_ACCESS /* (TEST/DEBUG) */
lis r12,HIGH_ADDR(EXT(GratefulDeb)) /* (TEST/DEBUG) */
bne+ nodsidisp /* (TEST/DEBUG) */
mr. r22,r22 /* (TEST/DEBUG) */
beq- nottimed3 /* (TEST/DEBUG) */
blt+ cr2,nodsidisp /* (TEST/DEBUG) */
nottimed3: li r3,5 /* (TEST/DEBUG) */
ori r12,r12,LOW_ADDR(EXT(GratefulDeb)) /* (TEST/DEBUG) */
lwz r4,savesrr0(r13) /* (TEST/DEBUG) */
mtlr r12 /* (TEST/DEBUG) */
blrl /* (TEST/DEBUG) */
lis r12,HIGH_ADDR(EXT(GratefulDeb)) /* (TEST/DEBUG) */
ori r12,r12,LOW_ADDR(EXT(GratefulDeb)) /* (TEST/DEBUG) */
lis r3,9 /* (TEST/DEBUG) */
ori r3,r3,5 /* (TEST/DEBUG) */
mtlr r12 /* (TEST/DEBUG) */
lwz r4,savedar(r13) /* (TEST/DEBUG) */
blrl /* (TEST/DEBUG) */
nodsidisp: cmplwi r11,T_INSTRUCTION_ACCESS /* (TEST/DEBUG) */
lis r12,HIGH_ADDR(EXT(GratefulDeb)) /* (TEST/DEBUG) */
bne+ noisidisp /* (TEST/DEBUG) */
mr. r22,r22 /* (TEST/DEBUG) */
beq- nottimed4 /* (TEST/DEBUG) */
blt+ cr2,noisidisp /* (TEST/DEBUG) */
nottimed4: li r3,6 /* (TEST/DEBUG) */
ori r12,r12,LOW_ADDR(EXT(GratefulDeb)) /* (TEST/DEBUG) */
lwz r4,savesrr0(r13) /* (TEST/DEBUG) */
mtlr r12 /* (TEST/DEBUG) */
blrl /* (TEST/DEBUG) */
noisidisp: mr r3,r11 /* (TEST/DEBUG) */
#endif
#if 0
cmplwi r11,T_PROGRAM /* (TEST/DEBUG) */
lis r12,HIGH_ADDR(EXT(GratefulDeb)) /* (TEST/DEBUG) */
bne+ nopgmdisp /* (TEST/DEBUG) */
li r3,7 /* (TEST/DEBUG) */
ori r12,r12,LOW_ADDR(EXT(GratefulDeb)) /* (TEST/DEBUG) */
lwz r4,savesrr0(r13) /* (TEST/DEBUG) */
mtlr r12 /* (TEST/DEBUG) */
blrl /* (TEST/DEBUG) */
nopgmdisp: mr r3,r11 /* (TEST/DEBUG) */
#endif
#if RUPTTRC
lis r6,0x7FFF /* (TEST/DEBUG) */
mfdec r7 /* (TEST/DEBUG) */
or r6,r6,r7 /* (TEST/DEBUG) */
mtdec r6 /* (TEST/DEBUG) */
li r6,0x20 /* (TEST/DEBUG) */
lwarx r1,0,r6 ; ?
mpwait3: lwarx r1,0,r6 /* (TEST/DEBUG) */
mr. r1,r1 /* (TEST/DEBUG) */
bne- mpwait3 /* (TEST/DEBUG) */
stwcx. r6,0,r6 /* (TEST/DEBUG) */
bne- mpwait3 /* (TEST/DEBUG) */
stw r0,0x280(br0) /* (TEST/DEBUG) */
stmw r1,0x284(br0) /* (TEST/DEBUG) */
bne cr7,nono3 /* (TEST/DEBUG) */
lwz r0,0(br0) /* (TEST/DEBUG) */
mr. r0,r0 /* (TEST/DEBUG) */
beq+ nono3 /* (TEST/DEBUG) */
bne cr6,nopir7 /* (TEST/DEBUG) */
mfspr r4,pir /* (TEST/DEBUG) */
b gotpir7 /* (TEST/DEBUG) */
nopir7: li r4,0 /* (TEST/DEBUG) */
gotpir7: /* (TEST/DEBUG) */
lis r31,HIGH_ADDR(EXT(dbgDispLL)) /* (TEST/DEBUG) */
rlwinm r4,r4,24,4,7 /* (TEST/DEBUG) */
li r3,0 /* (TEST/DEBUG) */
mr r5,r11 /* (TEST/DEBUG) */
oris r4,r4,0x3030 /* (TEST/DEBUG) */
ori r31,r31,LOW_ADDR(EXT(dbgDispLL)) /* (TEST/DEBUG) */
ori r4,r4,0x3330 /* (TEST/DEBUG) */
mtlr r31 /* (TEST/DEBUG) */
blrl /* (TEST/DEBUG) */
bne cr6,nopir8 /* (TEST/DEBUG) */
mfspr r4,pir /* (TEST/DEBUG) */
b gotpir8 /* (TEST/DEBUG) */
nopir8: li r4,0 /* (TEST/DEBUG) */
gotpir8: /* (TEST/DEBUG) */
lis r31,HIGH_ADDR(EXT(dbgDispLL)) /* (TEST/DEBUG) */
rlwinm r4,r4,24,4,7 /* (TEST/DEBUG) */
li r3,0 /* (TEST/DEBUG) */
lwz r5,0x280(br0) /* (TEST/DEBUG) */
oris r4,r4,0x3030 /* (TEST/DEBUG) */
ori r31,r31,LOW_ADDR(EXT(dbgDispLL)) /* (TEST/DEBUG) */
ori r4,r4,0x3430 /* (TEST/DEBUG) */
mtlr r31 /* (TEST/DEBUG) */
blrl /* (TEST/DEBUG) */
nono3:
lmw r1,0x284(br0) /* (TEST/DEBUG) */
lwz r0,0x280(br0) /* (TEST/DEBUG) */
li r6,0 /* (TEST/DEBUG) */
stw r6,0x20(br0) /* (TEST/DEBUG) */
mtdec r7 /* (TEST/DEBUG) */
#endif
li r21,0 ; Assume no processor register for now
lis r12,hi16(EXT(hw_counts)) ; Get the high part of the interrupt counters
bne- cr6,nopirhere ; Jump if this processor does not have a PIR...
mfspr r21,pir ; Get the PIR
nopirhere: ori r12,r12,lo16(EXT(hw_counts)) ; Get the low part of the interrupt counters
rlwinm r21,r21,8,20,23 ; Get index to processor counts
mtcrf 0x80,r0 /* Set our CR0 to the high nybble of the request code */
rlwinm r6,r0,1,0,31 /* Move sign bit to the end */
cmplwi cr1,r11,T_SYSTEM_CALL /* Did we get a system call? */
crandc cr0_lt,cr0_lt,cr0_gt /* See if we have R0 equal to 0b10xx...x */
add r12,r12,r21 ; Point to the processor count area
cmplwi cr3,r11,T_IN_VAIN /* Was this all in vain? All for nothing? */
lwzx r22,r12,r11 ; Get the old value
cmplwi cr2,r6,1 /* See if original R0 had the CutTrace request code in it */
addi r22,r22,1 ; Count this one
cmplwi cr4,r11,T_SIGP /* Indicate if we had a SIGP 'rupt */
stwx r22,r12,r11 ; Store it back
beq- cr3,EatRupt /* Interrupt was all for nothing... */
cmplwi cr3,r11,T_MACHINE_CHECK ; Did we get a machine check?
bne+ cr1,noCutT /* Not a system call... */
bnl+ cr0,noCutT /* R0 not 0b10xxx...x, can't be any kind of magical system call... */
beq- cr2,isCutTrace /* This is a CutTrace system call */
/*
* Here's where we call the firmware. If it returns T_IN_VAIN, that means
* that it has handled the interruption. Remember: thou shalt not trash R13
* or R20 while you are away. Anything else is ok.
*/
lis r1,HIGH_ADDR(EXT(FirmwareCall)) /* Top half of firmware call handler */
ori r1,r1,LOW_ADDR(EXT(FirmwareCall)) /* Bottom half of it */
lwz r3,saver3(r13) /* Restore the first parameter, the rest are ok already */
mtlr r1 /* Get it in the link register */
blrl /* Call the handler */
#if RUPTTRC
lis r7,0x7FFF /* (TEST/DEBUG) */
mfdec r6 /* (TEST/DEBUG) */
or r7,r7,r6 /* (TEST/DEBUG) */
mtdec r7 /* (TEST/DEBUG) */
li r7,0x20 /* (TEST/DEBUG) */
lwarx r1,0,r7 ; ?
mpwait4: lwarx r1,0,r7 /* (TEST/DEBUG) */
mr. r1,r1 /* (TEST/DEBUG) */
bne- mpwait4 /* (TEST/DEBUG) */
stwcx. r7,0,r7 /* (TEST/DEBUG) */
bne- mpwait4 /* (TEST/DEBUG) */
stw r0,0x280(br0) /* (TEST/DEBUG) */
stmw r1,0x284(br0) /* (TEST/DEBUG) */
bne cr7,nono4 /* (TEST/DEBUG) */
lwz r0,0(br0) /* (TEST/DEBUG) */
mr. r0,r0 /* (TEST/DEBUG) */
beq+ nono4 /* (TEST/DEBUG) */
bne cr6,nopir9 /* (TEST/DEBUG) */
mfspr r4,pir /* (TEST/DEBUG) */
b gotpir9 /* (TEST/DEBUG) */
nopir9: li r4,0 /* (TEST/DEBUG) */
gotpir9: /* (TEST/DEBUG) */
lis r31,HIGH_ADDR(EXT(dbgDispLL)) /* (TEST/DEBUG) */
rlwinm r4,r4,24,4,7 /* (TEST/DEBUG) */
mr r5,r3 /* (TEST/DEBUG) */
li r3,0 /* (TEST/DEBUG) */
oris r4,r4,0x3030 /* (TEST/DEBUG) */
ori r31,r31,LOW_ADDR(EXT(dbgDispLL)) /* (TEST/DEBUG) */
ori r4,r4,0x3530 /* (TEST/DEBUG) */
mtlr r31 /* (TEST/DEBUG) */
blrl /* (TEST/DEBUG) */
mtdec r25 /* (TEST/DEBUG) */
nono4:
lmw r1,0x284(br0) /* (TEST/DEBUG) */
lwz r0,0x280(br0) /* (TEST/DEBUG) */
li r7,0 /* (TEST/DEBUG) */
stw r7,0x20(br0) /* (TEST/DEBUG) */
mtdec r6 /* (TEST/DEBUG) */
#endif
cmplwi r3,T_IN_VAIN /* Was it handled? */
mfsprg r2,0 /* Restore the per_processor area */
beq+ EatRupt /* Interrupt was handled... */
mr r11,r3 /* Put the 'rupt code in the right register */
b noSIGP /* Go to the normal system call handler */
isCutTrace:
li r7,-32768 /* Get a 0x8000 for the exception code */
bne- cr5,EatRupt /* Tracing is disabled... */
sth r7,LTR_excpt(r20) /* Modify the exception type to a CutTrace */
b EatRupt /* Time to go home... */
/* We are here 'cause we didn't have a CutTrace system call */
noCutT: beq- cr3,MachineCheck ; Whoa... Machine check...
bne+ cr4,noSIGP /* Skip away if we didn't get a SIGP... */
lis r6,HIGH_ADDR(EXT(MPsignalFW)) /* Top half of SIGP handler */
ori r6,r6,LOW_ADDR(EXT(MPsignalFW)) /* Bottom half of it */
mtlr r6 /* Get it in the link register */
blrl /* Call the handler - we'll only come back if this is an AST, */
/* 'cause FW can't handle that */
mfsprg r2,0 /* Restore the per_processor area */
;
; The following interrupts are the only ones that can be redriven
; by the higher level code or emulation routines.
;
Redrive: cmplwi cr0,r3,T_IN_VAIN /* Did the signal handler eat the signal? */
mr r11,r3 /* Move it to the right place */
beq+ cr0,EatRupt /* Bail now if the signal handler processed the signal... */
/*
* Here's where we check for the other fast-path exceptions: translation exceptions,
* emulated instructions, etc.
*/
noSIGP: cmplwi cr3,r11,T_ALTIVEC_ASSIST ; Check for an Altivec denorm assist
cmplwi cr1,r11,T_PROGRAM /* See if we got a program exception */
cmplwi cr2,r11,T_INSTRUCTION_ACCESS /* Check on an ISI */
bne+ cr3,noAltivecAssist ; It is not an assist...
b EXT(AltivecAssist) ; It is an assist...
noAltivecAssist:
bne+ cr1,noEmulate ; No emulation here...
b EXT(Emulate) ; Go try to emulate...
noEmulate: cmplwi cr3,r11,T_CSWITCH /* Are we context switching */
cmplwi r11,T_DATA_ACCESS /* Check on a DSI */
beq- cr2,DSIorISI /* It's a PTE fault... */
beq- cr3,conswtch /* It's a context switch... */
bne+ PassUp /* It's not a PTE fault... */
/*
* This call will either handle the fault, in which case it will not
* return, or return to pass the fault up the line.
*/
DSIorISI:
lis r7,HIGH_ADDR(EXT(handlePF)) /* Top half of DSI handler */
ori r7,r7,LOW_ADDR(EXT(handlePF)) /* Bottom half of it */
mtlr r7 /* Get it in the link register */
mr r3,r11 /* Move the 'rupt code */
blrl /* See if we can handle this fault */
#if RUPTTRC
bne cr7,nononono2 /* (TEST/DEBUG) */
lwz r7,0(br0) /* (TEST/DEBUG) */
mr. r7,r7 /* (TEST/DEBUG) */
beq+ nononono2 /* (TEST/DEBUG) */
#if 0
lis r7,0x7FFF /* (TEST/DEBUG) */
mfdec r2 /* (TEST/DEBUG) */
or r7,r7,r2 /* (TEST/DEBUG) */
mtdec r7 /* (TEST/DEBUG) */
li r7,0x20 /* (TEST/DEBUG) */
lwarx r0,0,r7 ; ?
yesyesyes2: lwarx r0,0,r7 /* (TEST/DEBUG) */
mr. r0,r0 /* (TEST/DEBUG) */
li r0,1 /* (TEST/DEBUG) */
bne- yesyesyes2 /* (TEST/DEBUG) */
stwcx. r0,0,r7 /* (TEST/DEBUG) */
bne- yesyesyes2 /* (TEST/DEBUG) */
#endif
stw r0,0x280(br0) /* (TEST/DEBUG) */
stmw r1,0x284(br0) /* (TEST/DEBUG) */
mr r20,r3
bne cr6,nopir10 /* (TEST/DEBUG) */
mfspr r4,pir /* (TEST/DEBUG) */
b gotpir10 /* (TEST/DEBUG) */
nopir10: li r4,0 /* (TEST/DEBUG) */
gotpir10: /* (TEST/DEBUG) */
lis r31,HIGH_ADDR(EXT(dbgDispLL)) /* (TEST/DEBUG) */
rlwinm r4,r4,24,4,7 /* (TEST/DEBUG) */
li r3,0 /* (TEST/DEBUG) */
or r4,r4,r20 /* (TEST/DEBUG) */
lwz r5,savedar(r13) /* (TEST/DEBUG) */
oris r4,r4,0x3030 /* (TEST/DEBUG) */
ori r31,r31,LOW_ADDR(EXT(dbgDispLL)) /* (TEST/DEBUG) */
ori r4,r4,0x3630 /* (TEST/DEBUG) */
mtlr r31 /* (TEST/DEBUG) */
blrl /* (TEST/DEBUG) */
#if 0
lis r31,HIGH_ADDR(EXT(dbgRegs)) /* (TEST/DEBUG) */
ori r31,r31,LOW_ADDR(EXT(dbgRegs)) /* (TEST/DEBUG) */
mtlr r31 /* (TEST/DEBUG) */
li r3,0 /* (TEST/DEBUG) */
blrl /* (TEST/DEBUG) */
#endif
lmw r1,0x284(br0) /* (TEST/DEBUG) */
lwz r0,0x280(br0) /* (TEST/DEBUG) */
li r0,0 /* (TEST/DEBUG) */
stw r0,0x20(br0) /* (TEST/DEBUG) */
mtdec r2 /* (TEST/DEBUG) */
nononono2: /* (TEST/DEBUG) */
#endif
lwz r0,savesrr1(r13) ; Get the MSR in use at exception time
mfsprg r2, 0 /* Get back per_proc */
cmplwi cr1,r3,T_IN_VAIN ; Was it handled?
andi. r4,r0,lo16(MASK(MSR_RI)) ; See if the recover bit is on
mr r11,r3 /* Make sure we can find this later */
beq+ cr1,EatRupt ; Yeah, just blast back to the user...
andc r0,r0,r4 ; Remove the recover bit
beq+ PassUp ; Not on, normal case...
lwz r4,savesrr0(r13) ; Get the failing instruction address
lwz r5,savecr(r13) ; Get the condition register
stw r0,savesrr1(r13) ; Save the result MSR
addi r4,r4,4 ; Skip failing instruction
rlwinm r5,r5,0,3,1 ; Clear CR0_EQ to let emulation code know we failed
stw r4,savesrr0(r13) ; Save instruction address
stw r4,savecr(r13) ; And the resume CR
b EatRupt ; Resume emulated code
/*
* Here is where we handle the context switch firmware call. The old
* context has been saved, and the new savearea in in saver3. We'll just
* muck around with the savearea pointers, and then join the exit routine
*/
conswtch: lwz r28,SAVflags(r13) /* The the flags of the current */
mr r29,r13 /* Save the save */
rlwinm r30,r13,0,0,19 /* Get the start of the savearea block */
lwz r5,saver3(r13) /* Switch to the new savearea */
oris r28,r28,HIGH_ADDR(SAVattach) /* Turn on the attached flag */
lwz r30,SACvrswap(r30) /* get real to virtual translation */
mr r13,r5 /* Switch saveareas */
xor r27,r29,r30 /* Flip to virtual */
stw r28,SAVflags(r29) /* Stash it back */
stw r27,saver3(r5) /* Push the new savearea to the switch to routine */
b EatRupt /* Start 'er up... */
;
; Handle machine check here.
;
; ?
;
MachineCheck:
lwz r27,savesrr1(r13) ; ?
rlwinm. r11,r27,0,dcmck,dcmck ; ?
beq+ notDCache ; ?
mfspr r11,msscr0 ; ?
dssall ; ?
sync
lwz r27,savesrr1(r13) ; ?
hiccup: cmplw r27,r27 ; ?
bne- hiccup ; ?
isync ; ?
oris r11,r11,hi16(dl1hwfm) ; ?
mtspr msscr0,r11 ; ?
rstbsy: mfspr r11,msscr0 ; ?
rlwinm. r11,r11,0,dl1hwf,dl1hwf ; ?
bne rstbsy ; ?
sync ; ?
li r11,T_IN_VAIN ; ?
b EatRupt ; ?
notDCache:
;
; Check if the failure was in
; ml_probe_read. If so, this is expected, so modify the PC to
; ml_proble_read_mck and then eat the exception.
;
lwz r30,savesrr0(r13) ; Get the failing PC
lis r28,hi16(EXT(ml_probe_read_mck)) ; High order part
lis r27,hi16(EXT(ml_probe_read)) ; High order part
ori r28,r28,lo16(EXT(ml_probe_read_mck)) ; Get the low part
ori r27,r27,lo16(EXT(ml_probe_read)) ; Get the low part
cmplw r30,r28 ; Check highest possible
cmplw cr1,r30,r27 ; Check lowest
bge- PassUp ; Outside of range
blt- cr1,PassUp ; Outside of range
;
; We need to fix up the BATs here because the probe
; routine messed them all up... As long as we are at it,
; fix up to return directly to caller of probe.
;
lwz r30,saver5(r13) ; Get proper DBAT values
lwz r28,saver6(r13)
lwz r27,saver7(r13)
lwz r11,saver8(r13)
lwz r18,saver9(r13)
sync
mtdbatu 0,r30 ; Restore DBAT 0 high
mtdbatl 0,r28 ; Restore DBAT 0 low
mtdbatu 1,r27 ; Restore DBAT 1 high
mtdbatu 2,r11 ; Restore DBAT 2 high
mtdbatu 3,r18 ; Restore DBAT 3 high
sync
lwz r28,savelr(r13) ; Get return point
lwz r27,saver0(r13) ; Get the saved MSR
li r30,0 ; Get a failure RC
stw r28,savesrr0(r13) ; Set the return point
stw r27,savesrr1(r13) ; Set the continued MSR
stw r30,saver3(r13) ; Set return code
li r11,T_IN_VAIN ; Set new interrupt code
b EatRupt ; Yum, yum, eat it all up...
/*
* Here's where we come back from some instruction emulator. If we come back with
* T_IN_VAIN, the emulation is done and we should just reload state and directly
* go back to the interrupted code. Otherwise, we'll check to see if
* we need to redrive with a different interrupt, i.e., DSI.
*/
.align 5
.globl EXT(EmulExit)
LEXT(EmulExit)
cmplwi r11,T_IN_VAIN /* Was it emulated? */
lis r1,hi16(SAVredrive) ; Get redrive request
mfsprg r2,0 ; Restore the per_proc area
beq+ EatRupt /* Yeah, just blast back to the user... */
lwz r4,SAVflags(r13) ; Pick up the flags
and. r0,r4,r1 ; Check if redrive requested
andc r4,r4,r1 ; Clear redrive
beq+ PassUp ; No redrive, just keep on going...
lwz r3,saveexception(r13) ; Restore exception code
stw r4,SAVflags(r13) ; Set the flags
b Redrive ; Redrive the exception...
/* Jump into main handler code switching on VM at the same time */
/* We assume kernel data is mapped contiguously in physical
* memory, otherwise we'd need to switch on (at least) virtual data.
* SRs are already set up.
*/
PassUp: lwz r2,PP_PHYS_EXCEPTION_HANDLERS(r2) /* Pick up the exception handler base */
lwzx r6,r2,r11 /* Get the actual exception handler address */
PassUpDeb: lwz r8,SAVflags(r13) /* Get the flags */
mtsrr0 r6 /* Set up the handler address */
oris r8,r8,HIGH_ADDR(SAVattach) /* Since we're passing it up, attach it */
rlwinm r5,r13,0,0,19 /* Back off to the start of savearea block */
mfmsr r3 /* Get our MSR */
stw r8,SAVflags(r13) /* Pass up the flags */
rlwinm r3,r3,0,MSR_BE_BIT+1,MSR_SE_BIT-1 /* Clear all but the trace bits */
li r2,MSR_SUPERVISOR_INT_OFF /* Get our normal MSR value */
lwz r5,SACvrswap(r5) /* Get real to virtual conversion */
or r2,r2,r3 /* Keep the trace bits if they're on */
mr r3,r11 /* Pass the exception code in the paramter reg */
mtsrr1 r2 /* Set up our normal MSR value */
xor r4,r13,r5 /* Pass up the virtual address of context savearea */
#if RUPTTRC
lis r20,0x7FFF /* (TEST/DEBUG) */
mfdec r25 /* (TEST/DEBUG) */
or r20,r20,r25 /* (TEST/DEBUG) */
mtdec r20 /* (TEST/DEBUG) */
li r20,0x20 /* (TEST/DEBUG) */
lwarx r21,0,r20 ; ?
mpwait5: lwarx r21,0,r20 /* (TEST/DEBUG) */
mr. r21,r21 /* (TEST/DEBUG) */
bne- mpwait5 /* (TEST/DEBUG) */
stwcx. r20,0,r20 /* (TEST/DEBUG) */
bne- mpwait5 /* (TEST/DEBUG) */
stw r0,0x280(br0) /* (TEST/DEBUG) */
stmw r1,0x284(br0) /* (TEST/DEBUG) */
bne cr7,nono9 /* (TEST/DEBUG) */
lwz r0,0(br0) /* (TEST/DEBUG) */
mr. r0,r0 /* (TEST/DEBUG) */
beq+ nono9 /* (TEST/DEBUG) */
mr r30,r4 /* (TEST/DEBUG) */
mr r24,r5 /* (TEST/DEBUG) */
bne cr6,nopir11 /* (TEST/DEBUG) */
mfspr r4,pir /* (TEST/DEBUG) */
b gotpir11 /* (TEST/DEBUG) */
nopir11: li r4,0 /* (TEST/DEBUG) */
gotpir11: /* (TEST/DEBUG) */
lis r31,HIGH_ADDR(EXT(dbgDispLL)) /* (TEST/DEBUG) */
rlwinm r4,r4,24,4,7 /* (TEST/DEBUG) */
li r3,0 /* (TEST/DEBUG) */
mr r5,r6 /* (TEST/DEBUG) */
oris r4,r4,0x3030 /* (TEST/DEBUG) */
ori r31,r31,LOW_ADDR(EXT(dbgDispLL)) /* (TEST/DEBUG) */
ori r4,r4,0x3930 /* (TEST/DEBUG) */
mtlr r31 /* (TEST/DEBUG) */
blrl /* (TEST/DEBUG) */
bne cr6,nopir12 /* (TEST/DEBUG) */
mfspr r4,pir /* (TEST/DEBUG) */
b gotpir12 /* (TEST/DEBUG) */
nopir12: li r4,0 /* (TEST/DEBUG) */
gotpir12: /* (TEST/DEBUG) */
lis r31,HIGH_ADDR(EXT(dbgDispLL)) /* (TEST/DEBUG) */
rlwinm r4,r4,24,4,7 /* (TEST/DEBUG) */
li r3,0 /* (TEST/DEBUG) */
mr r5,r30 /* (TEST/DEBUG) */
oris r4,r4,0x3031 /* (TEST/DEBUG) */
ori r31,r31,LOW_ADDR(EXT(dbgDispLL)) /* (TEST/DEBUG) */
ori r4,r4,0x3130 /* (TEST/DEBUG) */
mtlr r31 /* (TEST/DEBUG) */
blrl /* (TEST/DEBUG) */
bne cr6,nopir13 /* (TEST/DEBUG) */
mfspr r4,pir /* (TEST/DEBUG) */
b gotpir13 /* (TEST/DEBUG) */
nopir13: li r4,0 /* (TEST/DEBUG) */
gotpir13: /* (TEST/DEBUG) */
lis r31,HIGH_ADDR(EXT(dbgDispLL)) /* (TEST/DEBUG) */
rlwinm r4,r4,24,4,7 /* (TEST/DEBUG) */
li r3,0 /* (TEST/DEBUG) */
xor r5,r30,r24 /* (TEST/DEBUG) */
oris r4,r4,0x3031 /* (TEST/DEBUG) */
ori r31,r31,LOW_ADDR(EXT(dbgDispLL)) /* (TEST/DEBUG) */
ori r4,r4,0x3131 /* (TEST/DEBUG) */
mtlr r31 /* (TEST/DEBUG) */
blrl /* (TEST/DEBUG) */
bne cr6,nopir14 /* (TEST/DEBUG) */
mfspr r4,pir /* (TEST/DEBUG) */
b gotpir14 /* (TEST/DEBUG) */
nopir14: li r4,0 /* (TEST/DEBUG) */
gotpir14: /* (TEST/DEBUG) */
lis r31,HIGH_ADDR(EXT(dbgDispLL)) /* (TEST/DEBUG) */
rlwinm r4,r4,24,4,7 /* (TEST/DEBUG) */
li r3,0 /* (TEST/DEBUG) */
mr r5,r25 /* (TEST/DEBUG) */
oris r4,r4,0x3031 /* (TEST/DEBUG) */
ori r31,r31,LOW_ADDR(EXT(dbgDispLL)) /* (TEST/DEBUG) */
ori r4,r4,0x3132 /* (TEST/DEBUG) */
mtlr r31 /* (TEST/DEBUG) */
blrl /* (TEST/DEBUG) */
bne cr6,nopir15 /* (TEST/DEBUG) */
mfspr r4,pir /* (TEST/DEBUG) */
b gotpir15 /* (TEST/DEBUG) */
nopir15: li r4,0 /* (TEST/DEBUG) */
gotpir15: /* (TEST/DEBUG) */
lis r31,HIGH_ADDR(EXT(dbgDispLL)) /* (TEST/DEBUG) */
rlwinm r4,r4,24,4,7 /* (TEST/DEBUG) */
li r3,0 /* (TEST/DEBUG) */
mfsrr0 r5 /* (TEST/DEBUG) */
oris r4,r4,0x3031 /* (TEST/DEBUG) */
ori r31,r31,LOW_ADDR(EXT(dbgDispLL)) /* (TEST/DEBUG) */
ori r4,r4,0x3133 /* (TEST/DEBUG) */
mtlr r31 /* (TEST/DEBUG) */
blrl /* (TEST/DEBUG) */
nono9:
lmw r1,0x284(br0) /* (TEST/DEBUG) */
lwz r0,0x280(br0) /* (TEST/DEBUG) */
li r20,0 /* (TEST/DEBUG) */
stw r20,0x20(br0) /* (TEST/DEBUG) */
mtdec r25 /* (TEST/DEBUG) */
#endif
rfi /* Launch the exception handler */
.long 0 /* Leave these here gol durn it! */
.long 0
.long 0
.long 0
.long 0
.long 0
.long 0
.long 0
/*
* This routine is the only place where we return from an interruption.
* Anyplace else is wrong. Even if I write the code, it's still wrong
* Feel free to come by and slap me if I do do it. Even though I may
* have had a good reason to do it.
*
* All we need to remember here is that R13 must point to the savearea
* that has the context we need to load up. Translation and interruptions
* must be disabled.
*
* This code always loads the context in the savearea pointed to
* by R13. In the process, it throws away the savearea. If there
* is any tomfoolery with savearea stacks, it must be taken care of
* before we get here.
*/
EatRupt: mr r31,r13 /* Move the savearea pointer to the far end of the register set */
EatRupt2: mfsprg r2,0 /* Get the per_proc block */
/*
* First we see if we are able to free the new savearea.
* If it is not attached to anything, put it on the free list.
* This is real dangerous, we haven't restored context yet...
* So, the free savearea chain lock must stay until the bitter end!
*/
#if RUPTTRC
lis r18,0x7FFF /* (TEST/DEBUG) */
mfdec r25 /* (TEST/DEBUG) */
or r18,r18,r25 /* (TEST/DEBUG) */
mtdec r18 /* (TEST/DEBUG) */
li r18,0x20 /* (TEST/DEBUG) */
lwarx r19,0,r18 ; ?
mpwait6: lwarx r19,0,r18 /* (TEST/DEBUG) */
mr. r19,r19 /* (TEST/DEBUG) */
bne- mpwait6 /* (TEST/DEBUG) */
stwcx. r18,0,r18 /* (TEST/DEBUG) */
bne- mpwait6 /* (TEST/DEBUG) */
stw r0,0x280(br0) /* (TEST/DEBUG) */
stmw r1,0x284(br0) /* (TEST/DEBUG) */
bne cr7,nono5 /* (TEST/DEBUG) */
lwz r0,0(br0) /* (TEST/DEBUG) */
mr. r0,r0 /* (TEST/DEBUG) */
beq+ nono5 /* (TEST/DEBUG) */
bne cr6,nopir16 /* (TEST/DEBUG) */
mfspr r4,pir /* (TEST/DEBUG) */
b gotpir16 /* (TEST/DEBUG) */
nopir16: li r4,0 /* (TEST/DEBUG) */
gotpir16: /* (TEST/DEBUG) */
rlwinm r24,r31,0,0,19 /* (TEST/DEBUG) */
mr r5,r31 /* (TEST/DEBUG) */
mr r30,r31 /* (TEST/DEBUG) */
lwz r24,SACvrswap(r24) /* (TEST/DEBUG) */
lis r31,HIGH_ADDR(EXT(dbgDispLL)) /* (TEST/DEBUG) */
rlwinm r4,r4,24,4,7 /* (TEST/DEBUG) */
li r3,0 /* (TEST/DEBUG) */
oris r4,r4,0x3030 /* (TEST/DEBUG) */
ori r31,r31,LOW_ADDR(EXT(dbgDispLL)) /* (TEST/DEBUG) */
ori r4,r4,0x3730 /* (TEST/DEBUG) */
mtlr r31 /* (TEST/DEBUG) */
blrl /* (TEST/DEBUG) */
bne cr6,nopir17 /* (TEST/DEBUG) */
mfspr r4,pir /* (TEST/DEBUG) */
b gotpir17 /* (TEST/DEBUG) */
nopir17: li r4,0 /* (TEST/DEBUG) */
gotpir17: /* (TEST/DEBUG) */
lis r31,HIGH_ADDR(EXT(dbgDispLL)) /* (TEST/DEBUG) */
rlwinm r4,r4,24,4,7 /* (TEST/DEBUG) */
li r3,0 /* (TEST/DEBUG) */
xor r5,r30,r24 /* (TEST/DEBUG) */
oris r4,r4,0x3030 /* (TEST/DEBUG) */
ori r31,r31,LOW_ADDR(EXT(dbgDispLL)) /* (TEST/DEBUG) */
ori r4,r4,0x3731 /* (TEST/DEBUG) */
mtlr r31 /* (TEST/DEBUG) */
blrl /* (TEST/DEBUG) */
bne cr6,nopir18 /* (TEST/DEBUG) */
mfspr r4,pir /* (TEST/DEBUG) */
b gotpir18 /* (TEST/DEBUG) */
nopir18: li r4,0 /* (TEST/DEBUG) */
gotpir18: /* (TEST/DEBUG) */
lis r31,HIGH_ADDR(EXT(dbgDispLL)) /* (TEST/DEBUG) */
rlwinm r4,r4,24,4,7 /* (TEST/DEBUG) */
li r3,0 /* (TEST/DEBUG) */
mfsprg r5,1 /* (TEST/DEBUG) */
oris r4,r4,0x3030 /* (TEST/DEBUG) */
ori r31,r31,LOW_ADDR(EXT(dbgDispLL)) /* (TEST/DEBUG) */
ori r4,r4,0x3830 /* (TEST/DEBUG) */
mtlr r31 /* (TEST/DEBUG) */
blrl /* (TEST/DEBUG) */
bne cr6,nopir19 /* (TEST/DEBUG) */
mfspr r4,pir /* (TEST/DEBUG) */
b gotpir19 /* (TEST/DEBUG) */
nopir19: li r4,0 /* (TEST/DEBUG) */
gotpir19: /* (TEST/DEBUG) */
lis r31,HIGH_ADDR(EXT(dbgDispLL)) /* (TEST/DEBUG) */
rlwinm r4,r4,24,4,7 /* (TEST/DEBUG) */
li r3,0 /* (TEST/DEBUG) */
lwz r5,savesrr0(r30) /* (TEST/DEBUG) */
oris r4,r4,0x3031 /* (TEST/DEBUG) */
ori r31,r31,LOW_ADDR(EXT(dbgDispLL)) /* (TEST/DEBUG) */
ori r4,r4,0x3130 /* (TEST/DEBUG) */
mtlr r31 /* (TEST/DEBUG) */
blrl /* (TEST/DEBUG) */
bne cr6,nopir20 /* (TEST/DEBUG) */
mfspr r4,pir /* (TEST/DEBUG) */
b gotpir20 /* (TEST/DEBUG) */
nopir20: li r4,0 /* (TEST/DEBUG) */
gotpir20: /* (TEST/DEBUG) */
lis r31,HIGH_ADDR(EXT(dbgDispLL)) /* (TEST/DEBUG) */
rlwinm r4,r4,24,4,7 /* (TEST/DEBUG) */
li r3,0 /* (TEST/DEBUG) */
lwz r5,savesrr1(r30) /* (TEST/DEBUG) */
oris r4,r4,0x3031 /* (TEST/DEBUG) */
ori r31,r31,LOW_ADDR(EXT(dbgDispLL)) /* (TEST/DEBUG) */
ori r4,r4,0x3131 /* (TEST/DEBUG) */
mtlr r31 /* (TEST/DEBUG) */
blrl /* (TEST/DEBUG) */
bne cr6,nopir21 /* (TEST/DEBUG) */
mfspr r4,pir /* (TEST/DEBUG) */
b gotpir21 /* (TEST/DEBUG) */
nopir21: li r4,0 /* (TEST/DEBUG) */
gotpir21: /* (TEST/DEBUG) */
lis r31,HIGH_ADDR(EXT(dbgDispLL)) /* (TEST/DEBUG) */
rlwinm r4,r4,24,4,7 /* (TEST/DEBUG) */
li r3,0 /* (TEST/DEBUG) */
lwz r5,savelr(r30) /* (TEST/DEBUG) */
oris r4,r4,0x3031 /* (TEST/DEBUG) */
ori r31,r31,LOW_ADDR(EXT(dbgDispLL)) /* (TEST/DEBUG) */
ori r4,r4,0x3132 /* (TEST/DEBUG) */
mtlr r31 /* (TEST/DEBUG) */
blrl /* (TEST/DEBUG) */
nono5:
lmw r1,0x284(br0) /* (TEST/DEBUG) */
lwz r0,0x280(br0) /* (TEST/DEBUG) */
li r19,0 /* (TEST/DEBUG) */
stw r19,0x20(br0) /* (TEST/DEBUG) */
mtdec r25 /* (TEST/DEBUG) */
#endif
/*
* It's dangerous here. We haven't restored anything from the current savearea yet.
* And, we mark it the active one. So, if we get an exception in here, it is
* unrecoverable. Unless we mess up, we can't get any kind of exception. So,
* it is important to assay this code as only the purest of gold.
*
* But first, see if there is a savearea hanging off of quickfret. If so,
* we release that one first and then come back for the other. We should rarely
* see one, they appear when FPU or VMX context is discarded by either returning
* to a higher exception level, or explicitly.
*
* A word about QUICKFRET: Multiple saveareas may be queued for release. It is
* the responsibility of the queuer to insure that the savearea is not multiply
* queued and that the appropriate inuse bits are reset.
*/
#define TRCSAVE 0
#if TRCSAVE
lwz r30,saver0(r31) ; (TEST/DEBUG) Get users R0
lwz r20,saveexception(r31) ; (TEST/DEBUG) Returning from trace?
xor r30,r20,r30 ; (TEST/DEBUG) Make code
rlwinm r30,r30,1,0,31 ; (TEST/DEBUG) Make an easy test
cmplwi cr5,r30,0x61 ; (TEST/DEBUG) See if this is a trace
#endif
mr r18,r31 /* Save the savearea pointer */
lwz r19,PP_QUICKFRET(r2) /* Get the quick release savearea */
la r20,savesrr0(r18) /* Point to the first thing we look at */
li r0,0 /* Get a zero */
dcbt 0,r20 /* Touch in the first thing in the real savearea */
la r21,savesr0(r18) /* Point to the first thing we restore */
lis r30,HIGH_ADDR(EXT(saveanchor)) /* Get the high part of the anchor */
stw r0,PP_QUICKFRET(r2) /* Clear quickfret pointer */
ori r30,r30,LOW_ADDR(EXT(saveanchor)) /* Bottom half of the anchor */
dcbt 0,r21 /* Touch in the first thing */
#if TRCSAVE
beq- cr5,trkill0 ; (TEST/DEBUG) Do not trace this type
lwz r14,LOW_ADDR(traceMask-EXT(ExceptionVectorsStart))(br0) ; (TEST/DEBUG) Get the trace mask
mr. r14,r14 ; (TEST/DEBUG) Is it stopped?
beq- trkill0 ; (TEST/DEBUG) yes...
bl cte ; (TEST/DEBUG) Trace this
stw r18,LTR_r1(r20) ; (TEST/DEBUG) Normal savearea
stw r19,LTR_r2(r20) ; (TEST/DEBUG) Quickfret savearea
trkill0:
#endif
lwarx r22,0,r30 ; ?
rtlck: lwarx r22,0,r30 /* Grab the lock value */
li r23,1 /* Use part of the delay time */
mr. r22,r22 /* Is it locked? */
bne- rtlcks /* Yeah, wait for it to clear... */
stwcx. r23,0,r30 /* Try to seize that there durn lock */
beq+ fretagain ; Got it...
b rtlck /* Collision, try again... */
rtlcks: lwz r22,SVlock(r30) /* Get that lock in here */
mr. r22,r22 /* Is it free yet? */
beq+ rtlck /* Yeah, try for it again... */
b rtlcks /* Sniff away... */
;
; Lock gotten, toss the saveareas
;
fretagain:
#if TRCSAVE
beq- cr5,trkill1 ; (TEST/DEBUG) Do not trace this type
lwz r14,LOW_ADDR(traceMask-EXT(ExceptionVectorsStart))(br0) ; (TEST/DEBUG) Get the trace mask
mr. r14,r14 ; (TEST/DEBUG) Is it stopped?
beq- trkill1 ; (TEST/DEBUG) yes...
li r0,1 ; (TEST/DEBUG) ID number
bl cte ; (TEST/DEBUG) Trace this
stw r18,LTR_r1(r20) ; (TEST/DEBUG) Normal savearea
stw r19,LTR_r2(r20) ; (TEST/DEBUG) Quickfret savearea
trkill1:
#endif
mr. r18,r18 ; Are we actually done here?
beq- donefret ; Yeah...
mr. r31,r19 ; Is there a quickfret to do?
beq+ noqfrt ; Nope...
lwz r19,SAVqfret(r19) ; Yes, get the next in line
#if TRCSAVE
beq- cr5,trkill2 ; (TEST/DEBUG) Do not trace this type
lwz r14,LOW_ADDR(traceMask-EXT(ExceptionVectorsStart))(br0) ; (TEST/DEBUG) Get the trace mask
mr. r14,r14 ; (TEST/DEBUG) Is it stopped?
beq- trkill2 ; (TEST/DEBUG) yes...
li r0,2 ; (TEST/DEBUG) ID number
bl cte ; (TEST/DEBUG) Trace this
stw r18,LTR_r1(r20) ; (TEST/DEBUG) Normal savearea
stw r19,LTR_r2(r20) ; (TEST/DEBUG) next quickfret savearea
stw r31,LTR_r3(r20) ; (TEST/DEBUG) Current one to toss
trkill2:
#endif
b doqfrt ; Go do it...
noqfrt: mr r31,r18 ; Set the area to release
li r18,0 ; Show we have done it
#if TRCSAVE
beq- cr5,trkill3 ; (TEST/DEBUG) Do not trace this type
lwz r14,LOW_ADDR(traceMask-EXT(ExceptionVectorsStart))(br0) ; (TEST/DEBUG) Get the trace mask
mr. r14,r14 ; (TEST/DEBUG) Is it stopped?
beq- trkill3 ; (TEST/DEBUG) yes...
li r0,3 ; (TEST/DEBUG) ID number
bl cte ; (TEST/DEBUG) Trace this
stw r18,LTR_r1(r20) ; (TEST/DEBUG) Normal savearea
stw r19,LTR_r2(r20) ; (TEST/DEBUG) next quickfret savearea
stw r31,LTR_r3(r20) ; (TEST/DEBUG) Current one to toss
trkill3:
#endif
doqfrt: li r0,0 ; Get a constant 0
lis r26,0x8000 /* Build a bit mask and assume first savearea */
stw r0,SAVqfret(r31) ; Make sure back chain is unlinked
lwz r28,SAVflags(r31) ; Get the flags for the old active one
#if TRCSAVE
beq- cr5,trkill4 ; (TEST/DEBUG) Do not trace this type
lwz r14,LOW_ADDR(traceMask-EXT(ExceptionVectorsStart))(br0) ; (TEST/DEBUG) Get the trace mask
mr. r14,r14 ; (TEST/DEBUG) Is it stopped?
beq- trkill4 ; (TEST/DEBUG) yes...
li r0,4 ; (TEST/DEBUG) ID number
bl cte ; (TEST/DEBUG) Trace this
stw r18,LTR_r1(r20) ; (TEST/DEBUG) Normal savearea
stw r19,LTR_r2(r20) ; (TEST/DEBUG) next quickfret savearea
stw r31,LTR_r3(r20) ; (TEST/DEBUG) Current one to toss
stw r28,LTR_r4(r20) ; (TEST/DEBUG) Save current flags
trkill4:
#endif
rlwinm r25,r31,21,31,31 /* Get position of savearea in block */
andis. r28,r28,HIGH_ADDR(SAVinuse) /* See if we need to free it */
srw r26,r26,r25 /* Get bit position to deallocate */
rlwinm r29,r31,0,0,19 /* Round savearea pointer to even page address */
bne- fretagain /* Still in use, we can't free this one... */
lwz r23,SACalloc(r29) /* Get the allocation for this block */
lwz r24,SVinuse(r30) /* Get the in use count */
mr r28,r23 ; (TEST/DEBUG) save for trace
or r23,r23,r26 /* Turn on our bit */
subi r24,r24,1 /* Show that this one is free */
cmplw r23,r26 /* Is our's the only one free? */
stw r23,SACalloc(r29) /* Save it out */
bne+ rstrest /* Nope, then the block is already on the free list */
lwz r22,SVfree(r30) /* Get the old head of the free list */
stw r29,SVfree(r30) /* Point the head at us now */
stw r22,SACnext(r29) ; Point us to the old last
rstrest: stw r24,SVinuse(r30) /* Set the in use count */
#if TRCSAVE
beq- cr5,trkill5 ; (TEST/DEBUG) Do not trace this type
lwz r14,LOW_ADDR(traceMask-EXT(ExceptionVectorsStart))(br0) ; (TEST/DEBUG) Get the trace mask
mr. r14,r14 ; (TEST/DEBUG) Is it stopped?
beq- trkill5 ; (TEST/DEBUG) yes...
li r0,5 ; (TEST/DEBUG) ID number
bl cte ; (TEST/DEBUG) Trace this
stw r18,LTR_r1(r20) ; (TEST/DEBUG) Normal savearea
stw r19,LTR_r2(r20) ; (TEST/DEBUG) Next quickfret savearea
stw r31,LTR_r3(r20) ; (TEST/DEBUG) Current one to toss
stw r28,LTR_srr1(r20) ; (TEST/DEBUG) Save the original allocation
stw r23,LTR_dar(r20) ; (TEST/DEBUG) Save the new allocation
stw r24,LTR_save(r20) ; (TEST/DEBUG) Save the new in use count
stw r22,LTR_lr(r20) ; (TEST/DEBUG) Save the old top of free list
stw r29,LTR_ctr(r20) ; (TEST/DEBUG) Save the new top of free list
trkill5:
#endif
b fretagain ; Go finish up the rest...
;
; Build the SR values depending upon destination. If we are going to the kernel,
; the SRs are almost all the way set up. SR14 (or the currently used copyin/out register)
; must be set to whatever it was at the last exception because it varies. All the rest
; have been set up already.
;
; If we are going into user space, we need to check a bit more. SR0, SR1, SR2, and
; SR14 (current implementation) must be restored always. The others must be set if
; they are different that what was loaded last time (i.e., tasks have switched).
; We check the last loaded address space ID and if the same, we skip the loads.
; This is a performance gain because SR manipulations are slow.
;
donefret: lwz r26,savesrr1(r31) ; Get destination state flags
lwz r15,PP_USERSPACE(r2) ; Pick up the user space ID we may launch
rlwinm. r17,r26,0,MSR_PR_BIT,MSR_PR_BIT ; See if we are going to user or system
lwz r16,PP_LASTSPACE(r2) ; Pick up the last loaded SR value
oris r13,r15,hi16(SEG_REG_PROT) ; Get the protection bits correct
cmplw cr3,r15,r15 ; Set that we do not need to stop streams
addis r14,r13,0x0010 ; Generate next SR value
beq- gotokern ; We are going into kernel state, SRs all set up...
mtsr sr0,r13 ; Set SR0
addis r13,r14,0x0010 ; Generate next SR value
cmplw cr3,r15,r16 ; See if most of the SRs are already loaded
mtsr sr1,r14 ; Set SR1
addis r14,r13,0x0010 ; Generate next SR value
mtsr sr2,r13 ; Set SR2
addis r13,r14,0x0010 ; Generate next SR value
mtsr sr3,r14 ; Set SR3
beq+ cr3,noloadsr ; SRs have not changed, no reload...
addis r14,r13,0x0010 ; Generate next SR value
mtsr sr4,r13 ; Set SR4
addis r13,r14,0x0010 ; Generate next SR value
mtsr sr5,r14 ; Set SR5
addis r14,r13,0x0010 ; Generate next SR value
mtsr sr6,r13 ; Set SR6
addis r13,r14,0x0010 ; Generate next SR value
mtsr sr7,r14 ; Set SR7
addis r14,r13,0x0010 ; Generate next SR value
mtsr sr8,r13 ; Set SR8
addis r13,r14,0x0010 ; Generate next SR value
mtsr sr9,r14 ; Set SR9
addis r14,r13,0x0010 ; Generate next SR value
mtsr sr10,r13 ; Set SR10
addis r13,r14,0x0010 ; Generate next SR value
mtsr sr11,r14 ; Set SR11
addis r14,r13,0x0010 ; Generate next SR value
mtsr sr12,r13 ; Set SR12
addis r13,r14,0x0010 ; Generate next SR value
mtsr sr13,r14 ; Set SR13
addis r14,r13,0x0010 ; Generate next SR value
mtsr sr14,r13 ; Set SR14
mtsr sr15,r14 ; Set SR15
stw r15,PP_LASTSPACE(r2) ; Set the last loaded SR value
b ngotokern ; All done with user state SRs...
noloadsr: oris r14,r15,hi16(SEG_REG_PROT|0x00E00000) ; Build SR14 (copyin/out) value
b loadsr14 ; All done with user state SRs (except for SR14)...
gotokern: lwz r14,savesr14(r31) ; Get the copyin/out register at interrupt time
loadsr14: mtsr sr14,r14 ; Set SR14
ngotokern: lwz r25,savesrr0(r31) /* Get the SRR0 to use */
la r28,saver6(r31) /* Point to the next line to use */
lwz r0,saver0(r31) /* Restore */
dcbt 0,r28 /* Touch it in */
lwz r1,saver1(r31) /* Restore */
lwz r2,saver2(r31) /* Restore */
la r28,saver14(r31) /* Point to the next line to get */
lwz r3,saver3(r31) /* Restore */
mtsrr0 r25 /* Restore the SRR0 now */
lwz r4,saver4(r31) /* Restore */
lwz r5,saver5(r31) /* Restore */
mtsrr1 r26 /* Restore the SRR1 now */
lwz r6,saver6(r31) /* Restore */
dcbt 0,r28 /* Touch that next line on in */
lwz r7,saver7(r31) /* Restore */
lwz r8,saver8(r31) /* Restore */
lwz r9,saver9(r31) /* Restore */
lwz r10,saver10(r31) /* Restore */
lwz r11,saver11(r31) /* Restore */
lwz r12,saver12(r31) /* Restore */
lwz r13,saver13(r31) /* Restore */
la r28,saver22(r31) /* Point to the next line to do */
lwz r14,saver14(r31) /* Restore */
lwz r15,saver15(r31) /* Restore */
dcbt 0,r28 /* Touch in another line of context */
lwz r16,saver16(r31) /* Restore */
lwz r17,saver17(r31) /* Restore */
lwz r18,saver18(r31) /* Restore */
lwz r19,saver19(r31) /* Restore */
lwz r20,saver20(r31) /* Restore */
lwz r21,saver21(r31) /* Restore */
la r28,saver30(r31) /* Point to the final line */
lwz r22,saver22(r31) /* Restore */
dcbt 0,r28 /* Suck it in */
lwz r23,saver23(r31) /* Restore */
mfpvr r27 ; Get the processor version
lwz r24,saver24(r31) /* Restore */
rlwinm r27,r27,16,16,31 ; Get the processor type
lwz r25,saver25(r31) /* Restore */
cmplwi cr1,r27,PROCESSOR_VERSION_Max ; Do we have Altivec? */
lwz r26,saver26(r31) /* Restore */
lwz r27,saver27(r31) /* Restore */
dcbt 0,r28 /* Get the final line */
lwz r28,savecr(r31) /* Get CR to restore */
blt cr1,noavec4 ; No vector on this machine
lwz r29,savevrsave(r31) ; Get the vrsave
beq+ cr3,noavec3 ; SRs have not changed, no need to stop the streams...
dssall ; Kill all data streams
; The streams should be suspended
; already, and we do a bunch of
; dependent loads and a sync later
; so we should be cool.
noavec3: mtspr vrsave,r29 ; Set the vrsave
noavec4: lwz r29,savexer(r31) /* Get XER to restore */
mtcr r28 /* Restore the CR */
lwz r28,savelr(r31) /* Get LR to restore */
mtxer r29 /* Restore the XER */
lwz r29,savectr(r31) /* Get the CTR to restore */
mtlr r28 /* Restore the LR */
lwz r28,saver30(r31) /* Restore */
mtctr r29 /* Restore the CTR */
lwz r29,saver31(r31) /* Restore */
mtsprg 2,r28 /* Save R30 */
lwz r28,saver28(r31) /* Restore */
mtsprg 3,r29 /* Save R31 */
lwz r29,saver29(r31) /* Restore */
#if PERFTIMES && DEBUG
stmw r1,0x280(br0) ; Save all registers
mfcr r20 ; Save the CR
mflr r21 ; Save the LR
mfsrr0 r9 ; Save SRR0
mfsrr1 r11 ; Save SRR1
mr r8,r0 ; Save R0
li r3,69 ; Indicate interrupt
mr r4,r11 ; Set MSR to log
mr r5,r31 ; Get savearea to log
bl EXT(dbgLog2) ; Cut log entry
mr r0,r8 ; Restore R0
mtsrr0 r9 ; Restore SRR0
mtsrr1 r11 ; Restore SRR1
mtlr r21 ; Restore the LR
mtcr r20 ; Restore the CR
lmw r1,0x280(br0) ; Restore all the rest
#endif
li r31,0 /* Get set to clear lock */
sync /* Make sure it's all out there */
stw r31,SVlock(r30) /* Unlock it */
mfsprg r30,2 /* Restore R30 */
mfsprg r31,3 /* Restore R31 */
rfi /* Click heels three times and think very hard that there's no place like home */
.long 0 /* For old 601 bug */
.long 0
.long 0
.long 0
.long 0
.long 0
.long 0
.long 0
/*
* exception_exit(savearea *)
*
*
* ENTRY : IR and/or DR and/or interruptions can be on
* R3 points to the physical address of a savearea
*/
.align 5
.globl EXT(exception_exit)
nop ; Align ISYNC to last line in cache
nop
LEXT(exception_exit)
mfmsr r30 /* Get the current MSR */
mr r31,r3 /* Get the savearea in the right register */
andi. r30,r30,0x7FCF /* Turn off externals, IR, and DR */
lis r1,hi16(SAVredrive) ; Get redrive request
mtmsr r30 /* Translation and all off */
isync /* Toss prefetch */
mfsprg r2,0 ; Get the per_proc block
lwz r4,SAVflags(r3) ; Pick up the flags
mr r13,r3 ; Put savearea here also
and. r0,r4,r1 ; Check if redrive requested
andc r4,r4,r1 ; Clear redrive
dcbt br0,r2 ; We will need this in just a sec
beq+ EatRupt ; No redrive, just exit...
lwz r3,saveexception(r13) ; Restore exception code
stw r4,SAVflags(r13) ; Set the flags
b Redrive ; Redrive the exception...
;
; Make trace entry for lowmem_vectors internal debug
;
#if TRCSAVE
cte:
lwz r20,LOW_ADDR(EXT(traceCurr)-EXT(ExceptionVectorsStart))(br0) ; Pick up the current trace entry
lwz r16,LOW_ADDR(EXT(traceEnd)-EXT(ExceptionVectorsStart))(br0) ; Grab up the end of it all
addi r17,r20,LTR_size ; Point to the next trace entry
cmplw r17,r16 ; Do we need to wrap the trace table?
li r15,32 ; Second line of entry
bne+ ctenwrap ; We got a trace entry...
lwz r17,LOW_ADDR(EXT(traceStart)-EXT(ExceptionVectorsStart))(br0) ; Wrap back to the top
ctenwrap: stw r17,LOW_ADDR(EXT(traceCurr)-EXT(ExceptionVectorsStart))(br0) ; Set the next entry for the next guy
dcbz 0,r20 ; Allocate cache for the entry
dcbz r15,r20 ; Zap the second half
ctegetTB: mftbu r16 ; Get the upper timebase
mftb r17 ; Get the lower timebase
mftbu r15 ; Get the upper one again
cmplw r16,r15 ; Did the top tick?
bne- ctegetTB ; Yeah, need to get it again...
li r15,0x111 ; Get the special trace ID code
stw r0,LTR_r0(r20) ; Save R0 (usually used as an ID number
stw r16,LTR_timeHi(r20) ; Set the upper part of TB
mflr r16 ; Get the return point
stw r17,LTR_timeLo(r20) ; Set the lower part of TB
sth r15,LTR_excpt(r20) ; Save the exception type
stw r16,LTR_srr0(r20) ; Save the return point
blr ; Leave...
#endif
/*
* Start of the trace table
*/
.align 12 /* Align to 4k boundary */
traceTableBeg: /* Start of trace table */
/* .fill 2048,4,0 Make an 8k trace table for now */
.fill 13760,4,0 /* Make an .trace table for now */
/* .fill 240000,4,0 Make an .trace table for now */
traceTableEnd: /* End of trace table */
.globl EXT(ExceptionVectorsEnd)
EXT(ExceptionVectorsEnd): /* Used if relocating the exception vectors */
#ifndef HACKALERTHACKALERT
/*
* This .long needs to be here because the linker gets confused and tries to
* include the final label in a section in the next section if there is nothing
* after it
*/
.long 0 /* (HACK/HACK/HACK) */
#endif
.data
.align ALIGN
.globl EXT(exception_end)
EXT(exception_end):
.long EXT(ExceptionVectorsEnd) -EXT(ExceptionVectorsStart) /* phys fn */