Path: blob/master/arch/powerpc/kernel/exceptions-64e.S
10817 views
/*1* Boot code and exception vectors for Book3E processors2*3* Copyright (C) 2007 Ben. Herrenschmidt ([email protected]), IBM Corp.4*5* This program is free software; you can redistribute it and/or6* modify it under the terms of the GNU General Public License7* as published by the Free Software Foundation; either version8* 2 of the License, or (at your option) any later version.9*/1011#include <linux/threads.h>12#include <asm/reg.h>13#include <asm/page.h>14#include <asm/ppc_asm.h>15#include <asm/asm-offsets.h>16#include <asm/cputable.h>17#include <asm/setup.h>18#include <asm/thread_info.h>19#include <asm/reg_a2.h>20#include <asm/exception-64e.h>21#include <asm/bug.h>22#include <asm/irqflags.h>23#include <asm/ptrace.h>24#include <asm/ppc-opcode.h>25#include <asm/mmu.h>2627/* XXX This will ultimately add space for a special exception save28* structure used to save things like SRR0/SRR1, SPRGs, MAS, etc...29* when taking special interrupts. For now we don't support that,30* special interrupts from within a non-standard level will probably31* blow you up32*/33#define SPECIAL_EXC_FRAME_SIZE INT_FRAME_SIZE3435/* Exception prolog code for all exceptions */36#define EXCEPTION_PROLOG(n, type, addition) \37mtspr SPRN_SPRG_##type##_SCRATCH,r13; /* get spare registers */ \38mfspr r13,SPRN_SPRG_PACA; /* get PACA */ \39std r10,PACA_EX##type+EX_R10(r13); \40std r11,PACA_EX##type+EX_R11(r13); \41mfcr r10; /* save CR */ \42addition; /* additional code for that exc. */ \43std r1,PACA_EX##type+EX_R1(r13); /* save old r1 in the PACA */ \44stw r10,PACA_EX##type+EX_CR(r13); /* save old CR in the PACA */ \45mfspr r11,SPRN_##type##_SRR1;/* what are we coming from */ \46type##_SET_KSTACK; /* get special stack if necessary */\47andi. r10,r11,MSR_PR; /* save stack pointer */ \48beq 1f; /* branch around if supervisor */ \49ld r1,PACAKSAVE(r13); /* get kernel stack coming from usr */\501: cmpdi cr1,r1,0; /* check if SP makes sense */ \51bge- cr1,exc_##n##_bad_stack;/* bad stack (TODO: out of line) */ \52mfspr r10,SPRN_##type##_SRR0; /* read SRR0 before touching stack */5354/* Exception type-specific macros */55#define GEN_SET_KSTACK \56subi r1,r1,INT_FRAME_SIZE; /* alloc frame on kernel stack */57#define SPRN_GEN_SRR0 SPRN_SRR058#define SPRN_GEN_SRR1 SPRN_SRR15960#define CRIT_SET_KSTACK \61ld r1,PACA_CRIT_STACK(r13); \62subi r1,r1,SPECIAL_EXC_FRAME_SIZE;63#define SPRN_CRIT_SRR0 SPRN_CSRR064#define SPRN_CRIT_SRR1 SPRN_CSRR16566#define DBG_SET_KSTACK \67ld r1,PACA_DBG_STACK(r13); \68subi r1,r1,SPECIAL_EXC_FRAME_SIZE;69#define SPRN_DBG_SRR0 SPRN_DSRR070#define SPRN_DBG_SRR1 SPRN_DSRR17172#define MC_SET_KSTACK \73ld r1,PACA_MC_STACK(r13); \74subi r1,r1,SPECIAL_EXC_FRAME_SIZE;75#define SPRN_MC_SRR0 SPRN_MCSRR076#define SPRN_MC_SRR1 SPRN_MCSRR17778#define NORMAL_EXCEPTION_PROLOG(n, addition) \79EXCEPTION_PROLOG(n, GEN, addition##_GEN)8081#define CRIT_EXCEPTION_PROLOG(n, addition) \82EXCEPTION_PROLOG(n, CRIT, addition##_CRIT)8384#define DBG_EXCEPTION_PROLOG(n, addition) \85EXCEPTION_PROLOG(n, DBG, addition##_DBG)8687#define MC_EXCEPTION_PROLOG(n, addition) \88EXCEPTION_PROLOG(n, MC, addition##_MC)899091/* Variants of the "addition" argument for the prolog92*/93#define PROLOG_ADDITION_NONE_GEN94#define PROLOG_ADDITION_NONE_CRIT95#define PROLOG_ADDITION_NONE_DBG96#define PROLOG_ADDITION_NONE_MC9798#define PROLOG_ADDITION_MASKABLE_GEN \99lbz r11,PACASOFTIRQEN(r13); /* are irqs soft-disabled ? */ \100cmpwi cr0,r11,0; /* yes -> go out of line */ \101beq masked_interrupt_book3e;102103#define PROLOG_ADDITION_2REGS_GEN \104std r14,PACA_EXGEN+EX_R14(r13); \105std r15,PACA_EXGEN+EX_R15(r13)106107#define PROLOG_ADDITION_1REG_GEN \108std r14,PACA_EXGEN+EX_R14(r13);109110#define PROLOG_ADDITION_2REGS_CRIT \111std r14,PACA_EXCRIT+EX_R14(r13); \112std r15,PACA_EXCRIT+EX_R15(r13)113114#define PROLOG_ADDITION_2REGS_DBG \115std r14,PACA_EXDBG+EX_R14(r13); \116std r15,PACA_EXDBG+EX_R15(r13)117118#define PROLOG_ADDITION_2REGS_MC \119std r14,PACA_EXMC+EX_R14(r13); \120std r15,PACA_EXMC+EX_R15(r13)121122/* Core exception code for all exceptions except TLB misses.123* XXX: Needs to make SPRN_SPRG_GEN depend on exception type124*/125#define EXCEPTION_COMMON(n, excf, ints) \126std r0,GPR0(r1); /* save r0 in stackframe */ \127std r2,GPR2(r1); /* save r2 in stackframe */ \128SAVE_4GPRS(3, r1); /* save r3 - r6 in stackframe */ \129SAVE_2GPRS(7, r1); /* save r7, r8 in stackframe */ \130std r9,GPR9(r1); /* save r9 in stackframe */ \131std r10,_NIP(r1); /* save SRR0 to stackframe */ \132std r11,_MSR(r1); /* save SRR1 to stackframe */ \133ACCOUNT_CPU_USER_ENTRY(r10,r11);/* accounting (uses cr0+eq) */ \134ld r3,excf+EX_R10(r13); /* get back r10 */ \135ld r4,excf+EX_R11(r13); /* get back r11 */ \136mfspr r5,SPRN_SPRG_GEN_SCRATCH;/* get back r13 */ \137std r12,GPR12(r1); /* save r12 in stackframe */ \138ld r2,PACATOC(r13); /* get kernel TOC into r2 */ \139mflr r6; /* save LR in stackframe */ \140mfctr r7; /* save CTR in stackframe */ \141mfspr r8,SPRN_XER; /* save XER in stackframe */ \142ld r9,excf+EX_R1(r13); /* load orig r1 back from PACA */ \143lwz r10,excf+EX_CR(r13); /* load orig CR back from PACA */ \144lbz r11,PACASOFTIRQEN(r13); /* get current IRQ softe */ \145ld r12,exception_marker@toc(r2); \146li r0,0; \147std r3,GPR10(r1); /* save r10 to stackframe */ \148std r4,GPR11(r1); /* save r11 to stackframe */ \149std r5,GPR13(r1); /* save it to stackframe */ \150std r6,_LINK(r1); \151std r7,_CTR(r1); \152std r8,_XER(r1); \153li r3,(n)+1; /* indicate partial regs in trap */ \154std r9,0(r1); /* store stack frame back link */ \155std r10,_CCR(r1); /* store orig CR in stackframe */ \156std r9,GPR1(r1); /* store stack frame back link */ \157std r11,SOFTE(r1); /* and save it to stackframe */ \158std r12,STACK_FRAME_OVERHEAD-16(r1); /* mark the frame */ \159std r3,_TRAP(r1); /* set trap number */ \160std r0,RESULT(r1); /* clear regs->result */ \161ints;162163/* Variants for the "ints" argument */164#define INTS_KEEP165#define INTS_DISABLE_SOFT \166stb r0,PACASOFTIRQEN(r13); /* mark interrupts soft-disabled */ \167TRACE_DISABLE_INTS;168#define INTS_DISABLE_HARD \169stb r0,PACAHARDIRQEN(r13); /* and hard disabled */170#define INTS_DISABLE_ALL \171INTS_DISABLE_SOFT \172INTS_DISABLE_HARD173174/* This is called by exceptions that used INTS_KEEP (that is did not clear175* neither soft nor hard IRQ indicators in the PACA. This will restore MSR:EE176* to it's previous value177*178* XXX In the long run, we may want to open-code it in order to separate the179* load from the wrtee, thus limiting the latency caused by the dependency180* but at this point, I'll favor code clarity until we have a near to final181* implementation182*/183#define INTS_RESTORE_HARD \184ld r11,_MSR(r1); \185wrtee r11;186187/* XXX FIXME: Restore r14/r15 when necessary */188#define BAD_STACK_TRAMPOLINE(n) \189exc_##n##_bad_stack: \190li r1,(n); /* get exception number */ \191sth r1,PACA_TRAP_SAVE(r13); /* store trap */ \192b bad_stack_book3e; /* bad stack error */193194/* WARNING: If you change the layout of this stub, make sure you chcek195* the debug exception handler which handles single stepping196* into exceptions from userspace, and the MM code in197* arch/powerpc/mm/tlb_nohash.c which patches the branch here198* and would need to be updated if that branch is moved199*/200#define EXCEPTION_STUB(loc, label) \201. = interrupt_base_book3e + loc; \202nop; /* To make debug interrupts happy */ \203b exc_##label##_book3e;204205#define ACK_NONE(r)206#define ACK_DEC(r) \207lis r,TSR_DIS@h; \208mtspr SPRN_TSR,r209#define ACK_FIT(r) \210lis r,TSR_FIS@h; \211mtspr SPRN_TSR,r212213/* Used by asynchronous interrupt that may happen in the idle loop.214*215* This check if the thread was in the idle loop, and if yes, returns216* to the caller rather than the PC. This is to avoid a race if217* interrupts happen before the wait instruction.218*/219#define CHECK_NAPPING() \220clrrdi r11,r1,THREAD_SHIFT; \221ld r10,TI_LOCAL_FLAGS(r11); \222andi. r9,r10,_TLF_NAPPING; \223beq+ 1f; \224ld r8,_LINK(r1); \225rlwinm r7,r10,0,~_TLF_NAPPING; \226std r8,_NIP(r1); \227std r7,TI_LOCAL_FLAGS(r11); \2281:229230231#define MASKABLE_EXCEPTION(trapnum, label, hdlr, ack) \232START_EXCEPTION(label); \233NORMAL_EXCEPTION_PROLOG(trapnum, PROLOG_ADDITION_MASKABLE) \234EXCEPTION_COMMON(trapnum, PACA_EXGEN, INTS_DISABLE_ALL) \235ack(r8); \236CHECK_NAPPING(); \237addi r3,r1,STACK_FRAME_OVERHEAD; \238bl hdlr; \239b .ret_from_except_lite;240241/* This value is used to mark exception frames on the stack. */242.section ".toc","aw"243exception_marker:244.tc ID_EXC_MARKER[TC],STACK_FRAME_REGS_MARKER245246247/*248* And here we have the exception vectors !249*/250251.text252.balign 0x1000253.globl interrupt_base_book3e254interrupt_base_book3e: /* fake trap */255EXCEPTION_STUB(0x000, machine_check) /* 0x0200 */256EXCEPTION_STUB(0x020, critical_input) /* 0x0580 */257EXCEPTION_STUB(0x040, debug_crit) /* 0x0d00 */258EXCEPTION_STUB(0x060, data_storage) /* 0x0300 */259EXCEPTION_STUB(0x080, instruction_storage) /* 0x0400 */260EXCEPTION_STUB(0x0a0, external_input) /* 0x0500 */261EXCEPTION_STUB(0x0c0, alignment) /* 0x0600 */262EXCEPTION_STUB(0x0e0, program) /* 0x0700 */263EXCEPTION_STUB(0x100, fp_unavailable) /* 0x0800 */264EXCEPTION_STUB(0x120, system_call) /* 0x0c00 */265EXCEPTION_STUB(0x140, ap_unavailable) /* 0x0f20 */266EXCEPTION_STUB(0x160, decrementer) /* 0x0900 */267EXCEPTION_STUB(0x180, fixed_interval) /* 0x0980 */268EXCEPTION_STUB(0x1a0, watchdog) /* 0x09f0 */269EXCEPTION_STUB(0x1c0, data_tlb_miss)270EXCEPTION_STUB(0x1e0, instruction_tlb_miss)271EXCEPTION_STUB(0x260, perfmon)272EXCEPTION_STUB(0x280, doorbell)273EXCEPTION_STUB(0x2a0, doorbell_crit)274EXCEPTION_STUB(0x2c0, guest_doorbell)275EXCEPTION_STUB(0x2e0, guest_doorbell_crit)276EXCEPTION_STUB(0x300, hypercall)277EXCEPTION_STUB(0x320, ehpriv)278279.globl interrupt_end_book3e280interrupt_end_book3e:281282/* Critical Input Interrupt */283START_EXCEPTION(critical_input);284CRIT_EXCEPTION_PROLOG(0x100, PROLOG_ADDITION_NONE)285// EXCEPTION_COMMON(0x100, PACA_EXCRIT, INTS_DISABLE_ALL)286// bl special_reg_save_crit287// CHECK_NAPPING();288// addi r3,r1,STACK_FRAME_OVERHEAD289// bl .critical_exception290// b ret_from_crit_except291b .292293/* Machine Check Interrupt */294START_EXCEPTION(machine_check);295CRIT_EXCEPTION_PROLOG(0x200, PROLOG_ADDITION_NONE)296// EXCEPTION_COMMON(0x200, PACA_EXMC, INTS_DISABLE_ALL)297// bl special_reg_save_mc298// addi r3,r1,STACK_FRAME_OVERHEAD299// CHECK_NAPPING();300// bl .machine_check_exception301// b ret_from_mc_except302b .303304/* Data Storage Interrupt */305START_EXCEPTION(data_storage)306NORMAL_EXCEPTION_PROLOG(0x300, PROLOG_ADDITION_2REGS)307mfspr r14,SPRN_DEAR308mfspr r15,SPRN_ESR309EXCEPTION_COMMON(0x300, PACA_EXGEN, INTS_KEEP)310b storage_fault_common311312/* Instruction Storage Interrupt */313START_EXCEPTION(instruction_storage);314NORMAL_EXCEPTION_PROLOG(0x400, PROLOG_ADDITION_2REGS)315li r15,0316mr r14,r10317EXCEPTION_COMMON(0x400, PACA_EXGEN, INTS_KEEP)318b storage_fault_common319320/* External Input Interrupt */321MASKABLE_EXCEPTION(0x500, external_input, .do_IRQ, ACK_NONE)322323/* Alignment */324START_EXCEPTION(alignment);325NORMAL_EXCEPTION_PROLOG(0x600, PROLOG_ADDITION_2REGS)326mfspr r14,SPRN_DEAR327mfspr r15,SPRN_ESR328EXCEPTION_COMMON(0x600, PACA_EXGEN, INTS_KEEP)329b alignment_more /* no room, go out of line */330331/* Program Interrupt */332START_EXCEPTION(program);333NORMAL_EXCEPTION_PROLOG(0x700, PROLOG_ADDITION_1REG)334mfspr r14,SPRN_ESR335EXCEPTION_COMMON(0x700, PACA_EXGEN, INTS_DISABLE_SOFT)336std r14,_DSISR(r1)337addi r3,r1,STACK_FRAME_OVERHEAD338ld r14,PACA_EXGEN+EX_R14(r13)339bl .save_nvgprs340INTS_RESTORE_HARD341bl .program_check_exception342b .ret_from_except343344/* Floating Point Unavailable Interrupt */345START_EXCEPTION(fp_unavailable);346NORMAL_EXCEPTION_PROLOG(0x800, PROLOG_ADDITION_NONE)347/* we can probably do a shorter exception entry for that one... */348EXCEPTION_COMMON(0x800, PACA_EXGEN, INTS_KEEP)349bne 1f /* if from user, just load it up */350bl .save_nvgprs351addi r3,r1,STACK_FRAME_OVERHEAD352INTS_RESTORE_HARD353bl .kernel_fp_unavailable_exception354BUG_OPCODE3551: ld r12,_MSR(r1)356bl .load_up_fpu357b fast_exception_return358359/* Decrementer Interrupt */360MASKABLE_EXCEPTION(0x900, decrementer, .timer_interrupt, ACK_DEC)361362/* Fixed Interval Timer Interrupt */363MASKABLE_EXCEPTION(0x980, fixed_interval, .unknown_exception, ACK_FIT)364365/* Watchdog Timer Interrupt */366START_EXCEPTION(watchdog);367CRIT_EXCEPTION_PROLOG(0x9f0, PROLOG_ADDITION_NONE)368// EXCEPTION_COMMON(0x9f0, PACA_EXCRIT, INTS_DISABLE_ALL)369// bl special_reg_save_crit370// CHECK_NAPPING();371// addi r3,r1,STACK_FRAME_OVERHEAD372// bl .unknown_exception373// b ret_from_crit_except374b .375376/* System Call Interrupt */377START_EXCEPTION(system_call)378mr r9,r13 /* keep a copy of userland r13 */379mfspr r11,SPRN_SRR0 /* get return address */380mfspr r12,SPRN_SRR1 /* get previous MSR */381mfspr r13,SPRN_SPRG_PACA /* get our PACA */382b system_call_common383384/* Auxiliary Processor Unavailable Interrupt */385START_EXCEPTION(ap_unavailable);386NORMAL_EXCEPTION_PROLOG(0xf20, PROLOG_ADDITION_NONE)387EXCEPTION_COMMON(0xf20, PACA_EXGEN, INTS_KEEP)388addi r3,r1,STACK_FRAME_OVERHEAD389bl .save_nvgprs390INTS_RESTORE_HARD391bl .unknown_exception392b .ret_from_except393394/* Debug exception as a critical interrupt*/395START_EXCEPTION(debug_crit);396CRIT_EXCEPTION_PROLOG(0xd00, PROLOG_ADDITION_2REGS)397398/*399* If there is a single step or branch-taken exception in an400* exception entry sequence, it was probably meant to apply to401* the code where the exception occurred (since exception entry402* doesn't turn off DE automatically). We simulate the effect403* of turning off DE on entry to an exception handler by turning404* off DE in the CSRR1 value and clearing the debug status.405*/406407mfspr r14,SPRN_DBSR /* check single-step/branch taken */408andis. r15,r14,DBSR_IC@h409beq+ 1f410411LOAD_REG_IMMEDIATE(r14,interrupt_base_book3e)412LOAD_REG_IMMEDIATE(r15,interrupt_end_book3e)413cmpld cr0,r10,r14414cmpld cr1,r10,r15415blt+ cr0,1f416bge+ cr1,1f417418/* here it looks like we got an inappropriate debug exception. */419lis r14,DBSR_IC@h /* clear the IC event */420rlwinm r11,r11,0,~MSR_DE /* clear DE in the CSRR1 value */421mtspr SPRN_DBSR,r14422mtspr SPRN_CSRR1,r11423lwz r10,PACA_EXCRIT+EX_CR(r13) /* restore registers */424ld r1,PACA_EXCRIT+EX_R1(r13)425ld r14,PACA_EXCRIT+EX_R14(r13)426ld r15,PACA_EXCRIT+EX_R15(r13)427mtcr r10428ld r10,PACA_EXCRIT+EX_R10(r13) /* restore registers */429ld r11,PACA_EXCRIT+EX_R11(r13)430mfspr r13,SPRN_SPRG_CRIT_SCRATCH431rfci432433/* Normal debug exception */434/* XXX We only handle coming from userspace for now since we can't435* quite save properly an interrupted kernel state yet436*/4371: andi. r14,r11,MSR_PR; /* check for userspace again */438beq kernel_dbg_exc; /* if from kernel mode */439440/* Now we mash up things to make it look like we are coming on a441* normal exception442*/443mfspr r15,SPRN_SPRG_CRIT_SCRATCH444mtspr SPRN_SPRG_GEN_SCRATCH,r15445mfspr r14,SPRN_DBSR446EXCEPTION_COMMON(0xd00, PACA_EXCRIT, INTS_DISABLE_ALL)447std r14,_DSISR(r1)448addi r3,r1,STACK_FRAME_OVERHEAD449mr r4,r14450ld r14,PACA_EXCRIT+EX_R14(r13)451ld r15,PACA_EXCRIT+EX_R15(r13)452bl .save_nvgprs453bl .DebugException454b .ret_from_except455456kernel_dbg_exc:457b . /* NYI */458459/* Debug exception as a debug interrupt*/460START_EXCEPTION(debug_debug);461DBG_EXCEPTION_PROLOG(0xd00, PROLOG_ADDITION_2REGS)462463/*464* If there is a single step or branch-taken exception in an465* exception entry sequence, it was probably meant to apply to466* the code where the exception occurred (since exception entry467* doesn't turn off DE automatically). We simulate the effect468* of turning off DE on entry to an exception handler by turning469* off DE in the DSRR1 value and clearing the debug status.470*/471472mfspr r14,SPRN_DBSR /* check single-step/branch taken */473andis. r15,r14,DBSR_IC@h474beq+ 1f475476LOAD_REG_IMMEDIATE(r14,interrupt_base_book3e)477LOAD_REG_IMMEDIATE(r15,interrupt_end_book3e)478cmpld cr0,r10,r14479cmpld cr1,r10,r15480blt+ cr0,1f481bge+ cr1,1f482483/* here it looks like we got an inappropriate debug exception. */484lis r14,DBSR_IC@h /* clear the IC event */485rlwinm r11,r11,0,~MSR_DE /* clear DE in the DSRR1 value */486mtspr SPRN_DBSR,r14487mtspr SPRN_DSRR1,r11488lwz r10,PACA_EXDBG+EX_CR(r13) /* restore registers */489ld r1,PACA_EXDBG+EX_R1(r13)490ld r14,PACA_EXDBG+EX_R14(r13)491ld r15,PACA_EXDBG+EX_R15(r13)492mtcr r10493ld r10,PACA_EXDBG+EX_R10(r13) /* restore registers */494ld r11,PACA_EXDBG+EX_R11(r13)495mfspr r13,SPRN_SPRG_DBG_SCRATCH496rfdi497498/* Normal debug exception */499/* XXX We only handle coming from userspace for now since we can't500* quite save properly an interrupted kernel state yet501*/5021: andi. r14,r11,MSR_PR; /* check for userspace again */503beq kernel_dbg_exc; /* if from kernel mode */504505/* Now we mash up things to make it look like we are coming on a506* normal exception507*/508mfspr r15,SPRN_SPRG_DBG_SCRATCH509mtspr SPRN_SPRG_GEN_SCRATCH,r15510mfspr r14,SPRN_DBSR511EXCEPTION_COMMON(0xd00, PACA_EXDBG, INTS_DISABLE_ALL)512std r14,_DSISR(r1)513addi r3,r1,STACK_FRAME_OVERHEAD514mr r4,r14515ld r14,PACA_EXDBG+EX_R14(r13)516ld r15,PACA_EXDBG+EX_R15(r13)517bl .save_nvgprs518bl .DebugException519b .ret_from_except520521MASKABLE_EXCEPTION(0x260, perfmon, .performance_monitor_exception, ACK_NONE)522523/* Doorbell interrupt */524MASKABLE_EXCEPTION(0x2070, doorbell, .doorbell_exception, ACK_NONE)525526/* Doorbell critical Interrupt */527START_EXCEPTION(doorbell_crit);528CRIT_EXCEPTION_PROLOG(0x2080, PROLOG_ADDITION_NONE)529// EXCEPTION_COMMON(0x2080, PACA_EXCRIT, INTS_DISABLE_ALL)530// bl special_reg_save_crit531// CHECK_NAPPING();532// addi r3,r1,STACK_FRAME_OVERHEAD533// bl .doorbell_critical_exception534// b ret_from_crit_except535b .536537MASKABLE_EXCEPTION(0x2c0, guest_doorbell, .unknown_exception, ACK_NONE)538MASKABLE_EXCEPTION(0x2e0, guest_doorbell_crit, .unknown_exception, ACK_NONE)539MASKABLE_EXCEPTION(0x310, hypercall, .unknown_exception, ACK_NONE)540MASKABLE_EXCEPTION(0x320, ehpriv, .unknown_exception, ACK_NONE)541542543/*544* An interrupt came in while soft-disabled; clear EE in SRR1,545* clear paca->hard_enabled and return.546*/547masked_interrupt_book3e:548mtcr r10549stb r11,PACAHARDIRQEN(r13)550mfspr r10,SPRN_SRR1551rldicl r11,r10,48,1 /* clear MSR_EE */552rotldi r10,r11,16553mtspr SPRN_SRR1,r10554ld r10,PACA_EXGEN+EX_R10(r13); /* restore registers */555ld r11,PACA_EXGEN+EX_R11(r13);556mfspr r13,SPRN_SPRG_GEN_SCRATCH;557rfi558b .559560/*561* This is called from 0x300 and 0x400 handlers after the prologs with562* r14 and r15 containing the fault address and error code, with the563* original values stashed away in the PACA564*/565storage_fault_common:566std r14,_DAR(r1)567std r15,_DSISR(r1)568addi r3,r1,STACK_FRAME_OVERHEAD569mr r4,r14570mr r5,r15571ld r14,PACA_EXGEN+EX_R14(r13)572ld r15,PACA_EXGEN+EX_R15(r13)573INTS_RESTORE_HARD574bl .do_page_fault575cmpdi r3,0576bne- 1f577b .ret_from_except_lite5781: bl .save_nvgprs579mr r5,r3580addi r3,r1,STACK_FRAME_OVERHEAD581ld r4,_DAR(r1)582bl .bad_page_fault583b .ret_from_except584585/*586* Alignment exception doesn't fit entirely in the 0x100 bytes so it587* continues here.588*/589alignment_more:590std r14,_DAR(r1)591std r15,_DSISR(r1)592addi r3,r1,STACK_FRAME_OVERHEAD593ld r14,PACA_EXGEN+EX_R14(r13)594ld r15,PACA_EXGEN+EX_R15(r13)595bl .save_nvgprs596INTS_RESTORE_HARD597bl .alignment_exception598b .ret_from_except599600/*601* We branch here from entry_64.S for the last stage of the exception602* return code path. MSR:EE is expected to be off at that point603*/604_GLOBAL(exception_return_book3e)605b 1f606607/* This is the return from load_up_fpu fast path which could do with608* less GPR restores in fact, but for now we have a single return path609*/610.globl fast_exception_return611fast_exception_return:612wrteei 06131: mr r0,r13614ld r10,_MSR(r1)615REST_4GPRS(2, r1)616andi. r6,r10,MSR_PR617REST_2GPRS(6, r1)618beq 1f619ACCOUNT_CPU_USER_EXIT(r10, r11)620ld r0,GPR13(r1)6216221: stdcx. r0,0,r1 /* to clear the reservation */623624ld r8,_CCR(r1)625ld r9,_LINK(r1)626ld r10,_CTR(r1)627ld r11,_XER(r1)628mtcr r8629mtlr r9630mtctr r10631mtxer r11632REST_2GPRS(8, r1)633ld r10,GPR10(r1)634ld r11,GPR11(r1)635ld r12,GPR12(r1)636mtspr SPRN_SPRG_GEN_SCRATCH,r0637638std r10,PACA_EXGEN+EX_R10(r13);639std r11,PACA_EXGEN+EX_R11(r13);640ld r10,_NIP(r1)641ld r11,_MSR(r1)642ld r0,GPR0(r1)643ld r1,GPR1(r1)644mtspr SPRN_SRR0,r10645mtspr SPRN_SRR1,r11646ld r10,PACA_EXGEN+EX_R10(r13)647ld r11,PACA_EXGEN+EX_R11(r13)648mfspr r13,SPRN_SPRG_GEN_SCRATCH649rfi650651/*652* Trampolines used when spotting a bad kernel stack pointer in653* the exception entry code.654*655* TODO: move some bits like SRR0 read to trampoline, pass PACA656* index around, etc... to handle crit & mcheck657*/658BAD_STACK_TRAMPOLINE(0x000)659BAD_STACK_TRAMPOLINE(0x100)660BAD_STACK_TRAMPOLINE(0x200)661BAD_STACK_TRAMPOLINE(0x260)662BAD_STACK_TRAMPOLINE(0x2c0)663BAD_STACK_TRAMPOLINE(0x2e0)664BAD_STACK_TRAMPOLINE(0x300)665BAD_STACK_TRAMPOLINE(0x310)666BAD_STACK_TRAMPOLINE(0x320)667BAD_STACK_TRAMPOLINE(0x400)668BAD_STACK_TRAMPOLINE(0x500)669BAD_STACK_TRAMPOLINE(0x600)670BAD_STACK_TRAMPOLINE(0x700)671BAD_STACK_TRAMPOLINE(0x800)672BAD_STACK_TRAMPOLINE(0x900)673BAD_STACK_TRAMPOLINE(0x980)674BAD_STACK_TRAMPOLINE(0x9f0)675BAD_STACK_TRAMPOLINE(0xa00)676BAD_STACK_TRAMPOLINE(0xb00)677BAD_STACK_TRAMPOLINE(0xc00)678BAD_STACK_TRAMPOLINE(0xd00)679BAD_STACK_TRAMPOLINE(0xe00)680BAD_STACK_TRAMPOLINE(0xf00)681BAD_STACK_TRAMPOLINE(0xf20)682BAD_STACK_TRAMPOLINE(0x2070)683BAD_STACK_TRAMPOLINE(0x2080)684685.globl bad_stack_book3e686bad_stack_book3e:687/* XXX: Needs to make SPRN_SPRG_GEN depend on exception type */688mfspr r10,SPRN_SRR0; /* read SRR0 before touching stack */689ld r1,PACAEMERGSP(r13)690subi r1,r1,64+INT_FRAME_SIZE691std r10,_NIP(r1)692std r11,_MSR(r1)693ld r10,PACA_EXGEN+EX_R1(r13) /* FIXME for crit & mcheck */694lwz r11,PACA_EXGEN+EX_CR(r13) /* FIXME for crit & mcheck */695std r10,GPR1(r1)696std r11,_CCR(r1)697mfspr r10,SPRN_DEAR698mfspr r11,SPRN_ESR699std r10,_DAR(r1)700std r11,_DSISR(r1)701std r0,GPR0(r1); /* save r0 in stackframe */ \702std r2,GPR2(r1); /* save r2 in stackframe */ \703SAVE_4GPRS(3, r1); /* save r3 - r6 in stackframe */ \704SAVE_2GPRS(7, r1); /* save r7, r8 in stackframe */ \705std r9,GPR9(r1); /* save r9 in stackframe */ \706ld r3,PACA_EXGEN+EX_R10(r13);/* get back r10 */ \707ld r4,PACA_EXGEN+EX_R11(r13);/* get back r11 */ \708mfspr r5,SPRN_SPRG_GEN_SCRATCH;/* get back r13 XXX can be wrong */ \709std r3,GPR10(r1); /* save r10 to stackframe */ \710std r4,GPR11(r1); /* save r11 to stackframe */ \711std r12,GPR12(r1); /* save r12 in stackframe */ \712std r5,GPR13(r1); /* save it to stackframe */ \713mflr r10714mfctr r11715mfxer r12716std r10,_LINK(r1)717std r11,_CTR(r1)718std r12,_XER(r1)719SAVE_10GPRS(14,r1)720SAVE_8GPRS(24,r1)721lhz r12,PACA_TRAP_SAVE(r13)722std r12,_TRAP(r1)723addi r11,r1,INT_FRAME_SIZE724std r11,0(r1)725li r12,0726std r12,0(r11)727ld r2,PACATOC(r13)7281: addi r3,r1,STACK_FRAME_OVERHEAD729bl .kernel_bad_stack730b 1b731732/*733* Setup the initial TLB for a core. This current implementation734* assume that whatever we are running off will not conflict with735* the new mapping at PAGE_OFFSET.736*/737_GLOBAL(initial_tlb_book3e)738739/* Look for the first TLB with IPROT set */740mfspr r4,SPRN_TLB0CFG741andi. r3,r4,TLBnCFG_IPROT742lis r3,MAS0_TLBSEL(0)@h743bne found_iprot744745mfspr r4,SPRN_TLB1CFG746andi. r3,r4,TLBnCFG_IPROT747lis r3,MAS0_TLBSEL(1)@h748bne found_iprot749750mfspr r4,SPRN_TLB2CFG751andi. r3,r4,TLBnCFG_IPROT752lis r3,MAS0_TLBSEL(2)@h753bne found_iprot754755lis r3,MAS0_TLBSEL(3)@h756mfspr r4,SPRN_TLB3CFG757/* fall through */758759found_iprot:760andi. r5,r4,TLBnCFG_HES761bne have_hes762763mflr r8 /* save LR */764/* 1. Find the index of the entry we're executing in765*766* r3 = MAS0_TLBSEL (for the iprot array)767* r4 = SPRN_TLBnCFG768*/769bl invstr /* Find our address */770invstr: mflr r6 /* Make it accessible */771mfmsr r7772rlwinm r5,r7,27,31,31 /* extract MSR[IS] */773mfspr r7,SPRN_PID774slwi r7,r7,16775or r7,r7,r5776mtspr SPRN_MAS6,r7777tlbsx 0,r6 /* search MSR[IS], SPID=PID */778779mfspr r3,SPRN_MAS0780rlwinm r5,r3,16,20,31 /* Extract MAS0(Entry) */781782mfspr r7,SPRN_MAS1 /* Insure IPROT set */783oris r7,r7,MAS1_IPROT@h784mtspr SPRN_MAS1,r7785tlbwe786787/* 2. Invalidate all entries except the entry we're executing in788*789* r3 = MAS0 w/TLBSEL & ESEL for the entry we are running in790* r4 = SPRN_TLBnCFG791* r5 = ESEL of entry we are running in792*/793andi. r4,r4,TLBnCFG_N_ENTRY /* Extract # entries */794li r6,0 /* Set Entry counter to 0 */7951: mr r7,r3 /* Set MAS0(TLBSEL) */796rlwimi r7,r6,16,4,15 /* Setup MAS0 = TLBSEL | ESEL(r6) */797mtspr SPRN_MAS0,r7798tlbre799mfspr r7,SPRN_MAS1800rlwinm r7,r7,0,2,31 /* Clear MAS1 Valid and IPROT */801cmpw r5,r6802beq skpinv /* Dont update the current execution TLB */803mtspr SPRN_MAS1,r7804tlbwe805isync806skpinv: addi r6,r6,1 /* Increment */807cmpw r6,r4 /* Are we done? */808bne 1b /* If not, repeat */809810/* Invalidate all TLBs */811PPC_TLBILX_ALL(0,0)812sync813isync814815/* 3. Setup a temp mapping and jump to it816*817* r3 = MAS0 w/TLBSEL & ESEL for the entry we are running in818* r5 = ESEL of entry we are running in819*/820andi. r7,r5,0x1 /* Find an entry not used and is non-zero */821addi r7,r7,0x1822mr r4,r3 /* Set MAS0(TLBSEL) = 1 */823mtspr SPRN_MAS0,r4824tlbre825826rlwimi r4,r7,16,4,15 /* Setup MAS0 = TLBSEL | ESEL(r7) */827mtspr SPRN_MAS0,r4828829mfspr r7,SPRN_MAS1830xori r6,r7,MAS1_TS /* Setup TMP mapping in the other Address space */831mtspr SPRN_MAS1,r6832833tlbwe834835mfmsr r6836xori r6,r6,MSR_IS837mtspr SPRN_SRR1,r6838bl 1f /* Find our address */8391: mflr r6840addi r6,r6,(2f - 1b)841mtspr SPRN_SRR0,r6842rfi8432:844845/* 4. Clear out PIDs & Search info846*847* r3 = MAS0 w/TLBSEL & ESEL for the entry we started in848* r4 = MAS0 w/TLBSEL & ESEL for the temp mapping849* r5 = MAS3850*/851li r6,0852mtspr SPRN_MAS6,r6853mtspr SPRN_PID,r6854855/* 5. Invalidate mapping we started in856*857* r3 = MAS0 w/TLBSEL & ESEL for the entry we started in858* r4 = MAS0 w/TLBSEL & ESEL for the temp mapping859* r5 = MAS3860*/861mtspr SPRN_MAS0,r3862tlbre863mfspr r6,SPRN_MAS1864rlwinm r6,r6,0,2,0 /* clear IPROT */865mtspr SPRN_MAS1,r6866tlbwe867868/* Invalidate TLB1 */869PPC_TLBILX_ALL(0,0)870sync871isync872873/* The mapping only needs to be cache-coherent on SMP */874#ifdef CONFIG_SMP875#define M_IF_SMP MAS2_M876#else877#define M_IF_SMP 0878#endif879880/* 6. Setup KERNELBASE mapping in TLB[0]881*882* r3 = MAS0 w/TLBSEL & ESEL for the entry we started in883* r4 = MAS0 w/TLBSEL & ESEL for the temp mapping884* r5 = MAS3885*/886rlwinm r3,r3,0,16,3 /* clear ESEL */887mtspr SPRN_MAS0,r3888lis r6,(MAS1_VALID|MAS1_IPROT)@h889ori r6,r6,(MAS1_TSIZE(BOOK3E_PAGESZ_1GB))@l890mtspr SPRN_MAS1,r6891892LOAD_REG_IMMEDIATE(r6, PAGE_OFFSET | M_IF_SMP)893mtspr SPRN_MAS2,r6894895rlwinm r5,r5,0,0,25896ori r5,r5,MAS3_SR | MAS3_SW | MAS3_SX897mtspr SPRN_MAS3,r5898li r5,-1899rlwinm r5,r5,0,0,25900901tlbwe902903/* 7. Jump to KERNELBASE mapping904*905* r4 = MAS0 w/TLBSEL & ESEL for the temp mapping906*/907/* Now we branch the new virtual address mapped by this entry */908LOAD_REG_IMMEDIATE(r6,2f)909lis r7,MSR_KERNEL@h910ori r7,r7,MSR_KERNEL@l911mtspr SPRN_SRR0,r6912mtspr SPRN_SRR1,r7913rfi /* start execution out of TLB1[0] entry */9142:915916/* 8. Clear out the temp mapping917*918* r4 = MAS0 w/TLBSEL & ESEL for the entry we are running in919*/920mtspr SPRN_MAS0,r4921tlbre922mfspr r5,SPRN_MAS1923rlwinm r5,r5,0,2,0 /* clear IPROT */924mtspr SPRN_MAS1,r5925tlbwe926927/* Invalidate TLB1 */928PPC_TLBILX_ALL(0,0)929sync930isync931932/* We translate LR and return */933tovirt(r8,r8)934mtlr r8935blr936937have_hes:938/* Setup MAS 0,1,2,3 and 7 for tlbwe of a 1G entry that maps the939* kernel linear mapping. We also set MAS8 once for all here though940* that will have to be made dependent on whether we are running under941* a hypervisor I suppose.942*/943944/* BEWARE, MAGIC945* This code is called as an ordinary function on the boot CPU. But to946* avoid duplication, this code is also used in SCOM bringup of947* secondary CPUs. We read the code between the initial_tlb_code_start948* and initial_tlb_code_end labels one instruction at a time and RAM it949* into the new core via SCOM. That doesn't process branches, so there950* must be none between those two labels. It also means if this code951* ever takes any parameters, the SCOM code must also be updated to952* provide them.953*/954.globl a2_tlbinit_code_start955a2_tlbinit_code_start:956957ori r11,r3,MAS0_WQ_ALLWAYS958oris r11,r11,MAS0_ESEL(3)@h /* Use way 3: workaround A2 erratum 376 */959mtspr SPRN_MAS0,r11960lis r3,(MAS1_VALID | MAS1_IPROT)@h961ori r3,r3,BOOK3E_PAGESZ_1GB << MAS1_TSIZE_SHIFT962mtspr SPRN_MAS1,r3963LOAD_REG_IMMEDIATE(r3, PAGE_OFFSET | MAS2_M)964mtspr SPRN_MAS2,r3965li r3,MAS3_SR | MAS3_SW | MAS3_SX966mtspr SPRN_MAS7_MAS3,r3967li r3,0968mtspr SPRN_MAS8,r3969970/* Write the TLB entry */971tlbwe972973.globl a2_tlbinit_after_linear_map974a2_tlbinit_after_linear_map:975976/* Now we branch the new virtual address mapped by this entry */977LOAD_REG_IMMEDIATE(r3,1f)978mtctr r3979bctr9809811: /* We are now running at PAGE_OFFSET, clean the TLB of everything982* else (including IPROTed things left by firmware)983* r4 = TLBnCFG984* r3 = current address (more or less)985*/986987li r5,0988mtspr SPRN_MAS6,r5989tlbsx 0,r3990991rlwinm r9,r4,0,TLBnCFG_N_ENTRY992rlwinm r10,r4,8,0xff993addi r10,r10,-1 /* Get inner loop mask */994995li r3,1996997mfspr r5,SPRN_MAS1998rlwinm r5,r5,0,(~(MAS1_VALID|MAS1_IPROT))9991000mfspr r6,SPRN_MAS21001rldicr r6,r6,0,51 /* Extract EPN */10021003mfspr r7,SPRN_MAS01004rlwinm r7,r7,0,0xffff0fff /* Clear HES and WQ */10051006rlwinm r8,r7,16,0xfff /* Extract ESEL */100710082: add r4,r3,r81009and r4,r4,r1010101011rlwimi r7,r4,16,MAS0_ESEL_MASK10121013mtspr SPRN_MAS0,r71014mtspr SPRN_MAS1,r51015mtspr SPRN_MAS2,r61016tlbwe10171018addi r3,r3,11019and. r4,r3,r1010201021bne 3f1022addis r6,r6,(1<<30)@h10233:1024cmpw r3,r91025blt 2b10261027.globl a2_tlbinit_after_iprot_flush1028a2_tlbinit_after_iprot_flush:10291030#ifdef CONFIG_PPC_EARLY_DEBUG_WSP1031/* Now establish early debug mappings if applicable */1032/* Restore the MAS0 we used for linear mapping load */1033mtspr SPRN_MAS0,r1110341035lis r3,(MAS1_VALID | MAS1_IPROT)@h1036ori r3,r3,(BOOK3E_PAGESZ_4K << MAS1_TSIZE_SHIFT)1037mtspr SPRN_MAS1,r31038LOAD_REG_IMMEDIATE(r3, WSP_UART_VIRT | MAS2_I | MAS2_G)1039mtspr SPRN_MAS2,r31040LOAD_REG_IMMEDIATE(r3, WSP_UART_PHYS | MAS3_SR | MAS3_SW)1041mtspr SPRN_MAS7_MAS3,r31042/* re-use the MAS8 value from the linear mapping */1043tlbwe1044#endif /* CONFIG_PPC_EARLY_DEBUG_WSP */10451046PPC_TLBILX(0,0,0)1047sync1048isync10491050.globl a2_tlbinit_code_end1051a2_tlbinit_code_end:10521053/* We translate LR and return */1054mflr r31055tovirt(r3,r3)1056mtlr r31057blr10581059/*1060* Main entry (boot CPU, thread 0)1061*1062* We enter here from head_64.S, possibly after the prom_init trampoline1063* with r3 and r4 already saved to r31 and 30 respectively and in 64 bits1064* mode. Anything else is as it was left by the bootloader1065*1066* Initial requirements of this port:1067*1068* - Kernel loaded at 0 physical1069* - A good lump of memory mapped 0:0 by UTLB entry 01070* - MSR:IS & MSR:DS set to 01071*1072* Note that some of the above requirements will be relaxed in the future1073* as the kernel becomes smarter at dealing with different initial conditions1074* but for now you have to be careful1075*/1076_GLOBAL(start_initialization_book3e)1077mflr r2810781079/* First, we need to setup some initial TLBs to map the kernel1080* text, data and bss at PAGE_OFFSET. We don't have a real mode1081* and always use AS 0, so we just set it up to match our link1082* address and never use 0 based addresses.1083*/1084bl .initial_tlb_book3e10851086/* Init global core bits */1087bl .init_core_book3e10881089/* Init per-thread bits */1090bl .init_thread_book3e10911092/* Return to common init code */1093tovirt(r28,r28)1094mtlr r281095blr109610971098/*1099* Secondary core/processor entry1100*1101* This is entered for thread 0 of a secondary core, all other threads1102* are expected to be stopped. It's similar to start_initialization_book3e1103* except that it's generally entered from the holding loop in head_64.S1104* after CPUs have been gathered by Open Firmware.1105*1106* We assume we are in 32 bits mode running with whatever TLB entry was1107* set for us by the firmware or POR engine.1108*/1109_GLOBAL(book3e_secondary_core_init_tlb_set)1110li r4,11111b .generic_secondary_smp_init11121113_GLOBAL(book3e_secondary_core_init)1114mflr r2811151116/* Do we need to setup initial TLB entry ? */1117cmplwi r4,01118bne 2f11191120/* Setup TLB for this core */1121bl .initial_tlb_book3e11221123/* We can return from the above running at a different1124* address, so recalculate r2 (TOC)1125*/1126bl .relative_toc11271128/* Init global core bits */11292: bl .init_core_book3e11301131/* Init per-thread bits */11323: bl .init_thread_book3e11331134/* Return to common init code at proper virtual address.1135*1136* Due to various previous assumptions, we know we entered this1137* function at either the final PAGE_OFFSET mapping or using a1138* 1:1 mapping at 0, so we don't bother doing a complicated check1139* here, we just ensure the return address has the right top bits.1140*1141* Note that if we ever want to be smarter about where we can be1142* started from, we have to be careful that by the time we reach1143* the code below we may already be running at a different location1144* than the one we were called from since initial_tlb_book3e can1145* have moved us already.1146*/1147cmpdi cr0,r28,01148blt 1f1149lis r3,PAGE_OFFSET@highest1150sldi r3,r3,321151or r28,r28,r311521: mtlr r281153blr11541155_GLOBAL(book3e_secondary_thread_init)1156mflr r281157b 3b11581159_STATIC(init_core_book3e)1160/* Establish the interrupt vector base */1161LOAD_REG_IMMEDIATE(r3, interrupt_base_book3e)1162mtspr SPRN_IVPR,r31163sync1164blr11651166_STATIC(init_thread_book3e)1167lis r3,(SPRN_EPCR_ICM | SPRN_EPCR_GICM)@h1168mtspr SPRN_EPCR,r311691170/* Make sure interrupts are off */1171wrteei 011721173/* disable all timers and clear out status */1174li r3,01175mtspr SPRN_TCR,r31176mfspr r3,SPRN_TSR1177mtspr SPRN_TSR,r311781179blr11801181_GLOBAL(__setup_base_ivors)1182SET_IVOR(0, 0x020) /* Critical Input */1183SET_IVOR(1, 0x000) /* Machine Check */1184SET_IVOR(2, 0x060) /* Data Storage */1185SET_IVOR(3, 0x080) /* Instruction Storage */1186SET_IVOR(4, 0x0a0) /* External Input */1187SET_IVOR(5, 0x0c0) /* Alignment */1188SET_IVOR(6, 0x0e0) /* Program */1189SET_IVOR(7, 0x100) /* FP Unavailable */1190SET_IVOR(8, 0x120) /* System Call */1191SET_IVOR(9, 0x140) /* Auxiliary Processor Unavailable */1192SET_IVOR(10, 0x160) /* Decrementer */1193SET_IVOR(11, 0x180) /* Fixed Interval Timer */1194SET_IVOR(12, 0x1a0) /* Watchdog Timer */1195SET_IVOR(13, 0x1c0) /* Data TLB Error */1196SET_IVOR(14, 0x1e0) /* Instruction TLB Error */1197SET_IVOR(15, 0x040) /* Debug */11981199sync12001201blr12021203_GLOBAL(setup_perfmon_ivor)1204SET_IVOR(35, 0x260) /* Performance Monitor */1205blr12061207_GLOBAL(setup_doorbell_ivors)1208SET_IVOR(36, 0x280) /* Processor Doorbell */1209SET_IVOR(37, 0x2a0) /* Processor Doorbell Crit */12101211/* Check MMUCFG[LPIDSIZE] to determine if we have category E.HV */1212mfspr r10,SPRN_MMUCFG1213rlwinm. r10,r10,0,MMUCFG_LPIDSIZE1214beqlr12151216SET_IVOR(38, 0x2c0) /* Guest Processor Doorbell */1217SET_IVOR(39, 0x2e0) /* Guest Processor Doorbell Crit/MC */1218blr12191220_GLOBAL(setup_ehv_ivors)1221/*1222* We may be running as a guest and lack E.HV even on a chip1223* that normally has it.1224*/1225mfspr r10,SPRN_MMUCFG1226rlwinm. r10,r10,0,MMUCFG_LPIDSIZE1227beqlr12281229SET_IVOR(40, 0x300) /* Embedded Hypervisor System Call */1230SET_IVOR(41, 0x320) /* Embedded Hypervisor Privilege */1231blr123212331234