]> www.infradead.org Git - users/dwmw2/linux.git/commitdiff
powerpc/64e/interrupt: Fix nvgprs being clobbered
authorNicholas Piggin <npiggin@gmail.com>
Fri, 14 May 2021 04:40:08 +0000 (14:40 +1000)
committerMichael Ellerman <mpe@ellerman.id.au>
Fri, 14 May 2021 07:28:54 +0000 (17:28 +1000)
Some interrupt handlers have an "extra" that saves 1 or 2
registers (r14, r15) in the paca save area and makes them available to
use by the handler.

The change to always save nvgprs in exception handlers lead to some
interrupt handlers saving those scratch r14 / r15 registers into the
interrupt frame's GPR saves, which get restored on interrupt exit.

Fix this by always reloading those scratch registers from paca before
the EXCEPTION_COMMON that saves nvgprs.

Fixes: 4228b2c3d20e ("powerpc/64e/interrupt: always save nvgprs on interrupt")
Reported-by: Christian Zigotzky <chzigotzky@xenosoft.de>
Signed-off-by: Nicholas Piggin <npiggin@gmail.com>
Tested-by: Christian Zigotzky <chzigotzky@xenosoft.de>
Signed-off-by: Michael Ellerman <mpe@ellerman.id.au>
Link: https://lore.kernel.org/r/20210514044008.1955783-1-npiggin@gmail.com
arch/powerpc/kernel/exceptions-64e.S

index 7c3654b0d0f47b3f8a42436e59f3d3de0ca0232f..f1ae710274bc9142d5fd7fe6b4bd4f065044f734 100644 (file)
@@ -340,6 +340,12 @@ ret_from_mc_except:
        andi.   r10,r10,IRQS_DISABLED;  /* yes -> go out of line */ \
        bne     masked_interrupt_book3e_##n
 
+/*
+ * Additional regs must be re-loaded from paca before EXCEPTION_COMMON* is
+ * called, because that does SAVE_NVGPRS which must see the original register
+ * values, otherwise the scratch values might be restored when exiting the
+ * interrupt.
+ */
 #define PROLOG_ADDITION_2REGS_GEN(n)                                       \
        std     r14,PACA_EXGEN+EX_R14(r13);                                 \
        std     r15,PACA_EXGEN+EX_R15(r13)
@@ -535,6 +541,10 @@ __end_interrupts:
                                PROLOG_ADDITION_2REGS)
        mfspr   r14,SPRN_DEAR
        mfspr   r15,SPRN_ESR
+       std     r14,_DAR(r1)
+       std     r15,_DSISR(r1)
+       ld      r14,PACA_EXGEN+EX_R14(r13)
+       ld      r15,PACA_EXGEN+EX_R15(r13)
        EXCEPTION_COMMON(0x300)
        b       storage_fault_common
 
@@ -544,6 +554,10 @@ __end_interrupts:
                                PROLOG_ADDITION_2REGS)
        li      r15,0
        mr      r14,r10
+       std     r14,_DAR(r1)
+       std     r15,_DSISR(r1)
+       ld      r14,PACA_EXGEN+EX_R14(r13)
+       ld      r15,PACA_EXGEN+EX_R15(r13)
        EXCEPTION_COMMON(0x400)
        b       storage_fault_common
 
@@ -557,6 +571,10 @@ __end_interrupts:
                                PROLOG_ADDITION_2REGS)
        mfspr   r14,SPRN_DEAR
        mfspr   r15,SPRN_ESR
+       std     r14,_DAR(r1)
+       std     r15,_DSISR(r1)
+       ld      r14,PACA_EXGEN+EX_R14(r13)
+       ld      r15,PACA_EXGEN+EX_R15(r13)
        EXCEPTION_COMMON(0x600)
        b       alignment_more  /* no room, go out of line */
 
@@ -565,10 +583,10 @@ __end_interrupts:
        NORMAL_EXCEPTION_PROLOG(0x700, BOOKE_INTERRUPT_PROGRAM,
                                PROLOG_ADDITION_1REG)
        mfspr   r14,SPRN_ESR
-       EXCEPTION_COMMON(0x700)
        std     r14,_DSISR(r1)
-       addi    r3,r1,STACK_FRAME_OVERHEAD
        ld      r14,PACA_EXGEN+EX_R14(r13)
+       EXCEPTION_COMMON(0x700)
+       addi    r3,r1,STACK_FRAME_OVERHEAD
        bl      program_check_exception
        REST_NVGPRS(r1)
        b       interrupt_return
@@ -725,11 +743,11 @@ END_FTR_SECTION_IFSET(CPU_FTR_ALTIVEC)
         * normal exception
         */
        mfspr   r14,SPRN_DBSR
-       EXCEPTION_COMMON_CRIT(0xd00)
        std     r14,_DSISR(r1)
-       addi    r3,r1,STACK_FRAME_OVERHEAD
        ld      r14,PACA_EXCRIT+EX_R14(r13)
        ld      r15,PACA_EXCRIT+EX_R15(r13)
+       EXCEPTION_COMMON_CRIT(0xd00)
+       addi    r3,r1,STACK_FRAME_OVERHEAD
        bl      DebugException
        REST_NVGPRS(r1)
        b       interrupt_return
@@ -796,11 +814,11 @@ kernel_dbg_exc:
         * normal exception
         */
        mfspr   r14,SPRN_DBSR
-       EXCEPTION_COMMON_DBG(0xd08)
        std     r14,_DSISR(r1)
-       addi    r3,r1,STACK_FRAME_OVERHEAD
        ld      r14,PACA_EXDBG+EX_R14(r13)
        ld      r15,PACA_EXDBG+EX_R15(r13)
+       EXCEPTION_COMMON_DBG(0xd08)
+       addi    r3,r1,STACK_FRAME_OVERHEAD
        bl      DebugException
        REST_NVGPRS(r1)
        b       interrupt_return
@@ -931,11 +949,7 @@ masked_interrupt_book3e_0x2c0:
  * original values stashed away in the PACA
  */
 storage_fault_common:
-       std     r14,_DAR(r1)
-       std     r15,_DSISR(r1)
        addi    r3,r1,STACK_FRAME_OVERHEAD
-       ld      r14,PACA_EXGEN+EX_R14(r13)
-       ld      r15,PACA_EXGEN+EX_R15(r13)
        bl      do_page_fault
        b       interrupt_return
 
@@ -944,11 +958,7 @@ storage_fault_common:
  * continues here.
  */
 alignment_more:
-       std     r14,_DAR(r1)
-       std     r15,_DSISR(r1)
        addi    r3,r1,STACK_FRAME_OVERHEAD
-       ld      r14,PACA_EXGEN+EX_R14(r13)
-       ld      r15,PACA_EXGEN+EX_R15(r13)
        bl      alignment_exception
        REST_NVGPRS(r1)
        b       interrupt_return