Merge tag 'powerpc-4.9-1' of git://git.kernel.org/pub/scm/linux/kernel/git/powerpc...
[cascardo/linux.git] / arch / powerpc / kernel / exceptions-64s.S
index bffec73..08992f8 100644 (file)
 #include <asm/exception-64s.h>
 #include <asm/ptrace.h>
 #include <asm/cpuidle.h>
+#include <asm/head-64.h>
 
 /*
+ * There are a few constraints to be concerned with.
+ * - Real mode exceptions code/data must be located at their physical location.
+ * - Virtual mode exceptions must be mapped at their 0xc000... location.
+ * - Fixed location code must not call directly beyond the __end_interrupts
+ *   area when built with CONFIG_RELOCATABLE. LOAD_HANDLER / bctr sequence
+ *   must be used.
+ * - LOAD_HANDLER targets must be within first 64K of physical 0 /
+ *   virtual 0xc00...
+ * - Conditional branch targets must be within +/-32K of caller.
+ *
+ * "Virtual exceptions" run with relocation on (MSR_IR=1, MSR_DR=1), and
+ * therefore don't have to run in physically located code or rfid to
+ * virtual mode kernel code. However on relocatable kernels they do have
+ * to branch to KERNELBASE offset because the rest of the kernel (outside
+ * the exception vectors) may be located elsewhere.
+ *
+ * Virtual exceptions correspond with physical, except their entry points
+ * are offset by 0xc000000000000000 and also tend to get an added 0x4000
+ * offset applied. Virtual exceptions are enabled with the Alternate
+ * Interrupt Location (AIL) bit set in the LPCR. However this does not
+ * guarantee they will be delivered virtually. Some conditions (see the ISA)
+ * cause exceptions to be delivered in real mode.
+ *
+ * It's impossible to receive interrupts below 0x300 via AIL.
+ *
+ * KVM: None of the virtual exceptions are from the guest. Anything that
+ * escalated to HV=1 from HV=0 is delivered via real mode handlers.
+ *
+ *
  * We layout physical memory as follows:
  * 0x0000 - 0x00ff : Secondary processor spin code
- * 0x0100 - 0x17ff : pSeries Interrupt prologs
- * 0x1800 - 0x4000 : interrupt support common interrupt prologs
- * 0x4000 - 0x5fff : pSeries interrupts with IR=1,DR=1
- * 0x6000 - 0x6fff : more interrupt support including for IR=1,DR=1
+ * 0x0100 - 0x18ff : Real mode pSeries interrupt vectors
+ * 0x1900 - 0x3fff : Real mode trampolines
+ * 0x4000 - 0x58ff : Relon (IR=1,DR=1) mode pSeries interrupt vectors
+ * 0x5900 - 0x6fff : Relon mode trampolines
  * 0x7000 - 0x7fff : FWNMI data area
- * 0x8000 - 0x8fff : Initial (CPU0) segment table
- * 0x9000 -        : Early init and support code
+ * 0x8000 -   .... : Common interrupt handlers, remaining early
+ *                   setup code, rest of kernel.
+ *
+ * We could reclaim 0x4000-0x42ff for real mode trampolines if the space
+ * is necessary. Until then it's more consistent to explicitly put VIRT_NONE
+ * vectors there.
  */
-       /* Syscall routine is used twice, in reloc-off and reloc-on paths */
-#define SYSCALL_PSERIES_1                                      \
-BEGIN_FTR_SECTION                                              \
-       cmpdi   r0,0x1ebe ;                                     \
-       beq-    1f ;                                            \
-END_FTR_SECTION_IFSET(CPU_FTR_REAL_LE)                         \
-       mr      r9,r13 ;                                        \
-       GET_PACA(r13) ;                                         \
-       mfspr   r11,SPRN_SRR0 ;                                 \
-0:
-
-#define SYSCALL_PSERIES_2_RFID                                         \
-       mfspr   r12,SPRN_SRR1 ;                                 \
-       ld      r10,PACAKBASE(r13) ;                            \
-       LOAD_HANDLER(r10, system_call_entry) ;                  \
-       mtspr   SPRN_SRR0,r10 ;                                 \
-       ld      r10,PACAKMSR(r13) ;                             \
-       mtspr   SPRN_SRR1,r10 ;                                 \
-       rfid ;                                                  \
-       b       . ;     /* prevent speculative execution */
-
-#define SYSCALL_PSERIES_3                                      \
-       /* Fast LE/BE switch system call */                     \
-1:     mfspr   r12,SPRN_SRR1 ;                                 \
-       xori    r12,r12,MSR_LE ;                                \
-       mtspr   SPRN_SRR1,r12 ;                                 \
-       rfid ;          /* return to userspace */               \
-       b       . ;     /* prevent speculative execution */
-
-#if defined(CONFIG_RELOCATABLE)
-       /*
-        * We can't branch directly so we do it via the CTR which
-        * is volatile across system calls.
-        */
-#define SYSCALL_PSERIES_2_DIRECT                               \
-       mflr    r10 ;                                           \
-       ld      r12,PACAKBASE(r13) ;                            \
-       LOAD_HANDLER(r12, system_call_entry) ;                  \
-       mtctr   r12 ;                                           \
-       mfspr   r12,SPRN_SRR1 ;                                 \
-       /* Re-use of r13... No spare regs to do this */ \
-       li      r13,MSR_RI ;                                    \
-       mtmsrd  r13,1 ;                                         \
-       GET_PACA(r13) ; /* get r13 back */                      \
-       bctr ;
+OPEN_FIXED_SECTION(real_vectors,        0x0100, 0x1900)
+OPEN_FIXED_SECTION(real_trampolines,    0x1900, 0x4000)
+OPEN_FIXED_SECTION(virt_vectors,        0x4000, 0x5900)
+OPEN_FIXED_SECTION(virt_trampolines,    0x5900, 0x7000)
+#if defined(CONFIG_PPC_PSERIES) || defined(CONFIG_PPC_POWERNV)
+/*
+ * Data area reserved for FWNMI option.
+ * This address (0x7000) is fixed by the RPA.
+ * pseries and powernv need to keep the whole page from
+ * 0x7000 to 0x8000 free for use by the firmware
+ */
+ZERO_FIXED_SECTION(fwnmi_page,          0x7000, 0x8000)
+OPEN_TEXT_SECTION(0x8000)
 #else
-       /* We can branch directly */
-#define SYSCALL_PSERIES_2_DIRECT                               \
-       mfspr   r12,SPRN_SRR1 ;                                 \
-       li      r10,MSR_RI ;                                    \
-       mtmsrd  r10,1 ;                 /* Set RI (EE=0) */     \
-       b       system_call_common ;
+OPEN_TEXT_SECTION(0x7000)
 #endif
 
+USE_FIXED_SECTION(real_vectors)
+
 /*
  * This is the start of the interrupt handlers for pSeries
  * This code runs with relocation off.
@@ -90,12 +89,13 @@ END_FTR_SECTION_IFSET(CPU_FTR_REAL_LE)                              \
  * Therefore any relative branches in this section must only
  * branch to labels in this section.
  */
-       . = 0x100
        .globl __start_interrupts
 __start_interrupts:
 
-       .globl system_reset_pSeries;
-system_reset_pSeries:
+/* No virt vectors corresponding with 0x0..0x100 */
+EXC_VIRT_NONE(0x4000, 0x4100)
+
+EXC_REAL_BEGIN(system_reset, 0x100, 0x200)
        SET_SCRATCH0(r13)
 #ifdef CONFIG_PPC_P7_NAP
 BEGIN_FTR_SECTION
@@ -136,9 +136,22 @@ END_FTR_SECTION_IFSET(CPU_FTR_HVMODE | CPU_FTR_ARCH_206)
 #endif /* CONFIG_PPC_P7_NAP */
        EXCEPTION_PROLOG_PSERIES(PACA_EXGEN, system_reset_common, EXC_STD,
                                 NOTEST, 0x100)
+EXC_REAL_END(system_reset, 0x100, 0x200)
+EXC_VIRT_NONE(0x4100, 0x4200)
+EXC_COMMON(system_reset_common, 0x100, system_reset_exception)
+
+#ifdef CONFIG_PPC_PSERIES
+/*
+ * Vectors for the FWNMI option.  Share common code.
+ */
+TRAMP_REAL_BEGIN(system_reset_fwnmi)
+       SET_SCRATCH0(r13)               /* save r13 */
+       EXCEPTION_PROLOG_PSERIES(PACA_EXGEN, system_reset_common, EXC_STD,
+                                NOTEST, 0x100)
+#endif /* CONFIG_PPC_PSERIES */
 
