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

📄 unaligned.c

📁 Linux内核源代码 为压缩文件 是<<Linux内核>>一书中的源代码
💻 C
📖 第 1 页 / 共 3 页
字号:
				mem2float_extended(&fpr_init[1], &fpr_final[1]);				break;			case 1:				mem2float_integer(&fpr_init[0], &fpr_final[0]);				mem2float_integer(&fpr_init[1], &fpr_final[1]);				break;			case 2:				mem2float_single(&fpr_init[0], &fpr_final[0]);				mem2float_single(&fpr_init[1], &fpr_final[1]);				break;			case 3:				mem2float_double(&fpr_init[0], &fpr_final[0]);				mem2float_double(&fpr_init[1], &fpr_final[1]);				break;		}#ifdef DEBUG_UNALIGNED_TRAP		{ int i; char *c = (char *)&fpr_final;			printk("fpr_final= ");			for(i=0; i < len<<1; i++ ) {				printk("%02x ", c[i]&0xff);			}			printk("\n");		}#endif		/*		 * XXX fixme		 *		 * A possible optimization would be to drop fpr_final and directly		 * use the storage from the saved context i.e., the actual final		 * destination (pt_regs, switch_stack or thread structure).		 */		setfpreg(ld->r1, &fpr_final[0], regs);		setfpreg(ld->imm, &fpr_final[1], regs);	}	/*	 * Check for updates: only immediate updates are available for this	 * instruction.	 */	if (ld->m) {		/*		 * the immediate is implicit given the ldsz of the operation:		 * single: 8 (2x4) and for  all others it's 16 (2x8)		 */		ifa += len<<1;		/*		 * IMPORTANT: 		 * the fact that we force the NaT of r3 to zero is ONLY valid		 * as long as we don't come here with a ldfpX.s.		 * For this reason we keep this sanity check		 */		if (ld->x6_op == 1 || ld->x6_op == 3) {			printk(KERN_ERR "%s: register update on speculative load pair, error\n",			       __FUNCTION__);			}		setreg(ld->r3, ifa, 0, regs);	}	/*	 * Invalidate ALAT entries, if any, for both registers.	 */	if (ld->x6_op == 0x2) {		invala_fr(ld->r1);		invala_fr(ld->imm);	}	return 0;}static intemulate_load_float(unsigned long ifa, load_store_t *ld, struct pt_regs *regs){	struct ia64_fpreg fpr_init;	struct ia64_fpreg fpr_final;	unsigned long len = float_fsz[ld->x6_sz];	/*	 * check for load pair because our masking scheme is not fine grain enough	if (ld->x == 1) return emulate_load_floatpair(ifa,ld,regs);	 */	if (access_ok(VERIFY_READ, (void *)ifa, len) < 0) {		DPRINT(("verify area failed on %lx\n", ifa));		return -1;	}	/*	 * fr0 & fr1 don't need to be checked because Illegal Instruction	 * faults have higher priority than unaligned faults.	 *	 * r0 cannot be found as the base as it would never generate an 	 * unaligned reference.	 */	/* 	 * make sure we get clean buffers	 */	memset(&fpr_init,0, sizeof(fpr_init));	memset(&fpr_final,0, sizeof(fpr_final));	/*	 * ldfX.a we don't try to emulate anything but we must	 * invalidate the ALAT entry.	 * See comments in ldX for descriptions on how the various loads are handled.	 */	if (ld->x6_op != 0x2) {		/*		 * does the unaligned access		 */		memcpy(&fpr_init, (void *)ifa, len);		DPRINT(("ld.r1=%d x6_sz=%d\n", ld->r1, ld->x6_sz));#ifdef DEBUG_UNALIGNED_TRAP		{ int i; char *c = (char *)&fpr_init;			printk("fpr_init= ");			for(i=0; i < len; i++ ) {				printk("%02x ", c[i]&0xff);			}			printk("\n");		}#endif		/*		 * we only do something for x6_op={0,8,9}		 */		switch( ld->x6_sz ) {			case 0:				mem2float_extended(&fpr_init, &fpr_final);				break;			case 1:				mem2float_integer(&fpr_init, &fpr_final);				break;			case 2:				mem2float_single(&fpr_init, &fpr_final);				break;			case 3:				mem2float_double(&fpr_init, &fpr_final);				break;		}#ifdef DEBUG_UNALIGNED_TRAP		{ int i; char *c = (char *)&fpr_final;			printk("fpr_final= ");			for(i=0; i < len; i++ ) {				printk("%02x ", c[i]&0xff);			}			printk("\n");		}#endif		/*		 * XXX fixme		 *		 * A possible optimization would be to drop fpr_final and directly		 * use the storage from the saved context i.e., the actual final		 * destination (pt_regs, switch_stack or thread structure).		 */		setfpreg(ld->r1, &fpr_final, regs);	}	/*	 * check for updates on any loads	 */	if (ld->op == 0x7 || ld->m)		emulate_load_updates(ld->op == 0x7 ? UPD_IMMEDIATE: UPD_REG, ld, regs, ifa);	/*	 * invalidate ALAT entry in case of advanced floating point loads	 */	if (ld->x6_op == 0x2)		invala_fr(ld->r1);	return 0;}static intemulate_store_float(unsigned long ifa, load_store_t *ld, struct pt_regs *regs){	struct ia64_fpreg fpr_init;	struct ia64_fpreg fpr_final;	unsigned long len = float_fsz[ld->x6_sz];		/*	 * the macro supposes sequential access (which is the case)	 * if the first byte is an invalid address we return here. Otherwise	 * there is a guard page at the top of the user's address page and 	 * the first access would generate a NaT consumption fault and return	 * with a SIGSEGV, which is what we want.	 *	 * Note: the first argument is ignored 	 */	if (access_ok(VERIFY_WRITE, (void *)ifa, len) < 0) {		DPRINT(("verify area failed on %lx\n",ifa));		return -1;	}	/* 	 * make sure we get clean buffers	 */	memset(&fpr_init,0, sizeof(fpr_init));	memset(&fpr_final,0, sizeof(fpr_final));	/*	 * if we get to this handler, Nat bits on both r3 and r2 have already	 * been checked. so we don't need to do it	 *	 * extract the value to be stored	 */	getfpreg(ld->imm, &fpr_init, regs);	/*	 * during this step, we extract the spilled registers from the saved	 * context i.e., we refill. Then we store (no spill) to temporary	 * aligned location	 */	switch( ld->x6_sz ) {		case 0:			float2mem_extended(&fpr_init, &fpr_final);			break;		case 1:			float2mem_integer(&fpr_init, &fpr_final);			break;		case 2:			float2mem_single(&fpr_init, &fpr_final);			break;		case 3:			float2mem_double(&fpr_init, &fpr_final);			break;	}	DPRINT(("ld.r1=%d x6_sz=%d\n", ld->r1, ld->x6_sz));#ifdef DEBUG_UNALIGNED_TRAP		{ int i; char *c = (char *)&fpr_init;			printk("fpr_init= ");			for(i=0; i < len; i++ ) {				printk("%02x ", c[i]&0xff);			}			printk("\n");		}		{ int i; char *c = (char *)&fpr_final;			printk("fpr_final= ");			for(i=0; i < len; i++ ) {				printk("%02x ", c[i]&0xff);			}			printk("\n");		}#endif	/*	 * does the unaligned store	 */	memcpy((void *)ifa, &fpr_final, len);	/*	 * stfX [r3]=r2,imm(9)	 *	 * NOTE:	 * ld->r3 can never be r0, because r0 would not generate an 	 * unaligned access.	 */	if (ld->op == 0x7) {		unsigned long imm;		/*		 * form imm9: [12:6] contain first 7bits		 */		imm = ld->x << 7 | ld->r1;		/*		 * sign extend (8bits) if m set		 */		if (ld->m)			imm |= SIGN_EXT9; 		/*		 * ifa == r3 (NaT is necessarily cleared)		 */		ifa += imm;		DPRINT(("imm=%lx r3=%lx\n", imm, ifa));			setreg(ld->r3, ifa, 0, regs);	}	/*	 * we don't have alat_invalidate_multiple() so we need	 * to do the complete flush :-<<	 */	ia64_invala();	return 0;}voidia64_handle_unaligned(unsigned long ifa, struct pt_regs *regs){	static unsigned long unalign_count;	static long last_time;	struct ia64_psr *ipsr = ia64_psr(regs);	unsigned long *bundle_addr;	unsigned long opcode;	unsigned long op;	load_store_t *insn;	int ret = -1;	/*	 * Unaligned references in the kernel could come from unaligned	 *   arguments to system calls.  We fault the user process in	 *   these cases and panic the kernel otherwise (the kernel should	 *   be fixed to not make unaligned accesses).	 */	if (!user_mode(regs)) {		const struct exception_table_entry *fix;		fix = search_exception_table(regs->cr_iip);		if (fix) {			regs->r8 = -EFAULT;			if (fix->skip & 1) {				regs->r9 = 0;			}			regs->cr_iip += ((long) fix->skip) & ~15;			regs->cr_ipsr &= ~IA64_PSR_RI;	/* clear exception slot number */			return;		}		die_if_kernel("Unaligned reference while in kernel\n", regs, 30);		/* NOT_REACHED */	}	/*	 * For now, we don't support user processes running big-endian	 * which do unaligned accesses	 */	if (ia64_psr(regs)->be) {		struct siginfo si;		printk(KERN_ERR "%s(%d): big-endian unaligned access %016lx (ip=%016lx) not "		       "yet supported\n",		       current->comm, current->pid, ifa, regs->cr_iip + ipsr->ri);		si.si_signo = SIGBUS;		si.si_errno = 0;		si.si_code = BUS_ADRALN;		si.si_addr = (void *) ifa;		force_sig_info(SIGBUS, &si, current);		return;	}	if (current->thread.flags & IA64_THREAD_UAC_SIGBUS) {		struct siginfo si;		si.si_signo = SIGBUS;		si.si_errno = 0;		si.si_code = BUS_ADRALN;		si.si_addr = (void *) ifa;		force_sig_info(SIGBUS, &si, current);		return;	}	if (!(current->thread.flags & IA64_THREAD_UAC_NOPRINT)) {		/*		 * Make sure we log the unaligned access, so that		 * user/sysadmin can notice it and eventually fix the		 * program.		 *		 * We don't want to do that for every access so we		 * pace it with jiffies.		 */		if (unalign_count > 5 && jiffies - last_time > 5*HZ)			unalign_count = 0;		if (++unalign_count < 5) {			char buf[200];	/* comm[] is at most 16 bytes... */			size_t len;			last_time = jiffies;			len = sprintf(buf, "%s(%d): unaligned access to 0x%016lx, ip=0x%016lx\n\r",				      current->comm, current->pid, ifa, regs->cr_iip + ipsr->ri);			tty_write_message(current->tty, buf);			buf[len-1] = '\0';	/* drop '\r' */			printk("%s", buf);	/* guard against command names containing %s!! */		}	}	DPRINT(("iip=%lx ifa=%lx isr=%lx\n", regs->cr_iip, ifa, regs->cr_ipsr));	DPRINT(("ISR.ei=%d ISR.sp=%d\n", ipsr->ri, ipsr->it));	bundle_addr = (unsigned long *)(regs->cr_iip);	/*	 * extract the instruction from the bundle given the slot number	 */	switch ( ipsr->ri ) {		case 0: op = *bundle_addr >> 5;			break;		case 1: op = *bundle_addr >> 46 | (*(bundle_addr+1) & 0x7fffff)<<18;			break;		case 2: op = *(bundle_addr+1) >> 23;		 	break;	}	insn   = (load_store_t *)&op;	opcode = op & IA64_OPCODE_MASK;	DPRINT(("opcode=%lx ld.qp=%d ld.r1=%d ld.imm=%d ld.r3=%d ld.x=%d ld.hint=%d "		"ld.x6=0x%x ld.m=%d ld.op=%d\n",		opcode,		insn->qp,		insn->r1,		insn->imm,		insn->r3,		insn->x,		insn->hint,		insn->x6_sz,		insn->m,		insn->op));	/*  	 * IMPORTANT:	 * Notice that the swictch statement DOES not cover all possible instructions	 * that DO generate unaligned references. This is made on purpose because for some	 * instructions it DOES NOT make sense to try and emulate the access. Sometimes it	 * is WRONG to try and emulate. Here is a list of instruction we don't emulate i.e.,	 * the program will get a signal and die:	 *	 *	load/store:	 *		- ldX.spill	 *		- stX.spill	 * 	Reason: RNATs are based on addresses	 *	 *	synchronization:	 *		- cmpxchg	 *		- fetchadd	 *		- xchg	 * 	Reason: ATOMIC operations cannot be emulated properly using multiple 	 * 	        instructions.	 *	 *	speculative loads:	 *		- ldX.sZ	 *	Reason: side effects, code must be ready to deal with failure so simpler 	 * 		to let the load fail.	 * ---------------------------------------------------------------------------------	 * XXX fixme	 *	 * I would like to get rid of this switch case and do something	 * more elegant.	 */	switch(opcode) {		case LDS_OP:		case LDSA_OP:		case LDS_IMM_OP:		case LDSA_IMM_OP:		case LDFS_OP:		case LDFSA_OP:		case LDFS_IMM_OP:			/*			 * The instruction will be retried with defered exceptions			 * turned on, and we should get Nat bit installed			 *			 * IMPORTANT:			 * When PSR_ED is set, the register & immediate update			 * forms are actually executed even though the operation			 * failed. So we don't need to take care of this.			 */			DPRINT(("forcing PSR_ED\n"));			regs->cr_ipsr |= IA64_PSR_ED;			return;		case LD_OP:		case LDA_OP:		case LDBIAS_OP:		case LDACQ_OP:		case LDCCLR_OP:		case LDCNC_OP:		case LDCCLRACQ_OP:		case LD_IMM_OP:		case LDA_IMM_OP:		case LDBIAS_IMM_OP:		case LDACQ_IMM_OP:		case LDCCLR_IMM_OP:		case LDCNC_IMM_OP:		case LDCCLRACQ_IMM_OP:			ret = emulate_load_int(ifa, insn, regs);			break;		case ST_OP:		case STREL_OP:		case ST_IMM_OP:		case STREL_IMM_OP:			ret = emulate_store_int(ifa, insn, regs);			break;		case LDF_OP:		case LDFA_OP:		case LDFCCLR_OP:		case LDFCNC_OP:		case LDF_IMM_OP:		case LDFA_IMM_OP:		case LDFCCLR_IMM_OP:		case LDFCNC_IMM_OP:			ret = insn->x ? 			      emulate_load_floatpair(ifa, insn, regs):			      emulate_load_float(ifa, insn, regs);			break;		case STF_OP:		case STF_IMM_OP:			ret = emulate_store_float(ifa, insn, regs);	}	DPRINT(("ret=%d\n", ret));	if (ret) {		struct siginfo si;		si.si_signo = SIGBUS;		si.si_errno = 0;		si.si_code = BUS_ADRALN;		si.si_addr = (void *) ifa;	        force_sig_info(SIGBUS, &si, current);	} else {		/*	 	 * given today's architecture this case is not likely to happen	 	 * because a memory access instruction (M) can never be in the 	 	 * last slot of a bundle. But let's keep it for  now.	 	 */		if (ipsr->ri == 2)			regs->cr_iip += 16;		ipsr->ri = ++ipsr->ri & 3;	}	DPRINT(("ipsr->ri=%d iip=%lx\n", ipsr->ri, regs->cr_iip));}

⌨️ 快捷键说明

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