linux-omap-pm 2.6.29: update to latest git HEAD, sync patches and defconfig with...
[openembedded.git] / recipes / linux / linux-omap-pm-2.6.29 / vfp / 02-vfp-ptrace.patch
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
5
6 5387/1: Add ptrace VFP support on ARM
7
8 [ARM] 5387/1: Add ptrace VFP support on ARM
9
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.
14
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>
19 ---
20
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
25 @@ -27,6 +27,8 @@
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
31  
32  /*
33   * PSR bits
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 *);
41  
42 +extern void vfp_sync_state(struct thread_info *thread);
43 +
44  #endif
45  
46  /*
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)
54  
55 +/*
56 + * User specific VFP registers. If only VFPv2 is present, registers 16 to 31
57 + * are ignored by the ptrace system call.
58 + */
59 +struct user_vfp {
60 +       unsigned long long fpregs[32];
61 +       unsigned long fpscr;
62 +};
63 +
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)
70  }
71  #endif
72  
73 +#ifdef CONFIG_VFP
74 +/*
75 + * Get the child VFP state.
76 + */
77 +static int ptrace_getvfpregs(struct task_struct *tsk, void __user *data)
78 +{
79 +       struct thread_info *thread = task_thread_info(tsk);
80 +       union vfp_state *vfp = &thread->vfpstate;
81 +       struct user_vfp __user *ufp = data;
82 +
83 +       vfp_sync_state(thread);
84 +
85 +       /* copy the floating point registers */
86 +       if (copy_to_user(&ufp->fpregs, &vfp->hard.fpregs,
87 +                        sizeof(vfp->hard.fpregs)))
88 +               return -EFAULT;
89 +
90 +       /* copy the status and control register */
91 +       if (put_user(vfp->hard.fpscr, &ufp->fpscr))
92 +               return -EFAULT;
93 +
94 +       return 0;
95 +}
96 +
97 +/*
98 + * Set the child VFP state.
99 + */
100 +static int ptrace_setvfpregs(struct task_struct *tsk, void __user *data)
101 +{
102 +       struct thread_info *thread = task_thread_info(tsk);
103 +       union vfp_state *vfp = &thread->vfpstate;
104 +       struct user_vfp __user *ufp = data;
105 +
106 +       vfp_sync_state(thread);
107 +
108 +       /* copy the floating point registers */
109 +       if (copy_from_user(&vfp->hard.fpregs, &ufp->fpregs,
110 +                          sizeof(vfp->hard.fpregs)))
111 +               return -EFAULT;
112 +
113 +       /* copy the status and control register */
114 +       if (get_user(vfp->hard.fpscr, &ufp->fpscr))
115 +               return -EFAULT;
116 +
117 +       return 0;
118 +}
119 +#endif
120 +
121  long arch_ptrace(struct task_struct *child, long request, long addr, long data)
122  {
123         int ret;
124 @@ -775,6 +823,16 @@ long arch_ptrace(struct task_struct *child, long request, long addr, long data)
125                         break;
126  #endif
127  
128 +#ifdef CONFIG_VFP
129 +               case PTRACE_GETVFPREGS:
130 +                       ret = ptrace_getvfpregs(child, (void __user *)data);
131 +                       break;
132 +
133 +               case PTRACE_SETVFPREGS:
134 +                       ret = ptrace_setvfpregs(child, (void __user *)data);
135 +                       break;
136 +#endif
137 +
138                 default:
139                         ret = ptrace_request(child, request, addr, data);
140                         break;
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 {
146         u32 flags;
147  };
148  
149 -#if defined(CONFIG_SMP) || defined(CONFIG_PM)
150  extern void vfp_save_state(void *location, u32 fpexc);
151 -#endif
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)
159  
160 -#if defined(CONFIG_SMP) || defined(CONFIG_PM)
161  ENTRY(vfp_save_state)
162         @ Save the current VFP state
163         @ r0 - save location
164 @@ -181,7 +180,6 @@ ENTRY(vfp_save_state)
165         stmia   r0, {r1, r2, r3, r12}   @ save FPEXC, FPSCR, FPINST, FPINST2
166         mov     pc, lr
167  ENDPROC(vfp_save_state)
168 -#endif
169  
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 */
179  
180 +/*
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.
183 + */
184 +#ifdef CONFIG_SMP
185 +void vfp_sync_state(struct thread_info *thread)
186 +{
187 +       /*
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
191 +        * needed.
192 +        */
193 +       thread->vfpstate.hard.cpu = NR_CPUS;
194 +}
195 +#else
196 +void vfp_sync_state(struct thread_info *thread)
197 +{
198 +       unsigned int cpu = get_cpu();
199 +       u32 fpexc = fmrx(FPEXC);
200 +
201 +       /*
202 +        * If VFP is enabled, the previous state was already saved and
203 +        * last_VFP_context updated.
204 +        */
205 +       if (fpexc & FPEXC_EN)
206 +               goto out;
207 +
208 +       if (!last_VFP_context[cpu])
209 +               goto out;
210 +
211 +       /*
212 +        * Save the last VFP state on this CPU.
213 +        */
214 +       fmxr(FPEXC, fpexc | FPEXC_EN);
215 +       vfp_save_state(last_VFP_context[cpu], fpexc);
216 +       fmxr(FPEXC, fpexc);
217 +
218 +       /*
219 +        * Set the context to NULL to force a reload the next time the thread
220 +        * uses the VFP.
221 +        */
222 +       last_VFP_context[cpu] = NULL;
223 +
224 +out:
225 +       put_cpu();
226 +}
227 +#endif
228 +
229  #include <linux/smp.h>
230  
231  /*