/*-1* Copyright (C) 2006-2009 Semihalf, Rafal Jaworowski <[email protected]>2* Copyright (C) 2006 Semihalf, Marian Balakowicz <[email protected]>3* Copyright (C) 2006 Juniper Networks, Inc.4* All rights reserved.5*6* Redistribution and use in source and binary forms, with or without7* modification, are permitted provided that the following conditions8* are met:9* 1. Redistributions of source code must retain the above copyright10* notice, this list of conditions and the following disclaimer.11* 2. Redistributions in binary form must reproduce the above copyright12* notice, this list of conditions and the following disclaimer in the13* documentation and/or other materials provided with the distribution.14* 3. The name of the author may not be used to endorse or promote products15* derived from this software without specific prior written permission.16*17* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR18* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES19* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN20* NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,21* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED22* TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR23* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF24* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING25* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS26* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.27*/28/*-29* Copyright (C) 1995, 1996 Wolfgang Solfrank.30* Copyright (C) 1995, 1996 TooLs GmbH.31* All rights reserved.32*33* Redistribution and use in source and binary forms, with or without34* modification, are permitted provided that the following conditions35* are met:36* 1. Redistributions of source code must retain the above copyright37* notice, this list of conditions and the following disclaimer.38* 2. Redistributions in binary form must reproduce the above copyright39* notice, this list of conditions and the following disclaimer in the40* documentation and/or other materials provided with the distribution.41* 3. All advertising materials mentioning features or use of this software42* must display the following acknowledgement:43* This product includes software developed by TooLs GmbH.44* 4. The name of TooLs GmbH may not be used to endorse or promote products45* derived from this software without specific prior written permission.46*47* THIS SOFTWARE IS PROVIDED BY TOOLS GMBH ``AS IS'' AND ANY EXPRESS OR48* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES49* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.50* IN NO EVENT SHALL TOOLS GMBH BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,51* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,52* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;53* OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,54* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR55* OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF56* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.57*58* from: $NetBSD: trap_subr.S,v 1.20 2002/04/22 23:20:08 kleink Exp $59*/6061/*62* NOTICE: This is not a standalone file. to use it, #include it in63* your port's locore.S, like so:64*65* #include <powerpc/booke/trap_subr.S>66*/6768/*69* SPRG usage notes70*71* SPRG0 - pcpu pointer72* SPRG1 - all interrupts except TLB miss, critical, machine check73* SPRG2 - critical74* SPRG3 - machine check75* SPRG4-6 - scratch76*77*/7879/* Get the per-CPU data structure */80#define GET_CPUINFO(r) mfsprg0 r8182#define RES_GRANULE 6483#define RES_LOCK 0 /* offset to the 'lock' word */84#ifdef __powerpc64__85#define RES_RECURSE 8 /* offset to the 'recurse' word */86#else87#define RES_RECURSE 4 /* offset to the 'recurse' word */88#endif8990/*91* Standard interrupt prolog92*93* sprg_sp - SPRG{1-3} reg used to temporarily store the SP94* savearea - temp save area (pc_{tempsave, disisave, critsave, mchksave})95* isrr0-1 - save restore registers with CPU state at interrupt time (may be96* SRR0-1, CSRR0-1, MCSRR0-197*98* 1. saves in the given savearea:99* - R30-31100* - DEAR, ESR101* - xSRR0-1102*103* 2. saves CR -> R30104*105* 3. switches to kstack if needed106*107* 4. notes:108* - R31 can be used as scratch register until a new frame is laid on109* the stack with FRAME_SETUP110*111* - potential TLB miss: NO. Saveareas are always acessible via TLB1112* permanent entries, and within this prolog we do not dereference any113* locations potentially not in the TLB114*/115#define STANDARD_PROLOG(sprg_sp, savearea, isrr0, isrr1) \116mtspr sprg_sp, %r1; /* Save SP */ \117GET_CPUINFO(%r1); /* Per-cpu structure */ \118STORE %r30, (savearea+CPUSAVE_R30)(%r1); \119STORE %r31, (savearea+CPUSAVE_R31)(%r1); \120mfspr %r30, SPR_DEAR; \121mfspr %r31, SPR_ESR; \122STORE %r30, (savearea+CPUSAVE_BOOKE_DEAR)(%r1); \123STORE %r31, (savearea+CPUSAVE_BOOKE_ESR)(%r1); \124mfspr %r30, isrr0; \125mfspr %r31, isrr1; /* MSR at interrupt time */ \126STORE %r30, (savearea+CPUSAVE_SRR0)(%r1); \127STORE %r31, (savearea+CPUSAVE_SRR1)(%r1); \128isync; \129mfspr %r1, sprg_sp; /* Restore SP */ \130mfcr %r30; /* Save CR */ \131/* switch to per-thread kstack if intr taken in user mode */ \132mtcr %r31; /* MSR at interrupt time */ \133bf 17, 1f; \134GET_CPUINFO(%r1); /* Per-cpu structure */ \135LOAD %r1, PC_CURPCB(%r1); /* Per-thread kernel stack */ \1361:137138#define STANDARD_CRIT_PROLOG(sprg_sp, savearea, isrr0, isrr1) \139mtspr sprg_sp, %r1; /* Save SP */ \140GET_CPUINFO(%r1); /* Per-cpu structure */ \141STORE %r30, (savearea+CPUSAVE_R30)(%r1); \142STORE %r31, (savearea+CPUSAVE_R31)(%r1); \143mfspr %r30, SPR_DEAR; \144mfspr %r31, SPR_ESR; \145STORE %r30, (savearea+CPUSAVE_BOOKE_DEAR)(%r1); \146STORE %r31, (savearea+CPUSAVE_BOOKE_ESR)(%r1); \147mfspr %r30, isrr0; \148mfspr %r31, isrr1; /* MSR at interrupt time */ \149STORE %r30, (savearea+CPUSAVE_SRR0)(%r1); \150STORE %r31, (savearea+CPUSAVE_SRR1)(%r1); \151mfspr %r30, SPR_SRR0; \152mfspr %r31, SPR_SRR1; /* MSR at interrupt time */ \153STORE %r30, (savearea+BOOKE_CRITSAVE_SRR0)(%r1); \154STORE %r31, (savearea+BOOKE_CRITSAVE_SRR1)(%r1); \155isync; \156mfspr %r1, sprg_sp; /* Restore SP */ \157mfcr %r30; /* Save CR */ \158/* switch to per-thread kstack if intr taken in user mode */ \159mtcr %r31; /* MSR at interrupt time */ \160bf 17, 1f; \161GET_CPUINFO(%r1); /* Per-cpu structure */ \162LOAD %r1, PC_CURPCB(%r1); /* Per-thread kernel stack */ \1631:164165/*166* FRAME_SETUP assumes:167* SPRG{1-3} SP at the time interrupt occurred168* savearea r30-r31, DEAR, ESR, xSRR0-1169* r30 CR170* r31 scratch171* r1 kernel stack172*173* sprg_sp - SPRG reg containing SP at the time interrupt occurred174* savearea - temp save175* exc - exception number (EXC_xxx)176*177* 1. sets a new frame178* 2. saves in the frame:179* - R0, R1 (SP at the time of interrupt), R2, LR, CR180* - R3-31 (R30-31 first restored from savearea)181* - XER, CTR, DEAR, ESR (from savearea), xSRR0-1182*183* Notes:184* - potential TLB miss: YES, since we make dereferences to kstack, which185* can happen not covered (we can have up to two DTLB misses if fortunate186* enough i.e. when kstack crosses page boundary and both pages are187* untranslated)188*/189#ifdef __powerpc64__190#define SAVE_REGS(r) \191std %r3, FRAME_3+CALLSIZE(r); \192std %r4, FRAME_4+CALLSIZE(r); \193std %r5, FRAME_5+CALLSIZE(r); \194std %r6, FRAME_6+CALLSIZE(r); \195std %r7, FRAME_7+CALLSIZE(r); \196std %r8, FRAME_8+CALLSIZE(r); \197std %r9, FRAME_9+CALLSIZE(r); \198std %r10, FRAME_10+CALLSIZE(r); \199std %r11, FRAME_11+CALLSIZE(r); \200std %r12, FRAME_12+CALLSIZE(r); \201std %r13, FRAME_13+CALLSIZE(r); \202std %r14, FRAME_14+CALLSIZE(r); \203std %r15, FRAME_15+CALLSIZE(r); \204std %r16, FRAME_16+CALLSIZE(r); \205std %r17, FRAME_17+CALLSIZE(r); \206std %r18, FRAME_18+CALLSIZE(r); \207std %r19, FRAME_19+CALLSIZE(r); \208std %r20, FRAME_20+CALLSIZE(r); \209std %r21, FRAME_21+CALLSIZE(r); \210std %r22, FRAME_22+CALLSIZE(r); \211std %r23, FRAME_23+CALLSIZE(r); \212std %r24, FRAME_24+CALLSIZE(r); \213std %r25, FRAME_25+CALLSIZE(r); \214std %r26, FRAME_26+CALLSIZE(r); \215std %r27, FRAME_27+CALLSIZE(r); \216std %r28, FRAME_28+CALLSIZE(r); \217std %r29, FRAME_29+CALLSIZE(r); \218std %r30, FRAME_30+CALLSIZE(r); \219std %r31, FRAME_31+CALLSIZE(r)220#define LD_REGS(r) \221ld %r3, FRAME_3+CALLSIZE(r); \222ld %r4, FRAME_4+CALLSIZE(r); \223ld %r5, FRAME_5+CALLSIZE(r); \224ld %r6, FRAME_6+CALLSIZE(r); \225ld %r7, FRAME_7+CALLSIZE(r); \226ld %r8, FRAME_8+CALLSIZE(r); \227ld %r9, FRAME_9+CALLSIZE(r); \228ld %r10, FRAME_10+CALLSIZE(r); \229ld %r11, FRAME_11+CALLSIZE(r); \230ld %r12, FRAME_12+CALLSIZE(r); \231ld %r13, FRAME_13+CALLSIZE(r); \232ld %r14, FRAME_14+CALLSIZE(r); \233ld %r15, FRAME_15+CALLSIZE(r); \234ld %r16, FRAME_16+CALLSIZE(r); \235ld %r17, FRAME_17+CALLSIZE(r); \236ld %r18, FRAME_18+CALLSIZE(r); \237ld %r19, FRAME_19+CALLSIZE(r); \238ld %r20, FRAME_20+CALLSIZE(r); \239ld %r21, FRAME_21+CALLSIZE(r); \240ld %r22, FRAME_22+CALLSIZE(r); \241ld %r23, FRAME_23+CALLSIZE(r); \242ld %r24, FRAME_24+CALLSIZE(r); \243ld %r25, FRAME_25+CALLSIZE(r); \244ld %r26, FRAME_26+CALLSIZE(r); \245ld %r27, FRAME_27+CALLSIZE(r); \246ld %r28, FRAME_28+CALLSIZE(r); \247ld %r29, FRAME_29+CALLSIZE(r); \248ld %r30, FRAME_30+CALLSIZE(r); \249ld %r31, FRAME_31+CALLSIZE(r)250#else251#define SAVE_REGS(r) \252stmw %r3, FRAME_3+CALLSIZE(r)253#define LD_REGS(r) \254lmw %r3, FRAME_3+CALLSIZE(r)255#endif256#define FRAME_SETUP(sprg_sp, savearea, exc) \257mfspr %r31, sprg_sp; /* get saved SP */ \258/* establish a new stack frame and put everything on it */ \259STU %r31, -(FRAMELEN+REDZONE)(%r1); \260STORE %r0, FRAME_0+CALLSIZE(%r1); /* save r0 in the trapframe */ \261STORE %r31, FRAME_1+CALLSIZE(%r1); /* save SP " " */ \262STORE %r2, FRAME_2+CALLSIZE(%r1); /* save r2 " " */ \263mflr %r31; \264STORE %r31, FRAME_LR+CALLSIZE(%r1); /* save LR " " */ \265STORE %r30, FRAME_CR+CALLSIZE(%r1); /* save CR " " */ \266GET_CPUINFO(%r2); \267LOAD %r30, (savearea+CPUSAVE_R30)(%r2); /* get saved r30 */ \268LOAD %r31, (savearea+CPUSAVE_R31)(%r2); /* get saved r31 */ \269/* save R3-31 */ \270SAVE_REGS(%r1); \271/* save DEAR, ESR */ \272LOAD %r28, (savearea+CPUSAVE_BOOKE_DEAR)(%r2); \273LOAD %r29, (savearea+CPUSAVE_BOOKE_ESR)(%r2); \274STORE %r28, FRAME_BOOKE_DEAR+CALLSIZE(%r1); \275STORE %r29, FRAME_BOOKE_ESR+CALLSIZE(%r1); \276/* save XER, CTR, exc number */ \277mfxer %r3; \278mfctr %r4; \279STORE %r3, FRAME_XER+CALLSIZE(%r1); \280STORE %r4, FRAME_CTR+CALLSIZE(%r1); \281li %r5, exc; \282STORE %r5, FRAME_EXC+CALLSIZE(%r1); \283/* save DBCR0 */ \284mfspr %r3, SPR_DBCR0; \285STORE %r3, FRAME_BOOKE_DBCR0+CALLSIZE(%r1); \286/* save xSSR0-1 */ \287LOAD %r30, (savearea+CPUSAVE_SRR0)(%r2); \288LOAD %r31, (savearea+CPUSAVE_SRR1)(%r2); \289STORE %r30, FRAME_SRR0+CALLSIZE(%r1); \290STORE %r31, FRAME_SRR1+CALLSIZE(%r1); \291LOAD THREAD_REG, PC_CURTHREAD(%r2); \292293/*294*295* isrr0-1 - save restore registers to restore CPU state to (may be296* SRR0-1, CSRR0-1, MCSRR0-1297*298* Notes:299* - potential TLB miss: YES. The deref'd kstack may be not covered300*/301#define FRAME_LEAVE(isrr0, isrr1) \302wrteei 0; \303/* restore CTR, XER, LR, CR */ \304LOAD %r4, FRAME_CTR+CALLSIZE(%r1); \305LOAD %r5, FRAME_XER+CALLSIZE(%r1); \306LOAD %r6, FRAME_LR+CALLSIZE(%r1); \307LOAD %r7, FRAME_CR+CALLSIZE(%r1); \308mtctr %r4; \309mtxer %r5; \310mtlr %r6; \311mtcr %r7; \312/* restore DBCR0 */ \313LOAD %r4, FRAME_BOOKE_DBCR0+CALLSIZE(%r1); \314mtspr SPR_DBCR0, %r4; \315/* restore xSRR0-1 */ \316LOAD %r30, FRAME_SRR0+CALLSIZE(%r1); \317LOAD %r31, FRAME_SRR1+CALLSIZE(%r1); \318mtspr isrr0, %r30; \319mtspr isrr1, %r31; \320/* restore R2-31, SP */ \321LD_REGS(%r1); \322LOAD %r2, FRAME_2+CALLSIZE(%r1); \323LOAD %r0, FRAME_0+CALLSIZE(%r1); \324LOAD %r1, FRAME_1+CALLSIZE(%r1); \325isync326327/*328* TLB miss prolog329*330* saves LR, CR, SRR0-1, R20-31 in the TLBSAVE area331*332* Notes:333* - potential TLB miss: NO. It is crucial that we do not generate a TLB334* miss within the TLB prolog itself!335* - TLBSAVE is always translated336*/337#ifdef __powerpc64__338#define TLB_SAVE_REGS(br) \339std %r20, (TLBSAVE_BOOKE_R20)(br); \340std %r21, (TLBSAVE_BOOKE_R21)(br); \341std %r22, (TLBSAVE_BOOKE_R22)(br); \342std %r23, (TLBSAVE_BOOKE_R23)(br); \343std %r24, (TLBSAVE_BOOKE_R24)(br); \344std %r25, (TLBSAVE_BOOKE_R25)(br); \345std %r26, (TLBSAVE_BOOKE_R26)(br); \346std %r27, (TLBSAVE_BOOKE_R27)(br); \347std %r28, (TLBSAVE_BOOKE_R28)(br); \348std %r29, (TLBSAVE_BOOKE_R29)(br); \349std %r30, (TLBSAVE_BOOKE_R30)(br); \350std %r31, (TLBSAVE_BOOKE_R31)(br);351#define TLB_RESTORE_REGS(br) \352ld %r20, (TLBSAVE_BOOKE_R20)(br); \353ld %r21, (TLBSAVE_BOOKE_R21)(br); \354ld %r22, (TLBSAVE_BOOKE_R22)(br); \355ld %r23, (TLBSAVE_BOOKE_R23)(br); \356ld %r24, (TLBSAVE_BOOKE_R24)(br); \357ld %r25, (TLBSAVE_BOOKE_R25)(br); \358ld %r26, (TLBSAVE_BOOKE_R26)(br); \359ld %r27, (TLBSAVE_BOOKE_R27)(br); \360ld %r28, (TLBSAVE_BOOKE_R28)(br); \361ld %r29, (TLBSAVE_BOOKE_R29)(br); \362ld %r30, (TLBSAVE_BOOKE_R30)(br); \363ld %r31, (TLBSAVE_BOOKE_R31)(br);364#define TLB_NEST(outr,inr) \365rlwinm outr, inr, 7, 23, 24; /* 8 x TLBSAVE_LEN */366#else367#define TLB_SAVE_REGS(br) \368stmw %r20, TLBSAVE_BOOKE_R20(br)369#define TLB_RESTORE_REGS(br) \370lmw %r20, TLBSAVE_BOOKE_R20(br)371#define TLB_NEST(outr,inr) \372rlwinm outr, inr, 6, 24, 25; /* 4 x TLBSAVE_LEN */373#endif374#define TLB_PROLOG \375mtspr SPR_SPRG4, %r1; /* Save SP */ \376mtspr SPR_SPRG5, %r28; \377mtspr SPR_SPRG6, %r29; \378/* calculate TLB nesting level and TLBSAVE instance address */ \379GET_CPUINFO(%r1); /* Per-cpu structure */ \380LOAD %r28, PC_BOOKE_TLB_LEVEL(%r1); \381TLB_NEST(%r29,%r28); \382addi %r28, %r28, 1; \383STORE %r28, PC_BOOKE_TLB_LEVEL(%r1); \384addi %r29, %r29, PC_BOOKE_TLBSAVE@l; \385add %r1, %r1, %r29; /* current TLBSAVE ptr */ \386\387/* save R20-31 */ \388mfspr %r28, SPR_SPRG5; \389mfspr %r29, SPR_SPRG6; \390TLB_SAVE_REGS(%r1); \391/* save LR, CR */ \392mflr %r30; \393mfcr %r31; \394STORE %r30, (TLBSAVE_BOOKE_LR)(%r1); \395STORE %r31, (TLBSAVE_BOOKE_CR)(%r1); \396/* save SRR0-1 */ \397mfsrr0 %r30; /* execution addr at interrupt time */ \398mfsrr1 %r31; /* MSR at interrupt time*/ \399STORE %r30, (TLBSAVE_BOOKE_SRR0)(%r1); /* save SRR0 */ \400STORE %r31, (TLBSAVE_BOOKE_SRR1)(%r1); /* save SRR1 */ \401isync; \402mfspr %r1, SPR_SPRG4403404/*405* restores LR, CR, SRR0-1, R20-31 from the TLBSAVE area406*407* same notes as for the TLB_PROLOG408*/409#define TLB_RESTORE \410mtspr SPR_SPRG4, %r1; /* Save SP */ \411GET_CPUINFO(%r1); /* Per-cpu structure */ \412/* calculate TLB nesting level and TLBSAVE instance addr */ \413LOAD %r28, PC_BOOKE_TLB_LEVEL(%r1); \414subi %r28, %r28, 1; \415STORE %r28, PC_BOOKE_TLB_LEVEL(%r1); \416TLB_NEST(%r29,%r28); \417addi %r29, %r29, PC_BOOKE_TLBSAVE@l; \418add %r1, %r1, %r29; \419\420/* restore LR, CR */ \421LOAD %r30, (TLBSAVE_BOOKE_LR)(%r1); \422LOAD %r31, (TLBSAVE_BOOKE_CR)(%r1); \423mtlr %r30; \424mtcr %r31; \425/* restore SRR0-1 */ \426LOAD %r30, (TLBSAVE_BOOKE_SRR0)(%r1); \427LOAD %r31, (TLBSAVE_BOOKE_SRR1)(%r1); \428mtsrr0 %r30; \429mtsrr1 %r31; \430/* restore R20-31 */ \431TLB_RESTORE_REGS(%r1); \432mfspr %r1, SPR_SPRG4433434#ifdef SMP435#define TLB_LOCK \436GET_CPUINFO(%r20); \437LOAD %r21, PC_CURTHREAD(%r20); \438LOAD %r22, PC_BOOKE_TLB_LOCK(%r20); \439\4401: LOADX %r23, 0, %r22; \441CMPI %r23, TLB_UNLOCKED; \442beq 2f; \443\444/* check if this is recursion */ \445CMPL cr0, %r21, %r23; \446bne- 1b; \447\4482: /* try to acquire lock */ \449STOREX %r21, 0, %r22; \450bne- 1b; \451\452/* got it, update recursion counter */ \453lwz %r21, RES_RECURSE(%r22); \454addi %r21, %r21, 1; \455stw %r21, RES_RECURSE(%r22); \456isync; \457msync458459#define TLB_UNLOCK \460GET_CPUINFO(%r20); \461LOAD %r21, PC_CURTHREAD(%r20); \462LOAD %r22, PC_BOOKE_TLB_LOCK(%r20); \463\464/* update recursion counter */ \465lwz %r23, RES_RECURSE(%r22); \466subi %r23, %r23, 1; \467stw %r23, RES_RECURSE(%r22); \468\469cmplwi %r23, 0; \470bne 1f; \471isync; \472msync; \473\474/* release the lock */ \475li %r23, TLB_UNLOCKED; \476STORE %r23, 0(%r22); \4771: isync; \478msync479#else480#define TLB_LOCK481#define TLB_UNLOCK482#endif /* SMP */483484#define INTERRUPT(label) \485.globl label; \486.align 5; \487CNAME(label):488489/*490* Interrupt handling routines in BookE can be flexibly placed and do not have491* to live in pre-defined vectors location. Note they need to be TLB-mapped at492* all times in order to be able to handle exceptions. We thus arrange for493* them to be part of kernel text which is always TLB-accessible.494*495* The interrupt handling routines have to be 16 bytes aligned: we align them496* to 32 bytes (cache line length) which supposedly performs better.497*498*/499.text500.globl CNAME(interrupt_vector_base)501.align 5502interrupt_vector_base:503/*****************************************************************************504* Catch-all handler to handle uninstalled IVORs505****************************************************************************/506INTERRUPT(int_unknown)507STANDARD_PROLOG(SPR_SPRG1, PC_TEMPSAVE, SPR_SRR0, SPR_SRR1)508FRAME_SETUP(SPR_SPRG1, PC_TEMPSAVE, EXC_RSVD)509b trap_common510511/*****************************************************************************512* Critical input interrupt513****************************************************************************/514INTERRUPT(int_critical_input)515STANDARD_CRIT_PROLOG(SPR_SPRG2, PC_BOOKE_CRITSAVE, SPR_CSRR0, SPR_CSRR1)516FRAME_SETUP(SPR_SPRG2, PC_BOOKE_CRITSAVE, EXC_CRIT)517GET_TOCBASE(%r2)518addi %r3, %r1, CALLSIZE519bl CNAME(powerpc_interrupt)520TOC_RESTORE521FRAME_LEAVE(SPR_CSRR0, SPR_CSRR1)522rfci523524525/*****************************************************************************526* Machine check interrupt527****************************************************************************/528INTERRUPT(int_machine_check)529STANDARD_PROLOG(SPR_SPRG3, PC_BOOKE_MCHKSAVE, SPR_MCSRR0, SPR_MCSRR1)530FRAME_SETUP(SPR_SPRG3, PC_BOOKE_MCHKSAVE, EXC_MCHK)531GET_TOCBASE(%r2)532addi %r3, %r1, CALLSIZE533bl CNAME(powerpc_interrupt)534TOC_RESTORE535FRAME_LEAVE(SPR_MCSRR0, SPR_MCSRR1)536rfmci537538539/*****************************************************************************540* Data storage interrupt541****************************************************************************/542INTERRUPT(int_data_storage)543STANDARD_PROLOG(SPR_SPRG1, PC_DISISAVE, SPR_SRR0, SPR_SRR1)544FRAME_SETUP(SPR_SPRG1, PC_DISISAVE, EXC_DSI)545b trap_common546547548/*****************************************************************************549* Instruction storage interrupt550****************************************************************************/551INTERRUPT(int_instr_storage)552STANDARD_PROLOG(SPR_SPRG1, PC_TEMPSAVE, SPR_SRR0, SPR_SRR1)553FRAME_SETUP(SPR_SPRG1, PC_TEMPSAVE, EXC_ISI)554b trap_common555556557/*****************************************************************************558* External input interrupt559****************************************************************************/560INTERRUPT(int_external_input)561STANDARD_PROLOG(SPR_SPRG1, PC_TEMPSAVE, SPR_SRR0, SPR_SRR1)562FRAME_SETUP(SPR_SPRG1, PC_TEMPSAVE, EXC_EXI)563b trap_common564565566INTERRUPT(int_alignment)567STANDARD_PROLOG(SPR_SPRG1, PC_TEMPSAVE, SPR_SRR0, SPR_SRR1)568FRAME_SETUP(SPR_SPRG1, PC_TEMPSAVE, EXC_ALI)569b trap_common570571572INTERRUPT(int_program)573STANDARD_PROLOG(SPR_SPRG1, PC_TEMPSAVE, SPR_SRR0, SPR_SRR1)574FRAME_SETUP(SPR_SPRG1, PC_TEMPSAVE, EXC_PGM)575b trap_common576577578INTERRUPT(int_fpu)579STANDARD_PROLOG(SPR_SPRG1, PC_TEMPSAVE, SPR_SRR0, SPR_SRR1)580FRAME_SETUP(SPR_SPRG1, PC_TEMPSAVE, EXC_FPU)581b trap_common582583584/*****************************************************************************585* System call586****************************************************************************/587INTERRUPT(int_syscall)588STANDARD_PROLOG(SPR_SPRG1, PC_TEMPSAVE, SPR_SRR0, SPR_SRR1)589FRAME_SETUP(SPR_SPRG1, PC_TEMPSAVE, EXC_SC)590b trap_common591592593/*****************************************************************************594* Decrementer interrupt595****************************************************************************/596INTERRUPT(int_decrementer)597STANDARD_PROLOG(SPR_SPRG1, PC_TEMPSAVE, SPR_SRR0, SPR_SRR1)598FRAME_SETUP(SPR_SPRG1, PC_TEMPSAVE, EXC_DECR)599b trap_common600601602/*****************************************************************************603* Fixed interval timer604****************************************************************************/605INTERRUPT(int_fixed_interval_timer)606STANDARD_PROLOG(SPR_SPRG1, PC_TEMPSAVE, SPR_SRR0, SPR_SRR1)607FRAME_SETUP(SPR_SPRG1, PC_TEMPSAVE, EXC_FIT)608b trap_common609610611/*****************************************************************************612* Watchdog interrupt613****************************************************************************/614INTERRUPT(int_watchdog)615STANDARD_PROLOG(SPR_SPRG1, PC_TEMPSAVE, SPR_SRR0, SPR_SRR1)616FRAME_SETUP(SPR_SPRG1, PC_TEMPSAVE, EXC_WDOG)617b trap_common618619620/*****************************************************************************621* Altivec Unavailable interrupt622****************************************************************************/623INTERRUPT(int_vec)624STANDARD_PROLOG(SPR_SPRG1, PC_TEMPSAVE, SPR_SRR0, SPR_SRR1)625FRAME_SETUP(SPR_SPRG1, PC_TEMPSAVE, EXC_VEC)626b trap_common627628629/*****************************************************************************630* Altivec Assist interrupt631****************************************************************************/632INTERRUPT(int_vecast)633STANDARD_PROLOG(SPR_SPRG1, PC_TEMPSAVE, SPR_SRR0, SPR_SRR1)634FRAME_SETUP(SPR_SPRG1, PC_TEMPSAVE, EXC_VECAST_E)635b trap_common636637638#ifdef __SPE__639/*****************************************************************************640* Floating point Assist interrupt641****************************************************************************/642INTERRUPT(int_spe_fpdata)643STANDARD_PROLOG(SPR_SPRG1, PC_TEMPSAVE, SPR_SRR0, SPR_SRR1)644FRAME_SETUP(SPR_SPRG1, PC_TEMPSAVE, EXC_SPFPD)645addi %r3, %r1, CALLSIZE646bl spe_handle_fpdata647FRAME_LEAVE(SPR_SRR0, SPR_SRR1)648rfi649650INTERRUPT(int_spe_fpround)651STANDARD_PROLOG(SPR_SPRG1, PC_TEMPSAVE, SPR_SRR0, SPR_SRR1)652FRAME_SETUP(SPR_SPRG1, PC_TEMPSAVE, EXC_SPFPR)653addi %r3, %r1, CALLSIZE654bl spe_handle_fpround655FRAME_LEAVE(SPR_SRR0, SPR_SRR1)656rfi657#endif658659660#ifdef HWPMC_HOOKS661/*****************************************************************************662* PMC Interrupt663****************************************************************************/664INTERRUPT(int_performance_counter)665STANDARD_PROLOG(SPR_SPRG3, PC_TEMPSAVE, SPR_SRR0, SPR_SRR1)666FRAME_SETUP(SPR_SPRG3, PC_TEMPSAVE, EXC_PERF)667b trap_common668#endif669670671/*****************************************************************************672* Data TLB miss interrupt673*674* There can be nested TLB misses - while handling a TLB miss we reference675* data structures that may be not covered by translations. We support up to676* TLB_NESTED_MAX-1 nested misses.677*678* Registers use:679* r31 - dear680* r30 - unused681* r29 - saved mas0682* r28 - saved mas1683* r27 - saved mas2684* r26 - pmap address685* r25 - pte address686*687* r20:r23 - scratch registers688****************************************************************************/689INTERRUPT(int_data_tlb_error)690TLB_PROLOG691TLB_LOCK692693mfspr %r31, SPR_DEAR694695/*696* Save MAS0-MAS2 registers. There might be another tlb miss during697* pte lookup overwriting current contents (which was hw filled).698*/699mfspr %r29, SPR_MAS0700mfspr %r28, SPR_MAS1701mfspr %r27, SPR_MAS2702703/* Check faulting address. */704LOAD_ADDR(%r21, VM_MAXUSER_ADDRESS)705CMPL cr0, %r31, %r21706blt search_user_pmap707708/* If it's kernel address, allow only supervisor mode misses. */709mfsrr1 %r21710mtcr %r21711bt 17, search_failed /* check MSR[PR] */712713#ifdef __powerpc64__714srdi %r21, %r31, 48715cmpldi cr0, %r21, VM_MIN_KERNEL_ADDRESS@highest716#else717lis %r21, VM_MIN_KERNEL_ADDRESS@h718cmplw cr0, %r31, %r21719#endif720blt search_failed721722search_kernel_pmap:723/* Load r26 with kernel_pmap address */724bl 1f725#ifdef __powerpc64__726.llong kernel_pmap_store-.727#else728.long kernel_pmap_store-.729#endif7301: mflr %r21731LOAD %r26, 0(%r21)732add %r26, %r21, %r26 /* kernel_pmap_store in r26 */733734/* Force kernel tid, set TID to 0 in MAS1. */735li %r21, 0736rlwimi %r28, %r21, 0, 8, 15 /* clear TID bits */737738tlb_miss_handle:739/* This may result in nested tlb miss. */740bl pte_lookup /* returns PTE address in R25 */741742CMPI %r25, 0 /* pte found? */743beq search_failed744745/* Finish up, write TLB entry. */746bl tlb_fill_entry747748tlb_miss_return:749TLB_UNLOCK750TLB_RESTORE751rfi752753search_user_pmap:754/* Load r26 with current user space process pmap */755GET_CPUINFO(%r26)756LOAD %r26, PC_CURPMAP(%r26)757758b tlb_miss_handle759760search_failed:761/*762* Whenever we don't find a TLB mapping in PT, set a TLB0 entry with763* the faulting virtual address anyway, but put a fake RPN and no764* access rights. This should cause a following {D,I}SI exception.765*/766lis %r23, 0xffff0000@h /* revoke all permissions */767768/* Load MAS registers. */769mtspr SPR_MAS0, %r29770mtspr SPR_MAS1, %r28771mtspr SPR_MAS2, %r27772mtspr SPR_MAS3, %r23773774li %r23, 0775mtspr SPR_MAS7, %r23776777isync778tlbwe779msync780isync781b tlb_miss_return782783/*****************************************************************************784*785* Return pte address that corresponds to given pmap/va. If there is no valid786* entry return 0.787*788* input: r26 - pmap789* input: r31 - dear790* output: r25 - pte address791*792* scratch regs used: r21793*794****************************************************************************/795pte_lookup:796CMPI %r26, 0797beq 1f /* fail quickly if pmap is invalid */798799#ifdef __powerpc64__800rldicl %r21, %r31, (64 - PG_ROOT_L), (64 - PG_ROOT_NUM) /* pp2d offset */801slwi %r21, %r21, PG_ROOT_ENTRY_SHIFT /* multiply by pp2d entry size */802ld %r25, PM_ROOT(%r26) /* pmap pm_pp2d[] address */803ldx %r25, %r25, %r21 /* get pdir address, i.e. pmap->pm_pp2d[pp2d_idx] * */804805cmpdi %r25, 0806beq 2f807808rldicl %r21, %r31, (64 - PDIR_L1_L), (64 - PDIR_L1_NUM) /* pp2d offset */809slwi %r21, %r21, PDIR_L1_ENTRY_SHIFT /* multiply by pp2d entry size */810ldx %r25, %r25, %r21 /* get pdir address, i.e. pmap->pm_pp2d[pp2d_idx] * */811812cmpdi %r25, 0813beq 2f814815rldicl %r21, %r31, (64 - PDIR_L), (64 - PDIR_NUM) /* pdir offset */816slwi %r21, %r21, PDIR_ENTRY_SHIFT /* multiply by pdir entry size */817ldx %r25, %r25, %r21 /* get ptbl address, i.e. pmap->pm_pp2d[pp2d_idx][pdir_idx] */818819cmpdi %r25, 0820beq 2f821822rldicl %r21, %r31, (64 - PTBL_L), (64 - PTBL_NUM) /* ptbl offset */823slwi %r21, %r21, PTBL_ENTRY_SHIFT /* multiply by pte entry size */824825#else826srwi %r21, %r31, PDIR_SHIFT /* pdir offset */827slwi %r21, %r21, PDIR_ENTRY_SHIFT /* multiply by pdir entry size */828829lwz %r25, PM_PDIR(%r26) /* pmap pm_dir[] address */830/*831* Get ptbl address, i.e. pmap->pm_pdir[pdir_idx]832* This load may cause a Data TLB miss for non-kernel pmap!833*/834lwzx %r25, %r25, %r21 /* offset within pm_pdir[] table */835cmpwi %r25, 0836beq 2f837838lis %r21, PTBL_MASK@h839ori %r21, %r21, PTBL_MASK@l840and %r21, %r21, %r31841842/* ptbl offset, multiply by ptbl entry size */843srwi %r21, %r21, (PTBL_SHIFT - PTBL_ENTRY_SHIFT)844#endif845846add %r25, %r25, %r21 /* address of pte entry */847/*848* Get pte->flags849* This load may cause a Data TLB miss for non-kernel pmap!850*/851lwz %r21, PTE_FLAGS(%r25)852andi. %r21, %r21, PTE_VALID@l853bne 2f8541:855li %r25, 08562:857blr858859/*****************************************************************************860*861* Load MAS1-MAS3 registers with data, write TLB entry862*863* input:864* r29 - mas0865* r28 - mas1866* r27 - mas2867* r25 - pte868*869* output: none870*871* scratch regs: r21-r23872*873****************************************************************************/874tlb_fill_entry:875/*876* Update PTE flags: we have to do it atomically, as pmap_protect()877* running on other CPUs could attempt to update the flags at the same878* time.879*/880li %r23, PTE_FLAGS8811:882lwarx %r21, %r23, %r25 /* get pte->flags */883oris %r21, %r21, PTE_REFERENCED@h /* set referenced bit */884885andi. %r22, %r21, (PTE_SW | PTE_UW)@l /* check if writable */886beq 2f887ori %r21, %r21, PTE_MODIFIED@l /* set modified bit */8882:889stwcx. %r21, %r23, %r25 /* write it back */890bne- 1b891892/* Update MAS2. */893rlwimi %r27, %r21, 13, 27, 30 /* insert WIMG bits from pte */894895/* Setup MAS3 value in r23. */896LOAD %r23, PTE_RPN(%r25) /* get pte->rpn */897#ifdef __powerpc64__898rldicr %r22, %r23, 52, 51 /* extract MAS3 portion of RPN */899rldicl %r23, %r23, 20, 54 /* extract MAS7 portion of RPN */900901rlwimi %r22, %r21, 30, 26, 31 /* insert protection bits from pte */902#else903rlwinm %r22, %r23, 20, 0, 11 /* extract MAS3 portion of RPN */904905rlwimi %r22, %r21, 30, 26, 31 /* insert protection bits from pte */906rlwimi %r22, %r21, 20, 12, 19 /* insert lower 8 RPN bits to MAS3 */907rlwinm %r23, %r23, 20, 24, 31 /* MAS7 portion of RPN */908#endif909910/* Load MAS registers. */911mtspr SPR_MAS0, %r29912mtspr SPR_MAS1, %r28913mtspr SPR_MAS2, %r27914mtspr SPR_MAS3, %r22915mtspr SPR_MAS7, %r23916917isync918tlbwe919isync920msync921blr922923/*****************************************************************************924* Instruction TLB miss interrupt925*926* Same notes as for the Data TLB miss927****************************************************************************/928INTERRUPT(int_inst_tlb_error)929TLB_PROLOG930TLB_LOCK931932mfsrr0 %r31 /* faulting address */933934/*935* Save MAS0-MAS2 registers. There might be another tlb miss during pte936* lookup overwriting current contents (which was hw filled).937*/938mfspr %r29, SPR_MAS0939mfspr %r28, SPR_MAS1940mfspr %r27, SPR_MAS2941942mfsrr1 %r21943mtcr %r21944945/* check MSR[PR] */946bt 17, search_user_pmap947b search_kernel_pmap948949950.globl interrupt_vector_top951interrupt_vector_top:952953/*****************************************************************************954* Debug interrupt955****************************************************************************/956INTERRUPT(int_debug)957STANDARD_CRIT_PROLOG(SPR_SPRG2, PC_BOOKE_CRITSAVE, SPR_CSRR0, SPR_CSRR1)958FRAME_SETUP(SPR_SPRG2, PC_BOOKE_CRITSAVE, EXC_DEBUG)959bl int_debug_int960FRAME_LEAVE(SPR_CSRR0, SPR_CSRR1)961rfci962963INTERRUPT(int_debug_ed)964STANDARD_CRIT_PROLOG(SPR_SPRG2, PC_BOOKE_CRITSAVE, SPR_DSRR0, SPR_DSRR1)965FRAME_SETUP(SPR_SPRG2, PC_BOOKE_CRITSAVE, EXC_DEBUG)966bl int_debug_int967FRAME_LEAVE(SPR_DSRR0, SPR_DSRR1)968rfdi969/* .long 0x4c00004e */970971/* Internal helper for debug interrupt handling. */972/* Common code between e500v1/v2 and e500mc-based cores. */973int_debug_int:974mflr %r14975GET_CPUINFO(%r3)976LOAD %r3, (PC_BOOKE_CRITSAVE+CPUSAVE_SRR0)(%r3)977bl 0f978ADDR(interrupt_vector_base-.)979ADDR(interrupt_vector_top-.)9800: mflr %r5981LOAD %r4,0(%r5) /* interrupt_vector_base in r4 */982add %r4,%r4,%r5983CMPL cr0, %r3, %r4984blt trap_common985LOAD %r4,WORD_SIZE(%r5) /* interrupt_vector_top in r4 */986add %r4,%r4,%r5987addi %r4,%r4,4988CMPL cr0, %r3, %r4989bge trap_common990/* Disable single-stepping for the interrupt handlers. */991LOAD %r3, FRAME_SRR1+CALLSIZE(%r1);992rlwinm %r3, %r3, 0, 23, 21993STORE %r3, FRAME_SRR1+CALLSIZE(%r1);994/* Restore srr0 and srr1 as they could have been clobbered. */995GET_CPUINFO(%r4)996LOAD %r3, (PC_BOOKE_CRITSAVE+BOOKE_CRITSAVE_SRR0)(%r4);997mtspr SPR_SRR0, %r3998LOAD %r4, (PC_BOOKE_CRITSAVE+BOOKE_CRITSAVE_SRR1)(%r4);999mtspr SPR_SRR1, %r41000mtlr %r141001blr10021003/*****************************************************************************1004* Common trap code1005****************************************************************************/1006trap_common:1007/* Call C trap dispatcher */1008GET_TOCBASE(%r2)1009addi %r3, %r1, CALLSIZE1010bl CNAME(powerpc_interrupt)1011TOC_RESTORE10121013.globl CNAME(trapexit) /* exported for db_backtrace use */1014CNAME(trapexit):1015/* disable interrupts */1016wrteei 010171018/* Test AST pending - makes sense for user process only */1019LOAD %r5, FRAME_SRR1+CALLSIZE(%r1)1020mtcr %r51021bf 17, 1f10221023GET_CPUINFO(%r3)1024LOAD %r4, PC_CURTHREAD(%r3)1025lwz %r4, TD_AST(%r4)1026cmpwi %r4, 01027beq 1f10281029/* re-enable interrupts before calling ast() */1030wrteei 110311032addi %r3, %r1, CALLSIZE1033bl CNAME(ast)1034TOC_RESTORE1035.globl CNAME(asttrapexit) /* db_backtrace code sentinel #2 */1036CNAME(asttrapexit):1037b trapexit /* test ast ret value ? */10381:1039FRAME_LEAVE(SPR_SRR0, SPR_SRR1)1040rfi104110421043#if defined(KDB)1044/*1045* Deliberate entry to dbtrap1046*/1047/* .globl CNAME(breakpoint)*/1048ASENTRY_NOPROF(breakpoint)1049mtsprg1 %r11050mfmsr %r31051mtsrr1 %r31052li %r4, ~(PSL_EE | PSL_ME)@l1053oris %r4, %r4, ~(PSL_EE | PSL_ME)@h1054and %r3, %r3, %r41055mtmsr %r3 /* disable interrupts */1056isync1057GET_CPUINFO(%r3)1058STORE %r30, (PC_DBSAVE+CPUSAVE_R30)(%r3)1059STORE %r31, (PC_DBSAVE+CPUSAVE_R31)(%r3)10601061mflr %r311062mtsrr0 %r3110631064mfspr %r30, SPR_DEAR1065mfspr %r31, SPR_ESR1066STORE %r30, (PC_DBSAVE+CPUSAVE_BOOKE_DEAR)(%r3)1067STORE %r31, (PC_DBSAVE+CPUSAVE_BOOKE_ESR)(%r3)10681069mfsrr0 %r301070mfsrr1 %r311071STORE %r30, (PC_DBSAVE+CPUSAVE_SRR0)(%r3)1072STORE %r31, (PC_DBSAVE+CPUSAVE_SRR1)(%r3)1073isync10741075mfcr %r3010761077/*1078* Now the kdb trap catching code.1079*/1080dbtrap:1081FRAME_SETUP(SPR_SPRG1, PC_DBSAVE, EXC_DEBUG)1082/* Call C trap code: */1083GET_TOCBASE(%r2)1084addi %r3, %r1, CALLSIZE1085bl CNAME(db_trap_glue)1086TOC_RESTORE1087or. %r3, %r3, %r31088bne dbleave1089/* This wasn't for KDB, so switch to real trap: */1090b trap_common10911092dbleave:1093FRAME_LEAVE(SPR_SRR0, SPR_SRR1)1094rfi1095ASEND(breakpoint)1096#endif /* KDB */10971098#ifdef SMP1099ENTRY(tlb_lock)1100GET_CPUINFO(%r5)1101LOAD %r5, PC_CURTHREAD(%r5)11021: LOADX %r4, 0, %r31103CMPI %r4, TLB_UNLOCKED1104bne 1b1105STOREX %r5, 0, %r31106bne- 1b1107isync1108msync1109blr1110END(tlb_lock)11111112ENTRY(tlb_unlock)1113isync1114msync1115li %r4, TLB_UNLOCKED1116STORE %r4, 0(%r3)1117isync1118msync1119blr1120END(tlb_unlock)11211122/*1123* TLB miss spin locks. For each CPU we have a reservation granule (32 bytes);1124* only a single word from this granule will actually be used as a spin lock1125* for mutual exclusion between TLB miss handler and pmap layer that1126* manipulates page table contents.1127*/1128.data1129.align 51130GLOBAL(tlb0_miss_locks)1131.space RES_GRANULE * MAXCPU1132#endif113311341135