aboutsummaryrefslogtreecommitdiffstats
path: root/arch/powerpc/kernel/ptrace.c
diff options
context:
space:
mode:
authorRoland McGrath <roland@redhat.com>2007-12-20 06:57:39 -0500
committerPaul Mackerras <paulus@samba.org>2008-02-07 04:38:56 -0500
commit3caf06c6e0656b25f694e3d414191cedcecf76ce (patch)
tree54e2cd0769ac54b1d12dd7b9dec5fe5beab5bec9 /arch/powerpc/kernel/ptrace.c
parentf65255e8d51ecbc6c9eef20d39e0377d19b658ca (diff)
[POWERPC] Use user_regset accessors for altivec regs
This implements user_regset-style accessors for the powerpc Altivec data, and rewrites the existing ptrace code in terms of those calls. Signed-off-by: Roland McGrath <roland@redhat.com> Signed-off-by: Paul Mackerras <paulus@samba.org>
Diffstat (limited to 'arch/powerpc/kernel/ptrace.c')
-rw-r--r--arch/powerpc/kernel/ptrace.c112
1 files changed, 78 insertions, 34 deletions
diff --git a/arch/powerpc/kernel/ptrace.c b/arch/powerpc/kernel/ptrace.c
index f1ce64649256..7cdf35a7c833 100644
--- a/arch/powerpc/kernel/ptrace.c
+++ b/arch/powerpc/kernel/ptrace.c
@@ -22,6 +22,7 @@
22#include <linux/errno.h> 22#include <linux/errno.h>
23#include <linux/ptrace.h> 23#include <linux/ptrace.h>
24#include <linux/regset.h> 24#include <linux/regset.h>
25#include <linux/elf.h>
25#include <linux/user.h> 26#include <linux/user.h>
26#include <linux/security.h> 27#include <linux/security.h>
27#include <linux/signal.h> 28#include <linux/signal.h>
@@ -163,30 +164,87 @@ static int set_fpregs(void __user *data, struct task_struct *task,
163 * (combined (32- and 64-bit) gdb. 164 * (combined (32- and 64-bit) gdb.
164 */ 165 */
165 166
167static int vr_active(struct task_struct *target,
168 const struct user_regset *regset)
169{
170 flush_altivec_to_thread(target);
171 return target->thread.used_vr ? regset->n : 0;
172}
173
174static int vr_get(struct task_struct *target, const struct user_regset *regset,
175 unsigned int pos, unsigned int count,
176 void *kbuf, void __user *ubuf)
177{
178 int ret;
179
180 flush_altivec_to_thread(target);
181
182 BUILD_BUG_ON(offsetof(struct thread_struct, vscr) !=
183 offsetof(struct thread_struct, vr[32]));
184
185 ret = user_regset_copyout(&pos, &count, &kbuf, &ubuf,
186 &target->thread.vr, 0,
187 33 * sizeof(vector128));
188 if (!ret) {
189 /*
190 * Copy out only the low-order word of vrsave.
191 */
192 union {
193 elf_vrreg_t reg;
194 u32 word;
195 } vrsave;
196 memset(&vrsave, 0, sizeof(vrsave));
197 vrsave.word = target->thread.vrsave;
198 ret = user_regset_copyout(&pos, &count, &kbuf, &ubuf, &vrsave,
199 33 * sizeof(vector128), -1);
200 }
201
202 return ret;
203}
204
205static int vr_set(struct task_struct *target, const struct user_regset *regset,
206 unsigned int pos, unsigned int count,
207 const void *kbuf, const void __user *ubuf)
208{
209 int ret;
210
211 flush_altivec_to_thread(target);
212
213 BUILD_BUG_ON(offsetof(struct thread_struct, vscr) !=
214 offsetof(struct thread_struct, vr[32]));
215
216 ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf,
217 &target->thread.vr, 0, 33 * sizeof(vector128));
218 if (!ret && count > 0) {
219 /*
220 * We use only the first word of vrsave.
221 */
222 union {
223 elf_vrreg_t reg;
224 u32 word;
225 } vrsave;
226 memset(&vrsave, 0, sizeof(vrsave));
227 vrsave.word = target->thread.vrsave;
228 ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf, &vrsave,
229 33 * sizeof(vector128), -1);
230 if (!ret)
231 target->thread.vrsave = vrsave.word;
232 }
233
234 return ret;
235}
236
166/* 237/*
167 * Get contents of AltiVec register state in task TASK 238 * Get contents of AltiVec register state in task TASK
168 */ 239 */
169static int get_vrregs(unsigned long __user *data, struct task_struct *task) 240static int get_vrregs(unsigned long __user *data, struct task_struct *task)
170{ 241{
171 unsigned long regsize; 242 if (!access_ok(VERIFY_WRITE, data,
172 243 33 * sizeof(vector128) + sizeof(u32)))
173 /* copy AltiVec registers VR[0] .. VR[31] */
174 regsize = 32 * sizeof(vector128);
175 if (copy_to_user(data, task->thread.vr, regsize))
176 return -EFAULT;
177 data += (regsize / sizeof(unsigned long));
178
179 /* copy VSCR */
180 regsize = 1 * sizeof(vector128);
181 if (copy_to_user(data, &task->thread.vscr, regsize))
182 return -EFAULT; 244 return -EFAULT;
183 data += (regsize / sizeof(unsigned long));
184 245
185 /* copy VRSAVE */ 246 return vr_get(task, NULL, 0, 33 * sizeof(vector128) + sizeof(u32),
186 if (put_user(task->thread.vrsave, (u32 __user *)data)) 247 NULL, data);
187 return -EFAULT;
188
189 return 0;
190} 248}
191 249
192/* 250/*
@@ -194,25 +252,11 @@ static int get_vrregs(unsigned long __user *data, struct task_struct *task)
194 */ 252 */
195static int set_vrregs(struct task_struct *task, unsigned long __user *data) 253static int set_vrregs(struct task_struct *task, unsigned long __user *data)
196{ 254{
197 unsigned long regsize; 255 if (!access_ok(VERIFY_READ, data, 33 * sizeof(vector128) + sizeof(u32)))
198
199 /* copy AltiVec registers VR[0] .. VR[31] */
200 regsize = 32 * sizeof(vector128);
201 if (copy_from_user(task->thread.vr, data, regsize))
202 return -EFAULT;
203 data += (regsize / sizeof(unsigned long));
204
205 /* copy VSCR */
206 regsize = 1 * sizeof(vector128);
207 if (copy_from_user(&task->thread.vscr, data, regsize))
208 return -EFAULT;
209 data += (regsize / sizeof(unsigned long));
210
211 /* copy VRSAVE */
212 if (get_user(task->thread.vrsave, (u32 __user *)data))
213 return -EFAULT; 256 return -EFAULT;
214 257
215 return 0; 258 return vr_set(task, NULL, 0, 33 * sizeof(vector128) + sizeof(u32),
259 NULL, data);
216} 260}
217#endif /* CONFIG_ALTIVEC */ 261#endif /* CONFIG_ALTIVEC */
218 262