Merge tag 'powerpc-4.20-2' of git://git.kernel.org/pub/scm/linux/kernel/git/powerpc...
[sfrench/cifs-2.6.git] / arch / powerpc / kernel / process.c
index bb6ac471a784e70918d25a450e31ecba3f352881..96f34730010fe3f5f778400a14a7a470d4d38142 100644 (file)
@@ -43,6 +43,7 @@
 #include <linux/uaccess.h>
 #include <linux/elf-randomize.h>
 #include <linux/pkeys.h>
+#include <linux/seq_buf.h>
 
 #include <asm/pgtable.h>
 #include <asm/io.h>
@@ -65,6 +66,7 @@
 #include <asm/livepatch.h>
 #include <asm/cpu_has_feature.h>
 #include <asm/asm-prototypes.h>
+#include <asm/stacktrace.h>
 
 #include <linux/kprobes.h>
 #include <linux/kdebug.h>
@@ -102,24 +104,18 @@ static void check_if_tm_restore_required(struct task_struct *tsk)
        }
 }
 
-static inline bool msr_tm_active(unsigned long msr)
-{
-       return MSR_TM_ACTIVE(msr);
-}
-
 static bool tm_active_with_fp(struct task_struct *tsk)
 {
-       return msr_tm_active(tsk->thread.regs->msr) &&
+       return MSR_TM_ACTIVE(tsk->thread.regs->msr) &&
                (tsk->thread.ckpt_regs.msr & MSR_FP);
 }
 
 static bool tm_active_with_altivec(struct task_struct *tsk)
 {
-       return msr_tm_active(tsk->thread.regs->msr) &&
+       return MSR_TM_ACTIVE(tsk->thread.regs->msr) &&
                (tsk->thread.ckpt_regs.msr & MSR_VEC);
 }
 #else
-static inline bool msr_tm_active(unsigned long msr) { return false; }
 static inline void check_if_tm_restore_required(struct task_struct *tsk) { }
 static inline bool tm_active_with_fp(struct task_struct *tsk) { return false; }
 static inline bool tm_active_with_altivec(struct task_struct *tsk) { return false; }
@@ -247,7 +243,8 @@ void enable_kernel_fp(void)
                 * giveup as this would save  to the 'live' structure not the
                 * checkpointed structure.
                 */
-               if(!msr_tm_active(cpumsr) && msr_tm_active(current->thread.regs->msr))
+               if (!MSR_TM_ACTIVE(cpumsr) &&
+                    MSR_TM_ACTIVE(current->thread.regs->msr))
                        return;
                __giveup_fpu(current);
        }
@@ -311,7 +308,8 @@ void enable_kernel_altivec(void)
                 * giveup as this would save  to the 'live' structure not the
                 * checkpointed structure.
                 */
-               if(!msr_tm_active(cpumsr) && msr_tm_active(current->thread.regs->msr))
+               if (!MSR_TM_ACTIVE(cpumsr) &&
+                    MSR_TM_ACTIVE(current->thread.regs->msr))
                        return;
                __giveup_altivec(current);
        }
@@ -397,7 +395,8 @@ void enable_kernel_vsx(void)
                 * giveup as this would save  to the 'live' structure not the
                 * checkpointed structure.
                 */
-               if(!msr_tm_active(cpumsr) && msr_tm_active(current->thread.regs->msr))
+               if (!MSR_TM_ACTIVE(cpumsr) &&
+                    MSR_TM_ACTIVE(current->thread.regs->msr))
                        return;
                __giveup_vsx(current);
        }
