⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 traps.c

📁 linux-2.6.15.6
💻 C
📖 第 1 页 / 共 5 页
字号:
/* $Id: traps.c,v 1.85 2002/02/09 19:49:31 davem Exp $ * arch/sparc64/kernel/traps.c * * Copyright (C) 1995,1997 David S. Miller (davem@caip.rutgers.edu) * Copyright (C) 1997,1999,2000 Jakub Jelinek (jakub@redhat.com) *//* * I like traps on v9, :)))) */#include <linux/config.h>#include <linux/module.h>#include <linux/sched.h>  /* for jiffies */#include <linux/kernel.h>#include <linux/kallsyms.h>#include <linux/signal.h>#include <linux/smp.h>#include <linux/smp_lock.h>#include <linux/mm.h>#include <linux/init.h>#include <asm/delay.h>#include <asm/system.h>#include <asm/ptrace.h>#include <asm/oplib.h>#include <asm/page.h>#include <asm/pgtable.h>#include <asm/unistd.h>#include <asm/uaccess.h>#include <asm/fpumacro.h>#include <asm/lsu.h>#include <asm/dcu.h>#include <asm/estate.h>#include <asm/chafsr.h>#include <asm/sfafsr.h>#include <asm/psrcompat.h>#include <asm/processor.h>#include <asm/timer.h>#include <asm/kdebug.h>#ifdef CONFIG_KMOD#include <linux/kmod.h>#endifstruct notifier_block *sparc64die_chain;static DEFINE_SPINLOCK(die_notifier_lock);int register_die_notifier(struct notifier_block *nb){	int err = 0;	unsigned long flags;	spin_lock_irqsave(&die_notifier_lock, flags);	err = notifier_chain_register(&sparc64die_chain, nb);	spin_unlock_irqrestore(&die_notifier_lock, flags);	return err;}/* When an irrecoverable trap occurs at tl > 0, the trap entry * code logs the trap state registers at every level in the trap * stack.  It is found at (pt_regs + sizeof(pt_regs)) and the layout * is as follows: */struct tl1_traplog {	struct {		unsigned long tstate;		unsigned long tpc;		unsigned long tnpc;		unsigned long tt;	} trapstack[4];	unsigned long tl;};static void dump_tl1_traplog(struct tl1_traplog *p){	int i;	printk("TRAPLOG: Error at trap level 0x%lx, dumping track stack.\n",	       p->tl);	for (i = 0; i < 4; i++) {		printk(KERN_CRIT		       "TRAPLOG: Trap level %d TSTATE[%016lx] TPC[%016lx] "		       "TNPC[%016lx] TT[%lx]\n",		       i + 1,		       p->trapstack[i].tstate, p->trapstack[i].tpc,		       p->trapstack[i].tnpc, p->trapstack[i].tt);	}}void do_call_debug(struct pt_regs *regs) { 	notify_die(DIE_CALL, "debug call", regs, 0, 255, SIGINT); }void bad_trap(struct pt_regs *regs, long lvl){	char buffer[32];	siginfo_t info;	if (notify_die(DIE_TRAP, "bad trap", regs,		       0, lvl, SIGTRAP) == NOTIFY_STOP)		return;	if (lvl < 0x100) {		sprintf(buffer, "Bad hw trap %lx at tl0\n", lvl);		die_if_kernel(buffer, regs);	}	lvl -= 0x100;	if (regs->tstate & TSTATE_PRIV) {		sprintf(buffer, "Kernel bad sw trap %lx", lvl);		die_if_kernel(buffer, regs);	}	if (test_thread_flag(TIF_32BIT)) {		regs->tpc &= 0xffffffff;		regs->tnpc &= 0xffffffff;	}	info.si_signo = SIGILL;	info.si_errno = 0;	info.si_code = ILL_ILLTRP;	info.si_addr = (void __user *)regs->tpc;	info.si_trapno = lvl;	force_sig_info(SIGILL, &info, current);}void bad_trap_tl1(struct pt_regs *regs, long lvl){	char buffer[32];		if (notify_die(DIE_TRAP_TL1, "bad trap tl1", regs,		       0, lvl, SIGTRAP) == NOTIFY_STOP)		return;	dump_tl1_traplog((struct tl1_traplog *)(regs + 1));	sprintf (buffer, "Bad trap %lx at tl>0", lvl);	die_if_kernel (buffer, regs);}#ifdef CONFIG_DEBUG_BUGVERBOSEvoid do_BUG(const char *file, int line){	bust_spinlocks(1);	printk("kernel BUG at %s:%d!\n", file, line);}#endifvoid spitfire_insn_access_exception(struct pt_regs *regs, unsigned long sfsr, unsigned long sfar){	siginfo_t info;	if (notify_die(DIE_TRAP, "instruction access exception", regs,		       0, 0x8, SIGTRAP) == NOTIFY_STOP)		return;	if (regs->tstate & TSTATE_PRIV) {		printk("spitfire_insn_access_exception: SFSR[%016lx] "		       "SFAR[%016lx], going.\n", sfsr, sfar);		die_if_kernel("Iax", regs);	}	if (test_thread_flag(TIF_32BIT)) {		regs->tpc &= 0xffffffff;		regs->tnpc &= 0xffffffff;	}	info.si_signo = SIGSEGV;	info.si_errno = 0;	info.si_code = SEGV_MAPERR;	info.si_addr = (void __user *)regs->tpc;	info.si_trapno = 0;	force_sig_info(SIGSEGV, &info, current);}void spitfire_insn_access_exception_tl1(struct pt_regs *regs, unsigned long sfsr, unsigned long sfar){	if (notify_die(DIE_TRAP_TL1, "instruction access exception tl1", regs,		       0, 0x8, SIGTRAP) == NOTIFY_STOP)		return;	dump_tl1_traplog((struct tl1_traplog *)(regs + 1));	spitfire_insn_access_exception(regs, sfsr, sfar);}void spitfire_data_access_exception(struct pt_regs *regs, unsigned long sfsr, unsigned long sfar){	siginfo_t info;	if (notify_die(DIE_TRAP, "data access exception", regs,		       0, 0x30, SIGTRAP) == NOTIFY_STOP)		return;	if (regs->tstate & TSTATE_PRIV) {		/* Test if this comes from uaccess places. */		const struct exception_table_entry *entry;		entry = search_exception_tables(regs->tpc);		if (entry) {			/* Ouch, somebody is trying VM hole tricks on us... */#ifdef DEBUG_EXCEPTIONS			printk("Exception: PC<%016lx> faddr<UNKNOWN>\n", regs->tpc);			printk("EX_TABLE: insn<%016lx> fixup<%016lx>\n",			       regs->tpc, entry->fixup);#endif			regs->tpc = entry->fixup;			regs->tnpc = regs->tpc + 4;			return;		}		/* Shit... */		printk("spitfire_data_access_exception: SFSR[%016lx] "		       "SFAR[%016lx], going.\n", sfsr, sfar);		die_if_kernel("Dax", regs);	}	info.si_signo = SIGSEGV;	info.si_errno = 0;	info.si_code = SEGV_MAPERR;	info.si_addr = (void __user *)sfar;	info.si_trapno = 0;	force_sig_info(SIGSEGV, &info, current);}void spitfire_data_access_exception_tl1(struct pt_regs *regs, unsigned long sfsr, unsigned long sfar){	if (notify_die(DIE_TRAP_TL1, "data access exception tl1", regs,		       0, 0x30, SIGTRAP) == NOTIFY_STOP)		return;	dump_tl1_traplog((struct tl1_traplog *)(regs + 1));	spitfire_data_access_exception(regs, sfsr, sfar);}#ifdef CONFIG_PCI/* This is really pathetic... */extern volatile int pci_poke_in_progress;extern volatile int pci_poke_cpu;extern volatile int pci_poke_faulted;#endif/* When access exceptions happen, we must do this. */static void spitfire_clean_and_reenable_l1_caches(void){	unsigned long va;	if (tlb_type != spitfire)		BUG();	/* Clean 'em. */	for (va =  0; va < (PAGE_SIZE << 1); va += 32) {		spitfire_put_icache_tag(va, 0x0);		spitfire_put_dcache_tag(va, 0x0);	}	/* Re-enable in LSU. */	__asm__ __volatile__("flush %%g6\n\t"			     "membar #Sync\n\t"			     "stxa %0, [%%g0] %1\n\t"			     "membar #Sync"			     : /* no outputs */			     : "r" (LSU_CONTROL_IC | LSU_CONTROL_DC |				    LSU_CONTROL_IM | LSU_CONTROL_DM),			     "i" (ASI_LSU_CONTROL)			     : "memory");}static void spitfire_enable_estate_errors(void){	__asm__ __volatile__("stxa	%0, [%%g0] %1\n\t"			     "membar	#Sync"			     : /* no outputs */			     : "r" (ESTATE_ERR_ALL),			       "i" (ASI_ESTATE_ERROR_EN));}static char ecc_syndrome_table[] = {	0x4c, 0x40, 0x41, 0x48, 0x42, 0x48, 0x48, 0x49,	0x43, 0x48, 0x48, 0x49, 0x48, 0x49, 0x49, 0x4a,	0x44, 0x48, 0x48, 0x20, 0x48, 0x39, 0x4b, 0x48,	0x48, 0x25, 0x31, 0x48, 0x28, 0x48, 0x48, 0x2c,	0x45, 0x48, 0x48, 0x21, 0x48, 0x3d, 0x04, 0x48,	0x48, 0x4b, 0x35, 0x48, 0x2d, 0x48, 0x48, 0x29,	0x48, 0x00, 0x01, 0x48, 0x0a, 0x48, 0x48, 0x4b,	0x0f, 0x48, 0x48, 0x4b, 0x48, 0x49, 0x49, 0x48,	0x46, 0x48, 0x48, 0x2a, 0x48, 0x3b, 0x27, 0x48,	0x48, 0x4b, 0x33, 0x48, 0x22, 0x48, 0x48, 0x2e,	0x48, 0x19, 0x1d, 0x48, 0x1b, 0x4a, 0x48, 0x4b,	0x1f, 0x48, 0x4a, 0x4b, 0x48, 0x4b, 0x4b, 0x48,	0x48, 0x4b, 0x24, 0x48, 0x07, 0x48, 0x48, 0x36,	0x4b, 0x48, 0x48, 0x3e, 0x48, 0x30, 0x38, 0x48,	0x49, 0x48, 0x48, 0x4b, 0x48, 0x4b, 0x16, 0x48,	0x48, 0x12, 0x4b, 0x48, 0x49, 0x48, 0x48, 0x4b,	0x47, 0x48, 0x48, 0x2f, 0x48, 0x3f, 0x4b, 0x48,	0x48, 0x06, 0x37, 0x48, 0x23, 0x48, 0x48, 0x2b,	0x48, 0x05, 0x4b, 0x48, 0x4b, 0x48, 0x48, 0x32,	0x26, 0x48, 0x48, 0x3a, 0x48, 0x34, 0x3c, 0x48,	0x48, 0x11, 0x15, 0x48, 0x13, 0x4a, 0x48, 0x4b,	0x17, 0x48, 0x4a, 0x4b, 0x48, 0x4b, 0x4b, 0x48,	0x49, 0x48, 0x48, 0x4b, 0x48, 0x4b, 0x1e, 0x48,	0x48, 0x1a, 0x4b, 0x48, 0x49, 0x48, 0x48, 0x4b,	0x48, 0x08, 0x0d, 0x48, 0x02, 0x48, 0x48, 0x49,	0x03, 0x48, 0x48, 0x49, 0x48, 0x4b, 0x4b, 0x48,	0x49, 0x48, 0x48, 0x49, 0x48, 0x4b, 0x10, 0x48,	0x48, 0x14, 0x4b, 0x48, 0x4b, 0x48, 0x48, 0x4b,	0x49, 0x48, 0x48, 0x49, 0x48, 0x4b, 0x18, 0x48,	0x48, 0x1c, 0x4b, 0x48, 0x4b, 0x48, 0x48, 0x4b,	0x4a, 0x0c, 0x09, 0x48, 0x0e, 0x48, 0x48, 0x4b,	0x0b, 0x48, 0x48, 0x4b, 0x48, 0x4b, 0x4b, 0x4a};static char *syndrome_unknown = "<Unknown>";static void spitfire_log_udb_syndrome(unsigned long afar, unsigned long udbh, unsigned long udbl, unsigned long bit){	unsigned short scode;	char memmod_str[64], *p;	if (udbl & bit) {		scode = ecc_syndrome_table[udbl & 0xff];		if (prom_getunumber(scode, afar,				    memmod_str, sizeof(memmod_str)) == -1)			p = syndrome_unknown;		else			p = memmod_str;		printk(KERN_WARNING "CPU[%d]: UDBL Syndrome[%x] "		       "Memory Module \"%s\"\n",		       smp_processor_id(), scode, p);	}	if (udbh & bit) {		scode = ecc_syndrome_table[udbh & 0xff];		if (prom_getunumber(scode, afar,				    memmod_str, sizeof(memmod_str)) == -1)			p = syndrome_unknown;		else			p = memmod_str;		printk(KERN_WARNING "CPU[%d]: UDBH Syndrome[%x] "		       "Memory Module \"%s\"\n",		       smp_processor_id(), scode, p);	}}static void spitfire_cee_log(unsigned long afsr, unsigned long afar, unsigned long udbh, unsigned long udbl, int tl1, struct pt_regs *regs){	printk(KERN_WARNING "CPU[%d]: Correctable ECC Error "	       "AFSR[%lx] AFAR[%016lx] UDBL[%lx] UDBH[%lx] TL>1[%d]\n",	       smp_processor_id(), afsr, afar, udbl, udbh, tl1);	spitfire_log_udb_syndrome(afar, udbh, udbl, UDBE_CE);	/* We always log it, even if someone is listening for this	 * trap.	 */	notify_die(DIE_TRAP, "Correctable ECC Error", regs,		   0, TRAP_TYPE_CEE, SIGTRAP);	/* The Correctable ECC Error trap does not disable I/D caches.  So	 * we only have to restore the ESTATE Error Enable register.	 */	spitfire_enable_estate_errors();}static void spitfire_ue_log(unsigned long afsr, unsigned long afar, unsigned long udbh, unsigned long udbl, unsigned long tt, int tl1, struct pt_regs *regs){	siginfo_t info;	printk(KERN_WARNING "CPU[%d]: Uncorrectable Error AFSR[%lx] "	       "AFAR[%lx] UDBL[%lx] UDBH[%ld] TT[%lx] TL>1[%d]\n",	       smp_processor_id(), afsr, afar, udbl, udbh, tt, tl1);	/* XXX add more human friendly logging of the error status	 * XXX as is implemented for cheetah	 */	spitfire_log_udb_syndrome(afar, udbh, udbl, UDBE_UE);	/* We always log it, even if someone is listening for this	 * trap.	 */	notify_die(DIE_TRAP, "Uncorrectable Error", regs,		   0, tt, SIGTRAP);	if (regs->tstate & TSTATE_PRIV) {		if (tl1)			dump_tl1_traplog((struct tl1_traplog *)(regs + 1));		die_if_kernel("UE", regs);	}	/* XXX need more intelligent processing here, such as is implemented	 * XXX for cheetah errors, in fact if the E-cache still holds the	 * XXX line with bad parity this will loop	 */	spitfire_clean_and_reenable_l1_caches();	spitfire_enable_estate_errors();	if (test_thread_flag(TIF_32BIT)) {		regs->tpc &= 0xffffffff;		regs->tnpc &= 0xffffffff;	}	info.si_signo = SIGBUS;	info.si_errno = 0;	info.si_code = BUS_OBJERR;	info.si_addr = (void *)0;	info.si_trapno = 0;	force_sig_info(SIGBUS, &info, current);}void spitfire_access_error(struct pt_regs *regs, unsigned long status_encoded, unsigned long afar){	unsigned long afsr, tt, udbh, udbl;	int tl1;	afsr = (status_encoded & SFSTAT_AFSR_MASK) >> SFSTAT_AFSR_SHIFT;	tt = (status_encoded & SFSTAT_TRAP_TYPE) >> SFSTAT_TRAP_TYPE_SHIFT;	tl1 = (status_encoded & SFSTAT_TL_GT_ONE) ? 1 : 0;	udbl = (status_encoded & SFSTAT_UDBL_MASK) >> SFSTAT_UDBL_SHIFT;	udbh = (status_encoded & SFSTAT_UDBH_MASK) >> SFSTAT_UDBH_SHIFT;#ifdef CONFIG_PCI	if (tt == TRAP_TYPE_DAE &&	    pci_poke_in_progress && pci_poke_cpu == smp_processor_id()) {		spitfire_clean_and_reenable_l1_caches();		spitfire_enable_estate_errors();		pci_poke_faulted = 1;		regs->tnpc = regs->tpc + 4;		return;	}#endif	if (afsr & SFAFSR_UE)		spitfire_ue_log(afsr, afar, udbh, udbl, tt, tl1, regs);	if (tt == TRAP_TYPE_CEE) {		/* Handle the case where we took a CEE trap, but ACK'd		 * only the UE state in the UDB error registers.

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -