/* $NetBSD: trap_subr.S,v 1.20 2002/04/22 23:20:08 kleink Exp $ */12/*-3* Copyright (C) 1995, 1996 Wolfgang Solfrank.4* Copyright (C) 1995, 1996 TooLs GmbH.5* All rights reserved.6*7* Redistribution and use in source and binary forms, with or without8* modification, are permitted provided that the following conditions9* are met:10* 1. Redistributions of source code must retain the above copyright11* notice, this list of conditions and the following disclaimer.12* 2. Redistributions in binary form must reproduce the above copyright13* notice, this list of conditions and the following disclaimer in the14* documentation and/or other materials provided with the distribution.15* 3. All advertising materials mentioning features or use of this software16* must display the following acknowledgement:17* This product includes software developed by TooLs GmbH.18* 4. The name of TooLs GmbH may not be used to endorse or promote products19* derived from this software without specific prior written permission.20*21* THIS SOFTWARE IS PROVIDED BY TOOLS GMBH ``AS IS'' AND ANY EXPRESS OR22* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES23* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.24* IN NO EVENT SHALL TOOLS GMBH BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,25* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,26* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;27* OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,28* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR29* OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF30* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.31*/3233/*34* NOTICE: This is not a standalone file. to use it, #include it in35* your port's locore.S, like so:36*37* #include <powerpc/aim/trap_subr.S>38*/3940/*41* Save/restore segment registers42*/43#define RESTORE_SRS(pmap,sr) mtsr 0,sr; \44lwz sr,1*4(pmap); mtsr 1,sr; \45lwz sr,2*4(pmap); mtsr 2,sr; \46lwz sr,3*4(pmap); mtsr 3,sr; \47lwz sr,4*4(pmap); mtsr 4,sr; \48lwz sr,5*4(pmap); mtsr 5,sr; \49lwz sr,6*4(pmap); mtsr 6,sr; \50lwz sr,7*4(pmap); mtsr 7,sr; \51lwz sr,8*4(pmap); mtsr 8,sr; \52lwz sr,9*4(pmap); mtsr 9,sr; \53lwz sr,10*4(pmap); mtsr 10,sr; \54lwz sr,11*4(pmap); mtsr 11,sr; \55/* Skip segment 12 (USER_SR), which is restored differently */ \56lwz sr,13*4(pmap); mtsr 13,sr; \57lwz sr,14*4(pmap); mtsr 14,sr; \58lwz sr,15*4(pmap); mtsr 15,sr; isync;5960/*61* User SRs are loaded through a pointer to the current pmap.62*/63#define RESTORE_USER_SRS(pmap,sr) \64GET_CPUINFO(pmap); \65lwz pmap,PC_CURPMAP(pmap); \66lwzu sr,PM_SR(pmap); \67RESTORE_SRS(pmap,sr) \68/* Restore SR 12 */ \69lwz sr,12*4(pmap); mtsr 12,sr; isync7071/*72* Kernel SRs are loaded directly from kernel_pmap_73*/74#define RESTORE_KERN_SRS(pmap,sr) \75lwz pmap,TRAP_TOCBASE(0); \76lwz pmap,CNAME(kernel_pmap_store)@got(pmap); \77lwzu sr,PM_SR(pmap); \78RESTORE_SRS(pmap,sr)7980/*81* FRAME_SETUP assumes:82* SPRG1 SP (1)83* SPRG3 trap type84* savearea r28-r31,DAR,DSISR (DAR & DSISR only for DSI traps)85* r28 LR86* r29 CR87* r30 scratch88* r31 scratch89* r1 kernel stack90* SRR0/1 as at start of trap91*/92#define FRAME_SETUP(savearea) \93/* Have to enable translation to allow access of kernel stack: */ \94GET_CPUINFO(%r31); \95mfsrr0 %r30; \96stw %r30,(savearea+CPUSAVE_SRR0)(%r31); /* save SRR0 */ \97mfsrr1 %r30; \98stw %r30,(savearea+CPUSAVE_SRR1)(%r31); /* save SRR1 */ \99mfmsr %r30; \100ori %r30,%r30,(PSL_DR|PSL_IR|PSL_RI)@l; /* relocation on */ \101mtmsr %r30; /* stack can now be accessed */ \102isync; \103mfsprg1 %r31; /* get saved SP */ \104stwu %r31,-FRAMELEN(%r1); /* save it in the callframe */ \105stw %r0, FRAME_0+8(%r1); /* save r0 in the trapframe */ \106stw %r31,FRAME_1+8(%r1); /* save SP " " */ \107stw %r2, FRAME_2+8(%r1); /* save r2 " " */ \108stw %r28,FRAME_LR+8(%r1); /* save LR " " */ \109stw %r29,FRAME_CR+8(%r1); /* save CR " " */ \110GET_CPUINFO(%r2); \111lwz %r28,(savearea+CPUSAVE_R28)(%r2); /* get saved r28 */ \112lwz %r29,(savearea+CPUSAVE_R29)(%r2); /* get saved r29 */ \113lwz %r30,(savearea+CPUSAVE_R30)(%r2); /* get saved r30 */ \114lwz %r31,(savearea+CPUSAVE_R31)(%r2); /* get saved r31 */ \115stw %r3, FRAME_3+8(%r1); /* save r3-r31 */ \116stw %r4, FRAME_4+8(%r1); \117stw %r5, FRAME_5+8(%r1); \118stw %r6, FRAME_6+8(%r1); \119stw %r7, FRAME_7+8(%r1); \120stw %r8, FRAME_8+8(%r1); \121stw %r9, FRAME_9+8(%r1); \122stw %r10, FRAME_10+8(%r1); \123stw %r11, FRAME_11+8(%r1); \124stw %r12, FRAME_12+8(%r1); \125stw %r13, FRAME_13+8(%r1); \126stw %r14, FRAME_14+8(%r1); \127stw %r15, FRAME_15+8(%r1); \128stw %r16, FRAME_16+8(%r1); \129stw %r17, FRAME_17+8(%r1); \130stw %r18, FRAME_18+8(%r1); \131stw %r19, FRAME_19+8(%r1); \132stw %r20, FRAME_20+8(%r1); \133stw %r21, FRAME_21+8(%r1); \134stw %r22, FRAME_22+8(%r1); \135stw %r23, FRAME_23+8(%r1); \136stw %r24, FRAME_24+8(%r1); \137stw %r25, FRAME_25+8(%r1); \138stw %r26, FRAME_26+8(%r1); \139stw %r27, FRAME_27+8(%r1); \140stw %r28, FRAME_28+8(%r1); \141stw %r29, FRAME_29+8(%r1); \142stw %r30, FRAME_30+8(%r1); \143stw %r31, FRAME_31+8(%r1); \144lwz %r28,(savearea+CPUSAVE_AIM_DAR)(%r2); /* saved DAR */ \145lwz %r29,(savearea+CPUSAVE_AIM_DSISR)(%r2);/* saved DSISR */\146lwz %r30,(savearea+CPUSAVE_SRR0)(%r2); /* saved SRR0 */ \147lwz %r31,(savearea+CPUSAVE_SRR1)(%r2); /* saved SRR1 */ \148mfxer %r3; \149mfctr %r4; \150mfsprg3 %r5; \151stw %r3, FRAME_XER+8(1); /* save xer/ctr/exc */ \152stw %r4, FRAME_CTR+8(1); \153stw %r5, FRAME_EXC+8(1); \154stw %r28,FRAME_AIM_DAR+8(1); \155stw %r29,FRAME_AIM_DSISR+8(1); /* save dsisr/srr0/srr1 */ \156stw %r30,FRAME_SRR0+8(1); \157stw %r31,FRAME_SRR1+8(1); \158lwz %r2,PC_CURTHREAD(%r2) /* set curthread pointer */159160#define FRAME_LEAVE(savearea) \161/* Disable exceptions: */ \162mfmsr %r2; \163andi. %r2,%r2,~PSL_EE@l; \164mtmsr %r2; \165isync; \166/* Now restore regs: */ \167lwz %r2,FRAME_SRR0+8(%r1); \168lwz %r3,FRAME_SRR1+8(%r1); \169lwz %r4,FRAME_CTR+8(%r1); \170lwz %r5,FRAME_XER+8(%r1); \171lwz %r6,FRAME_LR+8(%r1); \172GET_CPUINFO(%r7); \173stw %r2,(savearea+CPUSAVE_SRR0)(%r7); /* save SRR0 */ \174stw %r3,(savearea+CPUSAVE_SRR1)(%r7); /* save SRR1 */ \175lwz %r7,FRAME_CR+8(%r1); \176mtctr %r4; \177mtxer %r5; \178mtlr %r6; \179mtsprg1 %r7; /* save cr */ \180lwz %r31,FRAME_31+8(%r1); /* restore r0-31 */ \181lwz %r30,FRAME_30+8(%r1); \182lwz %r29,FRAME_29+8(%r1); \183lwz %r28,FRAME_28+8(%r1); \184lwz %r27,FRAME_27+8(%r1); \185lwz %r26,FRAME_26+8(%r1); \186lwz %r25,FRAME_25+8(%r1); \187lwz %r24,FRAME_24+8(%r1); \188lwz %r23,FRAME_23+8(%r1); \189lwz %r22,FRAME_22+8(%r1); \190lwz %r21,FRAME_21+8(%r1); \191lwz %r20,FRAME_20+8(%r1); \192lwz %r19,FRAME_19+8(%r1); \193lwz %r18,FRAME_18+8(%r1); \194lwz %r17,FRAME_17+8(%r1); \195lwz %r16,FRAME_16+8(%r1); \196lwz %r15,FRAME_15+8(%r1); \197lwz %r14,FRAME_14+8(%r1); \198lwz %r13,FRAME_13+8(%r1); \199lwz %r12,FRAME_12+8(%r1); \200lwz %r11,FRAME_11+8(%r1); \201lwz %r10,FRAME_10+8(%r1); \202lwz %r9, FRAME_9+8(%r1); \203lwz %r8, FRAME_8+8(%r1); \204lwz %r7, FRAME_7+8(%r1); \205lwz %r6, FRAME_6+8(%r1); \206lwz %r5, FRAME_5+8(%r1); \207lwz %r4, FRAME_4+8(%r1); \208lwz %r3, FRAME_3+8(%r1); \209lwz %r2, FRAME_2+8(%r1); \210lwz %r0, FRAME_0+8(%r1); \211lwz %r1, FRAME_1+8(%r1); \212/* Can't touch %r1 from here on */ \213mtsprg2 %r2; /* save r2 & r3 */ \214mtsprg3 %r3; \215/* Disable translation, machine check and recoverability: */ \216mfmsr %r2; \217andi. %r2,%r2,~(PSL_DR|PSL_IR|PSL_ME|PSL_RI)@l; \218mtmsr %r2; \219isync; \220/* Decide whether we return to user mode: */ \221GET_CPUINFO(%r2); \222lwz %r3,(savearea+CPUSAVE_SRR1)(%r2); \223mtcr %r3; \224bf 17,1f; /* branch if PSL_PR is false */ \225/* Restore user SRs */ \226RESTORE_USER_SRS(%r2,%r3); \2271: mfsprg1 %r2; /* restore cr */ \228mtcr %r2; \229GET_CPUINFO(%r2); \230lwz %r3,(savearea+CPUSAVE_SRR0)(%r2); /* restore srr0 */ \231mtsrr0 %r3; \232lwz %r3,(savearea+CPUSAVE_SRR1)(%r2); /* restore srr1 */ \233\234/* Make sure HV bit of MSR propagated to SRR1 */ \235mfmsr %r2; \236or %r3,%r2,%r3; \237\238mtsrr1 %r3; \239mfsprg2 %r2; /* restore r2 & r3 */ \240mfsprg3 %r3241242#ifdef KDTRACE_HOOKS243.data244.globl dtrace_invop_calltrap_addr245.align 4246.type dtrace_invop_calltrap_addr, @object247.size dtrace_invop_calltrap_addr, 4248dtrace_invop_calltrap_addr:249.word 0250.word 0251252.text253#endif254255/*256* The next two routines are 64-bit glue code. The first is used to test if257* we are on a 64-bit system. By copying it to the illegal instruction258* handler, we can test for 64-bit mode by trying to execute a 64-bit259* instruction and seeing what happens. The second gets copied in front260* of all the other handlers to restore 32-bit bridge mode when traps261* are taken.262*/263264/* 64-bit test code. Sets SPRG2 to 0 if an illegal instruction is executed */265266.globl CNAME(testppc64),CNAME(testppc64size)267CNAME(testppc64):268mtsprg1 %r31269mfsrr0 %r31270addi %r31, %r31, 4271mtsrr0 %r31272273li %r31, 0274mtsprg2 %r31275mfsprg1 %r31276277rfi278CNAME(testppc64size) = .-CNAME(testppc64)279280281/* 64-bit bridge mode restore snippet. Gets copied in front of everything else282* on 64-bit systems. */283284.globl CNAME(restorebridge),CNAME(restorebridgesize)285CNAME(restorebridge):286mtsprg1 %r31287mfmsr %r31288clrldi %r31,%r31,1289mtmsrd %r31290mfsprg1 %r31291isync292CNAME(restorebridgesize) = .-CNAME(restorebridge)293294/*295* Processor reset exception handler. These are typically296* the first instructions the processor executes after a297* software reset. We do this in two bits so that we are298* not still hanging around in the trap handling region299* once the MMU is turned on.300*/301.globl CNAME(rstcode), CNAME(rstcodeend)302CNAME(rstcode):303lwz %r31, TRAP_GENTRAP(0)304addi %r31, %r31, (cpu_reset - generictrap)305mtlr %r31306blrl307CNAME(rstcodeend):308309cpu_reset:310bl 1f311312.space 1243133141:315mflr %r1316addi %r1,%r1,(124-16)@l317lwz %r30,TRAP_TOCBASE(0)318319bl CNAME(cpudep_ap_early_bootstrap)320lis %r3,1@l321bl CNAME(pmap_cpu_bootstrap)322bl CNAME(cpudep_ap_bootstrap)323mr %r1,%r3324bl CNAME(cpudep_ap_setup)325GET_CPUINFO(%r5)326lwz %r3,(PC_RESTORE)(%r5)327cmplwi %cr0,%r3,0328beq %cr0,2f329li %r4, 1330b CNAME(longjmp)3312:332#ifdef SMP333bl CNAME(machdep_ap_bootstrap)334#endif335336/* Should not be reached */3379:338b 9b339340/*341* This code gets copied to all the trap vectors342* (except ISI/DSI, ALI, and the interrupts)343*/344345.globl CNAME(trapcode),CNAME(trapcodeend)346CNAME(trapcode):347mtsprg1 %r1 /* save SP */348mflr %r1 /* Save the old LR in r1 */349mtsprg2 %r1 /* And then in SPRG2 */350lwz %r1, TRAP_ENTRY(0) /* Get branch address */351mtlr %r1352li %r1, 0xe0 /* How to get the vector from LR */353blrl /* LR & (0xff00 | r1) is exception # */354CNAME(trapcodeend):355356/*357* For ALI: has to save DSISR and DAR358*/359.globl CNAME(alitrap),CNAME(aliend)360CNAME(alitrap):361mtsprg1 %r1 /* save SP */362GET_CPUINFO(%r1)363stw %r28,(PC_TEMPSAVE+CPUSAVE_R28)(%r1) /* free r28-r31 */364stw %r29,(PC_TEMPSAVE+CPUSAVE_R29)(%r1)365stw %r30,(PC_TEMPSAVE+CPUSAVE_R30)(%r1)366stw %r31,(PC_TEMPSAVE+CPUSAVE_R31)(%r1)367mfdar %r30368mfdsisr %r31369stw %r30,(PC_TEMPSAVE+CPUSAVE_AIM_DAR)(%r1)370stw %r31,(PC_TEMPSAVE+CPUSAVE_AIM_DSISR)(%r1)371mfsprg1 %r1 /* restore SP, in case of branch */372mflr %r28 /* save LR */373mfcr %r29 /* save CR */374375/* Put our exception vector in SPRG3 */376li %r31, EXC_ALI377mtsprg3 %r31378379/* Test whether we already had PR set */380mfsrr1 %r31381mtcr %r31382383/* Jump to s_trap */384lwz %r31, TRAP_GENTRAP(0)385addi %r31, %r31, (s_trap - generictrap)386mtlr %r31387blrl388CNAME(aliend):389390/*391* G2 specific: instuction TLB miss.392*/393.globl CNAME(imisstrap),CNAME(imisssize)394CNAME(imisstrap):395mfspr %r2, SPR_HASH1 /* get first pointer */396addi %r1, 0, 8 /* load 8 for counter */397mfctr %r0 /* save counter */398mfspr %r3, SPR_ICMP /* get first compare value */399addi %r2, %r2, -8 /* pre dec the pointer */400im0:401mtctr %r1 /* load counter */402im1:403lwzu %r1, 8(%r2) /* get next pte */404cmp 0, 0, %r1, %r3 /* see if found pte */405bdnzf 2, im1 /* dec count br if cmp ne and if406* count not zero */407bne instr_sec_hash /* if not found set up second hash408* or exit */409lwz %r1, +4(%r2) /* load tlb entry lower-word */410andi. %r3, %r1, 8 /* check G bit */411bne do_isi_prot /* if guarded, take an ISI */412mtctr %r0 /* restore counter */413mfspr %r0, SPR_IMISS /* get the miss address for the tlbli */414mfspr %r3, SPR_SRR1 /* get the saved cr0 bits */415mtcrf 0x80, %r3 /* restore CR0 */416mtspr SPR_RPA, %r1 /* set the pte */417ori %r1, %r1, 0x100 /* set reference bit */418srwi %r1, %r1, 8 /* get byte 7 of pte */419tlbli %r0 /* load the itlb */420stb %r1, +6(%r2) /* update page table */421rfi /* return to executing program */422423instr_sec_hash:424andi. %r1, %r3, 0x0040 /* see if we have done second hash */425bne do_isi /* if so, go to ISI interrupt */426mfspr %r2, SPR_HASH2 /* get the second pointer */427ori %r3, %r3, 0x0040 /* change the compare value */428addi %r1, 0, 8 /* load 8 for counter */429addi %r2, %r2, -8 /* pre dec for update on load */430b im0 /* try second hash */431432/* Create a faked ISI interrupt as the address was not found */433do_isi_prot:434mfspr %r3, SPR_SRR1 /* get srr1 */435andi. %r2, %r3, 0xffff /* clean upper srr1 */436addis %r2, %r2, 0x0800 /* or in srr<4> = 1 to flag prot437* violation */438b isi1439do_isi:440mfspr %r3, SPR_SRR1 /* get srr1 */441andi. %r2, %r3, 0xffff /* clean srr1 */442addis %r2, %r2, 0x4000 /* or in srr1<1> = 1 to flag pte443* not found */444isi1:445mtctr %r0 /* restore counter */446mtspr SPR_SRR1, %r2 /* set srr1 */447mfmsr %r0 /* get msr */448xoris %r0, %r0, 0x2 /* flip the msr<tgpr> bit */449mtcrf 0x80, %r3 /* restore CR0 */450mtmsr %r0 /* flip back to the native gprs */451ba EXC_ISI /* go to instr. access interrupt */452453CNAME(imisssize) = .-CNAME(imisstrap)454455/*456* G2 specific: data load TLB miss.457*/458.globl CNAME(dlmisstrap),CNAME(dlmisssize)459CNAME(dlmisstrap):460mfspr %r2, SPR_HASH1 /* get first pointer */461addi %r1, 0, 8 /* load 8 for counter */462mfctr %r0 /* save counter */463mfspr %r3, SPR_DCMP /* get first compare value */464addi %r2, %r2, -8 /* pre dec the pointer */465dm0:466mtctr %r1 /* load counter */467dm1:468lwzu %r1, 8(%r2) /* get next pte */469cmp 0, 0, %r1, %r3 /* see if found pte */470bdnzf 2, dm1 /* dec count br if cmp ne and if471* count not zero */472bne data_sec_hash /* if not found set up second hash473* or exit */474lwz %r1, +4(%r2) /* load tlb entry lower-word */475mtctr %r0 /* restore counter */476mfspr %r0, SPR_DMISS /* get the miss address for the tlbld */477mfspr %r3, SPR_SRR1 /* get the saved cr0 bits */478mtcrf 0x80, %r3 /* restore CR0 */479mtspr SPR_RPA, %r1 /* set the pte */480ori %r1, %r1, 0x100 /* set reference bit */481srwi %r1, %r1, 8 /* get byte 7 of pte */482tlbld %r0 /* load the dtlb */483stb %r1, +6(%r2) /* update page table */484rfi /* return to executing program */485486data_sec_hash:487andi. %r1, %r3, 0x0040 /* see if we have done second hash */488bne do_dsi /* if so, go to DSI interrupt */489mfspr %r2, SPR_HASH2 /* get the second pointer */490ori %r3, %r3, 0x0040 /* change the compare value */491addi %r1, 0, 8 /* load 8 for counter */492addi %r2, %r2, -8 /* pre dec for update on load */493b dm0 /* try second hash */494495CNAME(dlmisssize) = .-CNAME(dlmisstrap)496497/*498* G2 specific: data store TLB miss.499*/500.globl CNAME(dsmisstrap),CNAME(dsmisssize)501CNAME(dsmisstrap):502mfspr %r2, SPR_HASH1 /* get first pointer */503addi %r1, 0, 8 /* load 8 for counter */504mfctr %r0 /* save counter */505mfspr %r3, SPR_DCMP /* get first compare value */506addi %r2, %r2, -8 /* pre dec the pointer */507ds0:508mtctr %r1 /* load counter */509ds1:510lwzu %r1, 8(%r2) /* get next pte */511cmp 0, 0, %r1, %r3 /* see if found pte */512bdnzf 2, ds1 /* dec count br if cmp ne and if513* count not zero */514bne data_store_sec_hash /* if not found set up second hash515* or exit */516lwz %r1, +4(%r2) /* load tlb entry lower-word */517andi. %r3, %r1, 0x80 /* check the C-bit */518beq data_store_chk_prot /* if (C==0)519* go check protection modes */520ds2:521mtctr %r0 /* restore counter */522mfspr %r0, SPR_DMISS /* get the miss address for the tlbld */523mfspr %r3, SPR_SRR1 /* get the saved cr0 bits */524mtcrf 0x80, %r3 /* restore CR0 */525mtspr SPR_RPA, %r1 /* set the pte */526tlbld %r0 /* load the dtlb */527rfi /* return to executing program */528529data_store_sec_hash:530andi. %r1, %r3, 0x0040 /* see if we have done second hash */531bne do_dsi /* if so, go to DSI interrupt */532mfspr %r2, SPR_HASH2 /* get the second pointer */533ori %r3, %r3, 0x0040 /* change the compare value */534addi %r1, 0, 8 /* load 8 for counter */535addi %r2, %r2, -8 /* pre dec for update on load */536b ds0 /* try second hash */537538/* Check the protection before setting PTE(c-bit) */539data_store_chk_prot:540rlwinm. %r3,%r1,30,0,1 /* test PP */541bge- chk0 /* if (PP == 00 or PP == 01)542* goto chk0: */543andi. %r3, %r1, 1 /* test PP[0] */544beq+ chk2 /* return if PP[0] == 0 */545b do_dsi_prot /* else DSIp */546chk0:547mfspr %r3,SPR_SRR1 /* get old msr */548andis. %r3,%r3,0x0008 /* test the KEY bit (SRR1-bit 12) */549beq chk2 /* if (KEY==0) goto chk2: */550b do_dsi_prot /* else do_dsi_prot */551chk2:552ori %r1, %r1, 0x180 /* set reference and change bit */553sth %r1, 6(%r2) /* update page table */554b ds2 /* and back we go */555556/* Create a faked DSI interrupt as the address was not found */557do_dsi:558mfspr %r3, SPR_SRR1 /* get srr1 */559rlwinm %r1,%r3,9,6,6 /* get srr1<flag> to bit 6 for560* load/store, zero rest */561addis %r1, %r1, 0x4000 /* or in dsisr<1> = 1 to flag pte562* not found */563b dsi1564565do_dsi_prot:566mfspr %r3, SPR_SRR1 /* get srr1 */567rlwinm %r1,%r3,9,6,6 /* get srr1<flag> to bit 6 for568*load/store, zero rest */569addis %r1, %r1, 0x0800 /* or in dsisr<4> = 1 to flag prot570* violation */571572dsi1:573mtctr %r0 /* restore counter */574andi. %r2, %r3, 0xffff /* clear upper bits of srr1 */575mtspr SPR_SRR1, %r2 /* set srr1 */576mtspr SPR_DSISR, %r1 /* load the dsisr */577mfspr %r1, SPR_DMISS /* get miss address */578rlwinm. %r2,%r2,0,31,31 /* test LE bit */579beq dsi2 /* if little endian then: */580xor %r1, %r1, 0x07 /* de-mung the data address */581dsi2:582mtspr SPR_DAR, %r1 /* put in dar */583mfmsr %r0 /* get msr */584xoris %r0, %r0, 0x2 /* flip the msr<tgpr> bit */585mtcrf 0x80, %r3 /* restore CR0 */586mtmsr %r0 /* flip back to the native gprs */587ba EXC_DSI /* branch to DSI interrupt */588589CNAME(dsmisssize) = .-CNAME(dsmisstrap)590591/*592* Similar to the above for DSI593* Has to handle BAT spills594* and standard pagetable spills595*/596.globl CNAME(dsitrap),CNAME(dsiend)597CNAME(dsitrap):598mtsprg1 %r1 /* save SP */599GET_CPUINFO(%r1)600stw %r28,(PC_DISISAVE+CPUSAVE_R28)(%r1) /* free r28-r31 */601stw %r29,(PC_DISISAVE+CPUSAVE_R29)(%r1)602stw %r30,(PC_DISISAVE+CPUSAVE_R30)(%r1)603stw %r31,(PC_DISISAVE+CPUSAVE_R31)(%r1)604mfsprg1 %r1 /* restore SP */605mfcr %r29 /* save CR */606mfxer %r30 /* save XER */607mtsprg2 %r30 /* in SPRG2 */608mfsrr1 %r31 /* test kernel mode */609mtcr %r31610bt 17,1f /* branch if PSL_PR is set */611mfdar %r31 /* get fault address */612rlwinm %r31,%r31,7,25,28 /* get segment * 8 */613614/* get batu */615lwz %r30,TRAP_TOCBASE(0)616lwz %r30,CNAME(battable)@got(%r30)617add %r31,%r30,%r31618lwz %r30,0(%r31)619mtcr %r30620bf 30,1f /* branch if supervisor valid is621false */622/* get batl */623lwz %r31,4(%r31)624/* We randomly use the highest two bat registers here */625mftb %r28626andi. %r28,%r28,1627bne 2f628mtdbatu 2,%r30629mtdbatl 2,%r31630b 3f6312:632mtdbatu 3,%r30633mtdbatl 3,%r316343:635mfsprg2 %r30 /* restore XER */636mtxer %r30637mtcr %r29 /* restore CR */638mtsprg1 %r1639GET_CPUINFO(%r1)640lwz %r28,(PC_DISISAVE+CPUSAVE_R28)(%r1) /* restore r28-r31 */641lwz %r29,(PC_DISISAVE+CPUSAVE_R29)(%r1)642lwz %r30,(PC_DISISAVE+CPUSAVE_R30)(%r1)643lwz %r31,(PC_DISISAVE+CPUSAVE_R31)(%r1)644mfsprg1 %r1645rfi /* return to trapped code */6461:647mflr %r28 /* save LR (SP already saved) */648649/* Jump to disitrap */650lwz %r1, TRAP_GENTRAP(0)651addi %r1, %r1, (disitrap - generictrap)652mtlr %r1653blrl654CNAME(dsiend):655656/*657* Preamble code for DSI/ISI traps658*/659disitrap:660/* Write the trap vector to SPRG3 by computing LR & 0xff00 */661mflr %r1662andi. %r1,%r1,0xff00663mtsprg3 %r1664665GET_CPUINFO(%r1)666lwz %r30,(PC_DISISAVE+CPUSAVE_R28)(%r1)667stw %r30,(PC_TEMPSAVE+CPUSAVE_R28)(%r1)668lwz %r31,(PC_DISISAVE+CPUSAVE_R29)(%r1)669stw %r31,(PC_TEMPSAVE+CPUSAVE_R29)(%r1)670lwz %r30,(PC_DISISAVE+CPUSAVE_R30)(%r1)671stw %r30,(PC_TEMPSAVE+CPUSAVE_R30)(%r1)672lwz %r31,(PC_DISISAVE+CPUSAVE_R31)(%r1)673stw %r31,(PC_TEMPSAVE+CPUSAVE_R31)(%r1)674mfdar %r30675mfdsisr %r31676stw %r30,(PC_TEMPSAVE+CPUSAVE_AIM_DAR)(%r1)677stw %r31,(PC_TEMPSAVE+CPUSAVE_AIM_DSISR)(%r1)678679#ifdef KDB680/* Try to detect a kernel stack overflow */681mfsrr1 %r31682mtcr %r31683bt 17,realtrap /* branch is user mode */684mfsprg1 %r31 /* get old SP */685clrrwi %r31,%r31,12 /* Round SP down to nearest page */686sub. %r30,%r31,%r30 /* SP - DAR */687bge 1f688neg %r30,%r30 /* modulo value */6891: cmplwi %cr0,%r30,4096 /* is DAR within a page of SP? */690bge %cr0,realtrap /* no, too far away. */691692/* Now convert this DSI into a DDB trap. */693GET_CPUINFO(%r1)694lwz %r30,(PC_TEMPSAVE+CPUSAVE_AIM_DAR)(%r1) /* get DAR */695stw %r30,(PC_DBSAVE +CPUSAVE_AIM_DAR)(%r1) /* save DAR */696lwz %r31,(PC_TEMPSAVE+CPUSAVE_AIM_DSISR)(%r1) /* get DSISR */697stw %r31,(PC_DBSAVE +CPUSAVE_AIM_DSISR)(%r1) /* save DSISR */698lwz %r30,(PC_DISISAVE+CPUSAVE_R28)(%r1) /* get r28 */699stw %r30,(PC_DBSAVE +CPUSAVE_R28)(%r1) /* save r28 */700lwz %r31,(PC_DISISAVE+CPUSAVE_R29)(%r1) /* get r29 */701stw %r31,(PC_DBSAVE +CPUSAVE_R29)(%r1) /* save r29 */702lwz %r30,(PC_DISISAVE+CPUSAVE_R30)(%r1) /* get r30 */703stw %r30,(PC_DBSAVE +CPUSAVE_R30)(%r1) /* save r30 */704lwz %r31,(PC_DISISAVE+CPUSAVE_R31)(%r1) /* get r31 */705stw %r31,(PC_DBSAVE +CPUSAVE_R31)(%r1) /* save r31 */706b dbtrap707#endif708709/* XXX need stack probe here */710realtrap:711/* Test whether we already had PR set */712mfsrr1 %r1713mtcr %r1714mfsprg1 %r1 /* restore SP (might have been715overwritten) */716bf 17,k_trap /* branch if PSL_PR is false */717GET_CPUINFO(%r1)718lwz %r1,PC_CURPCB(%r1)719RESTORE_KERN_SRS(%r30,%r31) /* enable kernel mapping */720b s_trap721722/*723* generictrap does some standard setup for trap handling to minimize724* the code that need be installed in the actual vectors. It expects725* the following conditions.726*727* R1 - Trap vector = LR & (0xff00 | R1)728* SPRG1 - Original R1 contents729* SPRG2 - Original LR730*/731732.globl CNAME(generictrap64)733generictrap64:734mtsprg3 %r31735mfmsr %r31736clrldi %r31,%r31,1737mtmsrd %r31738mfsprg3 %r31739isync740741.globl CNAME(generictrap)742generictrap:743/* Save R1 for computing the exception vector */744mtsprg3 %r1745746/* Save interesting registers */747GET_CPUINFO(%r1)748stw %r28,(PC_TEMPSAVE+CPUSAVE_R28)(%r1) /* free r28-r31 */749stw %r29,(PC_TEMPSAVE+CPUSAVE_R29)(%r1)750stw %r30,(PC_TEMPSAVE+CPUSAVE_R30)(%r1)751stw %r31,(PC_TEMPSAVE+CPUSAVE_R31)(%r1)752mfsprg1 %r1 /* restore SP, in case of branch */753mfsprg2 %r28 /* save LR */754mfcr %r29 /* save CR */755756/* Compute the exception vector from the link register */757mfsprg3 %r31758ori %r31,%r31,0xff00759mflr %r30760and %r30,%r30,%r31761mtsprg3 %r30762763/* Test whether we already had PR set */764mfsrr1 %r31765mtcr %r31766767s_trap:768bf 17,k_trap /* branch if PSL_PR is false */769GET_CPUINFO(%r1)770u_trap:771lwz %r1,PC_CURPCB(%r1)772RESTORE_KERN_SRS(%r30,%r31) /* enable kernel mapping */773774/*775* Now the common trap catching code.776*/777k_trap:778FRAME_SETUP(PC_TEMPSAVE)779/* Restore USER_SR */780GET_CPUINFO(%r30)781lwz %r30,PC_CURPCB(%r30)782lwz %r30,PCB_AIM_USR_VSID(%r30)783mtsr USER_SR,%r30; sync; isync784/* Call C interrupt dispatcher: */785trapagain:786addi %r3,%r1,8787bl CNAME(powerpc_interrupt)788.globl CNAME(trapexit) /* backtrace code sentinel */789CNAME(trapexit):790791/* Disable interrupts: */792mfmsr %r3793andi. %r3,%r3,~PSL_EE@l794mtmsr %r3795isync796/* Test AST pending: */797lwz %r5,FRAME_SRR1+8(%r1)798mtcr %r5799bf 17,1f /* branch if PSL_PR is false */800801GET_CPUINFO(%r3) /* get per-CPU pointer */802lwz %r4, TD_AST(%r2) /* get thread ast value803* (r2 is curthread) */804cmpwi %r4, 0805beq 1f806mfmsr %r3 /* re-enable interrupts */807ori %r3,%r3,PSL_EE@l808mtmsr %r3809isync810addi %r3,%r1,8811bl CNAME(ast)812.globl CNAME(asttrapexit) /* backtrace code sentinel #2 */813CNAME(asttrapexit):814b trapexit /* test ast ret value ? */8151:816FRAME_LEAVE(PC_TEMPSAVE)817818.globl CNAME(rfi_patch1) /* replace rfi with rfid on ppc64 */819CNAME(rfi_patch1):820rfi821822.globl CNAME(rfid_patch)823CNAME(rfid_patch):824rfid825826#if defined(KDB)827/*828* Deliberate entry to dbtrap829*/830.globl CNAME(breakpoint)831CNAME(breakpoint):832mtsprg1 %r1833mfmsr %r3834mtsrr1 %r3835andi. %r3,%r3,~(PSL_EE|PSL_ME)@l836mtmsr %r3 /* disable interrupts */837isync838GET_CPUINFO(%r3)839stw %r28,(PC_DBSAVE+CPUSAVE_R28)(%r3)840stw %r29,(PC_DBSAVE+CPUSAVE_R29)(%r3)841stw %r30,(PC_DBSAVE+CPUSAVE_R30)(%r3)842stw %r31,(PC_DBSAVE+CPUSAVE_R31)(%r3)843mflr %r28844li %r29,EXC_BPT845mtlr %r29846mfcr %r29847mtsrr0 %r28848849/*850* Now the kdb trap catching code.851*/852dbtrap:853/* Write the trap vector to SPRG3 by computing LR & 0xff00 */854mflr %r1855andi. %r1,%r1,0xff00856mtsprg3 %r1857858lwz %r1,TRAP_TOCBASE(0) /* get new SP */859lwz %r1,trapstk@got(%r1)860addi %r1,%r1,TRAPSTKSZ-16861862FRAME_SETUP(PC_DBSAVE)863/* Call C trap code: */864addi %r3,%r1,8865bl CNAME(db_trap_glue)866or. %r3,%r3,%r3867bne dbleave868/* This wasn't for KDB, so switch to real trap: */869lwz %r3,FRAME_EXC+8(%r1) /* save exception */870GET_CPUINFO(%r4)871stw %r3,(PC_DBSAVE+CPUSAVE_R31)(%r4)872FRAME_LEAVE(PC_DBSAVE)873mtsprg1 %r1 /* prepare for entrance to realtrap */874GET_CPUINFO(%r1)875stw %r28,(PC_TEMPSAVE+CPUSAVE_R28)(%r1)876stw %r29,(PC_TEMPSAVE+CPUSAVE_R29)(%r1)877stw %r30,(PC_TEMPSAVE+CPUSAVE_R30)(%r1)878stw %r31,(PC_TEMPSAVE+CPUSAVE_R31)(%r1)879mflr %r28880mfcr %r29881lwz %r31,(PC_DBSAVE+CPUSAVE_R31)(%r1)882mtsprg3 %r31 /* SPRG3 was clobbered by FRAME_LEAVE */883mfsprg1 %r1884b realtrap885dbleave:886FRAME_LEAVE(PC_DBSAVE)887.globl CNAME(rfi_patch2) /* replace rfi with rfid on ppc64 */888CNAME(rfi_patch2):889rfi890891/*892* In case of KDB we want a separate trap catcher for it893*/894.globl CNAME(dblow),CNAME(dbend)895CNAME(dblow):896mtsprg1 %r1 /* save SP */897mtsprg2 %r29 /* save r29 */898mfcr %r29 /* save CR in r29 */899mfsrr1 %r1900mtcr %r1901bf 17,1f /* branch if privileged */902/* Unprivileged case */903mtcr %r29 /* put the condition register back */904mfsprg2 %r29 /* ... and r29 */905mflr %r1 /* save LR */906mtsprg2 %r1 /* And then in SPRG2 */907908lwz %r1, TRAP_ENTRY(0) /* Get branch address */909mtlr %r1910li %r1, 0 /* How to get the vector from LR */911blrl /* LR & (0xff00 | r1) is exception # */9121:913/* Privileged, so drop to KDB */914GET_CPUINFO(%r1)915stw %r28,(PC_DBSAVE+CPUSAVE_R28)(%r1) /* free r28 */916mfsprg2 %r28 /* r29 holds cr... */917stw %r28,(PC_DBSAVE+CPUSAVE_R29)(%r1) /* free r29 */918stw %r30,(PC_DBSAVE+CPUSAVE_R30)(%r1) /* free r30 */919stw %r31,(PC_DBSAVE+CPUSAVE_R31)(%r1) /* free r31 */920mflr %r28 /* save LR */921922/* Jump to dbtrap */923lwz %r1, TRAP_GENTRAP(0)924addi %r1, %r1, (dbtrap - generictrap)925mtlr %r1926blrl927CNAME(dbend):928#endif /* KDB */929930931