@@ -530,7 +529,7 @@ void restore_math(struct pt_regs *regs)
 {
        unsigned long msr;
 
-       if (!msr_tm_active(regs->msr) &&
+       if (!MSR_TM_ACTIVE(regs->msr) &&
                !current->thread.load_fp && !loadvec(current->thread))
                return;
 
@@ -591,12 +590,11 @@ void flush_all_to_thread(struct task_struct *tsk)
        if (tsk->thread.regs) {
                preempt_disable();
                BUG_ON(tsk != current);
-               save_all(tsk);
-
 #ifdef CONFIG_SPE
                if (tsk->thread.regs->msr & MSR_SPE)
                        tsk->thread.spefscr = mfspr(SPRN_SPEFSCR);
 #endif
+               save_all(tsk);
 
                preempt_enable();
        }
@@ -620,8 +618,6 @@ void do_send_trap(struct pt_regs *regs, unsigned long address,
 void do_break (struct pt_regs *regs, unsigned long address,
                    unsigned long error_code)
 {
-       siginfo_t info;
-
        current->thread.trap_nr = TRAP_HWBKPT;
        if (notify_die(DIE_DABR_MATCH, "dabr_match", regs, error_code,
                        11, SIGSEGV) == NOTIFY_STOP)
@@ -634,12 +630,7 @@ void do_break (struct pt_regs *regs, unsigned long address,
        hw_breakpoint_disable();
 
        /* Deliver the signal to userspace */
-       clear_siginfo(&info);
-       info.si_signo = SIGTRAP;
-       info.si_errno = 0;
-       info.si_code = TRAP_HWBKPT;
-       info.si_addr = (void __user *)address;
-       force_sig_info(SIGTRAP, &info, current);
+       force_sig_fault(SIGTRAP, TRAP_HWBKPT, (void __user *)address, current);
 }
 #endif /* CONFIG_PPC_ADV_DEBUG_REGS */
 
@@ -1259,17 +1250,16 @@ struct task_struct *__switch_to(struct task_struct *prev,
        return last;
 }
 
-static int instructions_to_print = 16;
+#define NR_INSN_TO_PRINT       16
 
 static void show_instructions(struct pt_regs *regs)
 {
        int i;
-       unsigned long pc = regs->nip - (instructions_to_print * 3 / 4 *
-                       sizeof(int));
+       unsigned long pc = regs->nip - (NR_INSN_TO_PRINT * 3 / 4 * sizeof(int));
 
        printk("Instruction dump:");
 
-       for (i = 0; i < instructions_to_print; i++) {
+       for (i = 0; i < NR_INSN_TO_PRINT; i++) {
                int instr;
 
                if (!(i % 8))
@@ -1284,7 +1274,7 @@ static void show_instructions(struct pt_regs *regs)
 #endif
 
                if (!__kernel_text_address(pc) ||
-                    probe_kernel_address((unsigned int __user *)pc, instr)) {
+                   probe_kernel_address((const void *)pc, instr)) {
                        pr_cont("XXXXXXXX ");
                } else {
                        if (regs->nip == pc)
@@ -1302,43 +1292,43 @@ static void show_instructions(struct pt_regs *regs)
 void show_user_instructions(struct pt_regs *regs)
 {
        unsigned long pc;
-       int i;
+       int n = NR_INSN_TO_PRINT;
+       struct seq_buf s;
+       char buf[96]; /* enough for 8 times 9 + 2 chars */
 
-       pc = regs->nip - (instructions_to_print * 3 / 4 * sizeof(int));
+       pc = regs->nip - (NR_INSN_TO_PRINT * 3 / 4 * sizeof(int));
 
        /*
         * Make sure the NIP points at userspace, not kernel text/data or
         * elsewhere.
         */
-       if (!__access_ok(pc, instructions_to_print * sizeof(int), USER_DS)) {
+       if (!__access_ok(pc, NR_INSN_TO_PRINT * sizeof(int), USER_DS)) {
                pr_info("%s[%d]: Bad NIP, not dumping instructions.\n",
                        current->comm, current->pid);
                return;
        }
 
-       pr_info("%s[%d]: code: ", current->comm, current->pid);
+       seq_buf_init(&s, buf, sizeof(buf));
 
-       for (i = 0; i < instructions_to_print; i++) {
-               int instr;
+       while (n) {
+               int i;
 
-               if (!(i % 8) && (i > 0)) {
-                       pr_cont("\n");
-                       pr_info("%s[%d]: code: ", current->comm, current->pid);
-               }
+               seq_buf_clear(&s);
 
-               if (probe_kernel_address((unsigned int __user *)pc, instr)) {
-                       pr_cont("XXXXXXXX ");
-               } else {
-                       if (regs->nip == pc)
-                               pr_cont("<%08x> ", instr);
-                       else
-                               pr_cont("%08x ", instr);
+               for (i = 0; i < 8 && n; i++, n--, pc += sizeof(int)) {
+                       int instr;
+
+                       if (probe_kernel_address((const void *)pc, instr)) {
+                               seq_buf_printf(&s, "XXXXXXXX ");
+                               continue;
+                       }
+                       seq_buf_printf(&s, regs->nip == pc ? "<%08x> " : "%08x ", instr);
                }
 
-               pc += sizeof(int);
+               if (!seq_buf_has_overflowed(&s))
+                       pr_info("%s[%d]: code: %s\n", current->comm,
+                               current->pid, s.buffer);
        }
-
-       pr_cont("\n");
 }
 
 struct regbit {
@@ -1492,6 +1482,15 @@ void flush_thread(void)
 #endif /* CONFIG_HAVE_HW_BREAKPOINT */
 }
 
+#ifdef CONFIG_PPC_BOOK3S_64
+void arch_setup_new_exec(void)
+{
+       if (radix_enabled())
+               return;
+       hash__setup_new_exec();
+}
+#endif
+
 int set_thread_uses_vas(void)
 {
 #ifdef CONFIG_PPC_BOOK3S_64
@@ -1712,7 +1711,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
@@ -1720,6 +1719,8 @@ int copy_thread(unsigned long clone_flags, unsigned long usp,
        return 0;
 }
 
+void preload_new_slb_context(unsigned long start, unsigned long sp);
+
 /*
  * Set up a thread for executing a new program
  */
@@ -1727,6 +1728,10 @@ void start_thread(struct pt_regs *regs, unsigned long start, unsigned long sp)
 {
 #ifdef CONFIG_PPC64
        unsigned long load_addr = regs->gpr[2]; /* saved by ELF_PLAT_INIT */
+
+#ifdef CONFIG_PPC_BOOK3S_64
+       preload_new_slb_context(start, sp);
+#endif
 #endif
 
        /*
@@ -1817,6 +1822,7 @@ void start_thread(struct pt_regs *regs, unsigned long start, unsigned long sp)
 #ifdef CONFIG_VSX
        current->thread.used_vsr = 0;
 #endif
+       current->thread.load_slb = 0;
        current->thread.load_fp = 0;
        memset(&current->thread.fp_state, 0, sizeof(current->thread.fp_state));
        current->thread.fp_save_area = NULL;