-       . = 0x200
-machine_check_pSeries_1:
+
+EXC_REAL_BEGIN(machine_check, 0x200, 0x300)
        /* This is moved out of line as it can be patched by FW, but
         * some code path might still want to branch into the original
         * vector
@@ -158,253 +171,9 @@ BEGIN_FTR_SECTION
 FTR_SECTION_ELSE
        b       machine_check_pSeries_0
 ALT_FTR_SECTION_END_IFSET(CPU_FTR_HVMODE)
-
-       . = 0x300
-       .globl data_access_pSeries
-data_access_pSeries:
-       SET_SCRATCH0(r13)
-       EXCEPTION_PROLOG_PSERIES(PACA_EXGEN, data_access_common, EXC_STD,
-                                KVMTEST, 0x300)
-
-       . = 0x380
-       .globl data_access_slb_pSeries
-data_access_slb_pSeries:
-       SET_SCRATCH0(r13)
-       EXCEPTION_PROLOG_0(PACA_EXSLB)
-       EXCEPTION_PROLOG_1(PACA_EXSLB, KVMTEST, 0x380)
-       std     r3,PACA_EXSLB+EX_R3(r13)
-       mfspr   r3,SPRN_DAR
-       mfspr   r12,SPRN_SRR1
-#ifndef CONFIG_RELOCATABLE
-       b       slb_miss_realmode
-#else
-       /*
-        * We can't just use a direct branch to slb_miss_realmode
-        * because the distance from here to there depends on where
-        * the kernel ends up being put.
-        */
-       mfctr   r11
-       ld      r10,PACAKBASE(r13)
-       LOAD_HANDLER(r10, slb_miss_realmode)
-       mtctr   r10
-       bctr
-#endif
-
-       STD_EXCEPTION_PSERIES(0x400, instruction_access)
-
-       . = 0x480
-       .globl instruction_access_slb_pSeries
-instruction_access_slb_pSeries:
-       SET_SCRATCH0(r13)
-       EXCEPTION_PROLOG_0(PACA_EXSLB)
-       EXCEPTION_PROLOG_1(PACA_EXSLB, KVMTEST, 0x480)
-       std     r3,PACA_EXSLB+EX_R3(r13)
-       mfspr   r3,SPRN_SRR0            /* SRR0 is faulting address */
-       mfspr   r12,SPRN_SRR1
-#ifndef CONFIG_RELOCATABLE
-       b       slb_miss_realmode
-#else
-       mfctr   r11
-       ld      r10,PACAKBASE(r13)
-       LOAD_HANDLER(r10, slb_miss_realmode)
-       mtctr   r10
-       bctr
-#endif
-
-       /* We open code these as we can't have a ". = x" (even with
-        * x = "." within a feature section
-        */
-       . = 0x500;
-       .globl hardware_interrupt_pSeries;
-       .globl hardware_interrupt_hv;
-hardware_interrupt_pSeries:
-hardware_interrupt_hv:
-       BEGIN_FTR_SECTION
-               _MASKABLE_EXCEPTION_PSERIES(0x502, hardware_interrupt,
-                                           EXC_HV, SOFTEN_TEST_HV)
-               KVM_HANDLER(PACA_EXGEN, EXC_HV, 0x502)
-       FTR_SECTION_ELSE
-               _MASKABLE_EXCEPTION_PSERIES(0x500, hardware_interrupt,
-                                           EXC_STD, SOFTEN_TEST_PR)
-               KVM_HANDLER(PACA_EXGEN, EXC_STD, 0x500)
-       ALT_FTR_SECTION_END_IFSET(CPU_FTR_HVMODE | CPU_FTR_ARCH_206)
-
-       STD_EXCEPTION_PSERIES(0x600, alignment)
-       KVM_HANDLER(PACA_EXGEN, EXC_STD, 0x600)
-
-       STD_EXCEPTION_PSERIES(0x700, program_check)
-       KVM_HANDLER(PACA_EXGEN, EXC_STD, 0x700)
-
-       STD_EXCEPTION_PSERIES(0x800, fp_unavailable)
-       KVM_HANDLER(PACA_EXGEN, EXC_STD, 0x800)
-
-       . = 0x900
-       .globl decrementer_pSeries
-decrementer_pSeries:
-       _MASKABLE_EXCEPTION_PSERIES(0x900, decrementer, EXC_STD, SOFTEN_TEST_PR)
-
-       STD_EXCEPTION_HV(0x980, 0x982, hdecrementer)
-
-       MASKABLE_EXCEPTION_PSERIES(0xa00, 0xa00, doorbell_super)
-       KVM_HANDLER(PACA_EXGEN, EXC_STD, 0xa00)
-
-       STD_EXCEPTION_PSERIES(0xb00, trap_0b)
-       KVM_HANDLER(PACA_EXGEN, EXC_STD, 0xb00)
-
-       . = 0xc00
-       .globl  system_call_pSeries
-system_call_pSeries:
-        /*
-         * If CONFIG_KVM_BOOK3S_64_HANDLER is set, save the PPR (on systems
-         * that support it) before changing to HMT_MEDIUM. That allows the KVM
-         * code to save that value into the guest state (it is the guest's PPR
-         * value). Otherwise just change to HMT_MEDIUM as userspace has
-         * already saved the PPR.
-         */
-#ifdef CONFIG_KVM_BOOK3S_64_HANDLER
-       SET_SCRATCH0(r13)
-       GET_PACA(r13)
-       std     r9,PACA_EXGEN+EX_R9(r13)
-       OPT_GET_SPR(r9, SPRN_PPR, CPU_FTR_HAS_PPR);
-       HMT_MEDIUM;
-       std     r10,PACA_EXGEN+EX_R10(r13)
-       OPT_SAVE_REG_TO_PACA(PACA_EXGEN+EX_PPR, r9, CPU_FTR_HAS_PPR);
-       mfcr    r9
-       KVMTEST(0xc00)
-       GET_SCRATCH0(r13)
-#else
-       HMT_MEDIUM;
-#endif
-       SYSCALL_PSERIES_1
-       SYSCALL_PSERIES_2_RFID
-       SYSCALL_PSERIES_3
-       KVM_HANDLER(PACA_EXGEN, EXC_STD, 0xc00)
-
-       STD_EXCEPTION_PSERIES(0xd00, single_step)
-       KVM_HANDLER(PACA_EXGEN, EXC_STD, 0xd00)
-
-       /* At 0xe??? we have a bunch of hypervisor exceptions, we branch
-        * out of line to handle them
-        */
-       . = 0xe00
-hv_data_storage_trampoline:
-       SET_SCRATCH0(r13)
-       EXCEPTION_PROLOG_0(PACA_EXGEN)
-       b       h_data_storage_hv
-
-       . = 0xe20
-hv_instr_storage_trampoline:
-       SET_SCRATCH0(r13)
-       EXCEPTION_PROLOG_0(PACA_EXGEN)
-       b       h_instr_storage_hv
-
-       . = 0xe40
-emulation_assist_trampoline:
-       SET_SCRATCH0(r13)
-       EXCEPTION_PROLOG_0(PACA_EXGEN)
-       b       emulation_assist_hv
-
-       . = 0xe60
-hv_exception_trampoline:
-       SET_SCRATCH0(r13)
-       EXCEPTION_PROLOG_0(PACA_EXGEN)
-       b       hmi_exception_early
-
-       . = 0xe80
-hv_doorbell_trampoline:
-       SET_SCRATCH0(r13)
-       EXCEPTION_PROLOG_0(PACA_EXGEN)
-       b       h_doorbell_hv
-
-       . = 0xea0
-hv_virt_irq_trampoline:
-       SET_SCRATCH0(r13)
-       EXCEPTION_PROLOG_0(PACA_EXGEN)
-       b       h_virt_irq_hv
-
-       /* We need to deal with the Altivec unavailable exception
-        * here which is at 0xf20, thus in the middle of the
-        * prolog code of the PerformanceMonitor one. A little
-        * trickery is thus necessary
-        */
-       . = 0xf00
-performance_monitor_pseries_trampoline:
-       SET_SCRATCH0(r13)
-       EXCEPTION_PROLOG_0(PACA_EXGEN)
-       b       performance_monitor_pSeries
-
-       . = 0xf20
-altivec_unavailable_pseries_trampoline:
-       SET_SCRATCH0(r13)
-       EXCEPTION_PROLOG_0(PACA_EXGEN)
-       b       altivec_unavailable_pSeries
-
-       . = 0xf40
-vsx_unavailable_pseries_trampoline:
-       SET_SCRATCH0(r13)
-       EXCEPTION_PROLOG_0(PACA_EXGEN)
-       b       vsx_unavailable_pSeries
-
-       . = 0xf60
-facility_unavailable_trampoline:
-       SET_SCRATCH0(r13)
-       EXCEPTION_PROLOG_0(PACA_EXGEN)
-       b       facility_unavailable_pSeries
-
-       . = 0xf80
-hv_facility_unavailable_trampoline:
-       SET_SCRATCH0(r13)
-       EXCEPTION_PROLOG_0(PACA_EXGEN)
-       b       facility_unavailable_hv
-
-#ifdef CONFIG_CBE_RAS
-       STD_EXCEPTION_HV(0x1200, 0x1202, cbe_system_error)
-       KVM_HANDLER_SKIP(PACA_EXGEN, EXC_HV, 0x1202)
-#endif /* CONFIG_CBE_RAS */
-
-       STD_EXCEPTION_PSERIES(0x1300, instruction_breakpoint)
-       KVM_HANDLER_SKIP(PACA_EXGEN, EXC_STD, 0x1300)
-
-       . = 0x1500
-       .global denorm_exception_hv
-denorm_exception_hv:
-       mtspr   SPRN_SPRG_HSCRATCH0,r13
-       EXCEPTION_PROLOG_0(PACA_EXGEN)
-       EXCEPTION_PROLOG_1(PACA_EXGEN, NOTEST, 0x1500)
-
-#ifdef CONFIG_PPC_DENORMALISATION
-       mfspr   r10,SPRN_HSRR1
-       mfspr   r11,SPRN_HSRR0          /* save HSRR0 */
-       andis.  r10,r10,(HSRR1_DENORM)@h /* denorm? */
-       addi    r11,r11,-4              /* HSRR0 is next instruction */
-       bne+    denorm_assist
-#endif
-
-       KVMTEST(0x1500)
-       EXCEPTION_PROLOG_PSERIES_1(denorm_common, EXC_HV)
-       KVM_HANDLER_SKIP(PACA_EXGEN, EXC_STD, 0x1500)
-
-#ifdef CONFIG_CBE_RAS
-       STD_EXCEPTION_HV(0x1600, 0x1602, cbe_maintenance)
-       KVM_HANDLER_SKIP(PACA_EXGEN, EXC_HV, 0x1602)
-#endif /* CONFIG_CBE_RAS */
-
-       STD_EXCEPTION_PSERIES(0x1700, altivec_assist)
-       KVM_HANDLER(PACA_EXGEN, EXC_STD, 0x1700)
-
-#ifdef CONFIG_CBE_RAS
-       STD_EXCEPTION_HV(0x1800, 0x1802, cbe_thermal)
-       KVM_HANDLER_SKIP(PACA_EXGEN, EXC_HV, 0x1802)
-#else
-       . = 0x1800
-#endif /* CONFIG_CBE_RAS */
-
-
-/*** Out of line interrupts support ***/
-
-       .align  7
-       /* moved from 0x200 */
-machine_check_powernv_early:
+EXC_REAL_END(machine_check, 0x200, 0x300)
+EXC_VIRT_NONE(0x4200, 0x4300)
+TRAMP_REAL_BEGIN(machine_check_powernv_early)
 BEGIN_FTR_SECTION
        EXCEPTION_PROLOG_1(PACA_EXMC, NOTEST, 0x200)
        /*
@@ -457,7 +226,6 @@ BEGIN_FTR_SECTION
        mfmsr   r11                     /* get MSR value */
        ori     r11,r11,MSR_ME          /* turn on ME bit */
        ori     r11,r11,MSR_RI          /* turn on RI bit */
-       ld      r12,PACAKBASE(r13)      /* get high part of &label */
        LOAD_HANDLER(r12, machine_check_handle_early)
 1:     mtspr   SPRN_SRR0,r12
        mtspr   SPRN_SRR1,r11
@@ -470,7 +238,6 @@ BEGIN_FTR_SECTION
         */
        addi    r1,r1,INT_FRAME_SIZE    /* go back to previous stack frame */
        ld      r11,PACAKMSR(r13)
-       ld      r12,PACAKBASE(r13)
        LOAD_HANDLER(r12, unrecover_mce)
        li      r10,MSR_ME
        andc    r11,r11,r10             /* Turn off MSR_ME */
@@ -478,20 +245,19 @@ BEGIN_FTR_SECTION
        b       .       /* prevent speculative execution */
 END_FTR_SECTION_IFSET(CPU_FTR_HVMODE)
 
-machine_check_pSeries:
+TRAMP_REAL_BEGIN(machine_check_pSeries)
        .globl machine_check_fwnmi
 machine_check_fwnmi:
        SET_SCRATCH0(r13)               /* save r13 */
        EXCEPTION_PROLOG_0(PACA_EXMC)
 machine_check_pSeries_0:
-       EXCEPTION_PROLOG_1(PACA_EXMC, KVMTEST, 0x200)
+       EXCEPTION_PROLOG_1(PACA_EXMC, KVMTEST_PR, 0x200)
        /*
         * The following is essentially EXCEPTION_PROLOG_PSERIES_1 with the
         * difference that MSR_RI is not enabled, because PACA_EXMC is being
         * used, so nested machine check corrupts it. machine_check_common
         * enables MSR_RI.
         */
-       ld      r12,PACAKBASE(r13)
        ld      r10,PACAKMSR(r13)
        xori    r10,r10,MSR_RI
        mfspr   r11,SPRN_SRR0
@@ -502,287 +268,243 @@ machine_check_pSeries_0:
        rfid
        b       .       /* prevent speculative execution */
 
-       KVM_HANDLER_SKIP(PACA_EXMC, EXC_STD, 0x200)
-       KVM_HANDLER_SKIP(PACA_EXGEN, EXC_STD, 0x300)
-       KVM_HANDLER_SKIP(PACA_EXSLB, EXC_STD, 0x380)
-       KVM_HANDLER(PACA_EXGEN, EXC_STD, 0x400)
-       KVM_HANDLER(PACA_EXSLB, EXC_STD, 0x480)
-       KVM_HANDLER(PACA_EXGEN, EXC_STD, 0x900)
-       KVM_HANDLER(PACA_EXGEN, EXC_HV, 0x982)
-
-#ifdef CONFIG_PPC_DENORMALISATION
-denorm_assist:
-BEGIN_FTR_SECTION
-/*
- * To denormalise we need to move a copy of the register to itself.
- * For POWER6 do that here for all FP regs.
- */
-       mfmsr   r10
-       ori     r10,r10,(MSR_FP|MSR_FE0|MSR_FE1)
-       xori    r10,r10,(MSR_FE0|MSR_FE1)
-       mtmsrd  r10
-       sync
-
-#define FMR2(n)  fmr (n), (n) ; fmr n+1, n+1
-#define FMR4(n)  FMR2(n) ; FMR2(n+2)
-#define FMR8(n)  FMR4(n) ; FMR4(n+4)
-#define FMR16(n) FMR8(n) ; FMR8(n+8)
-#define FMR32(n) FMR16(n) ; FMR16(n+16)
-       FMR32(0)
+TRAMP_KVM_SKIP(PACA_EXMC, 0x200)
 
-FTR_SECTION_ELSE
-/*
- * To denormalise we need to move a copy of the register to itself.
- * For POWER7 do that here for the first 32 VSX registers only.
- */
-       mfmsr   r10
-       oris    r10,r10,MSR_VSX@h
-       mtmsrd  r10
-       sync
+EXC_COMMON_BEGIN(machine_check_common)
+       /*
+        * Machine check is different because we use a different
+        * save area: PACA_EXMC instead of PACA_EXGEN.
+        */
+       mfspr   r10,SPRN_DAR
+       std     r10,PACA_EXMC+EX_DAR(r13)
+       mfspr   r10,SPRN_DSISR
+       stw     r10,PACA_EXMC+EX_DSISR(r13)
+       EXCEPTION_PROLOG_COMMON(0x200, PACA_EXMC)
+       FINISH_NAP
+       RECONCILE_IRQ_STATE(r10, r11)
+       ld      r3,PACA_EXMC+EX_DAR(r13)
+       lwz     r4,PACA_EXMC+EX_DSISR(r13)
+       /* Enable MSR_RI when finished with PACA_EXMC */
+       li      r10,MSR_RI
+       mtmsrd  r10,1
+       std     r3,_DAR(r1)
+       std     r4,_DSISR(r1)
+       bl      save_nvgprs
+       addi    r3,r1,STACK_FRAME_OVERHEAD
+       bl      machine_check_exception
+       b       ret_from_except
 
-#define XVCPSGNDP2(n) XVCPSGNDP(n,n,n) ; XVCPSGNDP(n+1,n+1,n+1)
-#define XVCPSGNDP4(n) XVCPSGNDP2(n) ; XVCPSGNDP2(n+2)
-#define XVCPSGNDP8(n) XVCPSGNDP4(n) ; XVCPSGNDP4(n+4)
-#define XVCPSGNDP16(n) XVCPSGNDP8(n) ; XVCPSGNDP8(n+8)
-#define XVCPSGNDP32(n) XVCPSGNDP16(n) ; XVCPSGNDP16(n+16)
-       XVCPSGNDP32(0)
+#define MACHINE_CHECK_HANDLER_WINDUP                   \
+       /* Clear MSR_RI before setting SRR0 and SRR1. */\
+       li      r0,MSR_RI;                              \
+       mfmsr   r9;             /* get MSR value */     \
+       andc    r9,r9,r0;                               \
+       mtmsrd  r9,1;           /* Clear MSR_RI */      \
+       /* Move original SRR0 and SRR1 into the respective regs */      \
+       ld      r9,_MSR(r1);                            \
+       mtspr   SPRN_SRR1,r9;                           \
+       ld      r3,_NIP(r1);                            \
+       mtspr   SPRN_SRR0,r3;                           \
+       ld      r9,_CTR(r1);                            \
+       mtctr   r9;                                     \
+       ld      r9,_XER(r1);                            \
+       mtxer   r9;                                     \
+       ld      r9,_LINK(r1);                           \
+       mtlr    r9;                                     \
+       REST_GPR(0, r1);                                \
+       REST_8GPRS(2, r1);                              \
+       REST_GPR(10, r1);                               \
+       ld      r11,_CCR(r1);                           \
+       mtcr    r11;                                    \
+       /* Decrement paca->in_mce. */                   \
+       lhz     r12,PACA_IN_MCE(r13);                   \
+       subi    r12,r12,1;                              \
+       sth     r12,PACA_IN_MCE(r13);                   \
+       REST_GPR(11, r1);                               \
+       REST_2GPRS(12, r1);                             \
+       /* restore original r1. */                      \
+       ld      r1,GPR1(r1)
 
