From: Nicholas Piggin <npig...@gmail.com>

PPR is the odd register out when it comes to interrupt handling, it is
saved in current->thread.ppr while all others are saved on the stack.

The difficulty with this is that accessing thread.ppr can cause a SLB
fault, but the SLB fault handler implementation in C change had
assumed the normal exception entry handlers would not cause an SLB
fault.

Fix this by allocating room in the interrupt stack to save PPR.

Signed-off-by: Nicholas Piggin <npig...@gmail.com>
Signed-off-by: Michael Ellerman <m...@ellerman.id.au>
---
 arch/powerpc/include/asm/exception-64s.h |  9 ++++-----
 arch/powerpc/include/asm/processor.h     |  6 ++----
 arch/powerpc/include/asm/ptrace.h        |  4 ++++
 arch/powerpc/kernel/asm-offsets.c        |  2 +-
 arch/powerpc/kernel/entry_64.S           | 15 +++++----------
 arch/powerpc/kernel/process.c            |  2 +-
 arch/powerpc/kernel/ptrace.c             |  4 ++--
 7 files changed, 19 insertions(+), 23 deletions(-)

diff --git a/arch/powerpc/include/asm/exception-64s.h 
b/arch/powerpc/include/asm/exception-64s.h
index a86feddddad0..403d73898a9a 100644
--- a/arch/powerpc/include/asm/exception-64s.h
+++ b/arch/powerpc/include/asm/exception-64s.h
@@ -236,11 +236,10 @@
  * PPR save/restore macros used in exceptions_64s.S  
  * Used for P7 or later processors
  */
-#define SAVE_PPR(area, ra, rb)                                         \
+#define SAVE_PPR(area, ra)                                             \
 BEGIN_FTR_SECTION_NESTED(940)                                          \
-       ld      ra,PACACURRENT(r13);                                    \
-       ld      rb,area+EX_PPR(r13);    /* Read PPR from paca */        \
-       std     rb,TASKTHREADPPR(ra);                                   \
+       ld      ra,area+EX_PPR(r13);    /* Read PPR from paca */        \
+       std     ra,_PPR(r1);                                            \
 END_FTR_SECTION_NESTED(CPU_FTR_HAS_PPR,CPU_FTR_HAS_PPR,940)
 
 #define RESTORE_PPR_PACA(area, ra)                                     \
@@ -508,7 +507,7 @@ END_FTR_SECTION_NESTED(ftr,ftr,943)
 3:     EXCEPTION_PROLOG_COMMON_1();                                       \
        beq     4f;                     /* if from kernel mode          */ \
        ACCOUNT_CPU_USER_ENTRY(r13, r9, r10);                              \
-       SAVE_PPR(area, r9, r10);                                           \
+       SAVE_PPR(area, r9);                                                \
 4:     EXCEPTION_PROLOG_COMMON_2(area)                                    \
        EXCEPTION_PROLOG_COMMON_3(n)                                       \
        ACCOUNT_STOLEN_TIME
diff --git a/arch/powerpc/include/asm/processor.h 
b/arch/powerpc/include/asm/processor.h
index 52fadded5c1e..3fefb8a65b17 100644
--- a/arch/powerpc/include/asm/processor.h
+++ b/arch/powerpc/include/asm/processor.h
@@ -32,9 +32,9 @@
 /* Default SMT priority is set to 3. Use 11- 13bits to save priority. */
 #define PPR_PRIORITY 3
 #ifdef __ASSEMBLY__
-#define INIT_PPR (PPR_PRIORITY << 50)
+#define DEFAULT_PPR (PPR_PRIORITY << 50)
 #else
-#define INIT_PPR ((u64)PPR_PRIORITY << 50)
+#define DEFAULT_PPR ((u64)PPR_PRIORITY << 50)
 #endif /* __ASSEMBLY__ */
 #endif /* CONFIG_PPC64 */
 
@@ -341,7 +341,6 @@ struct thread_struct {
         * onwards.
         */
        int             dscr_inherit;
-       unsigned long   ppr;    /* used to save/restore SMT priority */
        unsigned long   tidr;
 #endif
 #ifdef CONFIG_PPC_BOOK3S_64
@@ -389,7 +388,6 @@ struct thread_struct {
        .regs = (struct pt_regs *)INIT_SP - 1, /* XXX bogus, I think */ \
        .addr_limit = KERNEL_DS, \
        .fpexc_mode = 0, \
-       .ppr = INIT_PPR, \
        .fscr = FSCR_TAR | FSCR_EBB \
 }
 #endif
diff --git a/arch/powerpc/include/asm/ptrace.h 
b/arch/powerpc/include/asm/ptrace.h
index 3dd15024db93..2ba2a1e52291 100644
--- a/arch/powerpc/include/asm/ptrace.h
+++ b/arch/powerpc/include/asm/ptrace.h
@@ -51,6 +51,10 @@ struct pt_regs
                        unsigned long result;
                };
        };
+
+#ifdef CONFIG_PPC64
+       unsigned long ppr;
+#endif
 };
 #endif
 
