| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271 | /* * arch/alpha/kernel/traps.c * * (C) Copyright 1994 Linus Torvalds *//* * This file initializes the trap entry points */#include <linux/jiffies.h>#include <linux/mm.h>#include <linux/sched.h>#include <linux/tty.h>#include <linux/delay.h>#include <linux/module.h>#include <linux/init.h>#include <linux/kallsyms.h>#include <linux/ratelimit.h>#include <asm/gentrap.h>#include <asm/uaccess.h>#include <asm/unaligned.h>#include <asm/sysinfo.h>#include <asm/hwrpb.h>#include <asm/mmu_context.h>#include <asm/special_insns.h>#include "proto.h"/* Work-around for some SRMs which mishandle opDEC faults.  */static int opDEC_fix;static void __cpuinitopDEC_check(void){	__asm__ __volatile__ (	/* Load the address of... */	"	br	$16, 1f\n"	/* A stub instruction fault handler.  Just add 4 to the	   pc and continue.  */	"	ldq	$16, 8($sp)\n"	"	addq	$16, 4, $16\n"	"	stq	$16, 8($sp)\n"	"	call_pal %[rti]\n"	/* Install the instruction fault handler.  */	"1:	lda	$17, 3\n"	"	call_pal %[wrent]\n"	/* With that in place, the fault from the round-to-minf fp	   insn will arrive either at the "lda 4" insn (bad) or one	   past that (good).  This places the correct fixup in %0.  */	"	lda %[fix], 0\n"	"	cvttq/svm $f31,$f31\n"	"	lda %[fix], 4"	: [fix] "=r" (opDEC_fix)	: [rti] "n" (PAL_rti), [wrent] "n" (PAL_wrent)	: "$0", "$1", "$16", "$17", "$22", "$23", "$24", "$25");	if (opDEC_fix)		printk("opDEC fixup enabled.\n");}voiddik_show_regs(struct pt_regs *regs, unsigned long *r9_15){	printk("pc = [<%016lx>]  ra = [<%016lx>]  ps = %04lx    %s\n",	       regs->pc, regs->r26, regs->ps, print_tainted());	print_symbol("pc is at %s\n", regs->pc);	print_symbol("ra is at %s\n", regs->r26 );	printk("v0 = %016lx  t0 = %016lx  t1 = %016lx\n",	       regs->r0, regs->r1, regs->r2);	printk("t2 = %016lx  t3 = %016lx  t4 = %016lx\n", 	       regs->r3, regs->r4, regs->r5);	printk("t5 = %016lx  t6 = %016lx  t7 = %016lx\n",	       regs->r6, regs->r7, regs->r8);	if (r9_15) {		printk("s0 = %016lx  s1 = %016lx  s2 = %016lx\n",		       r9_15[9], r9_15[10], r9_15[11]);		printk("s3 = %016lx  s4 = %016lx  s5 = %016lx\n",		       r9_15[12], r9_15[13], r9_15[14]);		printk("s6 = %016lx\n", r9_15[15]);	}	printk("a0 = %016lx  a1 = %016lx  a2 = %016lx\n",	       regs->r16, regs->r17, regs->r18);	printk("a3 = %016lx  a4 = %016lx  a5 = %016lx\n", 	       regs->r19, regs->r20, regs->r21); 	printk("t8 = %016lx  t9 = %016lx  t10= %016lx\n",	       regs->r22, regs->r23, regs->r24);	printk("t11= %016lx  pv = %016lx  at = %016lx\n",	       regs->r25, regs->r27, regs->r28);	printk("gp = %016lx  sp = %p\n", regs->gp, regs+1);#if 0__halt();#endif}#if 0static char * ireg_name[] = {"v0", "t0", "t1", "t2", "t3", "t4", "t5", "t6",			   "t7", "s0", "s1", "s2", "s3", "s4", "s5", "s6",			   "a0", "a1", "a2", "a3", "a4", "a5", "t8", "t9",			   "t10", "t11", "ra", "pv", "at", "gp", "sp", "zero"};#endifstatic voiddik_show_code(unsigned int *pc){	long i;	printk("Code:");	for (i = -6; i < 2; i++) {		unsigned int insn;		if (__get_user(insn, (unsigned int __user *)pc + i))			break;		printk("%c%08x%c", i ? ' ' : '<', insn, i ? ' ' : '>');	}	printk("\n");}static voiddik_show_trace(unsigned long *sp){	long i = 0;	printk("Trace:\n");	while (0x1ff8 & (unsigned long) sp) {		extern char _stext[], _etext[];		unsigned long tmp = *sp;		sp++;		if (tmp < (unsigned long) &_stext)			continue;		if (tmp >= (unsigned long) &_etext)			continue;		printk("[<%lx>]", tmp);		print_symbol(" %s", tmp);		printk("\n");		if (i > 40) {			printk(" ...");			break;		}	}	printk("\n");}static int kstack_depth_to_print = 24;void show_stack(struct task_struct *task, unsigned long *sp){	unsigned long *stack;	int i;	/*	 * debugging aid: "show_stack(NULL);" prints the	 * back trace for this cpu.	 */	if(sp==NULL)		sp=(unsigned long*)&sp;	stack = sp;	for(i=0; i < kstack_depth_to_print; i++) {		if (((long) stack & (THREAD_SIZE-1)) == 0)			break;		if (i && ((i % 4) == 0))			printk("\n       ");		printk("%016lx ", *stack++);	}	printk("\n");	dik_show_trace(sp);}void dump_stack(void){	show_stack(NULL, NULL);}EXPORT_SYMBOL(dump_stack);voiddie_if_kernel(char * str, struct pt_regs *regs, long err, unsigned long *r9_15){	if (regs->ps & 8)		return;#ifdef CONFIG_SMP	printk("CPU %d ", hard_smp_processor_id());#endif	printk("%s(%d): %s %ld\n", current->comm, task_pid_nr(current), str, err);	dik_show_regs(regs, r9_15);	add_taint(TAINT_DIE);	dik_show_trace((unsigned long *)(regs+1));	dik_show_code((unsigned int *)regs->pc);	if (test_and_set_thread_flag (TIF_DIE_IF_KERNEL)) {		printk("die_if_kernel recursion detected.\n");		local_irq_enable();		while (1);	}	do_exit(SIGSEGV);}#ifndef CONFIG_MATHEMUstatic long dummy_emul(void) { return 0; }long (*alpha_fp_emul_imprecise)(struct pt_regs *regs, unsigned long writemask)  = (void *)dummy_emul;long (*alpha_fp_emul) (unsigned long pc)  = (void *)dummy_emul;#elselong alpha_fp_emul_imprecise(struct pt_regs *regs, unsigned long writemask);long alpha_fp_emul (unsigned long pc);#endifasmlinkage voiddo_entArith(unsigned long summary, unsigned long write_mask,	    struct pt_regs *regs){	long si_code = FPE_FLTINV;	siginfo_t info;	if (summary & 1) {		/* Software-completion summary bit is set, so try to		   emulate the instruction.  If the processor supports		   precise exceptions, we don't have to search.  */		if (!amask(AMASK_PRECISE_TRAP))			si_code = alpha_fp_emul(regs->pc - 4);		else			si_code = alpha_fp_emul_imprecise(regs, write_mask);		if (si_code == 0)			return;	}	die_if_kernel("Arithmetic fault", regs, 0, NULL);	info.si_signo = SIGFPE;	info.si_errno = 0;	info.si_code = si_code;	info.si_addr = (void __user *) regs->pc;	send_sig_info(SIGFPE, &info, current);}asmlinkage voiddo_entIF(unsigned long type, struct pt_regs *regs){	siginfo_t info;	int signo, code;	if ((regs->ps & ~IPL_MAX) == 0) {		if (type == 1) {			const unsigned int *data			  = (const unsigned int *) regs->pc;			printk("Kernel bug at %s:%d\n",			       (const char *)(data[1] | (long)data[2] << 32), 			       data[0]);		}		die_if_kernel((type == 1 ? "Kernel Bug" : "Instruction fault"),			      regs, type, NULL);	}	switch (type) {	      case 0: /* breakpoint */		info.si_signo = SIGTRAP;		info.si_errno = 0;		info.si_code = TRAP_BRKPT;		info.si_trapno = 0;		info.si_addr = (void __user *) regs->pc;		if (ptrace_cancel_bpt(current)) {			regs->pc -= 4;	/* make pc point to former bpt */		}		send_sig_info(SIGTRAP, &info, current);		return;
 |