-ALT_FTR_SECTION_END_IFCLR(CPU_FTR_ARCH_206)
+       /*
+        * Handle machine check early in real mode. We come here with
+        * ME=1, MMU (IR=0 and DR=0) off and using MC emergency stack.
+        */
+EXC_COMMON_BEGIN(machine_check_handle_early)
+       std     r0,GPR0(r1)     /* Save r0 */
+       EXCEPTION_PROLOG_COMMON_3(0x200)
+       bl      save_nvgprs
+       addi    r3,r1,STACK_FRAME_OVERHEAD
+       bl      machine_check_early
+       std     r3,RESULT(r1)   /* Save result */
+       ld      r12,_MSR(r1)
+#ifdef CONFIG_PPC_P7_NAP
+       /*
+        * Check if thread was in power saving mode. We come here when any
+        * of the following is true:
+        * a. thread wasn't in power saving mode
+        * b. thread was in power saving mode with no state loss,
+        *    supervisor state loss or hypervisor state loss.
+        *
+        * Go back to nap/sleep/winkle mode again if (b) is true.
+        */
+       rlwinm. r11,r12,47-31,30,31     /* Was it in power saving mode? */
+       beq     4f                      /* No, it wasn;t */
+       /* Thread was in power saving mode. Go back to nap again. */
+       cmpwi   r11,2
+       blt     3f
+       /* Supervisor/Hypervisor state loss */
+       li      r0,1
+       stb     r0,PACA_NAPSTATELOST(r13)
+3:     bl      machine_check_queue_event
+       MACHINE_CHECK_HANDLER_WINDUP
+       GET_PACA(r13)
+       ld      r1,PACAR1(r13)
+       /*
+        * Check what idle state this CPU was in and go back to same mode
+        * again.
+        */
+       lbz     r3,PACA_THREAD_IDLE_STATE(r13)
+       cmpwi   r3,PNV_THREAD_NAP
+       bgt     10f
+       IDLE_STATE_ENTER_SEQ(PPC_NAP)
+       /* No return */
+10:
+       cmpwi   r3,PNV_THREAD_SLEEP
+       bgt     2f
+       IDLE_STATE_ENTER_SEQ(PPC_SLEEP)
+       /* No return */
 
-BEGIN_FTR_SECTION
-       b       denorm_done
-END_FTR_SECTION_IFCLR(CPU_FTR_ARCH_207S)
-/*
- * To denormalise we need to move a copy of the register to itself.
- * For POWER8 we need to do that for all 64 VSX registers
- */
-       XVCPSGNDP32(32)
-denorm_done:
-       mtspr   SPRN_HSRR0,r11
-       mtcrf   0x80,r9
-       ld      r9,PACA_EXGEN+EX_R9(r13)
-       RESTORE_PPR_PACA(PACA_EXGEN, r10)
-BEGIN_FTR_SECTION
-       ld      r10,PACA_EXGEN+EX_CFAR(r13)
-       mtspr   SPRN_CFAR,r10
-END_FTR_SECTION_IFSET(CPU_FTR_CFAR)
-       ld      r10,PACA_EXGEN+EX_R10(r13)
-       ld      r11,PACA_EXGEN+EX_R11(r13)
-       ld      r12,PACA_EXGEN+EX_R12(r13)
-       ld      r13,PACA_EXGEN+EX_R13(r13)
-       HRFID
-       b       .
+2:
+       /*
+        * Go back to winkle. Please note that this thread was woken up in
+        * machine check from winkle and have not restored the per-subcore
+        * state. Hence before going back to winkle, set last bit of HSPGR0
+        * to 1. This will make sure that if this thread gets woken up
+        * again at reset vector 0x100 then it will get chance to restore
+        * the subcore state.
+        */
+       ori     r13,r13,1
+       SET_PACA(r13)
+       IDLE_STATE_ENTER_SEQ(PPC_WINKLE)
+       /* No return */
+4:
 #endif
-
-       .align  7
-       /* moved from 0xe00 */
-       STD_EXCEPTION_HV_OOL(0xe02, h_data_storage)
-       KVM_HANDLER_SKIP(PACA_EXGEN, EXC_HV, 0xe02)
-       STD_EXCEPTION_HV_OOL(0xe22, h_instr_storage)
-       KVM_HANDLER(PACA_EXGEN, EXC_HV, 0xe22)
-       STD_EXCEPTION_HV_OOL(0xe42, emulation_assist)
-       KVM_HANDLER(PACA_EXGEN, EXC_HV, 0xe42)
-       MASKABLE_EXCEPTION_HV_OOL(0xe62, hmi_exception)
-       KVM_HANDLER(PACA_EXGEN, EXC_HV, 0xe62)
-
-       MASKABLE_EXCEPTION_HV_OOL(0xe82, h_doorbell)
-       KVM_HANDLER(PACA_EXGEN, EXC_HV, 0xe82)
-
-       MASKABLE_EXCEPTION_HV_OOL(0xea2, h_virt_irq)
-       KVM_HANDLER(PACA_EXGEN, EXC_HV, 0xea2)
-
-       /* moved from 0xf00 */
-       STD_EXCEPTION_PSERIES_OOL(0xf00, performance_monitor)
-       KVM_HANDLER(PACA_EXGEN, EXC_STD, 0xf00)
-       STD_EXCEPTION_PSERIES_OOL(0xf20, altivec_unavailable)
-       KVM_HANDLER(PACA_EXGEN, EXC_STD, 0xf20)
-       STD_EXCEPTION_PSERIES_OOL(0xf40, vsx_unavailable)
-       KVM_HANDLER(PACA_EXGEN, EXC_STD, 0xf40)
-       STD_EXCEPTION_PSERIES_OOL(0xf60, facility_unavailable)
-       KVM_HANDLER(PACA_EXGEN, EXC_STD, 0xf60)
-       STD_EXCEPTION_HV_OOL(0xf82, facility_unavailable)
-       KVM_HANDLER(PACA_EXGEN, EXC_HV, 0xf82)
-
-/*
- * An interrupt came in while soft-disabled. We set paca->irq_happened, then:
- * - If it was a decrementer interrupt, we bump the dec to max and and return.
- * - If it was a doorbell we return immediately since doorbells are edge
- *   triggered and won't automatically refire.
- * - If it was a HMI we return immediately since we handled it in realmode
- *   and it won't refire.
- * - else we hard disable and return.
- * This is called with r10 containing the value to OR to the paca field.
- */
-#define MASKED_INTERRUPT(_H)                           \
-masked_##_H##interrupt:                                        \
-       std     r11,PACA_EXGEN+EX_R11(r13);             \
-       lbz     r11,PACAIRQHAPPENED(r13);               \
-       or      r11,r11,r10;                            \
-       stb     r11,PACAIRQHAPPENED(r13);               \
-       cmpwi   r10,PACA_IRQ_DEC;                       \
-       bne     1f;                                     \
-       lis     r10,0x7fff;                             \
-       ori     r10,r10,0xffff;                         \
-       mtspr   SPRN_DEC,r10;                           \
-       b       2f;                                     \
-1:     cmpwi   r10,PACA_IRQ_DBELL;                     \
-       beq     2f;                                     \
-       cmpwi   r10,PACA_IRQ_HMI;                       \
-       beq     2f;                                     \
-       mfspr   r10,SPRN_##_H##SRR1;                    \
-       rldicl  r10,r10,48,1; /* clear MSR_EE */        \
-       rotldi  r10,r10,16;                             \
-       mtspr   SPRN_##_H##SRR1,r10;                    \
-2:     mtcrf   0x80,r9;                                \
-       ld      r9,PACA_EXGEN+EX_R9(r13);               \
-       ld      r10,PACA_EXGEN+EX_R10(r13);             \
-       ld      r11,PACA_EXGEN+EX_R11(r13);             \
-       GET_SCRATCH0(r13);                              \
-       ##_H##rfid;                                     \
-       b       .
-       
-       MASKED_INTERRUPT()
-       MASKED_INTERRUPT(H)
-
-/*
- * Called from arch_local_irq_enable when an interrupt needs
- * to be resent. r3 contains 0x500, 0x900, 0xa00 or 0xe80 to indicate
- * which kind of interrupt. MSR:EE is already off. We generate a
- * stackframe like if a real interrupt had happened.
- *
- * Note: While MSR:EE is off, we need to make sure that _MSR
- * in the generated frame has EE set to 1 or the exception
- * handler will not properly re-enable them.
- */
-_GLOBAL(__replay_interrupt)
-       /* We are going to jump to the exception common code which
-        * will retrieve various register values from the PACA which
-        * we don't give a damn about, so we don't bother storing them.
+       /*
+        * Check if we are coming from hypervisor userspace. If yes then we
+        * continue in host kernel in V mode to deliver the MC event.
         */
-       mfmsr   r12
-       mflr    r11
-       mfcr    r9
-       ori     r12,r12,MSR_EE
-       cmpwi   r3,0x900
-       beq     decrementer_common
-       cmpwi   r3,0x500
-       beq     hardware_interrupt_common
-BEGIN_FTR_SECTION
-       cmpwi   r3,0xe80
-       beq     h_doorbell_common
-       cmpwi   r3,0xea0
-       beq     h_virt_irq_common
-       cmpwi   r3,0xe60
-       beq     hmi_exception_common
-FTR_SECTION_ELSE
-       cmpwi   r3,0xa00
-       beq     doorbell_super_common
-ALT_FTR_SECTION_END_IFSET(CPU_FTR_HVMODE)
-       blr
-
-#ifdef CONFIG_PPC_PSERIES
-/*
- * Vectors for the FWNMI option.  Share common code.
- */
-       .globl system_reset_fwnmi
-      .align 7
-system_reset_fwnmi:
-       SET_SCRATCH0(r13)               /* save r13 */
-       EXCEPTION_PROLOG_PSERIES(PACA_EXGEN, system_reset_common, EXC_STD,
-                                NOTEST, 0x100)
-
-#endif /* CONFIG_PPC_PSERIES */
+       rldicl. r11,r12,4,63            /* See if MC hit while in HV mode. */
+       beq     5f
+       andi.   r11,r12,MSR_PR          /* See if coming from user. */
+       bne     9f                      /* continue in V mode if we are. */
 
+5:
 #ifdef CONFIG_KVM_BOOK3S_64_HANDLER
-kvmppc_skip_interrupt:
        /*
-        * Here all GPRs are unchanged from when the interrupt happened
-        * except for r13, which is saved in SPRG_SCRATCH0.
+        * We are coming from kernel context. Check if we are coming from
+        * guest. if yes, then we can continue. We will fall through
+        * do_kvm_200->kvmppc_interrupt to deliver the MC event to guest.
         */
-       mfspr   r13, SPRN_SRR0
-       addi    r13, r13, 4
-       mtspr   SPRN_SRR0, r13
-       GET_SCRATCH0(r13)
+       lbz     r11,HSTATE_IN_GUEST(r13)
+       cmpwi   r11,0                   /* Check if coming from guest */
+       bne     9f                      /* continue if we are. */
+#endif
+       /*
+        * At this point we are not sure about what context we come from.
+        * Queue up the MCE event and return from the interrupt.
+        * But before that, check if this is an un-recoverable exception.
+        * If yes, then stay on emergency stack and panic.
+        */
+       andi.   r11,r12,MSR_RI
+       bne     2f
+1:     mfspr   r11,SPRN_SRR0
+       LOAD_HANDLER(r10,unrecover_mce)
+       mtspr   SPRN_SRR0,r10
+       ld      r10,PACAKMSR(r13)
+       /*
+        * We are going down. But there are chances that we might get hit by
+        * another MCE during panic path and we may run into unstable state
+        * with no way out. Hence, turn ME bit off while going down, so that
+        * when another MCE is hit during panic path, system will checkstop
+        * and hypervisor will get restarted cleanly by SP.
+        */
+       li      r3,MSR_ME
+       andc    r10,r10,r3              /* Turn off MSR_ME */
+       mtspr   SPRN_SRR1,r10
        rfid
        b       .
-
-kvmppc_skip_Hinterrupt:
+2:
        /*
-        * Here all GPRs are unchanged from when the interrupt happened
-        * except for r13, which is saved in SPRG_SCRATCH0.
+        * Check if we have successfully handled/recovered from error, if not
+        * then stay on emergency stack and panic.
         */
-       mfspr   r13, SPRN_HSRR0
-       addi    r13, r13, 4
-       mtspr   SPRN_HSRR0, r13
-       GET_SCRATCH0(r13)
-       hrfid
-       b       .
-#endif
+       ld      r3,RESULT(r1)   /* Load result */
+       cmpdi   r3,0            /* see if we handled MCE successfully */
 
-/*
- * Ensure that any handlers that get invoked from the exception prologs
- * above are below the first 64KB (0x10000) of the kernel image because
- * the prologs assemble the addresses of these handlers using the
- * LOAD_HANDLER macro, which uses an ori instruction.
- */
+       beq     1b              /* if !handled then panic */
+       /*
+        * Return from MC interrupt.
+        * Queue up the MCE event so that we can log it later, while
+        * returning from kernel or opal call.
+        */
+       bl      machine_check_queue_event
+       MACHINE_CHECK_HANDLER_WINDUP
+       rfid
+9:
+       /* Deliver the machine check to host kernel in V mode. */
+       MACHINE_CHECK_HANDLER_WINDUP
+       b       machine_check_pSeries
 
-/*** Common interrupt handlers ***/
+EXC_COMMON_BEGIN(unrecover_mce)
+       /* Invoke machine_check_exception to print MCE event and panic. */
+       addi    r3,r1,STACK_FRAME_OVERHEAD
+       bl      machine_check_exception
+       /*
+        * We will not reach here. Even if we did, there is no way out. Call
+        * unrecoverable_exception and die.
+        */
+1:     addi    r3,r1,STACK_FRAME_OVERHEAD
+       bl      unrecoverable_exception
+       b       1b
 
-       STD_EXCEPTION_COMMON(0x100, system_reset, system_reset_exception)
 
