powerpc/ptrace: Enable in transaction NT_PPC_VMX ptrace requests
authorAnshuman Khandual <khandual@linux.vnet.ibm.com>
Thu, 28 Jul 2016 02:57:33 +0000 (10:57 +0800)
committerMichael Ellerman <mpe@ellerman.id.au>
Mon, 1 Aug 2016 01:15:16 +0000 (11:15 +1000)
This patch enables in transaction NT_PPC_VMX ptrace requests. The
function vr_get which gets the running value of all VMX registers
and the function vr_set which sets the running value of of all VMX
registers work on the running set of VMX registers whose location
will be different if transaction is active. This patch makes these
functions adapt to situations when the transaction is active.

Signed-off-by: Anshuman Khandual <khandual@linux.vnet.ibm.com>
Signed-off-by: Simon Guo <wei.guo.simon@gmail.com>
Signed-off-by: Michael Ellerman <mpe@ellerman.id.au>
arch/powerpc/kernel/ptrace.c

index e8d126c3e7cded59f2717d78497be6df2e9d21c3..72da7dc924f10de4ace004413929b59933ff0b86 100644 (file)
@@ -518,10 +518,28 @@ static int vr_active(struct task_struct *target,
        return target->thread.used_vr ? regset->n : 0;
 }
 
+/*
+ * When the transaction is active, 'transact_vr' holds the current running
+ * value of all the VMX registers and 'vr_state' holds the last checkpointed
+ * value of all the VMX registers for the current transaction to fall back
+ * on in case it aborts. When transaction is not active 'vr_state' holds
+ * the current running state of all the VMX registers. So this function which
+ * gets the current running values of all the VMX registers, needs to know
+ * whether any transaction is active or not.
+ *
+ * Userspace interface buffer layout:
+ *
+ * struct data {
+ *     vector128       vr[32];
+ *     vector128       vscr;
+ *     vector128       vrsave;
+ * };
+ */
 static int vr_get(struct task_struct *target, const struct user_regset *regset,
                  unsigned int pos, unsigned int count,
                  void *kbuf, void __user *ubuf)
 {
+       struct thread_vr_state *addr;
        int ret;
 
        flush_altivec_to_thread(target);
@@ -529,8 +547,19 @@ static int vr_get(struct task_struct *target, const struct user_regset *regset,
        BUILD_BUG_ON(offsetof(struct thread_vr_state, vscr) !=
                     offsetof(struct thread_vr_state, vr[32]));
 
+#ifdef CONFIG_PPC_TRANSACTIONAL_MEM
+       if (MSR_TM_ACTIVE(target->thread.regs->msr)) {
+               flush_fp_to_thread(target);
+               flush_tmregs_to_thread(target);
+               addr = &target->thread.transact_vr;
+       } else {
+               addr = &target->thread.vr_state;
+       }
+#else
+       addr = &target->thread.vr_state;
+#endif
        ret = user_regset_copyout(&pos, &count, &kbuf, &ubuf,
-                                 &target->thread.vr_state, 0,
+                                 addr, 0,
                                  33 * sizeof(vector128));
        if (!ret) {
                /*
@@ -541,7 +570,16 @@ static int vr_get(struct task_struct *target, const struct user_regset *regset,
                        u32 word;
                } vrsave;
                memset(&vrsave, 0, sizeof(vrsave));
+
+#ifdef CONFIG_PPC_TRANSACTIONAL_MEM
+               if (MSR_TM_ACTIVE(target->thread.regs->msr))
+                       vrsave.word = target->thread.transact_vrsave;
+               else
+                       vrsave.word = target->thread.vrsave;
+#else
                vrsave.word = target->thread.vrsave;
+#endif
+
                ret = user_regset_copyout(&pos, &count, &kbuf, &ubuf, &vrsave,
                                          33 * sizeof(vector128), -1);
        }
@@ -549,10 +587,28 @@ static int vr_get(struct task_struct *target, const struct user_regset *regset,
        return ret;
 }
 
+/*
+ * When the transaction is active, 'transact_vr' holds the current running
+ * value of all the VMX registers and 'vr_state' holds the last checkpointed
+ * value of all the VMX registers for the current transaction to fall back
+ * on in case it aborts. When transaction is not active 'vr_state' holds
+ * the current running state of all the VMX registers. So this function which
+ * sets the current running values of all the VMX registers, needs to know
+ * whether any transaction is active or not.
+ *
+ * Userspace interface buffer layout:
+ *
+ * struct data {
+ *     vector128       vr[32];
+ *     vector128       vscr;
+ *     vector128       vrsave;
+ * };
+ */
 static int vr_set(struct task_struct *target, const struct user_regset *regset,
                  unsigned int pos, unsigned int count,
                  const void *kbuf, const void __user *ubuf)
 {
+       struct thread_vr_state *addr;
        int ret;
 
        flush_altivec_to_thread(target);
@@ -560,8 +616,19 @@ static int vr_set(struct task_struct *target, const struct user_regset *regset,
        BUILD_BUG_ON(offsetof(struct thread_vr_state, vscr) !=
                     offsetof(struct thread_vr_state, vr[32]));
 
+#ifdef CONFIG_PPC_TRANSACTIONAL_MEM
+       if (MSR_TM_ACTIVE(target->thread.regs->msr)) {
+               flush_fp_to_thread(target);
+               flush_tmregs_to_thread(target);
+               addr = &target->thread.transact_vr;
+       } else {
+               addr = &target->thread.vr_state;
+       }
+#else
+       addr = &target->thread.vr_state;
+#endif
        ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf,
-                                &target->thread.vr_state, 0,
+                                addr, 0,
                                 33 * sizeof(vector128));
        if (!ret && count > 0) {
                /*
@@ -572,11 +639,28 @@ static int vr_set(struct task_struct *target, const struct user_regset *regset,
                        u32 word;
                } vrsave;
                memset(&vrsave, 0, sizeof(vrsave));
+
+#ifdef CONFIG_PPC_TRANSACTIONAL_MEM
+               if (MSR_TM_ACTIVE(target->thread.regs->msr))
+                       vrsave.word = target->thread.transact_vrsave;
+               else
+                       vrsave.word = target->thread.vrsave;
+#else
                vrsave.word = target->thread.vrsave;
+#endif
                ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf, &vrsave,
                                         33 * sizeof(vector128), -1);
-               if (!ret)
+               if (!ret) {
+
+#ifdef CONFIG_PPC_TRANSACTIONAL_MEM
+                       if (MSR_TM_ACTIVE(target->thread.regs->msr))
+                               target->thread.transact_vrsave = vrsave.word;
+                       else
+                               target->thread.vrsave = vrsave.word;
+#else
                        target->thread.vrsave = vrsave.word;
+#endif
+               }
        }
 
        return ret;