1 From: Catalin Marinas <catalin.marinas@arm.com>
2 Date: Wed, 11 Feb 2009 11:12:56 +0000 (+0100)
3 Subject: 5387/1: Add ptrace VFP support on ARM
4 X-Git-Url: http://siarhei.siamashka.name/gitweb/?p=linux-omap-2.6.git;a=commitdiff_plain;h=4dd5beb2244f15c895aba46474bd89545327d1a6
6 5387/1: Add ptrace VFP support on ARM
8 [ARM] 5387/1: Add ptrace VFP support on ARM
10 This patch adds ptrace support for setting and getting the VFP registers
11 using PTRACE_SETVFPREGS and PTRACE_GETVFPREGS. The user_vfp structure
12 defined in asm/user.h contains 32 double registers (to cover VFPv3 and
13 Neon hardware) and the FPSCR register.
15 Cc: Paul Brook <paul@codesourcery.com>
16 Cc: Daniel Jacobowitz <dan@codesourcery.com>
17 Signed-off-by: Catalin Marinas <catalin.marinas@arm.com>
18 Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
21 diff --git a/arch/arm/include/asm/ptrace.h b/arch/arm/include/asm/ptrace.h
22 index 7319261..236a06b 100644
23 --- a/arch/arm/include/asm/ptrace.h
24 +++ b/arch/arm/include/asm/ptrace.h
26 /* PTRACE_SYSCALL is 24 */
27 #define PTRACE_GETCRUNCHREGS 25
28 #define PTRACE_SETCRUNCHREGS 26
29 +#define PTRACE_GETVFPREGS 27
30 +#define PTRACE_SETVFPREGS 28
34 diff --git a/arch/arm/include/asm/thread_info.h b/arch/arm/include/asm/thread_info.h
35 index 68b9ec8..b9dc8a8 100644
36 --- a/arch/arm/include/asm/thread_info.h
37 +++ b/arch/arm/include/asm/thread_info.h
38 @@ -113,6 +113,8 @@ extern void iwmmxt_task_restore(struct thread_info *, void *);
39 extern void iwmmxt_task_release(struct thread_info *);
40 extern void iwmmxt_task_switch(struct thread_info *);
42 +extern void vfp_sync_state(struct thread_info *thread);
47 diff --git a/arch/arm/include/asm/user.h b/arch/arm/include/asm/user.h
48 index 825c1e7..df95e05 100644
49 --- a/arch/arm/include/asm/user.h
50 +++ b/arch/arm/include/asm/user.h
51 @@ -81,4 +81,13 @@ struct user{
52 #define HOST_TEXT_START_ADDR (u.start_code)
53 #define HOST_STACK_END_ADDR (u.start_stack + u.u_ssize * NBPG)
56 + * User specific VFP registers. If only VFPv2 is present, registers 16 to 31
57 + * are ignored by the ptrace system call.
60 + unsigned long long fpregs[32];
61 + unsigned long fpscr;
64 #endif /* _ARM_USER_H */
65 diff --git a/arch/arm/kernel/ptrace.c b/arch/arm/kernel/ptrace.c
66 index df653ea..89882a1 100644
67 --- a/arch/arm/kernel/ptrace.c
68 +++ b/arch/arm/kernel/ptrace.c
69 @@ -653,6 +653,54 @@ static int ptrace_setcrunchregs(struct task_struct *tsk, void __user *ufp)
75 + * Get the child VFP state.
77 +static int ptrace_getvfpregs(struct task_struct *tsk, void __user *data)
79 + struct thread_info *thread = task_thread_info(tsk);
80 + union vfp_state *vfp = &thread->vfpstate;
81 + struct user_vfp __user *ufp = data;
83 + vfp_sync_state(thread);
85 + /* copy the floating point registers */
86 + if (copy_to_user(&ufp->fpregs, &vfp->hard.fpregs,
87 + sizeof(vfp->hard.fpregs)))
90 + /* copy the status and control register */
91 + if (put_user(vfp->hard.fpscr, &ufp->fpscr))
98 + * Set the child VFP state.
100 +static int ptrace_setvfpregs(struct task_struct *tsk, void __user *data)
102 + struct thread_info *thread = task_thread_info(tsk);
103 + union vfp_state *vfp = &thread->vfpstate;
104 + struct user_vfp __user *ufp = data;
106 + vfp_sync_state(thread);
108 + /* copy the floating point registers */
109 + if (copy_from_user(&vfp->hard.fpregs, &ufp->fpregs,
110 + sizeof(vfp->hard.fpregs)))
113 + /* copy the status and control register */
114 + if (get_user(vfp->hard.fpscr, &ufp->fpscr))
121 long arch_ptrace(struct task_struct *child, long request, long addr, long data)
124 @@ -775,6 +823,16 @@ long arch_ptrace(struct task_struct *child, long request, long addr, long data)
129 + case PTRACE_GETVFPREGS:
130 + ret = ptrace_getvfpregs(child, (void __user *)data);
133 + case PTRACE_SETVFPREGS:
134 + ret = ptrace_setvfpregs(child, (void __user *)data);
139 ret = ptrace_request(child, request, addr, data);
141 diff --git a/arch/arm/vfp/vfp.h b/arch/arm/vfp/vfp.h
142 index 8de86e4..c8c98dd 100644
143 --- a/arch/arm/vfp/vfp.h
144 +++ b/arch/arm/vfp/vfp.h
145 @@ -377,6 +377,4 @@ struct op {
149 -#if defined(CONFIG_SMP) || defined(CONFIG_PM)
150 extern void vfp_save_state(void *location, u32 fpexc);
152 diff --git a/arch/arm/vfp/vfphw.S b/arch/arm/vfp/vfphw.S
153 index b21f43f..902d396 100644
154 --- a/arch/arm/vfp/vfphw.S
155 +++ b/arch/arm/vfp/vfphw.S
156 @@ -166,7 +166,6 @@ process_exception:
157 @ retry the faulted instruction
158 ENDPROC(vfp_support_entry)
160 -#if defined(CONFIG_SMP) || defined(CONFIG_PM)
161 ENTRY(vfp_save_state)
162 @ Save the current VFP state
164 @@ -181,7 +180,6 @@ ENTRY(vfp_save_state)
165 stmia r0, {r1, r2, r3, r12} @ save FPEXC, FPSCR, FPINST, FPINST2
167 ENDPROC(vfp_save_state)
170 last_VFP_context_address:
171 .word last_VFP_context
172 diff --git a/arch/arm/vfp/vfpmodule.c b/arch/arm/vfp/vfpmodule.c
173 index 9f476a1..7e12390 100644
174 --- a/arch/arm/vfp/vfpmodule.c
175 +++ b/arch/arm/vfp/vfpmodule.c
176 @@ -377,6 +377,55 @@ static void vfp_pm_init(void)
177 static inline void vfp_pm_init(void) { }
178 #endif /* CONFIG_PM */
181 + * Synchronise the hardware VFP state of a thread other than current with the
182 + * saved one. This function is used by the ptrace mechanism.
185 +void vfp_sync_state(struct thread_info *thread)
188 + * On SMP systems, the VFP state is automatically saved at every
189 + * context switch. We mark the thread VFP state as belonging to a
190 + * non-existent CPU so that the saved one will be reloaded when
193 + thread->vfpstate.hard.cpu = NR_CPUS;
196 +void vfp_sync_state(struct thread_info *thread)
198 + unsigned int cpu = get_cpu();
199 + u32 fpexc = fmrx(FPEXC);
202 + * If VFP is enabled, the previous state was already saved and
203 + * last_VFP_context updated.
205 + if (fpexc & FPEXC_EN)
208 + if (!last_VFP_context[cpu])
212 + * Save the last VFP state on this CPU.
214 + fmxr(FPEXC, fpexc | FPEXC_EN);
215 + vfp_save_state(last_VFP_context[cpu], fpexc);
216 + fmxr(FPEXC, fpexc);
219 + * Set the context to NULL to force a reload the next time the thread
222 + last_VFP_context[cpu] = NULL;
229 #include <linux/smp.h>