diff options
Diffstat (limited to 'arch/powerpc/kernel/ptrace.c')
-rw-r--r-- | arch/powerpc/kernel/ptrace.c | 114 |
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 | ||
227 | static int fpr_set(struct task_struct *target, const struct user_regset *regset, | 240 | static 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 | |||
360 | static 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 | |||
367 | static 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 | |||
384 | static 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. */ |