Merge branch 'master' of git://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux-2.6
[pandora-kernel.git] / arch / powerpc / kernel / ptrace.c
index 7673e98..8feb93e 100644 (file)
@@ -215,29 +215,56 @@ static int fpr_get(struct task_struct *target, const struct user_regset *regset,
                   unsigned int pos, unsigned int count,
                   void *kbuf, void __user *ubuf)
 {
+#ifdef CONFIG_VSX
+       double buf[33];
+       int i;
+#endif
        flush_fp_to_thread(target);
 
+#ifdef CONFIG_VSX
+       /* copy to local buffer then write that out */
+       for (i = 0; i < 32 ; i++)
+               buf[i] = target->thread.TS_FPR(i);
+       memcpy(&buf[32], &target->thread.fpscr, sizeof(double));
+       return user_regset_copyout(&pos, &count, &kbuf, &ubuf, buf, 0, -1);
+
+#else
        BUILD_BUG_ON(offsetof(struct thread_struct, fpscr) !=
-                    offsetof(struct thread_struct, fpr[32]));
+                    offsetof(struct thread_struct, TS_FPR(32)));
 
        return user_regset_copyout(&pos, &count, &kbuf, &ubuf,
                                   &target->thread.fpr, 0, -1);
+#endif
 }
 
 static int fpr_set(struct task_struct *target, const struct user_regset *regset,
                   unsigned int pos, unsigned int count,
                   const void *kbuf, const void __user *ubuf)
 {
+#ifdef CONFIG_VSX
+       double buf[33];
+       int i;
+#endif
        flush_fp_to_thread(target);
 
+#ifdef CONFIG_VSX
+       /* copy to local buffer then write that out */
+       i = user_regset_copyin(&pos, &count, &kbuf, &ubuf, buf, 0, -1);
+       if (i)
+               return i;
+       for (i = 0; i < 32 ; i++)
+               target->thread.TS_FPR(i) = buf[i];
+       memcpy(&target->thread.fpscr, &buf[32], sizeof(double));
+       return 0;
+#else
        BUILD_BUG_ON(offsetof(struct thread_struct, fpscr) !=
-                    offsetof(struct thread_struct, fpr[32]));
+                    offsetof(struct thread_struct, TS_FPR(32)));
 
        return user_regset_copyin(&pos, &count, &kbuf, &ubuf,
                                  &target->thread.fpr, 0, -1);
+#endif
 }
 
-
 #ifdef CONFIG_ALTIVEC
 /*
  * 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,
 }
 #endif /* CONFIG_ALTIVEC */
 
