traps.c
来自「h内核」· C语言 代码 · 共 2,161 行 · 第 1/5 页
C
2,161 行
/* $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/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 instruction_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("instruction_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 instruction_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)); instruction_access_exception(regs, sfsr, sfar);}void 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. */ unsigned long fixup; unsigned long g2 = regs->u_regs[UREG_G2]; if ((fixup = search_extables_range(regs->tpc, &g2))) { /* Ouch, somebody is trying ugly VM hole tricks on us... */#ifdef DEBUG_EXCEPTIONS printk("Exception: PC<%016lx> faddr<UNKNOWN>\n", regs->tpc); printk("EX_TABLE: insn<%016lx> fixup<%016lx> " "g2<%016lx>\n", regs->tpc, fixup, g2);#endif regs->tpc = fixup; regs->tnpc = regs->tpc + 4; regs->u_regs[UREG_G2] = g2; return; } /* Shit... */ printk("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);}#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");}void do_iae(struct pt_regs *regs){ siginfo_t info; spitfire_clean_and_reenable_l1_caches(); if (notify_die(DIE_TRAP, "instruction access exception", regs, 0, 0x8, SIGTRAP) == NOTIFY_STOP) return; 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 do_dae(struct pt_regs *regs){ siginfo_t info;#ifdef CONFIG_PCI if (pci_poke_in_progress && pci_poke_cpu == smp_processor_id()) { spitfire_clean_and_reenable_l1_caches(); pci_poke_faulted = 1; /* Why the fuck did they have to change this? */ if (tlb_type == cheetah || tlb_type == cheetah_plus) regs->tpc += 4; regs->tnpc = regs->tpc + 4; return; }#endif spitfire_clean_and_reenable_l1_caches(); if (notify_die(DIE_TRAP, "data access exception", regs, 0, 0x30, SIGTRAP) == NOTIFY_STOP) return; 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);}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};/* cee_trap in entry.S encodes AFSR/UDBH/UDBL error status * in the following format. The AFAR is left as is, with * reserved bits cleared, and is a raw 40-bit physical * address. */#define CE_STATUS_UDBH_UE (1UL << (43 + 9))#define CE_STATUS_UDBH_CE (1UL << (43 + 8))#define CE_STATUS_UDBH_ESYNDR (0xffUL << 43)#define CE_STATUS_UDBH_SHIFT 43#define CE_STATUS_UDBL_UE (1UL << (33 + 9))#define CE_STATUS_UDBL_CE (1UL << (33 + 8))#define CE_STATUS_UDBL_ESYNDR (0xffUL << 33)#define CE_STATUS_UDBL_SHIFT 33#define CE_STATUS_AFSR_MASK (0x1ffffffffUL)#define CE_STATUS_AFSR_ME (1UL << 32)#define CE_STATUS_AFSR_PRIV (1UL << 31)#define CE_STATUS_AFSR_ISAP (1UL << 30)#define CE_STATUS_AFSR_ETP (1UL << 29)#define CE_STATUS_AFSR_IVUE (1UL << 28)#define CE_STATUS_AFSR_TO (1UL << 27)#define CE_STATUS_AFSR_BERR (1UL << 26)#define CE_STATUS_AFSR_LDP (1UL << 25)#define CE_STATUS_AFSR_CP (1UL << 24)#define CE_STATUS_AFSR_WP (1UL << 23)#define CE_STATUS_AFSR_EDP (1UL << 22)#define CE_STATUS_AFSR_UE (1UL << 21)#define CE_STATUS_AFSR_CE (1UL << 20)#define CE_STATUS_AFSR_ETS (0xfUL << 16)#define CE_STATUS_AFSR_ETS_SHIFT 16#define CE_STATUS_AFSR_PSYND (0xffffUL << 0)#define CE_STATUS_AFSR_PSYND_SHIFT 0/* Layout of Ecache TAG Parity Syndrome of AFSR */#define AFSR_ETSYNDROME_7_0 0x1UL /* E$-tag bus bits <7:0> */#define AFSR_ETSYNDROME_15_8 0x2UL /* E$-tag bus bits <15:8> */#define AFSR_ETSYNDROME_21_16 0x4UL /* E$-tag bus bits <21:16> */#define AFSR_ETSYNDROME_24_22 0x8UL /* E$-tag bus bits <24:22> */static char *syndrome_unknown = "<Unknown>";asmlinkage void cee_log(unsigned long ce_status, unsigned long afar, struct pt_regs *regs){ char memmod_str[64]; char *p; unsigned short scode, udb_reg; printk(KERN_WARNING "CPU[%d]: Correctable ECC Error " "AFSR[%lx] AFAR[%016lx] UDBL[%lx] UDBH[%lx]\n", smp_processor_id(), (ce_status & CE_STATUS_AFSR_MASK), afar, ((ce_status >> CE_STATUS_UDBL_SHIFT) & 0x3ffUL), ((ce_status >> CE_STATUS_UDBH_SHIFT) & 0x3ffUL)); udb_reg = ((ce_status >> CE_STATUS_UDBL_SHIFT) & 0x3ffUL); if (udb_reg & (1 << 8)) { scode = ecc_syndrome_table[udb_reg & 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); } udb_reg = ((ce_status >> CE_STATUS_UDBH_SHIFT) & 0x3ffUL); if (udb_reg & (1 << 8)) { scode = ecc_syndrome_table[udb_reg & 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); }}/* Cheetah error trap handling. */static unsigned long ecache_flush_physbase;static unsigned long ecache_flush_linesize;static unsigned long ecache_flush_size;/* WARNING: The error trap handlers in assembly know the precise * layout of the following structure. * * C-level handlers below use this information to log the error * and then determine how to recover (if possible).
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?