This patch adds few more ptrace request macros expanding
the existing capability. These ptrace requests macros can
be classified into two categories.

(1) Transactional memory

        /* TM special purpose registers */
        PTRACE_GETTM_SPRREGS
        PTRACE_SETTM_SPRREGS

        /* Checkpointed GPR registers */
        PTRACE_GETTM_CGPRREGS
        PTRACE_SETTM_CGPRREGS

        /* Checkpointed FPR registers */
        PTRACE_GETTM_CFPRREGS
        PTRACE_SETTM_CFPRREGS

        /* Checkpointed VMX registers */
        PTRACE_GETTM_CVMXREGS
        PTRACE_SETTM_CVMXREGS

(2) Miscellaneous

        /* TAR, PPR, DSCR registers */
        PTRACE_GETMSCREGS
        PTRACE_SETMSCREGS

This patch also adds mutliple new generic ELF core note sections in
this regard which can be listed as follows.

        NT_PPC_TM_SPR   /* Transactional memory specific registers */
        NT_PPC_TM_CGPR  /* Transactional memory checkpointed GPR */
        NT_PPC_TM_CFPR  /* Transactional memory checkpointed FPR */
        NT_PPC_TM_CVMX  /* Transactional memory checkpointed VMX */
        NT_PPC_MISC     /* Miscellaneous registers */

Signed-off-by: Anshuman Khandual <khand...@linux.vnet.ibm.com>
---
 arch/powerpc/include/asm/switch_to.h   |   8 +
 arch/powerpc/include/uapi/asm/ptrace.h |  61 +++
 arch/powerpc/kernel/process.c          |  24 ++
 arch/powerpc/kernel/ptrace.c           | 658 +++++++++++++++++++++++++++++++--
 include/uapi/linux/elf.h               |   5 +
 5 files changed, 729 insertions(+), 27 deletions(-)

diff --git a/arch/powerpc/include/asm/switch_to.h 
b/arch/powerpc/include/asm/switch_to.h
index 0e83e7d..73e2601 100644
--- a/arch/powerpc/include/asm/switch_to.h
+++ b/arch/powerpc/include/asm/switch_to.h
@@ -80,6 +80,14 @@ static inline void flush_spe_to_thread(struct task_struct *t)
 }
 #endif
 
