Inter-revision diff: patch 4

Comparing v11 (message) to v12 (message)

--- v11
+++ v12
@@ -1,12 +1,11 @@
 From: Anshuman Khandual <khandual@linux.vnet.ibm.com>
 
-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_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.
+This patch enables in transaction NT_PPC_VMX ptrace requests. The
+function vr_get which gets the running value of all VMX registers
+and the function vr_set which sets the running value of of all VMX
+registers work on the running set of VMX registers whose location
+will be different if transaction is active. This patch makes these
+functions adapt to situations when the transaction is active.
 
 Cc: Benjamin Herrenschmidt <benh@kernel.crashing.org>
 Cc: Paul Mackerras <paulus@samba.org>
@@ -32,276 +31,159 @@
 Cc: linux-kselftest@vger.kernel.org
 Signed-off-by: Anshuman Khandual <khandual@linux.vnet.ibm.com>
 ---
- arch/powerpc/kernel/ptrace.c | 222 +++++++++++++++++++++++++++++++++++++++++++
- 1 file changed, 222 insertions(+)
+ arch/powerpc/kernel/ptrace.c | 90 ++++++++++++++++++++++++++++++++++++++++++--
+ 1 file changed, 87 insertions(+), 3 deletions(-)
 
 diff --git a/arch/powerpc/kernel/ptrace.c b/arch/powerpc/kernel/ptrace.c
-index 38df7f0..0334c23 100644
+index 82db082..3baa57e 100644
 --- a/arch/powerpc/kernel/ptrace.c
 +++ b/arch/powerpc/kernel/ptrace.c
-@@ -181,6 +181,26 @@ static int set_user_msr(struct task_struct *task, unsigned long msr)
- 	return 0;
+@@ -518,10 +518,28 @@ static int vr_active(struct task_struct *target,
+ 	return target->thread.used_vr ? regset->n : 0;
  }
  
