Inter-revision diff: patch 7

Comparing v11 (message) to v12 (message)

--- 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, &reg,
++					 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, &reg,
++					 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
Keyboard shortcuts
hback out one level
jnext message in thread
kprevious message in thread
ldrill in
Escclose help / fold thread tree
?toggle this help