diff --git a/arch/powerpc/kernel/asm-offsets.c 
b/arch/powerpc/kernel/asm-offsets.c
index 2eb4923f8468..92156c61d21c 100644
--- a/arch/powerpc/kernel/asm-offsets.c
+++ b/arch/powerpc/kernel/asm-offsets.c
@@ -89,7 +89,6 @@ int main(void)
 #ifdef CONFIG_PPC64
        DEFINE(SIGSEGV, SIGSEGV);
        DEFINE(NMI_MASK, NMI_MASK);
-       OFFSET(TASKTHREADPPR, task_struct, thread.ppr);
 #else
        OFFSET(THREAD_INFO, task_struct, stack);
        DEFINE(THREAD_INFO_GAP, _ALIGN_UP(sizeof(struct thread_info), 16));
@@ -323,6 +322,7 @@ int main(void)
        STACK_PT_REGS_OFFSET(_ESR, dsisr);
 #else /* CONFIG_PPC64 */
        STACK_PT_REGS_OFFSET(SOFTE, softe);
+       STACK_PT_REGS_OFFSET(_PPR, ppr);
 #endif /* CONFIG_PPC64 */
 
 #if defined(CONFIG_PPC32)
diff --git a/arch/powerpc/kernel/entry_64.S b/arch/powerpc/kernel/entry_64.S
index 7db00ee6be48..7b1693adff2a 100644
--- a/arch/powerpc/kernel/entry_64.S
+++ b/arch/powerpc/kernel/entry_64.S
@@ -386,10 +386,9 @@ END_FTR_SECTION_IFSET(CPU_FTR_HAS_PPR)
 
 4:     /* Anything else left to do? */
 BEGIN_FTR_SECTION
-       lis     r3,INIT_PPR@highest     /* Set thread.ppr = 3 */
-       ld      r10,PACACURRENT(r13)
+       lis     r3,DEFAULT_PPR@highest  /* Set default PPR */
        sldi    r3,r3,32        /* bits 11-13 are used for ppr */
-       std     r3,TASKTHREADPPR(r10)
+       std     r3,_PPR(r1)
 END_FTR_SECTION_IFSET(CPU_FTR_HAS_PPR)
 
        andi.   r0,r9,(_TIF_SYSCALL_DOTRACE|_TIF_SINGLESTEP)
@@ -942,12 +941,6 @@ fast_exception_return:
        andi.   r0,r3,MSR_RI
        beq-    .Lunrecov_restore
 
-       /* Load PPR from thread struct before we clear MSR:RI */
-BEGIN_FTR_SECTION
-       ld      r2,PACACURRENT(r13)
-       ld      r2,TASKTHREADPPR(r2)
-END_FTR_SECTION_IFSET(CPU_FTR_HAS_PPR)
-
        /*
         * Clear RI before restoring r13.  If we are returning to
         * userspace and we take an exception after restoring r13,
@@ -968,7 +961,9 @@ END_FTR_SECTION_IFSET(CPU_FTR_HAS_PPR)
        andi.   r0,r3,MSR_PR
        beq     1f
 BEGIN_FTR_SECTION
-       mtspr   SPRN_PPR,r2     /* Restore PPR */
+       /* Restore PPR */
+       ld      r2,_PPR(r1)
+       mtspr   SPRN_PPR,r2
 END_FTR_SECTION_IFSET(CPU_FTR_HAS_PPR)
        ACCOUNT_CPU_USER_EXIT(r13, r2, r4)
        REST_GPR(13, r1)
diff --git a/arch/powerpc/kernel/process.c b/arch/powerpc/kernel/process.c
index 0ed8d0968515..f9d1cca28cce 100644
--- a/arch/powerpc/kernel/process.c
+++ b/arch/powerpc/kernel/process.c
@@ -1710,7 +1710,7 @@ int copy_thread(unsigned long clone_flags, unsigned long 
usp,
                p->thread.dscr = mfspr(SPRN_DSCR);
        }
        if (cpu_has_feature(CPU_FTR_HAS_PPR))
-               p->thread.ppr = INIT_PPR;
+               childregs->ppr = DEFAULT_PPR;
 
        p->thread.tidr = 0;
 #endif
diff --git a/arch/powerpc/kernel/ptrace.c b/arch/powerpc/kernel/ptrace.c
index c7d0d0c1e34d..afb819f4ca68 100644
--- a/arch/powerpc/kernel/ptrace.c
+++ b/arch/powerpc/kernel/ptrace.c
@@ -1609,7 +1609,7 @@ static int ppr_get(struct task_struct *target,
                      void *kbuf, void __user *ubuf)
 {
        return user_regset_copyout(&pos, &count, &kbuf, &ubuf,
-                                  &target->thread.ppr, 0, sizeof(u64));
+                                  &target->thread.regs->ppr, 0, sizeof(u64));
 }
 
 static int ppr_set(struct task_struct *target,
@@ -1618,7 +1618,7 @@ static int ppr_set(struct task_struct *target,
                      const void *kbuf, const void __user *ubuf)
 {
        return user_regset_copyin(&pos, &count, &kbuf, &ubuf,
-                                 &target->thread.ppr, 0, sizeof(u64));
+                                 &target->thread.regs->ppr, 0, sizeof(u64));
 }
 
 static int dscr_get(struct task_struct *target,
-- 
2.17.1

Reply via email to