diff options
Diffstat (limited to 'arch/sparc/kernel/unaligned_64.c')
| -rw-r--r-- | arch/sparc/kernel/unaligned_64.c | 36 | 
1 files changed, 23 insertions, 13 deletions
diff --git a/arch/sparc/kernel/unaligned_64.c b/arch/sparc/kernel/unaligned_64.c index f81d038f734..8201c25e766 100644 --- a/arch/sparc/kernel/unaligned_64.c +++ b/arch/sparc/kernel/unaligned_64.c @@ -113,21 +113,24 @@ static inline long sign_extend_imm13(long imm)  static unsigned long fetch_reg(unsigned int reg, struct pt_regs *regs)  { -	unsigned long value; +	unsigned long value, fp;  	if (reg < 16)  		return (!reg ? 0 : regs->u_regs[reg]); + +	fp = regs->u_regs[UREG_FP]; +  	if (regs->tstate & TSTATE_PRIV) {  		struct reg_window *win; -		win = (struct reg_window *)(regs->u_regs[UREG_FP] + STACK_BIAS); +		win = (struct reg_window *)(fp + STACK_BIAS);  		value = win->locals[reg - 16]; -	} else if (test_thread_flag(TIF_32BIT)) { +	} else if (!test_thread_64bit_stack(fp)) {  		struct reg_window32 __user *win32; -		win32 = (struct reg_window32 __user *)((unsigned long)((u32)regs->u_regs[UREG_FP])); +		win32 = (struct reg_window32 __user *)((unsigned long)((u32)fp));  		get_user(value, &win32->locals[reg - 16]);  	} else {  		struct reg_window __user *win; -		win = (struct reg_window __user *)(regs->u_regs[UREG_FP] + STACK_BIAS); +		win = (struct reg_window __user *)(fp + STACK_BIAS);  		get_user(value, &win->locals[reg - 16]);  	}  	return value; @@ -135,19 +138,24 @@ static unsigned long fetch_reg(unsigned int reg, struct pt_regs *regs)  static unsigned long *fetch_reg_addr(unsigned int reg, struct pt_regs *regs)  { +	unsigned long fp; +  	if (reg < 16)  		return ®s->u_regs[reg]; + +	fp = regs->u_regs[UREG_FP]; +  	if (regs->tstate & TSTATE_PRIV) {  		struct reg_window *win; -		win = (struct reg_window *)(regs->u_regs[UREG_FP] + STACK_BIAS); +		win = (struct reg_window *)(fp + STACK_BIAS);  		return &win->locals[reg - 16]; -	} else if (test_thread_flag(TIF_32BIT)) { +	} else if (!test_thread_64bit_stack(fp)) {  		struct reg_window32 *win32; -		win32 = (struct reg_window32 *)((unsigned long)((u32)regs->u_regs[UREG_FP])); +		win32 = (struct reg_window32 *)((unsigned long)((u32)fp));  		return (unsigned long *)&win32->locals[reg - 16];  	} else {  		struct reg_window *win; -		win = (struct reg_window *)(regs->u_regs[UREG_FP] + STACK_BIAS); +		win = (struct reg_window *)(fp + STACK_BIAS);  		return &win->locals[reg - 16];  	}  } @@ -392,13 +400,15 @@ int handle_popc(u32 insn, struct pt_regs *regs)  		if (rd)  			regs->u_regs[rd] = ret;  	} else { -		if (test_thread_flag(TIF_32BIT)) { +		unsigned long fp = regs->u_regs[UREG_FP]; + +		if (!test_thread_64bit_stack(fp)) {  			struct reg_window32 __user *win32; -			win32 = (struct reg_window32 __user *)((unsigned long)((u32)regs->u_regs[UREG_FP])); +			win32 = (struct reg_window32 __user *)((unsigned long)((u32)fp));  			put_user(ret, &win32->locals[rd - 16]);  		} else {  			struct reg_window __user *win; -			win = (struct reg_window __user *)(regs->u_regs[UREG_FP] + STACK_BIAS); +			win = (struct reg_window __user *)(fp + STACK_BIAS);  			put_user(ret, &win->locals[rd - 16]);  		}  	} @@ -554,7 +564,7 @@ void handle_ld_nf(u32 insn, struct pt_regs *regs)  		reg[0] = 0;  		if ((insn & 0x780000) == 0x180000)  			reg[1] = 0; -	} else if (test_thread_flag(TIF_32BIT)) { +	} else if (!test_thread_64bit_stack(regs->u_regs[UREG_FP])) {  		put_user(0, (int __user *) reg);  		if ((insn & 0x780000) == 0x180000)  			put_user(0, ((int __user *) reg) + 1);  |