diff options
Diffstat (limited to 'arch/mips/kernel/signal.c')
| -rw-r--r-- | arch/mips/kernel/signal.c | 91 | 
1 files changed, 78 insertions, 13 deletions
diff --git a/arch/mips/kernel/signal.c b/arch/mips/kernel/signal.c index 2f285abc76d..9e60d117e41 100644 --- a/arch/mips/kernel/signal.c +++ b/arch/mips/kernel/signal.c @@ -6,6 +6,7 @@   * Copyright (C) 1991, 1992  Linus Torvalds   * Copyright (C) 1994 - 2000  Ralf Baechle   * Copyright (C) 1999, 2000 Silicon Graphics, Inc. + * Copyright (C) 2014, Imagination Technologies Ltd.   */  #include <linux/cache.h>  #include <linux/context_tracking.h> @@ -46,9 +47,6 @@ static int (*restore_fp_context)(struct sigcontext __user *sc);  extern asmlinkage int _save_fp_context(struct sigcontext __user *sc);  extern asmlinkage int _restore_fp_context(struct sigcontext __user *sc); -extern asmlinkage int fpu_emulator_save_context(struct sigcontext __user *sc); -extern asmlinkage int fpu_emulator_restore_context(struct sigcontext __user *sc); -  struct sigframe {  	u32 sf_ass[4];		/* argument save space for o32 */  	u32 sf_pad[2];		/* Was: signal trampoline */ @@ -64,16 +62,55 @@ struct rt_sigframe {  };  /* + * Thread saved context copy to/from a signal context presumed to be on the + * user stack, and therefore accessed with appropriate macros from uaccess.h. + */ +static int copy_fp_to_sigcontext(struct sigcontext __user *sc) +{ +	int i; +	int err = 0; + +	for (i = 0; i < NUM_FPU_REGS; i++) { +		err |= +		    __put_user(get_fpr64(¤t->thread.fpu.fpr[i], 0), +			       &sc->sc_fpregs[i]); +	} +	err |= __put_user(current->thread.fpu.fcr31, &sc->sc_fpc_csr); + +	return err; +} + +static int copy_fp_from_sigcontext(struct sigcontext __user *sc) +{ +	int i; +	int err = 0; +	u64 fpr_val; + +	for (i = 0; i < NUM_FPU_REGS; i++) { +		err |= __get_user(fpr_val, &sc->sc_fpregs[i]); +		set_fpr64(¤t->thread.fpu.fpr[i], 0, fpr_val); +	} +	err |= __get_user(current->thread.fpu.fcr31, &sc->sc_fpc_csr); + +	return err; +} + +/*   * Helper routines   */  static int protected_save_fp_context(struct sigcontext __user *sc)  {  	int err; +#ifndef CONFIG_EVA  	while (1) {  		lock_fpu_owner(); -		own_fpu_inatomic(1); -		err = save_fp_context(sc); /* this might fail */ -		unlock_fpu_owner(); +		if (is_fpu_owner()) { +			err = save_fp_context(sc); +			unlock_fpu_owner(); +		} else { +			unlock_fpu_owner(); +			err = copy_fp_to_sigcontext(sc); +		}  		if (likely(!err))  			break;  		/* touch the sigcontext and try again */ @@ -83,17 +120,30 @@ static int protected_save_fp_context(struct sigcontext __user *sc)  		if (err)  			break;	/* really bad sigcontext */  	} +#else +	/* +	 * EVA does not have FPU EVA instructions so saving fpu context directly +	 * does not work. +	 */ +	lose_fpu(1); +	err = save_fp_context(sc); /* this might fail */ +#endif  	return err;  }  static int protected_restore_fp_context(struct sigcontext __user *sc)  {  	int err, tmp __maybe_unused; +#ifndef CONFIG_EVA  	while (1) {  		lock_fpu_owner(); -		own_fpu_inatomic(0); -		err = restore_fp_context(sc); /* this might fail */ -		unlock_fpu_owner(); +		if (is_fpu_owner()) { +			err = restore_fp_context(sc); +			unlock_fpu_owner(); +		} else { +			unlock_fpu_owner(); +			err = copy_fp_from_sigcontext(sc); +		}  		if (likely(!err))  			break;  		/* touch the sigcontext and try again */ @@ -103,6 +153,14 @@ static int protected_restore_fp_context(struct sigcontext __user *sc)  		if (err)  			break;	/* really bad sigcontext */  	} +#else +	/* +	 * EVA does not have FPU EVA instructions so restoring fpu context +	 * directly does not work. +	 */ +	lose_fpu(0); +	err = restore_fp_context(sc); /* this might fail */ +#endif  	return err;  } @@ -589,23 +647,26 @@ asmlinkage void do_notify_resume(struct pt_regs *regs, void *unused,  }  #ifdef CONFIG_SMP +#ifndef CONFIG_EVA  static int smp_save_fp_context(struct sigcontext __user *sc)  {  	return raw_cpu_has_fpu  	       ? _save_fp_context(sc) -	       : fpu_emulator_save_context(sc); +	       : copy_fp_to_sigcontext(sc);  }  static int smp_restore_fp_context(struct sigcontext __user *sc)  {  	return raw_cpu_has_fpu  	       ? _restore_fp_context(sc) -	       : fpu_emulator_restore_context(sc); +	       : copy_fp_from_sigcontext(sc);  } +#endif /* CONFIG_EVA */  #endif  static int signal_setup(void)  { +#ifndef CONFIG_EVA  #ifdef CONFIG_SMP  	/* For now just do the cpu_has_fpu check when the functions are invoked */  	save_fp_context = smp_save_fp_context; @@ -615,9 +676,13 @@ static int signal_setup(void)  		save_fp_context = _save_fp_context;  		restore_fp_context = _restore_fp_context;  	} else { -		save_fp_context = fpu_emulator_save_context; -		restore_fp_context = fpu_emulator_restore_context; +		save_fp_context = copy_fp_from_sigcontext; +		restore_fp_context = copy_fp_to_sigcontext;  	} +#endif /* CONFIG_SMP */ +#else +	save_fp_context = copy_fp_from_sigcontext;; +	restore_fp_context = copy_fp_to_sigcontext;  #endif  	return 0;  | 
