diff options
| author | Michael Neuling <mikey@neuling.org> | 2009-02-19 18:52:20 +0000 | 
|---|---|---|
| committer | Benjamin Herrenschmidt <benh@kernel.crashing.org> | 2009-02-23 15:53:05 +1100 | 
| commit | 553631e25f238de3a8085d2daf9cd4dcd96f8573 (patch) | |
| tree | 1e2b0dc9c4f22e2109cc454b742115bf2d6c480a /arch/powerpc/kernel/align.c | |
| parent | 545bba18247067bb63c94e042bed90599d08151b (diff) | |
| download | olio-linux-3.10-553631e25f238de3a8085d2daf9cd4dcd96f8573.tar.xz olio-linux-3.10-553631e25f238de3a8085d2daf9cd4dcd96f8573.zip  | |
powerpc: Fix load/store float double alignment handler
When we introduced VSX, we changed the way FPRs are stored in the
thread_struct.  Unfortunately we missed the load/store float double
alignment handler code when updating how we access FPRs in the
thread_struct.
Below fixes this and merges the little/big endian case.
Signed-off-by: Michael Neuling <mikey@neuling.org>
Signed-off-by: Benjamin Herrenschmidt <benh@kernel.crashing.org>
Diffstat (limited to 'arch/powerpc/kernel/align.c')
| -rw-r--r-- | arch/powerpc/kernel/align.c | 29 | 
1 files changed, 13 insertions, 16 deletions
diff --git a/arch/powerpc/kernel/align.c b/arch/powerpc/kernel/align.c index 076aa0ea234..5ffcfaa77d6 100644 --- a/arch/powerpc/kernel/align.c +++ b/arch/powerpc/kernel/align.c @@ -367,27 +367,24 @@ static int emulate_multiple(struct pt_regs *regs, unsigned char __user *addr,  static int emulate_fp_pair(unsigned char __user *addr, unsigned int reg,  			   unsigned int flags)  { -	char *ptr = (char *) ¤t->thread.TS_FPR(reg); -	int i, ret; +	char *ptr0 = (char *) ¤t->thread.TS_FPR(reg); +	char *ptr1 = (char *) ¤t->thread.TS_FPR(reg+1); +	int i, ret, sw = 0;  	if (!(flags & F))  		return 0;  	if (reg & 1)  		return 0;	/* invalid form: FRS/FRT must be even */ -	if (!(flags & SW)) { -		/* not byte-swapped - easy */ -		if (!(flags & ST)) -			ret = __copy_from_user(ptr, addr, 16); -		else -			ret = __copy_to_user(addr, ptr, 16); -	} else { -		/* each FPR value is byte-swapped separately */ -		ret = 0; -		for (i = 0; i < 16; ++i) { -			if (!(flags & ST)) -				ret |= __get_user(ptr[i^7], addr + i); -			else -				ret |= __put_user(ptr[i^7], addr + i); +	if (flags & SW) +		sw = 7; +	ret = 0; +	for (i = 0; i < 8; ++i) { +		if (!(flags & ST)) { +			ret |= __get_user(ptr0[i^sw], addr + i); +			ret |= __get_user(ptr1[i^sw], addr + i + 8); +		} else { +			ret |= __put_user(ptr0[i^sw], addr + i); +			ret |= __put_user(ptr1[i^sw], addr + i + 8);  		}  	}  	if (ret)  |