Anshuman Khandual [khand...@linux.vnet.ibm.com] wrote:
| This patch enables get and set of transactional memory related register
| sets through PTRACE_GETREGSET-PTRACE_SETREGSET interface by implementing
| four new powerpc specific register sets i.e REGSET_TM_SPR, REGSET_TM_CGPR,
| REGSET_TM_CFPR, REGSET_CVMX support corresponding to these following new
| ELF core note types added previously in this regard.
| 
|       (1) NT_PPC_TM_SPR
|       (2) NT_PPC_TM_CGPR
|       (3) NT_PPC_TM_CFPR
|       (4) NT_PPC_TM_CVMX
| 
| Signed-off-by: Anshuman Khandual <khand...@linux.vnet.ibm.com>
| ---
|  arch/powerpc/include/uapi/asm/elf.h |   2 +
|  arch/powerpc/kernel/ptrace.c        | 666 
+++++++++++++++++++++++++++++++++++-
|  2 files changed, 653 insertions(+), 15 deletions(-)
| 
| diff --git a/arch/powerpc/include/uapi/asm/elf.h 
b/arch/powerpc/include/uapi/asm/elf.h
| index 59dad11..fdc8e2f 100644
| --- a/arch/powerpc/include/uapi/asm/elf.h
| +++ b/arch/powerpc/include/uapi/asm/elf.h
| @@ -91,6 +91,8 @@
| 
|  #define ELF_NGREG    48      /* includes nip, msr, lr, etc. */
|  #define ELF_NFPREG   33      /* includes fpscr */
| +#define ELF_NVMX     34      /* includes all vector registers */
| +#define ELF_NTMSPRREG        7       /* includes TM sprs, org_msr, dscr, 
tar, ppr */
| 
|  typedef unsigned long elf_greg_t64;
|  typedef elf_greg_t64 elf_gregset_t64[ELF_NGREG];
| diff --git a/arch/powerpc/kernel/ptrace.c b/arch/powerpc/kernel/ptrace.c
| index 2bbbd10..b279947 100644
| --- a/arch/powerpc/kernel/ptrace.c
| +++ b/arch/powerpc/kernel/ptrace.c
| @@ -63,6 +63,11 @@ struct pt_regs_offset {
|       {.name = STR(gpr##num), .offset = offsetof(struct pt_regs, gpr[num])}
|  #define REG_OFFSET_END {.name = NULL, .offset = 0}
| 
| +/* Some common structure offsets */
| +#define TSO(f)       (offsetof(struct thread_struct, f))
| +#define TVSO(f)      (offsetof(struct thread_vr_state, f))
| +#define TFSO(f)      (offsetof(struct thread_fp_state, f))
| +
|  static const struct pt_regs_offset regoffset_table[] = {
|       GPR_OFFSET_NAME(0),
|       GPR_OFFSET_NAME(1),
| @@ -792,6 +797,534 @@ static int evr_set(struct task_struct *target, const 
struct user_regset *regset,
|  }
|  #endif /* CONFIG_SPE */
| 
| +#ifdef CONFIG_PPC_TRANSACTIONAL_MEM
| +/*
| + * tm_spr_active
| + *
| + * This function checks number of available regisers in
| + * the transactional memory SPR category.
| + */
| +static int tm_spr_active(struct task_struct *target,
| +                      const struct user_regset *regset)
| +{
| +     if (!cpu_has_feature(CPU_FTR_TM))
| +             return -ENODEV;
| +
| +     if (!MSR_TM_ACTIVE(target->thread.regs->msr))
| +             return 0;
| +
| +     return regset->n;
| +}
| +
| +/*
| + * tm_spr_get
| + *
| + * This function gets transactional memory related SPR registers
| + *
| + * Userspace interface buffer layout:
| + *
| + * 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;
| +
| +     /* Build tests */
| +     BUILD_BUG_ON(TSO(tm_tfhar) + sizeof(u64) != TSO(tm_texasr));
| +     BUILD_BUG_ON(TSO(tm_texasr) + sizeof(u64) != TSO(tm_tfiar));
| +     BUILD_BUG_ON(TSO(tm_tfiar) + sizeof(u64) != TSO(tm_orig_msr));
| +     BUILD_BUG_ON(TSO(tm_orig_msr) + sizeof(unsigned long) +
Can we replace TSO(tm_orig_msr) + sizeof(unsigned long) with
TSO(ckpt_regs) ?
| +                             sizeof(struct pt_regs) != TSO(tm_tar));
| +     BUILD_BUG_ON(TSO(tm_tar) + sizeof(unsigned long) != TSO(tm_ppr));
| +     BUILD_BUG_ON(TSO(tm_ppr) + sizeof(unsigned long) != TSO(tm_dscr));
| +
| +     if (!cpu_has_feature(CPU_FTR_TM))
| +             return -ENODEV;
| +
| +     if (!MSR_TM_ACTIVE(target->thread.regs->msr))
| +             return -ENODATA;
| +
| +     /* Flush the states */
| +     flush_fp_to_thread(target);
| +     flush_altivec_to_thread(target);
| +     flush_tmregs_to_thread(target);
| +
| +     /* TFHAR register */
| +     ret = user_regset_copyout(&pos, &count, &kbuf, &ubuf,
| +                             &target->thread.tm_tfhar, 0, sizeof(u64));

The last two parameters, (start_pos, end_pos) are easy to understand
here, but...

| +
| +     /* TEXASR register */
| +     if (!ret)
| +             ret = user_regset_copyout(&pos, &count, &kbuf, &ubuf,
| +                             &target->thread.tm_texasr, sizeof(u64),
| +                             2 * sizeof(u64));

... gets harder to understand here and subsequent fields below.

Given that you already do the BUILD_BUG_ON() tests above, how about
using TSO(tm_texasr) and TSO(tfiar) here for start_pos and end_pos ?

Also, how about just returning if the copyout fails ?  If the first
copyout fails, we will still check 'if(!ret)' several times below.

| +
| +     /* TFIAR register */
| +     if (!ret)
| +             ret = user_regset_copyout(&pos, &count, &kbuf, &ubuf,
| +                             &target->thread.tm_tfiar,
| +                             2 * sizeof(u64), 3 * sizeof(u64));
| +
| +     /* 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));
| +
| +     /* 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));
| +
| +     /* 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));
| +
| +     /* 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;
| +}
| +
| +/*
| + * tm_spr_set
| + *
| + * This function sets transactional memory related SPR registers
| + *
| + * Userspace interface buffer layout:
| + *
| + * 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_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;
| +
| +     /* Build tests */
| +     BUILD_BUG_ON(TSO(tm_tfhar) + sizeof(u64) != TSO(tm_texasr));
| +     BUILD_BUG_ON(TSO(tm_texasr) + sizeof(u64) != TSO(tm_tfiar));
| +     BUILD_BUG_ON(TSO(tm_orig_msr) + sizeof(unsigned long)

Can we replace TSO(tm_orig_msr) + sizeof(unsigned long) with
TSO(ckpt_regs) ?

| +                             + sizeof(struct pt_regs) != TSO(tm_tar));
| +     BUILD_BUG_ON(TSO(tm_tar) + sizeof(unsigned long) != TSO(tm_ppr));
| +     BUILD_BUG_ON(TSO(tm_ppr) + sizeof(unsigned long) != TSO(tm_dscr));
| +     BUILD_BUG_ON(TSO(tm_tfiar) + sizeof(u64) != TSO(tm_orig_msr));

How about moving this last line up after the check for TSO(tm_tfiar) ?
| +
| +     if (!cpu_has_feature(CPU_FTR_TM))
| +             return -ENODEV;
| +
| +     if (!MSR_TM_ACTIVE(target->thread.regs->msr))
| +             return -ENODATA;
| +
| +     /* Flush the states */
| +     flush_fp_to_thread(target);
| +     flush_altivec_to_thread(target);
| +     flush_tmregs_to_thread(target);
| +
| +     /* TFHAR register */
| +     ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf,
| +                             &target->thread.tm_tfhar, 0, sizeof(u64));
| +
| +     /* TEXASR register */
| +     if (!ret)
| +             ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf,
| +                             &target->thread.tm_texasr, sizeof(u64),
| +                             2 * sizeof(u64));

Return if copyin() fails ?

| +
| +     /* TFIAR register */
| +     if (!ret)
| +             ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf,
| +                             &target->thread.tm_tfiar,
| +                              2 * sizeof(u64), 3 * sizeof(u64));
| +
| +
| +     /* 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));
| +
| +
| +     /* 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));
| +
| +     /* 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));
| +
| +     /* 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;
| +}
| +
| +/*
| + * tm_cgpr_active
| + *
| + * This function checks the number of available regisers in
| + * transaction checkpointed GPR category.
| + */
| +static int tm_cgpr_active(struct task_struct *target,
| +                       const struct user_regset *regset)
| +{
| +     if (!cpu_has_feature(CPU_FTR_TM))
| +             return -ENODEV;
| +
| +     if (!MSR_TM_ACTIVE(target->thread.regs->msr))
| +             return 0;
| +
| +     return regset->n;
| +}
| +
| +/*
| + * tm_cgpr_get
| + *
| + * This function gets transaction checkpointed GPR registers
| + *
| + * When the transaction is active, 'ckpt_regs' holds all the checkpointed
| + * GPR register values for the current transaction to fall back on if it
| + * aborts in between. This function gets those checkpointed GPR registers.
| + *
| + * Userspace interface buffer layout:
| + *
| + * 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;
| +
| +     if (!cpu_has_feature(CPU_FTR_TM))
| +             return -ENODEV;
| +
| +     if (!MSR_TM_ACTIVE(target->thread.regs->msr))
| +             return -ENODATA;
| +
| +     flush_fp_to_thread(target);
| +     flush_altivec_to_thread(target);
| +     flush_tmregs_to_thread(target);
| +     ret = user_regset_copyout(&pos, &count, &kbuf, &ubuf,
| +                                     &target->thread.ckpt_regs, 0,
| +                                     sizeof(struct pt_regs));
| +     return ret;
| +}
| +
| +/*
| + * tm_cgpr_set
| + *
| + * This function sets in transaction checkpointed GPR registers
| + *
| + * When the transaction is active, 'ckpt_regs' holds the checkpointed
| + * GPR register values for the current transaction to fall back on if it
| + * aborts in between. This function sets those checkpointed GPR registers.
| + *
| + * Userspace intaerface buffer:
| + *
| + * struct data {
| + *   struct pt_regs ckpt_regs;
| + * };
| + */
| +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;
| +
| +     if (!cpu_has_feature(CPU_FTR_TM))
| +             return -ENODEV;
| +
| +     if (!MSR_TM_ACTIVE(target->thread.regs->msr))
| +             return -ENODATA;
| +
| +     flush_fp_to_thread(target);
| +     flush_altivec_to_thread(target);
| +     flush_tmregs_to_thread(target);
| +     ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf,
| +                                     &target->thread.ckpt_regs, 0,
| +                                     sizeof(struct pt_regs));
| +     return ret;
| +}
| +
| +/*
| + * tm_cfpr_active
| + *
| + * This function checks number of available regisers in
| + * transaction checkpointed FPR category.
| + */
| +static int tm_cfpr_active(struct task_struct *target,
| +                             const struct user_regset *regset)
| +{
| +     if (!cpu_has_feature(CPU_FTR_TM))
| +             return -ENODEV;
| +
| +     if (!MSR_TM_ACTIVE(target->thread.regs->msr))
| +             return 0;
| +
| +     return regset->n;
| +}
| +
| +/*
| + * tm_cfpr_get
| + *
| + * This function gets in transaction checkpointed FPR registers
| + *
| + * When the transaction is active 'fp_state' holds the checkpointed
| + * values for the current transaction to fall back on if it aborts
| + * in between. This function gets those checkpointed FPR registers.
| + *
| + * Userspace interface buffer layout:
| + *
| + * 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)
| +{
| +     u64 buf[33];
| +     int i;
| +
| +     if (!cpu_has_feature(CPU_FTR_TM))
| +             return -ENODEV;
| +
| +     if (!MSR_TM_ACTIVE(target->thread.regs->msr))
| +             return -ENODATA;
| +
| +     flush_fp_to_thread(target);
| +     flush_altivec_to_thread(target);
| +     flush_tmregs_to_thread(target);
| +
| +     /* 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);
| +}
| +
| +/*
| + * tm_cfpr_set
| + *
| + * This function sets in transaction checkpointed FPR registers
| + *
| + * When the transaction is active 'fp_state' holds the checkpointed
| + * FPR register values for the current transaction to fall back on
| + * if it aborts in between. This function sets these checkpointed
| + * FPR registers.
| + *
| + * Userspace interface buffer layout:
| + *
| + * struct data {
| + *   u64     fpr[32];
| + *   u64     fpscr;
| + *};
| + */
| +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)
| +{
| +     u64 buf[33];
| +     int i;
| +
| +     if (!cpu_has_feature(CPU_FTR_TM))
| +             return -ENODEV;
| +
| +     if (!MSR_TM_ACTIVE(target->thread.regs->msr))
| +             return -ENODATA;
| +
| +     flush_fp_to_thread(target);
| +     flush_altivec_to_thread(target);
| +     flush_tmregs_to_thread(target);
| +
| +     /* 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;
| +}
| +
| +/*
| + * tm_cvmx_active
| + *
| + * This function checks the number of available regisers in
| + * checkpointed VMX category.
| + */
| +static int tm_cvmx_active(struct task_struct *target,
| +                             const struct user_regset *regset)
| +{
| +     if (!cpu_has_feature(CPU_FTR_TM))
| +             return -ENODEV;
| +
| +     if (!MSR_TM_ACTIVE(target->thread.regs->msr))
| +             return 0;
| +
| +     return regset->n;
| +}
| +
| +/*
| + * tm_cvmx_get
| + *
| + * This function gets in transaction checkpointed VMX registers
| + *
| + * When the transaction is active 'vr_state' and 'vr_save' hold
| + * the checkpointed values for the current transaction to fall
| + * back on if it aborts in between.
| + *
| + * User interface buffer:
| + *
| + * 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;
| +
| +     BUILD_BUG_ON(TVSO(vscr) != TVSO(vr[32]));
| +
| +     if (!cpu_has_feature(CPU_FTR_TM))
| +             return -ENODEV;
| +
| +     if (!MSR_TM_ACTIVE(target->thread.regs->msr))
| +             return -ENODATA;
| +
| +     /* Flush the state */
| +     flush_fp_to_thread(target);
| +     flush_altivec_to_thread(target);
| +     flush_tmregs_to_thread(target);
| +
| +     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;
| +}
| +
| +/*
| + * tm_cvmx_set
| + *
| + * This function sets in transaction checkpointed VMX registers
| + *
| + * When the transaction is active 'vr_state' and 'vr_save' hold
| + * the checkpointed values for the current transaction to fall
| + * back on if it aborts in between.
| + *
| + * Userspace interface buffer:
| + *
| + * struct data {
| + *   vector128       vr[32];
| + *   vector128       vscr;
| + *   vector128       vrsave;
| + *};
| + */
| +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;
| +
| +     BUILD_BUG_ON(TVSO(vscr) != TVSO(vr[32]));
| +
| +     if (!cpu_has_feature(CPU_FTR_TM))
| +             return -ENODEV;
| +
| +     if (!MSR_TM_ACTIVE(target->thread.regs->msr))
| +             return -ENODATA;
| +
| +     flush_fp_to_thread(target);
| +     flush_altivec_to_thread(target);
| +     flush_tmregs_to_thread(target);
| +
| +     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.

