diff options
Diffstat (limited to 'sys/powerpc/aim/locore.S')
-rw-r--r-- | sys/powerpc/aim/locore.S | 1373 |
1 files changed, 1373 insertions, 0 deletions
diff --git a/sys/powerpc/aim/locore.S b/sys/powerpc/aim/locore.S new file mode 100644 index 0000000..2ede211 --- /dev/null +++ b/sys/powerpc/aim/locore.S @@ -0,0 +1,1373 @@ +/* $FreeBSD$ */ +/* $NetBSD: locore.S,v 1.24 2000/05/31 05:09:17 thorpej Exp $ */ + +/* + * Copyright (C) 2001 Benno Rice + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY Benno Rice ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL TOOLS GMBH BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; + * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +/* + * Copyright (C) 1995, 1996 Wolfgang Solfrank. + * Copyright (C) 1995, 1996 TooLs GmbH. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by TooLs GmbH. + * 4. The name of TooLs GmbH may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY TOOLS GMBH ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL TOOLS GMBH BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; + * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "opt_ddb.h" +#include "opt_ipkdb.h" +#include "assym.s" + +#include <sys/syscall.h> + +#include <machine/trap.h> +#include <machine/param.h> +#include <machine/pmap.h> +#include <machine/psl.h> +#include <machine/asm.h> + +/* + * Some instructions gas doesn't understand (yet?) + */ +#define bdneq bdnzf 2, + +/* + * Globals + */ + .data +GLOBAL(tmpstk) + .space 8208 +GLOBAL(esym) + .long 0 /* end of symbol table */ +GLOBAL(proc0paddr) + .long 0 /* proc0 p_addr */ +GLOBAL(PTmap) + .long 0 /* PTmap */ + +GLOBAL(intrnames) + .asciz "irq0", "irq1", "irq2", "irq3" + .asciz "irq4", "irq5", "irq6", "irq7" + .asciz "irq8", "irq9", "irq10", "irq11" + .asciz "irq12", "irq13", "irq14", "irq15" + .asciz "irq16", "irq17", "irq18", "irq19" + .asciz "irq20", "irq21", "irq22", "irq23" + .asciz "irq24", "irq25", "irq26", "irq27" + .asciz "irq28", "irq29", "irq30", "irq31" + .asciz "irq32", "irq33", "irq34", "irq35" + .asciz "irq36", "irq37", "irq38", "irq39" + .asciz "irq40", "irq41", "irq42", "irq43" + .asciz "irq44", "irq45", "irq46", "irq47" + .asciz "irq48", "irq49", "irq50", "irq51" + .asciz "irq52", "irq53", "irq54", "irq55" + .asciz "irq56", "irq57", "irq58", "irq59" + .asciz "irq60", "irq61", "irq62", "irq63" + .asciz "clock", "softclock", "softnet", "softserial" +GLOBAL(eintrnames) + .align 4 +GLOBAL(intrcnt) + .long 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 + .long 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 + .long 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 + .long 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 + .long 0,0,0,0 +GLOBAL(eintrcnt) + +GLOBAL(ofmsr) + .long 0 /* msr used in Open Firmware */ + +GLOBAL(powersave) + .long 0 + +/* + * File-scope for locore.S + */ +idle_u: + .long 0 /* fake uarea during idle after exit */ +openfirmware_entry: + .long 0 /* openfirmware entry point */ +srsave: + .long 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 + +/* + * This symbol is here for the benefit of kvm_mkdb, and is supposed to + * mark the start of kernel text. + */ + .text + .globl kernel_text +kernel_text: + +/* + * Startup entry. Note, this must be the first thing in the text + * segment! + */ + .text + .globl start +start: +#ifdef FIRMWORKSBUGS + mfmsr 0 + andi. 0,0,PSL_IR|PSL_DR + beq 1f + + bl ofwr_init +1: +#endif + li 8,0 + li 9,0x100 + mtctr 9 +1: + dcbf 0,8 + icbi 0,8 + addi 8,8,0x20 + bdnz 1b + sync + isync + + mtibatu 0,0 + mtibatu 1,0 + mtibatu 2,0 + mtibatu 3,0 + mtdbatu 0,0 + mtdbatu 1,0 + mtdbatu 2,0 + mtdbatu 3,0 + + li 9,0x12 + mtibatl 0,9 + mtdbatl 0,9 + li 9,0x1ffe + mtibatu 0,9 + mtdbatu 0,9 + isync + + lis 8,openfirmware_entry@ha + stw 5,openfirmware_entry@l(8) /* save client interface handler */ + mr 3,5 + + lis 1,tmpstk@ha + addi 1,1,tmpstk@l + addi 1,1,8192 + + mfmsr 0 + lis 9,ofmsr@ha + stw 0,ofmsr@l(9) + + bl OF_init + + lis 4,end@ha + addi 4,4,end@l + mr 5,4 + li 9,PAGE_MASK + add 4,4,9 + andc 4,4,9 + lis 9,OF_buf@ha + stw 4,OF_buf@l(9) + addi 4,4,PAGE_SIZE + lis 9,proc0paddr@ha + stw 4,proc0paddr@l(9) + addi 4,4,USPACE-FRAMELEN + mr 1,4 + xor 0,0,0 + stwu 0,-16(1) + + lis 3,kernel_text@ha + addi 3,3,kernel_text@l +#if 0 + mr 5,6 +#endif + + bl powerpc_init + bl mi_startup + b OF_exit + +#if 0 /* XXX: We may switch back to this in the future. */ +/* + * OpenFirmware entry point + */ +ENTRY(openfirmware) + mflr 0 /* save return address */ + stw 0,4(1) + stwu 1,-16(1) /* setup stack frame */ + + mfmsr 4 /* save msr */ + stw 4,8(1) + + lis 4,openfirmware_entry@ha /* get firmware entry point */ + lwz 4,openfirmware_entry@l(4) + mtlr 4 + + li 0,0 /* clear battable translations */ + mtdbatu 2,0 + mtdbatu 3,0 + mtibatu 2,0 + mtibatu 3,0 + + lis 4,ofmsr@ha /* Open Firmware msr */ + lwz 4,ofmsr@l(4) + mtmsr 4 + isync + + lis 4,srsave@ha /* save old SR */ + addi 4,4,srsave@l + li 5,0 +1: mfsrin 0,5 + stw 0,0(4) + addi 4,4,4 + addis 5,5,0x10000000@h + cmpwi 5,0 + bne 1b + + lis 4,ofw_pmap@ha /* load OFW SR */ + addi 4,4,ofw_pmap@l + lwz 0,PM_KERNELSR(4) + cmpwi 0,0 /* pm_sr[KERNEL_SR] == 0? */ + beq 2f /* then skip (not initialized yet) */ + li 5,0 +1: lwz 0,0(4) + mtsrin 0,5 + addi 4,4,4 + addis 5,5,0x10000000@h + cmpwi 5,0 + bne 1b +2: + blrl /* call Open Firmware */ + + mfmsr 4 + li 5,PSL_IR|PSL_DR + andc 4,4,5 + mtmsr 4 + isync + + lis 4,srsave@ha /* restore saved SR */ + addi 4,4,srsave@l + li 5,0 +1: lwz 0,0(4) + mtsrin 0,5 + addi 4,4,4 + addis 5,5,0x10000000@h + cmpwi 5,0 + bne 1b + + lwz 4,8(1) /* restore msr */ + mtmsr 4 + isync + + lwz 1,0(1) /* and return */ + lwz 0,4(1) + mtlr 0 + blr +#endif + +/* + * Switch to/from OpenFirmware real mode stack + * + * Note: has to be called as the very first thing in OpenFirmware interface + * routines. + * E.g.: + * int + * OF_xxx(arg1, arg2) + * type arg1, arg2; + * { + * static struct { + * char *name; + * int nargs; + * int nreturns; + * char *method; + * int arg1; + * int arg2; + * int ret; + * } args = { + * "xxx", + * 2, + * 1, + * }; + * + * ofw_stack(); + * args.arg1 = arg1; + * args.arg2 = arg2; + * if (openfirmware(&args) < 0) + * return -1; + * return args.ret; + * } + */ + + .local firmstk + .comm firmstk,PAGE_SIZE,8 + +ENTRY(ofw_stack) + mfmsr 8 /* turn off interrupts */ + andi. 0,8,~(PSL_EE|PSL_RI)@l + mtmsr 0 + stw 8,4(1) /* abuse return address slot */ + + lwz 5,0(1) /* get length of stack frame */ + subf 5,1,5 + + lis 7,firmstk+PAGE_SIZE-8@ha + addi 7,7,firmstk+PAGE_SIZE-8@l + lis 6,ofw_back@ha + addi 6,6,ofw_back@l + subf 4,5,7 /* make room for stack frame on + new stack */ + stw 6,-4(7) /* setup return pointer */ + stwu 1,-8(7) + + stw 7,-8(4) + + addi 3,1,8 + addi 1,4,-8 + subi 5,5,8 + + cmpw 3,4 + beqlr + + mr 0,5 + addi 5,5,-1 + cmpwi 0,0 + beqlr + +1: lwz 0,0(3) + stw 0,0(4) + addi 3,3,1 + addi 4,4,1 + mr 0,5 + addi 5,5,-1 + cmpwi 0,0 + bne 1b + blr + +ofw_back: + lwz 1,0(1) /* get callers original stack pointer */ + + lwz 0,4(1) /* get saved msr from abused slot */ + mtmsr 0 + + lwz 1,0(1) /* return */ + lwz 0,4(1) + mtlr 0 + blr + +/* + * Data used during primary/secondary traps/interrupts + */ +#define tempsave 0x2e0 /* primary save area for trap handling */ +#define disisave 0x3e0 /* primary save area for dsi/isi traps */ + +#define INTSTK (8*1024) /* 8K interrupt stack */ + .data + .align 4 +intstk: + .space INTSTK /* interrupt stack */ + +GLOBAL(intr_depth) + .long -1 /* in-use marker */ + +#define SPILLSTK 1024 /* 1K spill stack */ + + .comm spillstk,SPILLSTK,8 + +/* + * This code gets copied to all the trap vectors + * (except ISI/DSI, ALI, the interrupts, and possibly the debugging + * traps when using IPKDB). + */ + .text + .globl trapcode,trapsize +trapcode: + mtsprg 1,1 /* save SP */ + stmw 28,tempsave(0) /* free r28-r31 */ + mflr 28 /* save LR */ + mfcr 29 /* save CR */ +/* Test whether we already had PR set */ + mfsrr1 31 + mtcr 31 + bc 4,17,1f /* branch if PSL_PR is clear */ + mfsprg 1,0 + lwz 1,GD_CURPCB(1) + addi 1,1,USPACE /* stack is top of user struct */ +1: + bla s_trap +trapsize = .-trapcode + +/* + * For ALI: has to save DSISR and DAR + */ + .globl alitrap,alisize +alitrap: + mtsprg 1,1 /* save SP */ + stmw 28,tempsave(0) /* free r28-r31 */ + mfdar 30 + mfdsisr 31 + stmw 30,tempsave+16(0) + mflr 28 /* save LR */ + mfcr 29 /* save CR */ +/* Test whether we already had PR set */ + mfsrr1 31 + mtcr 31 + bc 4,17,1f /* branch if PSL_PR is clear */ + mfsprg 1,0 + lwz 1,GD_CURPCB(1) + addi 1,1,USPACE /* stack is top of user struct */ +1: + bla s_trap +alisize = .-alitrap + +/* + * Similar to the above for DSI + * Has to handle BAT spills + * and standard pagetable spills + */ + .globl dsitrap,dsisize +dsitrap: + stmw 28,disisave(0) /* free r28-r31 */ + mfcr 29 /* save CR */ + mfxer 30 /* save XER */ + mtsprg 2,30 /* in SPRG2 */ + mfsrr1 31 /* test kernel mode */ + mtcr 31 + bc 12,17,1f /* branch if PSL_PR is set */ + mfdar 31 /* get fault address */ + rlwinm 31,31,7,25,28 /* get segment * 8 */ + + /* get batu */ + addis 31,31,battable@ha + lwz 30,battable@l(31) + mtcr 30 + bc 4,30,1f /* branch if supervisor valid is + false */ + /* get batl */ + lwz 31,battable+4@l(31) +/* We randomly use the highest two bat registers here */ + mftb 28 + andi. 28,28,1 + bne 2f + mtdbatu 2,30 + mtdbatl 2,31 + b 3f +2: + mtdbatu 3,30 + mtdbatl 3,31 +3: + mfsprg 30,2 /* restore XER */ + mtxer 30 + mtcr 29 /* restore CR */ + lmw 28,disisave(0) /* restore r28-r31 */ + rfi /* return to trapped code */ +1: + mflr 28 /* save LR */ + bla s_dsitrap +dsisize = .-dsitrap + +/* + * Similar to the above for ISI + */ + .globl isitrap,isisize +isitrap: + stmw 28,disisave(0) /* free r28-r31 */ + mflr 28 /* save LR */ + mfcr 29 /* save CR */ + mfsrr1 31 /* test kernel mode */ + mtcr 31 + bc 12,17,1f /* branch if PSL_PR is set */ + mfsrr0 31 /* get fault address */ + rlwinm 31,31,7,25,28 /* get segment * 8 */ + + /* get batu */ + addis 31,31,battable@ha + lwz 30,battable@l(31) + mtcr 30 + bc 4,30,1f /* branch if supervisor valid is + false */ + mtibatu 3,30 + + /* get batl */ + lwz 30,battable+4@l(31) + mtibatl 3,30 + + mtcr 29 /* restore CR */ + lmw 28,disisave(0) /* restore r28-r31 */ + rfi /* return to trapped code */ +1: + bla s_isitrap +isisize = .-isitrap + +/* + * This one for the external interrupt handler. + */ + .globl extint,extsize +extint: + mtsprg 1,1 /* save SP */ + stmw 28,tempsave(0) /* free r28-r31 */ + mflr 28 /* save LR */ + mfcr 29 /* save CR */ + mfxer 30 /* save XER */ + lis 1,intstk+INTSTK@ha /* get interrupt stack */ + addi 1,1,intstk+INTSTK@l + lwz 31,0(1) /* were we already running on intstk? */ + addic. 31,31,1 + stw 31,0(1) + beq 1f + mfsprg 1,1 /* yes, get old SP */ +1: + ba extintr +extsize = .-extint + +/* + * And this one for the decrementer interrupt handler. + */ + .globl decrint,decrsize +decrint: + mtsprg 1,1 /* save SP */ + stmw 28,tempsave(0) /* free r28-r31 */ + mflr 28 /* save LR */ + mfcr 29 /* save CR */ + mfxer 30 /* save XER */ + lis 1,intstk+INTSTK@ha /* get interrupt stack */ + addi 1,1,intstk+INTSTK@l + lwz 31,0(1) /* were we already running on intstk? */ + addic. 31,31,1 + stw 31,0(1) + beq 1f + mfsprg 1,1 /* yes, get old SP */ +1: + ba decrintr +decrsize = .-decrint + +/* + * Now the tlb software load for 603 processors: + * (Code essentially from the 603e User Manual, Chapter 5, but + * corrected a lot.) + */ +#define DMISS 976 +#define DCMP 977 +#define HASH1 978 +#define HASH2 979 +#define IMISS 980 +#define ICMP 981 +#define RPA 982 + + .globl tlbimiss,tlbimsize +tlbimiss: + mfspr 2,HASH1 /* get first pointer */ + li 1,8 + mfctr 0 /* save counter */ + mfspr 3,ICMP /* get first compare value */ + addi 2,2,-8 /* predec pointer */ +1: + mtctr 1 /* load counter */ +2: + lwzu 1,8(2) /* get next pte */ + cmpl 0,1,3 /* see if found pte */ + bdneq 2b /* loop if not eq */ + bne 3f /* not found */ + lwz 1,4(2) /* load tlb entry lower word */ + andi. 3,1,8 /* check G-bit */ + bne 4f /* if guarded, take ISI */ + mtctr 0 /* restore counter */ + mfspr 0,IMISS /* get the miss address for the tlbli */ + mfsrr1 3 /* get the saved cr0 bits */ + mtcrf 0x80,3 /* and restore */ + ori 1,1,0x100 /* set the reference bit */ + mtspr RPA,1 /* set the pte */ + srwi 1,1,8 /* get byte 7 of pte */ + tlbli 0 /* load the itlb */ + stb 1,6(2) /* update page table */ + rfi + +3: /* not found in pteg */ + andi. 1,3,0x40 /* have we already done second hash? */ + bne 5f + mfspr 2,HASH2 /* get the second pointer */ + ori 3,3,0x40 /* change the compare value */ + li 1,8 + addi 2,2,-8 /* predec pointer */ + b 1b +4: /* guarded */ + mfsrr1 3 + andi. 2,3,0xffff /* clean upper srr1 */ + oris 2,2,0x8000000@h /* set srr<4> to flag prot violation */ + b 6f +5: /* not found anywhere */ + mfsrr1 3 + andi. 2,3,0xffff /* clean upper srr1 */ + oris 2,2,0x40000000@h /* set srr1<1> to flag pte not found */ +6: + mtctr 0 /* restore counter */ + mtsrr1 2 + mfmsr 0 + xoris 0,0,0x20000@h /* flip the msr<tgpr> bit */ + mtcrf 0x80,3 /* restore cr0 */ + mtmsr 0 /* now with native gprs */ + isync + ba EXC_ISI +tlbimsize = .-tlbimiss + + .globl tlbdlmiss,tlbdlmsize +tlbdlmiss: + mfspr 2,HASH1 /* get first pointer */ + li 1,8 + mfctr 0 /* save counter */ + mfspr 3,DCMP /* get first compare value */ + addi 2,2,-8 /* predec pointer */ +1: + mtctr 1 /* load counter */ +2: + lwzu 1,8(2) /* get next pte */ + cmpl 0,1,3 /* see if found pte */ + bdneq 2b /* loop if not eq */ + bne 3f /* not found */ + lwz 1,4(2) /* load tlb entry lower word */ + mtctr 0 /* restore counter */ + mfspr 0,DMISS /* get the miss address for the tlbld */ + mfsrr1 3 /* get the saved cr0 bits */ + mtcrf 0x80,3 /* and restore */ + ori 1,1,0x100 /* set the reference bit */ + mtspr RPA,1 /* set the pte */ + srwi 1,1,8 /* get byte 7 of pte */ + tlbld 0 /* load the dtlb */ + stb 1,6(2) /* update page table */ + rfi + +3: /* not found in pteg */ + andi. 1,3,0x40 /* have we already done second hash? */ + bne 5f + mfspr 2,HASH2 /* get the second pointer */ + ori 3,3,0x40 /* change the compare value */ + li 1,8 + addi 2,2,-8 /* predec pointer */ + b 1b +5: /* not found anywhere */ + mfsrr1 3 + lis 1,0x40000000@h /* set dsisr<1> to flag pte not found */ + mtctr 0 /* restore counter */ + andi. 2,3,0xffff /* clean upper srr1 */ + mtsrr1 2 + mtdsisr 1 /* load the dsisr */ + mfspr 1,DMISS /* get the miss address */ + mtdar 1 /* put in dar */ + mfmsr 0 + xoris 0,0,0x20000@h /* flip the msr<tgpr> bit */ + mtcrf 0x80,3 /* restore cr0 */ + mtmsr 0 /* now with native gprs */ + isync + ba EXC_DSI +tlbdlmsize = .-tlbdlmiss + + .globl tlbdsmiss,tlbdsmsize +tlbdsmiss: + mfspr 2,HASH1 /* get first pointer */ + li 1,8 + mfctr 0 /* save counter */ + mfspr 3,DCMP /* get first compare value */ + addi 2,2,-8 /* predec pointer */ +1: + mtctr 1 /* load counter */ +2: + lwzu 1,8(2) /* get next pte */ + cmpl 0,1,3 /* see if found pte */ + bdneq 2b /* loop if not eq */ + bne 3f /* not found */ + lwz 1,4(2) /* load tlb entry lower word */ + andi. 3,1,0x80 /* check the C-bit */ + beq 4f +5: + mtctr 0 /* restore counter */ + mfspr 0,DMISS /* get the miss address for the tlbld */ + mfsrr1 3 /* get the saved cr0 bits */ + mtcrf 0x80,3 /* and restore */ + mtspr RPA,1 /* set the pte */ + tlbld 0 /* load the dtlb */ + rfi + +3: /* not found in pteg */ + andi. 1,3,0x40 /* have we already done second hash? */ + bne 5f + mfspr 2,HASH2 /* get the second pointer */ + ori 3,3,0x40 /* change the compare value */ + li 1,8 + addi 2,2,-8 /* predec pointer */ + b 1b +4: /* found, but C-bit = 0 */ + rlwinm. 3,1,30,0,1 /* test PP */ + bge- 7f + andi. 3,1,1 + beq+ 8f +9: /* found, but protection violation (PP==00)*/ + mfsrr1 3 + lis 1,0xa000000@h /* indicate protection violation + on store */ + b 1f +7: /* found, PP=1x */ + mfspr 3,DMISS /* get the miss address */ + mfsrin 1,3 /* get the segment register */ + mfsrr1 3 + rlwinm 3,3,18,31,31 /* get PR-bit */ + rlwnm. 2,2,3,1,1 /* get the key */ + bne- 9b /* protection violation */ +8: /* found, set reference/change bits */ + lwz 1,4(2) /* reload tlb entry */ + ori 1,1,0x180 + sth 1,6(2) + b 5b +5: /* not found anywhere */ + mfsrr1 3 + lis 1,0x42000000@h /* set dsisr<1> to flag pte not found */ + /* dsisr<6> to flag store */ +1: + mtctr 0 /* restore counter */ + andi. 2,3,0xffff /* clean upper srr1 */ + mtsrr1 2 + mtdsisr 1 /* load the dsisr */ + mfspr 1,DMISS /* get the miss address */ + mtdar 1 /* put in dar */ + mfmsr 0 + xoris 0,0,0x20000@h /* flip the msr<tgpr> bit */ + mtcrf 0x80,3 /* restore cr0 */ + mtmsr 0 /* now with native gprs */ + isync + ba EXC_DSI +tlbdsmsize = .-tlbdsmiss + +#ifdef DDB +#define ddbsave 0xde0 /* primary save area for DDB */ +/* + * In case of DDB we want a separate trap catcher for it + */ + .local ddbstk + .comm ddbstk,INTSTK,8 /* ddb stack */ + + .globl ddblow,ddbsize +ddblow: + mtsprg 1,1 /* save SP */ + stmw 28,ddbsave(0) /* free r28-r31 */ + mflr 28 /* save LR */ + mfcr 29 /* save CR */ + lis 1,ddbstk+INTSTK@ha /* get new SP */ + addi 1,1,ddbstk+INTSTK@l + bla ddbtrap +ddbsize = .-ddblow +#endif /* DDB */ + +#ifdef IPKDB +#define ipkdbsave 0xde0 /* primary save area for IPKDB */ +/* + * In case of IPKDB we want a separate trap catcher for it + */ + + .local ipkdbstk + .comm ipkdbstk,INTSTK,8 /* ipkdb stack */ + + .globl ipkdblow,ipkdbsize +ipkdblow: + mtsprg 1,1 /* save SP */ + stmw 28,ipkdbsave(0) /* free r28-r31 */ + mflr 28 /* save LR */ + mfcr 29 /* save CR */ + lis 1,ipkdbstk+INTSTK@ha /* get new SP */ + addi 1,1,ipkdbstk+INTSTK@l + bla ipkdbtrap +ipkdbsize = .-ipkdblow +#endif /* IPKDB */ + +/* + * FRAME_SETUP assumes: + * SPRG1 SP (1) + * savearea r28-r31,DAR,DSISR (DAR & DSISR only for DSI traps) + * 28 LR + * 29 CR + * 1 kernel stack + * LR trap type + * SRR0/1 as at start of trap + */ +#define FRAME_SETUP(savearea) \ +/* Have to enable translation to allow access of kernel stack: */ \ + mfsrr0 30; \ + mfsrr1 31; \ + stmw 30,savearea+24(0); \ + mfmsr 30; \ + ori 30,30,(PSL_DR|PSL_IR); \ + mtmsr 30; \ + isync; \ + mfsprg 31,1; \ + stwu 31,-FRAMELEN(1); \ + stw 0,FRAME_0+8(1); \ + stw 31,FRAME_1+8(1); \ + stw 28,FRAME_LR+8(1); \ + stw 29,FRAME_CR+8(1); \ + lmw 28,savearea(0); \ + stmw 2,FRAME_2+8(1); \ + lmw 28,savearea+16(0); \ + mfxer 3; \ + mfctr 4; \ + mflr 5; \ + andi. 5,5,0xff00; \ + stw 3,FRAME_XER+8(1); \ + stw 4,FRAME_CTR+8(1); \ + stw 5,FRAME_EXC+8(1); \ + stw 28,FRAME_DAR+8(1); \ + stw 29,FRAME_DSISR+8(1); \ + stw 30,FRAME_SRR0+8(1); \ + stw 31,FRAME_SRR1+8(1) + +#define FRAME_LEAVE(savearea) \ +/* Now restore regs: */ \ + lwz 2,FRAME_SRR0+8(1); \ + lwz 3,FRAME_SRR1+8(1); \ + lwz 4,FRAME_CTR+8(1); \ + lwz 5,FRAME_XER+8(1); \ + lwz 6,FRAME_LR+8(1); \ + lwz 7,FRAME_CR+8(1); \ + stw 2,savearea(0); \ + stw 3,savearea+4(0); \ + mtctr 4; \ + mtxer 5; \ + mtlr 6; \ + mtsprg 1,7; /* save cr */ \ + lmw 2,FRAME_2+8(1); \ + lwz 0,FRAME_0+8(1); \ + lwz 1,FRAME_1+8(1); \ + mtsprg 2,2; /* save r2 & r3 */ \ + mtsprg 3,3; \ +/* Disable translation, machine check and recoverability: */ \ + mfmsr 2; \ + andi. 2,2,~(PSL_DR|PSL_IR|PSL_ME|PSL_RI)@l; \ + mtmsr 2; \ + isync; \ +/* Decide whether we return to user mode: */ \ + lwz 3,savearea+4(0); \ + mtcr 3; \ + bc 4,17,1f; /* branch if PSL_PR is false */ \ +/* Restore user & kernel access SR: */ \ +/* lis 2,curpm@ha; get real address of pmap */ \ +/* lwz 2,curpm@l(2); */ \ +/* lwz 3,PM_USRSR(2); */ \ +/* mtsr USER_SR,3; */ \ +/* lwz 3,PM_KERNELSR(2); */ \ +/* mtsr KERNEL_SR,3; */ \ +1: mfsprg 2,1; /* restore cr */ \ + mtcr 2; \ + lwz 2,savearea(0); \ + lwz 3,savearea+4(0); \ + mtsrr0 2; \ + mtsrr1 3; \ + mfsprg 2,2; /* restore r2 & r3 */ \ + mfsprg 3,3 + +/* + * Preamble code for DSI/ISI traps + */ +disitrap: + lmw 30,disisave(0) + stmw 30,tempsave(0) + lmw 30,disisave+8(0) + stmw 30,tempsave+8(0) + mfdar 30 + mfdsisr 31 + stmw 30,tempsave+16(0) +realtrap: +/* Test whether we already had PR set */ + mfsrr1 1 + mtcr 1 + mfsprg 1,1 /* restore SP (might have been + overwritten) */ + bc 4,17,s_trap /* branch if PSL_PR is false */ + mfsprg 1,0 + lwz 1,GD_CURPCB(1) + addi 1,1,USPACE /* stack is top of user struct */ + +/* + * Now the common trap catching code. + */ +s_trap: +/* First have to enable KERNEL mapping */ + lis 31,KERNEL_SEGMENT@h + ori 31,31,KERNEL_SEGMENT@l + mtsr KERNEL_SR,31 + FRAME_SETUP(tempsave) +/* Now we can recover interrupts again: */ + mfmsr 7 + ori 7,7,(PSL_EE|PSL_ME|PSL_RI)@l + mtmsr 7 + isync +/* Call C trap code: */ +trapagain: + addi 3,1,8 + bl trap +trapexit: +/* Disable interrupts: */ + mfmsr 3 + andi. 3,3,~PSL_EE@l + mtmsr 3 +/* Test AST pending: */ + lwz 5,FRAME_SRR1+8(1) + mtcr 5 + bc 4,17,1f /* branch if PSL_PR is false */ + lis 3,astpending@ha + lwz 4,astpending@l(3) + andi. 4,4,1 + beq 1f +#if 0 /* XXX */ + li 6,EXC_AST +#endif + stw 6,FRAME_EXC+8(1) + b trapagain +1: +#if 0 + FRAME_LEAVE(tempsave) +#endif + rfi + +/* + * Child comes here at the end of a fork. + * Mostly similar to the above. + */ + .globl fork_trampoline +fork_trampoline: + xor 3,3,3 +#if 0 /* XXX */ + bl lcsplx +#endif + mtlr 31 + mr 3,30 + blrl /* jump indirect to r31 */ + b trapexit + +/* + * DSI second stage fault handler + */ +s_dsitrap: + mfdsisr 31 /* test whether this may be a + spill fault */ + mtcr 31 + mtsprg 1,1 /* save SP */ + bc 4,1,disitrap /* branch if table miss is false */ + lis 1,spillstk+SPILLSTK@ha + addi 1,1,spillstk+SPILLSTK@l /* get spill stack */ + stwu 1,-52(1) + stw 0,48(1) /* save non-volatile registers */ + stw 3,44(1) + stw 4,40(1) + stw 5,36(1) + stw 6,32(1) + stw 7,28(1) + stw 8,24(1) + stw 9,20(1) + stw 10,16(1) + stw 11,12(1) + stw 12,8(1) + mflr 30 /* save trap type */ + mfctr 31 /* & CTR */ + mfdar 3 +s_pte_spill: + bl pte_spill /* try a spill */ + or. 3,3,3 + mtctr 31 /* restore CTR */ + mtlr 30 /* and trap type */ + mfsprg 31,2 /* get saved XER */ + mtxer 31 /* restore XER */ + lwz 12,8(1) /* restore non-volatile registers */ + lwz 11,12(1) + lwz 10,16(1) + lwz 9,20(1) + lwz 8,24(1) + lwz 7,28(1) + lwz 6,32(1) + lwz 5,36(1) + lwz 4,40(1) + lwz 3,44(1) + lwz 0,48(1) + beq disitrap + mfsprg 1,1 /* restore SP */ + mtcr 29 /* restore CR */ + mtlr 28 /* restore LR */ + lmw 28,disisave(0) /* restore r28-r31 */ + rfi /* return to trapped code */ + +/* + * ISI second stage fault handler + */ +s_isitrap: + mfsrr1 31 /* test whether this may be a + spill fault */ + mtcr 31 + mtsprg 1,1 /* save SP */ + bc 4,1,disitrap /* branch if table miss is false */ + lis 1,spillstk+SPILLSTK@ha + addi 1,1,spillstk+SPILLSTK@l /* get spill stack */ + stwu 1,-52(1) + stw 0,48(1) /* save non-volatile registers */ + stw 3,44(1) + stw 4,40(1) + stw 5,36(1) + stw 6,32(1) + stw 7,28(1) + stw 8,24(1) + stw 9,20(1) + stw 10,16(1) + stw 11,12(1) + stw 12,8(1) + mfxer 30 /* save XER */ + mtsprg 2,30 + mflr 30 /* save trap type */ + mfctr 31 /* & ctr */ + mfsrr0 3 + b s_pte_spill /* above */ + +/* + * External interrupt second level handler + */ +#define INTRENTER \ +/* Save non-volatile registers: */ \ + stwu 1,-88(1); /* temporarily */ \ + stw 0,84(1); \ + mfsprg 0,1; /* get original SP */ \ + stw 0,0(1); /* and store it */ \ + stw 3,80(1); \ + stw 4,76(1); \ + stw 5,72(1); \ + stw 6,68(1); \ + stw 7,64(1); \ + stw 8,60(1); \ + stw 9,56(1); \ + stw 10,52(1); \ + stw 11,48(1); \ + stw 12,44(1); \ + stw 28,40(1); /* saved LR */ \ + stw 29,36(1); /* saved CR */ \ + stw 30,32(1); /* saved XER */ \ + lmw 28,tempsave(0); /* restore r28-r31 */ \ + mfctr 6; \ + lis 5,intr_depth@ha; \ + lwz 5,intr_depth@l(5); \ + mfsrr0 4; \ + mfsrr1 3; \ + stw 6,28(1); \ + stw 5,20(1); \ + stw 4,12(1); \ + stw 3,8(1); \ +/* interrupts are recoverable here, and enable translation */ \ + lis 3,(KERNEL_SEGMENT|SR_SUKEY|SR_PRKEY)@h; \ + ori 3,3,(KERNEL_SEGMENT|SR_SUKEY|SR_PRKEY)@l; \ + mtsr KERNEL_SR,3; \ + mfmsr 5; \ + ori 5,5,(PSL_IR|PSL_DR|PSL_RI); \ + mtmsr 5; \ + isync + + .globl extint_call +extintr: + INTRENTER +extint_call: + bl extint_call /* to be filled in later */ + +intr_exit: +/* Disable interrupts (should already be disabled) and MMU here: */ + mfmsr 3 + andi. 3,3,~(PSL_EE|PSL_ME|PSL_RI|PSL_DR|PSL_IR)@l + mtmsr 3 + isync +/* restore possibly overwritten registers: */ + lwz 12,44(1) + lwz 11,48(1) + lwz 10,52(1) + lwz 9,56(1) + lwz 8,60(1) + lwz 7,64(1) + lwz 6,8(1) + lwz 5,12(1) + lwz 4,28(1) + lwz 3,32(1) + mtsrr1 6 + mtsrr0 5 + mtctr 4 + mtxer 3 +/* Returning to user mode? */ + mtcr 6 /* saved SRR1 */ + bc 4,17,1f /* branch if PSL_PR is false */ + mfsprg 3,0 /* get globaldata */ + lwz 3,GD_CURPCB(3) /* get curpcb from globaldata */ + lwz 3,PCB_PMR(3) /* get pmap real address from curpcb */ + mtsr KERNEL_SR,3 + lis 3,astpending@ha /* Test AST pending */ + lwz 4,astpending@l(3) + andi. 4,4,1 + beq 1f +/* Setup for entry to realtrap: */ + lwz 3,0(1) /* get saved SP */ + mtsprg 1,3 +#if 0 /* XXX */ + li 6,EXC_AST +#endif + stmw 28,tempsave(0) /* establish tempsave again */ + mtlr 6 + lwz 28,40(1) /* saved LR */ + lwz 29,36(1) /* saved CR */ + lwz 6,68(1) + lwz 5,72(1) + lwz 4,76(1) + lwz 3,80(1) + lwz 0,84(1) + lis 30,intr_depth@ha /* adjust reentrancy count */ + lwz 31,intr_depth@l(30) + addi 31,31,-1 + stw 31,intr_depth@l(30) + b realtrap +1: +/* Here is the normal exit of extintr: */ + lwz 5,36(1) + lwz 6,40(1) + mtcr 5 + mtlr 6 + lwz 6,68(1) + lwz 5,72(1) + lis 3,intr_depth@ha /* adjust reentrancy count */ + lwz 4,intr_depth@l(3) + addi 4,4,-1 + stw 4,intr_depth@l(3) + lwz 4,76(1) + lwz 3,80(1) + lwz 0,84(1) + lwz 1,0(1) + rfi + +/* + * Decrementer interrupt second level handler + */ +decrintr: + INTRENTER + addi 3,1,8 /* intr frame */ + bl decr_intr + b intr_exit + +#ifdef DDB +/* + * Deliberate entry to ddbtrap + */ + .globl ddb_trap +ddb_trap: + mtsprg 1,1 + mfmsr 3 + mtsrr1 3 + andi. 3,3,~(PSL_EE|PSL_ME)@l + mtmsr 3 /* disable interrupts */ + isync + stmw 28,ddbsave(0) + mflr 28 + li 29,EXC_BPT + mtlr 29 + mfcr 29 + mtsrr0 28 + +/* + * Now the ddb trap catching code. + */ +ddbtrap: + FRAME_SETUP(ddbsave) +/* Call C trap code: */ + addi 3,1,8 + bl ddb_trap_glue + or. 3,3,3 + bne ddbleave +/* This wasn't for DDB, so switch to real trap: */ + lwz 3,FRAME_EXC+8(1) /* save exception */ + stw 3,ddbsave+8(0) + FRAME_LEAVE(ddbsave) + mtsprg 1,1 /* prepare for entrance to realtrap */ + stmw 28,tempsave(0) + mflr 28 + mfcr 29 + lwz 31,ddbsave+8(0) + mtlr 31 + b realtrap +ddbleave: + FRAME_LEAVE(ddbsave) + rfi +#endif /* DDB */ + +#ifdef IPKDB +/* + * Deliberate entry to ipkdbtrap + */ + .globl ipkdb_trap +ipkdb_trap: + mtsprg 1,1 + mfmsr 3 + mtsrr1 3 + andi. 3,3,~(PSL_EE|PSL_ME)@l + mtmsr 3 /* disable interrupts */ + isync + stmw 28,ipkdbsave(0) + mflr 28 + li 29,EXC_BPT + mtlr 29 + mfcr 29 + mtsrr0 28 + +/* + * Now the ipkdb trap catching code. + */ +ipkdbtrap: + FRAME_SETUP(ipkdbsave) +/* Call C trap code: */ + addi 3,1,8 + bl ipkdb_trap_glue + or. 3,3,3 + bne ipkdbleave +/* This wasn't for IPKDB, so switch to real trap: */ + lwz 3,FRAME_EXC+8(1) /* save exception */ + stw 3,ipkdbsave+8(0) + FRAME_LEAVE(ipkdbsave) + mtsprg 1,1 /* prepare for entrance to realtrap */ + stmw 28,tempsave(0) + mflr 28 + mfcr 29 + lwz 31,ipkdbsave+8(0) + mtlr 31 + b realtrap +ipkdbleave: + FRAME_LEAVE(ipkdbsave) + rfi + +ipkdbfault: + ba _ipkdbfault +_ipkdbfault: + mfsrr0 3 + addi 3,3,4 + mtsrr0 3 + li 3,-1 + rfi + +/* + * int ipkdbfbyte(unsigned char *p) + */ + .globl ipkdbfbyte +ipkdbfbyte: + li 9,EXC_DSI /* establish new fault routine */ + lwz 5,0(9) + lis 6,ipkdbfault@ha + lwz 6,ipkdbfault@l(6) + stw 6,0(9) +#ifdef IPKDBUSERHACK + lis 8,ipkdbsr@ha + lwz 8,ipkdbsr@l(8) + mtsr USER_SR,8 + isync +#endif + dcbst 0,9 /* flush data... */ + sync + icbi 0,9 /* and instruction caches */ + lbz 3,0(3) /* fetch data */ + stw 5,0(9) /* restore previous fault handler */ + dcbst 0,9 /* and flush data... */ + sync + icbi 0,9 /* and instruction caches */ + blr + +/* + * int ipkdbsbyte(unsigned char *p, int c) + */ + .globl ipkdbsbyte +ipkdbsbyte: + li 9,EXC_DSI /* establish new fault routine */ + lwz 5,0(9) + lis 6,ipkdbfault@ha + lwz 6,ipkdbfault@l(6) + stw 6,0(9) +#ifdef IPKDBUSERHACK + lis 8,ipkdbsr@ha + lwz 8,ipkdbsr@l(8) + mtsr USER_SR,8 + isync +#endif + dcbst 0,9 /* flush data... */ + sync + icbi 0,9 /* and instruction caches */ + mr 6,3 + xor 3,3,3 + stb 4,0(6) + dcbst 0,6 /* Now do appropriate flushes + to data... */ + sync + icbi 0,6 /* and instruction caches */ + stw 5,0(9) /* restore previous fault handler */ + dcbst 0,9 /* and flush data... */ + sync + icbi 0,9 /* and instruction caches */ + blr +#endif /* IPKDB */ + +/* + * int setfault() + * + * Similar to setjmp to setup for handling faults on accesses to user memory. + * Any routine using this may only call bcopy, either the form below, + * or the (currently used) C code optimized, so it doesn't use any non-volatile + * registers. + */ + .globl setfault +setfault: + mflr 0 + mfcr 12 + mfsprg 4,0 + lwz 4,GD_CURPCB(4) + stw 3,PCB_FAULT(4) + stw 0,0(3) + stw 1,4(3) + stw 2,8(3) + stmw 12,12(3) + xor 3,3,3 + blr + +/* + * Signal "trampoline" code. + */ + .globl sigcode +sigcode: + b sys_exit +esigcode: + .data +GLOBAL(szsigcode) + .long esigcode-sigcode + .text + |