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

📄 traps.c

📁 MIZI Research, Inc.发布的嵌入式Linux内核源码
💻 C
📖 第 1 页 / 共 2 页
字号:
		"	.gprel32 4b\n"		"	lda $31,5b-4b(%0)\n"		".previous"			: "=r"(error), "=&r"(tmp1), "=&r"(tmp2),			  "=&r"(tmp3), "=&r"(tmp4)			: "r"(va), "r"(una_reg(reg)), "0"(0));		if (error)			goto got_exception;		return;	case 0x2d: /* stq */		__asm__ __volatile__(		"1:	ldq_u %2,7(%5)\n"		"2:	ldq_u %1,0(%5)\n"		"	insqh %6,%5,%4\n"		"	insql %6,%5,%3\n"		"	mskqh %2,%5,%2\n"		"	mskql %1,%5,%1\n"		"	or %2,%4,%2\n"		"	or %1,%3,%1\n"		"3:	stq_u %2,7(%5)\n"		"4:	stq_u %1,0(%5)\n"		"5:\n"		".section __ex_table,\"a\"\n\t"		"	.gprel32 1b\n"		"	lda %2,5b-1b(%0)\n"		"	.gprel32 2b\n"		"	lda %1,5b-2b(%0)\n"		"	.gprel32 3b\n"		"	lda $31,5b-3b(%0)\n"		"	.gprel32 4b\n"		"	lda $31,5b-4b(%0)\n"		".previous"			: "=r"(error), "=&r"(tmp1), "=&r"(tmp2),			  "=&r"(tmp3), "=&r"(tmp4)			: "r"(va), "r"(una_reg(reg)), "0"(0));		if (error)			goto got_exception;		return;	}	lock_kernel();	printk("Bad unaligned kernel access at %016lx: %p %lx %ld\n",		pc, va, opcode, reg);	do_exit(SIGSEGV);got_exception:	/* Ok, we caught the exception, but we don't want it.  Is there	   someone to pass it along to?  */	if ((fixup = search_exception_table(pc, regs.gp)) != 0) {		unsigned long newpc;		newpc = fixup_exception(una_reg, fixup, pc);		printk("Forwarding unaligned exception at %lx (%lx)\n",		       pc, newpc);		(&regs)->pc = newpc;		return;	}	/*	 * Yikes!  No one to forward the exception to.	 * Since the registers are in a weird format, dump them ourselves. 	 */	lock_kernel();	printk("%s(%d): unhandled unaligned exception\n",	       current->comm, current->pid);	printk("pc = [<%016lx>]  ra = [<%016lx>]  ps = %04lx\n",	       pc, una_reg(26), regs.ps);	printk("r0 = %016lx  r1 = %016lx  r2 = %016lx\n",	       una_reg(0), una_reg(1), una_reg(2));	printk("r3 = %016lx  r4 = %016lx  r5 = %016lx\n", 	       una_reg(3), una_reg(4), una_reg(5));	printk("r6 = %016lx  r7 = %016lx  r8 = %016lx\n",	       una_reg(6), una_reg(7), una_reg(8));	printk("r9 = %016lx  r10= %016lx  r11= %016lx\n",	       una_reg(9), una_reg(10), una_reg(11));	printk("r12= %016lx  r13= %016lx  r14= %016lx\n",	       una_reg(12), una_reg(13), una_reg(14));	printk("r15= %016lx\n", una_reg(15));	printk("r16= %016lx  r17= %016lx  r18= %016lx\n",	       una_reg(16), una_reg(17), una_reg(18));	printk("r19= %016lx  r20= %016lx  r21= %016lx\n", 	       una_reg(19), una_reg(20), una_reg(21)); 	printk("r22= %016lx  r23= %016lx  r24= %016lx\n",	       una_reg(22), una_reg(23), una_reg(24));	printk("r25= %016lx  r27= %016lx  r28= %016lx\n",	       una_reg(25), una_reg(27), una_reg(28));	printk("gp = %016lx  sp = %p\n", regs.gp, &regs+1);	dik_show_code((unsigned int *)pc);	dik_show_trace((unsigned long *)(&regs+1));	if (current->thread.flags & (1UL << 63)) {		printk("die_if_kernel recursion detected.\n");		sti();		while (1);	}	current->thread.flags |= (1UL << 63);	do_exit(SIGSEGV);}/* * Convert an s-floating point value in memory format to the * corresponding value in register format.  The exponent * needs to be remapped to preserve non-finite values * (infinities, not-a-numbers, denormals). */static inline unsigned longs_mem_to_reg (unsigned long s_mem){	unsigned long frac    = (s_mem >>  0) & 0x7fffff;	unsigned long sign    = (s_mem >> 31) & 0x1;	unsigned long exp_msb = (s_mem >> 30) & 0x1;	unsigned long exp_low = (s_mem >> 23) & 0x7f;	unsigned long exp;	exp = (exp_msb << 10) | exp_low;	/* common case */	if (exp_msb) {		if (exp_low == 0x7f) {			exp = 0x7ff;		}	} else {		if (exp_low == 0x00) {			exp = 0x000;		} else {			exp |= (0x7 << 7);		}	}	return (sign << 63) | (exp << 52) | (frac << 29);}/* * Convert an s-floating point value in register format to the * corresponding value in memory format. */static inline unsigned longs_reg_to_mem (unsigned long s_reg){	return ((s_reg >> 62) << 30) | ((s_reg << 5) >> 34);}/* * Handle user-level unaligned fault.  Handling user-level unaligned * faults is *extremely* slow and produces nasty messages.  A user * program *should* fix unaligned faults ASAP. * * Notice that we have (almost) the regular kernel stack layout here, * so finding the appropriate registers is a little more difficult * than in the kernel case. * * Finally, we handle regular integer load/stores only.  In * particular, load-linked/store-conditionally and floating point * load/stores are not supported.  The former make no sense with * unaligned faults (they are guaranteed to fail) and I don't think * the latter will occur in any decent program. * * Sigh. We *do* have to handle some FP operations, because GCC will * uses them as temporary storage for integer memory to memory copies. * However, we need to deal with stt/ldt and sts/lds only. */#define OP_INT_MASK	( 1L << 0x28 | 1L << 0x2c   /* ldl stl */	\			| 1L << 0x29 | 1L << 0x2d   /* ldq stq */	\			| 1L << 0x0c | 1L << 0x0d   /* ldwu stw */	\			| 1L << 0x0a | 1L << 0x0e ) /* ldbu stb */#define OP_WRITE_MASK	( 1L << 0x26 | 1L << 0x27   /* sts stt */	\			| 1L << 0x2c | 1L << 0x2d   /* stl stq */	\			| 1L << 0x0d | 1L << 0x0e ) /* stw stb */#define R(x)	((size_t) &((struct pt_regs *)0)->x)static int unauser_reg_offsets[32] = {	R(r0), R(r1), R(r2), R(r3), R(r4), R(r5), R(r6), R(r7), R(r8),	/* r9 ... r15 are stored in front of regs.  */	-56, -48, -40, -32, -24, -16, -8,	R(r16), R(r17), R(r18),	R(r19), R(r20), R(r21), R(r22), R(r23), R(r24), R(r25), R(r26),	R(r27), R(r28), R(gp),	0, 0};#undef Rasmlinkage voiddo_entUnaUser(void * va, unsigned long opcode,	      unsigned long reg, struct pt_regs *regs){	static int cnt = 0;	static long last_time = 0;	unsigned long tmp1, tmp2, tmp3, tmp4;	unsigned long fake_reg, *reg_addr = &fake_reg;	unsigned long uac_bits;	long error;	/* Check the UAC bits to decide what the user wants us to do	   with the unaliged access.  */	uac_bits = (current->thread.flags >> UAC_SHIFT) & UAC_BITMASK;	if (!(uac_bits & UAC_NOPRINT)) {		if (cnt >= 5 && jiffies - last_time > 5*HZ) {			cnt = 0;		}		if (++cnt < 5) {			printk("%s(%d): unaligned trap at %016lx: %p %lx %ld\n",			       current->comm, current->pid,			       regs->pc - 4, va, opcode, reg);		}		last_time = jiffies;	}	if (uac_bits & UAC_SIGBUS) {		goto give_sigbus;	}	if (uac_bits & UAC_NOFIX) {		/* Not sure why you'd want to use this, but... */		return;	}	/* Don't bother reading ds in the access check since we already	   know that this came from the user.  Also rely on the fact that	   the page at TASK_SIZE is unmapped and so can't be touched anyway. */	if (!__access_ok((unsigned long)va, 0, USER_DS))		goto give_sigsegv;	++unaligned[1].count;	unaligned[1].va = (unsigned long)va;	unaligned[1].pc = regs->pc - 4;	if ((1L << opcode) & OP_INT_MASK) {		/* it's an integer load/store */		if (reg < 30) {			reg_addr = (unsigned long *)			  ((char *)regs + unauser_reg_offsets[reg]);		} else if (reg == 30) {			/* usp in PAL regs */			fake_reg = rdusp();		} else {			/* zero "register" */			fake_reg = 0;		}	}	/* We don't want to use the generic get/put unaligned macros as	   we want to trap exceptions.  Only if we actually get an	   exception will we decide whether we should have caught it.  */	switch (opcode) {	case 0x0c: /* ldwu */		__asm__ __volatile__(		"1:	ldq_u %1,0(%3)\n"		"2:	ldq_u %2,1(%3)\n"		"	extwl %1,%3,%1\n"		"	extwh %2,%3,%2\n"		"3:\n"		".section __ex_table,\"a\"\n"		"	.gprel32 1b\n"		"	lda %1,3b-1b(%0)\n"		"	.gprel32 2b\n"		"	lda %2,3b-2b(%0)\n"		".previous"			: "=r"(error), "=&r"(tmp1), "=&r"(tmp2)			: "r"(va), "0"(0));		if (error)			goto give_sigsegv;		*reg_addr = tmp1|tmp2;		break;	case 0x22: /* lds */		__asm__ __volatile__(		"1:	ldq_u %1,0(%3)\n"		"2:	ldq_u %2,3(%3)\n"		"	extll %1,%3,%1\n"		"	extlh %2,%3,%2\n"		"3:\n"		".section __ex_table,\"a\"\n"		"	.gprel32 1b\n"		"	lda %1,3b-1b(%0)\n"		"	.gprel32 2b\n"		"	lda %2,3b-2b(%0)\n"		".previous"			: "=r"(error), "=&r"(tmp1), "=&r"(tmp2)			: "r"(va), "0"(0));		if (error)			goto give_sigsegv;		alpha_write_fp_reg(reg, s_mem_to_reg((int)(tmp1|tmp2)));		return;	case 0x23: /* ldt */		__asm__ __volatile__(		"1:	ldq_u %1,0(%3)\n"		"2:	ldq_u %2,7(%3)\n"		"	extql %1,%3,%1\n"		"	extqh %2,%3,%2\n"		"3:\n"		".section __ex_table,\"a\"\n"		"	.gprel32 1b\n"		"	lda %1,3b-1b(%0)\n"		"	.gprel32 2b\n"		"	lda %2,3b-2b(%0)\n"		".previous"			: "=r"(error), "=&r"(tmp1), "=&r"(tmp2)			: "r"(va), "0"(0));		if (error)			goto give_sigsegv;		alpha_write_fp_reg(reg, tmp1|tmp2);		return;	case 0x28: /* ldl */		__asm__ __volatile__(		"1:	ldq_u %1,0(%3)\n"		"2:	ldq_u %2,3(%3)\n"		"	extll %1,%3,%1\n"		"	extlh %2,%3,%2\n"		"3:\n"		".section __ex_table,\"a\"\n"		"	.gprel32 1b\n"		"	lda %1,3b-1b(%0)\n"		"	.gprel32 2b\n"		"	lda %2,3b-2b(%0)\n"		".previous"			: "=r"(error), "=&r"(tmp1), "=&r"(tmp2)			: "r"(va), "0"(0));		if (error)			goto give_sigsegv;		*reg_addr = (int)(tmp1|tmp2);		break;	case 0x29: /* ldq */		__asm__ __volatile__(		"1:	ldq_u %1,0(%3)\n"		"2:	ldq_u %2,7(%3)\n"		"	extql %1,%3,%1\n"		"	extqh %2,%3,%2\n"		"3:\n"		".section __ex_table,\"a\"\n"		"	.gprel32 1b\n"		"	lda %1,3b-1b(%0)\n"		"	.gprel32 2b\n"		"	lda %2,3b-2b(%0)\n"		".previous"			: "=r"(error), "=&r"(tmp1), "=&r"(tmp2)			: "r"(va), "0"(0));		if (error)			goto give_sigsegv;		*reg_addr = tmp1|tmp2;		break;	/* Note that the store sequences do not indicate that they change	   memory because it _should_ be affecting nothing in this context.	   (Otherwise we have other, much larger, problems.)  */	case 0x0d: /* stw */		__asm__ __volatile__(		"1:	ldq_u %2,1(%5)\n"		"2:	ldq_u %1,0(%5)\n"		"	inswh %6,%5,%4\n"		"	inswl %6,%5,%3\n"		"	mskwh %2,%5,%2\n"		"	mskwl %1,%5,%1\n"		"	or %2,%4,%2\n"		"	or %1,%3,%1\n"		"3:	stq_u %2,1(%5)\n"		"4:	stq_u %1,0(%5)\n"		"5:\n"		".section __ex_table,\"a\"\n"		"	.gprel32 1b\n"		"	lda %2,5b-1b(%0)\n"		"	.gprel32 2b\n"		"	lda %1,5b-2b(%0)\n"		"	.gprel32 3b\n"		"	lda $31,5b-3b(%0)\n"		"	.gprel32 4b\n"		"	lda $31,5b-4b(%0)\n"		".previous"			: "=r"(error), "=&r"(tmp1), "=&r"(tmp2),			  "=&r"(tmp3), "=&r"(tmp4)			: "r"(va), "r"(*reg_addr), "0"(0));		if (error)			goto give_sigsegv;		return;	case 0x26: /* sts */		fake_reg = s_reg_to_mem(alpha_read_fp_reg(reg));		/* FALLTHRU */	case 0x2c: /* stl */		__asm__ __volatile__(		"1:	ldq_u %2,3(%5)\n"		"2:	ldq_u %1,0(%5)\n"		"	inslh %6,%5,%4\n"		"	insll %6,%5,%3\n"		"	msklh %2,%5,%2\n"		"	mskll %1,%5,%1\n"		"	or %2,%4,%2\n"		"	or %1,%3,%1\n"		"3:	stq_u %2,3(%5)\n"		"4:	stq_u %1,0(%5)\n"		"5:\n"		".section __ex_table,\"a\"\n"		"	.gprel32 1b\n"		"	lda %2,5b-1b(%0)\n"		"	.gprel32 2b\n"		"	lda %1,5b-2b(%0)\n"		"	.gprel32 3b\n"		"	lda $31,5b-3b(%0)\n"		"	.gprel32 4b\n"		"	lda $31,5b-4b(%0)\n"		".previous"			: "=r"(error), "=&r"(tmp1), "=&r"(tmp2),			  "=&r"(tmp3), "=&r"(tmp4)			: "r"(va), "r"(*reg_addr), "0"(0));		if (error)			goto give_sigsegv;		return;	case 0x27: /* stt */		fake_reg = alpha_read_fp_reg(reg);		/* FALLTHRU */	case 0x2d: /* stq */		__asm__ __volatile__(		"1:	ldq_u %2,7(%5)\n"		"2:	ldq_u %1,0(%5)\n"		"	insqh %6,%5,%4\n"		"	insql %6,%5,%3\n"		"	mskqh %2,%5,%2\n"		"	mskql %1,%5,%1\n"		"	or %2,%4,%2\n"		"	or %1,%3,%1\n"		"3:	stq_u %2,7(%5)\n"		"4:	stq_u %1,0(%5)\n"		"5:\n"		".section __ex_table,\"a\"\n\t"		"	.gprel32 1b\n"		"	lda %2,5b-1b(%0)\n"		"	.gprel32 2b\n"		"	lda %1,5b-2b(%0)\n"		"	.gprel32 3b\n"		"	lda $31,5b-3b(%0)\n"		"	.gprel32 4b\n"		"	lda $31,5b-4b(%0)\n"		".previous"			: "=r"(error), "=&r"(tmp1), "=&r"(tmp2),			  "=&r"(tmp3), "=&r"(tmp4)			: "r"(va), "r"(*reg_addr), "0"(0));		if (error)			goto give_sigsegv;		return;	default:		/* What instruction were you trying to use, exactly?  */		goto give_sigbus;	}	/* Only integer loads should get here; everyone else returns early. */	if (reg == 30)		wrusp(fake_reg);	return;give_sigsegv:	regs->pc -= 4;  /* make pc point to faulting insn */	send_sig(SIGSEGV, current, 1);	return;give_sigbus:	regs->pc -= 4;	send_sig(SIGBUS, current, 1);	return;}/* * Unimplemented system calls. */asmlinkage longalpha_ni_syscall(unsigned long a0, unsigned long a1, unsigned long a2,		 unsigned long a3, unsigned long a4, unsigned long a5,		 struct pt_regs regs){	/* We only get here for OSF system calls, minus #112;	   the rest go to sys_ni_syscall.  */#if 0	printk("<sc %ld(%lx,%lx,%lx)>", regs.r0, a0, a1, a2);#endif	return -ENOSYS;}voidtrap_init(void){	/* Tell PAL-code what global pointer we want in the kernel.  */	register unsigned long gptr __asm__("$29");	wrkgp(gptr);	wrent(entArith, 1);	wrent(entMM, 2);	wrent(entIF, 3);	wrent(entUna, 4);	wrent(entSys, 5);	wrent(entDbg, 6);	/* Hack for Multia (UDB) and JENSEN: some of their SRMs have	 * a bug in the handling of the opDEC fault.  Fix it up if so.	 */	if (implver() == IMPLVER_EV4) {		opDEC_check();	}}

⌨️ 快捷键说明

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