]> git.kernelconcepts.de Git - karo-tx-linux.git/blobdiff - arch/powerpc/kernel/exceptions-64s.S
powerpc/64s: Avoid saving faulting address into EX_DAR in SLB miss
[karo-tx-linux.git] / arch / powerpc / kernel / exceptions-64s.S
index a9312b52fe6fdc5336e82cdd55f5f86b2729c6e3..fe3bc52aadf88f42e7b0d648295c82091a3772fb 100644 (file)
@@ -99,7 +99,9 @@ EXC_VIRT_NONE(0x4000, 0x100)
 #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. 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 ;                                             \
@@ -107,7 +109,7 @@ EXC_VIRT_NONE(0x4000, 0x100)
        rlwinm. r10,r10,47-31,30,31 ;                                   \
        beq-    1f ;                                                    \
        cmpwi   cr3,r10,2 ;                                             \
-       BRANCH_TO_COMMON(r10, system_reset_idle_common) ;               \
+       BRANCH_TO_C000(r10, system_reset_idle_common) ;                 \
 1:                                                                     \
        END_FTR_SECTION_IFSET(CPU_FTR_HVMODE | CPU_FTR_ARCH_206)
 #else
@@ -128,6 +130,7 @@ EXC_VIRT_NONE(0x4100, 0x100)
 
 #ifdef CONFIG_PPC_P7_NAP
 EXC_COMMON_BEGIN(system_reset_idle_common)
+       mfspr   r12,SPRN_SRR1
        b       pnv_powersave_wakeup
 #endif
 
@@ -391,9 +394,7 @@ EXC_COMMON_BEGIN(machine_check_handle_early)
         */
        BEGIN_FTR_SECTION
        rlwinm. r11,r12,47-31,30,31
-       beq-    4f
-       BRANCH_TO_COMMON(r10, machine_check_idle_common)
-4:
+       bne     machine_check_idle_common
        END_FTR_SECTION_IFSET(CPU_FTR_HVMODE | CPU_FTR_ARCH_206)
 #endif
 
@@ -630,7 +631,6 @@ EXC_COMMON_BEGIN(slb_miss_realmode)
 
        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)
 
        crset   4*cr0+eq
 #ifdef CONFIG_PPC_STD_MMU_64
@@ -640,11 +640,10 @@ END_MMU_FTR_SECTION_IFCLR(MMU_FTR_TYPE_RADIX)
 #endif
 
        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
 
-       beq     8f              /* if bad address, make full stack frame */
+       beq-    8f              /* if bad address, make full stack frame */
 
        andi.   r10,r12,MSR_RI  /* check for unrecoverable exception */
        beq-    2f
@@ -659,6 +658,7 @@ END_MMU_FTR_SECTION_IFCLR(MMU_FTR_TYPE_RADIX)
 .machine       pop
 
        RESTORE_PPR_PACA(PACA_EXSLB, r9)
+       ld      r3,PACA_EXSLB+EX_R3(r13)
        ld      r9,PACA_EXSLB+EX_R9(r13)
        ld      r10,PACA_EXSLB+EX_R10(r13)
        ld      r11,PACA_EXSLB+EX_R11(r13)
@@ -667,7 +667,9 @@ END_MMU_FTR_SECTION_IFCLR(MMU_FTR_TYPE_RADIX)
        rfid
        b       .       /* prevent speculative execution */
 
-2:     mfspr   r11,SPRN_SRR0
+2:     std     r3,PACA_EXSLB+EX_DAR(r13)
+       ld      r3,PACA_EXSLB+EX_R3(r13)
+       mfspr   r11,SPRN_SRR0
        LOAD_HANDLER(r10,unrecov_slb)
        mtspr   SPRN_SRR0,r10
        ld      r10,PACAKMSR(r13)
@@ -675,7 +677,9 @@ END_MMU_FTR_SECTION_IFCLR(MMU_FTR_TYPE_RADIX)
        rfid
        b       .
 
-8:     mfspr   r11,SPRN_SRR0
+8:     std     r3,PACA_EXSLB+EX_DAR(r13)
+       ld      r3,PACA_EXSLB+EX_R3(r13)
+       mfspr   r11,SPRN_SRR0
        LOAD_HANDLER(r10,bad_addr_slb)
        mtspr   SPRN_SRR0,r10
        ld      r10,PACAKMSR(r13)
@@ -823,46 +827,80 @@ EXC_VIRT(trap_0b, 0x4b00, 0x100, 0xb00)
 TRAMP_KVM(PACA_EXGEN, 0xb00)
 EXC_COMMON(trap_0b_common, 0xb00, unknown_exception)
 
