--- v11
+++ v12
@@ -1,9 +1,9 @@
From: Anshuman Khandual <khandual@linux.vnet.ibm.com>
-This patch enables support for TM checkpointed VSX register
-set ELF core note NT_PPC_CVSX based ptrace requests through
+This patch enables support for TM checkpointed GPR register
+set ELF core note NT_PPC_CGPR based ptrace requests through
PTRACE_GETREGSET, PTRACE_SETREGSET calls. This is achieved
-through adding a register set REGSET_CVSX in powerpc
+through adding a register set REGSET_CGPR in powerpc
corresponding to the ELF core note section added. It
implements the get, set and active functions for this new
register set added.
@@ -31,51 +31,56 @@
Cc: linux-kernel@vger.kernel.org
Cc: linux-kselftest@vger.kernel.org
Signed-off-by: Anshuman Khandual <khandual@linux.vnet.ibm.com>
-Signed-off-by: Simon Guo <wei.guo.simon@gmail.com>
---
- arch/powerpc/include/uapi/asm/elf.h | 1 +
- arch/powerpc/kernel/ptrace.c | 129 ++++++++++++++++++++++++++++++++++++
- 2 files changed, 130 insertions(+)
+ arch/powerpc/kernel/ptrace.c | 222 +++++++++++++++++++++++++++++++++++++++++++
+ 1 file changed, 222 insertions(+)
-diff --git a/arch/powerpc/include/uapi/asm/elf.h b/arch/powerpc/include/uapi/asm/elf.h
-index ecb4e84..1549172 100644
---- a/arch/powerpc/include/uapi/asm/elf.h
-+++ b/arch/powerpc/include/uapi/asm/elf.h
-@@ -92,6 +92,7 @@
- #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_NVSX 32 /* includes all VSX registers */
-
- 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 a2cf240..a824e491 100644
+index 2cdb4e7..d42c79a 100644
--- a/arch/powerpc/kernel/ptrace.c
+++ b/arch/powerpc/kernel/ptrace.c
-@@ -65,6 +65,7 @@ struct pt_regs_offset {
- #define REG_OFFSET_END {.name = NULL, .offset = 0}
-
- #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),
-@@ -1061,6 +1062,123 @@ static int tm_cvmx_set(struct task_struct *target,
-
- return ret;
+@@ -181,6 +181,26 @@ static int set_user_msr(struct task_struct *task, unsigned long msr)
+ return 0;
}
-+
+
++#ifdef CONFIG_PPC_TRANSACTIONAL_MEM
++static unsigned long get_user_ckpt_msr(struct task_struct *task)
++{
++ return task->thread.ckpt_regs.msr | task->thread.fpexc_mode;
++}
++
++static int set_user_ckpt_msr(struct task_struct *task, unsigned long msr)
++{
++ task->thread.ckpt_regs.msr &= ~MSR_DEBUGCHANGE;
++ task->thread.ckpt_regs.msr |= msr & MSR_DEBUGCHANGE;
++ return 0;
++}
++
++static int set_user_ckpt_trap(struct task_struct *task, unsigned long trap)
++{
++ task->thread.ckpt_regs.trap = trap & 0xfff0;
++ return 0;
++}
++#endif
++
+ #ifdef CONFIG_PPC64
+ static int get_user_dscr(struct task_struct *task, unsigned long *data)
+ {
+@@ -847,6 +867,172 @@ static int evr_set(struct task_struct *target, const struct user_regset *regset,
+ }
+ #endif /* CONFIG_SPE */
+
++#ifdef CONFIG_PPC_TRANSACTIONAL_MEM
+/**
-+ * tm_cvsx_active - get active number of registers in CVSX
++ * tm_cgpr_active - get active number of registers in CGPR
+ * @target: The target task.
+ * @regset: The user regset structure.
+ *
+ * This function checks for the active number of available
-+ * regisers in transaction checkpointed VSX category.
++ * regisers in transaction checkpointed GPR category.
+ */
-+static int tm_cvsx_active(struct task_struct *target,
-+ const struct user_regset *regset)
++static int tm_cgpr_active(struct task_struct *target,
++ const struct user_regset *regset)
+{
+ if (!cpu_has_feature(CPU_FTR_TM))
+ return -ENODEV;
@@ -83,12 +88,11 @@
+ if (!MSR_TM_ACTIVE(target->thread.regs->msr))
+ return 0;
+
-+ flush_vsx_to_thread(target);
-+ return target->thread.used_vsr ? regset->n : 0;
++ return regset->n;
+}
+
+/**
-+ * tm_cvsx_get - get CVSX registers
++ * tm_cgpr_get - get CGPR registers
+ * @target: The target task.
+ * @regset: The user regset structure.
+ * @pos: The buffer position.
@@ -96,24 +100,23 @@
+ * @kbuf: Kernel buffer to copy from.
+ * @ubuf: User buffer to copy into.
+ *
-+ * This function gets in transaction checkpointed VSX registers.
-+ *
-+ * When the transaction is active 'ckfp_state' holds the checkpointed
-+ * values for the current transaction to fall back on if it aborts
-+ * in between. This function gets those checkpointed VSX registers.
++ * 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.
+ * The userspace interface buffer layout is as follows.
+ *
+ * struct data {
-+ * u64 vsx[32];
-+ *};
++ * struct pt_regs ckpt_regs;
++ * };
+ */
-+static int tm_cvsx_get(struct task_struct *target,
++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)
+{
-+ u64 buf[32];
-+ int ret, i;
++ int ret;
+
+ if (!cpu_has_feature(CPU_FTR_TM))
+ return -ENODEV;
@@ -121,22 +124,39 @@
+ 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);
-+ flush_vsx_to_thread(target);
-+
-+ for (i = 0; i < 32 ; i++)
-+ buf[i] = target->thread.ckfp_state.fpr[i][TS_VSRLOWOFFSET];
++
+ ret = user_regset_copyout(&pos, &count, &kbuf, &ubuf,
-+ buf, 0, 32 * sizeof(double));
++ &target->thread.ckpt_regs,
++ 0, offsetof(struct pt_regs, msr));
++ if (!ret) {
++ unsigned long msr = get_user_ckpt_msr(target);
++
++ ret = user_regset_copyout(&pos, &count, &kbuf, &ubuf, &msr,
++ offsetof(struct pt_regs, msr),
++ offsetof(struct pt_regs, msr) +
++ sizeof(msr));
++ }
++
++ BUILD_BUG_ON(offsetof(struct pt_regs, orig_gpr3) !=
++ offsetof(struct pt_regs, msr) + sizeof(long));
++
++ if (!ret)
++ ret = user_regset_copyout(&pos, &count, &kbuf, &ubuf,
++ &target->thread.ckpt_regs.orig_gpr3,
++ offsetof(struct pt_regs, orig_gpr3),
++ sizeof(struct pt_regs));
++ if (!ret)
++ ret = user_regset_copyout_zero(&pos, &count, &kbuf, &ubuf,
++ sizeof(struct pt_regs), -1);
+
+ return ret;
+}
+
-+/**
-+ * tm_cvsx_set - set CFPR registers
++/*
++ * tm_cgpr_set - set the CGPR registers
+ * @target: The target task.
+ * @regset: The user regset structure.
+ * @pos: The buffer position.
@@ -144,24 +164,24 @@
+ * @kbuf: Kernel buffer to copy into.
+ * @ubuf: User buffer to copy from.
+ *
-+ * This function sets in transaction checkpointed VSX registers.
-+ *
-+ * When the transaction is active 'fp_state' holds the checkpointed
-+ * VSX register values for the current transaction to fall back on
-+ * if it aborts in between. This function sets these checkpointed
-+ * FPR registers. The userspace interface buffer layout is as follows.
++ * 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.
++ * The userspace interface buffer layout is as follows.
+ *
+ * struct data {
-+ * u64 vsx[32];
-+ *};
++ * struct pt_regs ckpt_regs;
++ * };
+ */
-+static int tm_cvsx_set(struct task_struct *target,
++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)
+{
-+ u64 buf[32];
-+ int ret, i;
++ unsigned long reg;
++ int ret;
+
+ if (!cpu_has_feature(CPU_FTR_TM))
+ return -ENODEV;
@@ -169,53 +189,119 @@
+ 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);
-+ flush_vsx_to_thread(target);
+
+ ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf,
-+ buf, 0, 32 * sizeof(double));
-+ for (i = 0; i < 32 ; i++)
-+ target->thread.ckfp_state.fpr[i][TS_VSRLOWOFFSET] = buf[i];
++ &target->thread.ckpt_regs,
++ 0, PT_MSR * sizeof(reg));
++
++ if (!ret && count > 0) {
++ ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf, ®,
++ PT_MSR * sizeof(reg),
++ (PT_MSR + 1) * sizeof(reg));
++ if (!ret)
++ ret = set_user_ckpt_msr(target, reg);
++ }
++
++ BUILD_BUG_ON(offsetof(struct pt_regs, orig_gpr3) !=
++ offsetof(struct pt_regs, msr) + sizeof(long));
++
++ if (!ret)
++ ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf,
++ &target->thread.ckpt_regs.orig_gpr3,
++ PT_ORIG_R3 * sizeof(reg),
++ (PT_MAX_PUT_REG + 1) * sizeof(reg));
++
++ if (PT_MAX_PUT_REG + 1 < PT_TRAP && !ret)
++ ret = user_regset_copyin_ignore(
++ &pos, &count, &kbuf, &ubuf,
++ (PT_MAX_PUT_REG + 1) * sizeof(reg),
++ PT_TRAP * sizeof(reg));
++
++ if (!ret && count > 0) {
++ ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf, ®,
++ PT_TRAP * sizeof(reg),
++ (PT_TRAP + 1) * sizeof(reg));
++ if (!ret)
++ ret = set_user_ckpt_trap(target, reg);
++ }
++
++ if (!ret)
++ ret = user_regset_copyin_ignore(
++ &pos, &count, &kbuf, &ubuf,
++ (PT_TRAP + 1) * sizeof(reg), -1);
+
+ return ret;
+}
++#endif
+
+ /*
+ * These are our native regset flavors.
+@@ -863,6 +1049,9 @@ enum powerpc_regset {
+ #ifdef CONFIG_SPE
+ REGSET_SPE,
#endif
-
- /*
-@@ -1082,6 +1200,7 @@ enum powerpc_regset {
- REGSET_TM_CGPR, /* TM checkpointed GPR registers */
- REGSET_TM_CFPR, /* TM checkpointed FPR registers */
- REGSET_TM_CVMX, /* TM checkpointed VMX registers */
-+ REGSET_TM_CVSX, /* TM checkpointed VSX registers */
++#ifdef CONFIG_PPC_TRANSACTIONAL_MEM
++ REGSET_TM_CGPR, /* TM checkpointed GPR registers */
++#endif
+ };
+
+ static const struct user_regset native_regsets[] = {
+@@ -897,6 +1086,13 @@ static const struct user_regset native_regsets[] = {
+ .active = evr_active, .get = evr_get, .set = evr_set
+ },
#endif
++#ifdef CONFIG_PPC_TRANSACTIONAL_MEM
++ [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
++ },
++#endif
};
-@@ -1133,6 +1252,11 @@ static const struct user_regset native_regsets[] = {
- .size = sizeof(vector128), .align = sizeof(vector128),
- .active = tm_cvmx_active, .get = tm_cvmx_get, .set = tm_cvmx_set
+ static const struct user_regset_view user_ppc_native_view = {
+@@ -1059,6 +1255,24 @@ static int gpr32_set_common(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 gpr32_get_common(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 gpr32_set_common(target, regset, pos, count, kbuf, ubuf, 1);
++}
++#endif /* CONFIG_PPC_TRANSACTIONAL_MEM */
++
+ static int gpr32_get(struct task_struct *target,
+ const struct user_regset *regset,
+ unsigned int pos, unsigned int count,
+@@ -1103,6 +1317,14 @@ static const struct user_regset compat_regsets[] = {
+ .active = evr_active, .get = evr_get, .set = evr_set
},
-+ [REGSET_TM_CVSX] = {
-+ .core_note_type = NT_PPC_TM_CVSX, .n = ELF_NVSX,
-+ .size = sizeof(double), .align = sizeof(double),
-+ .active = tm_cvsx_active, .get = tm_cvsx_get, .set = tm_cvsx_set
+ #endif
++#ifdef CONFIG_PPC_TRANSACTIONAL_MEM
++ [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
+ },
- #endif
++#endif
};
-@@ -1375,6 +1499,11 @@ static const struct user_regset compat_regsets[] = {
- .size = sizeof(vector128), .align = sizeof(vector128),
- .active = tm_cvmx_active, .get = tm_cvmx_get, .set = tm_cvmx_set
- },
-+ [REGSET_TM_CVSX] = {
-+ .core_note_type = NT_PPC_TM_CVSX, .n = ELF_NVSX,
-+ .size = sizeof(double), .align = sizeof(double),
-+ .active = tm_cvsx_active, .get = tm_cvsx_get, .set = tm_cvsx_set
-+ },
- #endif
- };
-
+ static const struct user_regset_view user_ppc_compat_view = {
--
1.8.3.1