]> git.proxmox.com Git - mirror_ubuntu-zesty-kernel.git/blobdiff - arch/powerpc/kernel/exceptions-64s.S
UBUNTU: SAUCE: powerpc/64s: Use emergency stack for kernel TM Bad Thing program checks
[mirror_ubuntu-zesty-kernel.git] / arch / powerpc / kernel / exceptions-64s.S
index d39d6118c6e922c1db0eb6faf7a7bebab0ec479b..6e670a4693ebaec8e0265ac6ddb8ea88dc6e4ef2 100644 (file)
@@ -99,7 +99,11 @@ EXC_VIRT_NONE(0x4000, 0x4100)
 #ifdef CONFIG_PPC_P7_NAP
        /*
         * If running native on arch 2.06 or later, check if we are waking up
-        * from nap/sleep/winkle, and branch to idle handler.
+        * from nap/sleep/winkle, and branch to idle handler. This tests SRR1
+        * bits 46:47. A non-0 value indicates that we are coming from a power
+        * saving state. The idle wakeup handler initially runs in real mode,
+        * but we branch to the 0xc000... address so we can turn on relocation
+        * with mtmsr.
         */
 #define IDLETEST(n)                                                    \
        BEGIN_FTR_SECTION ;                                             \
@@ -142,7 +146,7 @@ END_FTR_SECTION_IFCLR(CPU_FTR_ARCH_300)
        lbz     r0,HSTATE_HWTHREAD_REQ(r13)
        cmpwi   r0,0
        beq     1f
-       b       kvm_start_guest
+       BRANCH_TO_KVM(r10, kvm_start_guest)
 1:
 #endif
 
@@ -381,12 +385,12 @@ EXC_COMMON_BEGIN(machine_check_handle_early)
        lbz     r3,PACA_THREAD_IDLE_STATE(r13)
        cmpwi   r3,PNV_THREAD_NAP
        bgt     10f
-       IDLE_STATE_ENTER_SEQ(PPC_NAP)
+       IDLE_STATE_ENTER_SEQ_NORET(PPC_NAP)
        /* No return */
 10:
        cmpwi   r3,PNV_THREAD_SLEEP
        bgt     2f
-       IDLE_STATE_ENTER_SEQ(PPC_SLEEP)
+       IDLE_STATE_ENTER_SEQ_NORET(PPC_SLEEP)
        /* No return */
 
 2:
@@ -400,7 +404,7 @@ EXC_COMMON_BEGIN(machine_check_handle_early)
         */
        ori     r13,r13,1
        SET_PACA(r13)
-       IDLE_STATE_ENTER_SEQ(PPC_WINKLE)
+       IDLE_STATE_ENTER_SEQ_NORET(PPC_WINKLE)
        /* No return */
 4:
 #endif
@@ -717,13 +721,9 @@ 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)
 
@@ -737,6 +737,8 @@ hardware_interrupt_relon_hv:
        ALT_FTR_SECTION_END_IFSET(CPU_FTR_HVMODE)
 EXC_VIRT_END(hardware_interrupt, 0x4500, 0x4600)
 
+TRAMP_KVM(PACA_EXGEN, 0x500)
+TRAMP_KVM_HV(PACA_EXGEN, 0x500)
 EXC_COMMON_ASYNC(hardware_interrupt_common, 0x500, do_IRQ)
 
 
@@ -764,7 +766,29 @@ 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)
+       /*
+        * It's possible to receive a TM Bad Thing type program check with
+        * userspace register values (in particular r1), but with SRR1 reporting
+        * that we came from the kernel. Normally that would confuse the bad
+        * stack logic, and we would report a bad kernel stack pointer. Instead
+        * we switch to the emergency stack if we're taking a TM Bad Thing from
+        * the kernel.
+        */
+       li      r10,MSR_PR              /* Build a mask of MSR_PR ..    */
+       oris    r10,r10,0x200000@h      /* .. and SRR1_PROGTM           */
+       and     r10,r10,r12             /* Mask SRR1 with that.         */
+       srdi    r10,r10,8               /* Shift it so we can compare   */
+       cmpldi  r10,(0x200000 >> 8)     /* .. with an immediate.        */
+       bne 1f                          /* If != go to normal path.     */
+
+       /* SRR1 had PR=0 and SRR1_PROGTM=1, so use the emergency stack  */
+       andi.   r10,r12,MSR_PR;         /* Set CR0 correctly for label  */
+                                       /* 3 in EXCEPTION_PROLOG_COMMON */
+       mr      r10,r1                  /* Save r1                      */
+       ld      r1,PACAEMERGSP(r13)     /* Use emergency stack          */
+       subi    r1,r1,INT_FRAME_SIZE    /* alloc stack frame            */
+       b 3f                            /* Jump into the macro !!       */
+1:     EXCEPTION_PROLOG_COMMON(0x700, PACA_EXGEN)
        bl      save_nvgprs
        RECONCILE_IRQ_STATE(r10, r11)
        addi    r3,r1,STACK_FRAME_OVERHEAD
@@ -832,6 +856,31 @@ EXC_VIRT(trap_0b, 0x4b00, 0x4c00, 0xb00)
 TRAMP_KVM(PACA_EXGEN, 0xb00)
 EXC_COMMON(trap_0b_common, 0xb00, unknown_exception)
 
+#ifdef CONFIG_KVM_BOOK3S_64_HANDLER
+        /*
+         * 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.
+         */
+#define SYSCALL_KVMTEST                                                        \
+       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
+#define SYSCALL_KVMTEST                                                        \
+       HMT_MEDIUM
+#endif
+       
 #define LOAD_SYSCALL_HANDLER(reg)                                      \
        __LOAD_HANDLER(reg, system_call_common)
 
@@ -885,34 +934,14 @@ END_FTR_SECTION_IFSET(CPU_FTR_REAL_LE)                            \
 #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_KVMTEST
        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_KVMTEST
        SYSCALL_PSERIES_1
        SYSCALL_PSERIES_2_DIRECT
        SYSCALL_PSERIES_3
@@ -927,7 +956,7 @@ 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)
+EXC_VIRT_OOL_HV(h_data_storage, 0x4e00, 0x4e20, 0xe00)
 TRAMP_KVM_HV_SKIP(PACA_EXGEN, 0xe00)
 EXC_COMMON_BEGIN(h_data_storage_common)
        mfspr   r10,SPRN_HDAR
@@ -943,7 +972,7 @@ EXC_COMMON_BEGIN(h_data_storage_common)
 
 
 EXC_REAL_OOL_HV(h_instr_storage, 0xe20, 0xe40)
-EXC_VIRT_NONE(0x4e20, 0x4e40)
+EXC_VIRT_OOL_HV(h_instr_storage, 0x4e20, 0x4e40, 0xe20)
 TRAMP_KVM_HV(PACA_EXGEN, 0xe20)
 EXC_COMMON(h_instr_storage_common, 0xe20, unknown_exception)
 
@@ -979,7 +1008,7 @@ TRAMP_REAL_BEGIN(hmi_exception_early)
        EXCEPTION_PROLOG_COMMON_2(PACA_EXGEN)
        EXCEPTION_PROLOG_COMMON_3(0xe60)
        addi    r3,r1,STACK_FRAME_OVERHEAD
-       bl      hmi_exception_realmode
+       BRANCH_LINK_TO_FAR(hmi_exception_realmode) /* Function call ABI */
        /* Windup the stack. */
        /* Move original HSRR0 and HSRR1 into the respective regs */
        ld      r9,_MSR(r1)