+#ifdef CONFIG_PPC_TRANSACTIONAL_MEM
+extern void flush_tmreg_to_thread(struct task_struct *);
+#else
+static inline void flush_tmreg_to_thread(struct task_struct *t)
+{
+}
+#endif
+
 static inline void clear_task_ebb(struct task_struct *t)
 {
 #ifdef CONFIG_PPC_BOOK3S_64
diff --git a/arch/powerpc/include/uapi/asm/ptrace.h 
b/arch/powerpc/include/uapi/asm/ptrace.h
index 77d2ed3..fd962d6 100644
--- a/arch/powerpc/include/uapi/asm/ptrace.h
+++ b/arch/powerpc/include/uapi/asm/ptrace.h
@@ -190,6 +190,67 @@ struct pt_regs {
 #define PPC_PTRACE_SETHWDEBUG  0x88
 #define PPC_PTRACE_DELHWDEBUG  0x87
 
+/* Transactional memory registers */
+
+/*
+ * SPR
+ *
+ * struct data {
+ *     u64             tm_tfhar;
+ *     u64             tm_texasr;
+ *     u64             tm_tfiar;
+ *     unsigned long   tm_orig_msr;
+ *     u64             tm_tar;
+ *     u64             tm_ppr;
+ *     u64             tm_dscr;
+ * };
+ */
+#define PTRACE_GETTM_SPRREGS   0x70
+#define PTRACE_SETTM_SPRREGS   0x71
+
+/* 
+ * Checkpointed GPR
+ *
+ * struct data {
+ *     struct pt_regs  ckpt_regs;
+ * };
+ */
+#define PTRACE_GETTM_CGPRREGS  0x72
+#define PTRACE_SETTM_CGPRREGS  0x73
+
+/*
+ * Checkpointed FPR
+ *
+ * struct data {
+ *     u64     fpr[32];
+ *     u64     fpscr;
+ * };
+ */
+#define PTRACE_GETTM_CFPRREGS  0x74
+#define PTRACE_SETTM_CFPRREGS  0x75
+
+/* 
+ * Checkpointed VMX
+ *
+ * struct data {
+ *     vector128       vr[32];
+ *     vector128       vscr;
+ *     unsigned long   vrsave; 
+ *};
+ */
+#define PTRACE_GETTM_CVMXREGS  0x76
+#define PTRACE_SETTM_CVMXREGS  0x77
+
+/* Miscellaneous registers */
+#define PTRACE_GETMSCREGS      0x78
+#define PTRACE_SETMSCREGS      0x79
+
+/*
+ * XXX: A note to application developers. The existing data layout
+ * of the above four ptrace requests can change when new registers
+ * are available for each category in forthcoming processors.
+ */
+
 #ifndef __ASSEMBLY__
 
 struct ppc_debug_info {
diff --git a/arch/powerpc/kernel/process.c b/arch/powerpc/kernel/process.c
index af064d2..e5dfd8e 100644
--- a/arch/powerpc/kernel/process.c
+++ b/arch/powerpc/kernel/process.c
@@ -673,6 +673,30 @@ static inline void __switch_to_tm(struct task_struct *prev)
        }
 }
 
+void flush_tmreg_to_thread(struct task_struct *tsk)
+{
+       /*
+        * If task is not current, it should have been flushed
+        * already to it's thread_struct during __switch_to().
+        */
+       if (tsk != current)
+               return;
+
+       preempt_disable();
+       if (tsk->thread.regs) {
+               /* 
+                * If we are still current, the TM state need to
+                * be flushed to thread_struct as it will be still
+                * present in the current cpu
+                */
+               if (MSR_TM_ACTIVE(tsk->thread.regs->msr)) {
+                       __switch_to_tm(tsk);
+                       tm_recheckpoint_new_task(tsk);
+               }
+       }
+       preempt_enable();
+}
+
 /*
  * This is called if we are on the way out to userspace and the
  * TIF_RESTORE_TM flag is set.  It checks if we need to reload
diff --git a/arch/powerpc/kernel/ptrace.c b/arch/powerpc/kernel/ptrace.c
index 2e3d2bf..cb4d5bf 100644
--- a/arch/powerpc/kernel/ptrace.c
+++ b/arch/powerpc/kernel/ptrace.c
@@ -357,6 +357,17 @@ static int gpr_set(struct task_struct *target, const 
struct user_regset *regset,
        return ret;
 }
 
+/*
+ * When any transaction is active, thread_struct->transact_fp holds
+ * the current running value of all FPR registers and thread_struct->
+ * fp_state hold the last checkpointed FPR state for the given
+ * transaction.
+ *
+ * struct data {
+ *     u64     fpr[32];
+ *     u64     fpscr;  
+ * };
+ */
 static int fpr_get(struct task_struct *target, const struct user_regset 
*regset,
                   unsigned int pos, unsigned int count,
                   void *kbuf, void __user *ubuf)
@@ -365,21 +376,41 @@ static int fpr_get(struct task_struct *target, const 
struct user_regset *regset,
        u64 buf[33];
        int i;
 #endif
-       flush_fp_to_thread(target);
+       if (MSR_TM_ACTIVE(target->thread.regs->msr)) {
+               flush_fp_to_thread(target);
+               flush_altivec_to_thread(target);
+               flush_tmreg_to_thread(target);
+       } else {
+               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);
-       buf[32] = target->thread.fp_state.fpscr;
+       if (MSR_TM_ACTIVE(target->thread.regs->msr)) {
+               for (i = 0; i < 32 ; i++)
+                       buf[i] = target->thread.TS_TRANS_FPR(i);
+               buf[32] = target->thread.transact_fp.fpscr;
+       } else {
+               for (i = 0; i < 32 ; i++)
+                       buf[i] = target->thread.TS_FPR(i);
+               buf[32] = target->thread.fp_state.fpscr;
+       }
        return user_regset_copyout(&pos, &count, &kbuf, &ubuf, buf, 0, -1);
 
 #else
-       BUILD_BUG_ON(offsetof(struct thread_fp_state, fpscr) !=
-                    offsetof(struct thread_fp_state, fpr[32][0]));
+       if (MSR_TM_ACTIVE(tsk->thread.regs->msr)) {
+               BUILD_BUG_ON(offsetof(struct transact_fp, fpscr) !=
+                               offsetof(struct transact_fp, fpr[32][0]));
 
-       return user_regset_copyout(&pos, &count, &kbuf, &ubuf,
+               return user_regset_copyout(&pos, &count, &kbuf, &ubuf,
+                                  &target->thread.transact_fp, 0, -1);
+       } esle {
+               BUILD_BUG_ON(offsetof(struct thread_fp_state, fpscr) !=
+                            offsetof(struct thread_fp_state, fpr[32][0]));
+
+               return user_regset_copyout(&pos, &count, &kbuf, &ubuf,
                                   &target->thread.fp_state, 0, -1);
+       }
 #endif
 }
 
@@ -391,23 +422,44 @@ static int fpr_set(struct task_struct *target, const 
struct user_regset *regset,
        u64 buf[33];
        int i;
 #endif
-       flush_fp_to_thread(target);
+       if (MSR_TM_ACTIVE(target->thread.regs->msr)) {
+               flush_fp_to_thread(target);
+               flush_altivec_to_thread(target);
+               flush_tmreg_to_thread(target);
+       } else {
+               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];
-       target->thread.fp_state.fpscr = buf[32];
+       for (i = 0; i < 32 ; i++) {
+               if (MSR_TM_ACTIVE(target->thread.regs->msr))
+                       target->thread.TS_TRANS_FPR(i) = buf[i];
+               else
+                       target->thread.TS_FPR(i) = buf[i];
+       }
+       if (MSR_TM_ACTIVE(target->thread.regs->msr))
+               target->thread.transact_fp.fpscr = buf[32];
+       else
+               target->thread.fp_state.fpscr = buf[32];
        return 0;
 #else
-       BUILD_BUG_ON(offsetof(struct thread_fp_state, fpscr) !=
-                    offsetof(struct thread_fp_state, fpr[32][0]));
+       if (MSR_TM_ACTIVE(target->thread.regs->msr)) {
+               BUILD_BUG_ON(offsetof(struct transact_fp, fpscr) !=
+                            offsetof(struct transact_fp, fpr[32][0]));
 
-       return user_regset_copyin(&pos, &count, &kbuf, &ubuf,
-                                 &target->thread.fp_state, 0, -1);
+               return user_regset_copyin(&pos, &count, &kbuf, &ubuf,
+                                         &target->thread.transact_fp, 0, -1);
+       } else {
+               BUILD_BUG_ON(offsetof(struct thread_fp_state, fpscr) !=
+                            offsetof(struct thread_fp_state, fpr[32][0]));
+
+               return user_regset_copyin(&pos, &count, &kbuf, &ubuf,
+                               &target->thread.fp_state, 0, -1);
+       }
 #endif
 }
 
@@ -432,20 +484,44 @@ static int vr_active(struct task_struct *target,
        return target->thread.used_vr ? regset->n : 0;
 }
 
+/*
+ * When any transaction is active, thread_struct->transact_vr holds
+ * the current running value of all VMX registers and thread_struct->
+ * vr_state hold the last checkpointed VMX state for the given
+ * transaction.
+ *
+ * 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)
 {
        int ret;
+       struct thread_vr_state *addr;
 
-       flush_altivec_to_thread(target);
+       if (MSR_TM_ACTIVE(target->thread.regs->msr)) {
+               flush_fp_to_thread(target);
+               flush_altivec_to_thread(target);
+               flush_tmreg_to_thread(target);
+       } else {
+               flush_altivec_to_thread(target);
+       }
 
        BUILD_BUG_ON(offsetof(struct thread_vr_state, vscr) !=
                     offsetof(struct thread_vr_state, vr[32]));
 
+       if (MSR_TM_ACTIVE(target->thread.regs->msr))
+               addr = &target->thread.transact_vr;
+       else
+               addr = &target->thread.vr_state;
+
        ret = user_regset_copyout(&pos, &count, &kbuf, &ubuf,
-                                 &target->thread.vr_state, 0,
-                                 33 * sizeof(vector128));
+                               addr, 0, 33 * sizeof(vector128));
+
        if (!ret) {
                /*
                 * Copy out only the low-order word of vrsave.
@@ -455,11 +531,14 @@ static int vr_get(struct task_struct *target, const 
struct user_regset *regset,
                        u32 word;
                } vrsave;
                memset(&vrsave, 0, sizeof(vrsave));
-               vrsave.word = target->thread.vrsave;
+               if (MSR_TM_ACTIVE(target->thread.regs->msr))
+                       vrsave.word = target->thread.transact_vrsave;
+               else
+                       vrsave.word = target->thread.vrsave;
+
                ret = user_regset_copyout(&pos, &count, &kbuf, &ubuf, &vrsave,
                                          33 * sizeof(vector128), -1);
        }
-
        return ret;
 }
 
@@ -467,16 +546,27 @@ 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);
+       if (MSR_TM_ACTIVE(target->thread.regs->msr)) {
+               flush_fp_to_thread(target);
+               flush_altivec_to_thread(target);
+               flush_tmreg_to_thread(target);
+       } else {
+               flush_altivec_to_thread(target);
+       }
 
        BUILD_BUG_ON(offsetof(struct thread_vr_state, vscr) !=
                     offsetof(struct thread_vr_state, vr[32]));
 
+       if (MSR_TM_ACTIVE(target->thread.regs->msr))
+               addr = &target->thread.transact_vr;
+       else
+               addr = &target->thread.vr_state;
        ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf,
-                                &target->thread.vr_state, 0,
-                                33 * sizeof(vector128));
+                       addr, 0, 33 * sizeof(vector128));
+
        if (!ret && count > 0) {
                /*
                 * We use only the first word of vrsave.
@@ -486,13 +576,21 @@ static int vr_set(struct task_struct *target, const 
struct user_regset *regset,
                        u32 word;
                } vrsave;
                memset(&vrsave, 0, sizeof(vrsave));
-               vrsave.word = target->thread.vrsave;
+
+               if (MSR_TM_ACTIVE(target->thread.regs->msr))
+                       vrsave.word = target->thread.transact_vrsave;
+               else
+                       vrsave.word = target->thread.vrsave;
+
                ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf, &vrsave,
                                         33 * sizeof(vector128), -1);
-               if (!ret)
-                       target->thread.vrsave = vrsave.word;
+               if (!ret) {
+                       if (MSR_TM_ACTIVE(target->thread.regs->msr))
+                               target->thread.transact_vrsave = vrsave.word;
+                       else
+                               target->thread.vrsave = vrsave.word;
+               }
        }
-
        return ret;
 }
 #endif /* CONFIG_ALTIVEC */
@@ -613,6 +711,417 @@ static int evr_set(struct task_struct *target, const 
struct user_regset *regset,
 }
 #endif /* CONFIG_SPE */
 
+#ifdef CONFIG_PPC_TRANSACTIONAL_MEM
+
+/*
+ *  Transactional SPR
+ *
+ * struct {
+ *     u64             tm_tfhar;
+ *     u64             tm_texasr;
+ *     u64             tm_tfiar;
+ *     unsigned long   tm_orig_msr;
+ *     unsigned long   tm_tar;
+ *     unsigned long   tm_ppr;
+ *     unsigned long   tm_dscr;
+ * };
+ */
+static int tm_spr_get(struct task_struct *target, const struct user_regset 
*regset,
+                  unsigned int pos, unsigned int count,
+                  void *kbuf, void __user *ubuf)
+{
+       int ret;
+
+       flush_fp_to_thread(target);
+       flush_altivec_to_thread(target);
+       flush_tmreg_to_thread(target);
+
+       /* TFHAR register */
+       ret = user_regset_copyout(&pos, &count, &kbuf, &ubuf,
+                       &target->thread.tm_tfhar, 0, sizeof(u64));
+
+       BUILD_BUG_ON(offsetof(struct thread_struct, tm_tfhar) +
+                       sizeof(u64) != offsetof(struct thread_struct, 
tm_texasr));
+
+       /* TEXASR register */
+       if (!ret)
+               ret = user_regset_copyout(&pos, &count, &kbuf, &ubuf,
+                       &target->thread.tm_texasr, sizeof(u64), 2 * 
sizeof(u64));
+
+       BUILD_BUG_ON(offsetof(struct thread_struct, tm_texasr) +
+                       sizeof(u64) != offsetof(struct thread_struct, 
tm_tfiar));
+
+       /* TFIAR register */
+       if (!ret)
+               ret = user_regset_copyout(&pos, &count, &kbuf, &ubuf,
+                       &target->thread.tm_tfiar, 2 * sizeof(u64), 3 * 
sizeof(u64));
+
+       BUILD_BUG_ON(offsetof(struct thread_struct, tm_tfiar) +
+                       sizeof(u64) != offsetof(struct thread_struct, 
tm_orig_msr));
+
+       /* TM checkpointed original MSR */
+       if (!ret)
+               ret = user_regset_copyout(&pos, &count, &kbuf, &ubuf,
+                       &target->thread.tm_orig_msr, 3 * sizeof(u64),
+                               3 * sizeof(u64) + sizeof(unsigned long));
+
+       BUILD_BUG_ON(offsetof(struct thread_struct, tm_orig_msr) +
+                       sizeof(unsigned long) + sizeof(struct pt_regs)
+                               != offsetof(struct thread_struct, tm_tar));
+
+       /* TM checkpointed TAR register */
+       if (!ret)
+               ret = user_regset_copyout(&pos, &count, &kbuf, &ubuf,
+                       &target->thread.tm_tar, 3 * sizeof(u64) +
+                               sizeof(unsigned long) , 3 * sizeof(u64) +
+                                       2 * sizeof(unsigned long));
+
+       BUILD_BUG_ON(offsetof(struct thread_struct, tm_tar)
+                       + sizeof(unsigned long) !=
+                               offsetof(struct thread_struct, tm_ppr));
+
+       /* TM checkpointed PPR register */
+       if (!ret)
+               ret = user_regset_copyout(&pos, &count, &kbuf, &ubuf, 
+                               &target->thread.tm_ppr, 3 * sizeof(u64) +
+                                       2 * sizeof(unsigned long), 3 * 
sizeof(u64) +
+                                               3 * sizeof(unsigned long));
+
+       BUILD_BUG_ON(offsetof(struct thread_struct, tm_ppr) +
+                       sizeof(unsigned long) !=
+                               offsetof(struct thread_struct, tm_dscr));
+
+       /* TM checkpointed DSCR register */
+       if (!ret)
+               ret = user_regset_copyout(&pos, &count, &kbuf, &ubuf,
+                       &target->thread.tm_dscr, 3 * sizeof(u64)
+                               + 3 * sizeof(unsigned long), 3 * sizeof(u64)
+                                               + 4 * sizeof(unsigned long));
+       return ret;
+}
+
+static int tm_spr_set(struct task_struct *target, const struct user_regset 
*regset,
+                  unsigned int pos, unsigned int count,
+                  const void *kbuf, const void __user *ubuf)
+{
+       int ret;
+
+       flush_fp_to_thread(target);
+       flush_altivec_to_thread(target);
+       flush_tmreg_to_thread(target);
+
+       /* TFHAR register */
+       ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf,
+                               &target->thread.tm_tfhar, 0, sizeof(u64));
+
+       BUILD_BUG_ON(offsetof(struct thread_struct, tm_tfhar)
+               + sizeof(u64) != offsetof(struct thread_struct, tm_texasr));
+
+       /* TEXASR register */
+       if (!ret)
+               ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf,
+                       &target->thread.tm_texasr, sizeof(u64), 2 * 
sizeof(u64));
+
+       BUILD_BUG_ON(offsetof(struct thread_struct, tm_texasr)
+               + sizeof(u64) != offsetof(struct thread_struct, tm_tfiar));
+
+       /* TFIAR register */
+       if (!ret)
+               ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf,
+                       &target->thread.tm_tfiar, 2 * sizeof(u64), 3 * 
sizeof(u64));
+
+       BUILD_BUG_ON(offsetof(struct thread_struct, tm_tfiar)
+               + sizeof(u64) != offsetof(struct thread_struct, tm_orig_msr));
+
+       /* TM checkpointed orig MSR */
+       if (!ret)
+               ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf,
+                       &target->thread.tm_orig_msr, 3 * sizeof(u64),
+                               3 * sizeof(u64) + sizeof(unsigned long));
+       
+       BUILD_BUG_ON(offsetof(struct thread_struct, tm_orig_msr)
+               + sizeof(unsigned long) + sizeof(struct pt_regs) !=
+                       offsetof(struct thread_struct, tm_tar));
+
+       /* TM checkpointed TAR register */
+       if (!ret)
+               ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf,
+                       &target->thread.tm_tar, 3 * sizeof(u64) +
+                               sizeof(unsigned long), 3 * sizeof(u64) +
+                                       2 * sizeof(unsigned long));
+
+       BUILD_BUG_ON(offsetof(struct thread_struct, tm_tar)
+                       + sizeof(unsigned long) != offsetof(struct 
thread_struct, tm_ppr));
+
+       /* TM checkpointed PPR register */
+       if (!ret)
+               ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf,
+                               &target->thread.tm_ppr, 3 * sizeof(u64)
+                                       + 2 * sizeof(unsigned long), 3 * 
sizeof(u64)
+                                       + 3 * sizeof(unsigned long));
+
+       BUILD_BUG_ON(offsetof(struct thread_struct, tm_ppr) +
+                       sizeof(unsigned long) !=
+                               offsetof(struct thread_struct, tm_dscr));
+
+       /* TM checkpointed DSCR register */
+       if (!ret)
+               ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf,
+                               &target->thread.tm_dscr,
+                                       3 * sizeof(u64) + 3 * sizeof(unsigned 
long),
+                                       3 * sizeof(u64) + 4 * sizeof(unsigned 
long));
+
+       return ret;
+}
+
+/*
+ * Checkpointed GPR
+ *
+ * struct data {
+ *     struct pt_regs ckpt_regs;
+ * };
+ */
+static int tm_cgpr_get(struct task_struct *target, const struct user_regset 
*regset,
+                  unsigned int pos, unsigned int count,
+                  void *kbuf, void __user *ubuf)
+{
+       int ret;
+
+       flush_fp_to_thread(target);
+       flush_altivec_to_thread(target);
+       flush_tmreg_to_thread(target);
+       ret = user_regset_copyout(&pos, &count, &kbuf, &ubuf,
+                       &target->thread.ckpt_regs, 0,
+                               sizeof(struct pt_regs));
+       return ret;
+}
+
+static int tm_cgpr_set(struct task_struct *target, const struct user_regset 
*regset,
+                  unsigned int pos, unsigned int count,
+                  const void *kbuf, const void __user *ubuf)
+{
+       int ret;
+
+       flush_fp_to_thread(target);
+       flush_altivec_to_thread(target);
+       flush_tmreg_to_thread(target);
+       ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf,
+                                       &target->thread.ckpt_regs, 0,
+                                               sizeof(struct pt_regs));
+       return ret;
+}
+
+/*
+ * Checkpointed FPR
+ *
+ * struct data {
+ *     u64     fpr[32];
+ *     u64     fpscr;
+ * };
+ */
+static int tm_cfpr_get(struct task_struct *target, const struct user_regset 
*regset,
+                  unsigned int pos, unsigned int count,
+                  void *kbuf, void __user *ubuf)
+{
+#ifdef CONFIG_VSX
+       u64 buf[33];
+       int i;
+#endif
+       flush_fp_to_thread(target);
+       flush_altivec_to_thread(target);
+       flush_tmreg_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);
+       buf[32] = target->thread.fp_state.fpscr;
+       return user_regset_copyout(&pos, &count, &kbuf, &ubuf, buf, 0, -1);
+
+#else
+       BUILD_BUG_ON(offsetof(struct thread_fp_state, fpscr) !=
+               offsetof(struct thread_fp_state, fpr[32][0]));
+
+       return user_regset_copyout(&pos, &count, &kbuf, &ubuf,
+                       &target->thread.thread_fp_state, 0, -1);
+#endif
+}
+
+static int tm_cfpr_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
+       u64 buf[33];
+       int i;
+#endif
+       flush_fp_to_thread(target);
+       flush_altivec_to_thread(target);
+       flush_tmreg_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];
+       target->thread.fp_state.fpscr = buf[32];
+        return 0;
+#else
+       BUILD_BUG_ON(offsetof(struct thread_fp_state, fpscr) !=
+                     offsetof(struct thread_fp_state, fpr[32][0]));
+
+       return user_regset_copyin(&pos, &count, &kbuf, &ubuf,
+                               &target->thread.fp_state, 0, -1);
+#endif
+}
+
+/*
+ * Checkpointed VMX
+ *
+ * struct data {
+ *     vector128       vr[32];
+ *     vector128       vscr;
+ *     vector128       vrsave; 
+ *};
+ */
+static int tm_cvmx_get(struct task_struct *target, const struct user_regset 
*regset,
+                  unsigned int pos, unsigned int count,
+                  void *kbuf, void __user *ubuf)
+{
+       int ret;
+
+       flush_fp_to_thread(target);
+       flush_altivec_to_thread(target);
+       flush_tmreg_to_thread(target);
+
+       BUILD_BUG_ON(offsetof(struct thread_vr_state, vscr) !=
+                    offsetof(struct thread_vr_state, vr[32]));
+
+       ret = user_regset_copyout(&pos, &count, &kbuf, &ubuf,
+                                 &target->thread.vr_state, 0,
+                                 33 * sizeof(vector128));
+       if (!ret) {
+               /*
+                * Copy out only the low-order word of vrsave.
+                */
+               union {
+                       elf_vrreg_t reg;
+                       u32 word;
+               } vrsave;
+               memset(&vrsave, 0, sizeof(vrsave));
+               vrsave.word = target->thread.vrsave;
+               ret = user_regset_copyout(&pos, &count, &kbuf, &ubuf, &vrsave,
+                                         33 * sizeof(vector128), -1);
+       }
+       return ret;
+}
+
+static int tm_cvmx_set(struct task_struct *target, const struct user_regset 
*regset,
+                  unsigned int pos, unsigned int count,
+                  const void *kbuf, const void __user *ubuf)
+{
+       int ret;
+
+       flush_fp_to_thread(target);
+       flush_altivec_to_thread(target);
+       flush_tmreg_to_thread(target);
+
+       BUILD_BUG_ON(offsetof(struct thread_vr_state, vscr) !=
+               offsetof(struct thread_vr_state, vr[32]));
+
+       ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf,
+                                &target->thread.vr_state, 0,
+                                33 * sizeof(vector128));
+       if (!ret && count > 0) {
+               /*
+                * We use only the first word of vrsave.
+                */
+               union {
+                       elf_vrreg_t reg;
+                       u32 word;
+               } vrsave;
+               memset(&vrsave, 0, sizeof(vrsave));
+               vrsave.word = target->thread.vrsave;
+               ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf, &vrsave,
+                                        33 * sizeof(vector128), -1);
+               if (!ret)
+                       target->thread.vrsave = vrsave.word;
+       }
+       return ret;
+}
+#endif /* CONFIG_PPC_TRANSACTIONAL_MEM */
+
+/*
+ * Miscellaneous Registers
+ *
+ * struct {
+ *     unsigned long dscr;
+ *     unsigned long ppr;
+ *     unsigned long tar;
+ * };
+ */
+static int misc_get(struct task_struct *target, const struct user_regset 
*regset,
+                  unsigned int pos, unsigned int count,
+                  void *kbuf, void __user *ubuf)
+{
+       int ret;
+
+       /* DSCR register */
+       ret = user_regset_copyout(&pos, &count, &kbuf, &ubuf,
+                                       &target->thread.dscr, 0,
+                                       sizeof(unsigned long));
+
+       BUILD_BUG_ON(offsetof(struct thread_struct, dscr) + sizeof(unsigned 
long) +
+                               sizeof(unsigned long) != offsetof(struct 
thread_struct, ppr));
+
+       /* PPR register */
+       if (!ret)
+               ret = user_regset_copyout(&pos, &count, &kbuf, &ubuf,
+                                         &target->thread.ppr, sizeof(unsigned 
long),
+                                         2 * sizeof(unsigned long));
+
+       BUILD_BUG_ON(offsetof(struct thread_struct, ppr) + sizeof(unsigned long)
+                                       != offsetof(struct thread_struct, tar));
+       /* TAR register */
+       if (!ret)
+               ret = user_regset_copyout(&pos, &count, &kbuf, &ubuf,
+                                         &target->thread.tar, 2 * 
sizeof(unsigned long),
+                                         3 * sizeof(unsigned long));
+       return ret;
+}
+
+static int misc_set(struct task_struct *target, const struct user_regset 
*regset,
+                  unsigned int pos, unsigned int count,
+                  const void *kbuf, const void __user *ubuf)
+{
+       int ret;
+
+       /* DSCR register */
+       ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf,
+                                       &target->thread.dscr, 0,
+                                       sizeof(unsigned long));
+
+       BUILD_BUG_ON(offsetof(struct thread_struct, dscr) + sizeof(unsigned 
long) +
+                       sizeof(unsigned long) != offsetof(struct thread_struct, 
ppr));
+
+       /* PPR register */
+       if (!ret)
+               ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf,
+                                               &target->thread.ppr, 
sizeof(unsigned long),
+                                               2 * sizeof(unsigned long));
+
+       BUILD_BUG_ON(offsetof(struct thread_struct, ppr) + sizeof(unsigned long)
+                                               != offsetof(struct 
thread_struct, tar));
+
+       /* TAR register */
+       if (!ret)
+               ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf,
+                                               &target->thread.tar, 2 * 
sizeof(unsigned long),
+                                               3 * sizeof(unsigned long));
+       return ret;
+}
 
 /*
  * These are our native regset flavors.
@@ -629,6 +1138,13 @@ enum powerpc_regset {
 #ifdef CONFIG_SPE
        REGSET_SPE,
 #endif
+#ifdef CONFIG_PPC_TRANSACTIONAL_MEM
+       REGSET_TM_SPR,          /* TM generic SPR */
+       REGSET_TM_CGPR,         /* TM checkpointed GPR */
+       REGSET_TM_CFPR,         /* TM checkpointed FPR */
+       REGSET_TM_CVMX,         /* TM checkpointed VMX */
+#endif
+       REGSET_MISC             /* Miscellaneous */
 };
 
 static const struct user_regset native_regsets[] = {
@@ -663,6 +1179,33 @@ static const struct user_regset native_regsets[] = {
                .active = evr_active, .get = evr_get, .set = evr_set
        },
 #endif
+#ifdef CONFIG_PPC_TRANSACTIONAL_MEM
+       [REGSET_TM_SPR] = {
+               .core_note_type = NT_PPC_TM_SPR, .n = 7,
+               .size = sizeof(u64), .align = sizeof(u64),
+               .get = tm_spr_get, .set = tm_spr_set
+       },
+       [REGSET_TM_CGPR] = {
+               .core_note_type = NT_PPC_TM_CGPR, .n = 14,
+               .size = sizeof(u64), .align = sizeof(u64),
+               .get = tm_cgpr_get, .set = tm_cgpr_set
+       },
+       [REGSET_TM_CFPR] = {
+               .core_note_type = NT_PPC_TM_CFPR, .n = ELF_NFPREG,
+               .size = sizeof(double), .align = sizeof(double),
+               .get = tm_cfpr_get, .set = tm_cfpr_set
+       },
+       [REGSET_TM_CVMX] = {
+               .core_note_type = NT_PPC_TM_CVMX, .n = 34,
+               .size = sizeof(vector128), .align = sizeof(vector128),
+               .get = tm_cvmx_get, .set = tm_cvmx_set
+       },
+#endif
+       [REGSET_MISC] = {
+               .core_note_type = NT_PPC_MISC, .n = 3,
+               .size = sizeof(u64), .align = sizeof(u64),
+               .get = misc_get, .set = misc_set
+       },
 };
 
 static const struct user_regset_view user_ppc_native_view = {
@@ -831,6 +1374,33 @@ static const struct user_regset compat_regsets[] = {
                .active = evr_active, .get = evr_get, .set = evr_set
        },
 #endif
+#ifdef CONFIG_PPC_TRANSACTIONAL_MEM
+       [REGSET_TM_SPR] = {
+               .core_note_type = NT_PPC_TM_SPR, .n = 7,
+               .size = sizeof(u64), .align = sizeof(u64),
+               .get = tm_spr_get, .set = tm_spr_set
+       },
+       [REGSET_TM_CGPR] = {
+               .core_note_type = NT_PPC_TM_CGPR, .n = 14,
+               .size = sizeof(u64), .align = sizeof(u64),
+               .get = tm_cgpr_get, .set = tm_cgpr_set
+       },
+       [REGSET_TM_CFPR] = {
+               .core_note_type = NT_PPC_TM_CFPR, .n = ELF_NFPREG,
+               .size = sizeof(double), .align = sizeof(double),
+               .get = tm_cfpr_get, .set = tm_cfpr_set
+       },
+       [REGSET_TM_CVMX] = {
+               .core_note_type = NT_PPC_TM_CVMX, .n = 34,
+               .size = sizeof(vector128), .align = sizeof(vector128),
+               .get = tm_cvmx_get, .set = tm_cvmx_set
+       },
+#endif
+       [REGSET_MISC] = {
+               .core_note_type = NT_PPC_MISC, .n = 3,
+               .size = sizeof(u64), .align = sizeof(u64),
+               .get = misc_get, .set = misc_set
+       },
 };
 
 static const struct user_regset_view user_ppc_compat_view = {
@@ -1754,7 +2324,41 @@ long arch_ptrace(struct task_struct *child, long request,
                                             REGSET_SPE, 0, 35 * sizeof(u32),
                                             datavp);
 #endif
+#ifdef CONFIG_PPC_TRANSACTIONAL_MEM
+       case PTRACE_GETTM_SPRREGS:
+               return copy_regset_to_user(child, &user_ppc_native_view,
+                                          REGSET_TM_SPR, 0, 6 * sizeof(u64) + 
sizeof(unsigned long), datavp);
+       case PTRACE_SETTM_SPRREGS:
+               return copy_regset_from_user(child, &user_ppc_native_view,
+                                          REGSET_TM_SPR, 0, 6 * sizeof(u64) + 
sizeof(unsigned long), datavp);
+       case PTRACE_GETTM_CGPRREGS:
+               return copy_regset_to_user(child, &user_ppc_native_view,
+                                          REGSET_TM_CGPR, 0, sizeof(struct 
pt_regs), datavp);
+       case PTRACE_SETTM_CGPRREGS:
+               return copy_regset_from_user(child, &user_ppc_native_view,
+                                          REGSET_TM_CGPR, 0, sizeof(struct 
pt_regs), datavp);
+       case PTRACE_GETTM_CFPRREGS:
+               return copy_regset_to_user(child, &user_ppc_native_view,
+                                          REGSET_TM_CFPR, 0, 
sizeof(elf_fpregset_t), datavp);
+       case PTRACE_SETTM_CFPRREGS:
+               return copy_regset_from_user(child, &user_ppc_native_view,
+                                          REGSET_TM_CFPR, 0, 
sizeof(elf_fpregset_t), datavp);
+       case PTRACE_GETTM_CVMXREGS:
+               return copy_regset_to_user(child, &user_ppc_native_view,
+                                          REGSET_TM_CVMX, 0, (33 * 
sizeof(vector128) + sizeof(u32)), datavp);
+       case PTRACE_SETTM_CVMXREGS:
+               return copy_regset_from_user(child, &user_ppc_native_view,
+                                          REGSET_TM_CVMX, 0, (33 * 
sizeof(vector128) + sizeof(u32)), datavp);
+#endif /* CONFIG_PPC_TRANSACTIONAL_MEM */
 
+       case PTRACE_GETMSCREGS:
+               return copy_regset_to_user(child, &user_ppc_native_view,
+                                          REGSET_MISC, 0, 3 * sizeof(u64),
+                                          datavp);
+       case PTRACE_SETMSCREGS:
+               return copy_regset_from_user(child, &user_ppc_native_view,
+                                          REGSET_MISC, 0, 3 * sizeof(u64),
+                                          datavp);
        default:
                ret = ptrace_request(child, request, addr, data);
                break;
diff --git a/include/uapi/linux/elf.h b/include/uapi/linux/elf.h
index ef6103b..13090e3 100644
--- a/include/uapi/linux/elf.h
+++ b/include/uapi/linux/elf.h
@@ -379,6 +379,11 @@ typedef struct elf64_shdr {
 #define NT_PPC_VMX     0x100           /* PowerPC Altivec/VMX registers */
 #define NT_PPC_SPE     0x101           /* PowerPC SPE/EVR registers */
 #define NT_PPC_VSX     0x102           /* PowerPC VSX registers */
+#define NT_PPC_TM_SPR  0x103           /* PowerPC transactional memory 
specific registers */
+#define NT_PPC_TM_CGPR 0x104           /* PowerpC transactional memory 
checkpointed GPR */
+#define NT_PPC_TM_CFPR 0x105           /* PowerPC transactional memory 
checkpointed FPR */
+#define NT_PPC_TM_CVMX 0x106           /* PowerPC transactional memory 
checkpointed VMX */
+#define NT_PPC_MISC    0x107           /* PowerPC miscellaneous registers */
 #define NT_386_TLS     0x200           /* i386 TLS slots (struct user_desc) */
 #define NT_386_IOPERM  0x201           /* x86 io permission bitmap (1=deny) */
 #define NT_X86_XSTATE  0x202           /* x86 extended state using xsave */
-- 
1.7.11.7

_______________________________________________
Linuxppc-dev mailing list
Linuxppc-dev@lists.ozlabs.org
https://lists.ozlabs.org/listinfo/linuxppc-dev

Reply via email to