⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 traps.c

📁 Linux内核源代码 为压缩文件 是<<Linux内核>>一书中的源代码
💻 C
📖 第 1 页 / 共 2 页
字号:
/* *  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){	extern int console_loglevel;	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("\n");	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 + -