Пример #1
0
static void vfp_thread_copy(struct thread_info *thread)
{
	struct thread_info *parent = current_thread_info();

	vfp_sync_hwstate(parent);
	thread->vfpstate = parent->vfpstate;
}
Пример #2
0
/*
 * VFP register get/set implementations.
 *
 * With respect to the kernel, struct user_fp is divided into three chunks:
 * 16 or 32 real VFP registers (d0-d15 or d0-31)
 *	These are transferred to/from the real registers in the task's
 *	vfp_hard_struct.  The number of registers depends on the kernel
 *	configuration.
 *
 * 16 or 0 fake VFP registers (d16-d31 or empty)
 *	i.e., the user_vfp structure has space for 32 registers even if
 *	the kernel doesn't have them all.
 *
 *	vfp_get() reads this chunk as zero where applicable
 *	vfp_set() ignores this chunk
 *
 * 1 word for the FPSCR
 *
 * The bounds-checking logic built into user_regset_copyout and friends
 * means that we can make a simple sequence of calls to map the relevant data
 * to/from the specified slice of the user regset structure.
 */
static int vfp_get(struct task_struct *target,
		   const struct user_regset *regset,
		   unsigned int pos, unsigned int count,
		   void *kbuf, void __user *ubuf)
{
	int ret;
	struct thread_info *thread = task_thread_info(target);
	struct vfp_hard_struct const *vfp = &thread->vfpstate.hard;
	const size_t user_fpregs_offset = offsetof(struct user_vfp, fpregs);
	const size_t user_fpscr_offset = offsetof(struct user_vfp, fpscr);

	vfp_sync_hwstate(thread);

	ret = user_regset_copyout(&pos, &count, &kbuf, &ubuf,
				  &vfp->fpregs,
				  user_fpregs_offset,
				  user_fpregs_offset + sizeof(vfp->fpregs));
	if (ret)
		return ret;

	ret = user_regset_copyout_zero(&pos, &count, &kbuf, &ubuf,
				       user_fpregs_offset + sizeof(vfp->fpregs),
				       user_fpscr_offset);
	if (ret)
		return ret;

	return user_regset_copyout(&pos, &count, &kbuf, &ubuf,
				   &vfp->fpscr,
				   user_fpscr_offset,
				   user_fpscr_offset + sizeof(vfp->fpscr));
}
int vfp_preserve_user_clear_hwstate(struct user_vfp __user *ufp,
				    struct user_vfp_exc __user *ufp_exc)
{
	struct thread_info *thread = current_thread_info();
	struct vfp_hard_struct *hwstate = &thread->vfpstate.hard;
	int err = 0;

	
	vfp_sync_hwstate(thread);

	err |= __copy_to_user(&ufp->fpregs, &hwstate->fpregs,
			      sizeof(hwstate->fpregs));
	__put_user_error(hwstate->fpscr, &ufp->fpscr, err);

	__put_user_error(hwstate->fpexc, &ufp_exc->fpexc, err);
	__put_user_error(hwstate->fpinst, &ufp_exc->fpinst, err);
	__put_user_error(hwstate->fpinst2, &ufp_exc->fpinst2, err);

	if (err)
		return -EFAULT;

	
	vfp_flush_hwstate(thread);

	hwstate->fpscr &= ~(FPSCR_LENGTH_MASK | FPSCR_STRIDE_MASK);
	return 0;
}
Пример #4
0
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 void vfp_thread_copy(struct thread_info *thread)
{
	struct thread_info *parent = current_thread_info();

	vfp_sync_hwstate(parent);
	thread->vfpstate = parent->vfpstate;
#ifdef CONFIG_SMP
	thread->vfpstate.hard.cpu = NR_CPUS;
#endif
}
Пример #6
0
/*
 * Save the current VFP state into the provided structures and prepare
 * for entry into a new function (signal handler).
 */
int vfp_preserve_user_hwstate(struct user_vfp __user *ufp,
			      struct user_vfp_exc __user *ufp_exc)
{
	struct thread_info *thread = current_thread_info();
	struct vfp_hard_struct *hwstate = &thread->vfpstate.hard;
	int err = 0;

	/* Ensure that the saved hwstate is up-to-date. */
	vfp_sync_hwstate(thread);

	/*
	 * Copy the floating point registers. There can be unused
	 * registers see asm/hwcap.h for details.
	 */
	err |= __copy_to_user(&ufp->fpregs, &hwstate->fpregs,
			      sizeof(hwstate->fpregs));
	/*
	 * Copy the status and control register.
	 */
	__put_user_error(hwstate->fpscr, &ufp->fpscr, err);

	/*
	 * Copy the exception registers.
	 */
	__put_user_error(hwstate->fpexc, &ufp_exc->fpexc, err);
	__put_user_error(hwstate->fpinst, &ufp_exc->fpinst, err);
	__put_user_error(hwstate->fpinst2, &ufp_exc->fpinst2, err);

	if (err)
		return -EFAULT;

	/* Ensure that VFP is disabled. */
	vfp_flush_hwstate(thread);

	/*
	 * As per the PCS, clear the length and stride bits before entry
	 * to the signal handler.
	 */
	hwstate->fpscr &= ~(FPSCR_LENGTH_MASK | FPSCR_STRIDE_MASK);

	/*
	 * Disable VFP in the hwstate so that we can detect if it was
	 * used by the signal handler.
	 */
	hwstate->fpexc &= ~FPEXC_EN;
	return 0;
}
Пример #7
0
/*
 * For vfp_set() a read-modify-write is done on the VFP registers,
 * in order to avoid writing back a half-modified set of registers on
 * failure.
 */
static int vfp_set(struct task_struct *target,
			  const struct user_regset *regset,
			  unsigned int pos, unsigned int count,
			  const void *kbuf, const void __user *ubuf)
{
	int ret;
	struct thread_info *thread = task_thread_info(target);
/*	struct vfp_hard_struct new_vfp = thread->vfpstate.hard; */
	struct vfp_hard_struct new_vfp;
	const size_t user_fpregs_offset = offsetof(struct user_vfp, fpregs);
	const size_t user_fpscr_offset = offsetof(struct user_vfp, fpscr);

	vfp_sync_hwstate(thread);
	new_vfp = thread->vfpstate.hard;
	
	ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf,
				  &new_vfp.fpregs,
				  user_fpregs_offset,
				  user_fpregs_offset + sizeof(new_vfp.fpregs));
	if (ret)
		return ret;

	ret = user_regset_copyin_ignore(&pos, &count, &kbuf, &ubuf,
				user_fpregs_offset + sizeof(new_vfp.fpregs),
				user_fpscr_offset);
	if (ret)
		return ret;

	ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf,
				 &new_vfp.fpscr,
				 user_fpscr_offset,
				 user_fpscr_offset + sizeof(new_vfp.fpscr));
	if (ret)
		return ret;

/*	vfp_sync_hwstate(thread); */
/*	thread->vfpstate.hard = new_vfp; */
	vfp_flush_hwstate(thread);
	thread->vfpstate.hard = new_vfp;

	return 0;
}