-       STD_EXCEPTION_COMMON_ASYNC(0x500, hardware_interrupt, do_IRQ)
-       STD_EXCEPTION_COMMON_ASYNC(0x900, decrementer, timer_interrupt)
-       STD_EXCEPTION_COMMON(0x980, hdecrementer, hdec_interrupt)
-#ifdef CONFIG_PPC_DOORBELL
-       STD_EXCEPTION_COMMON_ASYNC(0xa00, doorbell_super, doorbell_exception)
-#else
-       STD_EXCEPTION_COMMON_ASYNC(0xa00, doorbell_super, unknown_exception)
-#endif
-       STD_EXCEPTION_COMMON(0xb00, trap_0b, unknown_exception)
-       STD_EXCEPTION_COMMON(0xd00, single_step, single_step_exception)
-       STD_EXCEPTION_COMMON(0xe00, trap_0e, unknown_exception)
-       STD_EXCEPTION_COMMON(0xe40, emulation_assist, emulation_assist_interrupt)
-       STD_EXCEPTION_COMMON_ASYNC(0xe60, hmi_exception, handle_hmi_exception)
-#ifdef CONFIG_PPC_DOORBELL
-       STD_EXCEPTION_COMMON_ASYNC(0xe80, h_doorbell, doorbell_exception)
-#else
-       STD_EXCEPTION_COMMON_ASYNC(0xe80, h_doorbell, unknown_exception)
-#endif
-       STD_EXCEPTION_COMMON_ASYNC(0xea0, h_virt_irq, do_IRQ)
-       STD_EXCEPTION_COMMON_ASYNC(0xf00, performance_monitor, performance_monitor_exception)
-       STD_EXCEPTION_COMMON(0x1300, instruction_breakpoint, instruction_breakpoint_exception)
-       STD_EXCEPTION_COMMON(0x1502, denorm, unknown_exception)
-#ifdef CONFIG_ALTIVEC
-       STD_EXCEPTION_COMMON(0x1700, altivec_assist, altivec_assist_exception)
-#else
-       STD_EXCEPTION_COMMON(0x1700, altivec_assist, unknown_exception)
-#endif
+EXC_REAL(data_access, 0x300, 0x380)
+EXC_VIRT(data_access, 0x4300, 0x4380, 0x300)
+TRAMP_KVM_SKIP(PACA_EXGEN, 0x300)
 
+EXC_COMMON_BEGIN(data_access_common)
        /*
-        * Relocation-on interrupts: A subset of the interrupts can be delivered
-        * with IR=1/DR=1, if AIL==2 and MSR.HV won't be changed by delivering
-        * it.  Addresses are the same as the original interrupt addresses, but
-        * offset by 0xc000000000004000.
-        * It's impossible to receive interrupts below 0x300 via this mechanism.
-        * KVM: None of these traps are from the guest ; anything that escalated
-        * to HV=1 from HV=0 is delivered via real mode handlers.
+        * Here r13 points to the paca, r9 contains the saved CR,
+        * SRR0 and SRR1 are saved in r11 and r12,
+        * r9 - r13 are saved in paca->exgen.
         */
+       mfspr   r10,SPRN_DAR
+       std     r10,PACA_EXGEN+EX_DAR(r13)
+       mfspr   r10,SPRN_DSISR
+       stw     r10,PACA_EXGEN+EX_DSISR(r13)
+       EXCEPTION_PROLOG_COMMON(0x300, PACA_EXGEN)
+       RECONCILE_IRQ_STATE(r10, r11)
+       ld      r12,_MSR(r1)
+       ld      r3,PACA_EXGEN+EX_DAR(r13)
+       lwz     r4,PACA_EXGEN+EX_DSISR(r13)
+       li      r5,0x300
+       std     r3,_DAR(r1)
+       std     r4,_DSISR(r1)
+BEGIN_MMU_FTR_SECTION
+       b       do_hash_page            /* Try to handle as hpte fault */
+MMU_FTR_SECTION_ELSE
+       b       handle_page_fault
+ALT_MMU_FTR_SECTION_END_IFCLR(MMU_FTR_TYPE_RADIX)
 
-       /*
-        * This uses the standard macro, since the original 0x300 vector
-        * only has extra guff for STAB-based processors -- which never
-        * come here.
-        */
-       STD_RELON_EXCEPTION_PSERIES(0x4300, 0x300, data_access)
-       . = 0x4380
-       .globl data_access_slb_relon_pSeries
-data_access_slb_relon_pSeries:
+
+EXC_REAL_BEGIN(data_access_slb, 0x380, 0x400)
        SET_SCRATCH0(r13)
        EXCEPTION_PROLOG_0(PACA_EXSLB)
-       EXCEPTION_PROLOG_1(PACA_EXSLB, NOTEST, 0x380)
+       EXCEPTION_PROLOG_1(PACA_EXSLB, KVMTEST_PR, 0x380)
        std     r3,PACA_EXSLB+EX_R3(r13)
        mfspr   r3,SPRN_DAR
        mfspr   r12,SPRN_SRR1
+       crset   4*cr6+eq
 #ifndef CONFIG_RELOCATABLE
        b       slb_miss_realmode
 #else
@@ -792,220 +514,221 @@ data_access_slb_relon_pSeries:
         * the kernel ends up being put.
         */
        mfctr   r11
-       ld      r10,PACAKBASE(r13)
        LOAD_HANDLER(r10, slb_miss_realmode)
        mtctr   r10
        bctr
 #endif
+EXC_REAL_END(data_access_slb, 0x380, 0x400)
 
-       STD_RELON_EXCEPTION_PSERIES(0x4400, 0x400, instruction_access)
-       . = 0x4480
-       .globl instruction_access_slb_relon_pSeries
-instruction_access_slb_relon_pSeries:
+EXC_VIRT_BEGIN(data_access_slb, 0x4380, 0x4400)
        SET_SCRATCH0(r13)
        EXCEPTION_PROLOG_0(PACA_EXSLB)
-       EXCEPTION_PROLOG_1(PACA_EXSLB, NOTEST, 0x480)
+       EXCEPTION_PROLOG_1(PACA_EXSLB, NOTEST, 0x380)
        std     r3,PACA_EXSLB+EX_R3(r13)
-       mfspr   r3,SPRN_SRR0            /* SRR0 is faulting address */
+       mfspr   r3,SPRN_DAR
        mfspr   r12,SPRN_SRR1
+       crset   4*cr6+eq
 #ifndef CONFIG_RELOCATABLE
        b       slb_miss_realmode
 #else
+       /*
+        * We can't just use a direct branch to slb_miss_realmode
+        * because the distance from here to there depends on where
+        * the kernel ends up being put.
+        */
        mfctr   r11
-       ld      r10,PACAKBASE(r13)
        LOAD_HANDLER(r10, slb_miss_realmode)
        mtctr   r10
        bctr
 #endif
+EXC_VIRT_END(data_access_slb, 0x4380, 0x4400)
+TRAMP_KVM_SKIP(PACA_EXSLB, 0x380)
 
-       . = 0x4500
-       .globl hardware_interrupt_relon_pSeries;
-       .globl hardware_interrupt_relon_hv;
-hardware_interrupt_relon_pSeries:
-hardware_interrupt_relon_hv:
-       BEGIN_FTR_SECTION
-               _MASKABLE_RELON_EXCEPTION_PSERIES(0x502, hardware_interrupt, EXC_HV, SOFTEN_TEST_HV)
-       FTR_SECTION_ELSE
-               _MASKABLE_RELON_EXCEPTION_PSERIES(0x500, hardware_interrupt, EXC_STD, SOFTEN_TEST_PR)
-       ALT_FTR_SECTION_END_IFSET(CPU_FTR_HVMODE)
-       STD_RELON_EXCEPTION_PSERIES(0x4600, 0x600, alignment)
-       STD_RELON_EXCEPTION_PSERIES(0x4700, 0x700, program_check)
-       STD_RELON_EXCEPTION_PSERIES(0x4800, 0x800, fp_unavailable)
-       MASKABLE_RELON_EXCEPTION_PSERIES(0x4900, 0x900, decrementer)
-       STD_RELON_EXCEPTION_HV(0x4980, 0x982, hdecrementer)
-       MASKABLE_RELON_EXCEPTION_PSERIES(0x4a00, 0xa00, doorbell_super)
-       STD_RELON_EXCEPTION_PSERIES(0x4b00, 0xb00, trap_0b)
-
-       . = 0x4c00
-       .globl system_call_relon_pSeries
-system_call_relon_pSeries:
-       HMT_MEDIUM
-       SYSCALL_PSERIES_1
-       SYSCALL_PSERIES_2_DIRECT
-       SYSCALL_PSERIES_3
 
-       STD_RELON_EXCEPTION_PSERIES(0x4d00, 0xd00, single_step)
+EXC_REAL(instruction_access, 0x400, 0x480)
+EXC_VIRT(instruction_access, 0x4400, 0x4480, 0x400)
+TRAMP_KVM(PACA_EXGEN, 0x400)
 
-       . = 0x4e00
-       b       .       /* Can't happen, see v2.07 Book III-S section 6.5 */
+EXC_COMMON_BEGIN(instruction_access_common)
+       EXCEPTION_PROLOG_COMMON(0x400, PACA_EXGEN)
+       RECONCILE_IRQ_STATE(r10, r11)
+       ld      r12,_MSR(r1)
+       ld      r3,_NIP(r1)
+       andis.  r4,r12,0x5820
+       li      r5,0x400
+       std     r3,_DAR(r1)
+       std     r4,_DSISR(r1)
+BEGIN_MMU_FTR_SECTION
+       b       do_hash_page            /* Try to handle as hpte fault */
+MMU_FTR_SECTION_ELSE
+       b       handle_page_fault
+ALT_MMU_FTR_SECTION_END_IFCLR(MMU_FTR_TYPE_RADIX)
 
-       . = 0x4e20
-       b       .       /* Can't happen, see v2.07 Book III-S section 6.5 */
 
-       . = 0x4e40
-emulation_assist_relon_trampoline:
+EXC_REAL_BEGIN(instruction_access_slb, 0x480, 0x500)
        SET_SCRATCH0(r13)
-       EXCEPTION_PROLOG_0(PACA_EXGEN)
-       b       emulation_assist_relon_hv
-
-       . = 0x4e60
-       b       .       /* Can't happen, see v2.07 Book III-S section 6.5 */
+       EXCEPTION_PROLOG_0(PACA_EXSLB)
+       EXCEPTION_PROLOG_1(PACA_EXSLB, KVMTEST_PR, 0x480)
+       std     r3,PACA_EXSLB+EX_R3(r13)
+       mfspr   r3,SPRN_SRR0            /* SRR0 is faulting address */
+       mfspr   r12,SPRN_SRR1
+       crclr   4*cr6+eq
+#ifndef CONFIG_RELOCATABLE
+       b       slb_miss_realmode
+#else
+       mfctr   r11
+       LOAD_HANDLER(r10, slb_miss_realmode)
+       mtctr   r10
+       bctr
+#endif
+EXC_REAL_END(instruction_access_slb, 0x480, 0x500)
 
-       . = 0x4e80
-h_doorbell_relon_trampoline:
+EXC_VIRT_BEGIN(instruction_access_slb, 0x4480, 0x4500)
        SET_SCRATCH0(r13)
-       EXCEPTION_PROLOG_0(PACA_EXGEN)
-       b       h_doorbell_relon_hv
+       EXCEPTION_PROLOG_0(PACA_EXSLB)
+       EXCEPTION_PROLOG_1(PACA_EXSLB, NOTEST, 0x480)
+       std     r3,PACA_EXSLB+EX_R3(r13)
+       mfspr   r3,SPRN_SRR0            /* SRR0 is faulting address */
+       mfspr   r12,SPRN_SRR1
+       crclr   4*cr6+eq
+#ifndef CONFIG_RELOCATABLE
+       b       slb_miss_realmode
+#else
+       mfctr   r11
+       LOAD_HANDLER(r10, slb_miss_realmode)
+       mtctr   r10
+       bctr
+#endif
+EXC_VIRT_END(instruction_access_slb, 0x4480, 0x4500)
+TRAMP_KVM(PACA_EXSLB, 0x480)
 
-       . = 0x4ea0
-h_virt_irq_relon_trampoline:
-       SET_SCRATCH0(r13)
-       EXCEPTION_PROLOG_0(PACA_EXGEN)
-       b       h_virt_irq_relon_hv
 
-       . = 0x4f00
-performance_monitor_relon_pseries_trampoline:
-       SET_SCRATCH0(r13)
-       EXCEPTION_PROLOG_0(PACA_EXGEN)
-       b       performance_monitor_relon_pSeries
+/* This handler is used by both 0x380 and 0x480 slb miss interrupts */
+EXC_COMMON_BEGIN(slb_miss_realmode)
+       /*
+        * r13 points to the PACA, r9 contains the saved CR,
+        * r12 contain the saved SRR1, SRR0 is still ready for return
+        * r3 has the faulting address
+        * r9 - r13 are saved in paca->exslb.
+        * r3 is saved in paca->slb_r3
+        * cr6.eq is set for a D-SLB miss, clear for a I-SLB miss
+        * We assume we aren't going to take any exceptions during this
+        * procedure.
+        */
+       mflr    r10
+#ifdef CONFIG_RELOCATABLE
+       mtctr   r11
+#endif
 
-       . = 0x4f20
-altivec_unavailable_relon_pseries_trampoline:
-       SET_SCRATCH0(r13)
-       EXCEPTION_PROLOG_0(PACA_EXGEN)
-       b       altivec_unavailable_relon_pSeries
+       stw     r9,PACA_EXSLB+EX_CCR(r13)       /* save CR in exc. frame */
+       std     r10,PACA_EXSLB+EX_LR(r13)       /* save LR */
+       std     r3,PACA_EXSLB+EX_DAR(r13)
 
-       . = 0x4f40
-vsx_unavailable_relon_pseries_trampoline:
-       SET_SCRATCH0(r13)
-       EXCEPTION_PROLOG_0(PACA_EXGEN)
-       b       vsx_unavailable_relon_pSeries
+       crset   4*cr0+eq
+#ifdef CONFIG_PPC_STD_MMU_64
+BEGIN_MMU_FTR_SECTION
+       bl      slb_allocate_realmode
+END_MMU_FTR_SECTION_IFCLR(MMU_FTR_TYPE_RADIX)
+#endif
 
