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

📄 traps.c

📁 linux 内核源代码
💻 C
📖 第 1 页 / 共 3 页
字号:
 * instead, so we're doing the emulation thing in both exception handlers. */static int simulate_llsc(struct pt_regs *regs, unsigned int opcode){	if ((opcode & OPCODE) == LL)		return simulate_ll(regs, opcode);	if ((opcode & OPCODE) == SC)		return simulate_sc(regs, opcode);	return -1;			/* Must be something else ... */}/* * Simulate trapping 'rdhwr' instructions to provide user accessible * registers not implemented in hardware.  The only current use of this * is the thread area pointer. */static int simulate_rdhwr(struct pt_regs *regs, unsigned int opcode){	struct thread_info *ti = task_thread_info(current);	if ((opcode & OPCODE) == SPEC3 && (opcode & FUNC) == RDHWR) {		int rd = (opcode & RD) >> 11;		int rt = (opcode & RT) >> 16;		switch (rd) {			case 29:				regs->regs[rt] = ti->tp_value;				return 0;			default:				return -1;		}	}	/* Not ours.  */	return -1;}static int simulate_sync(struct pt_regs *regs, unsigned int opcode){	if ((opcode & OPCODE) == SPEC0 && (opcode & FUNC) == SYNC)		return 0;	return -1;			/* Must be something else ... */}asmlinkage void do_ov(struct pt_regs *regs){	siginfo_t info;	die_if_kernel("Integer overflow", regs);	info.si_code = FPE_INTOVF;	info.si_signo = SIGFPE;	info.si_errno = 0;	info.si_addr = (void __user *) regs->cp0_epc;	force_sig_info(SIGFPE, &info, current);}/* * XXX Delayed fp exceptions when doing a lazy ctx switch XXX */asmlinkage void do_fpe(struct pt_regs *regs, unsigned long fcr31){	siginfo_t info;	die_if_kernel("FP exception in kernel code", regs);	if (fcr31 & FPU_CSR_UNI_X) {		int sig;		/*		 * Unimplemented operation exception.  If we've got the full		 * software emulator on-board, let's use it...		 *		 * Force FPU to dump state into task/thread context.  We're		 * moving a lot of data here for what is probably a single		 * instruction, but the alternative is to pre-decode the FP		 * register operands before invoking the emulator, which seems		 * a bit extreme for what should be an infrequent event.		 */		/* Ensure 'resume' not overwrite saved fp context again. */		lose_fpu(1);		/* Run the emulator */		sig = fpu_emulator_cop1Handler(regs, &current->thread.fpu, 1);		/*		 * We can't allow the emulated instruction to leave any of		 * the cause bit set in $fcr31.		 */		current->thread.fpu.fcr31 &= ~FPU_CSR_ALL_X;		/* Restore the hardware register state */		own_fpu(1);	/* Using the FPU again.  */		/* If something went wrong, signal */		if (sig)			force_sig(sig, current);		return;	} else if (fcr31 & FPU_CSR_INV_X)		info.si_code = FPE_FLTINV;	else if (fcr31 & FPU_CSR_DIV_X)		info.si_code = FPE_FLTDIV;	else if (fcr31 & FPU_CSR_OVF_X)		info.si_code = FPE_FLTOVF;	else if (fcr31 & FPU_CSR_UDF_X)		info.si_code = FPE_FLTUND;	else if (fcr31 & FPU_CSR_INE_X)		info.si_code = FPE_FLTRES;	else		info.si_code = __SI_FAULT;	info.si_signo = SIGFPE;	info.si_errno = 0;	info.si_addr = (void __user *) regs->cp0_epc;	force_sig_info(SIGFPE, &info, current);}asmlinkage void do_bp(struct pt_regs *regs){	unsigned int opcode, bcode;	siginfo_t info;	if (__get_user(opcode, (unsigned int __user *) exception_epc(regs)))		goto out_sigsegv;	/*	 * There is the ancient bug in the MIPS assemblers that the break	 * code starts left to bit 16 instead to bit 6 in the opcode.	 * Gas is bug-compatible, but not always, grrr...	 * We handle both cases with a simple heuristics.  --macro	 */	bcode = ((opcode >> 6) & ((1 << 20) - 1));	if (bcode < (1 << 10))		bcode <<= 10;	/*	 * (A short test says that IRIX 5.3 sends SIGTRAP for all break	 * insns, even for break codes that indicate arithmetic failures.	 * Weird ...)	 * But should we continue the brokenness???  --macro	 */	switch (bcode) {	case BRK_OVERFLOW << 10:	case BRK_DIVZERO << 10:		die_if_kernel("Break instruction in kernel code", regs);		if (bcode == (BRK_DIVZERO << 10))			info.si_code = FPE_INTDIV;		else			info.si_code = FPE_INTOVF;		info.si_signo = SIGFPE;		info.si_errno = 0;		info.si_addr = (void __user *) regs->cp0_epc;		force_sig_info(SIGFPE, &info, current);		break;	case BRK_BUG:		die("Kernel bug detected", regs);		break;	default:		die_if_kernel("Break instruction in kernel code", regs);		force_sig(SIGTRAP, current);	}	return;out_sigsegv:	force_sig(SIGSEGV, current);}asmlinkage void do_tr(struct pt_regs *regs){	unsigned int opcode, tcode = 0;	siginfo_t info;	if (__get_user(opcode, (unsigned int __user *) exception_epc(regs)))		goto out_sigsegv;	/* Immediate versions don't provide a code.  */	if (!(opcode & OPCODE))		tcode = ((opcode >> 6) & ((1 << 10) - 1));	/*	 * (A short test says that IRIX 5.3 sends SIGTRAP for all trap	 * insns, even for trap codes that indicate arithmetic failures.	 * Weird ...)	 * But should we continue the brokenness???  --macro	 */	switch (tcode) {	case BRK_OVERFLOW:	case BRK_DIVZERO:		die_if_kernel("Trap instruction in kernel code", regs);		if (tcode == BRK_DIVZERO)			info.si_code = FPE_INTDIV;		else			info.si_code = FPE_INTOVF;		info.si_signo = SIGFPE;		info.si_errno = 0;		info.si_addr = (void __user *) regs->cp0_epc;		force_sig_info(SIGFPE, &info, current);		break;	case BRK_BUG:		die("Kernel bug detected", regs);		break;	default:		die_if_kernel("Trap instruction in kernel code", regs);		force_sig(SIGTRAP, current);	}	return;out_sigsegv:	force_sig(SIGSEGV, current);}asmlinkage void do_ri(struct pt_regs *regs){	unsigned int __user *epc = (unsigned int __user *)exception_epc(regs);	unsigned long old_epc = regs->cp0_epc;	unsigned int opcode = 0;	int status = -1;	die_if_kernel("Reserved instruction in kernel code", regs);	if (unlikely(compute_return_epc(regs) < 0))		return;	if (unlikely(get_user(opcode, epc) < 0))		status = SIGSEGV;	if (!cpu_has_llsc && status < 0)		status = simulate_llsc(regs, opcode);	if (status < 0)		status = simulate_rdhwr(regs, opcode);	if (status < 0)		status = simulate_sync(regs, opcode);	if (status < 0)		status = SIGILL;	if (unlikely(status > 0)) {		regs->cp0_epc = old_epc;		/* Undo skip-over.  */		force_sig(status, current);	}}/* * MIPS MT processors may have fewer FPU contexts than CPU threads. If we've * emulated more than some threshold number of instructions, force migration to * a "CPU" that has FP support. */static void mt_ase_fp_affinity(void){#ifdef CONFIG_MIPS_MT_FPAFF	if (mt_fpemul_threshold > 0 &&	     ((current->thread.emulated_fp++ > mt_fpemul_threshold))) {		/*		 * If there's no FPU present, or if the application has already		 * restricted the allowed set to exclude any CPUs with FPUs,		 * we'll skip the procedure.		 */		if (cpus_intersects(current->cpus_allowed, mt_fpu_cpumask)) {			cpumask_t tmask;			cpus_and(tmask, current->thread.user_cpus_allowed,			         mt_fpu_cpumask);			set_cpus_allowed(current, tmask);			set_thread_flag(TIF_FPUBOUND);		}	}#endif /* CONFIG_MIPS_MT_FPAFF */}asmlinkage void do_cpu(struct pt_regs *regs){	unsigned int __user *epc;	unsigned long old_epc;	unsigned int opcode;	unsigned int cpid;	int status;	die_if_kernel("do_cpu invoked from kernel context!", regs);	cpid = (regs->cp0_cause >> CAUSEB_CE) & 3;	switch (cpid) {	case 0:		epc = (unsigned int __user *)exception_epc(regs);		old_epc = regs->cp0_epc;		opcode = 0;		status = -1;		if (unlikely(compute_return_epc(regs) < 0))			return;		if (unlikely(get_user(opcode, epc) < 0))			status = SIGSEGV;		if (!cpu_has_llsc && status < 0)			status = simulate_llsc(regs, opcode);		if (status < 0)			status = simulate_rdhwr(regs, opcode);		if (status < 0)			status = SIGILL;		if (unlikely(status > 0)) {			regs->cp0_epc = old_epc;	/* Undo skip-over.  */			force_sig(status, current);		}		return;	case 1:		if (used_math())	/* Using the FPU again.  */			own_fpu(1);		else {			/* First time FPU user.  */			init_fpu();			set_used_math();		}		if (!raw_cpu_has_fpu) {			int sig;			sig = fpu_emulator_cop1Handler(regs,						&current->thread.fpu, 0);			if (sig)				force_sig(sig, current);			else				mt_ase_fp_affinity();		}		return;	case 2:	case 3:		break;	}	force_sig(SIGILL, current);}asmlinkage void do_mdmx(struct pt_regs *regs){	force_sig(SIGILL, current);}asmlinkage void do_watch(struct pt_regs *regs){	if (board_watchpoint_handler) {		(*board_watchpoint_handler)(regs);		return;	}	/*	 * We use the watch exception where available to detect stack	 * overflows.	 */	dump_tlb_all();	show_regs(regs);	panic("Caught WATCH exception - probably caused by stack overflow.");}asmlinkage void do_mcheck(struct pt_regs *regs){	const int field = 2 * sizeof(unsigned long);	int multi_match = regs->cp0_status & ST0_TS;	show_regs(regs);	if (multi_match) {		printk("Index   : %0x\n", read_c0_index());		printk("Pagemask: %0x\n", read_c0_pagemask());		printk("EntryHi : %0*lx\n", field, read_c0_entryhi());		printk("EntryLo0: %0*lx\n", field, read_c0_entrylo0());		printk("EntryLo1: %0*lx\n", field, read_c0_entrylo1());		printk("\n");		dump_tlb_all();	}	show_code((unsigned int __user *) regs->cp0_epc);	/*	 * Some chips may have other causes of machine check (e.g. SB1	 * graduation timer)	 */	panic("Caught Machine Check exception - %scaused by multiple "	      "matching entries in the TLB.",	      (multi_match) ? "" : "not ");}asmlinkage void do_mt(struct pt_regs *regs){	int subcode;	subcode = (read_vpe_c0_vpecontrol() & VPECONTROL_EXCPT)			>> VPECONTROL_EXCPT_SHIFT;	switch (subcode) {	case 0:		printk(KERN_DEBUG "Thread Underflow\n");		break;	case 1:		printk(KERN_DEBUG "Thread Overflow\n");		break;	case 2:		printk(KERN_DEBUG "Invalid YIELD Qualifier\n");		break;	case 3:		printk(KERN_DEBUG "Gating Storage Exception\n");		break;	case 4:		printk(KERN_DEBUG "YIELD Scheduler Exception\n");		break;	case 5:		printk(KERN_DEBUG "Gating Storage Schedulier Exception\n");		break;	default:		printk(KERN_DEBUG "*** UNKNOWN THREAD EXCEPTION %d ***\n",			subcode);		break;	}	die_if_kernel("MIPS MT Thread exception in kernel", regs);	force_sig(SIGILL, current);}asmlinkage void do_dsp(struct pt_regs *regs){	if (cpu_has_dsp)		panic("Unexpected DSP exception\n");	force_sig(SIGILL, current);}asmlinkage void do_reserved(struct pt_regs *regs){	/*	 * Game over - no way to handle this if it ever occurs.  Most probably	 * caused by a new unknown cpu type or after another deadly	 * hard/software error.	 */	show_regs(regs);	panic("Caught reserved exception %ld - should not happen.",	      (regs->cp0_cause & 0x7f) >> 2);}/* * Some MIPS CPUs can enable/disable for cache parity detection, but do * it different ways. */static inline void parity_protection_init(void){	switch (current_cpu_type()) {	case CPU_24K:	case CPU_34K:	case CPU_5KC:		write_c0_ecc(0x80000000);		back_to_back_c0_hazard();		/* Set the PE bit (bit 31) in the c0_errctl register. */		printk(KERN_INFO "Cache parity protection %sabled\n",		       (read_c0_ecc() & 0x80000000) ? "en" : "dis");		break;	case CPU_20KC:	case CPU_25KF:		/* Clear the DE bit (bit 16) in the c0_status register. */		printk(KERN_INFO "Enable cache parity protection for "		       "MIPS 20KC/25KF CPUs.\n");		clear_c0_status(ST0_DE);		break;	default:		break;	}}asmlinkage void cache_parity_error(void){	const int field = 2 * sizeof(unsigned long);	unsigned int reg_val;	/* For the moment, report the problem and hang. */	printk("Cache error exception:\n");	printk("cp0_errorepc == %0*lx\n", field, read_c0_errorepc());	reg_val = read_c0_cacheerr();	printk("c0_cacheerr == %08x\n", reg_val);	printk("Decoded c0_cacheerr: %s cache fault in %s reference.\n",	       reg_val & (1<<30) ? "secondary" : "primary",	       reg_val & (1<<31) ? "data" : "insn");	printk("Error bits: %s%s%s%s%s%s%s\n",	       reg_val & (1<<29) ? "ED " : "",	       reg_val & (1<<28) ? "ET " : "",	       reg_val & (1<<26) ? "EE " : "",	       reg_val & (1<<25) ? "EB " : "",	       reg_val & (1<<24) ? "EI " : "",	       reg_val & (1<<23) ? "E1 " : "",	       reg_val & (1<<22) ? "E0 " : "");	printk("IDX: 0x%08x\n", reg_val & ((1<<22)-1));#if defined(CONFIG_CPU_MIPS32) || defined(CONFIG_CPU_MIPS64)	if (reg_val & (1<<22))		printk("DErrAddr0: 0x%0*lx\n", field, read_c0_derraddr0());	if (reg_val & (1<<23))		printk("DErrAddr1: 0x%0*lx\n", field, read_c0_derraddr1());#endif	panic("Can't handle the cache error!");}/* * SDBBP EJTAG debug exception handler. * We skip the instruction and return to the next instruction. */void ejtag_exception_handler(struct pt_regs *regs){	const int field = 2 * sizeof(unsigned long);	unsigned long depc, old_epc;	unsigned int debug;	printk(KERN_DEBUG "SDBBP EJTAG debug exception - not handled yet, just ignored!\n");	depc = read_c0_depc();	debug = read_c0_debug();

⌨️ 快捷键说明

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