Merge tag 'powerpc-4.16-1' of git://git.kernel.org/pub/scm/linux/kernel/git/powerpc...
[linux-2.6-microblaze.git] / arch / powerpc / kernel / traps.c
index c93f1e6..1e48d15 100644 (file)
@@ -20,6 +20,7 @@
 #include <linux/sched/debug.h>
 #include <linux/kernel.h>
 #include <linux/mm.h>
+#include <linux/pkeys.h>
 #include <linux/stddef.h>
 #include <linux/unistd.h>
 #include <linux/ptrace.h>
@@ -38,6 +39,8 @@
 #include <linux/ratelimit.h>
 #include <linux/context_tracking.h>
 #include <linux/smp.h>
+#include <linux/console.h>
+#include <linux/kmsg_dump.h>
 
 #include <asm/emulated_ops.h>
 #include <asm/pgtable.h>
@@ -142,6 +145,28 @@ static int die_owner = -1;
 static unsigned int die_nest_count;
 static int die_counter;
 
+extern void panic_flush_kmsg_start(void)
+{
+       /*
+        * These are mostly taken from kernel/panic.c, but tries to do
+        * relatively minimal work. Don't use delay functions (TB may
+        * be broken), don't crash dump (need to set a firmware log),
+        * don't run notifiers. We do want to get some information to
+        * Linux console.
+        */
+       console_verbose();
+       bust_spinlocks(1);
+}
+
+extern void panic_flush_kmsg_end(void)
+{
+       printk_safe_flush_on_panic();
+       kmsg_dump(KMSG_DUMP_PANIC);
+       bust_spinlocks(0);
+       debug_locks_off();
+       console_flush_on_panic();
+}
+
 static unsigned long oops_begin(struct pt_regs *regs)
 {
        int cpu;
@@ -266,7 +291,9 @@ void user_single_step_siginfo(struct task_struct *tsk,
        info->si_addr = (void __user *)regs->nip;
 }
 
-void _exception(int signr, struct pt_regs *regs, int code, unsigned long addr)
+
+void _exception_pkey(int signr, struct pt_regs *regs, int code,
+               unsigned long addr, int key)
 {
        siginfo_t info;
        const char fmt32[] = KERN_INFO "%s[%d]: unhandled signal %d " \
@@ -289,13 +316,27 @@ void _exception(int signr, struct pt_regs *regs, int code, unsigned long addr)
                local_irq_enable();
 
        current->thread.trap_nr = code;
+
+       /*
+        * Save all the pkey registers AMR/IAMR/UAMOR. Eg: Core dumps need
+        * to capture the content, if the task gets killed.
+        */
+       thread_pkey_regs_save(&current->thread);
+
        memset(&info, 0, sizeof(info));
        info.si_signo = signr;
        info.si_code = code;
        info.si_addr = (void __user *) addr;
+       info.si_pkey = key;
+
        force_sig_info(signr, &info, current);
 }
 
+void _exception(int signr, struct pt_regs *regs, int code, unsigned long addr)
+{
+       _exception_pkey(signr, regs, code, addr, 0);
+}
+
 void system_reset_exception(struct pt_regs *regs)
 {
        /*
@@ -337,7 +378,7 @@ void system_reset_exception(struct pt_regs *regs)
         * No debugger or crash dump registered, print logs then
         * panic.
         */
-       __die("System Reset", regs, SIGABRT);
+       die("System Reset", regs, SIGABRT);
 
        mdelay(2*MSEC_PER_SEC); /* Wait a little while for others to print */
        add_taint(TAINT_DIE, LOCKDEP_NOW_UNRELIABLE);
@@ -1564,7 +1605,7 @@ void facility_unavailable_exception(struct pt_regs *regs)
        u8 status;
        bool hv;
 
-       hv = (regs->trap == 0xf80);
+       hv = (TRAP(regs) == 0xf80);
        if (hv)
                value = mfspr(SPRN_HFSCR);
        else
@@ -2113,13 +2154,13 @@ static int __init ppc_warn_emulated_init(void)
        if (!dir)
                return -ENOMEM;
 
-       d = debugfs_create_u32("do_warn", S_IRUGO | S_IWUSR, dir,
+       d = debugfs_create_u32("do_warn", 0644, dir,
                               &ppc_warn_emulated);
        if (!d)
                goto fail;
 
        for (i = 0; i < sizeof(ppc_emulated)/sizeof(*entries); i++) {
-               d = debugfs_create_u32(entries[i].name, S_IRUGO | S_IWUSR, dir,
+               d = debugfs_create_u32(entries[i].name, 0644, dir,
                                       (u32 *)&entries[i].val.counter);
                if (!d)
                        goto fail;