-       . = 0x4f60
-facility_unavailable_relon_trampoline:
-       SET_SCRATCH0(r13)
-       EXCEPTION_PROLOG_0(PACA_EXGEN)
-       b       facility_unavailable_relon_pSeries
+       ld      r10,PACA_EXSLB+EX_LR(r13)
+       ld      r3,PACA_EXSLB+EX_R3(r13)
+       lwz     r9,PACA_EXSLB+EX_CCR(r13)       /* get saved CR */
+       mtlr    r10
 
-       . = 0x4f80
-hv_facility_unavailable_relon_trampoline:
-       SET_SCRATCH0(r13)
-       EXCEPTION_PROLOG_0(PACA_EXGEN)
-       b       hv_facility_unavailable_relon_hv
+       beq     8f              /* if bad address, make full stack frame */
 
-       STD_RELON_EXCEPTION_PSERIES(0x5300, 0x1300, instruction_breakpoint)
-#ifdef CONFIG_PPC_DENORMALISATION
-       . = 0x5500
-       b       denorm_exception_hv
-#endif
-       STD_RELON_EXCEPTION_PSERIES(0x5700, 0x1700, altivec_assist)
+       andi.   r10,r12,MSR_RI  /* check for unrecoverable exception */
+       beq-    2f
+
+       /* All done -- return from exception. */
+
+.machine       push
+.machine       "power4"
+       mtcrf   0x80,r9
+       mtcrf   0x02,r9         /* I/D indication is in cr6 */
+       mtcrf   0x01,r9         /* slb_allocate uses cr0 and cr7 */
+.machine       pop
+
+       RESTORE_PPR_PACA(PACA_EXSLB, r9)
+       ld      r9,PACA_EXSLB+EX_R9(r13)
+       ld      r10,PACA_EXSLB+EX_R10(r13)
+       ld      r11,PACA_EXSLB+EX_R11(r13)
+       ld      r12,PACA_EXSLB+EX_R12(r13)
+       ld      r13,PACA_EXSLB+EX_R13(r13)
+       rfid
+       b       .       /* prevent speculative execution */
 
-       .align  7
-system_call_entry:
-       b       system_call_common
+2:     mfspr   r11,SPRN_SRR0
+       LOAD_HANDLER(r10,unrecov_slb)
+       mtspr   SPRN_SRR0,r10
+       ld      r10,PACAKMSR(r13)
+       mtspr   SPRN_SRR1,r10
+       rfid
+       b       .
 
-ppc64_runlatch_on_trampoline:
-       b       __ppc64_runlatch_on
+8:     mfspr   r11,SPRN_SRR0
+       LOAD_HANDLER(r10,bad_addr_slb)
+       mtspr   SPRN_SRR0,r10
+       ld      r10,PACAKMSR(r13)
+       mtspr   SPRN_SRR1,r10
+       rfid
+       b       .
 
-/*
- * Here r13 points to the paca, r9 contains the saved CR,
- * SRR0 and SRR1 are saved in r11 and r12,
- * r9 - r13 are saved in paca->exgen.
- */
-       .align  7
-       .globl data_access_common
-data_access_common:
-       mfspr   r10,SPRN_DAR
-       std     r10,PACA_EXGEN+EX_DAR(r13)
-       mfspr   r10,SPRN_DSISR
-       stw     r10,PACA_EXGEN+EX_DSISR(r13)
-       EXCEPTION_PROLOG_COMMON(0x300, PACA_EXGEN)
+EXC_COMMON_BEGIN(unrecov_slb)
+       EXCEPTION_PROLOG_COMMON(0x4100, PACA_EXSLB)
        RECONCILE_IRQ_STATE(r10, r11)
-       ld      r12,_MSR(r1)
-       ld      r3,PACA_EXGEN+EX_DAR(r13)
-       lwz     r4,PACA_EXGEN+EX_DSISR(r13)
-       li      r5,0x300
-       std     r3,_DAR(r1)
-       std     r4,_DSISR(r1)
-BEGIN_MMU_FTR_SECTION
-       b       do_hash_page            /* Try to handle as hpte fault */
-MMU_FTR_SECTION_ELSE
-       b       handle_page_fault
-ALT_MMU_FTR_SECTION_END_IFCLR(MMU_FTR_TYPE_RADIX)
+       bl      save_nvgprs
+1:     addi    r3,r1,STACK_FRAME_OVERHEAD
+       bl      unrecoverable_exception
+       b       1b
 
-       .align  7
-       .globl  h_data_storage_common
-h_data_storage_common:
-       mfspr   r10,SPRN_HDAR
-       std     r10,PACA_EXGEN+EX_DAR(r13)
-       mfspr   r10,SPRN_HDSISR
-       stw     r10,PACA_EXGEN+EX_DSISR(r13)
-       EXCEPTION_PROLOG_COMMON(0xe00, PACA_EXGEN)
-       bl      save_nvgprs
+EXC_COMMON_BEGIN(bad_addr_slb)
+       EXCEPTION_PROLOG_COMMON(0x380, PACA_EXSLB)
        RECONCILE_IRQ_STATE(r10, r11)
-       addi    r3,r1,STACK_FRAME_OVERHEAD
-       bl      unknown_exception
-       b       ret_from_except
+       ld      r3, PACA_EXSLB+EX_DAR(r13)
+       std     r3, _DAR(r1)
+       beq     cr6, 2f
+       li      r10, 0x480              /* fix trap number for I-SLB miss */
+       std     r10, _TRAP(r1)
+2:     bl      save_nvgprs
+       addi    r3, r1, STACK_FRAME_OVERHEAD
+       bl      slb_miss_bad_addr
+       b       ret_from_except
 
-       .align  7
-       .globl instruction_access_common
-instruction_access_common:
-       EXCEPTION_PROLOG_COMMON(0x400, PACA_EXGEN)
-       RECONCILE_IRQ_STATE(r10, r11)
-       ld      r12,_MSR(r1)
-       ld      r3,_NIP(r1)
-       andis.  r4,r12,0x5820
-       li      r5,0x400
-       std     r3,_DAR(r1)
-       std     r4,_DSISR(r1)
-BEGIN_MMU_FTR_SECTION
-       b       do_hash_page            /* Try to handle as hpte fault */
-MMU_FTR_SECTION_ELSE
-       b       handle_page_fault
-ALT_MMU_FTR_SECTION_END_IFCLR(MMU_FTR_TYPE_RADIX)
+EXC_REAL_BEGIN(hardware_interrupt, 0x500, 0x600)
+       .globl hardware_interrupt_hv;
+hardware_interrupt_hv:
+       BEGIN_FTR_SECTION
+               _MASKABLE_EXCEPTION_PSERIES(0x500, hardware_interrupt_common,
+                                           EXC_HV, SOFTEN_TEST_HV)
+do_kvm_H0x500:
+               KVM_HANDLER(PACA_EXGEN, EXC_HV, 0x502)
+       FTR_SECTION_ELSE
+               _MASKABLE_EXCEPTION_PSERIES(0x500, hardware_interrupt_common,
+                                           EXC_STD, SOFTEN_TEST_PR)
+do_kvm_0x500:
+               KVM_HANDLER(PACA_EXGEN, EXC_STD, 0x500)
+       ALT_FTR_SECTION_END_IFSET(CPU_FTR_HVMODE | CPU_FTR_ARCH_206)
+EXC_REAL_END(hardware_interrupt, 0x500, 0x600)
 
-       STD_EXCEPTION_COMMON(0xe20, h_instr_storage, unknown_exception)
+EXC_VIRT_BEGIN(hardware_interrupt, 0x4500, 0x4600)
+       .globl hardware_interrupt_relon_hv;
+hardware_interrupt_relon_hv:
+       BEGIN_FTR_SECTION
+               _MASKABLE_RELON_EXCEPTION_PSERIES(0x500, hardware_interrupt_common, EXC_HV, SOFTEN_TEST_HV)
+       FTR_SECTION_ELSE
+               _MASKABLE_RELON_EXCEPTION_PSERIES(0x500, hardware_interrupt_common, EXC_STD, SOFTEN_TEST_PR)
+       ALT_FTR_SECTION_END_IFSET(CPU_FTR_HVMODE)
+EXC_VIRT_END(hardware_interrupt, 0x4500, 0x4600)
 
-       /*
-        * Machine check is different because we use a different
-        * save area: PACA_EXMC instead of PACA_EXGEN.
-        */
-       .align  7
-       .globl machine_check_common
-machine_check_common:
+EXC_COMMON_ASYNC(hardware_interrupt_common, 0x500, do_IRQ)
 
-       mfspr   r10,SPRN_DAR
-       std     r10,PACA_EXMC+EX_DAR(r13)
-       mfspr   r10,SPRN_DSISR
-       stw     r10,PACA_EXMC+EX_DSISR(r13)
-       EXCEPTION_PROLOG_COMMON(0x200, PACA_EXMC)
-       FINISH_NAP
-       RECONCILE_IRQ_STATE(r10, r11)
-       ld      r3,PACA_EXMC+EX_DAR(r13)
-       lwz     r4,PACA_EXMC+EX_DSISR(r13)
-       /* Enable MSR_RI when finished with PACA_EXMC */
-       li      r10,MSR_RI
-       mtmsrd  r10,1
-       std     r3,_DAR(r1)
-       std     r4,_DSISR(r1)
-       bl      save_nvgprs
-       addi    r3,r1,STACK_FRAME_OVERHEAD
-       bl      machine_check_exception
-       b       ret_from_except
 
-       .align  7
-       .globl alignment_common
-alignment_common:
+EXC_REAL(alignment, 0x600, 0x700)
+EXC_VIRT(alignment, 0x4600, 0x4700, 0x600)
+TRAMP_KVM(PACA_EXGEN, 0x600)
+EXC_COMMON_BEGIN(alignment_common)
        mfspr   r10,SPRN_DAR
        std     r10,PACA_EXGEN+EX_DAR(r13)
        mfspr   r10,SPRN_DSISR
@@ -1021,9 +744,11 @@ alignment_common:
        bl      alignment_exception
        b       ret_from_except
 
-       .align  7
-       .globl program_check_common
-program_check_common:
+
+EXC_REAL(program_check, 0x700, 0x800)
+EXC_VIRT(program_check, 0x4700, 0x4800, 0x700)
+TRAMP_KVM(PACA_EXGEN, 0x700)
+EXC_COMMON_BEGIN(program_check_common)
        EXCEPTION_PROLOG_COMMON(0x700, PACA_EXGEN)
        bl      save_nvgprs
        RECONCILE_IRQ_STATE(r10, r11)
@@ -1031,9 +756,11 @@ program_check_common:
        bl      program_check_exception
        b       ret_from_except
 
-       .align  7
-       .globl fp_unavailable_common
-fp_unavailable_common:
+
+EXC_REAL(fp_unavailable, 0x800, 0x900)
+EXC_VIRT(fp_unavailable, 0x4800, 0x4900, 0x800)
+TRAMP_KVM(PACA_EXGEN, 0x800)
+EXC_COMMON_BEGIN(fp_unavailable_common)
        EXCEPTION_PROLOG_COMMON(0x800, PACA_EXGEN)
        bne     1f                      /* if from user, just load it up */
        bl      save_nvgprs
@@ -1061,9 +788,250 @@ END_FTR_SECTION_IFSET(CPU_FTR_TM)
        bl      fp_unavailable_tm
        b       ret_from_except
 #endif
