嵌入式系统设计与实例开发源码

源代码在线查看: align.c

软件大小: 17783 K
上传用户: wwangllei
关键词: 嵌入式系统设计 源码
下载地址: 免注册下载 普通下载 VIP

相关代码

				/*				 * BK Id: SCCS/s.align.c 1.5 05/17/01 18:14:21 cort				 */				/*				 * align.c - handle alignment exceptions for the Power PC.				 *				 * Copyright (c) 1996 Paul Mackerras 				 * Copyright (c) 1998-1999 TiVo, Inc.				 *   PowerPC 403GCX modifications.				 * Copyright (c) 1999 Grant Erickson 				 *   PowerPC 403GCX/405GP modifications.				 */				#include 				#include 				#include 				#include 				#include 				#include 				#include 				#include 								struct aligninfo {					unsigned char len;					unsigned char flags;				};								#if defined(CONFIG_4xx) || defined(CONFIG_POWER4)				#define	OPCD(inst)	(((inst) & 0xFC000000) >> 26)				#define	RS(inst)	(((inst) & 0x03E00000) >> 21)				#define	RA(inst)	(((inst) & 0x001F0000) >> 16)				#define	IS_DFORM(code)	((code) >= 32 && (code) 				#endif								#define INVALID	{ 0, 0 }								#define LD	1	/* load */				#define ST	2	/* store */				#define	SE	4	/* sign-extend value */				#define F	8	/* to/from fp regs */				#define U	0x10	/* update index register */				#define M	0x20	/* multiple load/store */				#define S	0x40	/* single-precision fp, or byte-swap value */				#define HARD	0x80	/* string, stwcx. */								#define DCBZ	0x5f	/* 8xx/82xx dcbz faults when cache not enabled */								/*				 * The PowerPC stores certain bits of the instruction that caused the				 * alignment exception in the DSISR register.  This array maps those				 * bits to information about the operand length and what the				 * instruction would do.				 */				static struct aligninfo aligninfo[128] = {					{ 4, LD },		/* 00 0 0000: lwz / lwarx */					INVALID,		/* 00 0 0001 */					{ 4, ST },		/* 00 0 0010: stw */					INVALID,		/* 00 0 0011 */					{ 2, LD },		/* 00 0 0100: lhz */					{ 2, LD+SE },		/* 00 0 0101: lha */					{ 2, ST },		/* 00 0 0110: sth */					{ 4, LD+M },		/* 00 0 0111: lmw */					{ 4, LD+F+S },		/* 00 0 1000: lfs */					{ 8, LD+F },		/* 00 0 1001: lfd */					{ 4, ST+F+S },		/* 00 0 1010: stfs */					{ 8, ST+F },		/* 00 0 1011: stfd */					INVALID,		/* 00 0 1100 */					INVALID,		/* 00 0 1101 */					INVALID,		/* 00 0 1110 */					INVALID,		/* 00 0 1111 */					{ 4, LD+U },		/* 00 1 0000: lwzu */					INVALID,		/* 00 1 0001 */					{ 4, ST+U },		/* 00 1 0010: stwu */					INVALID,		/* 00 1 0011 */					{ 2, LD+U },		/* 00 1 0100: lhzu */					{ 2, LD+SE+U },		/* 00 1 0101: lhau */					{ 2, ST+U },		/* 00 1 0110: sthu */					{ 4, ST+M },		/* 00 1 0111: stmw */					{ 4, LD+F+S+U },	/* 00 1 1000: lfsu */					{ 8, LD+F+U },		/* 00 1 1001: lfdu */					{ 4, ST+F+S+U },	/* 00 1 1010: stfsu */					{ 8, ST+F+U },		/* 00 1 1011: stfdu */					INVALID,		/* 00 1 1100 */					INVALID,		/* 00 1 1101 */					INVALID,		/* 00 1 1110 */					INVALID,		/* 00 1 1111 */					INVALID,		/* 01 0 0000 */					INVALID,		/* 01 0 0001 */					INVALID,		/* 01 0 0010 */					INVALID,		/* 01 0 0011 */					INVALID,		/* 01 0 0100 */					INVALID,		/* 01 0 0101: lwax?? */					INVALID,		/* 01 0 0110 */					INVALID,		/* 01 0 0111 */					{ 0, LD+HARD },		/* 01 0 1000: lswx */					{ 0, LD+HARD },		/* 01 0 1001: lswi */					{ 0, ST+HARD },		/* 01 0 1010: stswx */					{ 0, ST+HARD },		/* 01 0 1011: stswi */					INVALID,		/* 01 0 1100 */					INVALID,		/* 01 0 1101 */					INVALID,		/* 01 0 1110 */					INVALID,		/* 01 0 1111 */					INVALID,		/* 01 1 0000 */					INVALID,		/* 01 1 0001 */					INVALID,		/* 01 1 0010 */					INVALID,		/* 01 1 0011 */					INVALID,		/* 01 1 0100 */					INVALID,		/* 01 1 0101: lwaux?? */					INVALID,		/* 01 1 0110 */					INVALID,		/* 01 1 0111 */					INVALID,		/* 01 1 1000 */					INVALID,		/* 01 1 1001 */					INVALID,		/* 01 1 1010 */					INVALID,		/* 01 1 1011 */					INVALID,		/* 01 1 1100 */					INVALID,		/* 01 1 1101 */					INVALID,		/* 01 1 1110 */					INVALID,		/* 01 1 1111 */					INVALID,		/* 10 0 0000 */					INVALID,		/* 10 0 0001 */					{ 0, ST+HARD },		/* 10 0 0010: stwcx. */					INVALID,		/* 10 0 0011 */					INVALID,		/* 10 0 0100 */					INVALID,		/* 10 0 0101 */					INVALID,		/* 10 0 0110 */					INVALID,		/* 10 0 0111 */					{ 4, LD+S },		/* 10 0 1000: lwbrx */					INVALID,		/* 10 0 1001 */					{ 4, ST+S },		/* 10 0 1010: stwbrx */					INVALID,		/* 10 0 1011 */					{ 2, LD+S },		/* 10 0 1100: lhbrx */					INVALID,		/* 10 0 1101 */					{ 2, ST+S },		/* 10 0 1110: sthbrx */					INVALID,		/* 10 0 1111 */					INVALID,		/* 10 1 0000 */					INVALID,		/* 10 1 0001 */					INVALID,		/* 10 1 0010 */					INVALID,		/* 10 1 0011 */					INVALID,		/* 10 1 0100 */					INVALID,		/* 10 1 0101 */					INVALID,		/* 10 1 0110 */					INVALID,		/* 10 1 0111 */					INVALID,		/* 10 1 1000 */					INVALID,		/* 10 1 1001 */					INVALID,		/* 10 1 1010 */					INVALID,		/* 10 1 1011 */					INVALID,		/* 10 1 1100 */					INVALID,		/* 10 1 1101 */					INVALID,		/* 10 1 1110 */					{ 0, ST+HARD },		/* 10 1 1111: dcbz */					{ 4, LD },		/* 11 0 0000: lwzx */					INVALID,		/* 11 0 0001 */					{ 4, ST },		/* 11 0 0010: stwx */					INVALID,		/* 11 0 0011 */					{ 2, LD },		/* 11 0 0100: lhzx */					{ 2, LD+SE },		/* 11 0 0101: lhax */					{ 2, ST },		/* 11 0 0110: sthx */					INVALID,		/* 11 0 0111 */					{ 4, LD+F+S },		/* 11 0 1000: lfsx */					{ 8, LD+F },		/* 11 0 1001: lfdx */					{ 4, ST+F+S },		/* 11 0 1010: stfsx */					{ 8, ST+F },		/* 11 0 1011: stfdx */					INVALID,		/* 11 0 1100 */					INVALID,		/* 11 0 1101 */					INVALID,		/* 11 0 1110 */					INVALID,		/* 11 0 1111 */					{ 4, LD+U },		/* 11 1 0000: lwzux */					INVALID,		/* 11 1 0001 */					{ 4, ST+U },		/* 11 1 0010: stwux */					INVALID,		/* 11 1 0011 */					{ 2, LD+U },		/* 11 1 0100: lhzux */					{ 2, LD+SE+U },		/* 11 1 0101: lhaux */					{ 2, ST+U },		/* 11 1 0110: sthux */					INVALID,		/* 11 1 0111 */					{ 4, LD+F+S+U },	/* 11 1 1000: lfsux */					{ 8, LD+F+U },		/* 11 1 1001: lfdux */					{ 4, ST+F+S+U },	/* 11 1 1010: stfsux */					{ 8, ST+F+U },		/* 11 1 1011: stfdux */					INVALID,		/* 11 1 1100 */					INVALID,		/* 11 1 1101 */					INVALID,		/* 11 1 1110 */					INVALID,		/* 11 1 1111 */				};								#define SWAP(a, b)	(t = (a), (a) = (b), (b) = t)								int				fix_alignment(struct pt_regs *regs)				{					int instr, nb, flags;				#if defined(CONFIG_4xx) || defined(CONFIG_POWER4)					int opcode, f1, f2, f3;				#endif					int i, t;					int reg, areg;					unsigned char *addr;					union {						long l;						float f;						double d;						unsigned char v[8];					} data;								#if defined(CONFIG_4xx) || defined(CONFIG_POWER4)					/* The 4xx-family processors have no DSISR register,					 * so we emulate it.					 * The POWER4 has a DSISR register but doesn't set it on					 * an alignment fault.  -- paulus					 */									instr = *((unsigned int *)regs->nip);					opcode = OPCD(instr);					reg = RS(instr);					areg = RA(instr);									if (IS_DFORM(opcode)) {						f1 = 0;						f2 = (instr & 0x04000000) >> 26;						f3 = (instr & 0x78000000) >> 27;					} else {						f1 = (instr & 0x00000006) >> 1;						f2 = (instr & 0x00000040) >> 6;						f3 = (instr & 0x00000780) >> 7;					}									instr = ((f1 				#else					reg = (regs->dsisr >> 5) & 0x1f;	/* source/dest register */					areg = regs->dsisr & 0x1f;		/* register to update */					instr = (regs->dsisr >> 10) & 0x7f;				#endif									nb = aligninfo[instr].len;					if (nb == 0) {						long *p;						int i;										if (instr != DCBZ)							return 0;	/* too hard or invalid instruction */						/*						 * The dcbz (data cache block zero) instruction						 * gives an alignment fault if used on non-cacheable						 * memory.  We handle the fault mainly for the						 * case when we are running with the cache disabled						 * for debugging.						 */						p = (long *) (regs->dar & -L1_CACHE_BYTES);						for (i = 0; i < L1_CACHE_BYTES / sizeof(long); ++i)							p[i] = 0;						return 1;					}									flags = aligninfo[instr].flags;									/* For the 4xx-family processors, the 'dar' field of the					 * pt_regs structure is overloaded and is really from the DEAR.					 */									addr = (unsigned char *)regs->dar;									/* Verify the address of the operand */					if (user_mode(regs)) {						if (verify_area((flags & ST? VERIFY_WRITE: VERIFY_READ), addr, nb))							return -EFAULT;	/* bad address */					}									if ((flags & F) && (regs->msr & MSR_FP))						giveup_fpu(current);					if (flags & M)						return 0;		/* too hard for now */									/* If we read the operand, copy it in */					if (flags & LD) {						if (nb == 2) {							data.v[0] = data.v[1] = 0;							if (__get_user(data.v[2], addr)							    || __get_user(data.v[3], addr+1))								return -EFAULT;						} else {							for (i = 0; i < nb; ++i)								if (__get_user(data.v[i], addr+i))									return -EFAULT;						}					}									switch (flags & ~U) {					case LD+SE:						if (data.v[2] >= 0x80)							data.v[0] = data.v[1] = -1;						/* fall through */					case LD:						regs->gpr[reg] = data.l;						break;					case LD+S:						if (nb == 2) {							SWAP(data.v[2], data.v[3]);						} else {							SWAP(data.v[0], data.v[3]);							SWAP(data.v[1], data.v[2]);						}						regs->gpr[reg] = data.l;						break;					case ST:						data.l = regs->gpr[reg];						break;					case ST+S:						data.l = regs->gpr[reg];						if (nb == 2) {							SWAP(data.v[2], data.v[3]);						} else {							SWAP(data.v[0], data.v[3]);							SWAP(data.v[1], data.v[2]);						}						break;					case LD+F:						current->thread.fpr[reg] = data.d;						break;					case ST+F:						data.d = current->thread.fpr[reg];						break;					/* these require some floating point conversions... */					/* we'd like to use the assignment, but we have to compile					 * the kernel with -msoft-float so it doesn't use the					 * fp regs for copying 8-byte objects. */					case LD+F+S:						enable_kernel_fp();						cvt_fd(&data.f, ¤t->thread.fpr[reg], ¤t->thread.fpscr);						/* current->thread.fpr[reg] = data.f; */						break;					case ST+F+S:						enable_kernel_fp();						cvt_df(¤t->thread.fpr[reg], &data.f, ¤t->thread.fpscr);						/* data.f = current->thread.fpr[reg]; */						break;					default:						printk("align: can't handle flags=%x\n", flags);						return 0;					}									if (flags & ST) {						if (nb == 2) {							if (__put_user(data.v[2], addr)							    || __put_user(data.v[3], addr+1))								return -EFAULT;						} else {							for (i = 0; i < nb; ++i)								if (__put_user(data.v[i], addr+i))									return -EFAULT;						}					}									if (flags & U) {						regs->gpr[areg] = regs->dar;					}									return 1;				}							

相关资源