📄 traps.c
字号:
/* * 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/config.h>#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/mm.h>#include <linux/smp.h>#include <linux/smp_lock.h>#include <linux/spinlock.h>#include <linux/init.h>#include <linux/interrupt.h>#include <asm/system.h>#include <asm/uaccess.h>#include <asm/io.h>#include <asm/irq.h>#include <asm/atomic.h>#include <asm/smp.h>#include <asm/pdc.h>#ifdef CONFIG_KWDB#include <kdb/break.h> /* for BI2_KGDB_GDB */#include <kdb/kgdb_types.h> /* for __() */#include <kdb/save_state.h> /* for struct save_state */#include <kdb/kgdb_machine.h> /* for pt_regs_to_ssp and ssp_to_pt_regs */#include <kdb/trap.h> /* for I_BRK_INST */#endif /* CONFIG_KWDB */static inline void console_verbose(void){ console_loglevel = 15;}void page_exception(void);/* * These constants are for searching for possible module text * segments. VMALLOC_OFFSET comes from mm/vmalloc.c; MODULE_RANGE is * a guess of how much space is likely to be vmalloced. */#define VMALLOC_OFFSET (8*1024*1024)#define MODULE_RANGE (8*1024*1024)int kstack_depth_to_print = 24;static void printbinary(unsigned long x, int nbits){ unsigned long mask = 1UL << (nbits - 1); while (mask != 0) { printk(mask & x ? "1" : "0"); mask >>= 1; }}void show_regs(struct pt_regs *regs){ int i;#ifdef __LP64__#define RFMT " %016lx"#else#define RFMT " %08lx"#endif printk("\n"); /* don't want to have that pretty register dump messed up */ printk(" YZrvWESTHLNXBCVMcbcbcbcbOGFRQPDI\nPSW: "); printbinary(regs->gr[0], 32); printk(" %s\n", print_tainted()); for (i = 0; i < 32; i += 4) { int j; printk("r%d-%d\t", i, i + 3); for (j = 0; j < 4; j++) { printk(RFMT, i + j == 0 ? 0 : regs->gr[i + j]); } printk("\n"); } for (i = 0; i < 8; i += 4) { int j; printk("sr%d-%d\t", i, i + 4); for (j = 0; j < 4; j++) { printk(RFMT, regs->sr[i + j]); } printk("\n"); }#if REDICULOUSLY_VERBOSE for (i = 0; i < 32; i++) { printk("FR%2d : %016lx ", i, regs->fr[i]); if ((i & 1) == 1) printk("\n"); }#endif printk("\nIASQ:" RFMT RFMT " IAOQ:" RFMT RFMT "\n", regs->iasq[0], regs->iasq[1], regs->iaoq[0], regs->iaoq[1]); printk(" IIR: %08lx ISR:" RFMT " IOR:" RFMT "\nORIG_R28:" RFMT "\n", regs->iir, regs->isr, regs->ior, regs->orig_r28);}voiddie_if_kernel (char *str, struct pt_regs *regs, long err){ if (user_mode(regs)) {#if 1 if (err == 0) return; /* STFU */ /* XXX for debugging only */ printk ("!!die_if_kernel: %s(%d): %s %ld\n", current->comm, current->pid, str, err); show_regs(regs);#endif return; } printk("%s[%d]: %s %ld\n", current->comm, current->pid, str, err); show_regs(regs); /* Wot's wrong wif bein' racy? */ if (current->thread.flags & PARISC_KERNEL_DEATH) { printk("die_if_kernel recursion detected.\n"); sti(); while (1); } current->thread.flags |= PARISC_KERNEL_DEATH; do_exit(SIGSEGV);}asmlinkage void cache_flush_denied(struct pt_regs * regs, long error_code){}asmlinkage void do_general_protection(struct pt_regs * regs, long error_code){}#ifndef CONFIG_MATH_EMULATIONasmlinkage void math_emulate(long arg){}#endif /* CONFIG_MATH_EMULATION */int syscall_ipi(int (*syscall) (struct pt_regs *), struct pt_regs *regs){ return syscall(regs);}struct { int retval; int (*func) (void *, struct pt_regs *); void * data;} ipi_action[NR_CPUS];void ipi_interrupt(int irq, void *unused, struct pt_regs *regs){ int cpu = smp_processor_id(); if(!ipi_action[cpu].func) BUG(); ipi_action[cpu].retval = ipi_action[cpu].func(ipi_action[cpu].data, regs);}/* gdb uses break 4,8 */#define GDB_BREAK_INSN 0x10004void handle_gdb_break(struct pt_regs *regs, int wot){ struct siginfo si; si.si_code = wot; si.si_addr = (void *) (regs->iaoq[0] & ~3); si.si_signo = SIGTRAP; si.si_errno = 0; force_sig_info(SIGTRAP, &si, current);}void handle_break(unsigned iir, struct pt_regs *regs){ struct siginfo si;#ifdef CONFIG_KWDB struct save_state ssp;#endif /* CONFIG_KWDB */ flush_all_caches(); switch(iir) { case 0x00: /* show registers, halt */ cli(); printk("break 0,0: pid=%d command='%s'\n", current->pid, current->comm); die_if_kernel("Breakpoint", regs, 0); show_regs(regs); si.si_code = TRAP_BRKPT; si.si_addr = (void *) (regs->iaoq[0] & ~3); si.si_signo = SIGTRAP; force_sig_info(SIGTRAP, &si, current); break; case GDB_BREAK_INSN: die_if_kernel("Breakpoint", regs, 0); handle_gdb_break(regs, TRAP_BRKPT); break;#ifdef CONFIG_KWDB case KGDB_BREAK_INSN: mtctl(0, 15); pt_regs_to_ssp(regs, &ssp); kgdb_trap(I_BRK_INST, &ssp, 1); ssp_to_pt_regs(&ssp, regs); break; case KGDB_INIT_BREAK_INSN: mtctl(0, 15); pt_regs_to_ssp(regs, &ssp); kgdb_trap(I_BRK_INST, &ssp, 1); ssp_to_pt_regs(&ssp, regs); /* Advance pcoq to skip break */ regs->iaoq[0] = regs->iaoq[1]; regs->iaoq[1] += 4; break;#endif /* CONFIG_KWDB */ default: set_eiem(0); printk("break %#08x: pid=%d command='%s'\n", iir, current->pid, current->comm); show_regs(regs); si.si_signo = SIGTRAP; si.si_code = TRAP_BRKPT; si.si_addr = (void *) (regs->iaoq[0] & ~3); force_sig_info(SIGTRAP, &si, current); return; }}/* Format of the floating-point exception registers. */struct exc_reg { unsigned int exception : 6; unsigned int ei : 26;};/* Macros for grabbing bits of the instruction format from the 'ei' field above. *//* Major opcode 0c and 0e */#define FP0CE_UID(i) (((i) >> 6) & 3)#define FP0CE_CLASS(i) (((i) >> 9) & 3)#define FP0CE_SUBOP(i) (((i) >> 13) & 7)#define FP0CE_SUBOP1(i) (((i) >> 15) & 7) /* Class 1 subopcode */#define FP0C_FORMAT(i) (((i) >> 11) & 3)#define FP0E_FORMAT(i) (((i) >> 11) & 1)/* Major opcode 0c, uid 2 (performance monitoring) */#define FPPM_SUBOP(i) (((i) >> 9) & 0x1f)/* Major opcode 2e (fused operations). */#define FP2E_SUBOP(i) (((i) >> 5) & 1)#define FP2E_FORMAT(i) (((i) >> 11) & 1)/* Major opcode 26 (FMPYSUB) *//* Major opcode 06 (FMPYADD) */#define FPx6_FORMAT(i) ((i) & 0x1f)/* Flags and enable bits of the status word. */#define FPSW_FLAGS(w) ((w) >> 27)#define FPSW_ENABLE(w) ((w) & 0x1f)#define FPSW_V (1<<4)#define FPSW_Z (1<<3)#define FPSW_O (1<<2)#define FPSW_U (1<<1)#define FPSW_I (1<<0)/* Emulate a floating point instruction if necessary and possible (this will be moved elsewhere eventually). Return zero if successful or if emulation was not required, -1 if the instruction is actually illegal or unimplemented. The status word passed as the first parameter will be modified to signal exceptions, if any. *//* FIXME!!! This is really incomplete and, at the moment, most illegal FP instructions will simply act as no-ops. Obviously that is *not* what we want. Also we don't even try to handle exception types other than the 'unimplemented' ones. */intfp_emul_insn(u32 *sw, struct exc_reg exc, struct pt_regs *regs){ switch (exc.exception) { case 0x3: /* Unimplemented, opcode 06 */ break; case 0x9: /* Unimplemented, opcode 0c */ /* We do not support quadword operations, end of story. There's no support for them in GCC. */ if (FP0C_FORMAT(exc.ei) == 3) return -1; /* SIGILL */ /* Fall through. */ case 0xa: /* Unimplemented, opcode 0e */ if (FP0CE_CLASS(exc.ei) == 1) { /* FCNV instructions of various sorts. */ } else { if (FP0CE_CLASS(exc.ei == 0) && FP0CE_SUBOP(exc.ei == 5)) { /* FRND instructions should be emulated, at some point, I guess. */ return -1; /* SIGILL */ } } break; case 0x23: /* Unimplemented, opcode 26 */ break; case 0x2b: /* Unimplemented, opcode 2e */ break; case 0x1: /* Unimplemented, opcode 0e/0c */ /* FIXME: How the hell are we supposed to tell which opcode it is? */ break; default: return -1; /* Punt */ } return 0;}/* Handle a floating point exception. Return zero if the faulting instruction can be completed successfully. */inthandle_fpe(struct pt_regs *regs){ struct siginfo si; union { struct fpsw { /* flag bits */ unsigned int fv : 1; unsigned int fz : 1; unsigned int fo : 1; unsigned int fu : 1; unsigned int fi : 1; unsigned int c : 1; unsigned int pad1 : 4; unsigned int cq : 11; unsigned int rm : 2; unsigned int pad2 : 2; unsigned int t : 1; unsigned int d : 1; /* enable bits */ unsigned int ev : 1; unsigned int ez : 1; unsigned int eo : 1; unsigned int eu : 1; unsigned int ei : 1; } status; u32 word; } sw; struct exc_reg excepts[7]; unsigned int code = 0; unsigned int throw; /* Status word = FR0L. */ memcpy(&sw, regs->fr, sizeof(sw)); /* Exception words = FR0R-FR3R. */ memcpy(excepts, ((char *) regs->fr) + 4, sizeof(excepts)); /* This is all CPU dependent. Since there is no public documentation on the PA2.0 processors we will just assume everything is like the 7100/7100LC/7300LC for now. Specifically: All exceptions are marked as "unimplemented" in the exception word, and the only exception word used is excepts[1]. */ /* Try to emulate the instruction. Also determine if it is really an illegal instruction in the process. FIXME: fp_emul_insn() only checks for the "unimplemented" exceptions at the moment. So this may break horribly on PA2.0, where we may want to also check to see if we should just send SIGFPE (or maybe not, let's see the documentation first...) */ if (fp_emul_insn(&sw.word, excepts[1], regs) == -1) goto send_sigill; /* Take the intersection of the flag bits in the FPSW and the enable bits in the FPSW. */ throw = FPSW_FLAGS(sw.word) & FPSW_ENABLE(sw.word); /* Concoct an appropriate si_code. Of course we don't know what to do if multiple exceptions were enabled and multiple flags were set. Maybe that's why HP/UX doesn't implement feenableexcept(). */ if (throw == 0) goto success; /* Duh. */ else if (throw & FPSW_V) code = FPE_FLTINV; else if (throw & FPSW_Z) code = FPE_FLTDIV; else if (throw & FPSW_O) code = FPE_FLTOVF; else if (throw & FPSW_U) code = FPE_FLTUND; else if (throw & FPSW_I) code = FPE_FLTRES;#if 1 /* Debugging... */ printk("Unemulated floating point exception, pid=%d (%s)\n", current->pid, current->comm); show_regs(regs); { int i; printk("FP Status: %08x\n", sw.word); printk("FP Exceptions:\n"); for (i = 0; i < 7; i++) { printk("\tExcept%d: exception %03x insn %06x\n", i, excepts[i].exception, excepts[i].ei); } }#endif /* FIXME: Should we clear the flag bits, T bit, and exception registers here? */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -