diff options
Diffstat (limited to 'arch/arm/kernel/signal.c')
| -rw-r--r-- | arch/arm/kernel/signal.c | 93 | 
1 files changed, 89 insertions, 4 deletions
diff --git a/arch/arm/kernel/signal.c b/arch/arm/kernel/signal.c index e7714f367eb..907d5a620bc 100644 --- a/arch/arm/kernel/signal.c +++ b/arch/arm/kernel/signal.c @@ -18,6 +18,7 @@  #include <asm/cacheflush.h>  #include <asm/ucontext.h>  #include <asm/unistd.h> +#include <asm/vfp.h>  #include "ptrace.h"  #include "signal.h" @@ -175,6 +176,90 @@ static int restore_iwmmxt_context(struct iwmmxt_sigframe *frame)  #endif +#ifdef CONFIG_VFP + +static int preserve_vfp_context(struct vfp_sigframe __user *frame) +{ +	struct thread_info *thread = current_thread_info(); +	struct vfp_hard_struct *h = &thread->vfpstate.hard; +	const unsigned long magic = VFP_MAGIC; +	const unsigned long size = VFP_STORAGE_SIZE; +	int err = 0; + +	vfp_sync_hwstate(thread); +	__put_user_error(magic, &frame->magic, err); +	__put_user_error(size, &frame->size, err); + +	/* +	 * Copy the floating point registers. There can be unused +	 * registers see asm/hwcap.h for details. +	 */ +	err |= __copy_to_user(&frame->ufp.fpregs, &h->fpregs, +			      sizeof(h->fpregs)); +	/* +	 * Copy the status and control register. +	 */ +	__put_user_error(h->fpscr, &frame->ufp.fpscr, err); + +	/* +	 * Copy the exception registers. +	 */ +	__put_user_error(h->fpexc, &frame->ufp_exc.fpexc, err); +	__put_user_error(h->fpinst, &frame->ufp_exc.fpinst, err); +	__put_user_error(h->fpinst2, &frame->ufp_exc.fpinst2, err); + +	return err ? -EFAULT : 0; +} + +static int restore_vfp_context(struct vfp_sigframe __user *frame) +{ +	struct thread_info *thread = current_thread_info(); +	struct vfp_hard_struct *h = &thread->vfpstate.hard; +	unsigned long magic; +	unsigned long size; +	unsigned long fpexc; +	int err = 0; + +	__get_user_error(magic, &frame->magic, err); +	__get_user_error(size, &frame->size, err); + +	if (err) +		return -EFAULT; +	if (magic != VFP_MAGIC || size != VFP_STORAGE_SIZE) +		return -EINVAL; + +	/* +	 * Copy the floating point registers. There can be unused +	 * registers see asm/hwcap.h for details. +	 */ +	err |= __copy_from_user(&h->fpregs, &frame->ufp.fpregs, +				sizeof(h->fpregs)); +	/* +	 * Copy the status and control register. +	 */ +	__get_user_error(h->fpscr, &frame->ufp.fpscr, err); + +	/* +	 * Sanitise and restore the exception registers. +	 */ +	__get_user_error(fpexc, &frame->ufp_exc.fpexc, err); +	/* Ensure the VFP is enabled. */ +	fpexc |= FPEXC_EN; +	/* Ensure FPINST2 is invalid and the exception flag is cleared. */ +	fpexc &= ~(FPEXC_EX | FPEXC_FP2V); +	h->fpexc = fpexc; + +	__get_user_error(h->fpinst, &frame->ufp_exc.fpinst, err); +	__get_user_error(h->fpinst2, &frame->ufp_exc.fpinst2, err); + +	if (!err) +		vfp_flush_hwstate(thread); + +	return err ? -EFAULT : 0; +} + +#endif +  /*   * Do a signal return; undo the signal stack.  These are aligned to 64-bit.   */ @@ -233,8 +318,8 @@ static int restore_sigframe(struct pt_regs *regs, struct sigframe __user *sf)  		err |= restore_iwmmxt_context(&aux->iwmmxt);  #endif  #ifdef CONFIG_VFP -//	if (err == 0) -//		err |= vfp_restore_state(&sf->aux.vfp); +	if (err == 0) +		err |= restore_vfp_context(&aux->vfp);  #endif  	return err; @@ -348,8 +433,8 @@ setup_sigframe(struct sigframe __user *sf, struct pt_regs *regs, sigset_t *set)  		err |= preserve_iwmmxt_context(&aux->iwmmxt);  #endif  #ifdef CONFIG_VFP -//	if (err == 0) -//		err |= vfp_save_state(&sf->aux.vfp); +	if (err == 0) +		err |= preserve_vfp_context(&aux->vfp);  #endif  	__put_user_error(0, &aux->end_magic, err);  |