++/*
++ * When the transaction is active, 'transact_vr' holds the current running
++ * value of all the VMX registers and 'vr_state' holds the last checkpointed
++ * value of all the VMX registers for the current transaction to fall back
++ * on in case it aborts. When transaction is not active 'vr_state' holds
++ * the current running state of all the VMX registers. So this function which
++ * gets the current running values of all the VMX registers, needs to know
++ * whether any transaction is active or not.
++ *
++ * Userspace interface buffer layout:
++ *
++ * 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)
+ {
++	struct thread_vr_state *addr;
+ 	int ret;
+ 
+ 	flush_altivec_to_thread(target);
+@@ -529,8 +547,19 @@ static int vr_get(struct task_struct *target, const struct user_regset *regset,
+ 	BUILD_BUG_ON(offsetof(struct thread_vr_state, vscr) !=
+ 		     offsetof(struct thread_vr_state, vr[32]));
+ 
 +#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;
-+}
++	if (MSR_TM_ACTIVE(target->thread.regs->msr)) {
++		flush_fp_to_thread(target);
++		flush_tmregs_to_thread(target);
++		addr = &target->thread.transact_vr;
++	} else {
++		addr = &target->thread.vr_state;
++	}
++#else
++	addr = &target->thread.vr_state;
++#endif
+ 	ret = user_regset_copyout(&pos, &count, &kbuf, &ubuf,
+-				  &target->thread.vr_state, 0,
++				  addr, 0,
+ 				  33 * sizeof(vector128));
+ 	if (!ret) {
+ 		/*
+@@ -541,7 +570,16 @@ static int vr_get(struct task_struct *target, const struct user_regset *regset,
+ 			u32 word;
+ 		} vrsave;
+ 		memset(&vrsave, 0, sizeof(vrsave));
 +
-+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;
-+}
++#ifdef CONFIG_PPC_TRANSACTIONAL_MEM
++		if (MSR_TM_ACTIVE(target->thread.regs->msr))
++			vrsave.word = target->thread.transact_vrsave;
++		else
++			vrsave.word = target->thread.vrsave;
++#else
+ 		vrsave.word = target->thread.vrsave;
 +#endif
 +
- #ifdef CONFIG_PPC64
- static int get_user_dscr(struct task_struct *task, unsigned long *data)
+ 		ret = user_regset_copyout(&pos, &count, &kbuf, &ubuf, &vrsave,
+ 					  33 * sizeof(vector128), -1);
+ 	}
+@@ -549,10 +587,28 @@ static int vr_get(struct task_struct *target, const struct user_regset *regset,
+ 	return ret;
+ }
+ 
++/*
++ * When the transaction is active, 'transact_vr' holds the current running
++ * value of all the VMX registers and 'vr_state' holds the last checkpointed
++ * value of all the VMX registers for the current transaction to fall back
++ * on in case it aborts. When transaction is not active 'vr_state' holds
++ * the current running state of all the VMX registers. So this function which
++ * sets the current running values of all the VMX registers, needs to know
++ * whether any transaction is active or not.
++ *
++ * Userspace interface buffer layout:
++ *
++ * struct data {
++ *	vector128	vr[32];
++ *	vector128	vscr;
++ *	vector128	vrsave;
++ * };
++ */
+ 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)
  {
-@@ -614,6 +634,172 @@ static int evr_set(struct task_struct *target, const struct user_regset *regset,
- }
- #endif /* CONFIG_SPE */
++	struct thread_vr_state *addr;
+ 	int ret;
+ 
+ 	flush_altivec_to_thread(target);
+@@ -560,8 +616,19 @@ static int vr_set(struct task_struct *target, const struct user_regset *regset,
+ 	BUILD_BUG_ON(offsetof(struct thread_vr_state, vscr) !=
+ 		     offsetof(struct thread_vr_state, vr[32]));
  
 +#ifdef CONFIG_PPC_TRANSACTIONAL_MEM
-+/**
-+ * 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 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)) {
++		flush_fp_to_thread(target);
++		flush_tmregs_to_thread(target);
++		addr = &target->thread.transact_vr;
++	} else {
++		addr = &target->thread.vr_state;
++	}
++#else
++	addr = &target->thread.vr_state;
++#endif
+ 	ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf,
+-				 &target->thread.vr_state, 0,
++				 addr, 0,
+ 				 33 * sizeof(vector128));
+ 	if (!ret && count > 0) {
+ 		/*
+@@ -572,11 +639,28 @@ static int vr_set(struct task_struct *target, const struct user_regset *regset,
+ 			u32 word;
+ 		} vrsave;
+ 		memset(&vrsave, 0, sizeof(vrsave));
 +
-+	if (!MSR_TM_ACTIVE(target->thread.regs->msr))
-+		return 0;
++#ifdef CONFIG_PPC_TRANSACTIONAL_MEM
++		if (MSR_TM_ACTIVE(target->thread.regs->msr))
++			vrsave.word = target->thread.transact_vrsave;
++		else
++			vrsave.word = target->thread.vrsave;
++#else
+ 		vrsave.word = target->thread.vrsave;
++#endif
+ 		ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf, &vrsave,
+ 					 33 * sizeof(vector128), -1);
+-		if (!ret)
++		if (!ret) {
 +
-+	return regset->n;
-+}
-+
-+/**
-+ * tm_cgpr_get - get CGPR registers
-+ * @target:	The target task.
-+ * @regset:	The user regset structure.
-+ * @pos:	The buffer position.
-+ * @count:	Number of bytes to copy.
-+ * @kbuf:	Kernel buffer to copy from.
-+ * @ubuf:	User buffer to copy into.
-+ *
-+ * 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 {
-+ *	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, 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_cgpr_set - set the CGPR registers
-+ * @target:	The target task.
-+ * @regset:	The user regset structure.
-+ * @pos:	The buffer position.
-+ * @count:	Number of bytes to copy.
-+ * @kbuf:	Kernel buffer to copy into.
-+ * @ubuf:	User buffer to copy from.
-+ *
-+ * 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 {
-+ *	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)
-+{
-+	unsigned long reg;
-+	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, 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;
-+}
++#ifdef CONFIG_PPC_TRANSACTIONAL_MEM
++			if (MSR_TM_ACTIVE(target->thread.regs->msr))
++				target->thread.transact_vrsave = vrsave.word;
++			else
++				target->thread.vrsave = vrsave.word;
++#else
+ 			target->thread.vrsave = vrsave.word;
 +#endif
++		}
+ 	}
  
- /*
-  * These are our native regset flavors.
-@@ -630,6 +816,9 @@ enum powerpc_regset {
- #ifdef CONFIG_SPE
- 	REGSET_SPE,
- #endif
-+#ifdef CONFIG_PPC_TRANSACTIONAL_MEM
-+	REGSET_TM_CGPR,		/* TM checkpointed GPR registers */
-+#endif
- };
- 
- static const struct user_regset native_regsets[] = {
-@@ -664,6 +853,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
- };
- 
- static const struct user_regset_view user_ppc_native_view = {
-@@ -826,6 +1022,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,
-@@ -870,6 +1084,14 @@ static const struct user_regset compat_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_cgpr32_get, .set = tm_cgpr32_set
-+	},
-+#endif
- };
- 
- static const struct user_regset_view user_ppc_compat_view = {
+ 	return ret;
 -- 
 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