For consistency with the _get() function above, s/first/low-order/ ?
| +              */
| +             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 */
| 
|  /*
|   * These are our native regset flavors.
| @@ -808,6 +1341,12 @@ enum powerpc_regset {
|  #ifdef CONFIG_SPE
|       REGSET_SPE,
|  #endif
| +#ifdef CONFIG_PPC_TRANSACTIONAL_MEM
| +     REGSET_TM_SPR,          /* TM specific SPR registers */
| +     REGSET_TM_CGPR,         /* TM checkpointed GPR registers */
| +     REGSET_TM_CFPR,         /* TM checkpointed FPR registers */
| +     REGSET_TM_CVMX,         /* TM checkpointed VMX registers */
| +#endif
|  };
| 
|  static const struct user_regset native_regsets[] = {
| @@ -842,6 +1381,28 @@ 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 = ELF_NTMSPRREG,
| +             .size = sizeof(u64), .align = sizeof(u64),
| +             .active = tm_spr_active, .get = tm_spr_get, .set = tm_spr_set
| +     },
| +     [REGSET_TM_CGPR] = {
| +             .core_note_type = NT_PPC_TM_CGPR, .n = ELF_NGREG,
| +             .size = sizeof(long), .align = sizeof(long),
| +             .active = tm_cgpr_active, .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),
| +             .active = tm_cfpr_active, .get = tm_cfpr_get, .set = tm_cfpr_set
| +     },
| +     [REGSET_TM_CVMX] = {
| +             .core_note_type = NT_PPC_TM_CVMX, .n = ELF_NVMX,
| +             .size = sizeof(vector128), .align = sizeof(vector128),
| +             .active = tm_cvmx_active, .get = tm_cvmx_get, .set = tm_cvmx_set
| +     },
| +#endif
|  };
| 
|  static const struct user_regset_view user_ppc_native_view = {
| @@ -852,24 +1413,35 @@ static const struct user_regset_view 
user_ppc_native_view = {
|  #ifdef CONFIG_PPC64
|  #include <linux/compat.h>
| 
| -static int gpr32_get(struct task_struct *target,
| +static int common_gpr32_get(struct task_struct *target,
|                    const struct user_regset *regset,
|                    unsigned int pos, unsigned int count,
| -                  void *kbuf, void __user *ubuf)
| +                         void *kbuf, void __user *ubuf, bool in_tm)
|  {
| -     const unsigned long *regs = &target->thread.regs->gpr[0];
| +     const unsigned long *regs;
|       compat_ulong_t *k = kbuf;
|       compat_ulong_t __user *u = ubuf;
|       compat_ulong_t reg;
|       int i;
| 
| -     if (target->thread.regs == NULL)
| -             return -EIO;
| +     if (in_tm) {
| +#ifdef CONFIG_PPC_TRANSACTIONAL_MEM
| +             regs = &target->thread.ckpt_regs.gpr[0];
| +#endif

regs uninitialized if in_tm is true and CONFIG_PPC_TRANSACTIONAL_MEM
is false ? It appears that it cannot/should not happen, how about BUGON() ?
or at least regs = NULL to silence compiler warnings ?


| +     } else {
| +             regs = &target->thread.regs->gpr[0];
| 
| -     if (!FULL_REGS(target->thread.regs)) {
| -             /* We have a partial register set.  Fill 14-31 with bogus 
values */
| -             for (i = 14; i < 32; i++)
| -                     target->thread.regs->gpr[i] = NV_REG_POISON; 
| +             if (target->thread.regs == NULL)
| +                     return -EIO;
| +
| +             if (!FULL_REGS(target->thread.regs)) {
| +                     /*
| +                      * We have a partial register set.
| +                      * Fill 14-31 with bogus values.
| +                      */
| +                     for (i = 14; i < 32; i++)
| +                             target->thread.regs->gpr[i] = NV_REG_POISON;
| +             }
|       }
| 
|       pos /= sizeof(reg);
| @@ -909,20 +1481,28 @@ static int gpr32_get(struct task_struct *target,
|                                       PT_REGS_COUNT * sizeof(reg), -1);
|  }
| 
| -static int gpr32_set(struct task_struct *target,
| +static int common_gpr32_set(struct task_struct *target,
|                    const struct user_regset *regset,
|                    unsigned int pos, unsigned int count,
| -                  const void *kbuf, const void __user *ubuf)
| +                  const void *kbuf, const void __user *ubuf, bool in_tm)
|  {
| -     unsigned long *regs = &target->thread.regs->gpr[0];
| +     unsigned long *regs;
|       const compat_ulong_t *k = kbuf;
|       const compat_ulong_t __user *u = ubuf;
|       compat_ulong_t reg;
| 
| -     if (target->thread.regs == NULL)
| -             return -EIO;
| +     if (in_tm) {
| +#ifdef CONFIG_PPC_TRANSACTIONAL_MEM
| +             regs = &target->thread.ckpt_regs.gpr[0];
| +#endif

ditto

| +     } else {
| +             regs = &target->thread.regs->gpr[0];
| 
| -     CHECK_FULL_REGS(target->thread.regs);
| +             if (target->thread.regs == NULL)
| +                     return -EIO;
| +
| +             CHECK_FULL_REGS(target->thread.regs);
| +     }
| 
|       pos /= sizeof(reg);
|       count /= sizeof(reg);
| @@ -982,6 +1562,39 @@ static int gpr32_set(struct task_struct *target,
|                                        (PT_TRAP + 1) * sizeof(reg), -1);
|  }
| 
| +#ifdef CONFIG_PPC_TRANSACTIONAL_MEM
| +static int tm_cgpr32_get(struct task_struct *target,
| +                  const struct user_regset *regset,
| +                  unsigned int pos, unsigned int count,
| +                  void *kbuf, void __user *ubuf)
| +{
| +     return common_gpr32_get(target, regset, pos, count, kbuf, ubuf, 1);
| +}
| +
| +static int tm_cgpr32_set(struct task_struct *target,
| +                  const struct user_regset *regset,
| +                  unsigned int pos, unsigned int count,
| +                  const void *kbuf, const void __user *ubuf)
| +{
| +     return common_gpr32_set(target, regset, pos, count, kbuf, ubuf, 0);
| +}
| +#endif /* CONFIG_PPC_TRANSACTIONAL_MEM */
| +
| +static int gpr32_get(struct task_struct *target,
| +                  const struct user_regset *regset,
| +                  unsigned int pos, unsigned int count,
| +                  void *kbuf, void __user *ubuf)
| +{
| +     return common_gpr32_get(target, regset, pos, count, kbuf, ubuf, 0);
| +}
| +
| +static int gpr32_set(struct task_struct *target,
| +                  const struct user_regset *regset,
| +                  unsigned int pos, unsigned int count,
| +                  const void *kbuf, const void __user *ubuf)
| +{
| +     return common_gpr32_set(target, regset, pos, count, kbuf, ubuf, 0);
| +}
|  /*
|   * These are the regset flavors matching the CONFIG_PPC32 native set.
|   */
| @@ -1010,6 +1623,29 @@ 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 = ELF_NTMSPRREG,
| +             .size = sizeof(u64), .align = sizeof(u64),
| +             .active = tm_spr_active, .get = tm_spr_get, .set = tm_spr_set
| +     },
| +     [REGSET_TM_CGPR] = {
| +             .core_note_type = NT_PPC_TM_CGPR, .n = ELF_NGREG,
| +             .size = sizeof(long), .align = sizeof(long),
| +             .active = tm_cgpr_active,
| +             .get = tm_cgpr32_get, .set = tm_cgpr32_set
| +     },
| +     [REGSET_TM_CFPR] = {
| +             .core_note_type = NT_PPC_TM_CFPR, .n = ELF_NFPREG,
| +             .size = sizeof(double), .align = sizeof(double),
| +             .active = tm_cfpr_active, .get = tm_cfpr_get, .set = tm_cfpr_set
| +     },
| +     [REGSET_TM_CVMX] = {
| +             .core_note_type = NT_PPC_TM_CVMX, .n = ELF_NVMX,
| +             .size = sizeof(vector128), .align = sizeof(vector128),
| +             .active = tm_cvmx_active, .get = tm_cvmx_get, .set = tm_cvmx_set
| +     },
| +#endif
|  };
| 
|  static const struct user_regset_view user_ppc_compat_view = {
| -- 
| 1.9.3

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

Reply via email to