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 __cpuinit
- opDEC_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");
- }
- void
- dik_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 0
- static 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"};
- #endif
- static void
- dik_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 void
- dik_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);
- void
- die_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_MATHEMU
- static 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;
- #else
- long alpha_fp_emul_imprecise(struct pt_regs *regs, unsigned long writemask);
- long alpha_fp_emul (unsigned long pc);
- #endif
- asmlinkage void
- do_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 void
- do_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;
|