traps.c

来自「linux 内核源代码」· C语言 代码 · 共 862 行 · 第 1/2 页

C
862
字号
/* *  linux/arch/parisc/traps.c * *  Copyright (C) 1991, 1992  Linus Torvalds *  Copyright (C) 1999, 2000  Philipp Rumpf <prumpf@tux.org> *//* * 'Traps.c' handles hardware traps and faults after we have saved some * state in 'asm.s'. */#include <linux/sched.h>#include <linux/kernel.h>#include <linux/string.h>#include <linux/errno.h>#include <linux/ptrace.h>#include <linux/timer.h>#include <linux/delay.h>#include <linux/mm.h>#include <linux/module.h>#include <linux/smp.h>#include <linux/spinlock.h>#include <linux/init.h>#include <linux/interrupt.h>#include <linux/console.h>#include <linux/kallsyms.h>#include <linux/bug.h>#include <asm/assembly.h>#include <asm/system.h>#include <asm/uaccess.h>#include <asm/io.h>#include <asm/irq.h>#include <asm/traps.h>#include <asm/unaligned.h>#include <asm/atomic.h>#include <asm/smp.h>#include <asm/pdc.h>#include <asm/pdc_chassis.h>#include <asm/unwind.h>#include <asm/tlbflush.h>#include <asm/cacheflush.h>#include "../math-emu/math-emu.h"	/* for handle_fpe() */#define PRINT_USER_FAULTS /* (turn this on if you want user faults to be */			  /*  dumped to the console via printk)          */#if defined(CONFIG_SMP) || defined(CONFIG_DEBUG_SPINLOCK)DEFINE_SPINLOCK(pa_dbit_lock);#endifstatic int printbinary(char *buf, unsigned long x, int nbits){	unsigned long mask = 1UL << (nbits - 1);	while (mask != 0) {		*buf++ = (mask & x ? '1' : '0');		mask >>= 1;	}	*buf = '\0';	return nbits;}#ifdef CONFIG_64BIT#define RFMT "%016lx"#else#define RFMT "%08lx"#endif#define FFMT "%016llx"	/* fpregs are 64-bit always */#define PRINTREGS(lvl,r,f,fmt,x)	\	printk("%s%s%02d-%02d  " fmt " " fmt " " fmt " " fmt "\n",	\		lvl, f, (x), (x+3), (r)[(x)+0], (r)[(x)+1],		\		(r)[(x)+2], (r)[(x)+3])static void print_gr(char *level, struct pt_regs *regs){	int i;	char buf[64];	printk("%s\n", level);	printk("%s     YZrvWESTHLNXBCVMcbcbcbcbOGFRQPDI\n", level);	printbinary(buf, regs->gr[0], 32);	printk("%sPSW: %s %s\n", level, buf, print_tainted());	for (i = 0; i < 32; i += 4)		PRINTREGS(level, regs->gr, "r", RFMT, i);}static void print_fr(char *level, struct pt_regs *regs){	int i;	char buf[64];	struct { u32 sw[2]; } s;	/* FR are 64bit everywhere. Need to use asm to get the content	 * of fpsr/fper1, and we assume that we won't have a FP Identify	 * in our way, otherwise we're screwed.	 * The fldd is used to restore the T-bit if there was one, as the	 * store clears it anyway.	 * PA2.0 book says "thou shall not use fstw on FPSR/FPERs" - T-Bone */	asm volatile ("fstd %%fr0,0(%1)	\n\t"		      "fldd 0(%1),%%fr0	\n\t"		      : "=m" (s) : "r" (&s) : "r0");	printk("%s\n", level);	printk("%s      VZOUICununcqcqcqcqcqcrmunTDVZOUI\n", level);	printbinary(buf, s.sw[0], 32);	printk("%sFPSR: %s\n", level, buf);	printk("%sFPER1: %08x\n", level, s.sw[1]);	/* here we'll print fr0 again, tho it'll be meaningless */	for (i = 0; i < 32; i += 4)		PRINTREGS(level, regs->fr, "fr", FFMT, i);}void show_regs(struct pt_regs *regs){	int i;	char *level;	unsigned long cr30, cr31;	level = user_mode(regs) ? KERN_DEBUG : KERN_CRIT;	print_gr(level, regs);	for (i = 0; i < 8; i += 4)		PRINTREGS(level, regs->sr, "sr", RFMT, i);	if (user_mode(regs))		print_fr(level, regs);	cr30 = mfctl(30);	cr31 = mfctl(31);	printk("%s\n", level);	printk("%sIASQ: " RFMT " " RFMT " IAOQ: " RFMT " " RFMT "\n",	       level, regs->iasq[0], regs->iasq[1], regs->iaoq[0], regs->iaoq[1]);	printk("%s IIR: %08lx    ISR: " RFMT "  IOR: " RFMT "\n",	       level, regs->iir, regs->isr, regs->ior);	printk("%s CPU: %8d   CR30: " RFMT " CR31: " RFMT "\n",	       level, current_thread_info()->cpu, cr30, cr31);	printk("%s ORIG_R28: " RFMT "\n", level, regs->orig_r28);	printk(level);	print_symbol(" IAOQ[0]: %s\n", regs->iaoq[0]);	printk(level);	print_symbol(" IAOQ[1]: %s\n", regs->iaoq[1]);	printk(level);	print_symbol(" RP(r2): %s\n", regs->gr[2]);}void dump_stack(void){	show_stack(NULL, NULL);}EXPORT_SYMBOL(dump_stack);static void do_show_stack(struct unwind_frame_info *info){	int i = 1;	printk(KERN_CRIT "Backtrace:\n");	while (i <= 16) {		if (unwind_once(info) < 0 || info->ip == 0)			break;		if (__kernel_text_address(info->ip)) {			printk("%s [<" RFMT ">] ", (i&0x3)==1 ? KERN_CRIT : "", info->ip);#ifdef CONFIG_KALLSYMS			print_symbol("%s\n", info->ip);#else			if ((i & 0x03) == 0)				printk("\n");#endif			i++;		}	}	printk("\n");}void show_stack(struct task_struct *task, unsigned long *s){	struct unwind_frame_info info;	if (!task) {		unsigned long sp;HERE:		asm volatile ("copy %%r30, %0" : "=r"(sp));		{			struct pt_regs r;			memset(&r, 0, sizeof(struct pt_regs));			r.iaoq[0] = (unsigned long)&&HERE;			r.gr[2] = (unsigned long)__builtin_return_address(0);			r.gr[30] = sp;			unwind_frame_init(&info, current, &r);		}	} else {		unwind_frame_init_from_blocked_task(&info, task);	}	do_show_stack(&info);}int is_valid_bugaddr(unsigned long iaoq){	return 1;}void die_if_kernel(char *str, struct pt_regs *regs, long err){	if (user_mode(regs)) {		if (err == 0)			return; /* STFU */		printk(KERN_CRIT "%s (pid %d): %s (code %ld) at " RFMT "\n",			current->comm, task_pid_nr(current), str, err, regs->iaoq[0]);#ifdef PRINT_USER_FAULTS		/* XXX for debugging only */		show_regs(regs);#endif		return;	}	oops_in_progress = 1;	/* Amuse the user in a SPARC fashion */	if (err) printk(KERN_CRIT "      _______________________________ \n"KERN_CRIT "     < Your System ate a SPARC! Gah! >\n"KERN_CRIT "      ------------------------------- \n"KERN_CRIT "             \\   ^__^\n"KERN_CRIT "              \\  (xx)\\_______\n"KERN_CRIT "                 (__)\\       )\\/\\\n"KERN_CRIT "                  U  ||----w |\n"KERN_CRIT "                     ||     ||\n");		/* unlock the pdc lock if necessary */	pdc_emergency_unlock();	/* maybe the kernel hasn't booted very far yet and hasn't been able 	 * to initialize the serial or STI console. In that case we should 	 * re-enable the pdc console, so that the user will be able to 	 * identify the problem. */	if (!console_drivers)		pdc_console_restart();		if (err)		printk(KERN_CRIT "%s (pid %d): %s (code %ld)\n",			current->comm, task_pid_nr(current), str, err);	/* Wot's wrong wif bein' racy? */	if (current->thread.flags & PARISC_KERNEL_DEATH) {		printk(KERN_CRIT "%s() recursion detected.\n", __FUNCTION__);		local_irq_enable();		while (1);	}	current->thread.flags |= PARISC_KERNEL_DEATH;	show_regs(regs);	dump_stack();	add_taint(TAINT_DIE);	if (in_interrupt())		panic("Fatal exception in interrupt");	if (panic_on_oops) {		printk(KERN_EMERG "Fatal exception: panic in 5 seconds\n");		ssleep(5);		panic("Fatal exception");	}	do_exit(SIGSEGV);}int syscall_ipi(int (*syscall) (struct pt_regs *), struct pt_regs *regs){	return syscall(regs);}/* gdb uses break 4,8 */#define GDB_BREAK_INSN 0x10004static void handle_gdb_break(struct pt_regs *regs, int wot){	struct siginfo si;	si.si_signo = SIGTRAP;	si.si_errno = 0;	si.si_code = wot;	si.si_addr = (void __user *) (regs->iaoq[0] & ~3);	force_sig_info(SIGTRAP, &si, current);}static void handle_break(struct pt_regs *regs){	unsigned iir = regs->iir;	if (unlikely(iir == PARISC_BUG_BREAK_INSN && !user_mode(regs))) {		/* check if a BUG() or WARN() trapped here.  */		enum bug_trap_type tt;		tt = report_bug(regs->iaoq[0] & ~3, regs);		if (tt == BUG_TRAP_TYPE_WARN) {			regs->iaoq[0] += 4;			regs->iaoq[1] += 4;			return; /* return to next instruction when WARN_ON().  */		}		die_if_kernel("Unknown kernel breakpoint", regs,			(tt == BUG_TRAP_TYPE_NONE) ? 9 : 0);	}#ifdef PRINT_USER_FAULTS	if (unlikely(iir != GDB_BREAK_INSN)) {		printk(KERN_DEBUG "break %d,%d: pid=%d command='%s'\n",			iir & 31, (iir>>13) & ((1<<13)-1),			task_pid_nr(current), current->comm);		show_regs(regs);	}#endif	/* send standard GDB signal */	handle_gdb_break(regs, TRAP_BRKPT);}static void default_trap(int code, struct pt_regs *regs){	printk(KERN_ERR "Trap %d on CPU %d\n", code, smp_processor_id());	show_regs(regs);}void (*cpu_lpmc) (int code, struct pt_regs *regs) __read_mostly = default_trap;void transfer_pim_to_trap_frame(struct pt_regs *regs){    register int i;    extern unsigned int hpmc_pim_data[];    struct pdc_hpmc_pim_11 *pim_narrow;    struct pdc_hpmc_pim_20 *pim_wide;    if (boot_cpu_data.cpu_type >= pcxu) {	pim_wide = (struct pdc_hpmc_pim_20 *)hpmc_pim_data;	/*	 * Note: The following code will probably generate a	 * bunch of truncation error warnings from the compiler.	 * Could be handled with an ifdef, but perhaps there	 * is a better way.	 */	regs->gr[0] = pim_wide->cr[22];	for (i = 1; i < 32; i++)	    regs->gr[i] = pim_wide->gr[i];	for (i = 0; i < 32; i++)	    regs->fr[i] = pim_wide->fr[i];	for (i = 0; i < 8; i++)	    regs->sr[i] = pim_wide->sr[i];	regs->iasq[0] = pim_wide->cr[17];	regs->iasq[1] = pim_wide->iasq_back;	regs->iaoq[0] = pim_wide->cr[18];	regs->iaoq[1] = pim_wide->iaoq_back;	regs->sar  = pim_wide->cr[11];	regs->iir  = pim_wide->cr[19];	regs->isr  = pim_wide->cr[20];	regs->ior  = pim_wide->cr[21];    }    else {	pim_narrow = (struct pdc_hpmc_pim_11 *)hpmc_pim_data;	regs->gr[0] = pim_narrow->cr[22];	for (i = 1; i < 32; i++)	    regs->gr[i] = pim_narrow->gr[i];	for (i = 0; i < 32; i++)	    regs->fr[i] = pim_narrow->fr[i];	for (i = 0; i < 8; i++)	    regs->sr[i] = pim_narrow->sr[i];	regs->iasq[0] = pim_narrow->cr[17];	regs->iasq[1] = pim_narrow->iasq_back;	regs->iaoq[0] = pim_narrow->cr[18];	regs->iaoq[1] = pim_narrow->iaoq_back;	regs->sar  = pim_narrow->cr[11];	regs->iir  = pim_narrow->cr[19];	regs->isr  = pim_narrow->cr[20];	regs->ior  = pim_narrow->cr[21];    }    /*     * The following fields only have meaning if we came through     * another path. So just zero them here.     */    regs->ksp = 0;    regs->kpc = 0;    regs->orig_r28 = 0;}/* * This routine is called as a last resort when everything else * has gone clearly wrong. We get called for faults in kernel space, * and HPMC's. */void parisc_terminate(char *msg, struct pt_regs *regs, int code, unsigned long offset){	static DEFINE_SPINLOCK(terminate_lock);	oops_in_progress = 1;	set_eiem(0);	local_irq_disable();	spin_lock(&terminate_lock);	/* unlock the pdc lock if necessary */	pdc_emergency_unlock();	/* restart pdc console if necessary */

⌨️ 快捷键说明

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