aboutsummaryrefslogtreecommitdiffstats
path: root/arch/powerpc/kernel/ptrace.c
diff options
context:
space:
mode:
Diffstat (limited to 'arch/powerpc/kernel/ptrace.c')
-rw-r--r--arch/powerpc/kernel/ptrace.c114
1 files changed, 109 insertions, 5 deletions
diff --git a/arch/powerpc/kernel/ptrace.c b/arch/powerpc/kernel/ptrace.c
index 2a9fe97e4521..8feb93e7890c 100644
--- a/arch/powerpc/kernel/ptrace.c
+++ b/arch/powerpc/kernel/ptrace.c
@@ -215,29 +215,56 @@ static int fpr_get(struct task_struct *target, const struct user_regset *regset,
215 unsigned int pos, unsigned int count, 215 unsigned int pos, unsigned int count,
216 void *kbuf, void __user *ubuf) 216 void *kbuf, void __user *ubuf)
217{ 217{
218#ifdef CONFIG_VSX
219 double buf[33];
220 int i;
221#endif
218 flush_fp_to_thread(target); 222 flush_fp_to_thread(target);
219 223
224#ifdef CONFIG_VSX
225 /* copy to local buffer then write that out */
226 for (i = 0; i < 32 ; i++)
227 buf[i] = target->thread.TS_FPR(i);
228 memcpy(&buf[32], &target->thread.fpscr, sizeof(double));
229 return user_regset_copyout(&pos, &count, &kbuf, &ubuf, buf, 0, -1);
230
231#else
220 BUILD_BUG_ON(offsetof(struct thread_struct, fpscr) != 232 BUILD_BUG_ON(offsetof(struct thread_struct, fpscr) !=
221 offsetof(struct thread_struct, fpr[32])); 233 offsetof(struct thread_struct, TS_FPR(32)));
222 234
223 return user_regset_copyout(&pos, &count, &kbuf, &ubuf, 235 return user_regset_copyout(&pos, &count, &kbuf, &ubuf,
224 &target->thread.fpr, 0, -1); 236 &target->thread.fpr, 0, -1);
237#endif
225} 238}
226 239
227static int fpr_set(struct task_struct *target, const struct user_regset *regset, 240static int fpr_set(struct task_struct *target, const struct user_regset *regset,
228 unsigned int pos, unsigned int count, 241 unsigned int pos, unsigned int count,
229 const void *kbuf, const void __user *ubuf) 242 const void *kbuf, const void __user *ubuf)
230{ 243{
244#ifdef CONFIG_VSX
245 double buf[33];
246 int i;
247#endif
231 flush_fp_to_thread(target); 248 flush_fp_to_thread(target);
232 249
250#ifdef CONFIG_VSX
251 /* copy to local buffer then write that out */
252 i = user_regset_copyin(&pos, &count, &kbuf, &ubuf, buf, 0, -1);
253 if (i)
254 return i;
255 for (i = 0; i < 32 ; i++)
256 target->thread.TS_FPR(i) = buf[i];
257 memcpy(&target->thread.fpscr, &buf[32], sizeof(double));
258 return 0;
259#else
233 BUILD_BUG_ON(offsetof(struct thread_struct, fpscr) != 260 BUILD_BUG_ON(offsetof(struct thread_struct, fpscr) !=
234 offsetof(struct thread_struct, fpr[32])); 261 offsetof(struct thread_struct, TS_FPR(32)));
235 262
236 return user_regset_copyin(&pos, &count, &kbuf, &ubuf, 263 return user_regset_copyin(&pos, &count, &kbuf, &ubuf,
237 &target->thread.fpr, 0, -1); 264 &target->thread.fpr, 0, -1);
265#endif
238} 266}
239 267
240
241#ifdef CONFIG_ALTIVEC 268#ifdef CONFIG_ALTIVEC
242/* 269/*
243 * Get/set all the altivec registers vr0..vr31, vscr, vrsave, in one go. 270 * Get/set all the altivec registers vr0..vr31, vscr, vrsave, in one go.
@@ -323,6 +350,56 @@ static int vr_set(struct task_struct *target, const struct user_regset *regset,
323} 350}
324#endif /* CONFIG_ALTIVEC */ 351#endif /* CONFIG_ALTIVEC */
325 352
353#ifdef CONFIG_VSX
354/*
355 * Currently to set and and get all the vsx state, you need to call
356 * the fp and VMX calls aswell. This only get/sets the lower 32
357 * 128bit VSX registers.
358 */
359
360static int vsr_active(struct task_struct *target,
361 const struct user_regset *regset)
362{
363 flush_vsx_to_thread(target);
364 return target->thread.used_vsr ? regset->n : 0;
365}
366
367static int vsr_get(struct task_struct *target, const struct user_regset *regset,
368 unsigned int pos, unsigned int count,
369 void *kbuf, void __user *ubuf)
370{
371 double buf[32];
372 int ret, i;
373
374 flush_vsx_to_thread(target);
375
376 for (i = 0; i < 32 ; i++)
377 buf[i] = current->thread.fpr[i][TS_VSRLOWOFFSET];
378 ret = user_regset_copyout(&pos, &count, &kbuf, &ubuf,
379 buf, 0, 32 * sizeof(double));
380
381 return ret;
382}
383
384static int vsr_set(struct task_struct *target, const struct user_regset *regset,
385 unsigned int pos, unsigned int count,
386 const void *kbuf, const void __user *ubuf)
387{
388 double buf[32];
389 int ret,i;
390
391 flush_vsx_to_thread(target);
392
393 ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf,
394 buf, 0, 32 * sizeof(double));
395 for (i = 0; i < 32 ; i++)
396 current->thread.fpr[i][TS_VSRLOWOFFSET] = buf[i];
397
398
399 return ret;
400}
401#endif /* CONFIG_VSX */
402
326#ifdef CONFIG_SPE 403#ifdef CONFIG_SPE
327 404
328/* 405/*
@@ -399,6 +476,9 @@ enum powerpc_regset {
399#ifdef CONFIG_ALTIVEC 476#ifdef CONFIG_ALTIVEC
400 REGSET_VMX, 477 REGSET_VMX,
401#endif 478#endif
479#ifdef CONFIG_VSX
480 REGSET_VSX,
481#endif
402#ifdef CONFIG_SPE 482#ifdef CONFIG_SPE
403 REGSET_SPE, 483 REGSET_SPE,
404#endif 484#endif
@@ -422,6 +502,13 @@ static const struct user_regset native_regsets[] = {
422 .active = vr_active, .get = vr_get, .set = vr_set 502 .active = vr_active, .get = vr_get, .set = vr_set
423 }, 503 },
424#endif 504#endif
505#ifdef CONFIG_VSX
506 [REGSET_VSX] = {
507 .core_note_type = NT_PPC_VSX, .n = 32,
508 .size = sizeof(double), .align = sizeof(double),
509 .active = vsr_active, .get = vsr_get, .set = vsr_set
510 },
511#endif
425#ifdef CONFIG_SPE 512#ifdef CONFIG_SPE
426 [REGSET_SPE] = { 513 [REGSET_SPE] = {
427 .n = 35, 514 .n = 35,
@@ -728,7 +815,8 @@ long arch_ptrace(struct task_struct *child, long request, long addr, long data)
728 tmp = ptrace_get_reg(child, (int) index); 815 tmp = ptrace_get_reg(child, (int) index);
729 } else { 816 } else {
730 flush_fp_to_thread(child); 817 flush_fp_to_thread(child);
731 tmp = ((unsigned long *)child->thread.fpr)[index - PT_FPR0]; 818 tmp = ((unsigned long *)child->thread.fpr)
819 [TS_FPRWIDTH * (index - PT_FPR0)];
732 } 820 }
733 ret = put_user(tmp,(unsigned long __user *) data); 821 ret = put_user(tmp,(unsigned long __user *) data);
734 break; 822 break;
@@ -755,7 +843,8 @@ long arch_ptrace(struct task_struct *child, long request, long addr, long data)
755 ret = ptrace_put_reg(child, index, data); 843 ret = ptrace_put_reg(child, index, data);
756 } else { 844 } else {
757 flush_fp_to_thread(child); 845 flush_fp_to_thread(child);
758 ((unsigned long *)child->thread.fpr)[index - PT_FPR0] = data; 846 ((unsigned long *)child->thread.fpr)
847 [TS_FPRWIDTH * (index - PT_FPR0)] = data;
759 ret = 0; 848 ret = 0;
760 } 849 }
761 break; 850 break;
@@ -820,6 +909,21 @@ long arch_ptrace(struct task_struct *child, long request, long addr, long data)
820 sizeof(u32)), 909 sizeof(u32)),
821 (const void __user *) data); 910 (const void __user *) data);
822#endif 911#endif
912#ifdef CONFIG_VSX
913 case PTRACE_GETVSRREGS:
914 return copy_regset_to_user(child, &user_ppc_native_view,
915 REGSET_VSX,
916 0, (32 * sizeof(vector128) +
917 sizeof(u32)),
918 (void __user *) data);
919
920 case PTRACE_SETVSRREGS:
921 return copy_regset_from_user(child, &user_ppc_native_view,
922 REGSET_VSX,
923 0, (32 * sizeof(vector128) +
924 sizeof(u32)),
925 (const void __user *) data);
926#endif
823#ifdef CONFIG_SPE 927#ifdef CONFIG_SPE
824 case PTRACE_GETEVRREGS: 928 case PTRACE_GETEVRREGS:
825 /* Get the child spe register state. */ 929 /* Get the child spe register state. */