+/*
+ * system call / hypercall (0xc00, 0x4c00)
+ *
+ * The system call exception is invoked with "sc 0" and does not alter HV bit.
+ * There is support for kernel code to invoke system calls but there are no
+ * in-tree users.
+ *
+ * The hypercall is invoked with "sc 1" and sets HV=1.
+ *
+ * In HPT, sc 1 always goes to 0xc00 real mode. In RADIX, sc 1 can go to
+ * 0x4c00 virtual mode.
+ *
+ * Call convention:
+ *
+ * syscall register convention is in Documentation/powerpc/syscall64-abi.txt
+ *
+ * For hypercalls, the register convention is as follows:
+ * r0 volatile
+ * r1-2 nonvolatile
+ * r3 volatile parameter and return value for status
+ * r4-r10 volatile input and output value
+ * r11 volatile hypercall number and output value
+ * r12 volatile
+ * r13-r31 nonvolatile
+ * LR nonvolatile
+ * CTR volatile
+ * XER volatile
+ * CR0-1 CR5-7 volatile
+ * CR2-4 nonvolatile
+ * Other registers nonvolatile
+ *
+ * The intersection of volatile registers that don't contain possible
+ * inputs is: r12, cr0, xer, ctr. We may use these as scratch regs
+ * upon entry without saving.
+ */
 #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.
-         */
+       /*
+        * There is a little bit of juggling to get syscall and hcall
+        * working well. Save r10 in ctr to be restored in case it is a
+        * hcall.
+        *
+        * Userspace syscalls have already saved the PPR, hcalls must save
+        * it before setting HMT_MEDIUM.
+        */
 #define SYSCALL_KVMTEST                                                        \
-       SET_SCRATCH0(r13);                                              \
+       mr      r12,r13;                                                \
        GET_PACA(r13);                                                  \
-       std     r9,PACA_EXGEN+EX_R9(r13);                               \
-       OPT_GET_SPR(r9, SPRN_PPR, CPU_FTR_HAS_PPR);                     \
+       mtctr   r10;                                                    \
+       KVMTEST_PR(0xc00); /* uses r10, branch to do_kvm_0xc00_system_call */ \
        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)
+       mr      r9,r12;                                                 \
 
 #else
 #define SYSCALL_KVMTEST                                                        \
-       HMT_MEDIUM
+       HMT_MEDIUM;                                                     \
+       mr      r9,r13;                                                 \
+       GET_PACA(r13);
 #endif
        
 #define LOAD_SYSCALL_HANDLER(reg)                                      \
        __LOAD_HANDLER(reg, system_call_common)
 
-/* Syscall routine is used twice, in reloc-off and reloc-on paths */
-#define SYSCALL_PSERIES_1                                      \
+#define SYSCALL_FASTENDIAN_TEST                                        \
 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                                         \
+/*
+ * After SYSCALL_KVMTEST, we reach here with PACA in r13, r13 in r9,
+ * and HMT_MEDIUM.
+ */
+#define SYSCALL_REAL                                           \
+       mfspr   r11,SPRN_SRR0 ;                                 \
        mfspr   r12,SPRN_SRR1 ;                                 \
        LOAD_SYSCALL_HANDLER(r10) ;                             \
        mtspr   SPRN_SRR0,r10 ;                                 \
@@ -871,11 +909,12 @@ END_FTR_SECTION_IFSET(CPU_FTR_REAL_LE)                            \
        rfid ;                                                  \
        b       . ;     /* prevent speculative execution */
 
-#define SYSCALL_PSERIES_3                                      \
+#define SYSCALL_FASTENDIAN                                     \
        /* Fast LE/BE switch system call */                     \
 1:     mfspr   r12,SPRN_SRR1 ;                                 \
        xori    r12,r12,MSR_LE ;                                \
        mtspr   SPRN_SRR1,r12 ;                                 \
+       mr      r13,r9 ;                                        \
        rfid ;          /* return to userspace */               \
        b       . ;     /* prevent speculative execution */
 
@@ -884,16 +923,18 @@ END_FTR_SECTION_IFSET(CPU_FTR_REAL_LE)                            \
         * 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 ;                                           \
+#define SYSCALL_VIRT                                           \
+       LOAD_SYSCALL_HANDLER(r10) ;                             \
+       mtctr   r10 ;                                           \
+       mfspr   r11,SPRN_SRR0 ;                                 \
        mfspr   r12,SPRN_SRR1 ;                                 \
        li      r10,MSR_RI ;                                    \
        mtmsrd  r10,1 ;                                         \
        bctr ;
 #else
        /* We can branch directly */
-#define SYSCALL_PSERIES_2_DIRECT                               \
+#define SYSCALL_VIRT                                           \
+       mfspr   r11,SPRN_SRR0 ;                                 \
        mfspr   r12,SPRN_SRR1 ;                                 \
        li      r10,MSR_RI ;                                    \
        mtmsrd  r10,1 ;                 /* Set RI (EE=0) */     \
