Mukesh Kumar Chaurasiyapowerpc: rename arch_irq_disabled_regsbaa59006 months agoHistory
2331 lines · 60.6 KB · C
RawDownload
// 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.