-       .align  7
-       .globl altivec_unavailable_common
-altivec_unavailable_common:
+
+
+EXC_REAL_MASKABLE(decrementer, 0x900, 0x980)
+EXC_VIRT_MASKABLE(decrementer, 0x4900, 0x4980, 0x900)
+TRAMP_KVM(PACA_EXGEN, 0x900)
+EXC_COMMON_ASYNC(decrementer_common, 0x900, timer_interrupt)
+
+
+EXC_REAL_HV(hdecrementer, 0x980, 0xa00)
+EXC_VIRT_HV(hdecrementer, 0x4980, 0x4a00, 0x980)
+TRAMP_KVM_HV(PACA_EXGEN, 0x980)
+EXC_COMMON(hdecrementer_common, 0x980, hdec_interrupt)
+
+
+EXC_REAL_MASKABLE(doorbell_super, 0xa00, 0xb00)
+EXC_VIRT_MASKABLE(doorbell_super, 0x4a00, 0x4b00, 0xa00)
+TRAMP_KVM(PACA_EXGEN, 0xa00)
+#ifdef CONFIG_PPC_DOORBELL
+EXC_COMMON_ASYNC(doorbell_super_common, 0xa00, doorbell_exception)
+#else
+EXC_COMMON_ASYNC(doorbell_super_common, 0xa00, unknown_exception)
+#endif
+
+
+EXC_REAL(trap_0b, 0xb00, 0xc00)
+EXC_VIRT(trap_0b, 0x4b00, 0x4c00, 0xb00)
+TRAMP_KVM(PACA_EXGEN, 0xb00)
+EXC_COMMON(trap_0b_common, 0xb00, unknown_exception)
+
+
+#define LOAD_SYSCALL_HANDLER(reg)                              \
+       ld      reg,PACAKBASE(r13);                             \
+       ori     reg,reg,(ABS_ADDR(system_call_common))@l;
+
+/* Syscall routine is used twice, in reloc-off and reloc-on paths */
+#define SYSCALL_PSERIES_1                                      \
+BEGIN_FTR_SECTION                                              \
+       cmpdi   r0,0x1ebe ;                                     \
+       beq-    1f ;                                            \
+END_FTR_SECTION_IFSET(CPU_FTR_REAL_LE)                         \
+       mr      r9,r13 ;                                        \
+       GET_PACA(r13) ;                                         \
+       mfspr   r11,SPRN_SRR0 ;                                 \
+0:
+
+#define SYSCALL_PSERIES_2_RFID                                         \
+       mfspr   r12,SPRN_SRR1 ;                                 \
+       LOAD_SYSCALL_HANDLER(r10) ;                             \
+       mtspr   SPRN_SRR0,r10 ;                                 \
+       ld      r10,PACAKMSR(r13) ;                             \
+       mtspr   SPRN_SRR1,r10 ;                                 \
+       rfid ;                                                  \
+       b       . ;     /* prevent speculative execution */
+
+#define SYSCALL_PSERIES_3                                      \
+       /* Fast LE/BE switch system call */                     \
+1:     mfspr   r12,SPRN_SRR1 ;                                 \
+       xori    r12,r12,MSR_LE ;                                \
+       mtspr   SPRN_SRR1,r12 ;                                 \
+       rfid ;          /* return to userspace */               \
+       b       . ;     /* prevent speculative execution */
+
+#if defined(CONFIG_RELOCATABLE)
+       /*
+        * We can't branch directly so we do it via the CTR which
+        * is volatile across system calls.
+        */
+#define SYSCALL_PSERIES_2_DIRECT                               \
+       LOAD_SYSCALL_HANDLER(r12) ;                             \
+       mtctr   r12 ;                                           \
+       mfspr   r12,SPRN_SRR1 ;                                 \
+       li      r10,MSR_RI ;                                    \
+       mtmsrd  r10,1 ;                                         \
+       bctr ;
+#else
+       /* We can branch directly */
+#define SYSCALL_PSERIES_2_DIRECT                               \
+       mfspr   r12,SPRN_SRR1 ;                                 \
+       li      r10,MSR_RI ;                                    \
+       mtmsrd  r10,1 ;                 /* Set RI (EE=0) */     \
+       b       system_call_common ;
+#endif
+
+EXC_REAL_BEGIN(system_call, 0xc00, 0xd00)
+        /*
+         * If CONFIG_KVM_BOOK3S_64_HANDLER is set, save the PPR (on systems
+         * that support it) before changing to HMT_MEDIUM. That allows the KVM
+         * code to save that value into the guest state (it is the guest's PPR
+         * value). Otherwise just change to HMT_MEDIUM as userspace has
+         * already saved the PPR.
+         */
+#ifdef CONFIG_KVM_BOOK3S_64_HANDLER
+       SET_SCRATCH0(r13)
+       GET_PACA(r13)
+       std     r9,PACA_EXGEN+EX_R9(r13)
+       OPT_GET_SPR(r9, SPRN_PPR, CPU_FTR_HAS_PPR);
+       HMT_MEDIUM;
+       std     r10,PACA_EXGEN+EX_R10(r13)
+       OPT_SAVE_REG_TO_PACA(PACA_EXGEN+EX_PPR, r9, CPU_FTR_HAS_PPR);
+       mfcr    r9
+       KVMTEST_PR(0xc00)
+       GET_SCRATCH0(r13)
+#else
+       HMT_MEDIUM;
+#endif
+       SYSCALL_PSERIES_1
+       SYSCALL_PSERIES_2_RFID
+       SYSCALL_PSERIES_3
+EXC_REAL_END(system_call, 0xc00, 0xd00)
+
+EXC_VIRT_BEGIN(system_call, 0x4c00, 0x4d00)
+       HMT_MEDIUM
+       SYSCALL_PSERIES_1
+       SYSCALL_PSERIES_2_DIRECT
+       SYSCALL_PSERIES_3
+EXC_VIRT_END(system_call, 0x4c00, 0x4d00)
+
+TRAMP_KVM(PACA_EXGEN, 0xc00)
+
+
+EXC_REAL(single_step, 0xd00, 0xe00)
+EXC_VIRT(single_step, 0x4d00, 0x4e00, 0xd00)
+TRAMP_KVM(PACA_EXGEN, 0xd00)
+EXC_COMMON(single_step_common, 0xd00, single_step_exception)
+
+EXC_REAL_OOL_HV(h_data_storage, 0xe00, 0xe20)
+EXC_VIRT_NONE(0x4e00, 0x4e20)
+TRAMP_KVM_HV_SKIP(PACA_EXGEN, 0xe00)
+EXC_COMMON_BEGIN(h_data_storage_common)
+       mfspr   r10,SPRN_HDAR
+       std     r10,PACA_EXGEN+EX_DAR(r13)
+       mfspr   r10,SPRN_HDSISR
+       stw     r10,PACA_EXGEN+EX_DSISR(r13)
+       EXCEPTION_PROLOG_COMMON(0xe00, PACA_EXGEN)
+       bl      save_nvgprs
+       RECONCILE_IRQ_STATE(r10, r11)
+       addi    r3,r1,STACK_FRAME_OVERHEAD
+       bl      unknown_exception
+       b       ret_from_except
+
+
+EXC_REAL_OOL_HV(h_instr_storage, 0xe20, 0xe40)
+EXC_VIRT_NONE(0x4e20, 0x4e40)
+TRAMP_KVM_HV(PACA_EXGEN, 0xe20)
+EXC_COMMON(h_instr_storage_common, 0xe20, unknown_exception)
+
+
+EXC_REAL_OOL_HV(emulation_assist, 0xe40, 0xe60)
+EXC_VIRT_OOL_HV(emulation_assist, 0x4e40, 0x4e60, 0xe40)
+TRAMP_KVM_HV(PACA_EXGEN, 0xe40)
+EXC_COMMON(emulation_assist_common, 0xe40, emulation_assist_interrupt)
+
+
+/*
+ * hmi_exception trampoline is a special case. It jumps to hmi_exception_early
+ * first, and then eventaully from there to the trampoline to get into virtual
+ * mode.
+ */
+__EXC_REAL_OOL_HV_DIRECT(hmi_exception, 0xe60, 0xe80, hmi_exception_early)
+__TRAMP_REAL_REAL_OOL_MASKABLE_HV(hmi_exception, 0xe60)
+EXC_VIRT_NONE(0x4e60, 0x4e80)
+TRAMP_KVM_HV(PACA_EXGEN, 0xe60)
+TRAMP_REAL_BEGIN(hmi_exception_early)
+       EXCEPTION_PROLOG_1(PACA_EXGEN, KVMTEST_HV, 0xe60)
+       mr      r10,r1                  /* Save r1                      */
+       ld      r1,PACAEMERGSP(r13)     /* Use emergency stack          */
+       subi    r1,r1,INT_FRAME_SIZE    /* alloc stack frame            */
+       std     r9,_CCR(r1)             /* save CR in stackframe        */
+       mfspr   r11,SPRN_HSRR0          /* Save HSRR0 */
+       std     r11,_NIP(r1)            /* save HSRR0 in stackframe     */
+       mfspr   r12,SPRN_HSRR1          /* Save SRR1 */
+       std     r12,_MSR(r1)            /* save SRR1 in stackframe      */
+       std     r10,0(r1)               /* make stack chain pointer     */
+       std     r0,GPR0(r1)             /* save r0 in stackframe        */
+       std     r10,GPR1(r1)            /* save r1 in stackframe        */
+       EXCEPTION_PROLOG_COMMON_2(PACA_EXGEN)
+       EXCEPTION_PROLOG_COMMON_3(0xe60)
+       addi    r3,r1,STACK_FRAME_OVERHEAD
+       bl      hmi_exception_realmode
+       /* Windup the stack. */
+       /* Move original HSRR0 and HSRR1 into the respective regs */
+       ld      r9,_MSR(r1)
+       mtspr   SPRN_HSRR1,r9
+       ld      r3,_NIP(r1)
+       mtspr   SPRN_HSRR0,r3
+       ld      r9,_CTR(r1)
+       mtctr   r9
+       ld      r9,_XER(r1)
+       mtxer   r9
+       ld      r9,_LINK(r1)
+       mtlr    r9
+       REST_GPR(0, r1)
+       REST_8GPRS(2, r1)
+       REST_GPR(10, r1)
+       ld      r11,_CCR(r1)
+       mtcr    r11
+       REST_GPR(11, r1)
+       REST_2GPRS(12, r1)
+       /* restore original r1. */
+       ld      r1,GPR1(r1)
+
+       /*
+        * Go to virtual mode and pull the HMI event information from
+        * firmware.
+        */
+       .globl hmi_exception_after_realmode
+hmi_exception_after_realmode:
+       SET_SCRATCH0(r13)
+       EXCEPTION_PROLOG_0(PACA_EXGEN)
+       b       tramp_real_hmi_exception
+
+EXC_COMMON_ASYNC(hmi_exception_common, 0xe60, handle_hmi_exception)
+
+
+EXC_REAL_OOL_MASKABLE_HV(h_doorbell, 0xe80, 0xea0)
+EXC_VIRT_OOL_MASKABLE_HV(h_doorbell, 0x4e80, 0x4ea0, 0xe80)
+TRAMP_KVM_HV(PACA_EXGEN, 0xe80)
+#ifdef CONFIG_PPC_DOORBELL
+EXC_COMMON_ASYNC(h_doorbell_common, 0xe80, doorbell_exception)
+#else
+EXC_COMMON_ASYNC(h_doorbell_common, 0xe80, unknown_exception)
+#endif
+
+
+EXC_REAL_OOL_MASKABLE_HV(h_virt_irq, 0xea0, 0xec0)
+EXC_VIRT_OOL_MASKABLE_HV(h_virt_irq, 0x4ea0, 0x4ec0, 0xea0)
+TRAMP_KVM_HV(PACA_EXGEN, 0xea0)
+EXC_COMMON_ASYNC(h_virt_irq_common, 0xea0, do_IRQ)
+
+
+EXC_REAL_NONE(0xec0, 0xf00)
+EXC_VIRT_NONE(0x4ec0, 0x4f00)
+
+
+EXC_REAL_OOL(performance_monitor, 0xf00, 0xf20)
+EXC_VIRT_OOL(performance_monitor, 0x4f00, 0x4f20, 0xf00)
+TRAMP_KVM(PACA_EXGEN, 0xf00)
+EXC_COMMON_ASYNC(performance_monitor_common, 0xf00, performance_monitor_exception)
+
+
+EXC_REAL_OOL(altivec_unavailable, 0xf20, 0xf40)
+EXC_VIRT_OOL(altivec_unavailable, 0x4f20, 0x4f40, 0xf20)
+TRAMP_KVM(PACA_EXGEN, 0xf20)
+EXC_COMMON_BEGIN(altivec_unavailable_common)
        EXCEPTION_PROLOG_COMMON(0xf20, PACA_EXGEN)
 #ifdef CONFIG_ALTIVEC
 BEGIN_FTR_SECTION
@@ -1096,9 +1064,11 @@ END_FTR_SECTION_IFSET(CPU_FTR_ALTIVEC)
        bl      altivec_unavailable_exception
        b       ret_from_except
 
-       .align  7
-       .globl vsx_unavailable_common
-vsx_unavailable_common:
+
+EXC_REAL_OOL(vsx_unavailable, 0xf40, 0xf60)
+EXC_VIRT_OOL(vsx_unavailable, 0x4f40, 0x4f60, 0xf40)
+TRAMP_KVM(PACA_EXGEN, 0xf40)
+EXC_COMMON_BEGIN(vsx_unavailable_common)
        EXCEPTION_PROLOG_COMMON(0xf40, PACA_EXGEN)
 #ifdef CONFIG_VSX
 BEGIN_FTR_SECTION
@@ -1130,349 +1100,284 @@ END_FTR_SECTION_IFSET(CPU_FTR_VSX)
        bl      vsx_unavailable_exception
        b       ret_from_except
 
-       /* Equivalents to the above handlers for relocation-on interrupt vectors */
-       STD_RELON_EXCEPTION_HV_OOL(0xe40, emulation_assist)
-       MASKABLE_RELON_EXCEPTION_HV_OOL(0xe80, h_doorbell)
-       MASKABLE_RELON_EXCEPTION_HV_OOL(0xea0, h_virt_irq)
 
-       STD_RELON_EXCEPTION_PSERIES_OOL(0xf00, performance_monitor)
-       STD_RELON_EXCEPTION_PSERIES_OOL(0xf20, altivec_unavailable)
-       STD_RELON_EXCEPTION_PSERIES_OOL(0xf40, vsx_unavailable)
-       STD_RELON_EXCEPTION_PSERIES_OOL(0xf60, facility_unavailable)
-       STD_RELON_EXCEPTION_HV_OOL(0xf80, hv_facility_unavailable)
+EXC_REAL_OOL(facility_unavailable, 0xf60, 0xf80)
+EXC_VIRT_OOL(facility_unavailable, 0x4f60, 0x4f80, 0xf60)
+TRAMP_KVM(PACA_EXGEN, 0xf60)
+EXC_COMMON(facility_unavailable_common, 0xf60, facility_unavailable_exception)
 
-       /*
-        * The __end_interrupts marker must be past the out-of-line (OOL)
-        * handlers, so that they are copied to real address 0x100 when running
-        * a relocatable kernel. This ensures they can be reached from the short
-        * trampoline handlers (like 0x4f00, 0x4f20, etc.) which branch
-        * directly, without using LOAD_HANDLER().
-        */
-       .align  7
-       .globl  __end_interrupts
-__end_interrupts:
 
-#if defined(CONFIG_PPC_PSERIES) || defined(CONFIG_PPC_POWERNV)
-/*
- * Data area reserved for FWNMI option.
- * This address (0x7000) is fixed by the RPA.
- */
-       .= 0x7000
-       .globl fwnmi_data_area
-fwnmi_data_area:
+EXC_REAL_OOL_HV(h_facility_unavailable, 0xf80, 0xfa0)
+EXC_VIRT_OOL_HV(h_facility_unavailable, 0x4f80, 0x4fa0, 0xf80)
+TRAMP_KVM_HV(PACA_EXGEN, 0xf80)
+EXC_COMMON(h_facility_unavailable_common, 0xf80, facility_unavailable_exception)
 
