Re: [PATCH V4 6/8] powerpc, ptrace: Enable support for transactional memory register sets

From: Sukadev Bhattiprolu
Date: Tue Nov 18 2014 - 16:19:09 EST


Anshuman Khandual [khandual@xxxxxxxxxxxxxxxxxx] 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 <khandual@xxxxxxxxxxxxxxxxxx>
| ---
| 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

--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at http://vger.kernel.org/majordomo-info.html
Please read the FAQ at http://www.tux.org/lkml/