+#ifdef CONFIG_VSX
+/*
+ * Currently to set and and get all the vsx state, you need to call
+ * the fp and VMX calls aswell.  This only get/sets the lower 32
+ * 128bit VSX registers.
+ */
+
+static int vsr_active(struct task_struct *target,
+                     const struct user_regset *regset)
+{
+       flush_vsx_to_thread(target);
+       return target->thread.used_vsr ? regset->n : 0;
+}
+
+static int vsr_get(struct task_struct *target, const struct user_regset *regset,
+                  unsigned int pos, unsigned int count,
+                  void *kbuf, void __user *ubuf)
+{
+       double buf[32];
+       int ret, i;
+
+       flush_vsx_to_thread(target);
+
+       for (i = 0; i < 32 ; i++)
+               buf[i] = current->thread.fpr[i][TS_VSRLOWOFFSET];
+       ret = user_regset_copyout(&pos, &count, &kbuf, &ubuf,
+                                 buf, 0, 32 * sizeof(double));
+
+       return ret;
+}
+
+static int vsr_set(struct task_struct *target, const struct user_regset *regset,
+                  unsigned int pos, unsigned int count,
+                  const void *kbuf, const void __user *ubuf)
+{
+       double buf[32];
+       int ret,i;
+
+       flush_vsx_to_thread(target);
+
+       ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf,
+                                buf, 0, 32 * sizeof(double));
+       for (i = 0; i < 32 ; i++)
+               current->thread.fpr[i][TS_VSRLOWOFFSET] = buf[i];
+
+
+       return ret;
+}
+#endif /* CONFIG_VSX */
+
 #ifdef CONFIG_SPE
 
 /*
@@ -399,6 +476,9 @@ enum powerpc_regset {
 #ifdef CONFIG_ALTIVEC
        REGSET_VMX,
 #endif
+#ifdef CONFIG_VSX
+       REGSET_VSX,
+#endif
 #ifdef CONFIG_SPE
        REGSET_SPE,
 #endif
@@ -422,6 +502,13 @@ static const struct user_regset native_regsets[] = {
                .active = vr_active, .get = vr_get, .set = vr_set
        },
 #endif
+#ifdef CONFIG_VSX
+       [REGSET_VSX] = {
+               .core_note_type = NT_PPC_VSX, .n = 32,
+               .size = sizeof(double), .align = sizeof(double),
+               .active = vsr_active, .get = vsr_get, .set = vsr_set
+       },
+#endif
 #ifdef CONFIG_SPE
        [REGSET_SPE] = {
                .n = 35,
@@ -530,15 +617,21 @@ static int gpr32_set(struct task_struct *target,
                --count;
        }
 
-       if (kbuf)
+       if (kbuf) {
                for (; count > 0 && pos <= PT_MAX_PUT_REG; --count)
                        regs[pos++] = *k++;
-       else
+               for (; count > 0 && pos < PT_TRAP; --count, ++pos)
+                       ++k;
+       } else {
                for (; count > 0 && pos <= PT_MAX_PUT_REG; --count) {
                        if (__get_user(reg, u++))
                                return -EFAULT;
                        regs[pos++] = reg;
                }
+               for (; count > 0 && pos < PT_TRAP; --count, ++pos)
+                       if (__get_user(reg, u++))
+                               return -EFAULT;
+       }
 
        if (count > 0 && pos == PT_TRAP) {
                if (kbuf)
@@ -722,7 +815,8 @@ long arch_ptrace(struct task_struct *child, long request, long addr, long data)
                        tmp = ptrace_get_reg(child, (int) index);
                } else {
                        flush_fp_to_thread(child);
-                       tmp = ((unsigned long *)child->thread.fpr)[index - PT_FPR0];
+                       tmp = ((unsigned long *)child->thread.fpr)
+                               [TS_FPRWIDTH * (index - PT_FPR0)];
                }
                ret = put_user(tmp,(unsigned long __user *) data);
                break;
@@ -749,7 +843,8 @@ long arch_ptrace(struct task_struct *child, long request, long addr, long data)
                        ret = ptrace_put_reg(child, index, data);
                } else {
                        flush_fp_to_thread(child);
-                       ((unsigned long *)child->thread.fpr)[index - PT_FPR0] = data;
+                       ((unsigned long *)child->thread.fpr)
+                               [TS_FPRWIDTH * (index - PT_FPR0)] = data;
                        ret = 0;
                }
                break;
@@ -814,6 +909,21 @@ long arch_ptrace(struct task_struct *child, long request, long addr, long data)
                                                 sizeof(u32)),
                                             (const void __user *) data);
 #endif
+#ifdef CONFIG_VSX
+       case PTRACE_GETVSRREGS:
+               return copy_regset_to_user(child, &user_ppc_native_view,
+                                          REGSET_VSX,
+                                          0, (32 * sizeof(vector128) +
+                                              sizeof(u32)),
+                                          (void __user *) data);
+
+       case PTRACE_SETVSRREGS:
+               return copy_regset_from_user(child, &user_ppc_native_view,
+                                            REGSET_VSX,
+                                            0, (32 * sizeof(vector128) +
+                                                sizeof(u32)),
+                                            (const void __user *) data);
+#endif
 #ifdef CONFIG_SPE
        case PTRACE_GETEVRREGS:
                /* Get the child spe register state. */