Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 3d1228ea authored by Catalin Marinas's avatar Catalin Marinas Committed by Russell King
Browse files

[ARM] 5387/1: Add ptrace VFP support on ARM



This patch adds ptrace support for setting and getting the VFP registers
using PTRACE_SETVFPREGS and PTRACE_GETVFPREGS. The user_vfp structure
defined in asm/user.h contains 32 double registers (to cover VFPv3 and
Neon hardware) and the FPSCR register.

Cc: Paul Brook <paul@codesourcery.com>
Cc: Daniel Jacobowitz <dan@codesourcery.com>
Signed-off-by: default avatarCatalin Marinas <catalin.marinas@arm.com>
Signed-off-by: default avatarRussell King <rmk+kernel@arm.linux.org.uk>
parent f373e8c0
Loading
Loading
Loading
Loading
+2 −0
Original line number Diff line number Diff line
@@ -27,6 +27,8 @@
/* PTRACE_SYSCALL is 24 */
#define PTRACE_GETCRUNCHREGS	25
#define PTRACE_SETCRUNCHREGS	26
#define PTRACE_GETVFPREGS	27
#define PTRACE_SETVFPREGS	28

/*
 * PSR bits
+2 −0
Original line number Diff line number Diff line
@@ -113,6 +113,8 @@ extern void iwmmxt_task_restore(struct thread_info *, void *);
extern void iwmmxt_task_release(struct thread_info *);
extern void iwmmxt_task_switch(struct thread_info *);

extern void vfp_sync_state(struct thread_info *thread);

#endif

/*
+9 −0
Original line number Diff line number Diff line
@@ -81,4 +81,13 @@ struct user{
#define HOST_TEXT_START_ADDR (u.start_code)
#define HOST_STACK_END_ADDR (u.start_stack + u.u_ssize * NBPG)

/*
 * User specific VFP registers. If only VFPv2 is present, registers 16 to 31
 * are ignored by the ptrace system call.
 */
struct user_vfp {
	unsigned long long fpregs[32];
	unsigned long fpscr;
};

#endif /* _ARM_USER_H */
+58 −0
Original line number Diff line number Diff line
@@ -653,6 +653,54 @@ static int ptrace_setcrunchregs(struct task_struct *tsk, void __user *ufp)
}
#endif

#ifdef CONFIG_VFP
/*
 * Get the child VFP state.
 */
static int ptrace_getvfpregs(struct task_struct *tsk, void __user *data)
{
	struct thread_info *thread = task_thread_info(tsk);
	union vfp_state *vfp = &thread->vfpstate;
	struct user_vfp __user *ufp = data;

	vfp_sync_state(thread);

	/* copy the floating point registers */
	if (copy_to_user(&ufp->fpregs, &vfp->hard.fpregs,
			 sizeof(vfp->hard.fpregs)))
		return -EFAULT;

	/* copy the status and control register */
	if (put_user(vfp->hard.fpscr, &ufp->fpscr))
		return -EFAULT;

	return 0;
}

/*
 * Set the child VFP state.
 */
static int ptrace_setvfpregs(struct task_struct *tsk, void __user *data)
{
	struct thread_info *thread = task_thread_info(tsk);
	union vfp_state *vfp = &thread->vfpstate;
	struct user_vfp __user *ufp = data;

	vfp_sync_state(thread);

	/* copy the floating point registers */
	if (copy_from_user(&vfp->hard.fpregs, &ufp->fpregs,
			   sizeof(vfp->hard.fpregs)))
		return -EFAULT;

	/* copy the status and control register */
	if (get_user(vfp->hard.fpscr, &ufp->fpscr))
		return -EFAULT;

	return 0;
}
#endif

long arch_ptrace(struct task_struct *child, long request, long addr, long data)
{
	int ret;
@@ -775,6 +823,16 @@ long arch_ptrace(struct task_struct *child, long request, long addr, long data)
			break;
#endif

#ifdef CONFIG_VFP
		case PTRACE_GETVFPREGS:
			ret = ptrace_getvfpregs(child, (void __user *)data);
			break;

		case PTRACE_SETVFPREGS:
			ret = ptrace_setvfpregs(child, (void __user *)data);
			break;
#endif

		default:
			ret = ptrace_request(child, request, addr, data);
			break;
+0 −2
Original line number Diff line number Diff line
@@ -377,6 +377,4 @@ struct op {
	u32 flags;
};

#if defined(CONFIG_SMP) || defined(CONFIG_PM)
extern void vfp_save_state(void *location, u32 fpexc);
#endif
Loading