summaryrefslogtreecommitdiff
path: root/arch/arm/kernel
diff options
context:
space:
mode:
authorCatalin Marinas <catalin.marinas@arm.com>2009-02-11 13:12:56 +0100
committerRebecca Schultz Zavin <rebecca@android.com>2009-10-26 12:12:05 -0700
commitb15c4e90986aab12f5d93ce319c3441361478ff1 (patch)
tree5188864c9cd7396db63d0cb82fa0f8030c5a5e5c /arch/arm/kernel
parent5b1e81e05f98019eb10b80e7cc14f21a9b2906dc (diff)
[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: Catalin Marinas <catalin.marinas@arm.com> Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk> (cherry picked from commit 3d1228ead618b88e8606015cbabc49019981805d)
Diffstat (limited to 'arch/arm/kernel')
-rw-r--r--arch/arm/kernel/ptrace.c58
1 files changed, 58 insertions, 0 deletions
diff --git a/arch/arm/kernel/ptrace.c b/arch/arm/kernel/ptrace.c
index df653ea59250..89882a1d0187 100644
--- a/arch/arm/kernel/ptrace.c
+++ b/arch/arm/kernel/ptrace.c
@@ -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;