-       /* pseries and powernv need to keep the whole page from
-        * 0x7000 to 0x8000 free for use by the firmware
-        */
-       . = 0x8000
-#endif /* defined(CONFIG_PPC_PSERIES) || defined(CONFIG_PPC_POWERNV) */
 
-       STD_EXCEPTION_COMMON(0xf60, facility_unavailable, facility_unavailable_exception)
-       STD_EXCEPTION_COMMON(0xf80, hv_facility_unavailable, facility_unavailable_exception)
+EXC_REAL_NONE(0xfa0, 0x1200)
+EXC_VIRT_NONE(0x4fa0, 0x5200)
 
 #ifdef CONFIG_CBE_RAS
-       STD_EXCEPTION_COMMON(0x1200, cbe_system_error, cbe_system_error_exception)
-       STD_EXCEPTION_COMMON(0x1600, cbe_maintenance, cbe_maintenance_exception)
-       STD_EXCEPTION_COMMON(0x1800, cbe_thermal, cbe_thermal_exception)
-#endif /* CONFIG_CBE_RAS */
-
-       .globl hmi_exception_early
-hmi_exception_early:
-       EXCEPTION_PROLOG_1(PACA_EXGEN, KVMTEST, 0xe62)
-       mr      r10,r1                  /* Save r1                      */
-       ld      r1,PACAEMERGSP(r13)     /* Use emergency stack          */
-       subi    r1,r1,INT_FRAME_SIZE    /* alloc stack frame            */
-       std     r9,_CCR(r1)             /* save CR in stackframe        */
-       mfspr   r11,SPRN_HSRR0          /* Save HSRR0 */
-       std     r11,_NIP(r1)            /* save HSRR0 in stackframe     */
-       mfspr   r12,SPRN_HSRR1          /* Save SRR1 */
-       std     r12,_MSR(r1)            /* save SRR1 in stackframe      */
-       std     r10,0(r1)               /* make stack chain pointer     */
-       std     r0,GPR0(r1)             /* save r0 in stackframe        */
-       std     r10,GPR1(r1)            /* save r1 in stackframe        */
-       EXCEPTION_PROLOG_COMMON_2(PACA_EXGEN)
-       EXCEPTION_PROLOG_COMMON_3(0xe60)
-       addi    r3,r1,STACK_FRAME_OVERHEAD
-       bl      hmi_exception_realmode
-       /* Windup the stack. */
-       /* Move original HSRR0 and HSRR1 into the respective regs */
-       ld      r9,_MSR(r1)
-       mtspr   SPRN_HSRR1,r9
-       ld      r3,_NIP(r1)
-       mtspr   SPRN_HSRR0,r3
-       ld      r9,_CTR(r1)
-       mtctr   r9
-       ld      r9,_XER(r1)
-       mtxer   r9
-       ld      r9,_LINK(r1)
-       mtlr    r9
-       REST_GPR(0, r1)
-       REST_8GPRS(2, r1)
-       REST_GPR(10, r1)
-       ld      r11,_CCR(r1)
-       mtcr    r11
-       REST_GPR(11, r1)
-       REST_2GPRS(12, r1)
-       /* restore original r1. */
-       ld      r1,GPR1(r1)
+EXC_REAL_HV(cbe_system_error, 0x1200, 0x1300)
+EXC_VIRT_NONE(0x5200, 0x5300)
+TRAMP_KVM_HV_SKIP(PACA_EXGEN, 0x1200)
+EXC_COMMON(cbe_system_error_common, 0x1200, cbe_system_error_exception)
+#else /* CONFIG_CBE_RAS */
+EXC_REAL_NONE(0x1200, 0x1300)
+EXC_VIRT_NONE(0x5200, 0x5300)
+#endif
 
-       /*
-        * Go to virtual mode and pull the HMI event information from
-        * firmware.
-        */
-       .globl hmi_exception_after_realmode
-hmi_exception_after_realmode:
-       SET_SCRATCH0(r13)
+
+EXC_REAL(instruction_breakpoint, 0x1300, 0x1400)
+EXC_VIRT(instruction_breakpoint, 0x5300, 0x5400, 0x1300)
+TRAMP_KVM_SKIP(PACA_EXGEN, 0x1300)
+EXC_COMMON(instruction_breakpoint_common, 0x1300, instruction_breakpoint_exception)
+
+EXC_REAL_NONE(0x1400, 0x1500)
+EXC_VIRT_NONE(0x5400, 0x5500)
+
+EXC_REAL_BEGIN(denorm_exception_hv, 0x1500, 0x1600)
+       mtspr   SPRN_SPRG_HSCRATCH0,r13
        EXCEPTION_PROLOG_0(PACA_EXGEN)
-       b       hmi_exception_hv
+       EXCEPTION_PROLOG_1(PACA_EXGEN, NOTEST, 0x1500)
 
+#ifdef CONFIG_PPC_DENORMALISATION
+       mfspr   r10,SPRN_HSRR1
+       mfspr   r11,SPRN_HSRR0          /* save HSRR0 */
+       andis.  r10,r10,(HSRR1_DENORM)@h /* denorm? */
+       addi    r11,r11,-4              /* HSRR0 is next instruction */
+       bne+    denorm_assist
+#endif
 
-#define MACHINE_CHECK_HANDLER_WINDUP                   \
-       /* Clear MSR_RI before setting SRR0 and SRR1. */\
-       li      r0,MSR_RI;                              \
-       mfmsr   r9;             /* get MSR value */     \
-       andc    r9,r9,r0;                               \
-       mtmsrd  r9,1;           /* Clear MSR_RI */      \
-       /* Move original SRR0 and SRR1 into the respective regs */      \
-       ld      r9,_MSR(r1);                            \
-       mtspr   SPRN_SRR1,r9;                           \
-       ld      r3,_NIP(r1);                            \
-       mtspr   SPRN_SRR0,r3;                           \
-       ld      r9,_CTR(r1);                            \
-       mtctr   r9;                                     \
-       ld      r9,_XER(r1);                            \
-       mtxer   r9;                                     \
-       ld      r9,_LINK(r1);                           \
-       mtlr    r9;                                     \
-       REST_GPR(0, r1);                                \
-       REST_8GPRS(2, r1);                              \
-       REST_GPR(10, r1);                               \
-       ld      r11,_CCR(r1);                           \
-       mtcr    r11;                                    \
-       /* Decrement paca->in_mce. */                   \
-       lhz     r12,PACA_IN_MCE(r13);                   \
-       subi    r12,r12,1;                              \
-       sth     r12,PACA_IN_MCE(r13);                   \
-       REST_GPR(11, r1);                               \
-       REST_2GPRS(12, r1);                             \
-       /* restore original r1. */                      \
-       ld      r1,GPR1(r1)
+       KVMTEST_PR(0x1500)
+       EXCEPTION_PROLOG_PSERIES_1(denorm_common, EXC_HV)
+EXC_REAL_END(denorm_exception_hv, 0x1500, 0x1600)
 
-       /*
-        * Handle machine check early in real mode. We come here with
-        * ME=1, MMU (IR=0 and DR=0) off and using MC emergency stack.
-        */
-       .align  7
-       .globl machine_check_handle_early
-machine_check_handle_early:
-       std     r0,GPR0(r1)     /* Save r0 */
-       EXCEPTION_PROLOG_COMMON_3(0x200)
-       bl      save_nvgprs
-       addi    r3,r1,STACK_FRAME_OVERHEAD
-       bl      machine_check_early
-       std     r3,RESULT(r1)   /* Save result */
-       ld      r12,_MSR(r1)
-#ifdef CONFIG_PPC_P7_NAP
-       /*
-        * Check if thread was in power saving mode. We come here when any
-        * of the following is true:
-        * a. thread wasn't in power saving mode
-        * b. thread was in power saving mode with no state loss,
-        *    supervisor state loss or hypervisor state loss.
-        *
-        * Go back to nap/sleep/winkle mode again if (b) is true.
-        */
-       rlwinm. r11,r12,47-31,30,31     /* Was it in power saving mode? */
-       beq     4f                      /* No, it wasn;t */
-       /* Thread was in power saving mode. Go back to nap again. */
-       cmpwi   r11,2
-       blt     3f
-       /* Supervisor/Hypervisor state loss */
-       li      r0,1
-       stb     r0,PACA_NAPSTATELOST(r13)
-3:     bl      machine_check_queue_event
-       MACHINE_CHECK_HANDLER_WINDUP
-       GET_PACA(r13)
-       ld      r1,PACAR1(r13)
-       /*
-        * Check what idle state this CPU was in and go back to same mode
-        * again.
-        */
-       lbz     r3,PACA_THREAD_IDLE_STATE(r13)
-       cmpwi   r3,PNV_THREAD_NAP
-       bgt     10f
-       IDLE_STATE_ENTER_SEQ(PPC_NAP)
-       /* No return */
-10:
-       cmpwi   r3,PNV_THREAD_SLEEP
-       bgt     2f
-       IDLE_STATE_ENTER_SEQ(PPC_SLEEP)
-       /* No return */
+#ifdef CONFIG_PPC_DENORMALISATION
+EXC_VIRT_BEGIN(denorm_exception, 0x5500, 0x5600)
+       b       exc_real_0x1500_denorm_exception_hv
+EXC_VIRT_END(denorm_exception, 0x5500, 0x5600)
+#else
+EXC_VIRT_NONE(0x5500, 0x5600)
+#endif
 
-2:
-       /*
-        * Go back to winkle. Please note that this thread was woken up in
-        * machine check from winkle and have not restored the per-subcore
-        * state. Hence before going back to winkle, set last bit of HSPGR0
-        * to 1. This will make sure that if this thread gets woken up
-        * again at reset vector 0x100 then it will get chance to restore
-        * the subcore state.
-        */
-       ori     r13,r13,1
-       SET_PACA(r13)
-       IDLE_STATE_ENTER_SEQ(PPC_WINKLE)
-       /* No return */
-4:
+TRAMP_KVM_SKIP(PACA_EXGEN, 0x1500)
+
+#ifdef CONFIG_PPC_DENORMALISATION
+TRAMP_REAL_BEGIN(denorm_assist)
+BEGIN_FTR_SECTION
+/*
+ * To denormalise we need to move a copy of the register to itself.
+ * For POWER6 do that here for all FP regs.
+ */
+       mfmsr   r10
+       ori     r10,r10,(MSR_FP|MSR_FE0|MSR_FE1)
+       xori    r10,r10,(MSR_FE0|MSR_FE1)
+       mtmsrd  r10
+       sync
+
+#define FMR2(n)  fmr (n), (n) ; fmr n+1, n+1
+#define FMR4(n)  FMR2(n) ; FMR2(n+2)
+#define FMR8(n)  FMR4(n) ; FMR4(n+4)
+#define FMR16(n) FMR8(n) ; FMR8(n+8)
+#define FMR32(n) FMR16(n) ; FMR16(n+16)
+       FMR32(0)
+
+FTR_SECTION_ELSE
+/*
+ * To denormalise we need to move a copy of the register to itself.
+ * For POWER7 do that here for the first 32 VSX registers only.
+ */
+       mfmsr   r10
+       oris    r10,r10,MSR_VSX@h
+       mtmsrd  r10
+       sync
+
+#define XVCPSGNDP2(n) XVCPSGNDP(n,n,n) ; XVCPSGNDP(n+1,n+1,n+1)
+#define XVCPSGNDP4(n) XVCPSGNDP2(n) ; XVCPSGNDP2(n+2)
+#define XVCPSGNDP8(n) XVCPSGNDP4(n) ; XVCPSGNDP4(n+4)
+#define XVCPSGNDP16(n) XVCPSGNDP8(n) ; XVCPSGNDP8(n+8)
+#define XVCPSGNDP32(n) XVCPSGNDP16(n) ; XVCPSGNDP16(n+16)
+       XVCPSGNDP32(0)
+
+ALT_FTR_SECTION_END_IFCLR(CPU_FTR_ARCH_206)
+
+BEGIN_FTR_SECTION
+       b       denorm_done
+END_FTR_SECTION_IFCLR(CPU_FTR_ARCH_207S)
+/*
+ * To denormalise we need to move a copy of the register to itself.
+ * For POWER8 we need to do that for all 64 VSX registers
+ */
+       XVCPSGNDP32(32)
+denorm_done:
+       mtspr   SPRN_HSRR0,r11
+       mtcrf   0x80,r9
+       ld      r9,PACA_EXGEN+EX_R9(r13)
+       RESTORE_PPR_PACA(PACA_EXGEN, r10)
+BEGIN_FTR_SECTION
+       ld      r10,PACA_EXGEN+EX_CFAR(r13)
+       mtspr   SPRN_CFAR,r10
+END_FTR_SECTION_IFSET(CPU_FTR_CFAR)
+       ld      r10,PACA_EXGEN+EX_R10(r13)
+       ld      r11,PACA_EXGEN+EX_R11(r13)
+       ld      r12,PACA_EXGEN+EX_R12(r13)
+       ld      r13,PACA_EXGEN+EX_R13(r13)
+       HRFID
+       b       .
+#endif
+
+EXC_COMMON_HV(denorm_common, 0x1500, unknown_exception)
+
+
+#ifdef CONFIG_CBE_RAS
+EXC_REAL_HV(cbe_maintenance, 0x1600, 0x1700)
+EXC_VIRT_NONE(0x5600, 0x5700)
+TRAMP_KVM_HV_SKIP(PACA_EXGEN, 0x1600)
+EXC_COMMON(cbe_maintenance_common, 0x1600, cbe_maintenance_exception)
+#else /* CONFIG_CBE_RAS */
+EXC_REAL_NONE(0x1600, 0x1700)
+EXC_VIRT_NONE(0x5600, 0x5700)
 #endif
-       /*
-        * Check if we are coming from hypervisor userspace. If yes then we
-        * continue in host kernel in V mode to deliver the MC event.
-        */
-       rldicl. r11,r12,4,63            /* See if MC hit while in HV mode. */
-       beq     5f
-       andi.   r11,r12,MSR_PR          /* See if coming from user. */
-       bne     9f                      /* continue in V mode if we are. */
 