@@ -901,20 +942,43 @@ END_FTR_SECTION_IFSET(CPU_FTR_REAL_LE)                            \
 #endif
 
 EXC_REAL_BEGIN(system_call, 0xc00, 0x100)
-       SYSCALL_KVMTEST
-       SYSCALL_PSERIES_1
-       SYSCALL_PSERIES_2_RFID
-       SYSCALL_PSERIES_3
+       SYSCALL_KVMTEST /* loads PACA into r13, and saves r13 to r9 */
+       SYSCALL_FASTENDIAN_TEST
+       SYSCALL_REAL
+       SYSCALL_FASTENDIAN
 EXC_REAL_END(system_call, 0xc00, 0x100)
 
 EXC_VIRT_BEGIN(system_call, 0x4c00, 0x100)
-       SYSCALL_KVMTEST
-       SYSCALL_PSERIES_1
-       SYSCALL_PSERIES_2_DIRECT
-       SYSCALL_PSERIES_3
+       SYSCALL_KVMTEST /* loads PACA into r13, and saves r13 to r9 */
+       SYSCALL_FASTENDIAN_TEST
+       SYSCALL_VIRT
+       SYSCALL_FASTENDIAN
 EXC_VIRT_END(system_call, 0x4c00, 0x100)
 
-TRAMP_KVM(PACA_EXGEN, 0xc00)
+#ifdef CONFIG_KVM_BOOK3S_64_HANDLER
+       /*
+        * This is a hcall, so register convention is as above, with these
+        * differences:
+        * r13 = PACA
+        * r12 = orig r13
+        * ctr = orig r10
+        */
+TRAMP_KVM_BEGIN(do_kvm_0xc00)
+        /*
+         * 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).
+         */
+       OPT_GET_SPR(r0, SPRN_PPR, CPU_FTR_HAS_PPR)
+       HMT_MEDIUM
+       OPT_SAVE_REG_TO_PACA(PACA_EXGEN+EX_PPR, r0, CPU_FTR_HAS_PPR)
+       mfctr   r10
+       SET_SCRATCH0(r12)
+       std     r9,PACA_EXGEN+EX_R9(r13)
+       mfcr    r9
+       std     r10,PACA_EXGEN+EX_R10(r13)
+       KVM_HANDLER(PACA_EXGEN, EXC_STD, 0xc00)
+#endif
 
 
 EXC_REAL(single_step, 0xd00, 0x100)
@@ -1553,6 +1617,25 @@ END_FTR_SECTION_IFSET(CPU_FTR_CFAR)
        bl      kernel_bad_stack
        b       1b
 
+/*
+ * When doorbell is triggered from system reset wakeup, the message is
+ * not cleared, so it would fire again when EE is enabled.
+ *
+ * When coming from local_irq_enable, there may be the same problem if
+ * we were hard disabled.
+ *
+ * Execute msgclr to clear pending exceptions before handling it.
+ */
+h_doorbell_common_msgclr:
+       LOAD_REG_IMMEDIATE(r3, PPC_DBELL_MSGTYPE << (63-36))
+       PPC_MSGCLR(3)
+       b       h_doorbell_common
+
+doorbell_super_common_msgclr:
+       LOAD_REG_IMMEDIATE(r3, PPC_DBELL_MSGTYPE << (63-36))
+       PPC_MSGCLRP(3)
+       b       doorbell_super_common
+
 /*
  * Called from arch_local_irq_enable when an interrupt needs
  * to be resent. r3 contains 0x500, 0x900, 0xa00 or 0xe80 to indicate
@@ -1562,6 +1645,10 @@ END_FTR_SECTION_IFSET(CPU_FTR_CFAR)
  * 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.
+ *
+ * Note that we don't specify LR as the NIP (return address) for
+ * the interrupt because that would unbalance the return branch
+ * predictor.
  */
 _GLOBAL(__replay_interrupt)
        /* We are going to jump to the exception common code which
@@ -1569,7 +1656,7 @@ _GLOBAL(__replay_interrupt)
         * we don't give a damn about, so we don't bother storing them.
         */
        mfmsr   r12
-       mflr    r11
+       LOAD_REG_ADDR(r11, .L__replay_interrupt_return)
        mfcr    r9
        ori     r12,r12,MSR_EE
        cmpwi   r3,0x900
@@ -1578,13 +1665,15 @@ _GLOBAL(__replay_interrupt)
        beq     hardware_interrupt_common
 BEGIN_FTR_SECTION
        cmpwi   r3,0xe80
-       beq     h_doorbell_common
+       beq     h_doorbell_common_msgclr
        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
+       beq     doorbell_super_common_msgclr
 ALT_FTR_SECTION_END_IFSET(CPU_FTR_HVMODE)
+.L__replay_interrupt_return:
        blr
+