// SPDX-License-Identifier: GPL-2.0-or-later/* * Copyright (C) 1995-1996 Gary Thomas (gdt@linuxppc.org) * Copyright 2007-2010 Freescale Semiconductor, Inc. * * Modified by Cort Dougan (cort@cs.nmt.edu) * and Paul Mackerras (paulus@samba.org) */ /* * This file handles the architecture-dependent parts of hardware exceptions */ #include <linux/errno.h>#include <linux/sched.h>#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>#include <linux/user.h>#include <linux/interrupt.h>#include <linux/init.h>#include <linux/extable.h>#include <linux/module.h> /* print_modules */#include <linux/prctl.h>#include <linux/delay.h>#include <linux/kprobes.h>#include <linux/kexec.h>#include <linux/backlight.h>#include <linux/bug.h>#include <linux/kdebug.h>#include <linux/ratelimit.h>#include <linux/context_tracking.h>#include <linux/smp.h>#include <linux/console.h>#include <linux/kmsg_dump.h>#include <linux/debugfs.h> #include <asm/emulated_ops.h>#include <linux/uaccess.h>#include <asm/interrupt.h>#include <asm/io.h>#include <asm/machdep.h>#include <asm/rtas.h>#include <asm/pmc.h>#include <asm/reg.h>#ifdef CONFIG_PMAC_BACKLIGHT#include <asm/backlight.h>#endif#ifdef CONFIG_PPC64#include <asm/firmware.h>#include <asm/processor.h>#endif#include <asm/kexec.h>#include <asm/ppc-opcode.h>#include <asm/rio.h>#include <asm/fadump.h>#include <asm/switch_to.h>#include <asm/tm.h>#include <asm/debug.h>#include <asm/asm-prototypes.h>#include <asm/hmi.h>#include <sysdev/fsl_pci.h>#include <asm/kprobes.h>#include <asm/stacktrace.h>#include <asm/nmi.h>#include <asm/disassemble.h>#include <asm/udbg.h> #if defined(CONFIG_DEBUGGER) || defined(CONFIG_KEXEC_CORE)int (*__debugger)(struct pt_regs *regs) __read_mostly;int (*__debugger_ipi)(struct pt_regs *regs) __read_mostly;int (*__debugger_bpt)(struct pt_regs *regs) __read_mostly;int (*__debugger_sstep)(struct pt_regs *regs) __read_mostly;int (*__debugger_iabr_match)(struct pt_regs *regs) __read_mostly;int (*__debugger_break_match)(struct pt_regs *regs) __read_mostly;int (*__debugger_fault_handler)(struct pt_regs *regs) __read_mostly; EXPORT_SYMBOL(__debugger);EXPORT_SYMBOL(__debugger_ipi);EXPORT_SYMBOL(__debugger_bpt);EXPORT_SYMBOL(__debugger_sstep);EXPORT_SYMBOL(__debugger_iabr_match);EXPORT_SYMBOL(__debugger_break_match);EXPORT_SYMBOL(__debugger_fault_handler);#endif /* Transactional Memory trap debug */#ifdef TM_DEBUG_SW#define TM_DEBUG(x...) printk(KERN_INFO x)#else#define TM_DEBUG(x...) do { } while(0)#endif static const char *signame(int signr){ switch (signr) { case SIGBUS: return "bus error"; case SIGFPE: return "floating point exception"; case SIGILL: return "illegal instruction"; case SIGSEGV: return "segfault"; case SIGTRAP: return "unhandled trap"; } return "unknown signal";} /* * Trap & Exception support */ #ifdef CONFIG_PMAC_BACKLIGHTstatic void pmac_backlight_unblank(void){ mutex_lock(&pmac_backlight_mutex); if (pmac_backlight) { struct backlight_properties *props; props = &pmac_backlight->props; props->brightness = props->max_brightness; props->power = BACKLIGHT_POWER_ON; backlight_update_status(pmac_backlight); } mutex_unlock(&pmac_backlight_mutex);}#elsestatic inline void pmac_backlight_unblank(void) { }#endif /* * If oops/die is expected to crash the machine, return true here. * * This should not be expected to be 100% accurate, there may be * notifiers registered or other unexpected conditions that may bring * down the kernel. Or if the current process in the kernel is holding * locks or has other critical state, the kernel may become effectively * unusable anyway. */bool die_will_crash(void){ if (should_fadump_crash()) return true; if (kexec_should_crash(current)) return true; if (in_interrupt() || panic_on_oops || !current->pid || is_global_init(current)) return true; return false;} static arch_spinlock_t die_lock = __ARCH_SPIN_LOCK_UNLOCKED;static int die_owner = -1;static unsigned int die_nest_count;static int die_counter; 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);} void panic_flush_kmsg_end(void){ kmsg_dump(KMSG_DUMP_PANIC); bust_spinlocks(0); debug_locks_off(); console_flush_on_panic(CONSOLE_FLUSH_PENDING);} static unsigned long oops_begin(struct pt_regs *regs){ int cpu; unsigned long flags; oops_enter(); /* racy, but better than risking deadlock. */ raw_local_irq_save(flags); cpu = smp_processor_id(); if (!arch_spin_trylock(&die_lock)) { if (cpu == die_owner) /* nested oops. should stop eventually */; else arch_spin_lock(&die_lock); } die_nest_count++; die_owner = cpu; console_verbose(); bust_spinlocks(1); if (machine_is(powermac)) pmac_backlight_unblank(); return flags;}NOKPROBE_SYMBOL(oops_begin); static void oops_end(unsigned long flags, struct pt_regs *regs, int signr){ bust_spinlocks(0); add_taint(TAINT_DIE, LOCKDEP_NOW_UNRELIABLE); die_nest_count--; oops_exit(); printk("\n"); if (!die_nest_count) { /* Nest count reaches zero, release the lock. */ die_owner = -1; arch_spin_unlock(&die_lock); } raw_local_irq_restore(flags); /* * system_reset_excption handles debugger, crash dump, panic, for 0x100 */ if (TRAP(regs) == INTERRUPT_SYSTEM_RESET) return; crash_fadump(regs, "die oops"); if (kexec_should_crash(current)) crash_kexec(regs); if (!signr) return; /* * While our oops output is serialised by a spinlock, output * from panic() called below can race and corrupt it. If we * know we are going to panic, delay for 1 second so we have a * chance to get clean backtraces from all CPUs that are oopsing. */ if (in_interrupt() || panic_on_oops || !current->pid || is_global_init(current)) { mdelay(MSEC_PER_SEC); } if (panic_on_oops) panic("Fatal exception"); make_task_dead(signr);}NOKPROBE_SYMBOL(oops_end); static char *get_mmu_str(void){ if (early_radix_enabled()) return " MMU=Radix"; if (early_mmu_has_feature(MMU_FTR_HPTE_TABLE)) return " MMU=Hash"; return "";} static int __die(const char *str, struct pt_regs *regs, long err){ printk("Oops: %s, sig: %ld [#%d]\n", str, err, ++die_counter); printk("%s PAGE_SIZE=%luK%s %s%s%s%s %s\n", IS_ENABLED(CONFIG_CPU_LITTLE_ENDIAN) ? "LE" : "BE", PAGE_SIZE / 1024, get_mmu_str(), IS_ENABLED(CONFIG_SMP) ? " SMP" : "", IS_ENABLED(CONFIG_SMP) ? (" NR_CPUS=" __stringify(NR_CPUS)) : "", debug_pagealloc_enabled() ? " DEBUG_PAGEALLOC" : "", IS_ENABLED(CONFIG_NUMA) ? " NUMA" : "", ppc_md.name ? ppc_md.name : ""); if (notify_die(DIE_OOPS, str, regs, err, 255, SIGSEGV) == NOTIFY_STOP) return 1; print_modules(); show_regs(regs); return 0;}NOKPROBE_SYMBOL(__die); void die(const char *str, struct pt_regs *regs, long err){ unsigned long flags; /* * system_reset_excption handles debugger, crash dump, panic, for 0x100 */ if (TRAP(regs) != INTERRUPT_SYSTEM_RESET) { if (debugger(regs)) return; } flags = oops_begin(regs); if (__die(str, regs, err)) err = 0; oops_end(flags, regs, err);}NOKPROBE_SYMBOL(die); void user_single_step_report(struct pt_regs *regs){ force_sig_fault(SIGTRAP, TRAP_TRACE, (void __user *)regs->nip);} static void show_signal_msg(int signr, struct pt_regs *regs, int code, unsigned long addr){ static DEFINE_RATELIMIT_STATE(rs, DEFAULT_RATELIMIT_INTERVAL, DEFAULT_RATELIMIT_BURST); if (!show_unhandled_signals) return; if (!unhandled_signal(current, signr)) return; if (!__ratelimit(&rs)) return; pr_info("%s[%d]: %s (%d) at %lx nip %lx lr %lx code %x", current->comm, current->pid, signame(signr), signr, addr, regs->nip, regs->link, code); print_vma_addr(KERN_CONT " in ", regs->nip); pr_cont("\n"); show_user_instructions(regs);} static bool exception_common(int signr, struct pt_regs *regs, int code, unsigned long addr){ if (!user_mode(regs)) { die("Exception in kernel mode", regs, signr); return false; } /* * Must not enable interrupts even for user-mode exception, because * this can be called from machine check, which may be a NMI or IRQ * which don't like interrupts being enabled. Could check for * in_hardirq || in_nmi perhaps, but there doesn't seem to be a good * reason why _exception() should enable irqs for an exception handler, * the handlers themselves do that directly. */ show_signal_msg(signr, regs, code, addr); current->thread.trap_nr = code; return true;} void _exception_pkey(struct pt_regs *regs, unsigned long addr, int key){ if (!exception_common(SIGSEGV, regs, SEGV_PKUERR, addr)) return; force_sig_pkuerr((void __user *) addr, key);} void _exception(int signr, struct pt_regs *regs, int code, unsigned long addr){ if (!exception_common(signr, regs, code, addr)) return; force_sig_fault(signr, code, (void __user *)addr);} /* * The interrupt architecture has a quirk in that the HV interrupts excluding * the NMIs (0x100 and 0x200) do not clear MSR[RI] at entry. The first thing * that an interrupt handler must do is save off a GPR into a scratch register, * and all interrupts on POWERNV (HV=1) use the HSPRG1 register as scratch. * Therefore an NMI can clobber an HV interrupt's live HSPRG1 without noticing * that it is non-reentrant, which leads to random data corruption. * * The solution is for NMI interrupts in HV mode to check if they originated * from these critical HV interrupt regions. If so, then mark them not * recoverable. * * An alternative would be for HV NMIs to use SPRG for scratch to avoid the * HSPRG1 clobber, however this would cause guest SPRG to be clobbered. Linux * guests should always have MSR[RI]=0 when its scratch SPRG is in use, so * that would work. However any other guest OS that may have the SPRG live * and MSR[RI]=1 could encounter silent corruption. * * Builds that do not support KVM could take this second option to increase * the recoverability of NMIs. */noinstr void hv_nmi_check_nonrecoverable(struct pt_regs *regs){#ifdef CONFIG_PPC_POWERNV unsigned long kbase = (unsigned long)_stext; unsigned long nip = regs->nip; if (!(regs->msr & MSR_RI)) return; if (!(regs->msr & MSR_HV)) return; if (user_mode(regs)) return; /* * Now test if the interrupt has hit a range that may be using * HSPRG1 without having RI=0 (i.e., an HSRR interrupt). The * problem ranges all run un-relocated. Test real and virt modes * at the same time by dropping the high bit of the nip (virt mode * entry points still have the +0x4000 offset). */ nip &= ~0xc000000000000000ULL; if ((nip >= 0x500 && nip < 0x600) || (nip >= 0x4500 && nip < 0x4600)) goto nonrecoverable; if ((nip >= 0x980 && nip < 0xa00) || (nip >= 0x4980 && nip < 0x4a00)) goto nonrecoverable; if ((nip >= 0xe00 && nip < 0xec0) || (nip >= 0x4e00 && nip < 0x4ec0)) goto nonrecoverable; if ((nip >= 0xf80 && nip < 0xfa0) || (nip >= 0x4f80 && nip < 0x4fa0)) goto nonrecoverable; /* Trampoline code runs un-relocated so subtract kbase. */ if (nip >= (unsigned long)(start_real_trampolines - kbase) && nip < (unsigned long)(end_real_trampolines - kbase)) goto nonrecoverable; if (nip >= (unsigned long)(start_virt_trampolines - kbase) && nip < (unsigned long)(end_virt_trampolines - kbase)) goto nonrecoverable; return; nonrecoverable: regs->msr &= ~MSR_RI; local_paca->hsrr_valid = 0; local_paca->srr_valid = 0;#endif}DEFINE_INTERRUPT_HANDLER_NMI(system_reset_exception){ unsigned long hsrr0, hsrr1; bool saved_hsrrs = false; /* * System reset can interrupt code where HSRRs are live and MSR[RI]=1. * The system reset interrupt itself may clobber HSRRs (e.g., to call * OPAL), so save them here and restore them before returning. * * Machine checks don't need to save HSRRs, as the real mode handler * is careful to avoid them, and the regular handler is not delivered * as an NMI. */ if (cpu_has_feature(CPU_FTR_HVMODE)) { hsrr0 = mfspr(SPRN_HSRR0); hsrr1 = mfspr(SPRN_HSRR1); saved_hsrrs = true; } hv_nmi_check_nonrecoverable(regs); __this_cpu_inc(irq_stat.sreset_irqs); /* See if any machine dependent calls */ if (ppc_md.system_reset_exception) { if (ppc_md.system_reset_exception(regs)) goto out; } if (debugger(regs)) goto out; kmsg_dump(KMSG_DUMP_OOPS); /* * A system reset is a request to dump, so we always send * it through the crashdump code (if fadump or kdump are * registered). */ crash_fadump(regs, "System Reset"); crash_kexec(regs); /* * We aren't the primary crash CPU. We need to send it * to a holding pattern to avoid it ending up in the panic * code. */ crash_kexec_secondary(regs); /* * No debugger or crash dump registered, print logs then * panic. */ 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); nmi_panic(regs, "System Reset"); Lines 1–500 of 2331. Load more
// SPDX-License-Identifier: GPL-2.0-or-later /* * Copyright (C) 1995-1996 Gary Thomas (gdt@linuxppc.org) * Copyright 2007-2010 Freescale Semiconductor, Inc. * * Modified by Cort Dougan (cort@cs.nmt.edu) * and Paul Mackerras (paulus@samba.org) */ /* * This file handles the architecture-dependent parts of hardware exceptions */ #include <linux/errno.h> #include <linux/sched.h> #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> #include <linux/user.h> #include <linux/interrupt.h> #include <linux/init.h> #include <linux/extable.h> #include <linux/module.h> /* print_modules */ #include <linux/prctl.h> #include <linux/delay.h> #include <linux/kprobes.h> #include <linux/kexec.h> #include <linux/backlight.h> #include <linux/bug.h> #include <linux/kdebug.h> #include <linux/ratelimit.h> #include <linux/context_tracking.h> #include <linux/smp.h> #include <linux/console.h> #include <linux/kmsg_dump.h> #include <linux/debugfs.h> #include <asm/emulated_ops.h> #include <linux/uaccess.h> #include <asm/interrupt.h> #include <asm/io.h> #include <asm/machdep.h> #include <asm/rtas.h> #include <asm/pmc.h> #include <asm/reg.h> #ifdef CONFIG_PMAC_BACKLIGHT #include <asm/backlight.h> #endif #ifdef CONFIG_PPC64 #include <asm/firmware.h> #include <asm/processor.h> #endif #include <asm/kexec.h> #include <asm/ppc-opcode.h> #include <asm/rio.h> #include <asm/fadump.h> #include <asm/switch_to.h> #include <asm/tm.h> #include <asm/debug.h> #include <asm/asm-prototypes.h> #include <asm/hmi.h> #include <sysdev/fsl_pci.h> #include <asm/kprobes.h> #include <asm/stacktrace.h> #include <asm/nmi.h> #include <asm/disassemble.h> #include <asm/udbg.h> #if defined(CONFIG_DEBUGGER) || defined(CONFIG_KEXEC_CORE) int (*__debugger)(struct pt_regs *regs) __read_mostly; int (*__debugger_ipi)(struct pt_regs *regs) __read_mostly; int (*__debugger_bpt)(struct pt_regs *regs) __read_mostly; int (*__debugger_sstep)(struct pt_regs *regs) __read_mostly; int (*__debugger_iabr_match)(struct pt_regs *regs) __read_mostly; int (*__debugger_break_match)(struct pt_regs *regs) __read_mostly; int (*__debugger_fault_handler)(struct pt_regs *regs) __read_mostly; EXPORT_SYMBOL(__debugger); EXPORT_SYMBOL(__debugger_ipi); EXPORT_SYMBOL(__debugger_bpt); EXPORT_SYMBOL(__debugger_sstep); EXPORT_SYMBOL(__debugger_iabr_match); EXPORT_SYMBOL(__debugger_break_match); EXPORT_SYMBOL(__debugger_fault_handler); #endif /* Transactional Memory trap debug */ #ifdef TM_DEBUG_SW #define TM_DEBUG(x...) printk(KERN_INFO x) #else #define TM_DEBUG(x...) do { } while(0) #endif static const char *signame(int signr) { switch (signr) { case SIGBUS: return "bus error"; case SIGFPE: return "floating point exception"; case SIGILL: return "illegal instruction"; case SIGSEGV: return "segfault"; case SIGTRAP: return "unhandled trap"; } return "unknown signal"; } /* * Trap & Exception support */ #ifdef CONFIG_PMAC_BACKLIGHT static void pmac_backlight_unblank(void) { mutex_lock(&pmac_backlight_mutex); if (pmac_backlight) { struct backlight_properties *props; props = &pmac_backlight->props; props->brightness = props->max_brightness; props->power = BACKLIGHT_POWER_ON; backlight_update_status(pmac_backlight); } mutex_unlock(&pmac_backlight_mutex); } #else static inline void pmac_backlight_unblank(void) { } #endif /* * If oops/die is expected to crash the machine, return true here. * * This should not be expected to be 100% accurate, there may be * notifiers registered or other unexpected conditions that may bring * down the kernel. Or if the current process in the kernel is holding * locks or has other critical state, the kernel may become effectively * unusable anyway. */ bool die_will_crash(void) { if (should_fadump_crash()) return true; if (kexec_should_crash(current)) return true; if (in_interrupt() || panic_on_oops || !current->pid || is_global_init(current)) return true; return false; } static arch_spinlock_t die_lock = __ARCH_SPIN_LOCK_UNLOCKED; static int die_owner = -1; static unsigned int die_nest_count; static int die_counter; 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); } void panic_flush_kmsg_end(void) { kmsg_dump(KMSG_DUMP_PANIC); bust_spinlocks(0); debug_locks_off(); console_flush_on_panic(CONSOLE_FLUSH_PENDING); } static unsigned long oops_begin(struct pt_regs *regs) { int cpu; unsigned long flags; oops_enter(); /* racy, but better than risking deadlock. */ raw_local_irq_save(flags); cpu = smp_processor_id(); if (!arch_spin_trylock(&die_lock)) { if (cpu == die_owner) /* nested oops. should stop eventually */; else arch_spin_lock(&die_lock); } die_nest_count++; die_owner = cpu; console_verbose(); bust_spinlocks(1); if (machine_is(powermac)) pmac_backlight_unblank(); return flags; } NOKPROBE_SYMBOL(oops_begin); static void oops_end(unsigned long flags, struct pt_regs *regs, int signr) { bust_spinlocks(0); add_taint(TAINT_DIE, LOCKDEP_NOW_UNRELIABLE); die_nest_count--; oops_exit(); printk("\n"); if (!die_nest_count) { /* Nest count reaches zero, release the lock. */ die_owner = -1; arch_spin_unlock(&die_lock); } raw_local_irq_restore(flags); /* * system_reset_excption handles debugger, crash dump, panic, for 0x100 */ if (TRAP(regs) == INTERRUPT_SYSTEM_RESET) return; crash_fadump(regs, "die oops"); if (kexec_should_crash(current)) crash_kexec(regs); if (!signr) return; /* * While our oops output is serialised by a spinlock, output * from panic() called below can race and corrupt it. If we * know we are going to panic, delay for 1 second so we have a * chance to get clean backtraces from all CPUs that are oopsing. */ if (in_interrupt() || panic_on_oops || !current->pid || is_global_init(current)) { mdelay(MSEC_PER_SEC); } if (panic_on_oops) panic("Fatal exception"); make_task_dead(signr); } NOKPROBE_SYMBOL(oops_end); static char *get_mmu_str(void) { if (early_radix_enabled()) return " MMU=Radix"; if (early_mmu_has_feature(MMU_FTR_HPTE_TABLE)) return " MMU=Hash"; return ""; } static int __die(const char *str, struct pt_regs *regs, long err) { printk("Oops: %s, sig: %ld [#%d]\n", str, err, ++die_counter); printk("%s PAGE_SIZE=%luK%s %s%s%s%s %s\n", IS_ENABLED(CONFIG_CPU_LITTLE_ENDIAN) ? "LE" : "BE", PAGE_SIZE / 1024, get_mmu_str(), IS_ENABLED(CONFIG_SMP) ? " SMP" : "", IS_ENABLED(CONFIG_SMP) ? (" NR_CPUS=" __stringify(NR_CPUS)) : "", debug_pagealloc_enabled() ? " DEBUG_PAGEALLOC" : "", IS_ENABLED(CONFIG_NUMA) ? " NUMA" : "", ppc_md.name ? ppc_md.name : ""); if (notify_die(DIE_OOPS, str, regs, err, 255, SIGSEGV) == NOTIFY_STOP) return 1; print_modules(); show_regs(regs); return 0; } NOKPROBE_SYMBOL(__die); void die(const char *str, struct pt_regs *regs, long err) { unsigned long flags; /* * system_reset_excption handles debugger, crash dump, panic, for 0x100 */ if (TRAP(regs) != INTERRUPT_SYSTEM_RESET) { if (debugger(regs)) return; } flags = oops_begin(regs); if (__die(str, regs, err)) err = 0; oops_end(flags, regs, err); } NOKPROBE_SYMBOL(die); void user_single_step_report(struct pt_regs *regs) { force_sig_fault(SIGTRAP, TRAP_TRACE, (void __user *)regs->nip); } static void show_signal_msg(int signr, struct pt_regs *regs, int code, unsigned long addr) { static DEFINE_RATELIMIT_STATE(rs, DEFAULT_RATELIMIT_INTERVAL, DEFAULT_RATELIMIT_BURST); if (!show_unhandled_signals) return; if (!unhandled_signal(current, signr)) return; if (!__ratelimit(&rs)) return; pr_info("%s[%d]: %s (%d) at %lx nip %lx lr %lx code %x", current->comm, current->pid, signame(signr), signr, addr, regs->nip, regs->link, code); print_vma_addr(KERN_CONT " in ", regs->nip); pr_cont("\n"); show_user_instructions(regs); } static bool exception_common(int signr, struct pt_regs *regs, int code, unsigned long addr) { if (!user_mode(regs)) { die("Exception in kernel mode", regs, signr); return false; } /* * Must not enable interrupts even for user-mode exception, because * this can be called from machine check, which may be a NMI or IRQ * which don't like interrupts being enabled. Could check for * in_hardirq || in_nmi perhaps, but there doesn't seem to be a good * reason why _exception() should enable irqs for an exception handler, * the handlers themselves do that directly. */ show_signal_msg(signr, regs, code, addr); current->thread.trap_nr = code; return true; } void _exception_pkey(struct pt_regs *regs, unsigned long addr, int key) { if (!exception_common(SIGSEGV, regs, SEGV_PKUERR, addr)) return; force_sig_pkuerr((void __user *) addr, key); } void _exception(int signr, struct pt_regs *regs, int code, unsigned long addr) { if (!exception_common(signr, regs, code, addr)) return; force_sig_fault(signr, code, (void __user *)addr); } /* * The interrupt architecture has a quirk in that the HV interrupts excluding * the NMIs (0x100 and 0x200) do not clear MSR[RI] at entry. The first thing * that an interrupt handler must do is save off a GPR into a scratch register, * and all interrupts on POWERNV (HV=1) use the HSPRG1 register as scratch. * Therefore an NMI can clobber an HV interrupt's live HSPRG1 without noticing * that it is non-reentrant, which leads to random data corruption. * * The solution is for NMI interrupts in HV mode to check if they originated * from these critical HV interrupt regions. If so, then mark them not * recoverable. * * An alternative would be for HV NMIs to use SPRG for scratch to avoid the * HSPRG1 clobber, however this would cause guest SPRG to be clobbered. Linux * guests should always have MSR[RI]=0 when its scratch SPRG is in use, so * that would work. However any other guest OS that may have the SPRG live * and MSR[RI]=1 could encounter silent corruption. * * Builds that do not support KVM could take this second option to increase * the recoverability of NMIs. */ noinstr void hv_nmi_check_nonrecoverable(struct pt_regs *regs) { #ifdef CONFIG_PPC_POWERNV unsigned long kbase = (unsigned long)_stext; unsigned long nip = regs->nip; if (!(regs->msr & MSR_RI)) return; if (!(regs->msr & MSR_HV)) return; if (user_mode(regs)) return; /* * Now test if the interrupt has hit a range that may be using * HSPRG1 without having RI=0 (i.e., an HSRR interrupt). The * problem ranges all run un-relocated. Test real and virt modes * at the same time by dropping the high bit of the nip (virt mode * entry points still have the +0x4000 offset). */ nip &= ~0xc000000000000000ULL; if ((nip >= 0x500 && nip < 0x600) || (nip >= 0x4500 && nip < 0x4600)) goto nonrecoverable; if ((nip >= 0x980 && nip < 0xa00) || (nip >= 0x4980 && nip < 0x4a00)) goto nonrecoverable; if ((nip >= 0xe00 && nip < 0xec0) || (nip >= 0x4e00 && nip < 0x4ec0)) goto nonrecoverable; if ((nip >= 0xf80 && nip < 0xfa0) || (nip >= 0x4f80 && nip < 0x4fa0)) goto nonrecoverable; /* Trampoline code runs un-relocated so subtract kbase. */ if (nip >= (unsigned long)(start_real_trampolines - kbase) && nip < (unsigned long)(end_real_trampolines - kbase)) goto nonrecoverable; if (nip >= (unsigned long)(start_virt_trampolines - kbase) && nip < (unsigned long)(end_virt_trampolines - kbase)) goto nonrecoverable; return; nonrecoverable: regs->msr &= ~MSR_RI; local_paca->hsrr_valid = 0; local_paca->srr_valid = 0; #endif } DEFINE_INTERRUPT_HANDLER_NMI(system_reset_exception) { unsigned long hsrr0, hsrr1; bool saved_hsrrs = false; /* * System reset can interrupt code where HSRRs are live and MSR[RI]=1. * The system reset interrupt itself may clobber HSRRs (e.g., to call * OPAL), so save them here and restore them before returning. * * Machine checks don't need to save HSRRs, as the real mode handler * is careful to avoid them, and the regular handler is not delivered * as an NMI. */ if (cpu_has_feature(CPU_FTR_HVMODE)) { hsrr0 = mfspr(SPRN_HSRR0); hsrr1 = mfspr(SPRN_HSRR1); saved_hsrrs = true; } hv_nmi_check_nonrecoverable(regs); __this_cpu_inc(irq_stat.sreset_irqs); /* See if any machine dependent calls */ if (ppc_md.system_reset_exception) { if (ppc_md.system_reset_exception(regs)) goto out; } if (debugger(regs)) goto out; kmsg_dump(KMSG_DUMP_OOPS); /* * A system reset is a request to dump, so we always send * it through the crashdump code (if fadump or kdump are * registered). */ crash_fadump(regs, "System Reset"); crash_kexec(regs); /* * We aren't the primary crash CPU. We need to send it * to a holding pattern to avoid it ending up in the panic * code. */ crash_kexec_secondary(regs); /* * No debugger or crash dump registered, print logs then * panic. */ 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); nmi_panic(regs, "System Reset");