-5:
-#ifdef CONFIG_KVM_BOOK3S_64_HANDLER
-       /*
-        * We are coming from kernel context. Check if we are coming from
-        * guest. if yes, then we can continue. We will fall through
-        * do_kvm_200->kvmppc_interrupt to deliver the MC event to guest.
-        */
-       lbz     r11,HSTATE_IN_GUEST(r13)
-       cmpwi   r11,0                   /* Check if coming from guest */
-       bne     9f                      /* continue if we are. */
+
+EXC_REAL(altivec_assist, 0x1700, 0x1800)
+EXC_VIRT(altivec_assist, 0x5700, 0x5800, 0x1700)
+TRAMP_KVM(PACA_EXGEN, 0x1700)
+#ifdef CONFIG_ALTIVEC
+EXC_COMMON(altivec_assist_common, 0x1700, altivec_assist_exception)
+#else
+EXC_COMMON(altivec_assist_common, 0x1700, unknown_exception)
 #endif
-       /*
-        * At this point we are not sure about what context we come from.
-        * Queue up the MCE event and return from the interrupt.
-        * But before that, check if this is an un-recoverable exception.
-        * If yes, then stay on emergency stack and panic.
-        */
-       andi.   r11,r12,MSR_RI
-       bne     2f
-1:     mfspr   r11,SPRN_SRR0
-       ld      r10,PACAKBASE(r13)
-       LOAD_HANDLER(r10,unrecover_mce)
-       mtspr   SPRN_SRR0,r10
-       ld      r10,PACAKMSR(r13)
-       /*
-        * We are going down. But there are chances that we might get hit by
-        * another MCE during panic path and we may run into unstable state
-        * with no way out. Hence, turn ME bit off while going down, so that
-        * when another MCE is hit during panic path, system will checkstop
-        * and hypervisor will get restarted cleanly by SP.
-        */
-       li      r3,MSR_ME
-       andc    r10,r10,r3              /* Turn off MSR_ME */
-       mtspr   SPRN_SRR1,r10
-       rfid
+
+
+#ifdef CONFIG_CBE_RAS
+EXC_REAL_HV(cbe_thermal, 0x1800, 0x1900)
+EXC_VIRT_NONE(0x5800, 0x5900)
+TRAMP_KVM_HV_SKIP(PACA_EXGEN, 0x1800)
+EXC_COMMON(cbe_thermal_common, 0x1800, cbe_thermal_exception)
+#else /* CONFIG_CBE_RAS */
+EXC_REAL_NONE(0x1800, 0x1900)
+EXC_VIRT_NONE(0x5800, 0x5900)
+#endif
+
+
+/*
+ * An interrupt came in while soft-disabled. We set paca->irq_happened, then:
+ * - If it was a decrementer interrupt, we bump the dec to max and and return.
+ * - If it was a doorbell we return immediately since doorbells are edge
+ *   triggered and won't automatically refire.
+ * - If it was a HMI we return immediately since we handled it in realmode
+ *   and it won't refire.
+ * - else we hard disable and return.
+ * This is called with r10 containing the value to OR to the paca field.
+ */
+#define MASKED_INTERRUPT(_H)                           \
+masked_##_H##interrupt:                                        \
+       std     r11,PACA_EXGEN+EX_R11(r13);             \
+       lbz     r11,PACAIRQHAPPENED(r13);               \
+       or      r11,r11,r10;                            \
+       stb     r11,PACAIRQHAPPENED(r13);               \
+       cmpwi   r10,PACA_IRQ_DEC;                       \
+       bne     1f;                                     \
+       lis     r10,0x7fff;                             \
+       ori     r10,r10,0xffff;                         \
+       mtspr   SPRN_DEC,r10;                           \
+       b       2f;                                     \
+1:     cmpwi   r10,PACA_IRQ_DBELL;                     \
+       beq     2f;                                     \
+       cmpwi   r10,PACA_IRQ_HMI;                       \
+       beq     2f;                                     \
+       mfspr   r10,SPRN_##_H##SRR1;                    \
+       rldicl  r10,r10,48,1; /* clear MSR_EE */        \
+       rotldi  r10,r10,16;                             \
+       mtspr   SPRN_##_H##SRR1,r10;                    \
+2:     mtcrf   0x80,r9;                                \
+       ld      r9,PACA_EXGEN+EX_R9(r13);               \
+       ld      r10,PACA_EXGEN+EX_R10(r13);             \
+       ld      r11,PACA_EXGEN+EX_R11(r13);             \
+       GET_SCRATCH0(r13);                              \
+       ##_H##rfid;                                     \
        b       .
-2:
-       /*
-        * Check if we have successfully handled/recovered from error, if not
-        * then stay on emergency stack and panic.
-        */
-       ld      r3,RESULT(r1)   /* Load result */
-       cmpdi   r3,0            /* see if we handled MCE successfully */
 
-       beq     1b              /* if !handled then panic */
+/*
+ * Real mode exceptions actually use this too, but alternate
+ * instruction code patches (which end up in the common .text area)
+ * cannot reach these if they are put there.
+ */
+USE_FIXED_SECTION(virt_trampolines)
+       MASKED_INTERRUPT()
+       MASKED_INTERRUPT(H)
+
+#ifdef CONFIG_KVM_BOOK3S_64_HANDLER
+TRAMP_REAL_BEGIN(kvmppc_skip_interrupt)
        /*
-        * Return from MC interrupt.
-        * Queue up the MCE event so that we can log it later, while
-        * returning from kernel or opal call.
+        * Here all GPRs are unchanged from when the interrupt happened
+        * except for r13, which is saved in SPRG_SCRATCH0.
         */
-       bl      machine_check_queue_event
-       MACHINE_CHECK_HANDLER_WINDUP
+       mfspr   r13, SPRN_SRR0
+       addi    r13, r13, 4
+       mtspr   SPRN_SRR0, r13
+       GET_SCRATCH0(r13)
        rfid
-9:
-       /* Deliver the machine check to host kernel in V mode. */
-       MACHINE_CHECK_HANDLER_WINDUP
-       b       machine_check_pSeries
+       b       .
 
-unrecover_mce:
-       /* Invoke machine_check_exception to print MCE event and panic. */
-       addi    r3,r1,STACK_FRAME_OVERHEAD
-       bl      machine_check_exception
+TRAMP_REAL_BEGIN(kvmppc_skip_Hinterrupt)
        /*
-        * We will not reach here. Even if we did, there is no way out. Call
-        * unrecoverable_exception and die.
+        * Here all GPRs are unchanged from when the interrupt happened
+        * except for r13, which is saved in SPRG_SCRATCH0.
         */
-1:     addi    r3,r1,STACK_FRAME_OVERHEAD
-       bl      unrecoverable_exception
-       b       1b
-/*
- * r13 points to the PACA, r9 contains the saved CR,
- * r12 contain the saved SRR1, SRR0 is still ready for return
- * r3 has the faulting address
- * r9 - r13 are saved in paca->exslb.
- * r3 is saved in paca->slb_r3
- * We assume we aren't going to take any exceptions during this procedure.
- */
-slb_miss_realmode:
-       mflr    r10
-#ifdef CONFIG_RELOCATABLE
-       mtctr   r11
-#endif
-
-       stw     r9,PACA_EXSLB+EX_CCR(r13)       /* save CR in exc. frame */
-       std     r10,PACA_EXSLB+EX_LR(r13)       /* save LR */
-
-#ifdef CONFIG_PPC_STD_MMU_64
-BEGIN_MMU_FTR_SECTION
-       bl      slb_allocate_realmode
-END_MMU_FTR_SECTION_IFCLR(MMU_FTR_TYPE_RADIX)
+       mfspr   r13, SPRN_HSRR0
+       addi    r13, r13, 4
+       mtspr   SPRN_HSRR0, r13
+       GET_SCRATCH0(r13)
+       hrfid
+       b       .
 #endif
-       /* All done -- return from exception. */
 
-       ld      r10,PACA_EXSLB+EX_LR(r13)
-       ld      r3,PACA_EXSLB+EX_R3(r13)
-       lwz     r9,PACA_EXSLB+EX_CCR(r13)       /* get saved CR */
+/*
+ * Ensure that any handlers that get invoked from the exception prologs
+ * above are below the first 64KB (0x10000) of the kernel image because
+ * the prologs assemble the addresses of these handlers using the
+ * LOAD_HANDLER macro, which uses an ori instruction.
+ */
 
-       mtlr    r10
-       andi.   r10,r12,MSR_RI  /* check for unrecoverable exception */
-BEGIN_MMU_FTR_SECTION
-       beq-    2f
-FTR_SECTION_ELSE
-       b       2f
-ALT_MMU_FTR_SECTION_END_IFCLR(MMU_FTR_TYPE_RADIX)
+/*** Common interrupt handlers ***/
 
-.machine       push
-.machine       "power4"
-       mtcrf   0x80,r9
-       mtcrf   0x01,r9         /* slb_allocate uses cr0 and cr7 */
-.machine       pop
 
-       RESTORE_PPR_PACA(PACA_EXSLB, r9)
-       ld      r9,PACA_EXSLB+EX_R9(r13)
-       ld      r10,PACA_EXSLB+EX_R10(r13)
-       ld      r11,PACA_EXSLB+EX_R11(r13)
-       ld      r12,PACA_EXSLB+EX_R12(r13)
-       ld      r13,PACA_EXSLB+EX_R13(r13)
-       rfid
-       b       .       /* prevent speculative execution */
+       /*
+        * Relocation-on interrupts: A subset of the interrupts can be delivered
+        * with IR=1/DR=1, if AIL==2 and MSR.HV won't be changed by delivering
+        * it.  Addresses are the same as the original interrupt addresses, but
+        * offset by 0xc000000000004000.
+        * It's impossible to receive interrupts below 0x300 via this mechanism.
+        * KVM: None of these traps are from the guest ; anything that escalated
+        * to HV=1 from HV=0 is delivered via real mode handlers.
+        */
 
-2:     mfspr   r11,SPRN_SRR0
-       ld      r10,PACAKBASE(r13)
-       LOAD_HANDLER(r10,unrecov_slb)
-       mtspr   SPRN_SRR0,r10
-       ld      r10,PACAKMSR(r13)
-       mtspr   SPRN_SRR1,r10
-       rfid
-       b       .
+       /*
+        * This uses the standard macro, since the original 0x300 vector
+        * only has extra guff for STAB-based processors -- which never
+        * come here.
+        */
 
-unrecov_slb:
-       EXCEPTION_PROLOG_COMMON(0x4100, PACA_EXSLB)
-       RECONCILE_IRQ_STATE(r10, r11)
-       bl      save_nvgprs
-1:     addi    r3,r1,STACK_FRAME_OVERHEAD
-       bl      unrecoverable_exception
-       b       1b
+EXC_COMMON_BEGIN(ppc64_runlatch_on_trampoline)
+       b       __ppc64_runlatch_on
 
+USE_FIXED_SECTION(virt_trampolines)
+       /*
+        * The __end_interrupts marker must be past the out-of-line (OOL)
+        * handlers, so that they are copied to real address 0x100 when running
+        * a relocatable kernel. This ensures they can be reached from the short
+        * trampoline handlers (like 0x4f00, 0x4f20, etc.) which branch
+        * directly, without using LOAD_HANDLER().
+        */
+       .align  7
+       .globl  __end_interrupts
+__end_interrupts:
+DEFINE_FIXED_SYMBOL(__end_interrupts)
 
 #ifdef CONFIG_PPC_970_NAP
-power4_fixup_nap:
+TRAMP_REAL_BEGIN(power4_fixup_nap)
        andc    r9,r9,r10
        std     r9,TI_LOCAL_FLAGS(r11)
        ld      r10,_LINK(r1)           /* make idle task do the */
@@ -1480,6 +1385,13 @@ power4_fixup_nap:
        blr
 #endif
 
+CLOSE_FIXED_SECTION(real_vectors);
+CLOSE_FIXED_SECTION(real_trampolines);
+CLOSE_FIXED_SECTION(virt_vectors);
+CLOSE_FIXED_SECTION(virt_trampolines);
+
+USE_TEXT_SECTION()
+
 /*
  * Hash table stuff
  */
@@ -1625,3 +1537,39 @@ END_FTR_SECTION_IFSET(CPU_FTR_CFAR)
 1:     addi    r3,r1,STACK_FRAME_OVERHEAD
        bl      kernel_bad_stack
        b       1b
+
+/*
+ * Called from arch_local_irq_enable when an interrupt needs
+ * to be resent. r3 contains 0x500, 0x900, 0xa00 or 0xe80 to indicate
+ * which kind of interrupt. MSR:EE is already off. We generate a
+ * stackframe like if a real interrupt had happened.
+ *
+ * Note: While MSR:EE is off, we need to make sure that _MSR
+ * in the generated frame has EE set to 1 or the exception
+ * handler will not properly re-enable them.
+ */
+_GLOBAL(__replay_interrupt)
+       /* We are going to jump to the exception common code which
+        * will retrieve various register values from the PACA which
+        * we don't give a damn about, so we don't bother storing them.
+        */
+       mfmsr   r12
+       mflr    r11
+       mfcr    r9
+       ori     r12,r12,MSR_EE
+       cmpwi   r3,0x900
+       beq     decrementer_common
+       cmpwi   r3,0x500
+       beq     hardware_interrupt_common
+BEGIN_FTR_SECTION
+       cmpwi   r3,0xe80
+       beq     h_doorbell_common
+       cmpwi   r3,0xea0
+       beq     h_virt_irq_common
+       cmpwi   r3,0xe60
+       beq     hmi_exception_common
+FTR_SECTION_ELSE
+       cmpwi   r3,0xa00
+       beq     doorbell_super_common
+ALT_FTR_SECTION_END_IFSET(CPU_FTR_HVMODE)
+       blr