/* SPDX-License-Identifier: GPL-2.0-or-later *//* * Boot code and exception vectors for Book3E processors * * Copyright (C) 2007 Ben. Herrenschmidt (benh@kernel.crashing.org), IBM Corp. */ #include <linux/linkage.h>#include <linux/threads.h>#include <asm/reg.h>#include <asm/page.h>#include <asm/ppc_asm.h>#include <asm/asm-offsets.h>#include <asm/cputable.h>#include <asm/setup.h>#include <asm/thread_info.h>#include <asm/exception-64e.h>#include <asm/bug.h>#include <asm/irqflags.h>#include <asm/ptrace.h>#include <asm/ppc-opcode.h>#include <asm/mmu.h>#include <asm/hw_irq.h>#include <asm/kvm_asm.h>#include <asm/kvm_booke_hv_asm.h>#include <asm/feature-fixups.h>#include <asm/context_tracking.h> /* 64e interrupt returns always use SRR registers */#define fast_interrupt_return fast_interrupt_return_srr#define interrupt_return interrupt_return_srr /* XXX This will ultimately add space for a special exception save * structure used to save things like SRR0/SRR1, SPRGs, MAS, etc... * when taking special interrupts. For now we don't support that, * special interrupts from within a non-standard level will probably * blow you up */#define SPECIAL_EXC_SRR0 0#define SPECIAL_EXC_SRR1 1#define SPECIAL_EXC_SPRG_GEN 2#define SPECIAL_EXC_SPRG_TLB 3#define SPECIAL_EXC_MAS0 4#define SPECIAL_EXC_MAS1 5#define SPECIAL_EXC_MAS2 6#define SPECIAL_EXC_MAS3 7#define SPECIAL_EXC_MAS6 8#define SPECIAL_EXC_MAS7 9#define SPECIAL_EXC_MAS5 10 /* E.HV only */#define SPECIAL_EXC_MAS8 11 /* E.HV only */#define SPECIAL_EXC_IRQHAPPENED 12#define SPECIAL_EXC_DEAR 13#define SPECIAL_EXC_ESR 14#define SPECIAL_EXC_SOFTE 15#define SPECIAL_EXC_CSRR0 16#define SPECIAL_EXC_CSRR1 17/* must be even to keep 16-byte stack alignment */#define SPECIAL_EXC_END 18 #define SPECIAL_EXC_FRAME_SIZE (INT_FRAME_SIZE + SPECIAL_EXC_END * 8)#define SPECIAL_EXC_FRAME_OFFS (INT_FRAME_SIZE - 288) #define SPECIAL_EXC_STORE(reg, name) \ std reg, (SPECIAL_EXC_##name * 8 + SPECIAL_EXC_FRAME_OFFS)(r1) #define SPECIAL_EXC_LOAD(reg, name) \ ld reg, (SPECIAL_EXC_##name * 8 + SPECIAL_EXC_FRAME_OFFS)(r1) SYM_CODE_START_LOCAL(special_reg_save) /* * We only need (or have stack space) to save this stuff if * we interrupted the kernel. */ ld r3,_MSR(r1) andi. r3,r3,MSR_PR bnelr /* * Advance to the next TLB exception frame for handler * types that don't do it automatically. */ LOAD_REG_ADDR(r11,extlb_level_exc) lwz r12,0(r11) mfspr r10,SPRN_SPRG_TLB_EXFRAME add r10,r10,r12 mtspr SPRN_SPRG_TLB_EXFRAME,r10 /* * Save registers needed to allow nesting of certain exceptions * (such as TLB misses) inside special exception levels */ mfspr r10,SPRN_SRR0 SPECIAL_EXC_STORE(r10,SRR0) mfspr r10,SPRN_SRR1 SPECIAL_EXC_STORE(r10,SRR1) mfspr r10,SPRN_SPRG_GEN_SCRATCH SPECIAL_EXC_STORE(r10,SPRG_GEN) mfspr r10,SPRN_SPRG_TLB_SCRATCH SPECIAL_EXC_STORE(r10,SPRG_TLB) mfspr r10,SPRN_MAS0 SPECIAL_EXC_STORE(r10,MAS0) mfspr r10,SPRN_MAS1 SPECIAL_EXC_STORE(r10,MAS1) mfspr r10,SPRN_MAS2 SPECIAL_EXC_STORE(r10,MAS2) mfspr r10,SPRN_MAS3 SPECIAL_EXC_STORE(r10,MAS3) mfspr r10,SPRN_MAS6 SPECIAL_EXC_STORE(r10,MAS6) mfspr r10,SPRN_MAS7 SPECIAL_EXC_STORE(r10,MAS7)BEGIN_FTR_SECTION mfspr r10,SPRN_MAS5 SPECIAL_EXC_STORE(r10,MAS5) mfspr r10,SPRN_MAS8 SPECIAL_EXC_STORE(r10,MAS8) /* MAS5/8 could have inappropriate values if we interrupted KVM code */ li r10,0 mtspr SPRN_MAS5,r10 mtspr SPRN_MAS8,r10END_FTR_SECTION_IFSET(CPU_FTR_EMB_HV) mfspr r10,SPRN_DEAR SPECIAL_EXC_STORE(r10,DEAR) mfspr r10,SPRN_ESR SPECIAL_EXC_STORE(r10,ESR) ld r10,_NIP(r1) SPECIAL_EXC_STORE(r10,CSRR0) ld r10,_MSR(r1) SPECIAL_EXC_STORE(r10,CSRR1) blrSYM_CODE_END(special_reg_save) SYM_CODE_START_LOCAL(ret_from_level_except) ld r3,_MSR(r1) andi. r3,r3,MSR_PR beq 1f REST_NVGPRS(r1) b interrupt_return1: LOAD_REG_ADDR(r11,extlb_level_exc) lwz r12,0(r11) mfspr r10,SPRN_SPRG_TLB_EXFRAME sub r10,r10,r12 mtspr SPRN_SPRG_TLB_EXFRAME,r10 /* * It's possible that the special level exception interrupted a * TLB miss handler, and inserted the same entry that the * interrupted handler was about to insert. On CPUs without TLB * write conditional, this can result in a duplicate TLB entry. * Wipe all non-bolted entries to be safe. * * Note that this doesn't protect against any TLB misses * we may take accessing the stack from here to the end of * the special level exception. It's not clear how we can * reasonably protect against that, but only CPUs with * neither TLB write conditional nor bolted kernel memory * are affected. Do any such CPUs even exist? */ PPC_TLBILX_ALL(0,R0) REST_NVGPRS(r1) SPECIAL_EXC_LOAD(r10,SRR0) mtspr SPRN_SRR0,r10 SPECIAL_EXC_LOAD(r10,SRR1) mtspr SPRN_SRR1,r10 SPECIAL_EXC_LOAD(r10,SPRG_GEN) mtspr SPRN_SPRG_GEN_SCRATCH,r10 SPECIAL_EXC_LOAD(r10,SPRG_TLB) mtspr SPRN_SPRG_TLB_SCRATCH,r10 SPECIAL_EXC_LOAD(r10,MAS0) mtspr SPRN_MAS0,r10 SPECIAL_EXC_LOAD(r10,MAS1) mtspr SPRN_MAS1,r10 SPECIAL_EXC_LOAD(r10,MAS2) mtspr SPRN_MAS2,r10 SPECIAL_EXC_LOAD(r10,MAS3) mtspr SPRN_MAS3,r10 SPECIAL_EXC_LOAD(r10,MAS6) mtspr SPRN_MAS6,r10 SPECIAL_EXC_LOAD(r10,MAS7) mtspr SPRN_MAS7,r10BEGIN_FTR_SECTION SPECIAL_EXC_LOAD(r10,MAS5) mtspr SPRN_MAS5,r10 SPECIAL_EXC_LOAD(r10,MAS8) mtspr SPRN_MAS8,r10END_FTR_SECTION_IFSET(CPU_FTR_EMB_HV) SPECIAL_EXC_LOAD(r10,DEAR) mtspr SPRN_DEAR,r10 SPECIAL_EXC_LOAD(r10,ESR) mtspr SPRN_ESR,r10 stdcx. r0,0,r1 /* to clear the reservation */ REST_GPRS(2, 9, r1) ld r10,_CTR(r1) ld r11,_XER(r1) mtctr r10 mtxer r11 blrSYM_CODE_END(ret_from_level_except) .macro ret_from_level srr0 srr1 paca_ex scratch bl ret_from_level_except ld r10,_LINK(r1) ld r11,_CCR(r1) ld r0,GPR13(r1) mtlr r10 mtcr r11 REST_GPRS(10, 12, r1) mtspr \scratch,r0 std r10,\paca_ex+EX_R10(r13); std r11,\paca_ex+EX_R11(r13); ld r10,_NIP(r1) ld r11,_MSR(r1) REST_GPR(0, r1) REST_GPR(1, r1) mtspr \srr0,r10 mtspr \srr1,r11 ld r10,\paca_ex+EX_R10(r13) ld r11,\paca_ex+EX_R11(r13) mfspr r13,\scratch.endm SYM_CODE_START_LOCAL(ret_from_crit_except) ret_from_level SPRN_CSRR0 SPRN_CSRR1 PACA_EXCRIT SPRN_SPRG_CRIT_SCRATCH rfciSYM_CODE_END(ret_from_crit_except) SYM_CODE_START_LOCAL(ret_from_mc_except) ret_from_level SPRN_MCSRR0 SPRN_MCSRR1 PACA_EXMC SPRN_SPRG_MC_SCRATCH rfmciSYM_CODE_END(ret_from_mc_except) /* Exception prolog code for all exceptions */#define EXCEPTION_PROLOG(n, intnum, type, addition) \ mtspr SPRN_SPRG_##type##_SCRATCH,r13; /* get spare registers */ \ mfspr r13,SPRN_SPRG_PACA; /* get PACA */ \ std r10,PACA_EX##type+EX_R10(r13); \ std r11,PACA_EX##type+EX_R11(r13); \ mfcr r10; /* save CR */ \ mfspr r11,SPRN_##type##_SRR1;/* what are we coming from */ \ DO_KVM intnum,SPRN_##type##_SRR1; /* KVM hook */ \ stw r10,PACA_EX##type+EX_CR(r13); /* save old CR in the PACA */ \ addition; /* additional code for that exc. */ \ std r1,PACA_EX##type+EX_R1(r13); /* save old r1 in the PACA */ \ type##_SET_KSTACK; /* get special stack if necessary */\ andi. r10,r11,MSR_PR; /* save stack pointer */ \ beq 1f; /* branch around if supervisor */ \ ld r1,PACAKSAVE(r13); /* get kernel stack coming from usr */\1: type##_BTB_FLUSH \ cmpdi cr1,r1,0; /* check if SP makes sense */ \ bge- cr1,exc_##n##_bad_stack;/* bad stack (TODO: out of line) */ \ mfspr r10,SPRN_##type##_SRR0; /* read SRR0 before touching stack */ /* Exception type-specific macros */#define GEN_SET_KSTACK \ subi r1,r1,INT_FRAME_SIZE; /* alloc frame on kernel stack */#define SPRN_GEN_SRR0 SPRN_SRR0#define SPRN_GEN_SRR1 SPRN_SRR1 #define GDBELL_SET_KSTACK GEN_SET_KSTACK#define SPRN_GDBELL_SRR0 SPRN_GSRR0#define SPRN_GDBELL_SRR1 SPRN_GSRR1 #define CRIT_SET_KSTACK \ ld r1,PACA_CRIT_STACK(r13); \ subi r1,r1,SPECIAL_EXC_FRAME_SIZE#define SPRN_CRIT_SRR0 SPRN_CSRR0#define SPRN_CRIT_SRR1 SPRN_CSRR1 #define DBG_SET_KSTACK \ ld r1,PACA_DBG_STACK(r13); \ subi r1,r1,SPECIAL_EXC_FRAME_SIZE#define SPRN_DBG_SRR0 SPRN_DSRR0#define SPRN_DBG_SRR1 SPRN_DSRR1 #define MC_SET_KSTACK \ ld r1,PACA_MC_STACK(r13); \ subi r1,r1,SPECIAL_EXC_FRAME_SIZE#define SPRN_MC_SRR0 SPRN_MCSRR0#define SPRN_MC_SRR1 SPRN_MCSRR1 #define GEN_BTB_FLUSH \ START_BTB_FLUSH_SECTION \ beq 1f; \ BTB_FLUSH(r10) \ 1: \ END_BTB_FLUSH_SECTION #define CRIT_BTB_FLUSH \ START_BTB_FLUSH_SECTION \ BTB_FLUSH(r10) \ END_BTB_FLUSH_SECTION #define DBG_BTB_FLUSH CRIT_BTB_FLUSH#define MC_BTB_FLUSH CRIT_BTB_FLUSH#define GDBELL_BTB_FLUSH GEN_BTB_FLUSH #define NORMAL_EXCEPTION_PROLOG(n, intnum, addition) \ EXCEPTION_PROLOG(n, intnum, GEN, addition##_GEN(n)) #define CRIT_EXCEPTION_PROLOG(n, intnum, addition) \ EXCEPTION_PROLOG(n, intnum, CRIT, addition##_CRIT(n)) #define DBG_EXCEPTION_PROLOG(n, intnum, addition) \ EXCEPTION_PROLOG(n, intnum, DBG, addition##_DBG(n)) #define MC_EXCEPTION_PROLOG(n, intnum, addition) \ EXCEPTION_PROLOG(n, intnum, MC, addition##_MC(n)) #define GDBELL_EXCEPTION_PROLOG(n, intnum, addition) \ EXCEPTION_PROLOG(n, intnum, GDBELL, addition##_GDBELL(n)) /* Variants of the "addition" argument for the prolog */#define PROLOG_ADDITION_NONE_GEN(n)#define PROLOG_ADDITION_NONE_GDBELL(n)#define PROLOG_ADDITION_NONE_CRIT(n)#define PROLOG_ADDITION_NONE_DBG(n)#define PROLOG_ADDITION_NONE_MC(n) #define PROLOG_ADDITION_MASKABLE_GEN(n) \ lbz r10,PACAIRQSOFTMASK(r13); /* are irqs soft-masked? */ \ andi. r10,r10,IRQS_DISABLED; /* yes -> go out of line */ \ bne masked_interrupt_book3e_##n /* * Additional regs must be re-loaded from paca before EXCEPTION_COMMON* is * called, because that does SAVE_NVGPRS which must see the original register * values, otherwise the scratch values might be restored when exiting the * interrupt. */#define PROLOG_ADDITION_2REGS_GEN(n) \ std r14,PACA_EXGEN+EX_R14(r13); \ std r15,PACA_EXGEN+EX_R15(r13) #define PROLOG_ADDITION_1REG_GEN(n) \ std r14,PACA_EXGEN+EX_R14(r13); #define PROLOG_ADDITION_2REGS_CRIT(n) \ std r14,PACA_EXCRIT+EX_R14(r13); \ std r15,PACA_EXCRIT+EX_R15(r13) #define PROLOG_ADDITION_2REGS_DBG(n) \ std r14,PACA_EXDBG+EX_R14(r13); \ std r15,PACA_EXDBG+EX_R15(r13) #define PROLOG_ADDITION_2REGS_MC(n) \ std r14,PACA_EXMC+EX_R14(r13); \ std r15,PACA_EXMC+EX_R15(r13) /* Core exception code for all exceptions except TLB misses. */#define EXCEPTION_COMMON_LVL(n, scratch, excf) \exc_##n##_common: \ SAVE_GPR(0, r1); /* save r0 in stackframe */ \ SAVE_GPRS(2, 9, r1); /* save r2 - r9 in stackframe */ \ std r10,_NIP(r1); /* save SRR0 to stackframe */ \ std r11,_MSR(r1); /* save SRR1 to stackframe */ \ beq 2f; /* if from kernel mode */ \2: ld r3,excf+EX_R10(r13); /* get back r10 */ \ ld r4,excf+EX_R11(r13); /* get back r11 */ \ mfspr r5,scratch; /* get back r13 */ \ SAVE_GPR(12, r1); /* save r12 in stackframe */ \ LOAD_PACA_TOC(); /* get kernel TOC into r2 */ \ mflr r6; /* save LR in stackframe */ \ mfctr r7; /* save CTR in stackframe */ \ mfspr r8,SPRN_XER; /* save XER in stackframe */ \ ld r9,excf+EX_R1(r13); /* load orig r1 back from PACA */ \ lwz r10,excf+EX_CR(r13); /* load orig CR back from PACA */ \ lbz r11,PACAIRQSOFTMASK(r13); /* get current IRQ softe */ \ LOAD_REG_IMMEDIATE(r12, STACK_FRAME_REGS_MARKER); \ ZEROIZE_GPR(0); \ std r3,GPR10(r1); /* save r10 to stackframe */ \ std r4,GPR11(r1); /* save r11 to stackframe */ \ std r5,GPR13(r1); /* save it to stackframe */ \ std r6,_LINK(r1); \ std r7,_CTR(r1); \ std r8,_XER(r1); \ li r3,(n); /* regs.trap vector */ \ std r9,0(r1); /* store stack frame back link */ \ std r10,_CCR(r1); /* store orig CR in stackframe */ \ std r9,GPR1(r1); /* store stack frame back link */ \ std r11,SOFTE(r1); /* and save it to stackframe */ \ std r12,STACK_INT_FRAME_MARKER(r1); /* mark the frame */ \ std r3,_TRAP(r1); /* set trap number */ \ std r0,RESULT(r1); /* clear regs->result */ \ SAVE_NVGPRS(r1); \ SANITIZE_NVGPRS(); /* minimise speculation influence */ #define EXCEPTION_COMMON(n) \ EXCEPTION_COMMON_LVL(n, SPRN_SPRG_GEN_SCRATCH, PACA_EXGEN)#define EXCEPTION_COMMON_CRIT(n) \ EXCEPTION_COMMON_LVL(n, SPRN_SPRG_CRIT_SCRATCH, PACA_EXCRIT)#define EXCEPTION_COMMON_MC(n) \ EXCEPTION_COMMON_LVL(n, SPRN_SPRG_MC_SCRATCH, PACA_EXMC)#define EXCEPTION_COMMON_DBG(n) \ EXCEPTION_COMMON_LVL(n, SPRN_SPRG_DBG_SCRATCH, PACA_EXDBG) /* XXX FIXME: Restore r14/r15 when necessary */#define BAD_STACK_TRAMPOLINE(n) \exc_##n##_bad_stack: \ li r1,(n); /* get exception number */ \ sth r1,PACA_TRAP_SAVE(r13); /* store trap */ \ b bad_stack_book3e; /* bad stack error */ /* WARNING: If you change the layout of this stub, make sure you check * the debug exception handler which handles single stepping * into exceptions from userspace, and the MM code in * arch/powerpc/mm/tlb_nohash.c which patches the branch here * and would need to be updated if that branch is moved */#define EXCEPTION_STUB(loc, label) \ . = interrupt_base_book3e + loc; \ nop; /* To make debug interrupts happy */ \ b exc_##label##_book3e; #define ACK_NONE(r)#define ACK_DEC(r) \ lis r,TSR_DIS@h; \ mtspr SPRN_TSR,r#define ACK_FIT(r) \ lis r,TSR_FIS@h; \ mtspr SPRN_TSR,r /* Used by asynchronous interrupt that may happen in the idle loop. * * This check if the thread was in the idle loop, and if yes, returns * to the caller rather than the PC. This is to avoid a race if * interrupts happen before the wait instruction. */#define CHECK_NAPPING() \ ld r11, PACA_THREAD_INFO(r13); \ ld r10,TI_LOCAL_FLAGS(r11); \ andi. r9,r10,_TLF_NAPPING; \ beq+ 1f; \ ld r8,_LINK(r1); \ rlwinm r7,r10,0,~_TLF_NAPPING; \ std r8,_NIP(r1); \ std r7,TI_LOCAL_FLAGS(r11); \1: #define MASKABLE_EXCEPTION(trapnum, intnum, label, hdlr, ack) \ START_EXCEPTION(label); \ NORMAL_EXCEPTION_PROLOG(trapnum, intnum, PROLOG_ADDITION_MASKABLE)\ EXCEPTION_COMMON(trapnum) \ ack(r8); \ CHECK_NAPPING(); \ addi r3,r1,STACK_INT_FRAME_REGS; \ bl hdlr; \ b interrupt_return /* * And here we have the exception vectors ! */ .text .balign 0x1000 .globl interrupt_base_book3einterrupt_base_book3e: /* fake trap */ EXCEPTION_STUB(0x000, machine_check) EXCEPTION_STUB(0x020, critical_input) /* 0x0100 */ EXCEPTION_STUB(0x040, debug_crit) /* 0x0d00 */ EXCEPTION_STUB(0x060, data_storage) /* 0x0300 */ EXCEPTION_STUB(0x080, instruction_storage) /* 0x0400 */ EXCEPTION_STUB(0x0a0, external_input) /* 0x0500 */ EXCEPTION_STUB(0x0c0, alignment) /* 0x0600 */ EXCEPTION_STUB(0x0e0, program) /* 0x0700 */ EXCEPTION_STUB(0x100, fp_unavailable) /* 0x0800 */ EXCEPTION_STUB(0x120, system_call) /* 0x0c00 */ EXCEPTION_STUB(0x140, ap_unavailable) /* 0x0f20 */ EXCEPTION_STUB(0x160, decrementer) /* 0x0900 */ EXCEPTION_STUB(0x180, fixed_interval) /* 0x0980 */ EXCEPTION_STUB(0x1a0, watchdog) /* 0x09f0 */ EXCEPTION_STUB(0x1c0, data_tlb_miss_bolted) EXCEPTION_STUB(0x1e0, instruction_tlb_miss_bolted) EXCEPTION_STUB(0x200, altivec_unavailable) EXCEPTION_STUB(0x220, altivec_assist) EXCEPTION_STUB(0x260, perfmon) EXCEPTION_STUB(0x280, doorbell) EXCEPTION_STUB(0x2a0, doorbell_crit) EXCEPTION_STUB(0x2c0, guest_doorbell) EXCEPTION_STUB(0x2e0, guest_doorbell_crit) EXCEPTION_STUB(0x300, hypercall) EXCEPTION_STUB(0x320, ehpriv) EXCEPTION_STUB(0x340, lrat_error) Lines 1–500 of 1555. Load more
/* SPDX-License-Identifier: GPL-2.0-or-later */ /* * Boot code and exception vectors for Book3E processors * * Copyright (C) 2007 Ben. Herrenschmidt (benh@kernel.crashing.org), IBM Corp. */ #include <linux/linkage.h> #include <linux/threads.h> #include <asm/reg.h> #include <asm/page.h> #include <asm/ppc_asm.h> #include <asm/asm-offsets.h> #include <asm/cputable.h> #include <asm/setup.h> #include <asm/thread_info.h> #include <asm/exception-64e.h> #include <asm/bug.h> #include <asm/irqflags.h> #include <asm/ptrace.h> #include <asm/ppc-opcode.h> #include <asm/mmu.h> #include <asm/hw_irq.h> #include <asm/kvm_asm.h> #include <asm/kvm_booke_hv_asm.h> #include <asm/feature-fixups.h> #include <asm/context_tracking.h> /* 64e interrupt returns always use SRR registers */ #define fast_interrupt_return fast_interrupt_return_srr #define interrupt_return interrupt_return_srr /* XXX This will ultimately add space for a special exception save * structure used to save things like SRR0/SRR1, SPRGs, MAS, etc... * when taking special interrupts. For now we don't support that, * special interrupts from within a non-standard level will probably * blow you up */ #define SPECIAL_EXC_SRR0 0 #define SPECIAL_EXC_SRR1 1 #define SPECIAL_EXC_SPRG_GEN 2 #define SPECIAL_EXC_SPRG_TLB 3 #define SPECIAL_EXC_MAS0 4 #define SPECIAL_EXC_MAS1 5 #define SPECIAL_EXC_MAS2 6 #define SPECIAL_EXC_MAS3 7 #define SPECIAL_EXC_MAS6 8 #define SPECIAL_EXC_MAS7 9 #define SPECIAL_EXC_MAS5 10 /* E.HV only */ #define SPECIAL_EXC_MAS8 11 /* E.HV only */ #define SPECIAL_EXC_IRQHAPPENED 12 #define SPECIAL_EXC_DEAR 13 #define SPECIAL_EXC_ESR 14 #define SPECIAL_EXC_SOFTE 15 #define SPECIAL_EXC_CSRR0 16 #define SPECIAL_EXC_CSRR1 17 /* must be even to keep 16-byte stack alignment */ #define SPECIAL_EXC_END 18 #define SPECIAL_EXC_FRAME_SIZE (INT_FRAME_SIZE + SPECIAL_EXC_END * 8) #define SPECIAL_EXC_FRAME_OFFS (INT_FRAME_SIZE - 288) #define SPECIAL_EXC_STORE(reg, name) \ std reg, (SPECIAL_EXC_##name * 8 + SPECIAL_EXC_FRAME_OFFS)(r1) #define SPECIAL_EXC_LOAD(reg, name) \ ld reg, (SPECIAL_EXC_##name * 8 + SPECIAL_EXC_FRAME_OFFS)(r1) SYM_CODE_START_LOCAL(special_reg_save) /* * We only need (or have stack space) to save this stuff if * we interrupted the kernel. */ ld r3,_MSR(r1) andi. r3,r3,MSR_PR bnelr /* * Advance to the next TLB exception frame for handler * types that don't do it automatically. */ LOAD_REG_ADDR(r11,extlb_level_exc) lwz r12,0(r11) mfspr r10,SPRN_SPRG_TLB_EXFRAME add r10,r10,r12 mtspr SPRN_SPRG_TLB_EXFRAME,r10 /* * Save registers needed to allow nesting of certain exceptions * (such as TLB misses) inside special exception levels */ mfspr r10,SPRN_SRR0 SPECIAL_EXC_STORE(r10,SRR0) mfspr r10,SPRN_SRR1 SPECIAL_EXC_STORE(r10,SRR1) mfspr r10,SPRN_SPRG_GEN_SCRATCH SPECIAL_EXC_STORE(r10,SPRG_GEN) mfspr r10,SPRN_SPRG_TLB_SCRATCH SPECIAL_EXC_STORE(r10,SPRG_TLB) mfspr r10,SPRN_MAS0 SPECIAL_EXC_STORE(r10,MAS0) mfspr r10,SPRN_MAS1 SPECIAL_EXC_STORE(r10,MAS1) mfspr r10,SPRN_MAS2 SPECIAL_EXC_STORE(r10,MAS2) mfspr r10,SPRN_MAS3 SPECIAL_EXC_STORE(r10,MAS3) mfspr r10,SPRN_MAS6 SPECIAL_EXC_STORE(r10,MAS6) mfspr r10,SPRN_MAS7 SPECIAL_EXC_STORE(r10,MAS7) BEGIN_FTR_SECTION mfspr r10,SPRN_MAS5 SPECIAL_EXC_STORE(r10,MAS5) mfspr r10,SPRN_MAS8 SPECIAL_EXC_STORE(r10,MAS8) /* MAS5/8 could have inappropriate values if we interrupted KVM code */ li r10,0 mtspr SPRN_MAS5,r10 mtspr SPRN_MAS8,r10 END_FTR_SECTION_IFSET(CPU_FTR_EMB_HV) mfspr r10,SPRN_DEAR SPECIAL_EXC_STORE(r10,DEAR) mfspr r10,SPRN_ESR SPECIAL_EXC_STORE(r10,ESR) ld r10,_NIP(r1) SPECIAL_EXC_STORE(r10,CSRR0) ld r10,_MSR(r1) SPECIAL_EXC_STORE(r10,CSRR1) blr SYM_CODE_END(special_reg_save) SYM_CODE_START_LOCAL(ret_from_level_except) ld r3,_MSR(r1) andi. r3,r3,MSR_PR beq 1f REST_NVGPRS(r1) b interrupt_return 1: LOAD_REG_ADDR(r11,extlb_level_exc) lwz r12,0(r11) mfspr r10,SPRN_SPRG_TLB_EXFRAME sub r10,r10,r12 mtspr SPRN_SPRG_TLB_EXFRAME,r10 /* * It's possible that the special level exception interrupted a * TLB miss handler, and inserted the same entry that the * interrupted handler was about to insert. On CPUs without TLB * write conditional, this can result in a duplicate TLB entry. * Wipe all non-bolted entries to be safe. * * Note that this doesn't protect against any TLB misses * we may take accessing the stack from here to the end of * the special level exception. It's not clear how we can * reasonably protect against that, but only CPUs with * neither TLB write conditional nor bolted kernel memory * are affected. Do any such CPUs even exist? */ PPC_TLBILX_ALL(0,R0) REST_NVGPRS(r1) SPECIAL_EXC_LOAD(r10,SRR0) mtspr SPRN_SRR0,r10 SPECIAL_EXC_LOAD(r10,SRR1) mtspr SPRN_SRR1,r10 SPECIAL_EXC_LOAD(r10,SPRG_GEN) mtspr SPRN_SPRG_GEN_SCRATCH,r10 SPECIAL_EXC_LOAD(r10,SPRG_TLB) mtspr SPRN_SPRG_TLB_SCRATCH,r10 SPECIAL_EXC_LOAD(r10,MAS0) mtspr SPRN_MAS0,r10 SPECIAL_EXC_LOAD(r10,MAS1) mtspr SPRN_MAS1,r10 SPECIAL_EXC_LOAD(r10,MAS2) mtspr SPRN_MAS2,r10 SPECIAL_EXC_LOAD(r10,MAS3) mtspr SPRN_MAS3,r10 SPECIAL_EXC_LOAD(r10,MAS6) mtspr SPRN_MAS6,r10 SPECIAL_EXC_LOAD(r10,MAS7) mtspr SPRN_MAS7,r10 BEGIN_FTR_SECTION SPECIAL_EXC_LOAD(r10,MAS5) mtspr SPRN_MAS5,r10 SPECIAL_EXC_LOAD(r10,MAS8) mtspr SPRN_MAS8,r10 END_FTR_SECTION_IFSET(CPU_FTR_EMB_HV) SPECIAL_EXC_LOAD(r10,DEAR) mtspr SPRN_DEAR,r10 SPECIAL_EXC_LOAD(r10,ESR) mtspr SPRN_ESR,r10 stdcx. r0,0,r1 /* to clear the reservation */ REST_GPRS(2, 9, r1) ld r10,_CTR(r1) ld r11,_XER(r1) mtctr r10 mtxer r11 blr SYM_CODE_END(ret_from_level_except) .macro ret_from_level srr0 srr1 paca_ex scratch bl ret_from_level_except ld r10,_LINK(r1) ld r11,_CCR(r1) ld r0,GPR13(r1) mtlr r10 mtcr r11 REST_GPRS(10, 12, r1) mtspr \scratch,r0 std r10,\paca_ex+EX_R10(r13); std r11,\paca_ex+EX_R11(r13); ld r10,_NIP(r1) ld r11,_MSR(r1) REST_GPR(0, r1) REST_GPR(1, r1) mtspr \srr0,r10 mtspr \srr1,r11 ld r10,\paca_ex+EX_R10(r13) ld r11,\paca_ex+EX_R11(r13) mfspr r13,\scratch .endm SYM_CODE_START_LOCAL(ret_from_crit_except) ret_from_level SPRN_CSRR0 SPRN_CSRR1 PACA_EXCRIT SPRN_SPRG_CRIT_SCRATCH rfci SYM_CODE_END(ret_from_crit_except) SYM_CODE_START_LOCAL(ret_from_mc_except) ret_from_level SPRN_MCSRR0 SPRN_MCSRR1 PACA_EXMC SPRN_SPRG_MC_SCRATCH rfmci SYM_CODE_END(ret_from_mc_except) /* Exception prolog code for all exceptions */ #define EXCEPTION_PROLOG(n, intnum, type, addition) \ mtspr SPRN_SPRG_##type##_SCRATCH,r13; /* get spare registers */ \ mfspr r13,SPRN_SPRG_PACA; /* get PACA */ \ std r10,PACA_EX##type+EX_R10(r13); \ std r11,PACA_EX##type+EX_R11(r13); \ mfcr r10; /* save CR */ \ mfspr r11,SPRN_##type##_SRR1;/* what are we coming from */ \ DO_KVM intnum,SPRN_##type##_SRR1; /* KVM hook */ \ stw r10,PACA_EX##type+EX_CR(r13); /* save old CR in the PACA */ \ addition; /* additional code for that exc. */ \ std r1,PACA_EX##type+EX_R1(r13); /* save old r1 in the PACA */ \ type##_SET_KSTACK; /* get special stack if necessary */\ andi. r10,r11,MSR_PR; /* save stack pointer */ \ beq 1f; /* branch around if supervisor */ \ ld r1,PACAKSAVE(r13); /* get kernel stack coming from usr */\ 1: type##_BTB_FLUSH \ cmpdi cr1,r1,0; /* check if SP makes sense */ \ bge- cr1,exc_##n##_bad_stack;/* bad stack (TODO: out of line) */ \ mfspr r10,SPRN_##type##_SRR0; /* read SRR0 before touching stack */ /* Exception type-specific macros */ #define GEN_SET_KSTACK \ subi r1,r1,INT_FRAME_SIZE; /* alloc frame on kernel stack */ #define SPRN_GEN_SRR0 SPRN_SRR0 #define SPRN_GEN_SRR1 SPRN_SRR1 #define GDBELL_SET_KSTACK GEN_SET_KSTACK #define SPRN_GDBELL_SRR0 SPRN_GSRR0 #define SPRN_GDBELL_SRR1 SPRN_GSRR1 #define CRIT_SET_KSTACK \ ld r1,PACA_CRIT_STACK(r13); \ subi r1,r1,SPECIAL_EXC_FRAME_SIZE #define SPRN_CRIT_SRR0 SPRN_CSRR0 #define SPRN_CRIT_SRR1 SPRN_CSRR1 #define DBG_SET_KSTACK \ ld r1,PACA_DBG_STACK(r13); \ subi r1,r1,SPECIAL_EXC_FRAME_SIZE #define SPRN_DBG_SRR0 SPRN_DSRR0 #define SPRN_DBG_SRR1 SPRN_DSRR1 #define MC_SET_KSTACK \ ld r1,PACA_MC_STACK(r13); \ subi r1,r1,SPECIAL_EXC_FRAME_SIZE #define SPRN_MC_SRR0 SPRN_MCSRR0 #define SPRN_MC_SRR1 SPRN_MCSRR1 #define GEN_BTB_FLUSH \ START_BTB_FLUSH_SECTION \ beq 1f; \ BTB_FLUSH(r10) \ 1: \ END_BTB_FLUSH_SECTION #define CRIT_BTB_FLUSH \ START_BTB_FLUSH_SECTION \ BTB_FLUSH(r10) \ END_BTB_FLUSH_SECTION #define DBG_BTB_FLUSH CRIT_BTB_FLUSH #define MC_BTB_FLUSH CRIT_BTB_FLUSH #define GDBELL_BTB_FLUSH GEN_BTB_FLUSH #define NORMAL_EXCEPTION_PROLOG(n, intnum, addition) \ EXCEPTION_PROLOG(n, intnum, GEN, addition##_GEN(n)) #define CRIT_EXCEPTION_PROLOG(n, intnum, addition) \ EXCEPTION_PROLOG(n, intnum, CRIT, addition##_CRIT(n)) #define DBG_EXCEPTION_PROLOG(n, intnum, addition) \ EXCEPTION_PROLOG(n, intnum, DBG, addition##_DBG(n)) #define MC_EXCEPTION_PROLOG(n, intnum, addition) \ EXCEPTION_PROLOG(n, intnum, MC, addition##_MC(n)) #define GDBELL_EXCEPTION_PROLOG(n, intnum, addition) \ EXCEPTION_PROLOG(n, intnum, GDBELL, addition##_GDBELL(n)) /* Variants of the "addition" argument for the prolog */ #define PROLOG_ADDITION_NONE_GEN(n) #define PROLOG_ADDITION_NONE_GDBELL(n) #define PROLOG_ADDITION_NONE_CRIT(n) #define PROLOG_ADDITION_NONE_DBG(n) #define PROLOG_ADDITION_NONE_MC(n) #define PROLOG_ADDITION_MASKABLE_GEN(n) \ lbz r10,PACAIRQSOFTMASK(r13); /* are irqs soft-masked? */ \ andi. r10,r10,IRQS_DISABLED; /* yes -> go out of line */ \ bne masked_interrupt_book3e_##n /* * Additional regs must be re-loaded from paca before EXCEPTION_COMMON* is * called, because that does SAVE_NVGPRS which must see the original register * values, otherwise the scratch values might be restored when exiting the * interrupt. */ #define PROLOG_ADDITION_2REGS_GEN(n) \ std r14,PACA_EXGEN+EX_R14(r13); \ std r15,PACA_EXGEN+EX_R15(r13) #define PROLOG_ADDITION_1REG_GEN(n) \ std r14,PACA_EXGEN+EX_R14(r13); #define PROLOG_ADDITION_2REGS_CRIT(n) \ std r14,PACA_EXCRIT+EX_R14(r13); \ std r15,PACA_EXCRIT+EX_R15(r13) #define PROLOG_ADDITION_2REGS_DBG(n) \ std r14,PACA_EXDBG+EX_R14(r13); \ std r15,PACA_EXDBG+EX_R15(r13) #define PROLOG_ADDITION_2REGS_MC(n) \ std r14,PACA_EXMC+EX_R14(r13); \ std r15,PACA_EXMC+EX_R15(r13) /* Core exception code for all exceptions except TLB misses. */ #define EXCEPTION_COMMON_LVL(n, scratch, excf) \ exc_##n##_common: \ SAVE_GPR(0, r1); /* save r0 in stackframe */ \ SAVE_GPRS(2, 9, r1); /* save r2 - r9 in stackframe */ \ std r10,_NIP(r1); /* save SRR0 to stackframe */ \ std r11,_MSR(r1); /* save SRR1 to stackframe */ \ beq 2f; /* if from kernel mode */ \ 2: ld r3,excf+EX_R10(r13); /* get back r10 */ \ ld r4,excf+EX_R11(r13); /* get back r11 */ \ mfspr r5,scratch; /* get back r13 */ \ SAVE_GPR(12, r1); /* save r12 in stackframe */ \ LOAD_PACA_TOC(); /* get kernel TOC into r2 */ \ mflr r6; /* save LR in stackframe */ \ mfctr r7; /* save CTR in stackframe */ \ mfspr r8,SPRN_XER; /* save XER in stackframe */ \ ld r9,excf+EX_R1(r13); /* load orig r1 back from PACA */ \ lwz r10,excf+EX_CR(r13); /* load orig CR back from PACA */ \ lbz r11,PACAIRQSOFTMASK(r13); /* get current IRQ softe */ \ LOAD_REG_IMMEDIATE(r12, STACK_FRAME_REGS_MARKER); \ ZEROIZE_GPR(0); \ std r3,GPR10(r1); /* save r10 to stackframe */ \ std r4,GPR11(r1); /* save r11 to stackframe */ \ std r5,GPR13(r1); /* save it to stackframe */ \ std r6,_LINK(r1); \ std r7,_CTR(r1); \ std r8,_XER(r1); \ li r3,(n); /* regs.trap vector */ \ std r9,0(r1); /* store stack frame back link */ \ std r10,_CCR(r1); /* store orig CR in stackframe */ \ std r9,GPR1(r1); /* store stack frame back link */ \ std r11,SOFTE(r1); /* and save it to stackframe */ \ std r12,STACK_INT_FRAME_MARKER(r1); /* mark the frame */ \ std r3,_TRAP(r1); /* set trap number */ \ std r0,RESULT(r1); /* clear regs->result */ \ SAVE_NVGPRS(r1); \ SANITIZE_NVGPRS(); /* minimise speculation influence */ #define EXCEPTION_COMMON(n) \ EXCEPTION_COMMON_LVL(n, SPRN_SPRG_GEN_SCRATCH, PACA_EXGEN) #define EXCEPTION_COMMON_CRIT(n) \ EXCEPTION_COMMON_LVL(n, SPRN_SPRG_CRIT_SCRATCH, PACA_EXCRIT) #define EXCEPTION_COMMON_MC(n) \ EXCEPTION_COMMON_LVL(n, SPRN_SPRG_MC_SCRATCH, PACA_EXMC) #define EXCEPTION_COMMON_DBG(n) \ EXCEPTION_COMMON_LVL(n, SPRN_SPRG_DBG_SCRATCH, PACA_EXDBG) /* XXX FIXME: Restore r14/r15 when necessary */ #define BAD_STACK_TRAMPOLINE(n) \ exc_##n##_bad_stack: \ li r1,(n); /* get exception number */ \ sth r1,PACA_TRAP_SAVE(r13); /* store trap */ \ b bad_stack_book3e; /* bad stack error */ /* WARNING: If you change the layout of this stub, make sure you check * the debug exception handler which handles single stepping * into exceptions from userspace, and the MM code in * arch/powerpc/mm/tlb_nohash.c which patches the branch here * and would need to be updated if that branch is moved */ #define EXCEPTION_STUB(loc, label) \ . = interrupt_base_book3e + loc; \ nop; /* To make debug interrupts happy */ \ b exc_##label##_book3e; #define ACK_NONE(r) #define ACK_DEC(r) \ lis r,TSR_DIS@h; \ mtspr SPRN_TSR,r #define ACK_FIT(r) \ lis r,TSR_FIS@h; \ mtspr SPRN_TSR,r /* Used by asynchronous interrupt that may happen in the idle loop. * * This check if the thread was in the idle loop, and if yes, returns * to the caller rather than the PC. This is to avoid a race if * interrupts happen before the wait instruction. */ #define CHECK_NAPPING() \ ld r11, PACA_THREAD_INFO(r13); \ ld r10,TI_LOCAL_FLAGS(r11); \ andi. r9,r10,_TLF_NAPPING; \ beq+ 1f; \ ld r8,_LINK(r1); \ rlwinm r7,r10,0,~_TLF_NAPPING; \ std r8,_NIP(r1); \ std r7,TI_LOCAL_FLAGS(r11); \ 1: #define MASKABLE_EXCEPTION(trapnum, intnum, label, hdlr, ack) \ START_EXCEPTION(label); \ NORMAL_EXCEPTION_PROLOG(trapnum, intnum, PROLOG_ADDITION_MASKABLE)\ EXCEPTION_COMMON(trapnum) \ ack(r8); \ CHECK_NAPPING(); \ addi r3,r1,STACK_INT_FRAME_REGS; \ bl hdlr; \ b interrupt_return /* * And here we have the exception vectors ! */ .text .balign 0x1000 .globl interrupt_base_book3e interrupt_base_book3e: /* fake trap */ EXCEPTION_STUB(0x000, machine_check) EXCEPTION_STUB(0x020, critical_input) /* 0x0100 */ EXCEPTION_STUB(0x040, debug_crit) /* 0x0d00 */ EXCEPTION_STUB(0x060, data_storage) /* 0x0300 */ EXCEPTION_STUB(0x080, instruction_storage) /* 0x0400 */ EXCEPTION_STUB(0x0a0, external_input) /* 0x0500 */ EXCEPTION_STUB(0x0c0, alignment) /* 0x0600 */ EXCEPTION_STUB(0x0e0, program) /* 0x0700 */ EXCEPTION_STUB(0x100, fp_unavailable) /* 0x0800 */ EXCEPTION_STUB(0x120, system_call) /* 0x0c00 */ EXCEPTION_STUB(0x140, ap_unavailable) /* 0x0f20 */ EXCEPTION_STUB(0x160, decrementer) /* 0x0900 */ EXCEPTION_STUB(0x180, fixed_interval) /* 0x0980 */ EXCEPTION_STUB(0x1a0, watchdog) /* 0x09f0 */ EXCEPTION_STUB(0x1c0, data_tlb_miss_bolted) EXCEPTION_STUB(0x1e0, instruction_tlb_miss_bolted) EXCEPTION_STUB(0x200, altivec_unavailable) EXCEPTION_STUB(0x220, altivec_assist) EXCEPTION_STUB(0x260, perfmon) EXCEPTION_STUB(0x280, doorbell) EXCEPTION_STUB(0x2a0, doorbell_crit) EXCEPTION_STUB(0x2c0, guest_doorbell) EXCEPTION_STUB(0x2e0, guest_doorbell_crit) EXCEPTION_STUB(0x300, hypercall) EXCEPTION_STUB(0x320, ehpriv) EXCEPTION_STUB(0x340, lrat_error)